@docusaurus/utils 3.1.0 → 3.2.0

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 (52) hide show
  1. package/lib/cliUtils.d.ts +14 -0
  2. package/lib/cliUtils.d.ts.map +1 -0
  3. package/lib/cliUtils.js +50 -0
  4. package/lib/cliUtils.js.map +1 -0
  5. package/lib/emitUtils.d.ts.map +1 -1
  6. package/lib/emitUtils.js +6 -3
  7. package/lib/emitUtils.js.map +1 -1
  8. package/lib/gitUtils.d.ts +6 -6
  9. package/lib/gitUtils.d.ts.map +1 -1
  10. package/lib/gitUtils.js +21 -10
  11. package/lib/gitUtils.js.map +1 -1
  12. package/lib/globUtils.d.ts.map +1 -1
  13. package/lib/globUtils.js +2 -2
  14. package/lib/globUtils.js.map +1 -1
  15. package/lib/index.d.ts +6 -3
  16. package/lib/index.d.ts.map +1 -1
  17. package/lib/index.js +12 -7
  18. package/lib/index.js.map +1 -1
  19. package/lib/jsUtils.d.ts +0 -8
  20. package/lib/jsUtils.d.ts.map +1 -1
  21. package/lib/jsUtils.js +1 -25
  22. package/lib/jsUtils.js.map +1 -1
  23. package/lib/lastUpdateUtils.d.ts +28 -0
  24. package/lib/lastUpdateUtils.d.ts.map +1 -0
  25. package/lib/lastUpdateUtils.js +88 -0
  26. package/lib/lastUpdateUtils.js.map +1 -0
  27. package/lib/markdownUtils.js +2 -2
  28. package/lib/markdownUtils.js.map +1 -1
  29. package/lib/pathUtils.d.ts +8 -0
  30. package/lib/pathUtils.d.ts.map +1 -1
  31. package/lib/pathUtils.js +15 -1
  32. package/lib/pathUtils.js.map +1 -1
  33. package/lib/routeUtils.d.ts +13 -0
  34. package/lib/routeUtils.d.ts.map +1 -0
  35. package/lib/routeUtils.js +21 -0
  36. package/lib/routeUtils.js.map +1 -0
  37. package/lib/urlUtils.d.ts +0 -6
  38. package/lib/urlUtils.d.ts.map +1 -1
  39. package/lib/urlUtils.js +1 -18
  40. package/lib/urlUtils.js.map +1 -1
  41. package/package.json +6 -4
  42. package/src/cliUtils.ts +65 -0
  43. package/src/emitUtils.ts +7 -3
  44. package/src/gitUtils.ts +44 -20
  45. package/src/globUtils.ts +1 -2
  46. package/src/index.ts +13 -9
  47. package/src/jsUtils.ts +0 -24
  48. package/src/lastUpdateUtils.ts +132 -0
  49. package/src/markdownUtils.ts +2 -2
  50. package/src/pathUtils.ts +14 -0
  51. package/src/routeUtils.ts +19 -0
  52. package/src/urlUtils.ts +0 -17
@@ -0,0 +1,132 @@
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 _ from 'lodash';
9
+ import logger from '@docusaurus/logger';
10
+ import {
11
+ FileNotTrackedError,
12
+ GitNotFoundError,
13
+ getFileCommitDate,
14
+ } from './gitUtils';
15
+ import type {PluginOptions} from '@docusaurus/types';
16
+
17
+ export type LastUpdateData = {
18
+ /** A timestamp in **milliseconds**, usually read from `git log` */
19
+ lastUpdatedAt?: number;
20
+ /** The author's name, usually coming from `git log` */
21
+ lastUpdatedBy?: string;
22
+ };
23
+
24
+ let showedGitRequirementError = false;
25
+ let showedFileNotTrackedError = false;
26
+
27
+ export async function getGitLastUpdate(
28
+ filePath: string,
29
+ ): Promise<LastUpdateData | null> {
30
+ if (!filePath) {
31
+ return null;
32
+ }
33
+
34
+ // Wrap in try/catch in case the shell commands fail
35
+ // (e.g. project doesn't use Git, etc).
36
+ try {
37
+ const result = await getFileCommitDate(filePath, {
38
+ age: 'newest',
39
+ includeAuthor: true,
40
+ });
41
+
42
+ return {lastUpdatedAt: result.timestamp, lastUpdatedBy: result.author};
43
+ } catch (err) {
44
+ if (err instanceof GitNotFoundError) {
45
+ if (!showedGitRequirementError) {
46
+ logger.warn('Sorry, the last update options require Git.');
47
+ showedGitRequirementError = true;
48
+ }
49
+ } else if (err instanceof FileNotTrackedError) {
50
+ if (!showedFileNotTrackedError) {
51
+ logger.warn(
52
+ 'Cannot infer the update date for some files, as they are not tracked by git.',
53
+ );
54
+ showedFileNotTrackedError = true;
55
+ }
56
+ } else {
57
+ throw new Error(
58
+ `An error occurred when trying to get the last update date`,
59
+ {cause: err},
60
+ );
61
+ }
62
+ return null;
63
+ }
64
+ }
65
+
66
+ export const LAST_UPDATE_FALLBACK: LastUpdateData = {
67
+ lastUpdatedAt: 1539502055000,
68
+ lastUpdatedBy: 'Author',
69
+ };
70
+
71
+ export async function getLastUpdate(
72
+ filePath: string,
73
+ ): Promise<LastUpdateData | null> {
74
+ if (process.env.NODE_ENV !== 'production') {
75
+ // Use fake data in dev/test for faster development.
76
+ return LAST_UPDATE_FALLBACK;
77
+ }
78
+ return getGitLastUpdate(filePath);
79
+ }
80
+
81
+ type LastUpdateOptions = Pick<
82
+ PluginOptions,
83
+ 'showLastUpdateAuthor' | 'showLastUpdateTime'
84
+ >;
85
+
86
+ export type FrontMatterLastUpdate = {
87
+ author?: string;
88
+ /**
89
+ * Date can be any
90
+ * [parsable date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse).
91
+ */
92
+ date?: Date | string;
93
+ };
94
+
95
+ export async function readLastUpdateData(
96
+ filePath: string,
97
+ options: LastUpdateOptions,
98
+ lastUpdateFrontMatter: FrontMatterLastUpdate | undefined,
99
+ ): Promise<LastUpdateData> {
100
+ const {showLastUpdateAuthor, showLastUpdateTime} = options;
101
+
102
+ if (!showLastUpdateAuthor && !showLastUpdateTime) {
103
+ return {};
104
+ }
105
+
106
+ const frontMatterAuthor = lastUpdateFrontMatter?.author;
107
+ const frontMatterTimestamp = lastUpdateFrontMatter?.date
108
+ ? new Date(lastUpdateFrontMatter.date).getTime()
109
+ : undefined;
110
+
111
+ // We try to minimize git last update calls
112
+ // We call it at most once
113
+ // If all the data is provided as front matter, we do not call it
114
+ const getLastUpdateMemoized = _.memoize(() => getLastUpdate(filePath));
115
+ const getLastUpdateBy = () =>
116
+ getLastUpdateMemoized().then((update) => update?.lastUpdatedBy);
117
+ const getLastUpdateAt = () =>
118
+ getLastUpdateMemoized().then((update) => update?.lastUpdatedAt);
119
+
120
+ const lastUpdatedBy = showLastUpdateAuthor
121
+ ? frontMatterAuthor ?? (await getLastUpdateBy())
122
+ : undefined;
123
+
124
+ const lastUpdatedAt = showLastUpdateTime
125
+ ? frontMatterTimestamp ?? (await getLastUpdateAt())
126
+ : undefined;
127
+
128
+ return {
129
+ lastUpdatedBy,
130
+ lastUpdatedAt,
131
+ };
132
+ }
@@ -70,9 +70,9 @@ export function escapeMarkdownHeadingIds(content: string): string {
70
70
  export function unwrapMdxCodeBlocks(content: string): string {
71
71
  // We only support 3/4 backticks on purpose, should be good enough
72
72
  const regexp3 =
73
- /(?<begin>^|\n)```mdx-code-block\n(?<children>.*?)\n```(?<end>\n|$)/gs;
73
+ /(?<begin>^|\r?\n)```(?<spaces>\x20*)mdx-code-block\r?\n(?<children>.*?)\r?\n```(?<end>\r?\n|$)/gs;
74
74
  const regexp4 =
75
- /(?<begin>^|\n)````mdx-code-block\n(?<children>.*?)\n````(?<end>\n|$)/gs;
75
+ /(?<begin>^|\r?\n)````(?<spaces>\x20*)mdx-code-block\r?\n(?<children>.*?)\r?\n````(?<end>\r?\n|$)/gs;
76
76
 
77
77
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
78
  const replacer = (substring: string, ...args: any[]) => {
package/src/pathUtils.ts CHANGED
@@ -92,6 +92,20 @@ export function aliasedSitePath(filePath: string, siteDir: string): string {
92
92
  return `@site/${relativePath}`;
93
93
  }
94
94
 
95
+ /**
96
+ * Converts back the aliased site path (starting with "@site/...") to a relative path
97
+ *
98
+ * TODO method this is a workaround, we shouldn't need to alias/un-alias paths
99
+ * we should refactor the codebase to not have aliased site paths everywhere
100
+ * We probably only need aliasing for client-only paths required by Webpack
101
+ */
102
+ export function aliasedSitePathToRelativePath(filePath: string): string {
103
+ if (filePath.startsWith('@site/')) {
104
+ return filePath.replace('@site/', '');
105
+ }
106
+ throw new Error(`Unexpected, filePath is not site-aliased: ${filePath}`);
107
+ }
108
+
95
109
  /**
96
110
  * When you have a path like C:\X\Y
97
111
  * It is not safe to use directly when generating code
@@ -0,0 +1,19 @@
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 type {RouteConfig} from '@docusaurus/types';
9
+
10
+ /**
11
+ * Recursively flatten routes and only return the "leaf routes"
12
+ * Parent routes are filtered out
13
+ */
14
+ export function flattenRoutes(routeConfig: RouteConfig[]): RouteConfig[] {
15
+ function flatten(route: RouteConfig): RouteConfig[] {
16
+ return route.routes ? route.routes.flatMap(flatten) : [route];
17
+ }
18
+ return routeConfig.flatMap(flatten);
19
+ }
package/src/urlUtils.ts CHANGED
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  import resolvePathnameUnsafe from 'resolve-pathname';
9
- import {addPrefix, addSuffix, removeSuffix} from './jsUtils';
10
9
 
11
10
  /**
12
11
  * Much like `path.join`, but much better. Takes an array of URL segments, and
@@ -232,22 +231,6 @@ export function resolvePathname(to: string, from?: string): string {
232
231
  return resolvePathnameUnsafe(to, from);
233
232
  }
234
233
 
235
- /** Appends a leading slash to `str`, if one doesn't exist. */
236
- export function addLeadingSlash(str: string): string {
237
- return addPrefix(str, '/');
238
- }
239
-
240
- // TODO deduplicate: also present in @docusaurus/utils-common
241
- /** Appends a trailing slash to `str`, if one doesn't exist. */
242
- export function addTrailingSlash(str: string): string {
243
- return addSuffix(str, '/');
244
- }
245
-
246
- /** Removes the trailing slash from `str`. */
247
- export function removeTrailingSlash(str: string): string {
248
- return removeSuffix(str, '/');
249
- }
250
-
251
234
  /** Constructs an SSH URL that can be used to push to GitHub. */
252
235
  export function buildSshUrl(
253
236
  githubHost: string,