@docusaurus/utils 2.0.0-beta.ff31de0ff → 2.0.1

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 (111) hide show
  1. package/README.md +1 -1
  2. package/lib/constants.d.ts +73 -0
  3. package/lib/constants.d.ts.map +1 -0
  4. package/lib/constants.js +78 -0
  5. package/lib/constants.js.map +1 -0
  6. package/lib/dataFileUtils.d.ts +60 -0
  7. package/lib/dataFileUtils.d.ts.map +1 -0
  8. package/lib/dataFileUtils.js +91 -0
  9. package/lib/dataFileUtils.js.map +1 -0
  10. package/lib/emitUtils.d.ts +32 -0
  11. package/lib/emitUtils.d.ts.map +1 -0
  12. package/lib/emitUtils.js +80 -0
  13. package/lib/emitUtils.js.map +1 -0
  14. package/lib/gitUtils.d.ts +66 -0
  15. package/lib/gitUtils.d.ts.map +1 -0
  16. package/lib/gitUtils.js +63 -0
  17. package/lib/gitUtils.js.map +1 -0
  18. package/lib/globUtils.d.ts +40 -0
  19. package/lib/globUtils.d.ts.map +1 -0
  20. package/lib/globUtils.js +71 -0
  21. package/lib/globUtils.js.map +1 -0
  22. package/lib/hashUtils.d.ts +17 -0
  23. package/lib/hashUtils.d.ts.map +1 -0
  24. package/lib/hashUtils.js +42 -0
  25. package/lib/hashUtils.js.map +1 -0
  26. package/lib/i18nUtils.d.ts +53 -0
  27. package/lib/i18nUtils.d.ts.map +1 -0
  28. package/lib/i18nUtils.js +70 -0
  29. package/lib/i18nUtils.js.map +1 -0
  30. package/lib/index.d.ts +17 -82
  31. package/lib/index.d.ts.map +1 -0
  32. package/lib/index.js +91 -411
  33. package/lib/index.js.map +1 -0
  34. package/lib/jsUtils.d.ts +28 -0
  35. package/lib/jsUtils.d.ts.map +1 -0
  36. package/lib/jsUtils.js +57 -0
  37. package/lib/jsUtils.js.map +1 -0
  38. package/lib/markdownLinks.d.ts +49 -5
  39. package/lib/markdownLinks.d.ts.map +1 -0
  40. package/lib/markdownLinks.js +57 -13
  41. package/lib/markdownLinks.js.map +1 -0
  42. package/lib/markdownUtils.d.ts +112 -0
  43. package/lib/markdownUtils.d.ts.map +1 -0
  44. package/lib/markdownUtils.js +271 -0
  45. package/lib/markdownUtils.js.map +1 -0
  46. package/lib/pathUtils.d.ts +52 -0
  47. package/lib/pathUtils.d.ts.map +1 -0
  48. package/lib/pathUtils.js +115 -0
  49. package/lib/pathUtils.js.map +1 -0
  50. package/lib/shellUtils.d.ts +8 -0
  51. package/lib/shellUtils.d.ts.map +1 -0
  52. package/lib/shellUtils.js +21 -0
  53. package/lib/shellUtils.js.map +1 -0
  54. package/lib/slugger.d.ts +24 -0
  55. package/lib/slugger.d.ts.map +1 -0
  56. package/lib/slugger.js +23 -0
  57. package/lib/slugger.js.map +1 -0
  58. package/lib/tags.d.ts +59 -0
  59. package/lib/tags.d.ts.map +1 -0
  60. package/lib/tags.js +91 -0
  61. package/lib/tags.js.map +1 -0
  62. package/lib/urlUtils.d.ts +66 -0
  63. package/lib/urlUtils.d.ts.map +1 -0
  64. package/lib/urlUtils.js +207 -0
  65. package/lib/urlUtils.js.map +1 -0
  66. package/lib/webpackUtils.d.ts +35 -0
  67. package/lib/webpackUtils.d.ts.map +1 -0
  68. package/lib/webpackUtils.js +115 -0
  69. package/lib/webpackUtils.js.map +1 -0
  70. package/package.json +28 -10
  71. package/src/constants.ts +98 -0
  72. package/src/dataFileUtils.ts +122 -0
  73. package/src/deps.d.ts +10 -0
  74. package/src/emitUtils.ts +99 -0
  75. package/src/gitUtils.ts +146 -0
  76. package/src/globUtils.ts +85 -0
  77. package/src/hashUtils.ts +38 -0
  78. package/src/i18nUtils.ts +114 -0
  79. package/src/index.ts +98 -521
  80. package/src/jsUtils.ts +59 -0
  81. package/src/markdownLinks.ts +101 -30
  82. package/src/markdownUtils.ts +357 -0
  83. package/src/pathUtils.ts +123 -0
  84. package/src/shellUtils.ts +18 -0
  85. package/src/slugger.ts +36 -0
  86. package/src/tags.ts +130 -0
  87. package/src/urlUtils.ts +234 -0
  88. package/src/webpackUtils.ts +153 -0
  89. package/lib/.tsbuildinfo +0 -3928
  90. package/lib/codeTranslationsUtils.d.ts +0 -11
  91. package/lib/codeTranslationsUtils.js +0 -50
  92. package/lib/escapePath.d.ts +0 -17
  93. package/lib/escapePath.js +0 -25
  94. package/lib/markdownParser.d.ts +0 -28
  95. package/lib/markdownParser.js +0 -132
  96. package/lib/posixPath.d.ts +0 -14
  97. package/lib/posixPath.js +0 -28
  98. package/src/__tests__/__fixtures__/defaultCodeTranslations/en.json +0 -4
  99. package/src/__tests__/__fixtures__/defaultCodeTranslations/fr-FR.json +0 -5
  100. package/src/__tests__/__fixtures__/defaultCodeTranslations/fr.json +0 -4
  101. package/src/__tests__/__snapshots__/index.test.ts.snap +0 -8
  102. package/src/__tests__/codeTranslationsUtils.test.ts +0 -112
  103. package/src/__tests__/escapePath.test.ts +0 -25
  104. package/src/__tests__/index.test.ts +0 -681
  105. package/src/__tests__/markdownParser.test.ts +0 -772
  106. package/src/__tests__/posixPath.test.ts +0 -25
  107. package/src/codeTranslationsUtils.ts +0 -56
  108. package/src/escapePath.ts +0 -23
  109. package/src/markdownParser.ts +0 -177
  110. package/src/posixPath.ts +0 -27
  111. package/tsconfig.json +0 -9
package/src/index.ts CHANGED
@@ -5,524 +5,101 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import chalk from 'chalk';
9
- import path from 'path';
10
- import {createHash} from 'crypto';
11
- import {camelCase, kebabCase, mapValues} from 'lodash';
12
- import escapeStringRegexp from 'escape-string-regexp';
13
- import fs from 'fs-extra';
14
- import {URL} from 'url';
15
- import {
16
- ReportingSeverity,
17
- TranslationFileContent,
18
- TranslationFile,
19
- } from '@docusaurus/types';
20
-
21
- // @ts-expect-error: no typedefs :s
22
- import resolvePathnameUnsafe from 'resolve-pathname';
23
-
24
- import {posixPath as posixPathImport} from './posixPath';
25
-
26
- export const posixPath = posixPathImport;
27
-
28
- export * from './codeTranslationsUtils';
29
- export * from './markdownParser';
30
- export * from './markdownLinks';
31
- export * from './escapePath';
32
-
33
- const fileHash = new Map();
34
- export async function generate(
35
- generatedFilesDir: string,
36
- file: string,
37
- content: string,
38
- skipCache: boolean = process.env.NODE_ENV === 'production',
39
- ): Promise<void> {
40
- const filepath = path.join(generatedFilesDir, file);
41
-
42
- if (skipCache) {
43
- await fs.ensureDir(path.dirname(filepath));
44
- await fs.writeFile(filepath, content);
45
- return;
46
- }
47
-
48
- let lastHash = fileHash.get(filepath);
49
-
50
- // If file already exists but its not in runtime cache yet,
51
- // we try to calculate the content hash and then compare
52
- // This is to avoid unnecessary overwriting and we can reuse old file.
53
- if (!lastHash && fs.existsSync(filepath)) {
54
- const lastContent = await fs.readFile(filepath, 'utf8');
55
- lastHash = createHash('md5').update(lastContent).digest('hex');
56
- fileHash.set(filepath, lastHash);
57
- }
58
-
59
- const currentHash = createHash('md5').update(content).digest('hex');
60
-
61
- if (lastHash !== currentHash) {
62
- await fs.ensureDir(path.dirname(filepath));
63
- await fs.writeFile(filepath, content);
64
- fileHash.set(filepath, currentHash);
65
- }
66
- }
67
-
68
- export function objectWithKeySorted<T>(
69
- obj: Record<string, T>,
70
- ): Record<string, T> {
71
- // https://github.com/lodash/lodash/issues/1459#issuecomment-460941233
72
- return Object.keys(obj)
73
- .sort()
74
- .reduce((acc: Record<string, T>, key: string) => {
75
- acc[key] = obj[key];
76
- return acc;
77
- }, {});
78
- }
79
-
80
- const indexRE = /(^|.*\/)index\.(md|mdx|js|jsx|ts|tsx)$/i;
81
- const extRE = /\.(md|mdx|js|jsx|ts|tsx)$/;
82
-
83
- /**
84
- * Convert filepath to url path.
85
- * Example: 'index.md' -> '/', 'foo/bar.js' -> '/foo/bar',
86
- */
87
- export function fileToPath(file: string): string {
88
- if (indexRE.test(file)) {
89
- return file.replace(indexRE, '/$1');
90
- }
91
- return `/${file.replace(extRE, '').replace(/\\/g, '/')}`;
92
- }
93
-
94
- export function encodePath(userpath: string): string {
95
- return userpath
96
- .split('/')
97
- .map((item) => encodeURIComponent(item))
98
- .join('/');
99
- }
100
-
101
- export function simpleHash(str: string, length: number): string {
102
- return createHash('md5').update(str).digest('hex').substr(0, length);
103
- }
104
-
105
- /**
106
- * Given an input string, convert to kebab-case and append a hash.
107
- * Avoid str collision.
108
- */
109
- export function docuHash(str: string): string {
110
- if (str === '/') {
111
- return 'index';
112
- }
113
- const shortHash = simpleHash(str, 3);
114
- return `${kebabCase(str)}-${shortHash}`;
115
- }
116
-
117
- /**
118
- * Convert first string character to the upper case.
119
- * E.g: docusaurus -> Docusaurus
120
- */
121
- export function upperFirst(str: string): string {
122
- return str ? str.charAt(0).toUpperCase() + str.slice(1) : '';
123
- }
124
-
125
- /**
126
- * Generate unique React Component Name.
127
- * E.g: /foo-bar -> FooBar096
128
- */
129
- export function genComponentName(pagePath: string): string {
130
- if (pagePath === '/') {
131
- return 'index';
132
- }
133
- const pageHash = docuHash(pagePath);
134
- return upperFirst(camelCase(pageHash));
135
- }
136
-
137
- // When you want to display a path in a message/warning/error,
138
- // it's more convenient to:
139
- // - make it relative to cwd()
140
- // - convert to posix (ie not using windows \ path separator)
141
- // This way, Jest tests can run more reliably on any computer/CI
142
- // on both Unix/Windows
143
- // For Windows users this is not perfect (as they see / instead of \) but it's probably good enough
144
- export function toMessageRelativeFilePath(filePath: string): string {
145
- return posixPath(path.relative(process.cwd(), filePath));
146
- }
147
-
148
- const chunkNameCache = new Map();
149
- /**
150
- * Generate unique chunk name given a module path.
151
- */
152
- export function genChunkName(
153
- modulePath: string,
154
- prefix?: string,
155
- preferredName?: string,
156
- shortId: boolean = process.env.NODE_ENV === 'production',
157
- ): string {
158
- let chunkName: string | undefined = chunkNameCache.get(modulePath);
159
- if (!chunkName) {
160
- if (shortId) {
161
- chunkName = simpleHash(modulePath, 8);
162
- } else {
163
- let str = modulePath;
164
- if (preferredName) {
165
- const shortHash = simpleHash(modulePath, 3);
166
- str = `${preferredName}${shortHash}`;
167
- }
168
- const name = str === '/' ? 'index' : docuHash(str);
169
- chunkName = prefix ? `${prefix}---${name}` : name;
170
- }
171
- chunkNameCache.set(modulePath, chunkName);
172
- }
173
- return chunkName;
174
- }
175
-
176
- // Too dynamic
177
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
178
- export function idx(target: any, keyPaths?: string | (string | number)[]): any {
179
- return (
180
- target &&
181
- keyPaths &&
182
- (Array.isArray(keyPaths)
183
- ? keyPaths.reduce((obj, key) => obj && obj[key], target)
184
- : target[keyPaths])
185
- );
186
- }
187
-
188
- /**
189
- * Given a filepath and dirpath, get the first directory.
190
- */
191
- export function getSubFolder(file: string, refDir: string): string | null {
192
- const separator = escapeStringRegexp(path.sep);
193
- const baseDir = escapeStringRegexp(path.basename(refDir));
194
- const regexSubFolder = new RegExp(
195
- `${baseDir}${separator}(.*?)${separator}.*`,
196
- );
197
- const match = regexSubFolder.exec(file);
198
- return match && match[1];
199
- }
200
-
201
- export function normalizeUrl(rawUrls: string[]): string {
202
- const urls = [...rawUrls];
203
- const resultArray = [];
204
-
205
- let hasStartingSlash = false;
206
- let hasEndingSlash = false;
207
-
208
- // If the first part is a plain protocol, we combine it with the next part.
209
- if (urls[0].match(/^[^/:]+:\/*$/) && urls.length > 1) {
210
- const first = urls.shift();
211
- urls[0] = first + urls[0];
212
- }
213
-
214
- // There must be two or three slashes in the file protocol,
215
- // two slashes in anything else.
216
- const replacement = urls[0].match(/^file:\/\/\//) ? '$1:///' : '$1://';
217
- urls[0] = urls[0].replace(/^([^/:]+):\/*/, replacement);
218
-
219
- // eslint-disable-next-line
220
- for (let i = 0; i < urls.length; i++) {
221
- let component = urls[i];
222
-
223
- if (typeof component !== 'string') {
224
- throw new TypeError(`Url must be a string. Received ${typeof component}`);
225
- }
226
-
227
- if (component === '') {
228
- if (i === urls.length - 1 && hasEndingSlash) {
229
- resultArray.push('/');
230
- }
231
- // eslint-disable-next-line
232
- continue;
233
- }
234
-
235
- if (component !== '/') {
236
- if (i > 0) {
237
- // Removing the starting slashes for each component but the first.
238
- component = component.replace(
239
- /^[/]+/,
240
- // Special case where the first element of rawUrls is empty ["", "/hello"] => /hello
241
- component[0] === '/' && !hasStartingSlash ? '/' : '',
242
- );
243
- }
244
-
245
- hasEndingSlash = component[component.length - 1] === '/';
246
- // Removing the ending slashes for each component but the last.
247
- // For the last component we will combine multiple slashes to a single one.
248
- component = component.replace(/[/]+$/, i < urls.length - 1 ? '' : '/');
249
- }
250
-
251
- hasStartingSlash = true;
252
- resultArray.push(component);
253
- }
254
-
255
- let str = resultArray.join('/');
256
- // Each input component is now separated by a single slash
257
- // except the possible first plain protocol part.
258
-
259
- // Remove trailing slash before parameters or hash.
260
- str = str.replace(/\/(\?|&|#[^!])/g, '$1');
261
-
262
- // Replace ? in parameters with &.
263
- const parts = str.split('?');
264
- str = parts.shift() + (parts.length > 0 ? '?' : '') + parts.join('&');
265
-
266
- // Dedupe forward slashes in the entire path, avoiding protocol slashes.
267
- str = str.replace(/([^:]\/)\/+/g, '$1');
268
-
269
- // Dedupe forward slashes at the beginning of the path.
270
- str = str.replace(/^\/+/g, '/');
271
-
272
- return str;
273
- }
274
-
275
- /**
276
- * Alias filepath relative to site directory, very useful so that we
277
- * don't expose user's site structure.
278
- * Example: some/path/to/website/docs/foo.md -> @site/docs/foo.md
279
- */
280
- export function aliasedSitePath(filePath: string, siteDir: string): string {
281
- const relativePath = posixPath(path.relative(siteDir, filePath));
282
- // Cannot use path.join() as it resolves '../' and removes
283
- // the '@site'. Let webpack loader resolve it.
284
- return `@site/${relativePath}`;
285
- }
286
-
287
- export function getEditUrl(
288
- fileRelativePath: string,
289
- editUrl?: string,
290
- ): string | undefined {
291
- return editUrl
292
- ? normalizeUrl([editUrl, posixPath(fileRelativePath)])
293
- : undefined;
294
- }
295
-
296
- export function isValidPathname(str: string): boolean {
297
- if (!str.startsWith('/')) {
298
- return false;
299
- }
300
- try {
301
- // weird, but is there a better way?
302
- const parsedPathname = new URL(str, 'https://domain.com').pathname;
303
- return parsedPathname === str || parsedPathname === encodeURI(str);
304
- } catch (e) {
305
- return false;
306
- }
307
- }
308
-
309
- // resolve pathname and fail fast if resolution fails
310
- export function resolvePathname(to: string, from?: string): string {
311
- return resolvePathnameUnsafe(to, from);
312
- }
313
- export function addLeadingSlash(str: string): string {
314
- return str.startsWith('/') ? str : `/${str}`;
315
- }
316
- export function addTrailingSlash(str: string): string {
317
- return str.endsWith('/') ? str : `${str}/`;
318
- }
319
- export function addTrailingPathSeparator(str: string): string {
320
- return str.endsWith(path.sep) ? str : `${str}${path.sep}`;
321
- }
322
-
323
- export function removeTrailingSlash(str: string): string {
324
- return removeSuffix(str, '/');
325
- }
326
-
327
- export function removeSuffix(str: string, suffix: string): string {
328
- if (suffix === '') {
329
- return str; // always returns "" otherwise!
330
- }
331
- return str.endsWith(suffix) ? str.slice(0, -suffix.length) : str;
332
- }
333
-
334
- export function removePrefix(str: string, prefix: string): string {
335
- return str.startsWith(prefix) ? str.slice(prefix.length) : str;
336
- }
337
-
338
- export function getFilePathForRoutePath(routePath: string): string {
339
- const fileName = path.basename(routePath);
340
- const filePath = path.dirname(routePath);
341
- return path.join(filePath, `${fileName}/index.html`);
342
- }
343
-
344
- export function getElementsAround<T extends unknown>(
345
- array: T[],
346
- aroundIndex: number,
347
- ): {
348
- next: T | undefined;
349
- previous: T | undefined;
350
- } {
351
- const min = 0;
352
- const max = array.length - 1;
353
- if (aroundIndex < min || aroundIndex > max) {
354
- throw new Error(
355
- `Valid aroundIndex for array (of size ${array.length}) are between ${min} and ${max}, but you provided aroundIndex=${aroundIndex}`,
356
- );
357
- }
358
- const previous = aroundIndex === min ? undefined : array[aroundIndex - 1];
359
- const next = aroundIndex === max ? undefined : array[aroundIndex + 1];
360
- return {previous, next};
361
- }
362
-
363
- export function getPluginI18nPath({
364
- siteDir,
365
- locale,
366
- pluginName,
367
- pluginId = 'default', // TODO duplicated constant
368
- subPaths = [],
369
- }: {
370
- siteDir: string;
371
- locale: string;
372
- pluginName: string;
373
- pluginId?: string | undefined;
374
- subPaths?: string[];
375
- }): string {
376
- return path.join(
377
- siteDir,
378
- 'i18n',
379
- // namespace first by locale: convenient to work in a single folder for a translator
380
- locale,
381
- // Make it convenient to use for single-instance
382
- // ie: return "docs", not "docs-default" nor "docs/default"
383
- `${pluginName}${
384
- // TODO duplicate constant :(
385
- pluginId === 'default' ? '' : `-${pluginId}`
386
- }`,
387
- ...subPaths,
388
- );
389
- }
390
-
391
- export async function mapAsyncSequencial<T extends unknown, R extends unknown>(
392
- array: T[],
393
- action: (t: T) => Promise<R>,
394
- ): Promise<R[]> {
395
- const results: R[] = [];
396
- // eslint-disable-next-line no-restricted-syntax
397
- for (const t of array) {
398
- // eslint-disable-next-line no-await-in-loop
399
- const result = await action(t);
400
- results.push(result);
401
- }
402
- return results;
403
- }
404
-
405
- export async function findAsyncSequential<T>(
406
- array: T[],
407
- predicate: (t: T) => Promise<boolean>,
408
- ): Promise<T | undefined> {
409
- // eslint-disable-next-line no-restricted-syntax
410
- for (const t of array) {
411
- // eslint-disable-next-line no-await-in-loop
412
- if (await predicate(t)) {
413
- return t;
414
- }
415
- }
416
- return undefined;
417
- }
418
-
419
- // return the first folder path in which the file exists in
420
- export async function findFolderContainingFile(
421
- folderPaths: string[],
422
- relativeFilePath: string,
423
- ): Promise<string | undefined> {
424
- return findAsyncSequential(folderPaths, (folderPath) =>
425
- fs.pathExists(path.join(folderPath, relativeFilePath)),
426
- );
427
- }
428
-
429
- export async function getFolderContainingFile(
430
- folderPaths: string[],
431
- relativeFilePath: string,
432
- ): Promise<string> {
433
- const maybeFolderPath = await findFolderContainingFile(
434
- folderPaths,
435
- relativeFilePath,
436
- );
437
- // should never happen, as the source was read from the FS anyway...
438
- if (!maybeFolderPath) {
439
- throw new Error(
440
- `relativeFilePath=[${relativeFilePath}] does not exist in any of these folders: \n- ${folderPaths.join(
441
- '\n- ',
442
- )}]`,
443
- );
444
- }
445
- return maybeFolderPath;
446
- }
447
-
448
- export function reportMessage(
449
- message: string,
450
- reportingSeverity: ReportingSeverity,
451
- ): void {
452
- switch (reportingSeverity) {
453
- case 'ignore':
454
- break;
455
- case 'log':
456
- console.log(chalk.bold.blue('info ') + chalk.blue(message));
457
- break;
458
- case 'warn':
459
- console.warn(chalk.bold.yellow('warn ') + chalk.yellow(message));
460
- break;
461
- case 'error':
462
- console.error(chalk.bold.red('error ') + chalk.red(message));
463
- break;
464
- case 'throw':
465
- throw new Error(message);
466
- default:
467
- throw new Error(
468
- `unexpected reportingSeverity value: ${reportingSeverity}`,
469
- );
470
- }
471
- }
472
-
473
- export function mergeTranslations(
474
- contents: TranslationFileContent[],
475
- ): TranslationFileContent {
476
- return contents.reduce((acc, content) => {
477
- return {...acc, ...content};
478
- }, {});
479
- }
480
-
481
- export function getSwizzledComponent(
482
- componentPath: string,
483
- ): string | undefined {
484
- const swizzledComponentPath = path.resolve(
485
- process.cwd(),
486
- 'src',
487
- componentPath,
488
- );
489
-
490
- return fs.existsSync(swizzledComponentPath)
491
- ? swizzledComponentPath
492
- : undefined;
493
- }
494
-
495
- // Useful to update all the messages of a translation file
496
- // Used in tests to simulate translations
497
- export function updateTranslationFileMessages(
498
- translationFile: TranslationFile,
499
- updateMessage: (message: string) => string,
500
- ): TranslationFile {
501
- return {
502
- ...translationFile,
503
- content: mapValues(translationFile.content, (translation) => ({
504
- ...translation,
505
- message: updateMessage(translation.message),
506
- })),
507
- };
508
- }
509
-
510
- // Input: ## Some heading {#some-heading}
511
- // Output: {text: "## Some heading", id: "some-heading"}
512
- export function parseMarkdownHeadingId(
513
- heading: string,
514
- ): {
515
- text: string;
516
- id?: string;
517
- } {
518
- const customHeadingIdRegex = /^(.*?)\s*\{#([\w-]+)\}$/;
519
- const matches = customHeadingIdRegex.exec(heading);
520
- if (matches) {
521
- return {
522
- text: matches[1],
523
- id: matches[2],
524
- };
525
- } else {
526
- return {text: heading, id: undefined};
527
- }
528
- }
8
+ export {
9
+ NODE_MAJOR_VERSION,
10
+ NODE_MINOR_VERSION,
11
+ DOCUSAURUS_VERSION,
12
+ DEFAULT_BUILD_DIR_NAME,
13
+ DEFAULT_CONFIG_FILE_NAME,
14
+ BABEL_CONFIG_FILE_NAME,
15
+ GENERATED_FILES_DIR_NAME,
16
+ SRC_DIR_NAME,
17
+ DEFAULT_STATIC_DIR_NAME,
18
+ OUTPUT_STATIC_ASSETS_DIR_NAME,
19
+ THEME_PATH,
20
+ DEFAULT_I18N_DIR_NAME,
21
+ CODE_TRANSLATIONS_FILE_NAME,
22
+ DEFAULT_PORT,
23
+ DEFAULT_PLUGIN_ID,
24
+ WEBPACK_URL_LOADER_LIMIT,
25
+ } from './constants';
26
+ export {generate, readOutputHTMLFile} from './emitUtils';
27
+ export {
28
+ getFileCommitDate,
29
+ FileNotTrackedError,
30
+ GitNotFoundError,
31
+ } from './gitUtils';
32
+ export {
33
+ mergeTranslations,
34
+ updateTranslationFileMessages,
35
+ getPluginI18nPath,
36
+ localizePath,
37
+ } from './i18nUtils';
38
+ export {
39
+ removeSuffix,
40
+ removePrefix,
41
+ mapAsyncSequential,
42
+ findAsyncSequential,
43
+ } from './jsUtils';
44
+ export {
45
+ normalizeUrl,
46
+ getEditUrl,
47
+ fileToPath,
48
+ encodePath,
49
+ isValidPathname,
50
+ resolvePathname,
51
+ addLeadingSlash,
52
+ addTrailingSlash,
53
+ removeTrailingSlash,
54
+ hasSSHProtocol,
55
+ buildHttpsUrl,
56
+ buildSshUrl,
57
+ } from './urlUtils';
58
+ export {
59
+ type Tag,
60
+ type TagsListItem,
61
+ type TagModule,
62
+ type FrontMatterTag,
63
+ normalizeFrontMatterTags,
64
+ groupTaggedItems,
65
+ } from './tags';
66
+ export {
67
+ parseMarkdownHeadingId,
68
+ createExcerpt,
69
+ parseFrontMatter,
70
+ parseMarkdownContentTitle,
71
+ parseMarkdownString,
72
+ writeMarkdownHeadingId,
73
+ type WriteHeadingIDOptions,
74
+ } from './markdownUtils';
75
+ export {
76
+ type ContentPaths,
77
+ type BrokenMarkdownLink,
78
+ replaceMarkdownLinks,
79
+ } from './markdownLinks';
80
+ export {type SluggerOptions, type Slugger, createSlugger} from './slugger';
81
+ export {
82
+ isNameTooLong,
83
+ shortName,
84
+ posixPath,
85
+ toMessageRelativeFilePath,
86
+ aliasedSitePath,
87
+ escapePath,
88
+ addTrailingPathSeparator,
89
+ } from './pathUtils';
90
+ export {md5Hash, simpleHash, docuHash} from './hashUtils';
91
+ export {
92
+ Globby,
93
+ GlobExcludeDefault,
94
+ createMatcher,
95
+ createAbsoluteFilePathMatcher,
96
+ } from './globUtils';
97
+ export {getFileLoaderUtils} from './webpackUtils';
98
+ export {escapeShellArg} from './shellUtils';
99
+ export {
100
+ getDataFilePath,
101
+ getDataFileData,
102
+ getContentPathList,
103
+ findFolderContainingFile,
104
+ getFolderContainingFile,
105
+ } from './dataFileUtils';
package/src/jsUtils.ts ADDED
@@ -0,0 +1,59 @@
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
+ /** Removes a given string suffix from `str`. */
9
+ export function removeSuffix(str: string, suffix: string): string {
10
+ if (suffix === '') {
11
+ // str.slice(0, 0) is ""
12
+ return str;
13
+ }
14
+ return str.endsWith(suffix) ? str.slice(0, -suffix.length) : str;
15
+ }
16
+
17
+ /** Removes a given string prefix from `str`. */
18
+ export function removePrefix(str: string, prefix: string): string {
19
+ return str.startsWith(prefix) ? str.slice(prefix.length) : str;
20
+ }
21
+
22
+ /**
23
+ * `Array#map` for async operations where order matters.
24
+ * @param array The array to traverse.
25
+ * @param action An async action to be performed on every array item. Will be
26
+ * awaited before working on the next.
27
+ * @returns The list of results returned from every `action(item)`
28
+ */
29
+ export async function mapAsyncSequential<T, R>(
30
+ array: T[],
31
+ action: (t: T) => Promise<R>,
32
+ ): Promise<R[]> {
33
+ const results: R[] = [];
34
+ for (const t of array) {
35
+ const result = await action(t);
36
+ results.push(result);
37
+ }
38
+ return results;
39
+ }
40
+
41
+ /**
42
+ * `Array#find` for async operations where order matters.
43
+ * @param array The array to traverse.
44
+ * @param predicate An async predicate to be called on every array item. Should
45
+ * return a boolean indicating whether the currently element should be returned.
46
+ * @returns The function immediately returns the first item on which `predicate`
47
+ * returns `true`, or `undefined` if none matches the predicate.
48
+ */
49
+ export async function findAsyncSequential<T>(
50
+ array: T[],
51
+ predicate: (t: T) => Promise<boolean>,
52
+ ): Promise<T | undefined> {
53
+ for (const t of array) {
54
+ if (await predicate(t)) {
55
+ return t;
56
+ }
57
+ }
58
+ return undefined;
59
+ }