@docusaurus/utils 2.0.0-beta.15a2b59f9 → 2.0.0-beta.17

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 (104) hide show
  1. package/lib/constants.d.ts +20 -0
  2. package/lib/constants.d.ts.map +1 -0
  3. package/lib/constants.js +26 -0
  4. package/lib/constants.js.map +1 -0
  5. package/lib/dataFileUtils.d.ts +24 -0
  6. package/lib/dataFileUtils.d.ts.map +1 -0
  7. package/lib/dataFileUtils.js +65 -0
  8. package/lib/dataFileUtils.js.map +1 -0
  9. package/lib/emitUtils.d.ts +23 -0
  10. package/lib/emitUtils.d.ts.map +1 -0
  11. package/lib/emitUtils.js +90 -0
  12. package/lib/emitUtils.js.map +1 -0
  13. package/lib/gitUtils.d.ts +17 -0
  14. package/lib/gitUtils.d.ts.map +1 -0
  15. package/lib/gitUtils.js +63 -0
  16. package/lib/gitUtils.js.map +1 -0
  17. package/lib/globUtils.d.ts +12 -0
  18. package/lib/globUtils.d.ts.map +1 -0
  19. package/lib/globUtils.js +48 -0
  20. package/lib/globUtils.js.map +1 -0
  21. package/lib/hashUtils.d.ts +1 -0
  22. package/lib/hashUtils.d.ts.map +1 -0
  23. package/lib/hashUtils.js +7 -5
  24. package/lib/hashUtils.js.map +1 -0
  25. package/lib/i18nUtils.d.ts +17 -0
  26. package/lib/i18nUtils.d.ts.map +1 -0
  27. package/lib/i18nUtils.js +40 -0
  28. package/lib/i18nUtils.js.map +1 -0
  29. package/lib/index.d.ts +15 -75
  30. package/lib/index.d.ts.map +1 -0
  31. package/lib/index.js +84 -395
  32. package/lib/index.js.map +1 -0
  33. package/lib/jsUtils.d.ts +17 -0
  34. package/lib/jsUtils.d.ts.map +1 -0
  35. package/lib/jsUtils.js +72 -0
  36. package/lib/jsUtils.js.map +1 -0
  37. package/lib/markdownLinks.d.ts +1 -0
  38. package/lib/markdownLinks.d.ts.map +1 -0
  39. package/lib/markdownLinks.js +36 -11
  40. package/lib/markdownLinks.js.map +1 -0
  41. package/lib/markdownParser.d.ts +5 -3
  42. package/lib/markdownParser.d.ts.map +1 -0
  43. package/lib/markdownParser.js +72 -52
  44. package/lib/markdownParser.js.map +1 -0
  45. package/lib/pathUtils.d.ts +44 -0
  46. package/lib/pathUtils.d.ts.map +1 -0
  47. package/lib/pathUtils.js +88 -10
  48. package/lib/pathUtils.js.map +1 -0
  49. package/lib/slugger.d.ts +14 -0
  50. package/lib/slugger.d.ts.map +1 -0
  51. package/lib/slugger.js +19 -0
  52. package/lib/slugger.js.map +1 -0
  53. package/lib/tags.d.ts +27 -0
  54. package/lib/tags.d.ts.map +1 -0
  55. package/lib/tags.js +76 -0
  56. package/lib/tags.js.map +1 -0
  57. package/lib/urlUtils.d.ts +20 -0
  58. package/lib/urlUtils.d.ts.map +1 -0
  59. package/lib/urlUtils.js +136 -0
  60. package/lib/urlUtils.js.map +1 -0
  61. package/lib/webpackUtils.d.ts +30 -0
  62. package/lib/webpackUtils.d.ts.map +1 -0
  63. package/lib/webpackUtils.js +112 -0
  64. package/lib/webpackUtils.js.map +1 -0
  65. package/package.json +20 -10
  66. package/src/constants.ts +38 -0
  67. package/src/dataFileUtils.ts +90 -0
  68. package/src/deps.d.ts +10 -0
  69. package/src/emitUtils.ts +113 -0
  70. package/src/gitUtils.ts +93 -0
  71. package/src/globUtils.ts +64 -0
  72. package/src/hashUtils.ts +3 -3
  73. package/src/i18nUtils.ts +58 -0
  74. package/src/index.ts +87 -502
  75. package/src/jsUtils.ts +88 -0
  76. package/src/markdownLinks.ts +35 -13
  77. package/src/markdownParser.ts +76 -57
  78. package/src/pathUtils.ts +87 -8
  79. package/src/slugger.ts +24 -0
  80. package/src/tags.ts +105 -0
  81. package/src/urlUtils.ts +149 -0
  82. package/src/webpackUtils.ts +146 -0
  83. package/lib/.tsbuildinfo +0 -1
  84. package/lib/codeTranslationsUtils.d.ts +0 -11
  85. package/lib/codeTranslationsUtils.js +0 -50
  86. package/lib/escapePath.d.ts +0 -17
  87. package/lib/escapePath.js +0 -25
  88. package/lib/posixPath.d.ts +0 -14
  89. package/lib/posixPath.js +0 -28
  90. package/src/__tests__/__fixtures__/defaultCodeTranslations/en.json +0 -4
  91. package/src/__tests__/__fixtures__/defaultCodeTranslations/fr-FR.json +0 -5
  92. package/src/__tests__/__fixtures__/defaultCodeTranslations/fr.json +0 -4
  93. package/src/__tests__/__snapshots__/index.test.ts.snap +0 -8
  94. package/src/__tests__/codeTranslationsUtils.test.ts +0 -112
  95. package/src/__tests__/escapePath.test.ts +0 -25
  96. package/src/__tests__/hashUtils.test.ts +0 -51
  97. package/src/__tests__/index.test.ts +0 -631
  98. package/src/__tests__/markdownParser.test.ts +0 -817
  99. package/src/__tests__/pathUtils.test.ts +0 -63
  100. package/src/__tests__/posixPath.test.ts +0 -25
  101. package/src/codeTranslationsUtils.ts +0 -56
  102. package/src/escapePath.ts +0 -23
  103. package/src/posixPath.ts +0 -27
  104. package/tsconfig.json +0 -9
@@ -0,0 +1,113 @@
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 fs from 'fs-extra';
10
+ import {createHash} from 'crypto';
11
+ import {simpleHash, docuHash} from './hashUtils';
12
+ import {findAsyncSequential} from './jsUtils';
13
+
14
+ const fileHash = new Map<string, string>();
15
+
16
+ export async function generate(
17
+ generatedFilesDir: string,
18
+ file: string,
19
+ content: string,
20
+ skipCache: boolean = process.env.NODE_ENV === 'production',
21
+ ): Promise<void> {
22
+ const filepath = path.join(generatedFilesDir, file);
23
+
24
+ if (skipCache) {
25
+ await fs.ensureDir(path.dirname(filepath));
26
+ await fs.writeFile(filepath, content);
27
+ return;
28
+ }
29
+
30
+ let lastHash = fileHash.get(filepath);
31
+
32
+ // If file already exists but its not in runtime cache yet,
33
+ // we try to calculate the content hash and then compare
34
+ // This is to avoid unnecessary overwriting and we can reuse old file.
35
+ if (!lastHash && (await fs.pathExists(filepath))) {
36
+ const lastContent = await fs.readFile(filepath, 'utf8');
37
+ lastHash = createHash('md5').update(lastContent).digest('hex');
38
+ fileHash.set(filepath, lastHash);
39
+ }
40
+
41
+ const currentHash = createHash('md5').update(content).digest('hex');
42
+
43
+ if (lastHash !== currentHash) {
44
+ await fs.ensureDir(path.dirname(filepath));
45
+ await fs.writeFile(filepath, content);
46
+ fileHash.set(filepath, currentHash);
47
+ }
48
+ }
49
+
50
+ const chunkNameCache = new Map();
51
+
52
+ /**
53
+ * Generate unique chunk name given a module path.
54
+ */
55
+ export function genChunkName(
56
+ modulePath: string,
57
+ prefix?: string,
58
+ preferredName?: string,
59
+ shortId: boolean = process.env.NODE_ENV === 'production',
60
+ ): string {
61
+ let chunkName: string | undefined = chunkNameCache.get(modulePath);
62
+ if (!chunkName) {
63
+ if (shortId) {
64
+ chunkName = simpleHash(modulePath, 8);
65
+ } else {
66
+ let str = modulePath;
67
+ if (preferredName) {
68
+ const shortHash = simpleHash(modulePath, 3);
69
+ str = `${preferredName}${shortHash}`;
70
+ }
71
+ const name = str === '/' ? 'index' : docuHash(str);
72
+ chunkName = prefix ? `${prefix}---${name}` : name;
73
+ }
74
+ chunkNameCache.set(modulePath, chunkName);
75
+ }
76
+ return chunkName;
77
+ }
78
+
79
+ /**
80
+ * @param permalink The URL that the HTML file corresponds to, without base URL
81
+ * @param outDir Full path to the output directory
82
+ * @param trailingSlash The site config option. If provided, only one path will
83
+ * be read.
84
+ * @returns This returns a buffer, which you have to decode string yourself if
85
+ * needed. (Not always necessary since the output isn't for human consumption
86
+ * anyways, and most HTML manipulation libs accept buffers)
87
+ */
88
+ export async function readOutputHTMLFile(
89
+ permalink: string,
90
+ outDir: string,
91
+ trailingSlash: boolean | undefined,
92
+ ): Promise<Buffer> {
93
+ const withTrailingSlashPath = path.join(outDir, permalink, 'index.html');
94
+ const withoutTrailingSlashPath = path.join(
95
+ outDir,
96
+ `${permalink.replace(/\/$/, '')}.html`,
97
+ );
98
+ if (trailingSlash) {
99
+ return fs.readFile(withTrailingSlashPath);
100
+ } else if (trailingSlash === false) {
101
+ return fs.readFile(withoutTrailingSlashPath);
102
+ }
103
+ const HTMLPath = await findAsyncSequential(
104
+ [withTrailingSlashPath, withoutTrailingSlashPath],
105
+ fs.pathExists,
106
+ );
107
+ if (!HTMLPath) {
108
+ throw new Error(
109
+ `Expected output HTML file to be found at ${withTrailingSlashPath}`,
110
+ );
111
+ }
112
+ return fs.readFile(HTMLPath);
113
+ }
@@ -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
+ };
@@ -0,0 +1,64 @@
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
+ import Micromatch from 'micromatch'; // Note: Micromatch is used by Globby
11
+ import path from 'path';
12
+
13
+ export {default as Globby} from 'globby';
14
+
15
+ // The default patterns we ignore when globbing
16
+ // using _ prefix for exclusion by convention
17
+ export const GlobExcludeDefault = [
18
+ // Ignore files starting with _
19
+ '**/_*.{js,jsx,ts,tsx,md,mdx}',
20
+
21
+ // Ignore folders starting with _ (including folder content)
22
+ '**/_*/**',
23
+
24
+ // Ignore tests
25
+ '**/*.test.{js,jsx,ts,tsx}',
26
+ '**/__tests__/**',
27
+ ];
28
+
29
+ type Matcher = (str: string) => boolean;
30
+
31
+ export function createMatcher(patterns: string[]): Matcher {
32
+ const regexp = new RegExp(
33
+ patterns.map((pattern) => Micromatch.makeRe(pattern).source).join('|'),
34
+ );
35
+ return (str) => regexp.test(str);
36
+ }
37
+
38
+ // We use match patterns like '**/_*/**',
39
+ // This function permits to help to:
40
+ // Match /user/sebastien/website/docs/_partials/xyz.md
41
+ // Ignore /user/_sebastien/website/docs/partials/xyz.md
42
+ export function createAbsoluteFilePathMatcher(
43
+ patterns: string[],
44
+ rootFolders: string[],
45
+ ): Matcher {
46
+ const matcher = createMatcher(patterns);
47
+
48
+ function getRelativeFilePath(absoluteFilePath: string) {
49
+ const rootFolder = rootFolders.find((folderPath) =>
50
+ absoluteFilePath.startsWith(folderPath),
51
+ );
52
+ if (!rootFolder) {
53
+ throw new Error(
54
+ `createAbsoluteFilePathMatcher unexpected error, absoluteFilePath=${absoluteFilePath} was not contained in any of the root folders ${JSON.stringify(
55
+ rootFolders,
56
+ )}`,
57
+ );
58
+ }
59
+ return path.relative(rootFolder, absoluteFilePath);
60
+ }
61
+
62
+ return (absoluteFilePath: string) =>
63
+ matcher(getRelativeFilePath(absoluteFilePath));
64
+ }
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
  }
@@ -0,0 +1,58 @@
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 _ from 'lodash';
10
+ import type {TranslationFileContent, TranslationFile} from '@docusaurus/types';
11
+ import {DEFAULT_PLUGIN_ID} from './constants';
12
+
13
+ export function mergeTranslations(
14
+ contents: TranslationFileContent[],
15
+ ): TranslationFileContent {
16
+ return contents.reduce((acc, content) => ({...acc, ...content}), {});
17
+ }
18
+
19
+ // Useful to update all the messages of a translation file
20
+ // Used in tests to simulate translations
21
+ export function updateTranslationFileMessages(
22
+ translationFile: TranslationFile,
23
+ updateMessage: (message: string) => string,
24
+ ): TranslationFile {
25
+ return {
26
+ ...translationFile,
27
+ content: _.mapValues(translationFile.content, (translation) => ({
28
+ ...translation,
29
+ message: updateMessage(translation.message),
30
+ })),
31
+ };
32
+ }
33
+
34
+ export function getPluginI18nPath({
35
+ siteDir,
36
+ locale,
37
+ pluginName,
38
+ pluginId = DEFAULT_PLUGIN_ID,
39
+ subPaths = [],
40
+ }: {
41
+ siteDir: string;
42
+ locale: string;
43
+ pluginName: string;
44
+ pluginId?: string | undefined;
45
+ subPaths?: string[];
46
+ }): string {
47
+ return path.join(
48
+ siteDir,
49
+ 'i18n',
50
+ // namespace first by locale: convenient to work in a single folder for a
51
+ // translator
52
+ locale,
53
+ // Make it convenient to use for single-instance
54
+ // ie: return "docs", not "docs-default" nor "docs/default"
55
+ `${pluginName}${pluginId === DEFAULT_PLUGIN_ID ? '' : `-${pluginId}`}`,
56
+ ...subPaths,
57
+ );
58
+ }