@mui/internal-markdown 1.0.2 → 1.0.3
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/loader.js +124 -4
- package/package.json +1 -1
- package/parseMarkdown.js +1 -5
- package/parseMarkdown.test.js +3 -3
- package/prepareMarkdown.js +1 -1
package/loader.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { promises: fs, readdirSync } = require('fs');
|
|
1
|
+
const { promises: fs, readdirSync, statSync } = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const prepareMarkdown = require('./prepareMarkdown');
|
|
4
4
|
const extractImports = require('./extractImports');
|
|
@@ -127,6 +127,7 @@ module.exports = async function demoLoader() {
|
|
|
127
127
|
const demoModuleIDs = new Set();
|
|
128
128
|
const componentModuleIDs = new Set();
|
|
129
129
|
const nonEditableDemos = new Set();
|
|
130
|
+
const relativeModules = new Map();
|
|
130
131
|
const demoNames = Array.from(
|
|
131
132
|
new Set(
|
|
132
133
|
docs.en.rendered
|
|
@@ -142,6 +143,63 @@ module.exports = async function demoLoader() {
|
|
|
142
143
|
),
|
|
143
144
|
);
|
|
144
145
|
|
|
146
|
+
/**
|
|
147
|
+
* @param {*} demoName
|
|
148
|
+
* @param {*} moduleFilepath
|
|
149
|
+
* @param {*} variant
|
|
150
|
+
* @param {*} importModuleID
|
|
151
|
+
* @example detectRelativeImports('ComboBox.js', '', JS', './top100Films') => relativeModules.set('ComboBox.js', new Map([['./top100Films.js', ['JS']]]))
|
|
152
|
+
*/
|
|
153
|
+
function detectRelativeImports(demoName, moduleFilepath, variant, importModuleID) {
|
|
154
|
+
if (importModuleID.startsWith('.')) {
|
|
155
|
+
let relativeModuleFilename = importModuleID;
|
|
156
|
+
const demoMap = relativeModules.get(demoName);
|
|
157
|
+
// If the moduleID does not end with an extension, or ends with an unsupported extension (e.g. ".styling") we need to resolve it
|
|
158
|
+
// Fastest way to get a file extension, see: https://stackoverflow.com/a/12900504/
|
|
159
|
+
const importType = importModuleID.slice(
|
|
160
|
+
(Math.max(0, importModuleID.lastIndexOf('.')) || Infinity) + 1,
|
|
161
|
+
);
|
|
162
|
+
const supportedTypes = ['js', 'jsx', 'ts', 'tsx', 'css', 'json'];
|
|
163
|
+
if (!importType || !supportedTypes.includes(importType)) {
|
|
164
|
+
// If the demo is a JS demo, we can assume that the relative import is either
|
|
165
|
+
// a `.js` or a `.jsx` file, with `.js` taking precedence over `.jsx`
|
|
166
|
+
// likewise for TS demos, with `.ts` taking precedence over `.tsx`
|
|
167
|
+
const extensions =
|
|
168
|
+
variant === 'JS' ? ['.js', '.jsx', '.ts', '.tsx'] : ['.ts', '.tsx', '.js', '.jsx'];
|
|
169
|
+
const extension = extensions.find((ext) => {
|
|
170
|
+
try {
|
|
171
|
+
return statSync(path.join(moduleFilepath, '..', `${importModuleID}${ext}`));
|
|
172
|
+
} catch (error) {
|
|
173
|
+
// If the file does not exist, we return false and continue to the next extension
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
if (!extension) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
[
|
|
180
|
+
`You are trying to import a module "${importModuleID}" in the demo "${demoName}" that could not be resolved.`,
|
|
181
|
+
`Please make sure that one of the following file exists:`,
|
|
182
|
+
...extensions.map((ext) => `- ${importModuleID}${ext}`),
|
|
183
|
+
].join('\n'),
|
|
184
|
+
);
|
|
185
|
+
} else {
|
|
186
|
+
relativeModuleFilename = `${importModuleID}${extension}`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!demoMap) {
|
|
191
|
+
relativeModules.set(demoName, new Map([[relativeModuleFilename, [variant]]]));
|
|
192
|
+
} else {
|
|
193
|
+
const variantArray = demoMap.get(relativeModuleFilename);
|
|
194
|
+
if (variantArray) {
|
|
195
|
+
variantArray.push(variant);
|
|
196
|
+
} else {
|
|
197
|
+
demoMap.set(relativeModuleFilename, [variant]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
145
203
|
await Promise.all(
|
|
146
204
|
demoNames.map(async (demoName) => {
|
|
147
205
|
const multipleDemoVersionsUsed = !demoName.endsWith('.js');
|
|
@@ -168,11 +226,14 @@ module.exports = async function demoLoader() {
|
|
|
168
226
|
raw: await fs.readFile(moduleFilepath, { encoding: 'utf8' }),
|
|
169
227
|
};
|
|
170
228
|
demoModuleIDs.add(moduleID);
|
|
229
|
+
|
|
171
230
|
// Skip non-editable demos
|
|
172
231
|
if (!nonEditableDemos.has(demoName)) {
|
|
173
|
-
extractImports(demos[demoName].raw).forEach((importModuleID) =>
|
|
174
|
-
|
|
175
|
-
|
|
232
|
+
extractImports(demos[demoName].raw).forEach((importModuleID) => {
|
|
233
|
+
// detect relative import
|
|
234
|
+
detectRelativeImports(demoName, moduleFilepath, 'JS', importModuleID);
|
|
235
|
+
importedModuleIDs.add(importModuleID);
|
|
236
|
+
});
|
|
176
237
|
}
|
|
177
238
|
|
|
178
239
|
if (multipleDemoVersionsUsed) {
|
|
@@ -343,10 +404,69 @@ module.exports = async function demoLoader() {
|
|
|
343
404
|
// But this leads to building both demo version i.e. more build time.
|
|
344
405
|
demos[demoName].moduleTS = this.mode === 'production' ? moduleID : moduleTS;
|
|
345
406
|
demos[demoName].rawTS = rawTS;
|
|
407
|
+
|
|
408
|
+
// Extract relative imports from the TypeScript version
|
|
409
|
+
// of demos which have relative imports in the JS version
|
|
410
|
+
if (relativeModules.has(demoName)) {
|
|
411
|
+
extractImports(demos[demoName].rawTS).forEach((importModuleID) => {
|
|
412
|
+
detectRelativeImports(demoName, moduleTSFilepath, 'TS', importModuleID);
|
|
413
|
+
importedModuleIDs.add(importModuleID);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
346
417
|
demoModuleIDs.add(demos[demoName].moduleTS);
|
|
347
418
|
} catch (error) {
|
|
348
419
|
// TS version of the demo doesn't exist. This is fine.
|
|
349
420
|
}
|
|
421
|
+
|
|
422
|
+
/* Map over relative import module IDs and resolve them
|
|
423
|
+
* while grouping by demo variant
|
|
424
|
+
* From:
|
|
425
|
+
* relativeModules: { 'ComboBox.js' =>
|
|
426
|
+
* { './top100Films.js' => ['JS', 'TS'] }
|
|
427
|
+
* }
|
|
428
|
+
* To:
|
|
429
|
+
* demos["ComboBox.js"].relativeModules = {
|
|
430
|
+
* JS: [{ module: './top100Films.js', raw: '...' }],
|
|
431
|
+
* TS: [{ module: './top100Films.js', raw: '...' }]
|
|
432
|
+
* }
|
|
433
|
+
* }
|
|
434
|
+
*/
|
|
435
|
+
|
|
436
|
+
if (relativeModules.has(demoName)) {
|
|
437
|
+
if (!demos[demoName].relativeModules) {
|
|
438
|
+
demos[demoName].relativeModules = {};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
await Promise.all(
|
|
442
|
+
Array.from(relativeModules.get(demoName)).map(async ([relativeModuleID, variants]) => {
|
|
443
|
+
let raw = '';
|
|
444
|
+
try {
|
|
445
|
+
raw = await fs.readFile(path.join(path.dirname(moduleFilepath), relativeModuleID), {
|
|
446
|
+
encoding: 'utf8',
|
|
447
|
+
});
|
|
448
|
+
} catch {
|
|
449
|
+
throw new Error(
|
|
450
|
+
`Could not find a module for the relative import "${relativeModuleID}" in the demo "${demoName}"`,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const moduleData = { module: relativeModuleID, raw };
|
|
455
|
+
const modules = demos[demoName].relativeModules;
|
|
456
|
+
|
|
457
|
+
variants.forEach((variant) => {
|
|
458
|
+
if (modules[variant]) {
|
|
459
|
+
// Avoid duplicates
|
|
460
|
+
if (!modules[variant].some((elem) => elem.module === relativeModuleID)) {
|
|
461
|
+
modules[variant].push(moduleData);
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
modules[variant] = [moduleData];
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}),
|
|
468
|
+
);
|
|
469
|
+
}
|
|
350
470
|
}),
|
|
351
471
|
);
|
|
352
472
|
|
package/package.json
CHANGED
package/parseMarkdown.js
CHANGED
|
@@ -364,11 +364,7 @@ function createRender(context) {
|
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
return [
|
|
367
|
-
`<h${level} id="${hash}">`,
|
|
368
|
-
headingHtml,
|
|
369
|
-
`<a aria-labelledby="${hash}" class="anchor-link" href="#${hash}" tabindex="-1">`,
|
|
370
|
-
'<svg><use xlink:href="#anchor-link-icon" /></svg>',
|
|
371
|
-
'</a>',
|
|
367
|
+
`<h${level} id="${hash}"><a href="#${hash}" class="title-link-to-anchor">${headingHtml}<div class="anchor-icon"><svg><use xlink:href="#anchor-link-icon" /></svg></div></a>`,
|
|
372
368
|
`<button title="Post a comment" class="comment-link" data-feedback-hash="${hash}">`,
|
|
373
369
|
'<svg><use xlink:href="#comment-link-icon" /></svg>',
|
|
374
370
|
`</button>`,
|
package/parseMarkdown.test.js
CHANGED
|
@@ -295,9 +295,9 @@ authors:
|
|
|
295
295
|
).to.equal(
|
|
296
296
|
[
|
|
297
297
|
`<h1>Accordion</h1>`,
|
|
298
|
-
`<h2 id="basic-features"
|
|
299
|
-
`<h2 id="using-slots-and-slotprops"
|
|
300
|
-
`<h3 id="specific-example"
|
|
298
|
+
`<h2 id="basic-features"><a href="#basic-features" class="title-link-to-anchor">Basic features 🧪<div class="anchor-icon"><svg><use xlink:href="#anchor-link-icon" /></svg></div></a><button title="Post a comment" class="comment-link" data-feedback-hash="basic-features"><svg><use xlink:href="#comment-link-icon" /></svg></button></h2>`,
|
|
299
|
+
`<h2 id="using-slots-and-slotprops"><a href="#using-slots-and-slotprops" class="title-link-to-anchor">Using <code>slots</code> and <code>slotProps</code><div class="anchor-icon"><svg><use xlink:href="#anchor-link-icon" /></svg></div></a><button title="Post a comment" class="comment-link" data-feedback-hash="using-slots-and-slotprops"><svg><use xlink:href="#comment-link-icon" /></svg></button></h2>`,
|
|
300
|
+
`<h3 id="specific-example"><a href="#specific-example" class="title-link-to-anchor">Specific example<div class="anchor-icon"><svg><use xlink:href="#anchor-link-icon" /></svg></div></a><button title="Post a comment" class="comment-link" data-feedback-hash="specific-example"><svg><use xlink:href="#comment-link-icon" /></svg></button></h3>`,
|
|
301
301
|
].join(''),
|
|
302
302
|
);
|
|
303
303
|
|
package/prepareMarkdown.js
CHANGED