@mui/internal-markdown 1.0.1 → 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 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');
@@ -126,6 +126,8 @@ module.exports = async function demoLoader() {
126
126
  const components = {};
127
127
  const demoModuleIDs = new Set();
128
128
  const componentModuleIDs = new Set();
129
+ const nonEditableDemos = new Set();
130
+ const relativeModules = new Map();
129
131
  const demoNames = Array.from(
130
132
  new Set(
131
133
  docs.en.rendered
@@ -133,11 +135,71 @@ module.exports = async function demoLoader() {
133
135
  return typeof markdownOrComponentConfig !== 'string' && markdownOrComponentConfig.demo;
134
136
  })
135
137
  .map((demoConfig) => {
138
+ if (demoConfig.hideToolbar) {
139
+ nonEditableDemos.add(demoConfig.demo);
140
+ }
136
141
  return demoConfig.demo;
137
142
  }),
138
143
  ),
139
144
  );
140
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
+
141
203
  await Promise.all(
142
204
  demoNames.map(async (demoName) => {
143
205
  const multipleDemoVersionsUsed = !demoName.endsWith('.js');
@@ -164,9 +226,15 @@ module.exports = async function demoLoader() {
164
226
  raw: await fs.readFile(moduleFilepath, { encoding: 'utf8' }),
165
227
  };
166
228
  demoModuleIDs.add(moduleID);
167
- extractImports(demos[demoName].raw).forEach((importModuleID) =>
168
- importedModuleIDs.add(importModuleID),
169
- );
229
+
230
+ // Skip non-editable demos
231
+ if (!nonEditableDemos.has(demoName)) {
232
+ extractImports(demos[demoName].raw).forEach((importModuleID) => {
233
+ // detect relative import
234
+ detectRelativeImports(demoName, moduleFilepath, 'JS', importModuleID);
235
+ importedModuleIDs.add(importModuleID);
236
+ });
237
+ }
170
238
 
171
239
  if (multipleDemoVersionsUsed) {
172
240
  // Add Tailwind demo data
@@ -336,10 +404,69 @@ module.exports = async function demoLoader() {
336
404
  // But this leads to building both demo version i.e. more build time.
337
405
  demos[demoName].moduleTS = this.mode === 'production' ? moduleID : moduleTS;
338
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
+
339
417
  demoModuleIDs.add(demos[demoName].moduleTS);
340
418
  } catch (error) {
341
419
  // TS version of the demo doesn't exist. This is fine.
342
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
+ }
343
470
  }),
344
471
  );
345
472
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mui/internal-markdown",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "author": "MUI Team",
5
5
  "description": "MUI markdown parser. This is an internal package not meant for general use.",
6
6
  "main": "./index.js",
@@ -16,13 +16,13 @@
16
16
  "directory": "packages/markdown"
17
17
  },
18
18
  "dependencies": {
19
- "@babel/runtime": "^7.23.9",
19
+ "@babel/runtime": "^7.24.4",
20
20
  "lodash": "^4.17.21",
21
21
  "marked": "^5.1.2",
22
22
  "prismjs": "^1.29.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@types/chai": "^4.3.12",
25
+ "@types/chai": "^4.3.14",
26
26
  "chai": "^4.4.1"
27
27
  },
28
28
  "publishConfig": {
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>`,
@@ -295,9 +295,9 @@ authors:
295
295
  ).to.equal(
296
296
  [
297
297
  `<h1>Accordion</h1>`,
298
- `<h2 id="basic-features">Basic features 🧪<a aria-labelledby="basic-features" class="anchor-link" href="#basic-features" tabindex="-1"><svg><use xlink:href="#anchor-link-icon" /></svg></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">Using <code>slots</code> and <code>slotProps</code><a aria-labelledby="using-slots-and-slotprops" class="anchor-link" href="#using-slots-and-slotprops" tabindex="-1"><svg><use xlink:href="#anchor-link-icon" /></svg></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">Specific example<a aria-labelledby="specific-example" class="anchor-link" href="#specific-example" tabindex="-1"><svg><use xlink:href="#anchor-link-icon" /></svg></a><button title="Post a comment" class="comment-link" data-feedback-hash="specific-example"><svg><use xlink:href="#comment-link-icon" /></svg></button></h3>`,
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
 
@@ -110,7 +110,7 @@ This unstyled version of the component is the ideal choice for heavy customizati
110
110
  `);
111
111
  }
112
112
 
113
- if (headers.components.length > 0) {
113
+ if (headers.components.length > 0 && headers.productId !== 'base-ui') {
114
114
  contents.push(`
115
115
  ## API
116
116