@docusaurus/utils 2.0.0-beta.12faed89d → 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.
Files changed (85) hide show
  1. package/lib/constants.d.ts +20 -0
  2. package/lib/constants.d.ts.map +1 -0
  3. package/lib/constants.js +27 -0
  4. package/lib/constants.js.map +1 -0
  5. package/lib/escapePath.d.ts +1 -0
  6. package/lib/escapePath.d.ts.map +1 -0
  7. package/lib/escapePath.js +1 -0
  8. package/lib/escapePath.js.map +1 -0
  9. package/lib/globUtils.d.ts +12 -0
  10. package/lib/globUtils.d.ts.map +1 -0
  11. package/lib/globUtils.js +48 -0
  12. package/lib/globUtils.js.map +1 -0
  13. package/lib/hashUtils.d.ts +1 -0
  14. package/lib/hashUtils.d.ts.map +1 -0
  15. package/lib/hashUtils.js +5 -4
  16. package/lib/hashUtils.js.map +1 -0
  17. package/lib/index.d.ts +11 -6
  18. package/lib/index.d.ts.map +1 -0
  19. package/lib/index.js +43 -95
  20. package/lib/index.js.map +1 -0
  21. package/lib/markdownLinks.d.ts +1 -0
  22. package/lib/markdownLinks.d.ts.map +1 -0
  23. package/lib/markdownLinks.js +20 -6
  24. package/lib/markdownLinks.js.map +1 -0
  25. package/lib/markdownParser.d.ts +1 -0
  26. package/lib/markdownParser.d.ts.map +1 -0
  27. package/lib/markdownParser.js +17 -8
  28. package/lib/markdownParser.js.map +1 -0
  29. package/lib/mdxUtils.d.ts +17 -0
  30. package/lib/mdxUtils.d.ts.map +1 -0
  31. package/lib/mdxUtils.js +31 -0
  32. package/lib/mdxUtils.js.map +1 -0
  33. package/lib/normalizeUrl.d.ts +8 -0
  34. package/lib/normalizeUrl.d.ts.map +1 -0
  35. package/lib/normalizeUrl.js +67 -0
  36. package/lib/normalizeUrl.js.map +1 -0
  37. package/lib/pathUtils.d.ts +1 -0
  38. package/lib/pathUtils.d.ts.map +1 -0
  39. package/lib/pathUtils.js +4 -5
  40. package/lib/pathUtils.js.map +1 -0
  41. package/lib/posixPath.d.ts +1 -0
  42. package/lib/posixPath.d.ts.map +1 -0
  43. package/lib/posixPath.js +1 -0
  44. package/lib/posixPath.js.map +1 -0
  45. package/lib/slugger.d.ts +14 -0
  46. package/lib/slugger.d.ts.map +1 -0
  47. package/lib/slugger.js +19 -0
  48. package/lib/slugger.js.map +1 -0
  49. package/lib/tags.d.ts +19 -0
  50. package/lib/tags.d.ts.map +1 -0
  51. package/lib/tags.js +73 -0
  52. package/lib/tags.js.map +1 -0
  53. package/lib/webpackUtils.d.ts +30 -0
  54. package/lib/webpackUtils.d.ts.map +1 -0
  55. package/lib/webpackUtils.js +110 -0
  56. package/lib/webpackUtils.js.map +1 -0
  57. package/package.json +25 -8
  58. package/src/constants.ts +38 -0
  59. package/src/deps.d.ts +14 -0
  60. package/src/globUtils.ts +63 -0
  61. package/src/index.ts +25 -95
  62. package/src/markdownLinks.ts +19 -8
  63. package/src/markdownParser.ts +21 -16
  64. package/src/mdxUtils.ts +32 -0
  65. package/src/normalizeUrl.ts +80 -0
  66. package/src/pathUtils.ts +2 -3
  67. package/src/slugger.ts +24 -0
  68. package/src/tags.ts +100 -0
  69. package/src/webpackUtils.ts +144 -0
  70. package/lib/.tsbuildinfo +0 -1
  71. package/lib/codeTranslationsUtils.d.ts +0 -11
  72. package/lib/codeTranslationsUtils.js +0 -50
  73. package/src/__tests__/__fixtures__/defaultCodeTranslations/en.json +0 -4
  74. package/src/__tests__/__fixtures__/defaultCodeTranslations/fr-FR.json +0 -5
  75. package/src/__tests__/__fixtures__/defaultCodeTranslations/fr.json +0 -4
  76. package/src/__tests__/__snapshots__/index.test.ts.snap +0 -8
  77. package/src/__tests__/codeTranslationsUtils.test.ts +0 -112
  78. package/src/__tests__/escapePath.test.ts +0 -25
  79. package/src/__tests__/hashUtils.test.ts +0 -51
  80. package/src/__tests__/index.test.ts +0 -631
  81. package/src/__tests__/markdownParser.test.ts +0 -817
  82. package/src/__tests__/pathUtils.test.ts +0 -63
  83. package/src/__tests__/posixPath.test.ts +0 -25
  84. package/src/codeTranslationsUtils.ts +0 -56
  85. 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.12faed89d",
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/types": "2.0.0-beta.12faed89d",
22
- "@types/github-slugger": "^1.3.0",
23
- "chalk": "^4.1.1",
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.2.0"
35
+ "tslib": "^2.3.1",
36
+ "url-loader": "^4.1.1"
30
37
  },
31
38
  "engines": {
32
- "node": ">=12.13.0"
39
+ "node": ">=14"
33
40
  },
34
41
  "devDependencies": {
42
+ "@docusaurus/types": "2.0.0-beta.14",
35
43
  "@types/dedent": "^0.7.0",
36
- "dedent": "^0.7.0"
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": "1430dbacfbe9da59a17ce395ed29bdbddaf90049"
55
+ "gitHead": "c4824a8937d8f1aa0806667749cbc74058e2b294"
39
56
  }
@@ -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';
@@ -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 chalk from 'chalk';
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,19 +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 './codeTranslationsUtils';
30
35
  export * from './markdownParser';
31
36
  export * from './markdownLinks';
32
37
  export * from './escapePath';
38
+ export * from './slugger';
33
39
  export {md5Hash, simpleHash, docuHash} from './hashUtils';
40
+ export {
41
+ Globby,
42
+ GlobExcludeDefault,
43
+ createMatcher,
44
+ createAbsoluteFilePathMatcher,
45
+ } from './globUtils';
46
+ export * from './webpackUtils';
34
47
 
35
48
  const fileHash = new Map();
36
49
  export async function generate(
@@ -184,80 +197,6 @@ export function getSubFolder(file: string, refDir: string): string | null {
184
197
  return match && match[1];
185
198
  }
186
199
 
187
- export function normalizeUrl(rawUrls: string[]): string {
188
- const urls = [...rawUrls];
189
- const resultArray = [];
190
-
191
- let hasStartingSlash = false;
192
- let hasEndingSlash = false;
193
-
194
- // If the first part is a plain protocol, we combine it with the next part.
195
- if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
196
- const first = urls.shift();
197
- urls[0] = first + urls[0];
198
- }
199
-
200
- // There must be two or three slashes in the file protocol,
201
- // two slashes in anything else.
202
- const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
203
- urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement);
204
-
205
- // eslint-disable-next-line
206
- for (let i = 0; i < urls.length; i++) {
207
- let component = urls[i];
208
-
209
- if (typeof component !== 'string') {
210
- throw new TypeError(`Url must be a string. Received ${typeof component}`);
211
- }
212
-
213
- if (component === '') {
214
- if (i === urls.length - 1 && hasEndingSlash) {
215
- resultArray.push('/');
216
- }
217
- // eslint-disable-next-line
218
- continue;
219
- }
220
-
221
- if (component !== '/') {
222
- if (i > 0) {
223
- // Removing the starting slashes for each component but the first.
224
- component = component.replace(
225
- /^[/]+/,
226
- // Special case where the first element of rawUrls is empty ["", "/hello"] => /hello
227
- component[0] === '/' && !hasStartingSlash ? '/' : '',
228
- );
229
- }
230
-
231
- hasEndingSlash = component[component.length - 1] === '/';
232
- // Removing the ending slashes for each component but the last.
233
- // For the last component we will combine multiple slashes to a single one.
234
- component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/');
235
- }
236
-
237
- hasStartingSlash = true;
238
- resultArray.push(component);
239
- }
240
-
241
- let str = resultArray.join('/');
242
- // Each input component is now separated by a single slash
243
- // except the possible first plain protocol part.
244
-
245
- // Remove trailing slash before parameters or hash.
246
- str = str.replace(/\/(\?|&|#[^!])/g, '$1');
247
-
248
- // Replace ? in parameters with &.
249
- const parts = str.split('?');
250
- str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
251
-
252
- // Dedupe forward slashes in the entire path, avoiding protocol slashes.
253
- str = str.replace(/([^:]\/)\/+/g, '$1');
254
-
255
- // Dedupe forward slashes at the beginning of the path.
256
- str = str.replace(/^\/+/g, '/');
257
-
258
- return str;
259
- }
260
-
261
200
  /**
262
201
  * Alias filepath relative to site directory, very useful so that we
263
202
  * don't expose user's site structure.
@@ -323,7 +262,7 @@ export function removePrefix(str: string, prefix: string): string {
323
262
  return str.startsWith(prefix) ? str.slice(prefix.length) : str;
324
263
  }
325
264
 
326
- export function getElementsAround<T extends unknown>(
265
+ export function getElementsAround<T>(
327
266
  array: T[],
328
267
  aroundIndex: number,
329
268
  ): {
@@ -346,7 +285,7 @@ export function getPluginI18nPath({
346
285
  siteDir,
347
286
  locale,
348
287
  pluginName,
349
- pluginId = 'default', // TODO duplicated constant
288
+ pluginId = DEFAULT_PLUGIN_ID,
350
289
  subPaths = [],
351
290
  }: {
352
291
  siteDir: string;
@@ -362,22 +301,18 @@ export function getPluginI18nPath({
362
301
  locale,
363
302
  // Make it convenient to use for single-instance
364
303
  // ie: return "docs", not "docs-default" nor "docs/default"
365
- `${pluginName}${
366
- // TODO duplicate constant :(
367
- pluginId === 'default' ? '' : `-${pluginId}`
368
- }`,
304
+ `${pluginName}${pluginId === DEFAULT_PLUGIN_ID ? '' : `-${pluginId}`}`,
369
305
  ...subPaths,
370
306
  );
371
307
  }
372
308
 
373
- export async function mapAsyncSequencial<T extends unknown, R extends unknown>(
309
+ export async function mapAsyncSequencial<T, R>(
374
310
  array: T[],
375
311
  action: (t: T) => Promise<R>,
376
312
  ): Promise<R[]> {
377
313
  const results: R[] = [];
378
314
  // eslint-disable-next-line no-restricted-syntax
379
315
  for (const t of array) {
380
- // eslint-disable-next-line no-await-in-loop
381
316
  const result = await action(t);
382
317
  results.push(result);
383
318
  }
@@ -390,7 +325,6 @@ export async function findAsyncSequential<T>(
390
325
  ): Promise<T | undefined> {
391
326
  // eslint-disable-next-line no-restricted-syntax
392
327
  for (const t of array) {
393
- // eslint-disable-next-line no-await-in-loop
394
328
  if (await predicate(t)) {
395
329
  return t;
396
330
  }
@@ -435,13 +369,13 @@ export function reportMessage(
435
369
  case 'ignore':
436
370
  break;
437
371
  case 'log':
438
- console.log(chalk.bold.blue('info ') + chalk.blue(message));
372
+ logger.info(message);
439
373
  break;
440
374
  case 'warn':
441
- console.warn(chalk.bold.yellow('warn ') + chalk.yellow(message));
375
+ logger.warn(message);
442
376
  break;
443
377
  case 'error':
444
- console.error(chalk.bold.red('error ') + chalk.red(message));
378
+ logger.error(message);
445
379
  break;
446
380
  case 'throw':
447
381
  throw new Error(message);
@@ -455,9 +389,7 @@ export function reportMessage(
455
389
  export function mergeTranslations(
456
390
  contents: TranslationFileContent[],
457
391
  ): TranslationFileContent {
458
- return contents.reduce((acc, content) => {
459
- return {...acc, ...content};
460
- }, {});
392
+ return contents.reduce((acc, content) => ({...acc, ...content}), {});
461
393
  }
462
394
 
463
395
  export function getSwizzledComponent(
@@ -491,9 +423,7 @@ export function updateTranslationFileMessages(
491
423
 
492
424
  // Input: ## Some heading {#some-heading}
493
425
  // Output: {text: "## Some heading", id: "some-heading"}
494
- export function parseMarkdownHeadingId(
495
- heading: string,
496
- ): {
426
+ export function parseMarkdownHeadingId(heading: string): {
497
427
  text: string;
498
428
  id?: string;
499
429
  } {
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import {resolve} from 'url';
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 aliasedSource = (source: string) =>
67
- aliasedSitePath(source, siteDir);
66
+ const sourcesToTry = [
67
+ path.resolve(path.dirname(filePath), decodeURIComponent(mdLink)),
68
+ `${contentPathLocalized}/${decodeURIComponent(mdLink)}`,
69
+ `${contentPath}/${decodeURIComponent(mdLink)}`,
70
+ ];
68
71
 
69
- const permalink: string | undefined =
70
- sourceToPermalink[aliasedSource(resolve(filePath, mdLink))] ||
71
- sourceToPermalink[aliasedSource(`${contentPathLocalized}/${mdLink}`)] ||
72
- sourceToPermalink[aliasedSource(`${contentPath}/${mdLink}`)];
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
- modifiedLine = modifiedLine.replace(mdLink, permalink);
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,
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import chalk from 'chalk';
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 = /import\s+(([\w*{}\s\n,]+)from\s+)?["'\s]([@\w/_.-]+)["'\s];?|\n/
102
- .source;
103
- const REGULAR_TITLE = /(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>({#*[\w-]+})|#)?\n*?)/
104
- .source;
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} = parseFrontMatter(
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
- console.error(
163
- chalk.red(`Error while parsing Markdown frontmatter.
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
  }
@@ -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
- return isMacOs || isWindows
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
+ }