@docusaurus/utils 2.0.0-beta.12faed89d → 2.0.0-beta.13
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.
- package/lib/.tsbuildinfo +1 -1
- package/lib/constants.d.ts +19 -0
- package/lib/constants.js +26 -0
- package/lib/globUtils.d.ts +11 -0
- package/lib/globUtils.js +47 -0
- package/lib/hashUtils.js +4 -4
- package/lib/index.d.ts +10 -6
- package/lib/index.js +39 -92
- package/lib/markdownLinks.js +19 -6
- package/lib/markdownParser.js +14 -6
- package/lib/mdxUtils.d.ts +16 -0
- package/lib/mdxUtils.js +30 -0
- package/lib/normalizeUrl.d.ts +7 -0
- package/lib/normalizeUrl.js +66 -0
- package/lib/pathUtils.js +3 -5
- package/lib/slugger.d.ts +13 -0
- package/lib/slugger.js +18 -0
- package/lib/tags.d.ts +18 -0
- package/lib/tags.js +72 -0
- package/lib/webpackUtils.d.ts +29 -0
- package/lib/webpackUtils.js +109 -0
- package/package.json +23 -7
- package/src/__tests__/globUtils.test.ts +109 -0
- package/src/__tests__/index.test.ts +6 -110
- package/src/__tests__/markdownParser.test.ts +15 -2
- package/src/__tests__/mdxUtils.test.ts +133 -0
- package/src/__tests__/normalizeUrl.test.ts +117 -0
- package/src/__tests__/pathUtils.test.ts +4 -2
- package/src/__tests__/slugger.test.ts +27 -0
- package/src/__tests__/tags.test.ts +183 -0
- package/src/__tests__/webpackUtils.test.ts +33 -0
- package/src/constants.ts +38 -0
- package/src/deps.d.ts +14 -0
- package/src/globUtils.ts +63 -0
- package/src/index.ts +21 -91
- package/src/markdownLinks.ts +19 -8
- package/src/markdownParser.ts +18 -11
- package/src/mdxUtils.ts +32 -0
- package/src/normalizeUrl.ts +80 -0
- package/src/pathUtils.ts +2 -3
- package/src/slugger.ts +24 -0
- package/src/tags.ts +100 -0
- package/src/webpackUtils.ts +144 -0
- package/lib/codeTranslationsUtils.d.ts +0 -11
- package/lib/codeTranslationsUtils.js +0 -50
- package/src/__tests__/__fixtures__/defaultCodeTranslations/en.json +0 -4
- package/src/__tests__/__fixtures__/defaultCodeTranslations/fr-FR.json +0 -5
- package/src/__tests__/__fixtures__/defaultCodeTranslations/fr.json +0 -4
- package/src/__tests__/codeTranslationsUtils.test.ts +0 -112
- package/src/codeTranslationsUtils.ts +0 -56
|
@@ -0,0 +1,117 @@
|
|
|
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 {normalizeUrl} from '../normalizeUrl';
|
|
9
|
+
|
|
10
|
+
describe('normalizeUrl', () => {
|
|
11
|
+
test('should normalize urls correctly', () => {
|
|
12
|
+
const asserts = [
|
|
13
|
+
{
|
|
14
|
+
input: ['/', ''],
|
|
15
|
+
output: '/',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
input: ['', '/'],
|
|
19
|
+
output: '/',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
input: ['/'],
|
|
23
|
+
output: '/',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
input: [''],
|
|
27
|
+
output: '',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
input: ['/', '/'],
|
|
31
|
+
output: '/',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
input: ['/', 'docs'],
|
|
35
|
+
output: '/docs',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
input: ['/', 'docs', 'en', 'next', 'blog'],
|
|
39
|
+
output: '/docs/en/next/blog',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
input: ['/test/', '/docs', 'ro', 'doc1'],
|
|
43
|
+
output: '/test/docs/ro/doc1',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
input: ['/test/', '/', 'ro', 'doc1'],
|
|
47
|
+
output: '/test/ro/doc1',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
input: ['/', '/', '2020/02/29/leap-day'],
|
|
51
|
+
output: '/2020/02/29/leap-day',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
input: ['', '/', 'ko', 'hello'],
|
|
55
|
+
output: '/ko/hello',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
input: ['hello', 'world'],
|
|
59
|
+
output: 'hello/world',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
input: ['http://www.google.com/', 'foo/bar', '?test=123'],
|
|
63
|
+
output: 'http://www.google.com/foo/bar?test=123',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
input: ['http:', 'www.google.com///', 'foo/bar', '?test=123'],
|
|
67
|
+
output: 'http://www.google.com/foo/bar?test=123',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
input: ['http://foobar.com', '', 'test'],
|
|
71
|
+
output: 'http://foobar.com/test',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
input: ['http://foobar.com', '', 'test', '/'],
|
|
75
|
+
output: 'http://foobar.com/test/',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
input: ['/', '', 'hello', '', '/', '/', '', '/', '/world'],
|
|
79
|
+
output: '/hello/world',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
input: ['', '', '/tt', 'ko', 'hello'],
|
|
83
|
+
output: '/tt/ko/hello',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
input: ['', '///hello///', '', '///world'],
|
|
87
|
+
output: '/hello/world',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
input: ['', '/hello/', ''],
|
|
91
|
+
output: '/hello/',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
input: ['', '/', ''],
|
|
95
|
+
output: '/',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
input: ['///', '///'],
|
|
99
|
+
output: '/',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
input: ['/', '/hello/world/', '///'],
|
|
103
|
+
output: '/hello/world/',
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
asserts.forEach((testCase) => {
|
|
107
|
+
expect(normalizeUrl(testCase.input)).toBe(testCase.output);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(() =>
|
|
111
|
+
// @ts-expect-error undefined for test
|
|
112
|
+
normalizeUrl(['http:example.com', undefined]),
|
|
113
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
114
|
+
`"Url must be a string. Received undefined"`,
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -17,8 +17,10 @@ describe('pathUtils', () => {
|
|
|
17
17
|
'endi-lie-fd3': false,
|
|
18
18
|
'yangshun-tay-48d': false,
|
|
19
19
|
'yangshun-tay-f3b': false,
|
|
20
|
-
'foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-d46':
|
|
21
|
-
|
|
20
|
+
'foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-d46':
|
|
21
|
+
true,
|
|
22
|
+
'foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-foo-bar-test-1-test-2-787':
|
|
23
|
+
true,
|
|
22
24
|
};
|
|
23
25
|
Object.keys(asserts).forEach((path) => {
|
|
24
26
|
expect(isNameTooLong(path)).toBe(asserts[path]);
|
|
@@ -0,0 +1,27 @@
|
|
|
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 {createSlugger} from '../slugger';
|
|
9
|
+
|
|
10
|
+
describe('createSlugger', () => {
|
|
11
|
+
test('can create unique slugs', () => {
|
|
12
|
+
const slugger = createSlugger();
|
|
13
|
+
expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue');
|
|
14
|
+
expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue-1');
|
|
15
|
+
expect(slugger.slug('Some$/vaLue$!^')).toEqual('somevalue-2');
|
|
16
|
+
expect(slugger.slug('Some$/vaLue$!^-1')).toEqual('somevalue-1-1');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('can create unique slugs respecting case', () => {
|
|
20
|
+
const slugger = createSlugger();
|
|
21
|
+
const opt = {maintainCase: true};
|
|
22
|
+
expect(slugger.slug('Some$/vaLue$!^', opt)).toEqual('SomevaLue');
|
|
23
|
+
expect(slugger.slug('Some$/vaLue$!^', opt)).toEqual('SomevaLue-1');
|
|
24
|
+
expect(slugger.slug('Some$/vaLue$!^', opt)).toEqual('SomevaLue-2');
|
|
25
|
+
expect(slugger.slug('Some$/vaLue$!^-1', opt)).toEqual('SomevaLue-1-1');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,183 @@
|
|
|
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 {
|
|
9
|
+
normalizeFrontMatterTag,
|
|
10
|
+
normalizeFrontMatterTags,
|
|
11
|
+
groupTaggedItems,
|
|
12
|
+
Tag,
|
|
13
|
+
} from '../tags';
|
|
14
|
+
|
|
15
|
+
describe('normalizeFrontMatterTag', () => {
|
|
16
|
+
type Input = Parameters<typeof normalizeFrontMatterTag>[1];
|
|
17
|
+
type Output = ReturnType<typeof normalizeFrontMatterTag>;
|
|
18
|
+
|
|
19
|
+
test('should normalize simple string tag', () => {
|
|
20
|
+
const tagsPath = '/all/tags';
|
|
21
|
+
const input: Input = 'tag';
|
|
22
|
+
const expectedOutput: Output = {
|
|
23
|
+
label: 'tag',
|
|
24
|
+
permalink: `${tagsPath}/tag`,
|
|
25
|
+
};
|
|
26
|
+
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('should normalize complex string tag', () => {
|
|
30
|
+
const tagsPath = '/all/tags';
|
|
31
|
+
const input: Input = 'some more Complex_tag';
|
|
32
|
+
const expectedOutput: Output = {
|
|
33
|
+
label: 'some more Complex_tag',
|
|
34
|
+
permalink: `${tagsPath}/some-more-complex-tag`,
|
|
35
|
+
};
|
|
36
|
+
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should normalize simple object tag', () => {
|
|
40
|
+
const tagsPath = '/all/tags';
|
|
41
|
+
const input: Input = {label: 'tag', permalink: 'tagPermalink'};
|
|
42
|
+
const expectedOutput: Output = {
|
|
43
|
+
label: 'tag',
|
|
44
|
+
permalink: `${tagsPath}/tagPermalink`,
|
|
45
|
+
};
|
|
46
|
+
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should normalize complex string tag', () => {
|
|
50
|
+
const tagsPath = '/all/tags';
|
|
51
|
+
const input: Input = {
|
|
52
|
+
label: 'tag complex Label',
|
|
53
|
+
permalink: '/MoreComplex/Permalink',
|
|
54
|
+
};
|
|
55
|
+
const expectedOutput: Output = {
|
|
56
|
+
label: 'tag complex Label',
|
|
57
|
+
permalink: `${tagsPath}/MoreComplex/Permalink`,
|
|
58
|
+
};
|
|
59
|
+
expect(normalizeFrontMatterTag(tagsPath, input)).toEqual(expectedOutput);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('normalizeFrontMatterTags', () => {
|
|
64
|
+
type Input = Parameters<typeof normalizeFrontMatterTags>[1];
|
|
65
|
+
type Output = ReturnType<typeof normalizeFrontMatterTags>;
|
|
66
|
+
|
|
67
|
+
test('should normalize string list', () => {
|
|
68
|
+
const tagsPath = '/all/tags';
|
|
69
|
+
const input: Input = ['tag 1', 'tag-1', 'tag 3', 'tag1', 'tag-2'];
|
|
70
|
+
// Keep user input order but remove tags that lead to same permalink
|
|
71
|
+
const expectedOutput: Output = [
|
|
72
|
+
{
|
|
73
|
+
label: 'tag 1',
|
|
74
|
+
permalink: `${tagsPath}/tag-1`,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
label: 'tag 3',
|
|
78
|
+
permalink: `${tagsPath}/tag-3`,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
label: 'tag-2',
|
|
82
|
+
permalink: `${tagsPath}/tag-2`,
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
expect(normalizeFrontMatterTags(tagsPath, input)).toEqual(expectedOutput);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('should normalize complex mixed list', () => {
|
|
89
|
+
const tagsPath = '/all/tags';
|
|
90
|
+
const input: Input = [
|
|
91
|
+
'tag 1',
|
|
92
|
+
{label: 'tag-1', permalink: '/tag-1'},
|
|
93
|
+
'tag 3',
|
|
94
|
+
'tag1',
|
|
95
|
+
{label: 'tag 4', permalink: '/tag4Permalink'},
|
|
96
|
+
];
|
|
97
|
+
// Keep user input order but remove tags that lead to same permalink
|
|
98
|
+
const expectedOutput: Output = [
|
|
99
|
+
{
|
|
100
|
+
label: 'tag 1',
|
|
101
|
+
permalink: `${tagsPath}/tag-1`,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
label: 'tag 3',
|
|
105
|
+
permalink: `${tagsPath}/tag-3`,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
label: 'tag 4',
|
|
109
|
+
permalink: `${tagsPath}/tag4Permalink`,
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
expect(normalizeFrontMatterTags(tagsPath, input)).toEqual(expectedOutput);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('groupTaggedItems', () => {
|
|
117
|
+
type SomeTaggedItem = {
|
|
118
|
+
id: string;
|
|
119
|
+
nested: {
|
|
120
|
+
tags: Tag[];
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
function groupItems(items: SomeTaggedItem[]) {
|
|
124
|
+
return groupTaggedItems(items, (item) => item.nested.tags);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
type Input = Parameters<typeof groupItems>[0];
|
|
128
|
+
type Output = ReturnType<typeof groupItems>;
|
|
129
|
+
|
|
130
|
+
test('should group items by tag permalink', () => {
|
|
131
|
+
const tagGuide = {label: 'Guide', permalink: '/guide'};
|
|
132
|
+
const tagTutorial = {label: 'Tutorial', permalink: '/tutorial'};
|
|
133
|
+
const tagAPI = {label: 'API', permalink: '/api'};
|
|
134
|
+
|
|
135
|
+
// This one will be grouped under same permalink and label is ignored
|
|
136
|
+
const tagTutorialOtherLabel = {
|
|
137
|
+
label: 'TutorialOtherLabel',
|
|
138
|
+
permalink: '/tutorial',
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const item1: SomeTaggedItem = {
|
|
142
|
+
id: '1',
|
|
143
|
+
nested: {
|
|
144
|
+
tags: [
|
|
145
|
+
tagGuide,
|
|
146
|
+
tagTutorial,
|
|
147
|
+
tagAPI,
|
|
148
|
+
// Add some duplicates on purpose: they should be filtered
|
|
149
|
+
tagGuide,
|
|
150
|
+
tagTutorialOtherLabel,
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
const item2: SomeTaggedItem = {
|
|
155
|
+
id: '2',
|
|
156
|
+
nested: {
|
|
157
|
+
tags: [tagAPI],
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
const item3: SomeTaggedItem = {
|
|
161
|
+
id: '3',
|
|
162
|
+
nested: {
|
|
163
|
+
tags: [tagTutorial],
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
const item4: SomeTaggedItem = {
|
|
167
|
+
id: '4',
|
|
168
|
+
nested: {
|
|
169
|
+
tags: [tagTutorialOtherLabel],
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const input: Input = [item1, item2, item3, item4];
|
|
174
|
+
|
|
175
|
+
const expectedOutput: Output = {
|
|
176
|
+
'/guide': {tag: tagGuide, items: [item1]},
|
|
177
|
+
'/tutorial': {tag: tagTutorial, items: [item1, item3, item4]},
|
|
178
|
+
'/api': {tag: tagAPI, items: [item1, item2]},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
expect(groupItems(input)).toEqual(expectedOutput);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
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 {getFileLoaderUtils} from '../webpackUtils';
|
|
9
|
+
|
|
10
|
+
describe('getFileLoaderUtils()', () => {
|
|
11
|
+
test('plugin svgo/removeViewBox should be disabled', () => {
|
|
12
|
+
const {oneOf} = getFileLoaderUtils().rules.svg();
|
|
13
|
+
expect(oneOf[0].use).toContainEqual(
|
|
14
|
+
expect.objectContaining({
|
|
15
|
+
loader: require.resolve('@svgr/webpack'),
|
|
16
|
+
options: expect.objectContaining({
|
|
17
|
+
svgoConfig: {
|
|
18
|
+
plugins: [
|
|
19
|
+
{
|
|
20
|
+
name: 'preset-default',
|
|
21
|
+
params: {
|
|
22
|
+
overrides: {
|
|
23
|
+
removeViewBox: false,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
});
|
package/src/constants.ts
ADDED
|
@@ -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';
|
package/src/globUtils.ts
ADDED
|
@@ -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
|
@@ -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
|
|
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 =
|
|
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
|
|
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
|
}
|
|
@@ -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
|
} {
|