@docusaurus/utils 2.0.0-beta.138b4c997 → 2.0.0-beta.14
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 +20 -0
- package/lib/constants.d.ts.map +1 -0
- package/lib/constants.js +27 -0
- package/lib/constants.js.map +1 -0
- package/lib/escapePath.d.ts +1 -0
- package/lib/escapePath.d.ts.map +1 -0
- package/lib/escapePath.js +1 -0
- package/lib/escapePath.js.map +1 -0
- package/lib/globUtils.d.ts +12 -0
- package/lib/globUtils.d.ts.map +1 -0
- package/lib/globUtils.js +48 -0
- package/lib/globUtils.js.map +1 -0
- package/lib/hashUtils.d.ts +1 -0
- package/lib/hashUtils.d.ts.map +1 -0
- package/lib/hashUtils.js +5 -4
- package/lib/hashUtils.js.map +1 -0
- package/lib/index.d.ts +11 -7
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +43 -96
- package/lib/index.js.map +1 -0
- package/lib/markdownLinks.d.ts +1 -0
- package/lib/markdownLinks.d.ts.map +1 -0
- package/lib/markdownLinks.js +20 -6
- package/lib/markdownLinks.js.map +1 -0
- package/lib/markdownParser.d.ts +1 -0
- package/lib/markdownParser.d.ts.map +1 -0
- package/lib/markdownParser.js +17 -8
- package/lib/markdownParser.js.map +1 -0
- package/lib/mdxUtils.d.ts +17 -0
- package/lib/mdxUtils.d.ts.map +1 -0
- package/lib/mdxUtils.js +31 -0
- package/lib/mdxUtils.js.map +1 -0
- package/lib/{getFilePathForRoutePath.d.ts → normalizeUrl.d.ts} +2 -1
- package/lib/normalizeUrl.d.ts.map +1 -0
- package/lib/normalizeUrl.js +67 -0
- package/lib/normalizeUrl.js.map +1 -0
- package/lib/pathUtils.d.ts +1 -0
- package/lib/pathUtils.d.ts.map +1 -0
- package/lib/pathUtils.js +4 -5
- package/lib/pathUtils.js.map +1 -0
- package/lib/posixPath.d.ts +1 -0
- package/lib/posixPath.d.ts.map +1 -0
- package/lib/posixPath.js +1 -0
- package/lib/posixPath.js.map +1 -0
- package/lib/slugger.d.ts +14 -0
- package/lib/slugger.d.ts.map +1 -0
- package/lib/slugger.js +19 -0
- package/lib/slugger.js.map +1 -0
- package/lib/tags.d.ts +19 -0
- package/lib/tags.d.ts.map +1 -0
- package/lib/tags.js +73 -0
- package/lib/tags.js.map +1 -0
- package/lib/webpackUtils.d.ts +30 -0
- package/lib/webpackUtils.d.ts.map +1 -0
- package/lib/webpackUtils.js +110 -0
- package/lib/webpackUtils.js.map +1 -0
- package/package.json +25 -8
- package/src/constants.ts +38 -0
- package/src/deps.d.ts +14 -0
- package/src/globUtils.ts +63 -0
- package/src/index.ts +25 -96
- package/src/markdownLinks.ts +19 -8
- package/src/markdownParser.ts +21 -16
- package/src/mdxUtils.ts +32 -0
- package/src/normalizeUrl.ts +80 -0
- package/src/pathUtils.ts +2 -3
- package/src/slugger.ts +24 -0
- package/src/tags.ts +100 -0
- package/src/webpackUtils.ts +144 -0
- package/lib/.tsbuildinfo +0 -1
- package/lib/codeTranslationsUtils.d.ts +0 -11
- package/lib/codeTranslationsUtils.js +0 -50
- package/lib/getFilePathForRoutePath.js +0 -40
- package/src/__tests__/__fixtures__/defaultCodeTranslations/en.json +0 -4
- package/src/__tests__/__fixtures__/defaultCodeTranslations/fr-FR.json +0 -5
- package/src/__tests__/__fixtures__/defaultCodeTranslations/fr.json +0 -4
- package/src/__tests__/__snapshots__/index.test.ts.snap +0 -8
- package/src/__tests__/codeTranslationsUtils.test.ts +0 -112
- package/src/__tests__/escapePath.test.ts +0 -25
- package/src/__tests__/getFilePathForRoutePath.test.ts +0 -87
- package/src/__tests__/hashUtils.test.ts +0 -51
- package/src/__tests__/index.test.ts +0 -631
- package/src/__tests__/markdownParser.test.ts +0 -817
- package/src/__tests__/pathUtils.test.ts +0 -63
- package/src/__tests__/posixPath.test.ts +0 -25
- package/src/codeTranslationsUtils.ts +0 -56
- package/src/getFilePathForRoutePath.ts +0 -43
- package/tsconfig.json +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/utils",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.14",
|
|
4
4
|
"description": "Node utility functions for Docusaurus packages.",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -18,22 +18,39 @@
|
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@docusaurus/
|
|
22
|
-
"@
|
|
23
|
-
"
|
|
21
|
+
"@docusaurus/logger": "2.0.0-beta.14",
|
|
22
|
+
"@mdx-js/runtime": "^1.6.22",
|
|
23
|
+
"@svgr/webpack": "^6.0.0",
|
|
24
24
|
"escape-string-regexp": "^4.0.0",
|
|
25
|
+
"file-loader": "^6.2.0",
|
|
25
26
|
"fs-extra": "^10.0.0",
|
|
27
|
+
"github-slugger": "^1.4.0",
|
|
28
|
+
"globby": "^11.0.4",
|
|
26
29
|
"gray-matter": "^4.0.3",
|
|
27
30
|
"lodash": "^4.17.20",
|
|
31
|
+
"micromatch": "^4.0.4",
|
|
32
|
+
"remark-mdx-remove-exports": "^1.6.22",
|
|
33
|
+
"remark-mdx-remove-imports": "^1.6.22",
|
|
28
34
|
"resolve-pathname": "^3.0.0",
|
|
29
|
-
"tslib": "^2.
|
|
35
|
+
"tslib": "^2.3.1",
|
|
36
|
+
"url-loader": "^4.1.1"
|
|
30
37
|
},
|
|
31
38
|
"engines": {
|
|
32
|
-
"node": ">=
|
|
39
|
+
"node": ">=14"
|
|
33
40
|
},
|
|
34
41
|
"devDependencies": {
|
|
42
|
+
"@docusaurus/types": "2.0.0-beta.14",
|
|
35
43
|
"@types/dedent": "^0.7.0",
|
|
36
|
-
"
|
|
44
|
+
"@types/github-slugger": "^1.3.0",
|
|
45
|
+
"@types/micromatch": "^4.0.2",
|
|
46
|
+
"@types/react-dom": "^17.0.1",
|
|
47
|
+
"dedent": "^0.7.0",
|
|
48
|
+
"tslib": "^2.3.1"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"react": "*",
|
|
52
|
+
"react-dom": "*",
|
|
53
|
+
"webpack": "5.x"
|
|
37
54
|
},
|
|
38
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "c4824a8937d8f1aa0806667749cbc74058e2b294"
|
|
39
56
|
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
export const NODE_MAJOR_VERSION = parseInt(
|
|
9
|
+
process.versions.node.split('.')[0],
|
|
10
|
+
10,
|
|
11
|
+
);
|
|
12
|
+
export const NODE_MINOR_VERSION = parseInt(
|
|
13
|
+
process.versions.node.split('.')[1],
|
|
14
|
+
10,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
// Can be overridden with cli option --out-dir
|
|
18
|
+
export const DEFAULT_BUILD_DIR_NAME = 'build';
|
|
19
|
+
|
|
20
|
+
// Can be overridden with cli option --config
|
|
21
|
+
export const DEFAULT_CONFIG_FILE_NAME = 'docusaurus.config.js';
|
|
22
|
+
|
|
23
|
+
export const BABEL_CONFIG_FILE_NAME =
|
|
24
|
+
process.env.DOCUSAURUS_BABEL_CONFIG_FILE_NAME || 'babel.config.js';
|
|
25
|
+
|
|
26
|
+
export const GENERATED_FILES_DIR_NAME =
|
|
27
|
+
process.env.DOCUSAURUS_GENERATED_FILES_DIR_NAME || '.docusaurus';
|
|
28
|
+
|
|
29
|
+
export const SRC_DIR_NAME = 'src';
|
|
30
|
+
export const STATIC_DIR_NAME = 'static';
|
|
31
|
+
export const OUTPUT_STATIC_ASSETS_DIR_NAME = 'assets'; // files handled by webpack, hashed (can be cached aggressively)
|
|
32
|
+
export const THEME_PATH = `${SRC_DIR_NAME}/theme`;
|
|
33
|
+
export const DEFAULT_PORT = 3000;
|
|
34
|
+
export const DEFAULT_PLUGIN_ID = 'default';
|
|
35
|
+
|
|
36
|
+
// Temporary fix for https://github.com/facebook/docusaurus/issues/5493
|
|
37
|
+
export const WEBPACK_URL_LOADER_LIMIT =
|
|
38
|
+
process.env.WEBPACK_URL_LOADER_LIMIT ?? 10000;
|
package/src/deps.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
declare module 'resolve-pathname' {
|
|
9
|
+
export default function resolvePathname(to: string, from?: string): string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare module '@mdx-js/runtime';
|
|
13
|
+
declare module 'remark-mdx-remove-imports';
|
|
14
|
+
declare module 'remark-mdx-remove-exports';
|
package/src/globUtils.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
// Globby/Micromatch are the 2 libs we use in Docusaurus consistently
|
|
9
|
+
|
|
10
|
+
export {default as Globby} from 'globby';
|
|
11
|
+
import Micromatch from 'micromatch'; // Note: Micromatch is used by Globby
|
|
12
|
+
import path from 'path';
|
|
13
|
+
|
|
14
|
+
// The default patterns we ignore when globbing
|
|
15
|
+
// using _ prefix for exclusion by convention
|
|
16
|
+
export const GlobExcludeDefault = [
|
|
17
|
+
// Ignore files starting with _
|
|
18
|
+
'**/_*.{js,jsx,ts,tsx,md,mdx}',
|
|
19
|
+
|
|
20
|
+
// Ignore folders starting with _ (including folder content)
|
|
21
|
+
'**/_*/**',
|
|
22
|
+
|
|
23
|
+
// Ignore tests
|
|
24
|
+
'**/*.test.{js,jsx,ts,tsx}',
|
|
25
|
+
'**/__tests__/**',
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
type Matcher = (str: string) => boolean;
|
|
29
|
+
|
|
30
|
+
export function createMatcher(patterns: string[]): Matcher {
|
|
31
|
+
const regexp = new RegExp(
|
|
32
|
+
patterns.map((pattern) => Micromatch.makeRe(pattern).source).join('|'),
|
|
33
|
+
);
|
|
34
|
+
return (str) => regexp.test(str);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// We use match patterns like '**/_*/**',
|
|
38
|
+
// This function permits to help to:
|
|
39
|
+
// Match /user/sebastien/website/docs/_partials/xyz.md
|
|
40
|
+
// Ignore /user/_sebastien/website/docs/partials/xyz.md
|
|
41
|
+
export function createAbsoluteFilePathMatcher(
|
|
42
|
+
patterns: string[],
|
|
43
|
+
rootFolders: string[],
|
|
44
|
+
): Matcher {
|
|
45
|
+
const matcher = createMatcher(patterns);
|
|
46
|
+
|
|
47
|
+
function getRelativeFilePath(absoluteFilePath: string) {
|
|
48
|
+
const rootFolder = rootFolders.find((folderPath) =>
|
|
49
|
+
absoluteFilePath.startsWith(folderPath),
|
|
50
|
+
);
|
|
51
|
+
if (!rootFolder) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`createAbsoluteFilePathMatcher unexpected error, absoluteFilePath=${absoluteFilePath} was not contained in any of the root folders ${JSON.stringify(
|
|
54
|
+
rootFolders,
|
|
55
|
+
)}`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return path.relative(rootFolder, absoluteFilePath);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (absoluteFilePath: string) =>
|
|
62
|
+
matcher(getRelativeFilePath(absoluteFilePath));
|
|
63
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import logger from '@docusaurus/logger';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import {createHash} from 'crypto';
|
|
11
11
|
import {camelCase, mapValues} from 'lodash';
|
|
@@ -18,20 +18,32 @@ import {
|
|
|
18
18
|
TranslationFile,
|
|
19
19
|
} from '@docusaurus/types';
|
|
20
20
|
|
|
21
|
-
// @ts-expect-error: no typedefs :s
|
|
22
21
|
import resolvePathnameUnsafe from 'resolve-pathname';
|
|
23
22
|
|
|
24
23
|
import {posixPath as posixPathImport} from './posixPath';
|
|
25
24
|
import {simpleHash, docuHash} from './hashUtils';
|
|
25
|
+
import {normalizeUrl} from './normalizeUrl';
|
|
26
|
+
import {DEFAULT_PLUGIN_ID} from './constants';
|
|
27
|
+
|
|
28
|
+
export * from './constants';
|
|
29
|
+
export * from './mdxUtils';
|
|
30
|
+
export * from './normalizeUrl';
|
|
31
|
+
export * from './tags';
|
|
26
32
|
|
|
27
33
|
export const posixPath = posixPathImport;
|
|
28
34
|
|
|
29
|
-
export * from './getFilePathForRoutePath';
|
|
30
|
-
export * from './codeTranslationsUtils';
|
|
31
35
|
export * from './markdownParser';
|
|
32
36
|
export * from './markdownLinks';
|
|
33
37
|
export * from './escapePath';
|
|
38
|
+
export * from './slugger';
|
|
34
39
|
export {md5Hash, simpleHash, docuHash} from './hashUtils';
|
|
40
|
+
export {
|
|
41
|
+
Globby,
|
|
42
|
+
GlobExcludeDefault,
|
|
43
|
+
createMatcher,
|
|
44
|
+
createAbsoluteFilePathMatcher,
|
|
45
|
+
} from './globUtils';
|
|
46
|
+
export * from './webpackUtils';
|
|
35
47
|
|
|
36
48
|
const fileHash = new Map();
|
|
37
49
|
export async function generate(
|
|
@@ -185,80 +197,6 @@ export function getSubFolder(file: string, refDir: string): string | null {
|
|
|
185
197
|
return match && match[1];
|
|
186
198
|
}
|
|
187
199
|
|
|
188
|
-
export function normalizeUrl(rawUrls: string[]): string {
|
|
189
|
-
const urls = [...rawUrls];
|
|
190
|
-
const resultArray = [];
|
|
191
|
-
|
|
192
|
-
let hasStartingSlash = false;
|
|
193
|
-
let hasEndingSlash = false;
|
|
194
|
-
|
|
195
|
-
// If the first part is a plain protocol, we combine it with the next part.
|
|
196
|
-
if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
|
|
197
|
-
const first = urls.shift();
|
|
198
|
-
urls[0] = first + urls[0];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// There must be two or three slashes in the file protocol,
|
|
202
|
-
// two slashes in anything else.
|
|
203
|
-
const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
|
|
204
|
-
urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement);
|
|
205
|
-
|
|
206
|
-
// eslint-disable-next-line
|
|
207
|
-
for (let i = 0; i < urls.length; i++) {
|
|
208
|
-
let component = urls[i];
|
|
209
|
-
|
|
210
|
-
if (typeof component !== 'string') {
|
|
211
|
-
throw new TypeError(`Url must be a string. Received ${typeof component}`);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (component === '') {
|
|
215
|
-
if (i === urls.length - 1 && hasEndingSlash) {
|
|
216
|
-
resultArray.push('/');
|
|
217
|
-
}
|
|
218
|
-
// eslint-disable-next-line
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (component !== '/') {
|
|
223
|
-
if (i > 0) {
|
|
224
|
-
// Removing the starting slashes for each component but the first.
|
|
225
|
-
component = component.replace(
|
|
226
|
-
/^[/]+/,
|
|
227
|
-
// Special case where the first element of rawUrls is empty ["", "/hello"] => /hello
|
|
228
|
-
component[0] === '/' && !hasStartingSlash ? '/' : '',
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
hasEndingSlash = component[component.length - 1] === '/';
|
|
233
|
-
// Removing the ending slashes for each component but the last.
|
|
234
|
-
// For the last component we will combine multiple slashes to a single one.
|
|
235
|
-
component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
hasStartingSlash = true;
|
|
239
|
-
resultArray.push(component);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
let str = resultArray.join('/');
|
|
243
|
-
// Each input component is now separated by a single slash
|
|
244
|
-
// except the possible first plain protocol part.
|
|
245
|
-
|
|
246
|
-
// Remove trailing slash before parameters or hash.
|
|
247
|
-
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
|
|
248
|
-
|
|
249
|
-
// Replace ? in parameters with &.
|
|
250
|
-
const parts = str.split('?');
|
|
251
|
-
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
|
|
252
|
-
|
|
253
|
-
// Dedupe forward slashes in the entire path, avoiding protocol slashes.
|
|
254
|
-
str = str.replace(/([^:]\/)\/+/g, '$1');
|
|
255
|
-
|
|
256
|
-
// Dedupe forward slashes at the beginning of the path.
|
|
257
|
-
str = str.replace(/^\/+/g, '/');
|
|
258
|
-
|
|
259
|
-
return str;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
200
|
/**
|
|
263
201
|
* Alias filepath relative to site directory, very useful so that we
|
|
264
202
|
* don't expose user's site structure.
|
|
@@ -324,7 +262,7 @@ export function removePrefix(str: string, prefix: string): string {
|
|
|
324
262
|
return str.startsWith(prefix) ? str.slice(prefix.length) : str;
|
|
325
263
|
}
|
|
326
264
|
|
|
327
|
-
export function getElementsAround<T
|
|
265
|
+
export function getElementsAround<T>(
|
|
328
266
|
array: T[],
|
|
329
267
|
aroundIndex: number,
|
|
330
268
|
): {
|
|
@@ -347,7 +285,7 @@ export function getPluginI18nPath({
|
|
|
347
285
|
siteDir,
|
|
348
286
|
locale,
|
|
349
287
|
pluginName,
|
|
350
|
-
pluginId =
|
|
288
|
+
pluginId = DEFAULT_PLUGIN_ID,
|
|
351
289
|
subPaths = [],
|
|
352
290
|
}: {
|
|
353
291
|
siteDir: string;
|
|
@@ -363,22 +301,18 @@ export function getPluginI18nPath({
|
|
|
363
301
|
locale,
|
|
364
302
|
// Make it convenient to use for single-instance
|
|
365
303
|
// ie: return "docs", not "docs-default" nor "docs/default"
|
|
366
|
-
`${pluginName}${
|
|
367
|
-
// TODO duplicate constant :(
|
|
368
|
-
pluginId === 'default' ? '' : `-${pluginId}`
|
|
369
|
-
}`,
|
|
304
|
+
`${pluginName}${pluginId === DEFAULT_PLUGIN_ID ? '' : `-${pluginId}`}`,
|
|
370
305
|
...subPaths,
|
|
371
306
|
);
|
|
372
307
|
}
|
|
373
308
|
|
|
374
|
-
export async function mapAsyncSequencial<T
|
|
309
|
+
export async function mapAsyncSequencial<T, R>(
|
|
375
310
|
array: T[],
|
|
376
311
|
action: (t: T) => Promise<R>,
|
|
377
312
|
): Promise<R[]> {
|
|
378
313
|
const results: R[] = [];
|
|
379
314
|
// eslint-disable-next-line no-restricted-syntax
|
|
380
315
|
for (const t of array) {
|
|
381
|
-
// eslint-disable-next-line no-await-in-loop
|
|
382
316
|
const result = await action(t);
|
|
383
317
|
results.push(result);
|
|
384
318
|
}
|
|
@@ -391,7 +325,6 @@ export async function findAsyncSequential<T>(
|
|
|
391
325
|
): Promise<T | undefined> {
|
|
392
326
|
// eslint-disable-next-line no-restricted-syntax
|
|
393
327
|
for (const t of array) {
|
|
394
|
-
// eslint-disable-next-line no-await-in-loop
|
|
395
328
|
if (await predicate(t)) {
|
|
396
329
|
return t;
|
|
397
330
|
}
|
|
@@ -436,13 +369,13 @@ export function reportMessage(
|
|
|
436
369
|
case 'ignore':
|
|
437
370
|
break;
|
|
438
371
|
case 'log':
|
|
439
|
-
|
|
372
|
+
logger.info(message);
|
|
440
373
|
break;
|
|
441
374
|
case 'warn':
|
|
442
|
-
|
|
375
|
+
logger.warn(message);
|
|
443
376
|
break;
|
|
444
377
|
case 'error':
|
|
445
|
-
|
|
378
|
+
logger.error(message);
|
|
446
379
|
break;
|
|
447
380
|
case 'throw':
|
|
448
381
|
throw new Error(message);
|
|
@@ -456,9 +389,7 @@ export function reportMessage(
|
|
|
456
389
|
export function mergeTranslations(
|
|
457
390
|
contents: TranslationFileContent[],
|
|
458
391
|
): TranslationFileContent {
|
|
459
|
-
return contents.reduce((acc, content) => {
|
|
460
|
-
return {...acc, ...content};
|
|
461
|
-
}, {});
|
|
392
|
+
return contents.reduce((acc, content) => ({...acc, ...content}), {});
|
|
462
393
|
}
|
|
463
394
|
|
|
464
395
|
export function getSwizzledComponent(
|
|
@@ -492,9 +423,7 @@ export function updateTranslationFileMessages(
|
|
|
492
423
|
|
|
493
424
|
// Input: ## Some heading {#some-heading}
|
|
494
425
|
// Output: {text: "## Some heading", id: "some-heading"}
|
|
495
|
-
export function parseMarkdownHeadingId(
|
|
496
|
-
heading: string,
|
|
497
|
-
): {
|
|
426
|
+
export function parseMarkdownHeadingId(heading: string): {
|
|
498
427
|
text: string;
|
|
499
428
|
id?: string;
|
|
500
429
|
} {
|
package/src/markdownLinks.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import path from 'path';
|
|
9
9
|
import {aliasedSitePath} from './index';
|
|
10
10
|
|
|
11
11
|
export type ContentPaths = {
|
|
@@ -63,16 +63,27 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
|
|
|
63
63
|
// Replace it to correct html link.
|
|
64
64
|
const mdLink = mdMatch[1];
|
|
65
65
|
|
|
66
|
-
const
|
|
67
|
-
|
|
66
|
+
const sourcesToTry = [
|
|
67
|
+
path.resolve(path.dirname(filePath), decodeURIComponent(mdLink)),
|
|
68
|
+
`${contentPathLocalized}/${decodeURIComponent(mdLink)}`,
|
|
69
|
+
`${contentPath}/${decodeURIComponent(mdLink)}`,
|
|
70
|
+
];
|
|
68
71
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
sourceToPermalink[
|
|
72
|
-
|
|
72
|
+
const aliasedSourceMatch = sourcesToTry
|
|
73
|
+
.map((source) => aliasedSitePath(source, siteDir))
|
|
74
|
+
.find((source) => sourceToPermalink[source]);
|
|
75
|
+
|
|
76
|
+
const permalink: string | undefined = aliasedSourceMatch
|
|
77
|
+
? sourceToPermalink[aliasedSourceMatch]
|
|
78
|
+
: undefined;
|
|
73
79
|
|
|
74
80
|
if (permalink) {
|
|
75
|
-
|
|
81
|
+
// MDX won't be happy if the permalink contains a space, we need to convert it to %20
|
|
82
|
+
const encodedPermalink = permalink
|
|
83
|
+
.split('/')
|
|
84
|
+
.map((part) => part.replace(/\s/g, '%20'))
|
|
85
|
+
.join('/');
|
|
86
|
+
modifiedLine = modifiedLine.replace(mdLink, encodedPermalink);
|
|
76
87
|
} else {
|
|
77
88
|
const brokenMarkdownLink: BrokenMarkdownLink<T> = {
|
|
78
89
|
contentPaths,
|
package/src/markdownParser.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import logger from '@docusaurus/logger';
|
|
9
9
|
import fs from 'fs-extra';
|
|
10
10
|
import matter from 'gray-matter';
|
|
11
11
|
|
|
@@ -18,6 +18,7 @@ export function createExcerpt(fileString: string): string | undefined {
|
|
|
18
18
|
// Remove Markdown alternate title
|
|
19
19
|
.replace(/^[^\n]*\n[=]+/g, '')
|
|
20
20
|
.split('\n');
|
|
21
|
+
let inCode = false;
|
|
21
22
|
|
|
22
23
|
/* eslint-disable no-continue */
|
|
23
24
|
// eslint-disable-next-line no-restricted-syntax
|
|
@@ -32,6 +33,14 @@ export function createExcerpt(fileString: string): string | undefined {
|
|
|
32
33
|
continue;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
// Skip code block line.
|
|
37
|
+
if (fileLine.trim().startsWith('```')) {
|
|
38
|
+
inCode = !inCode;
|
|
39
|
+
continue;
|
|
40
|
+
} else if (inCode) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
const cleanedLine = fileLine
|
|
36
45
|
// Remove HTML tags.
|
|
37
46
|
.replace(/<[^>]*>/g, '')
|
|
@@ -67,9 +76,7 @@ export function createExcerpt(fileString: string): string | undefined {
|
|
|
67
76
|
return undefined;
|
|
68
77
|
}
|
|
69
78
|
|
|
70
|
-
export function parseFrontMatter(
|
|
71
|
-
markdownFileContent: string,
|
|
72
|
-
): {
|
|
79
|
+
export function parseFrontMatter(markdownFileContent: string): {
|
|
73
80
|
frontMatter: Record<string, unknown>;
|
|
74
81
|
content: string;
|
|
75
82
|
} {
|
|
@@ -98,10 +105,11 @@ export function parseMarkdownContentTitle(
|
|
|
98
105
|
|
|
99
106
|
const content = contentUntrimmed.trim();
|
|
100
107
|
|
|
101
|
-
const IMPORT_STATEMENT =
|
|
102
|
-
|
|
103
|
-
const REGULAR_TITLE =
|
|
104
|
-
|
|
108
|
+
const IMPORT_STATEMENT =
|
|
109
|
+
/import\s+(([\w*{}\s\n,]+)from\s+)?["'\s]([@\w/_.-]+)["'\s];?|\n/.source;
|
|
110
|
+
const REGULAR_TITLE =
|
|
111
|
+
/(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>({#*[\w-]+})|#)?\n*?)/
|
|
112
|
+
.source;
|
|
105
113
|
const ALTERNATE_TITLE = /(?<pattern>\s*(?<title>[^\n]*)\s*\n[=]+)/.source;
|
|
106
114
|
|
|
107
115
|
const regularTitleMatch = new RegExp(
|
|
@@ -141,9 +149,8 @@ export function parseMarkdownString(
|
|
|
141
149
|
options?: {removeContentTitle?: boolean},
|
|
142
150
|
): ParsedMarkdown {
|
|
143
151
|
try {
|
|
144
|
-
const {frontMatter, content: contentWithoutFrontMatter} =
|
|
145
|
-
markdownFileContent
|
|
146
|
-
);
|
|
152
|
+
const {frontMatter, content: contentWithoutFrontMatter} =
|
|
153
|
+
parseFrontMatter(markdownFileContent);
|
|
147
154
|
|
|
148
155
|
const {content, contentTitle} = parseMarkdownContentTitle(
|
|
149
156
|
contentWithoutFrontMatter,
|
|
@@ -159,10 +166,8 @@ export function parseMarkdownString(
|
|
|
159
166
|
excerpt,
|
|
160
167
|
};
|
|
161
168
|
} catch (e) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
This can happen if you use special characters in frontmatter values (try using double quotes around that value).`),
|
|
165
|
-
);
|
|
169
|
+
logger.error(`Error while parsing Markdown frontmatter.
|
|
170
|
+
This can happen if you use special characters in frontmatter values (try using double quotes around that value).`);
|
|
166
171
|
throw e;
|
|
167
172
|
}
|
|
168
173
|
}
|
|
@@ -176,7 +181,7 @@ export async function parseMarkdownFile(
|
|
|
176
181
|
return parseMarkdownString(markdownString, options);
|
|
177
182
|
} catch (e) {
|
|
178
183
|
throw new Error(
|
|
179
|
-
`Error while parsing Markdown file ${source}: "${e.message}".`,
|
|
184
|
+
`Error while parsing Markdown file ${source}: "${(e as Error).message}".`,
|
|
180
185
|
);
|
|
181
186
|
}
|
|
182
187
|
}
|
package/src/mdxUtils.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
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 React from 'react';
|
|
9
|
+
import ReactDOMServer from 'react-dom/server';
|
|
10
|
+
import MDX from '@mdx-js/runtime';
|
|
11
|
+
import removeImports from 'remark-mdx-remove-imports';
|
|
12
|
+
import removeExports from 'remark-mdx-remove-exports';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Transform mdx text to plain html text
|
|
16
|
+
* Initially created to convert MDX blog posts to HTML for the RSS feed
|
|
17
|
+
* without import/export nodes
|
|
18
|
+
*
|
|
19
|
+
* TODO not ideal implementation, won't work well with MDX elements!
|
|
20
|
+
* TODO theme+global site config should be able to declare MDX comps in scope for rendering the RSS feeds
|
|
21
|
+
* see also https://github.com/facebook/docusaurus/issues/4625
|
|
22
|
+
*/
|
|
23
|
+
export function mdxToHtml(
|
|
24
|
+
mdxStr: string,
|
|
25
|
+
// TODO allow providing components/scope here, see https://github.com/mdx-js/mdx/tree/v1.6.13/packages/runtime
|
|
26
|
+
): string {
|
|
27
|
+
return ReactDOMServer.renderToString(
|
|
28
|
+
React.createElement(MDX, {remarkPlugins: [removeImports, removeExports]}, [
|
|
29
|
+
mdxStr,
|
|
30
|
+
]),
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
export function normalizeUrl(rawUrls: string[]): string {
|
|
9
|
+
const urls = [...rawUrls];
|
|
10
|
+
const resultArray = [];
|
|
11
|
+
|
|
12
|
+
let hasStartingSlash = false;
|
|
13
|
+
let hasEndingSlash = false;
|
|
14
|
+
|
|
15
|
+
// If the first part is a plain protocol, we combine it with the next part.
|
|
16
|
+
if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
|
|
17
|
+
const first = urls.shift();
|
|
18
|
+
urls[0] = first + urls[0];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// There must be two or three slashes in the file protocol,
|
|
22
|
+
// two slashes in anything else.
|
|
23
|
+
const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
|
|
24
|
+
urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement);
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line
|
|
27
|
+
for (let i = 0; i < urls.length; i++) {
|
|
28
|
+
let component = urls[i];
|
|
29
|
+
|
|
30
|
+
if (typeof component !== 'string') {
|
|
31
|
+
throw new TypeError(`Url must be a string. Received ${typeof component}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (component === '') {
|
|
35
|
+
if (i === urls.length - 1 && hasEndingSlash) {
|
|
36
|
+
resultArray.push('/');
|
|
37
|
+
}
|
|
38
|
+
// eslint-disable-next-line
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (component !== '/') {
|
|
43
|
+
if (i > 0) {
|
|
44
|
+
// Removing the starting slashes for each component but the first.
|
|
45
|
+
component = component.replace(
|
|
46
|
+
/^[/]+/,
|
|
47
|
+
// Special case where the first element of rawUrls is empty ["", "/hello"] => /hello
|
|
48
|
+
component[0] === '/' && !hasStartingSlash ? '/' : '',
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
hasEndingSlash = component[component.length - 1] === '/';
|
|
53
|
+
// Removing the ending slashes for each component but the last.
|
|
54
|
+
// For the last component we will combine multiple slashes to a single one.
|
|
55
|
+
component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
hasStartingSlash = true;
|
|
59
|
+
resultArray.push(component);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let str = resultArray.join('/');
|
|
63
|
+
// Each input component is now separated by a single slash
|
|
64
|
+
// except the possible first plain protocol part.
|
|
65
|
+
|
|
66
|
+
// Remove trailing slash before parameters or hash.
|
|
67
|
+
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
|
|
68
|
+
|
|
69
|
+
// Replace ? in parameters with &.
|
|
70
|
+
const parts = str.split('?');
|
|
71
|
+
str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
|
|
72
|
+
|
|
73
|
+
// Dedupe forward slashes in the entire path, avoiding protocol slashes.
|
|
74
|
+
str = str.replace(/([^:]\/)\/+/g, '$1');
|
|
75
|
+
|
|
76
|
+
// Dedupe forward slashes at the beginning of the path.
|
|
77
|
+
str = str.replace(/^\/+/g, '/');
|
|
78
|
+
|
|
79
|
+
return str;
|
|
80
|
+
}
|
package/src/pathUtils.ts
CHANGED
|
@@ -16,11 +16,10 @@ const SPACE_FOR_APPENDING = 10;
|
|
|
16
16
|
const isMacOs = process.platform === `darwin`;
|
|
17
17
|
const isWindows = process.platform === `win32`;
|
|
18
18
|
|
|
19
|
-
export const isNameTooLong = (str: string): boolean =>
|
|
20
|
-
|
|
19
|
+
export const isNameTooLong = (str: string): boolean =>
|
|
20
|
+
isMacOs || isWindows
|
|
21
21
|
? str.length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_CHARS // MacOS (APFS) and Windows (NTFS) filename length limit (255 chars)
|
|
22
22
|
: Buffer.from(str).length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_BYTES; // Other (255 bytes)
|
|
23
|
-
};
|
|
24
23
|
|
|
25
24
|
export const shortName = (str: string): string => {
|
|
26
25
|
if (isMacOs || isWindows) {
|
package/src/slugger.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
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 GithubSlugger from 'github-slugger';
|
|
9
|
+
|
|
10
|
+
// We create our own abstraction on top of the lib:
|
|
11
|
+
// - unify usage everywhere in the codebase
|
|
12
|
+
// - ability to add extra options
|
|
13
|
+
export type SluggerOptions = {maintainCase?: boolean};
|
|
14
|
+
|
|
15
|
+
export type Slugger = {
|
|
16
|
+
slug: (value: string, options?: SluggerOptions) => string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function createSlugger(): Slugger {
|
|
20
|
+
const githubSlugger = new GithubSlugger();
|
|
21
|
+
return {
|
|
22
|
+
slug: (value, options) => githubSlugger.slug(value, options?.maintainCase),
|
|
23
|
+
};
|
|
24
|
+
}
|