@docusaurus/utils 2.0.0-beta.15 → 2.0.0-beta.16

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 (44) hide show
  1. package/lib/dataFileUtils.js +2 -2
  2. package/lib/dataFileUtils.js.map +1 -1
  3. package/lib/gitUtils.d.ts +17 -0
  4. package/lib/gitUtils.d.ts.map +1 -0
  5. package/lib/gitUtils.js +63 -0
  6. package/lib/gitUtils.js.map +1 -0
  7. package/lib/hashUtils.js +4 -3
  8. package/lib/hashUtils.js.map +1 -1
  9. package/lib/index.d.ts +14 -12
  10. package/lib/index.d.ts.map +1 -1
  11. package/lib/index.js +75 -29
  12. package/lib/index.js.map +1 -1
  13. package/lib/markdownLinks.d.ts.map +1 -1
  14. package/lib/markdownLinks.js +8 -5
  15. package/lib/markdownLinks.js.map +1 -1
  16. package/lib/markdownParser.d.ts.map +1 -1
  17. package/lib/markdownParser.js +35 -35
  18. package/lib/markdownParser.js.map +1 -1
  19. package/lib/pathUtils.d.ts +14 -1
  20. package/lib/pathUtils.d.ts.map +1 -1
  21. package/lib/pathUtils.js +19 -11
  22. package/lib/pathUtils.js.map +1 -1
  23. package/lib/tags.d.ts +8 -0
  24. package/lib/tags.d.ts.map +1 -1
  25. package/lib/tags.js +18 -13
  26. package/lib/tags.js.map +1 -1
  27. package/lib/urlUtils.d.ts.map +1 -1
  28. package/lib/urlUtils.js +11 -10
  29. package/lib/urlUtils.js.map +1 -1
  30. package/lib/webpackUtils.d.ts.map +1 -1
  31. package/lib/webpackUtils.js +11 -9
  32. package/lib/webpackUtils.js.map +1 -1
  33. package/package.json +12 -20
  34. package/src/dataFileUtils.ts +2 -2
  35. package/src/deps.d.ts +0 -4
  36. package/src/gitUtils.ts +93 -0
  37. package/src/hashUtils.ts +3 -3
  38. package/src/index.ts +86 -32
  39. package/src/markdownLinks.ts +9 -5
  40. package/src/markdownParser.ts +35 -33
  41. package/src/pathUtils.ts +19 -11
  42. package/src/tags.ts +17 -13
  43. package/src/urlUtils.ts +11 -10
  44. package/src/webpackUtils.ts +11 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/utils",
3
- "version": "2.0.0-beta.15",
3
+ "version": "2.0.0-beta.16",
4
4
  "description": "Node utility functions for Docusaurus packages.",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -18,40 +18,32 @@
18
18
  },
19
19
  "license": "MIT",
20
20
  "dependencies": {
21
- "@docusaurus/logger": "2.0.0-beta.15",
22
- "@mdx-js/runtime": "^1.6.22",
21
+ "@docusaurus/logger": "2.0.0-beta.16",
23
22
  "@svgr/webpack": "^6.0.0",
24
23
  "file-loader": "^6.2.0",
25
- "fs-extra": "^10.0.0",
24
+ "fs-extra": "^10.0.1",
26
25
  "github-slugger": "^1.4.0",
27
26
  "globby": "^11.0.4",
28
27
  "gray-matter": "^4.0.3",
29
- "js-yaml": "^4.0.0",
30
- "lodash": "^4.17.20",
28
+ "js-yaml": "^4.1.0",
29
+ "lodash": "^4.17.21",
31
30
  "micromatch": "^4.0.4",
32
- "remark-mdx-remove-exports": "^1.6.22",
33
- "remark-mdx-remove-imports": "^1.6.22",
34
31
  "resolve-pathname": "^3.0.0",
32
+ "shelljs": "^0.8.5",
35
33
  "tslib": "^2.3.1",
36
- "url-loader": "^4.1.1"
34
+ "url-loader": "^4.1.1",
35
+ "webpack": "^5.69.1"
37
36
  },
38
37
  "engines": {
39
38
  "node": ">=14"
40
39
  },
41
40
  "devDependencies": {
42
- "@docusaurus/types": "2.0.0-beta.15",
41
+ "@docusaurus/types": "2.0.0-beta.16",
43
42
  "@types/dedent": "^0.7.0",
44
43
  "@types/github-slugger": "^1.3.0",
45
44
  "@types/micromatch": "^4.0.2",
46
- "@types/react-dom": "^17.0.1",
47
- "dedent": "^0.7.0",
48
- "tslib": "^2.3.1"
45
+ "@types/react-dom": "^17.0.11",
46
+ "dedent": "^0.7.0"
49
47
  },
50
- "peerDependencies": {
51
- "@babel/core": "^7.0.0",
52
- "react": "*",
53
- "react-dom": "*",
54
- "webpack": "5.x"
55
- },
56
- "gitHead": "32ec84ef3c0a238436e913b2026ab809e5750fa8"
48
+ "gitHead": "eb43c4d4f95a4fb97dc9bb9dc615413e0dc2e1e7"
57
49
  }
@@ -48,10 +48,10 @@ export async function getDataFileData<T>(
48
48
  const contentString = await fs.readFile(filePath, {encoding: 'utf8'});
49
49
  const unsafeContent = Yaml.load(contentString);
50
50
  return validate(unsafeContent);
51
- } catch (e) {
51
+ } catch (err) {
52
52
  // TODO replace later by error cause, see https://v8.dev/features/error-cause
53
53
  logger.error`The ${params.fileType} file at path=${filePath} looks invalid.`;
54
- throw e;
54
+ throw err;
55
55
  }
56
56
  }
57
57
 
package/src/deps.d.ts CHANGED
@@ -8,7 +8,3 @@
8
8
  declare module 'resolve-pathname' {
9
9
  export default function resolvePathname(to: string, from?: string): string;
10
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,93 @@
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 path from 'path';
9
+ import shell from 'shelljs';
10
+
11
+ export class GitNotFoundError extends Error {}
12
+
13
+ export const getFileCommitDate = (
14
+ file: string,
15
+ {
16
+ age = 'oldest',
17
+ includeAuthor = false,
18
+ }: {
19
+ age?: 'oldest' | 'newest';
20
+ includeAuthor?: boolean;
21
+ },
22
+ ): {
23
+ date: Date;
24
+ timestamp: number;
25
+ author?: string;
26
+ } => {
27
+ if (!shell.which('git')) {
28
+ throw new GitNotFoundError(
29
+ `Failed to retrieve git history for "${file}" because git is not installed.`,
30
+ );
31
+ }
32
+
33
+ if (!shell.test('-f', file)) {
34
+ throw new Error(
35
+ `Failed to retrieve git history for "${file}" because the file does not exist.`,
36
+ );
37
+ }
38
+
39
+ const fileBasename = path.basename(file);
40
+ const fileDirname = path.dirname(file);
41
+
42
+ let formatArg = '--format=%ct';
43
+ if (includeAuthor) {
44
+ formatArg += ',%an';
45
+ }
46
+
47
+ let extraArgs = '--max-count=1';
48
+ if (age === 'oldest') {
49
+ // --follow is necessary to follow file renames
50
+ // --diff-filter=A ensures we only get the commit which (A)dded the file
51
+ extraArgs += ' --follow --diff-filter=A';
52
+ }
53
+
54
+ const result = shell.exec(
55
+ `git log ${extraArgs} ${formatArg} -- "${fileBasename}"`,
56
+ {
57
+ // cwd is important, see: https://github.com/facebook/docusaurus/pull/5048
58
+ cwd: fileDirname,
59
+ silent: true,
60
+ },
61
+ );
62
+ if (result.code !== 0) {
63
+ throw new Error(
64
+ `Failed to retrieve the git history for file "${file}" with exit code ${result.code}: ${result.stderr}`,
65
+ );
66
+ }
67
+ let regex = /^(?<timestamp>\d+)$/;
68
+ if (includeAuthor) {
69
+ regex = /^(?<timestamp>\d+),(?<author>.+)$/;
70
+ }
71
+
72
+ const output = result.stdout.trim();
73
+ const match = output.match(regex);
74
+
75
+ if (
76
+ !match ||
77
+ !match.groups ||
78
+ !match.groups.timestamp ||
79
+ (includeAuthor && !match.groups.author)
80
+ ) {
81
+ throw new Error(
82
+ `Failed to retrieve the git history for file "${file}" with unexpected output: ${output}`,
83
+ );
84
+ }
85
+
86
+ const timestamp = Number(match.groups.timestamp);
87
+ const date = new Date(timestamp * 1000);
88
+
89
+ if (includeAuthor) {
90
+ return {date, timestamp, author: match.groups.author};
91
+ }
92
+ return {date, timestamp};
93
+ };
package/src/hashUtils.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import {createHash} from 'crypto';
9
- import {kebabCase} from 'lodash';
9
+ import _ from 'lodash';
10
10
  import {shortName, isNameTooLong} from './pathUtils';
11
11
 
12
12
  export function md5Hash(str: string): string {
@@ -29,9 +29,9 @@ export function docuHash(str: string): string {
29
29
  return 'index';
30
30
  }
31
31
  const shortHash = simpleHash(str, 3);
32
- const parsedPath = `${kebabCase(str)}-${shortHash}`;
32
+ const parsedPath = `${_.kebabCase(str)}-${shortHash}`;
33
33
  if (isNameTooLong(parsedPath)) {
34
- return `${shortName(kebabCase(str))}-${shortHash}`;
34
+ return `${shortName(_.kebabCase(str))}-${shortHash}`;
35
35
  }
36
36
  return parsedPath;
37
37
  }
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  import logger from '@docusaurus/logger';
9
9
  import path from 'path';
10
10
  import {createHash} from 'crypto';
11
- import {mapValues} from 'lodash';
11
+ import _ from 'lodash';
12
12
  import fs from 'fs-extra';
13
13
  import {URL} from 'url';
14
14
  import type {
@@ -22,17 +22,69 @@ import resolvePathnameUnsafe from 'resolve-pathname';
22
22
  import {simpleHash, docuHash} from './hashUtils';
23
23
  import {DEFAULT_PLUGIN_ID} from './constants';
24
24
 
25
- export * from './constants';
26
- export * from './urlUtils';
27
- export * from './tags';
28
- export * from './markdownParser';
29
- export * from './markdownLinks';
30
- export * from './slugger';
31
- export * from './pathUtils';
32
- export * from './hashUtils';
33
- export * from './globUtils';
34
- export * from './webpackUtils';
35
- export * from './dataFileUtils';
25
+ export {
26
+ NODE_MAJOR_VERSION,
27
+ NODE_MINOR_VERSION,
28
+ DEFAULT_BUILD_DIR_NAME,
29
+ DEFAULT_CONFIG_FILE_NAME,
30
+ BABEL_CONFIG_FILE_NAME,
31
+ GENERATED_FILES_DIR_NAME,
32
+ SRC_DIR_NAME,
33
+ STATIC_DIR_NAME,
34
+ OUTPUT_STATIC_ASSETS_DIR_NAME,
35
+ THEME_PATH,
36
+ DEFAULT_PORT,
37
+ DEFAULT_PLUGIN_ID,
38
+ WEBPACK_URL_LOADER_LIMIT,
39
+ } from './constants';
40
+ export {getFileCommitDate, GitNotFoundError} from './gitUtils';
41
+ export {normalizeUrl, getEditUrl} from './urlUtils';
42
+ export {
43
+ type Tag,
44
+ type FrontMatterTag,
45
+ type TaggedItemGroup,
46
+ normalizeFrontMatterTag,
47
+ normalizeFrontMatterTags,
48
+ groupTaggedItems,
49
+ } from './tags';
50
+ export {
51
+ parseMarkdownHeadingId,
52
+ createExcerpt,
53
+ parseFrontMatter,
54
+ parseMarkdownContentTitle,
55
+ parseMarkdownString,
56
+ } from './markdownParser';
57
+ export {
58
+ type ContentPaths,
59
+ type BrokenMarkdownLink,
60
+ type ReplaceMarkdownLinksParams,
61
+ type ReplaceMarkdownLinksReturn,
62
+ replaceMarkdownLinks,
63
+ } from './markdownLinks';
64
+ export {type SluggerOptions, type Slugger, createSlugger} from './slugger';
65
+ export {
66
+ isNameTooLong,
67
+ shortName,
68
+ posixPath,
69
+ toMessageRelativeFilePath,
70
+ aliasedSitePath,
71
+ escapePath,
72
+ } from './pathUtils';
73
+ export {md5Hash, simpleHash, docuHash} from './hashUtils';
74
+ export {
75
+ Globby,
76
+ GlobExcludeDefault,
77
+ createMatcher,
78
+ createAbsoluteFilePathMatcher,
79
+ } from './globUtils';
80
+ export {getFileLoaderUtils} from './webpackUtils';
81
+ export {
82
+ getDataFilePath,
83
+ getDataFileData,
84
+ getContentPathList,
85
+ findFolderContainingFile,
86
+ getFolderContainingFile,
87
+ } from './dataFileUtils';
36
88
 
37
89
  const fileHash = new Map<string, string>();
38
90
  export async function generate(
@@ -54,7 +106,7 @@ export async function generate(
54
106
  // If file already exists but its not in runtime cache yet,
55
107
  // we try to calculate the content hash and then compare
56
108
  // This is to avoid unnecessary overwriting and we can reuse old file.
57
- if (!lastHash && fs.existsSync(filepath)) {
109
+ if (!lastHash && (await fs.pathExists(filepath))) {
58
110
  const lastContent = await fs.readFile(filepath, 'utf8');
59
111
  lastHash = createHash('md5').update(lastContent).digest('hex');
60
112
  fileHash.set(filepath, lastHash);
@@ -69,8 +121,8 @@ export async function generate(
69
121
  }
70
122
  }
71
123
 
72
- const indexRE = /(^|.*\/)index\.(md|mdx|js|jsx|ts|tsx)$/i;
73
- const extRE = /\.(md|mdx|js|jsx|ts|tsx)$/;
124
+ const indexRE = /(?<dirname>^|.*\/)index\.(?:mdx?|jsx?|tsx?)$/i;
125
+ const extRE = /\.(?:mdx?|jsx?|tsx?)$/;
74
126
 
75
127
  /**
76
128
  * Convert filepath to url path.
@@ -126,7 +178,7 @@ export function isValidPathname(str: string): boolean {
126
178
  // weird, but is there a better way?
127
179
  const parsedPathname = new URL(str, 'https://domain.com').pathname;
128
180
  return parsedPathname === str || parsedPathname === encodeURI(str);
129
- } catch (e) {
181
+ } catch {
130
182
  return false;
131
183
  }
132
184
  }
@@ -200,7 +252,8 @@ export function getPluginI18nPath({
200
252
  return path.join(
201
253
  siteDir,
202
254
  'i18n',
203
- // namespace first by locale: convenient to work in a single folder for a translator
255
+ // namespace first by locale: convenient to work in a single folder for a
256
+ // translator
204
257
  locale,
205
258
  // Make it convenient to use for single-instance
206
259
  // ie: return "docs", not "docs-default" nor "docs/default"
@@ -212,7 +265,8 @@ export function getPluginI18nPath({
212
265
  /**
213
266
  * @param permalink The URL that the HTML file corresponds to, without base URL
214
267
  * @param outDir Full path to the output directory
215
- * @param trailingSlash The site config option. If provided, only one path will be read.
268
+ * @param trailingSlash The site config option. If provided, only one path will
269
+ * be read.
216
270
  * @returns This returns a buffer, which you have to decode string yourself if
217
271
  * needed. (Not always necessary since the output isn't for human consumption
218
272
  * anyways, and most HTML manipulation libs accept buffers)
@@ -223,23 +277,25 @@ export async function readOutputHTMLFile(
223
277
  trailingSlash: boolean | undefined,
224
278
  ): Promise<Buffer> {
225
279
  const withTrailingSlashPath = path.join(outDir, permalink, 'index.html');
226
- const withoutTrailingSlashPath = path.join(outDir, `${permalink}.html`);
280
+ const withoutTrailingSlashPath = path.join(
281
+ outDir,
282
+ `${permalink.replace(/\/$/, '')}.html`,
283
+ );
227
284
  if (trailingSlash) {
228
285
  return fs.readFile(withTrailingSlashPath);
229
286
  } else if (trailingSlash === false) {
230
287
  return fs.readFile(withoutTrailingSlashPath);
231
- } else {
232
- const HTMLPath = await findAsyncSequential(
233
- [withTrailingSlashPath, withoutTrailingSlashPath],
234
- fs.pathExists,
288
+ }
289
+ const HTMLPath = await findAsyncSequential(
290
+ [withTrailingSlashPath, withoutTrailingSlashPath],
291
+ fs.pathExists,
292
+ );
293
+ if (!HTMLPath) {
294
+ throw new Error(
295
+ `Expected output HTML file to be found at ${withTrailingSlashPath}`,
235
296
  );
236
- if (!HTMLPath) {
237
- throw new Error(
238
- `Expected output HTML file to be found at ${withTrailingSlashPath}`,
239
- );
240
- }
241
- return fs.readFile(HTMLPath);
242
297
  }
298
+ return fs.readFile(HTMLPath);
243
299
  }
244
300
 
245
301
  export async function mapAsyncSequential<T, R>(
@@ -247,7 +303,6 @@ export async function mapAsyncSequential<T, R>(
247
303
  action: (t: T) => Promise<R>,
248
304
  ): Promise<R[]> {
249
305
  const results: R[] = [];
250
- // eslint-disable-next-line no-restricted-syntax
251
306
  for (const t of array) {
252
307
  const result = await action(t);
253
308
  results.push(result);
@@ -259,7 +314,6 @@ export async function findAsyncSequential<T>(
259
314
  array: T[],
260
315
  predicate: (t: T) => Promise<boolean>,
261
316
  ): Promise<T | undefined> {
262
- // eslint-disable-next-line no-restricted-syntax
263
317
  for (const t of array) {
264
318
  if (await predicate(t)) {
265
319
  return t;
@@ -307,7 +361,7 @@ export function updateTranslationFileMessages(
307
361
  ): TranslationFile {
308
362
  return {
309
363
  ...translationFile,
310
- content: mapValues(translationFile.content, (translation) => ({
364
+ content: _.mapValues(translationFile.content, (translation) => ({
311
365
  ...translation,
312
366
  message: updateMessage(translation.message),
313
367
  })),
@@ -51,7 +51,8 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
51
51
  if (!fencedBlock) {
52
52
  fencedBlock = true;
53
53
  [lastCodeFence] = line.trim().match(/^`+/)!;
54
- // If we are in a ````-fenced block, all ``` would be plain text instead of fences
54
+ // If we are in a ````-fenced block, all ``` would be plain text instead
55
+ // of fences
55
56
  } else if (line.trim().match(/^`+/)![0].length >= lastCodeFence.length) {
56
57
  fencedBlock = false;
57
58
  }
@@ -62,13 +63,15 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
62
63
 
63
64
  let modifiedLine = line;
64
65
  // Replace inline-style links or reference-style links e.g:
65
- // This is [Document 1](doc1.md) -> we replace this doc1.md with correct link
66
+ // This is [Document 1](doc1.md) -> we replace this doc1.md with correct
67
+ // ink
66
68
  // [doc1]: doc1.md -> we replace this doc1.md with correct link
67
- const mdRegex = /(?:(?:\]\()|(?:\]:\s?))(?!https?)([^'")\]\s>]+\.mdx?)/g;
69
+ const mdRegex =
70
+ /(?:(?:\]\()|(?:\]:\s*))(?!https?:\/\/|@site\/)(?<filename>[^'")\]\s>]+\.mdx?)/g;
68
71
  let mdMatch = mdRegex.exec(modifiedLine);
69
72
  while (mdMatch !== null) {
70
73
  // Replace it to correct html link.
71
- const mdLink = mdMatch[1];
74
+ const mdLink = mdMatch.groups!.filename;
72
75
 
73
76
  const sourcesToTry = [
74
77
  path.resolve(path.dirname(filePath), decodeURIComponent(mdLink)),
@@ -85,7 +88,8 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
85
88
  : undefined;
86
89
 
87
90
  if (permalink) {
88
- // MDX won't be happy if the permalink contains a space, we need to convert it to %20
91
+ // MDX won't be happy if the permalink contains a space, we need to
92
+ // convert it to %20
89
93
  const encodedPermalink = permalink
90
94
  .split('/')
91
95
  .map((part) => part.replace(/\s/g, '%20'))
@@ -14,16 +14,15 @@ export function parseMarkdownHeadingId(heading: string): {
14
14
  text: string;
15
15
  id?: string;
16
16
  } {
17
- const customHeadingIdRegex = /^(.*?)\s*\{#([\w-]+)\}$/;
17
+ const customHeadingIdRegex = /^(?<text>.*?)\s*\{#(?<id>[\w-]+)\}$/;
18
18
  const matches = customHeadingIdRegex.exec(heading);
19
19
  if (matches) {
20
20
  return {
21
- text: matches[1],
22
- id: matches[2],
21
+ text: matches.groups!.text,
22
+ id: matches.groups!.id,
23
23
  };
24
- } else {
25
- return {text: heading, id: undefined};
26
24
  }
25
+ return {text: heading, id: undefined};
27
26
  }
28
27
 
29
28
  // Hacky way of stripping out import statements from the excerpt
@@ -39,7 +38,6 @@ export function createExcerpt(fileString: string): string | undefined {
39
38
  let lastCodeFence = '';
40
39
 
41
40
  /* eslint-disable no-continue */
42
- // eslint-disable-next-line no-restricted-syntax
43
41
  for (const fileLine of fileLines) {
44
42
  // Skip empty line.
45
43
  if (!fileLine.trim()) {
@@ -47,7 +45,7 @@ export function createExcerpt(fileString: string): string | undefined {
47
45
  }
48
46
 
49
47
  // Skip import/export declaration.
50
- if (/^\s*?import\s.*(from.*)?;?|export\s.*{.*};?/.test(fileLine)) {
48
+ if (/^(?:import|export)\s.*/.test(fileLine)) {
51
49
  continue;
52
50
  }
53
51
 
@@ -56,7 +54,8 @@ export function createExcerpt(fileString: string): string | undefined {
56
54
  if (!inCode) {
57
55
  inCode = true;
58
56
  [lastCodeFence] = fileLine.trim().match(/^`+/)!;
59
- // If we are in a ````-fenced block, all ``` would be plain text instead of fences
57
+ // If we are in a ````-fenced block, all ``` would be plain text instead
58
+ // of fences
60
59
  } else if (
61
60
  fileLine.trim().match(/^`+/)![0].length >= lastCodeFence.length
62
61
  ) {
@@ -71,25 +70,27 @@ export function createExcerpt(fileString: string): string | undefined {
71
70
  // Remove HTML tags.
72
71
  .replace(/<[^>]*>/g, '')
73
72
  // Remove Title headers
74
- .replace(/^#\s*([^#]*)\s*#?/gm, '')
73
+ .replace(/^#\s*[^#]*\s*#?/gm, '')
75
74
  // Remove Markdown + ATX-style headers
76
- .replace(/^#{1,6}\s*([^#]*)\s*(#{1,6})?/gm, '$1')
77
- // Remove emphasis and strikethroughs.
78
- .replace(/([*_~]{1,3})(\S.*?\S{0,1})\1/g, '$2')
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')
79
80
  // Remove images.
80
- .replace(/!\[(.*?)\][[(].*?[\])]/g, '$1')
81
+ .replace(/!\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
81
82
  // Remove footnotes.
82
- .replace(/\[\^.+?\](: .*?$)?/g, '')
83
+ .replace(/\[\^.+?\](?:: .*?$)?/g, '')
83
84
  // Remove inline links.
84
- .replace(/\[(.*?)\][[(].*?[\])]/g, '$1')
85
+ .replace(/\[(?<alt>.*?)\][[(].*?[\])]/g, '$1')
85
86
  // Remove inline code.
86
- .replace(/`(.+?)`/g, '$1')
87
+ .replace(/`(?<text>.+?)`/g, '$1')
87
88
  // Remove blockquotes.
88
89
  .replace(/^\s{0,3}>\s?/g, '')
89
90
  // Remove admonition definition.
90
- .replace(/(:{3}.*)/, '')
91
+ .replace(/:::.*/, '')
91
92
  // Remove Emoji names within colons include preceding whitespace.
92
- .replace(/\s?(:(::|[^:\n])+:)/g, '')
93
+ .replace(/\s?:(?:::|[^:\n])+:/g, '')
93
94
  // Remove custom Markdown heading id.
94
95
  .replace(/{#*[\w-]+}/, '')
95
96
  .trim();
@@ -113,9 +114,11 @@ export function parseFrontMatter(markdownFileContent: string): {
113
114
  };
114
115
  }
115
116
 
116
- // Try to convert markdown heading as text
117
- // Does not need to be perfect, it is only used as a fallback when frontMatter.title is not provided
118
- // For now, we just unwrap possible inline code blocks (# `config.js`)
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
+ */
119
122
  function toTextContentTitle(contentTitle: string): string {
120
123
  if (contentTitle.startsWith('`') && contentTitle.endsWith('`')) {
121
124
  return contentTitle.substring(1, contentTitle.length - 1);
@@ -132,9 +135,9 @@ export function parseMarkdownContentTitle(
132
135
  const content = contentUntrimmed.trim();
133
136
 
134
137
  const IMPORT_STATEMENT =
135
- /import\s+(([\w*{}\s\n,]+)from\s+)?["'\s]([@\w/_.-]+)["'\s];?|\n/.source;
138
+ /import\s+(?:[\w*{}\s\n,]+from\s+)?["'\s][@\w/_.-]+["'\s];?|\n/.source;
136
139
  const REGULAR_TITLE =
137
- /(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>({#*[\w-]+})|#)?\n*?)/
140
+ /(?<pattern>#\s*(?<title>[^#\n{]*)+[ \t]*(?<suffix>(?:{#*[\w-]+})|#)?\n*?)/
138
141
  .source;
139
142
  const ALTERNATE_TITLE = /(?<pattern>\s*(?<title>[^\n]*)\s*\n[=]+)/.source;
140
143
 
@@ -152,15 +155,14 @@ export function parseMarkdownContentTitle(
152
155
 
153
156
  if (!pattern || !title) {
154
157
  return {content, contentTitle: undefined};
155
- } else {
156
- const newContent = removeContentTitleOption
157
- ? content.replace(pattern, '')
158
- : content;
159
- return {
160
- content: newContent.trim(),
161
- contentTitle: toTextContentTitle(title.trim()).trim(),
162
- };
163
158
  }
159
+ const newContent = removeContentTitleOption
160
+ ? content.replace(pattern, '')
161
+ : content;
162
+ return {
163
+ content: newContent.trim(),
164
+ contentTitle: toTextContentTitle(title.trim()).trim(),
165
+ };
164
166
  }
165
167
 
166
168
  type ParsedMarkdown = {
@@ -191,9 +193,9 @@ export function parseMarkdownString(
191
193
  contentTitle,
192
194
  excerpt,
193
195
  };
194
- } catch (e) {
196
+ } catch (err) {
195
197
  logger.error(`Error while parsing Markdown front matter.
196
198
  This can happen if you use special characters in front matter values (try using double quotes around that value).`);
197
- throw e;
199
+ throw err;
198
200
  }
199
201
  }
package/src/pathUtils.ts CHANGED
@@ -9,7 +9,8 @@
9
9
 
10
10
  import path from 'path';
11
11
 
12
- // MacOS (APFS) and Windows (NTFS) filename length limit = 255 chars, Others = 255 bytes
12
+ // MacOS (APFS) and Windows (NTFS) filename length limit = 255 chars,
13
+ // Others = 255 bytes
13
14
  const MAX_PATH_SEGMENT_CHARS = 255;
14
15
  const MAX_PATH_SEGMENT_BYTES = 255;
15
16
  // Space for appending things to the string like file extensions and so on
@@ -19,7 +20,7 @@ const isMacOs = () => process.platform === 'darwin';
19
20
  const isWindows = () => process.platform === 'win32';
20
21
 
21
22
  export const isNameTooLong = (str: string): boolean =>
22
- // This is actually not entirely correct: we can't assume FS from OS. But good enough?
23
+ // Not entirely correct: we can't assume FS from OS. But good enough?
23
24
  isMacOs() || isWindows()
24
25
  ? str.length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_CHARS // MacOS (APFS) and Windows (NTFS) filename length limit (255 chars)
25
26
  : Buffer.from(str).length + SPACE_FOR_APPENDING > MAX_PATH_SEGMENT_BYTES; // Other (255 bytes)
@@ -56,7 +57,8 @@ export const shortName = (str: string): string => {
56
57
  export function posixPath(str: string): string {
57
58
  const isExtendedLengthPath = /^\\\\\?\\/.test(str);
58
59
 
59
- // Forward slashes are only valid Windows paths when they don't contain non-ascii characters.
60
+ // Forward slashes are only valid Windows paths when they don't contain non-
61
+ // ascii characters.
60
62
  // eslint-disable-next-line no-control-regex
61
63
  const hasNonAscii = /[^\u0000-\u0080]+/.test(str);
62
64
 
@@ -66,13 +68,18 @@ export function posixPath(str: string): string {
66
68
  return str.replace(/\\/g, '/');
67
69
  }
68
70
 
69
- // When you want to display a path in a message/warning/error,
70
- // it's more convenient to:
71
- // - make it relative to cwd()
72
- // - convert to posix (ie not using windows \ path separator)
73
- // This way, Jest tests can run more reliably on any computer/CI
74
- // on both Unix/Windows
75
- // For Windows users this is not perfect (as they see / instead of \) but it's probably good enough
71
+ /**
72
+ * When you want to display a path in a message/warning/error, it's more
73
+ * convenient to:
74
+ *
75
+ * - make it relative to `cwd()`
76
+ * - convert to posix (ie not using windows \ path separator)
77
+ *
78
+ * This way, Jest tests can run more reliably on any computer/CI on both
79
+ * Unix/Windows
80
+ * For Windows users this is not perfect (as they see / instead of \) but it's
81
+ * probably good enough
82
+ */
76
83
  export function toMessageRelativeFilePath(filePath: string): string {
77
84
  return posixPath(path.relative(process.cwd(), filePath));
78
85
  }
@@ -92,7 +99,8 @@ export function aliasedSitePath(filePath: string, siteDir: string): string {
92
99
  /**
93
100
  * When you have a path like C:\X\Y
94
101
  * It is not safe to use directly when generating code
95
- * For example, this would fail due to unescaped \: `<img src={require('${filePath}')} />`
102
+ * For example, this would fail due to unescaped \:
103
+ * `<img src={require('${filePath}')} />`
96
104
  * But this would work: `<img src={require('${escapePath(filePath)}')} />`
97
105
  *
98
106
  * posixPath can't be used in all cases, because forward slashes are only valid