@docusaurus/utils 2.0.0-beta.16 → 2.0.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/constants.d.ts +51 -1
- package/lib/constants.d.ts.map +1 -1
- package/lib/constants.js +57 -10
- package/lib/constants.js.map +1 -1
- package/lib/dataFileUtils.d.ts +38 -2
- package/lib/dataFileUtils.d.ts.map +1 -1
- package/lib/dataFileUtils.js +39 -13
- package/lib/dataFileUtils.js.map +1 -1
- package/lib/emitUtils.d.ts +32 -0
- package/lib/emitUtils.d.ts.map +1 -0
- package/lib/emitUtils.js +80 -0
- package/lib/emitUtils.js.map +1 -0
- package/lib/gitUtils.d.ts +54 -5
- package/lib/gitUtils.d.ts.map +1 -1
- package/lib/gitUtils.js +17 -14
- package/lib/gitUtils.js.map +1 -1
- package/lib/globUtils.d.ts +28 -0
- package/lib/globUtils.d.ts.map +1 -1
- package/lib/globUtils.js +36 -13
- package/lib/globUtils.js.map +1 -1
- package/lib/hashUtils.d.ts +5 -4
- package/lib/hashUtils.d.ts.map +1 -1
- package/lib/hashUtils.js +7 -6
- package/lib/hashUtils.js.map +1 -1
- package/lib/i18nUtils.d.ts +51 -0
- package/lib/i18nUtils.d.ts.map +1 -0
- package/lib/i18nUtils.js +69 -0
- package/lib/i18nUtils.js.map +1 -0
- package/lib/index.d.ts +10 -54
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +56 -256
- package/lib/index.js.map +1 -1
- package/lib/jsUtils.d.ts +45 -0
- package/lib/jsUtils.d.ts.map +1 -0
- package/lib/jsUtils.js +94 -0
- package/lib/jsUtils.js.map +1 -0
- package/lib/markdownLinks.d.ts +48 -5
- package/lib/markdownLinks.d.ts.map +1 -1
- package/lib/markdownLinks.js +29 -13
- package/lib/markdownLinks.js.map +1 -1
- package/lib/markdownUtils.d.ts +112 -0
- package/lib/markdownUtils.d.ts.map +1 -0
- package/lib/markdownUtils.js +271 -0
- package/lib/markdownUtils.js.map +1 -0
- package/lib/pathUtils.d.ts +2 -1
- package/lib/pathUtils.d.ts.map +1 -1
- package/lib/pathUtils.js +16 -7
- package/lib/pathUtils.js.map +1 -1
- package/lib/slugger.d.ts +10 -0
- package/lib/slugger.d.ts.map +1 -1
- package/lib/slugger.js +6 -2
- package/lib/slugger.js.map +1 -1
- package/lib/tags.d.ts +42 -10
- package/lib/tags.d.ts.map +1 -1
- package/lib/tags.js +40 -26
- package/lib/tags.js.map +1 -1
- package/lib/urlUtils.d.ts +57 -0
- package/lib/urlUtils.d.ts.map +1 -1
- package/lib/urlUtils.js +132 -6
- package/lib/urlUtils.js.map +1 -1
- package/lib/webpackUtils.d.ts +5 -0
- package/lib/webpackUtils.d.ts.map +1 -1
- package/lib/webpackUtils.js +8 -5
- package/lib/webpackUtils.js.map +1 -1
- package/package.json +11 -11
- package/src/constants.ts +65 -9
- package/src/dataFileUtils.ts +44 -12
- package/src/emitUtils.ts +99 -0
- package/src/gitUtils.ts +77 -17
- package/src/globUtils.ts +34 -13
- package/src/hashUtils.ts +6 -5
- package/src/i18nUtils.ts +115 -0
- package/src/index.ts +43 -307
- package/src/jsUtils.ts +102 -0
- package/src/markdownLinks.ts +71 -28
- package/src/markdownUtils.ts +354 -0
- package/src/pathUtils.ts +15 -7
- package/src/slugger.ts +13 -1
- package/src/tags.ts +53 -28
- package/src/urlUtils.ts +145 -7
- package/src/webpackUtils.ts +11 -4
- package/lib/markdownParser.d.ts +0 -32
- package/lib/markdownParser.d.ts.map +0 -1
- package/lib/markdownParser.js +0 -161
- package/lib/markdownParser.js.map +0 -1
- package/src/markdownParser.ts +0 -201
package/src/urlUtils.ts
CHANGED
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import {removeSuffix} from './jsUtils';
|
|
9
|
+
import resolvePathnameUnsafe from 'resolve-pathname';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Much like `path.join`, but much better. Takes an array of URL segments, and
|
|
13
|
+
* joins them into a reasonable URL.
|
|
14
|
+
*
|
|
15
|
+
* - `["file:", "/home", "/user/", "website"]` => `file:///home/user/website`
|
|
16
|
+
* - `["file://", "home", "/user/", "website"]` => `file://home/user/website` (relative!)
|
|
17
|
+
* - Remove trailing slash before parameters or hash.
|
|
18
|
+
* - Replace `?` in query parameters with `&`.
|
|
19
|
+
* - Dedupe forward slashes in the entire path, avoiding protocol slashes.
|
|
20
|
+
*
|
|
21
|
+
* @throws {TypeError} If any of the URL segment is not a string, this throws.
|
|
22
|
+
*/
|
|
8
23
|
export function normalizeUrl(rawUrls: string[]): string {
|
|
9
24
|
const urls = [...rawUrls];
|
|
10
25
|
const resultArray = [];
|
|
@@ -12,10 +27,17 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|
|
12
27
|
let hasStartingSlash = false;
|
|
13
28
|
let hasEndingSlash = false;
|
|
14
29
|
|
|
30
|
+
const isNonEmptyArray = (arr: string[]): arr is [string, ...string[]] =>
|
|
31
|
+
arr.length > 0;
|
|
32
|
+
|
|
33
|
+
if (!isNonEmptyArray(urls)) {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
|
|
15
37
|
// If the first part is a plain protocol, we combine it with the next part.
|
|
16
38
|
if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
|
|
17
|
-
const first = urls.shift()
|
|
18
|
-
if (first
|
|
39
|
+
const first = urls.shift()!;
|
|
40
|
+
if (first.startsWith('file:') && urls[0].startsWith('/')) {
|
|
19
41
|
// Force a double slash here, else we lose the information that the next
|
|
20
42
|
// segment is an absolute path
|
|
21
43
|
urls[0] = `${first}//${urls[0]}`;
|
|
@@ -40,7 +62,6 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|
|
40
62
|
if (i === urls.length - 1 && hasEndingSlash) {
|
|
41
63
|
resultArray.push('/');
|
|
42
64
|
}
|
|
43
|
-
// eslint-disable-next-line no-continue
|
|
44
65
|
continue;
|
|
45
66
|
}
|
|
46
67
|
|
|
@@ -48,7 +69,7 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|
|
48
69
|
if (i > 0) {
|
|
49
70
|
// Removing the starting slashes for each component but the first.
|
|
50
71
|
component = component.replace(
|
|
51
|
-
|
|
72
|
+
/^\/+/,
|
|
52
73
|
// Special case where the first element of rawUrls is empty
|
|
53
74
|
// ["", "/hello"] => /hello
|
|
54
75
|
component[0] === '/' && !hasStartingSlash ? '/' : '',
|
|
@@ -58,7 +79,7 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|
|
58
79
|
hasEndingSlash = component[component.length - 1] === '/';
|
|
59
80
|
// Removing the ending slashes for each component but the last. For the
|
|
60
81
|
// last component we will combine multiple slashes to a single one.
|
|
61
|
-
component = component.replace(
|
|
82
|
+
component = component.replace(/\/+$/, i < urls.length - 1 ? '' : '/');
|
|
62
83
|
}
|
|
63
84
|
|
|
64
85
|
hasStartingSlash = true;
|
|
@@ -66,8 +87,8 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|
|
66
87
|
}
|
|
67
88
|
|
|
68
89
|
let str = resultArray.join('/');
|
|
69
|
-
// Each input component is now separated by a single slash
|
|
70
|
-
//
|
|
90
|
+
// Each input component is now separated by a single slash except the possible
|
|
91
|
+
// first plain protocol part.
|
|
71
92
|
|
|
72
93
|
// Remove trailing slash before parameters or hash.
|
|
73
94
|
str = str.replace(/\/(?<search>\?|&|#[^!])/g, '$1');
|
|
@@ -85,6 +106,11 @@ export function normalizeUrl(rawUrls: string[]): string {
|
|
|
85
106
|
return str;
|
|
86
107
|
}
|
|
87
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Takes a file's path, relative to its content folder, and computes its edit
|
|
111
|
+
* URL. If `editUrl` is `undefined`, this returns `undefined`, as is the case
|
|
112
|
+
* when the user doesn't want an edit URL in her config.
|
|
113
|
+
*/
|
|
88
114
|
export function getEditUrl(
|
|
89
115
|
fileRelativePath: string,
|
|
90
116
|
editUrl?: string,
|
|
@@ -94,3 +120,115 @@ export function getEditUrl(
|
|
|
94
120
|
normalizeUrl([editUrl, fileRelativePath.replace(/\\/g, '/')])
|
|
95
121
|
: undefined;
|
|
96
122
|
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Converts file path to a reasonable URL path, e.g. `'index.md'` -> `'/'`,
|
|
126
|
+
* `'foo/bar.js'` -> `'/foo/bar'`
|
|
127
|
+
*/
|
|
128
|
+
export function fileToPath(file: string): string {
|
|
129
|
+
const indexRE = /(?<dirname>^|.*\/)index\.(?:mdx?|jsx?|tsx?)$/i;
|
|
130
|
+
const extRE = /\.(?:mdx?|jsx?|tsx?)$/;
|
|
131
|
+
|
|
132
|
+
if (indexRE.test(file)) {
|
|
133
|
+
return file.replace(indexRE, '/$1');
|
|
134
|
+
}
|
|
135
|
+
return `/${file.replace(extRE, '').replace(/\\/g, '/')}`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Similar to `encodeURI`, but uses `encodeURIComponent` and assumes there's no
|
|
140
|
+
* query.
|
|
141
|
+
*
|
|
142
|
+
* `encodeURI("/question?/answer")` => `"/question?/answer#section"`;
|
|
143
|
+
* `encodePath("/question?/answer#section")` => `"/question%3F/answer%23foo"`
|
|
144
|
+
*/
|
|
145
|
+
export function encodePath(userPath: string): string {
|
|
146
|
+
return userPath
|
|
147
|
+
.split('/')
|
|
148
|
+
.map((item) => encodeURIComponent(item))
|
|
149
|
+
.join('/');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Whether `str` is a valid pathname. It must be absolute, and not contain
|
|
154
|
+
* special characters.
|
|
155
|
+
*/
|
|
156
|
+
export function isValidPathname(str: string): boolean {
|
|
157
|
+
if (!str.startsWith('/')) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const parsedPathname = new URL(str, 'https://domain.com').pathname;
|
|
162
|
+
return parsedPathname === str || parsedPathname === encodeURI(str);
|
|
163
|
+
} catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Resolve pathnames and fail-fast if resolution fails. Uses standard URL
|
|
170
|
+
* semantics (provided by `resolve-pathname` which is used internally by React
|
|
171
|
+
* router)
|
|
172
|
+
*/
|
|
173
|
+
export function resolvePathname(to: string, from?: string): string {
|
|
174
|
+
return resolvePathnameUnsafe(to, from);
|
|
175
|
+
}
|
|
176
|
+
/** Appends a leading slash to `str`, if one doesn't exist. */
|
|
177
|
+
export function addLeadingSlash(str: string): string {
|
|
178
|
+
return str.startsWith('/') ? str : `/${str}`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// TODO deduplicate: also present in @docusaurus/utils-common
|
|
182
|
+
/** Appends a trailing slash to `str`, if one doesn't exist. */
|
|
183
|
+
export function addTrailingSlash(str: string): string {
|
|
184
|
+
return str.endsWith('/') ? str : `${str}/`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Removes the trailing slash from `str`. */
|
|
188
|
+
export function removeTrailingSlash(str: string): string {
|
|
189
|
+
return removeSuffix(str, '/');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Constructs an SSH URL that can be used to push to GitHub. */
|
|
193
|
+
export function buildSshUrl(
|
|
194
|
+
githubHost: string,
|
|
195
|
+
organizationName: string,
|
|
196
|
+
projectName: string,
|
|
197
|
+
githubPort?: string,
|
|
198
|
+
): string {
|
|
199
|
+
if (githubPort) {
|
|
200
|
+
return `ssh://git@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
|
|
201
|
+
}
|
|
202
|
+
return `git@${githubHost}:${organizationName}/${projectName}.git`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Constructs an HTTP URL that can be used to push to GitHub. */
|
|
206
|
+
export function buildHttpsUrl(
|
|
207
|
+
gitCredentials: string,
|
|
208
|
+
githubHost: string,
|
|
209
|
+
organizationName: string,
|
|
210
|
+
projectName: string,
|
|
211
|
+
githubPort?: string,
|
|
212
|
+
): string {
|
|
213
|
+
if (githubPort) {
|
|
214
|
+
return `https://${gitCredentials}@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
|
|
215
|
+
}
|
|
216
|
+
return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Whether the current URL is an SSH protocol. In addition to looking for
|
|
221
|
+
* `ssh:`, it will also allow protocol-less URLs like
|
|
222
|
+
* `git@github.com:facebook/docusaurus.git`.
|
|
223
|
+
*/
|
|
224
|
+
export function hasSSHProtocol(sourceRepoUrl: string): boolean {
|
|
225
|
+
try {
|
|
226
|
+
if (new URL(sourceRepoUrl).protocol === 'ssh:') {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
} catch {
|
|
231
|
+
// Fails when there isn't a protocol
|
|
232
|
+
return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl);
|
|
233
|
+
}
|
|
234
|
+
}
|
package/src/webpackUtils.ts
CHANGED
|
@@ -31,15 +31,22 @@ type FileLoaderUtils = {
|
|
|
31
31
|
};
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Returns unified loader configurations to be used for various file types.
|
|
36
|
+
*
|
|
37
|
+
* Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447
|
|
38
|
+
*/
|
|
35
39
|
export function getFileLoaderUtils(): FileLoaderUtils {
|
|
36
|
-
//
|
|
40
|
+
// Files/images < urlLoaderLimit will be inlined as base64 strings directly in
|
|
37
41
|
// the html
|
|
38
42
|
const urlLoaderLimit = WEBPACK_URL_LOADER_LIMIT;
|
|
39
43
|
|
|
40
|
-
// defines the path/pattern of the assets handled by webpack
|
|
41
44
|
const fileLoaderFileName = (folder: AssetFolder) =>
|
|
42
|
-
|
|
45
|
+
path.posix.join(
|
|
46
|
+
OUTPUT_STATIC_ASSETS_DIR_NAME,
|
|
47
|
+
folder,
|
|
48
|
+
'[name]-[contenthash].[ext]',
|
|
49
|
+
);
|
|
43
50
|
|
|
44
51
|
const loaders: FileLoaderUtils['loaders'] = {
|
|
45
52
|
file: (options: {folder: AssetFolder}) => ({
|
package/lib/markdownParser.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
export declare function parseMarkdownHeadingId(heading: string): {
|
|
8
|
-
text: string;
|
|
9
|
-
id?: string;
|
|
10
|
-
};
|
|
11
|
-
export declare function createExcerpt(fileString: string): string | undefined;
|
|
12
|
-
export declare function parseFrontMatter(markdownFileContent: string): {
|
|
13
|
-
frontMatter: Record<string, unknown>;
|
|
14
|
-
content: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function parseMarkdownContentTitle(contentUntrimmed: string, options?: {
|
|
17
|
-
removeContentTitle?: boolean;
|
|
18
|
-
}): {
|
|
19
|
-
content: string;
|
|
20
|
-
contentTitle: string | undefined;
|
|
21
|
-
};
|
|
22
|
-
declare type ParsedMarkdown = {
|
|
23
|
-
frontMatter: Record<string, unknown>;
|
|
24
|
-
content: string;
|
|
25
|
-
contentTitle: string | undefined;
|
|
26
|
-
excerpt: string | undefined;
|
|
27
|
-
};
|
|
28
|
-
export declare function parseMarkdownString(markdownFileContent: string, options?: {
|
|
29
|
-
removeContentTitle?: boolean;
|
|
30
|
-
}): ParsedMarkdown;
|
|
31
|
-
export {};
|
|
32
|
-
//# sourceMappingURL=markdownParser.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"markdownParser.d.ts","sourceRoot":"","sources":["../src/markdownParser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAUA;AAKD,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAyEpE;AAED,wBAAgB,gBAAgB,CAAC,mBAAmB,EAAE,MAAM,GAAG;IAC7D,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB,CAMA;AAcD,wBAAgB,yBAAyB,CACvC,gBAAgB,EAAE,MAAM,EACxB,OAAO,CAAC,EAAE;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAC,GACvC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;CAAC,CAkCrD;AAED,aAAK,cAAc,GAAG;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,MAAM,EAC3B,OAAO,CAAC,EAAE;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAAC,GACvC,cAAc,CAuBhB"}
|
package/lib/markdownParser.js
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
4
|
-
*
|
|
5
|
-
* This source code is licensed under the MIT license found in the
|
|
6
|
-
* LICENSE file in the root directory of this source tree.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.parseMarkdownString = exports.parseMarkdownContentTitle = exports.parseFrontMatter = exports.createExcerpt = exports.parseMarkdownHeadingId = void 0;
|
|
10
|
-
const tslib_1 = require("tslib");
|
|
11
|
-
const logger_1 = (0, tslib_1.__importDefault)(require("@docusaurus/logger"));
|
|
12
|
-
const gray_matter_1 = (0, tslib_1.__importDefault)(require("gray-matter"));
|
|
13
|
-
// Input: ## Some heading {#some-heading}
|
|
14
|
-
// Output: {text: "## Some heading", id: "some-heading"}
|
|
15
|
-
function parseMarkdownHeadingId(heading) {
|
|
16
|
-
const customHeadingIdRegex = /^(?<text>.*?)\s*\{#(?<id>[\w-]+)\}$/;
|
|
17
|
-
const matches = customHeadingIdRegex.exec(heading);
|
|
18
|
-
if (matches) {
|
|
19
|
-
return {
|
|
20
|
-
text: matches.groups.text,
|
|
21
|
-
id: matches.groups.id,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
return { text: heading, id: undefined };
|
|
25
|
-
}
|
|
26
|
-
exports.parseMarkdownHeadingId = parseMarkdownHeadingId;
|
|
27
|
-
// Hacky way of stripping out import statements from the excerpt
|
|
28
|
-
// TODO: Find a better way to do so, possibly by compiling the Markdown content,
|
|
29
|
-
// stripping out HTML tags and obtaining the first line.
|
|
30
|
-
function createExcerpt(fileString) {
|
|
31
|
-
const fileLines = fileString
|
|
32
|
-
.trimLeft()
|
|
33
|
-
// Remove Markdown alternate title
|
|
34
|
-
.replace(/^[^\n]*\n[=]+/g, '')
|
|
35
|
-
.split('\n');
|
|
36
|
-
let inCode = false;
|
|
37
|
-
let lastCodeFence = '';
|
|
38
|
-
/* eslint-disable no-continue */
|
|
39
|
-
for (const fileLine of fileLines) {
|
|
40
|
-
// Skip empty line.
|
|
41
|
-
if (!fileLine.trim()) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
// Skip import/export declaration.
|
|
45
|
-
if (/^(?:import|export)\s.*/.test(fileLine)) {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
// Skip code block line.
|
|
49
|
-
if (fileLine.trim().startsWith('```')) {
|
|
50
|
-
if (!inCode) {
|
|
51
|
-
inCode = true;
|
|
52
|
-
[lastCodeFence] = fileLine.trim().match(/^`+/);
|
|
53
|
-
// If we are in a ````-fenced block, all ``` would be plain text instead
|
|
54
|
-
// of fences
|
|
55
|
-
}
|
|
56
|
-
else if (fileLine.trim().match(/^`+/)[0].length >= lastCodeFence.length) {
|
|
57
|
-
inCode = false;
|
|
58
|
-
}
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
else if (inCode) {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
const cleanedLine = fileLine
|
|
65
|
-
// Remove HTML tags.
|
|
66
|
-
.replace(/<[^>]*>/g, '')
|
|
67
|
-
// Remove Title headers
|
|
68
|
-
.replace(/^#\s*[^#]*\s*#?/gm, '')
|
|
69
|
-
// Remove Markdown + ATX-style headers
|
|
70
|
-
.replace(/^#{1,6}\s*(?<text>[^#]*)\s*(?:#{1,6})?/gm, '$1')
|
|
71
|
-
// Remove emphasis.
|
|
72
|
-
.replace(/(?<opening>[*_]{1,3})(?<text>.*?)\1/g, '$2')
|
|
73
|
-
// Remove strikethroughs.
|
|
74
|
-
.replace(/~~(?<text>\S.*\S)~~/g, '$1')
|
|
75
|
-
// Remove images.
|
|
76
|
-
.replace(/!\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
|
|
77
|
-
// Remove footnotes.
|
|
78
|
-
.replace(/\[\^.+?\](?:: .*?$)?/g, '')
|
|
79
|
-
// Remove inline links.
|
|
80
|
-
.replace(/\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
|
|
81
|
-
// Remove inline code.
|
|
82
|
-
.replace(/`(?<text>.+?)`/g, '$1')
|
|
83
|
-
// Remove blockquotes.
|
|
84
|
-
.replace(/^\s{0,3}>\s?/g, '')
|
|
85
|
-
// Remove admonition definition.
|
|
86
|
-
.replace(/:::.*/, '')
|
|
87
|
-
// Remove Emoji names within colons include preceding whitespace.
|
|
88
|
-
.replace(/\s?:(?:::|[^:\n])+:/g, '')
|
|
89
|
-
// Remove custom Markdown heading id.
|
|
90
|
-
.replace(/{#*[\w-]+}/, '')
|
|
91
|
-
.trim();
|
|
92
|
-
if (cleanedLine) {
|
|
93
|
-
return cleanedLine;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return undefined;
|
|
97
|
-
}
|
|
98
|
-
exports.createExcerpt = createExcerpt;
|
|
99
|
-
function parseFrontMatter(markdownFileContent) {
|
|
100
|
-
const { data, content } = (0, gray_matter_1.default)(markdownFileContent);
|
|
101
|
-
return {
|
|
102
|
-
frontMatter: data,
|
|
103
|
-
content: content.trim(),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
exports.parseFrontMatter = parseFrontMatter;
|
|
107
|
-
/**
|
|
108
|
-
* Try to convert markdown heading to text. Does not need to be perfect, it is
|
|
109
|
-
* only used as a fallback when frontMatter.title is not provided. For now, we
|
|
110
|
-
* just unwrap possible inline code blocks (# `config.js`)
|
|
111
|
-
*/
|
|
112
|
-
function toTextContentTitle(contentTitle) {
|
|
113
|
-
if (contentTitle.startsWith('`') && contentTitle.endsWith('`')) {
|
|
114
|
-
return contentTitle.substring(1, contentTitle.length - 1);
|
|
115
|
-
}
|
|
116
|
-
return contentTitle;
|
|
117
|
-
}
|
|
118
|
-
function parseMarkdownContentTitle(contentUntrimmed, options) {
|
|
119
|
-
var _a, _b;
|
|
120
|
-
const removeContentTitleOption = (_a = options === null || options === void 0 ? void 0 : options.removeContentTitle) !== null && _a !== void 0 ? _a : false;
|
|
121
|
-
const content = contentUntrimmed.trim();
|
|
122
|
-
const IMPORT_STATEMENT = /import\s+(?:[\w*{}\s\n,]+from\s+)?["'\s][@\w/_.-]+["'\s];?|\n/.source;
|
|
123
|
-
const REGULAR_TITLE = /(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>(?:{#*[\w-]+})|#)?\n*?)/
|
|
124
|
-
.source;
|
|
125
|
-
const ALTERNATE_TITLE = /(?<pattern>\s*(?<title>[^\n]*)\s*\n[=]+)/.source;
|
|
126
|
-
const regularTitleMatch = new RegExp(`^(?:${IMPORT_STATEMENT})*?${REGULAR_TITLE}`, 'g').exec(content);
|
|
127
|
-
const alternateTitleMatch = new RegExp(`^(?:${IMPORT_STATEMENT})*?${ALTERNATE_TITLE}`, 'g').exec(content);
|
|
128
|
-
const titleMatch = regularTitleMatch !== null && regularTitleMatch !== void 0 ? regularTitleMatch : alternateTitleMatch;
|
|
129
|
-
const { pattern, title } = (_b = titleMatch === null || titleMatch === void 0 ? void 0 : titleMatch.groups) !== null && _b !== void 0 ? _b : {};
|
|
130
|
-
if (!pattern || !title) {
|
|
131
|
-
return { content, contentTitle: undefined };
|
|
132
|
-
}
|
|
133
|
-
const newContent = removeContentTitleOption
|
|
134
|
-
? content.replace(pattern, '')
|
|
135
|
-
: content;
|
|
136
|
-
return {
|
|
137
|
-
content: newContent.trim(),
|
|
138
|
-
contentTitle: toTextContentTitle(title.trim()).trim(),
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
exports.parseMarkdownContentTitle = parseMarkdownContentTitle;
|
|
142
|
-
function parseMarkdownString(markdownFileContent, options) {
|
|
143
|
-
try {
|
|
144
|
-
const { frontMatter, content: contentWithoutFrontMatter } = parseFrontMatter(markdownFileContent);
|
|
145
|
-
const { content, contentTitle } = parseMarkdownContentTitle(contentWithoutFrontMatter, options);
|
|
146
|
-
const excerpt = createExcerpt(content);
|
|
147
|
-
return {
|
|
148
|
-
frontMatter,
|
|
149
|
-
content,
|
|
150
|
-
contentTitle,
|
|
151
|
-
excerpt,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
catch (err) {
|
|
155
|
-
logger_1.default.error(`Error while parsing Markdown front matter.
|
|
156
|
-
This can happen if you use special characters in front matter values (try using double quotes around that value).`);
|
|
157
|
-
throw err;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
exports.parseMarkdownString = parseMarkdownString;
|
|
161
|
-
//# sourceMappingURL=markdownParser.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"markdownParser.js","sourceRoot":"","sources":["../src/markdownParser.ts"],"names":[],"mappings":"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"}
|
package/src/markdownParser.ts
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import logger from '@docusaurus/logger';
|
|
9
|
-
import matter from 'gray-matter';
|
|
10
|
-
|
|
11
|
-
// Input: ## Some heading {#some-heading}
|
|
12
|
-
// Output: {text: "## Some heading", id: "some-heading"}
|
|
13
|
-
export function parseMarkdownHeadingId(heading: string): {
|
|
14
|
-
text: string;
|
|
15
|
-
id?: string;
|
|
16
|
-
} {
|
|
17
|
-
const customHeadingIdRegex = /^(?<text>.*?)\s*\{#(?<id>[\w-]+)\}$/;
|
|
18
|
-
const matches = customHeadingIdRegex.exec(heading);
|
|
19
|
-
if (matches) {
|
|
20
|
-
return {
|
|
21
|
-
text: matches.groups!.text,
|
|
22
|
-
id: matches.groups!.id,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
return {text: heading, id: undefined};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Hacky way of stripping out import statements from the excerpt
|
|
29
|
-
// TODO: Find a better way to do so, possibly by compiling the Markdown content,
|
|
30
|
-
// stripping out HTML tags and obtaining the first line.
|
|
31
|
-
export function createExcerpt(fileString: string): string | undefined {
|
|
32
|
-
const fileLines = fileString
|
|
33
|
-
.trimLeft()
|
|
34
|
-
// Remove Markdown alternate title
|
|
35
|
-
.replace(/^[^\n]*\n[=]+/g, '')
|
|
36
|
-
.split('\n');
|
|
37
|
-
let inCode = false;
|
|
38
|
-
let lastCodeFence = '';
|
|
39
|
-
|
|
40
|
-
/* eslint-disable no-continue */
|
|
41
|
-
for (const fileLine of fileLines) {
|
|
42
|
-
// Skip empty line.
|
|
43
|
-
if (!fileLine.trim()) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Skip import/export declaration.
|
|
48
|
-
if (/^(?:import|export)\s.*/.test(fileLine)) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Skip code block line.
|
|
53
|
-
if (fileLine.trim().startsWith('```')) {
|
|
54
|
-
if (!inCode) {
|
|
55
|
-
inCode = true;
|
|
56
|
-
[lastCodeFence] = fileLine.trim().match(/^`+/)!;
|
|
57
|
-
// If we are in a ````-fenced block, all ``` would be plain text instead
|
|
58
|
-
// of fences
|
|
59
|
-
} else if (
|
|
60
|
-
fileLine.trim().match(/^`+/)![0].length >= lastCodeFence.length
|
|
61
|
-
) {
|
|
62
|
-
inCode = false;
|
|
63
|
-
}
|
|
64
|
-
continue;
|
|
65
|
-
} else if (inCode) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const cleanedLine = fileLine
|
|
70
|
-
// Remove HTML tags.
|
|
71
|
-
.replace(/<[^>]*>/g, '')
|
|
72
|
-
// Remove Title headers
|
|
73
|
-
.replace(/^#\s*[^#]*\s*#?/gm, '')
|
|
74
|
-
// Remove Markdown + ATX-style headers
|
|
75
|
-
.replace(/^#{1,6}\s*(?<text>[^#]*)\s*(?:#{1,6})?/gm, '$1')
|
|
76
|
-
// Remove emphasis.
|
|
77
|
-
.replace(/(?<opening>[*_]{1,3})(?<text>.*?)\1/g, '$2')
|
|
78
|
-
// Remove strikethroughs.
|
|
79
|
-
.replace(/~~(?<text>\S.*\S)~~/g, '$1')
|
|
80
|
-
// Remove images.
|
|
81
|
-
.replace(/!\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
|
|
82
|
-
// Remove footnotes.
|
|
83
|
-
.replace(/\[\^.+?\](?:: .*?$)?/g, '')
|
|
84
|
-
// Remove inline links.
|
|
85
|
-
.replace(/\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
|
|
86
|
-
// Remove inline code.
|
|
87
|
-
.replace(/`(?<text>.+?)`/g, '$1')
|
|
88
|
-
// Remove blockquotes.
|
|
89
|
-
.replace(/^\s{0,3}>\s?/g, '')
|
|
90
|
-
// Remove admonition definition.
|
|
91
|
-
.replace(/:::.*/, '')
|
|
92
|
-
// Remove Emoji names within colons include preceding whitespace.
|
|
93
|
-
.replace(/\s?:(?:::|[^:\n])+:/g, '')
|
|
94
|
-
// Remove custom Markdown heading id.
|
|
95
|
-
.replace(/{#*[\w-]+}/, '')
|
|
96
|
-
.trim();
|
|
97
|
-
|
|
98
|
-
if (cleanedLine) {
|
|
99
|
-
return cleanedLine;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return undefined;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function parseFrontMatter(markdownFileContent: string): {
|
|
107
|
-
frontMatter: Record<string, unknown>;
|
|
108
|
-
content: string;
|
|
109
|
-
} {
|
|
110
|
-
const {data, content} = matter(markdownFileContent);
|
|
111
|
-
return {
|
|
112
|
-
frontMatter: data,
|
|
113
|
-
content: content.trim(),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Try to convert markdown heading to text. Does not need to be perfect, it is
|
|
119
|
-
* only used as a fallback when frontMatter.title is not provided. For now, we
|
|
120
|
-
* just unwrap possible inline code blocks (# `config.js`)
|
|
121
|
-
*/
|
|
122
|
-
function toTextContentTitle(contentTitle: string): string {
|
|
123
|
-
if (contentTitle.startsWith('`') && contentTitle.endsWith('`')) {
|
|
124
|
-
return contentTitle.substring(1, contentTitle.length - 1);
|
|
125
|
-
}
|
|
126
|
-
return contentTitle;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function parseMarkdownContentTitle(
|
|
130
|
-
contentUntrimmed: string,
|
|
131
|
-
options?: {removeContentTitle?: boolean},
|
|
132
|
-
): {content: string; contentTitle: string | undefined} {
|
|
133
|
-
const removeContentTitleOption = options?.removeContentTitle ?? false;
|
|
134
|
-
|
|
135
|
-
const content = contentUntrimmed.trim();
|
|
136
|
-
|
|
137
|
-
const IMPORT_STATEMENT =
|
|
138
|
-
/import\s+(?:[\w*{}\s\n,]+from\s+)?["'\s][@\w/_.-]+["'\s];?|\n/.source;
|
|
139
|
-
const REGULAR_TITLE =
|
|
140
|
-
/(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>(?:{#*[\w-]+})|#)?\n*?)/
|
|
141
|
-
.source;
|
|
142
|
-
const ALTERNATE_TITLE = /(?<pattern>\s*(?<title>[^\n]*)\s*\n[=]+)/.source;
|
|
143
|
-
|
|
144
|
-
const regularTitleMatch = new RegExp(
|
|
145
|
-
`^(?:${IMPORT_STATEMENT})*?${REGULAR_TITLE}`,
|
|
146
|
-
'g',
|
|
147
|
-
).exec(content);
|
|
148
|
-
const alternateTitleMatch = new RegExp(
|
|
149
|
-
`^(?:${IMPORT_STATEMENT})*?${ALTERNATE_TITLE}`,
|
|
150
|
-
'g',
|
|
151
|
-
).exec(content);
|
|
152
|
-
|
|
153
|
-
const titleMatch = regularTitleMatch ?? alternateTitleMatch;
|
|
154
|
-
const {pattern, title} = titleMatch?.groups ?? {};
|
|
155
|
-
|
|
156
|
-
if (!pattern || !title) {
|
|
157
|
-
return {content, contentTitle: undefined};
|
|
158
|
-
}
|
|
159
|
-
const newContent = removeContentTitleOption
|
|
160
|
-
? content.replace(pattern, '')
|
|
161
|
-
: content;
|
|
162
|
-
return {
|
|
163
|
-
content: newContent.trim(),
|
|
164
|
-
contentTitle: toTextContentTitle(title.trim()).trim(),
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
type ParsedMarkdown = {
|
|
169
|
-
frontMatter: Record<string, unknown>;
|
|
170
|
-
content: string;
|
|
171
|
-
contentTitle: string | undefined;
|
|
172
|
-
excerpt: string | undefined;
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
export function parseMarkdownString(
|
|
176
|
-
markdownFileContent: string,
|
|
177
|
-
options?: {removeContentTitle?: boolean},
|
|
178
|
-
): ParsedMarkdown {
|
|
179
|
-
try {
|
|
180
|
-
const {frontMatter, content: contentWithoutFrontMatter} =
|
|
181
|
-
parseFrontMatter(markdownFileContent);
|
|
182
|
-
|
|
183
|
-
const {content, contentTitle} = parseMarkdownContentTitle(
|
|
184
|
-
contentWithoutFrontMatter,
|
|
185
|
-
options,
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
const excerpt = createExcerpt(content);
|
|
189
|
-
|
|
190
|
-
return {
|
|
191
|
-
frontMatter,
|
|
192
|
-
content,
|
|
193
|
-
contentTitle,
|
|
194
|
-
excerpt,
|
|
195
|
-
};
|
|
196
|
-
} catch (err) {
|
|
197
|
-
logger.error(`Error while parsing Markdown front matter.
|
|
198
|
-
This can happen if you use special characters in front matter values (try using double quotes around that value).`);
|
|
199
|
-
throw err;
|
|
200
|
-
}
|
|
201
|
-
}
|