@mui/internal-code-infra 0.0.4-canary.3 → 0.0.4-canary.31

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 (69) hide show
  1. package/README.md +19 -8
  2. package/build/babel-config.d.mts +11 -3
  3. package/build/brokenLinksChecker/crawlWorker.d.mts +1 -0
  4. package/build/brokenLinksChecker/index.d.mts +35 -2
  5. package/build/changelog/types.d.ts +1 -1
  6. package/build/cli/cmdArgosPush.d.mts +2 -2
  7. package/build/cli/cmdBuild.d.mts +2 -2
  8. package/build/cli/cmdCopyFiles.d.mts +2 -2
  9. package/build/cli/cmdExtractErrorCodes.d.mts +2 -2
  10. package/build/cli/cmdGenerateChangelog.d.mts +2 -2
  11. package/build/cli/cmdGithubAuth.d.mts +2 -2
  12. package/build/cli/cmdListWorkspaces.d.mts +4 -2
  13. package/build/cli/cmdNetlifyIgnore.d.mts +2 -2
  14. package/build/cli/cmdPublish.d.mts +4 -2
  15. package/build/cli/cmdPublishCanary.d.mts +3 -2
  16. package/build/cli/cmdPublishNewPackage.d.mts +4 -2
  17. package/build/cli/cmdSetVersionOverrides.d.mts +2 -2
  18. package/build/cli/cmdVale.d.mts +46 -0
  19. package/build/cli/cmdValidateBuiltTypes.d.mts +2 -2
  20. package/build/eslint/mui/rules/disallow-react-api-in-server-components.d.mts +2 -2
  21. package/build/eslint/mui/rules/docgen-ignore-before-comment.d.mts +2 -2
  22. package/build/eslint/mui/rules/no-restricted-resolved-imports.d.mts +2 -2
  23. package/build/markdownlint/duplicate-h1.d.mts +1 -1
  24. package/build/markdownlint/git-diff.d.mts +1 -1
  25. package/build/markdownlint/index.d.mts +1 -1
  26. package/build/markdownlint/straight-quotes.d.mts +1 -1
  27. package/build/markdownlint/table-alignment.d.mts +1 -1
  28. package/build/markdownlint/terminal-language.d.mts +1 -1
  29. package/build/utils/build.d.mts +3 -3
  30. package/build/utils/github.d.mts +1 -1
  31. package/build/utils/pnpm.d.mts +68 -2
  32. package/build/utils/testUtils.d.mts +7 -0
  33. package/package.json +38 -31
  34. package/src/babel-config.mjs +9 -3
  35. package/src/brokenLinksChecker/__fixtures__/static-site/index.html +1 -0
  36. package/src/brokenLinksChecker/__fixtures__/static-site/invalid-html.html +15 -0
  37. package/src/brokenLinksChecker/crawlWorker.mjs +173 -0
  38. package/src/brokenLinksChecker/index.mjs +177 -164
  39. package/src/brokenLinksChecker/index.test.ts +55 -13
  40. package/src/build-env.d.ts +13 -0
  41. package/src/changelog/fetchChangelogs.mjs +6 -2
  42. package/src/changelog/types.ts +1 -1
  43. package/src/cli/cmdListWorkspaces.mjs +9 -2
  44. package/src/cli/cmdNetlifyIgnore.mjs +4 -88
  45. package/src/cli/cmdPublish.mjs +51 -14
  46. package/src/cli/cmdPublishCanary.mjs +139 -107
  47. package/src/cli/cmdPublishNewPackage.mjs +27 -6
  48. package/src/cli/cmdVale.mjs +513 -0
  49. package/src/cli/cmdVale.test.mjs +644 -0
  50. package/src/cli/index.mjs +2 -0
  51. package/src/eslint/baseConfig.mjs +2 -1
  52. package/src/eslint/docsConfig.mjs +2 -1
  53. package/src/eslint/jsonConfig.mjs +2 -1
  54. package/src/eslint/mui/config.mjs +11 -1
  55. package/src/eslint/testConfig.mjs +2 -1
  56. package/src/estree-typescript.d.ts +1 -1
  57. package/src/untyped-plugins.d.ts +11 -11
  58. package/src/utils/build.test.mjs +546 -575
  59. package/src/utils/pnpm.mjs +192 -3
  60. package/src/utils/pnpm.test.mjs +580 -0
  61. package/src/utils/testUtils.mjs +18 -0
  62. package/src/utils/typescript.test.mjs +249 -272
  63. package/vale/.vale.ini +1 -0
  64. package/vale/styles/MUI/CorrectReferenceAllCases.yml +43 -0
  65. package/vale/styles/MUI/CorrectRererenceCased.yml +14 -0
  66. package/vale/styles/MUI/GoogleLatin.yml +11 -0
  67. package/vale/styles/MUI/MuiBrandName.yml +22 -0
  68. package/vale/styles/MUI/NoBritish.yml +112 -0
  69. package/vale/styles/MUI/NoCompanyName.yml +17 -0
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@mui/internal-code-infra",
3
- "version": "0.0.4-canary.3",
3
+ "version": "0.0.4-canary.31",
4
+ "author": "MUI Team",
4
5
  "description": "Infra scripts and configs to be used across MUI repos.",
5
- "type": "module",
6
6
  "license": "MIT",
7
+ "type": "module",
7
8
  "repository": {
8
9
  "type": "git",
9
10
  "url": "git+https://github.com/mui/mui-public.git",
@@ -43,34 +44,38 @@
43
44
  "./brokenLinksChecker": {
44
45
  "types": "./build/brokenLinksChecker/index.d.mts",
45
46
  "default": "./src/brokenLinksChecker/index.mjs"
47
+ },
48
+ "./build-env": {
49
+ "types": "./src/build-env.d.ts"
46
50
  }
47
51
  },
48
52
  "bin": {
49
53
  "code-infra": "./bin/code-infra.mjs"
50
54
  },
51
55
  "dependencies": {
52
- "@argos-ci/core": "^4.5.0",
56
+ "@argos-ci/core": "^5.2.0",
53
57
  "@babel/cli": "^7.28.6",
54
58
  "@babel/core": "^7.29.0",
55
59
  "@babel/plugin-syntax-jsx": "^7.28.6",
56
60
  "@babel/plugin-syntax-typescript": "^7.28.6",
57
61
  "@babel/plugin-transform-runtime": "^7.29.0",
58
- "@babel/preset-env": "^7.29.0",
62
+ "@babel/preset-env": "^7.29.2",
59
63
  "@babel/preset-react": "^7.28.5",
60
64
  "@babel/preset-typescript": "^7.28.5",
61
- "@eslint/compat": "^2.0.2",
65
+ "@eslint/compat": "^2.0.3",
66
+ "@eslint/config-helpers": "^0.5.4",
62
67
  "@eslint/js": "^10.0.1",
63
- "@eslint/json": "^1.0.1",
64
- "@inquirer/confirm": "^6.0.4",
65
- "@inquirer/select": "^5.0.4",
68
+ "@eslint/json": "^1.1.0",
69
+ "@inquirer/confirm": "^6.0.11",
70
+ "@inquirer/select": "^5.1.3",
66
71
  "@napi-rs/keyring": "^1.2.0",
67
72
  "@octokit/auth-action": "^6.0.2",
68
73
  "@octokit/oauth-methods": "^6.0.2",
69
74
  "@octokit/rest": "^22.0.1",
70
- "@pnpm/find-workspace-dir": "^1000.1.4",
71
- "@typescript-eslint/types": "^8.56.1",
72
- "@typescript-eslint/utils": "^8.56.1",
73
- "@vitest/eslint-plugin": "^1.6.9",
75
+ "@pnpm/find-workspace-dir": "^1000.1.5",
76
+ "@typescript-eslint/types": "^8.57.1",
77
+ "@typescript-eslint/utils": "^8.57.1",
78
+ "@vitest/eslint-plugin": "^1.6.11",
74
79
  "babel-plugin-optimize-clsx": "^2.6.2",
75
80
  "babel-plugin-react-compiler": "^1.0.0",
76
81
  "babel-plugin-transform-import-meta": "^2.3.3",
@@ -78,13 +83,14 @@
78
83
  "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
79
84
  "babel-plugin-transform-remove-imports": "^1.8.1",
80
85
  "chalk": "^5.6.2",
81
- "clipboardy": "^5.3.0",
86
+ "clipboardy": "^5.3.1",
82
87
  "content-type": "^1.0.5",
83
88
  "env-ci": "^11.2.0",
89
+ "es-toolkit": "^1.45.1",
84
90
  "eslint-config-prettier": "^10.1.8",
85
91
  "eslint-import-resolver-typescript": "^4.4.4",
86
92
  "eslint-module-utils": "^2.12.1",
87
- "eslint-plugin-compat": "^6.2.0",
93
+ "eslint-plugin-compat": "^7.0.1",
88
94
  "eslint-plugin-import": "^2.32.0",
89
95
  "eslint-plugin-jsx-a11y": "^6.10.2",
90
96
  "eslint-plugin-mocha": "^11.2.0",
@@ -92,14 +98,14 @@
92
98
  "eslint-plugin-react-compiler": "^19.1.0-rc.2",
93
99
  "eslint-plugin-react-hooks": "^7.0.1",
94
100
  "eslint-plugin-testing-library": "^7.16.0",
95
- "es-toolkit": "^1.44.0",
96
101
  "execa": "^9.6.1",
97
102
  "git-url-parse": "^16.1.0",
98
- "globals": "^16.5.0",
103
+ "globals": "^17.5.0",
99
104
  "globby": "^16.1.1",
100
- "minimatch": "^10.2.2",
101
- "node-html-parser": "^7.0.2",
102
- "open": "^10.2.0",
105
+ "html-validate": "^10.13.0",
106
+ "minimatch": "^10.2.5",
107
+ "node-html-parser": "^7.1.0",
108
+ "open": "^11.0.0",
103
109
  "postcss-styled-syntax": "^0.7.1",
104
110
  "regexp.escape": "^2.0.1",
105
111
  "rehype-slug": "^6.0.0",
@@ -110,12 +116,12 @@
110
116
  "resolve-pkg-maps": "^1.0.0",
111
117
  "semver": "^7.7.4",
112
118
  "stylelint-config-standard": "^40.0.0",
113
- "typescript-eslint": "^8.56.1",
119
+ "typescript-eslint": "^8.57.1",
114
120
  "unified": "^11.0.5",
115
121
  "yargs": "^18.0.0",
116
- "@mui/internal-babel-plugin-display-name": "1.0.4-canary.14",
117
- "@mui/internal-babel-plugin-resolve-imports": "2.0.7-canary.33",
118
- "@mui/internal-babel-plugin-minify-errors": "2.0.8-canary.24"
122
+ "@mui/internal-babel-plugin-display-name": "1.0.4-canary.18",
123
+ "@mui/internal-babel-plugin-minify-errors": "2.0.8-canary.27",
124
+ "@mui/internal-babel-plugin-resolve-imports": "2.0.7-canary.36"
119
125
  },
120
126
  "peerDependencies": {
121
127
  "@next/eslint-plugin-next": "*",
@@ -143,25 +149,26 @@
143
149
  "@types/estree-jsx": "1.0.5",
144
150
  "@types/regexp.escape": "2.0.0",
145
151
  "@types/yargs": "17.0.35",
146
- "@typescript-eslint/parser": "8.56.1",
147
- "@typescript-eslint/rule-tester": "8.56.1",
148
- "eslint": "10.0.2",
149
- "get-port": "7.1.0",
150
- "prettier": "3.8.1",
151
- "serve": "14.2.5",
152
- "typescript-eslint": "8.56.1"
152
+ "@typescript-eslint/parser": "8.57.1",
153
+ "@typescript-eslint/rule-tester": "8.57.1",
154
+ "eslint": "10.0.3",
155
+ "get-port": "7.2.0",
156
+ "prettier": "3.8.3",
157
+ "serve": "14.2.6",
158
+ "typescript-eslint": "8.57.1"
153
159
  },
154
160
  "files": [
155
161
  "bin",
156
162
  "build",
157
163
  "src",
164
+ "vale",
158
165
  "README.md",
159
166
  "LICENSE"
160
167
  ],
161
168
  "publishConfig": {
162
169
  "access": "public"
163
170
  },
164
- "gitSha": "b172a15e6b44720b15353ba8b15816cbbf5674e8",
171
+ "gitSha": "b5ecb08ed447855ed858e123d924a08949b6ad6d",
165
172
  "scripts": {
166
173
  "build": "tsgo -p tsconfig.build.json",
167
174
  "typescript": "tsgo -noEmit",
@@ -10,6 +10,10 @@ import pluginTransformImportMeta from 'babel-plugin-transform-import-meta';
10
10
  import pluginTransformInlineEnvVars from 'babel-plugin-transform-inline-environment-variables';
11
11
  import pluginRemovePropTypes from 'babel-plugin-transform-react-remove-prop-types';
12
12
 
13
+ /**
14
+ * @typedef {'annotation' | 'syntax' | 'infer' | 'all'} ReactCompilationMode
15
+ */
16
+
13
17
  /**
14
18
  * @param {Object} param0
15
19
  * @param {boolean} [param0.debug]
@@ -20,7 +24,8 @@ import pluginRemovePropTypes from 'babel-plugin-transform-react-remove-prop-type
20
24
  * @param {string | null} param0.outExtension - Specify the output file extension.
21
25
  * @param {string} param0.runtimeVersion
22
26
  * @param {string} [param0.reactCompilerReactVersion]
23
- * @param {string} [param0.reactCompilerMode]
27
+ * @param {ReactCompilationMode} [param0.reactCompilerMode]
28
+ * @param {{ allowedCallees?: Record<string, string[]> }} [param0.displayName] - Options for the display name plugin.
24
29
  * @returns {import('@babel/core').TransformOptions} The base Babel configuration.
25
30
  */
26
31
  export function getBaseConfig({
@@ -33,6 +38,7 @@ export function getBaseConfig({
33
38
  outExtension,
34
39
  reactCompilerReactVersion,
35
40
  reactCompilerMode,
41
+ displayName,
36
42
  }) {
37
43
  /**
38
44
  * @type {import('@babel/preset-env').Options}
@@ -57,7 +63,7 @@ export function getBaseConfig({
57
63
  },
58
64
  '@babel/plugin-transform-runtime',
59
65
  ],
60
- [pluginDisplayName, {}, '@mui/internal-babel-plugin-display-name'],
66
+ [pluginDisplayName, { ...displayName }, '@mui/internal-babel-plugin-display-name'],
61
67
  [
62
68
  pluginTransformInlineEnvVars,
63
69
  {
@@ -183,6 +189,6 @@ export default function getBabelConfig(api) {
183
189
  removePropTypes: process.env.MUI_REMOVE_PROP_TYPES === 'true',
184
190
  noResolveImports,
185
191
  reactCompilerReactVersion: process.env.MUI_REACT_COMPILER_REACT_VERSION,
186
- reactCompilerMode: process.env.MUI_REACT_COMPILER_MODE,
192
+ reactCompilerMode: /** @type {ReactCompilationMode} */ (process.env.MUI_REACT_COMPILER_MODE),
187
193
  });
188
194
  }
@@ -22,6 +22,7 @@
22
22
  <li><a href="/page-with-api-links.html">Page with API Links</a></li>
23
23
  <li><a href="/example.md">Example Markdown</a></li>
24
24
  <li><a href="/unclosed-tags.html">Page with Unclosed Tags</a></li>
25
+ <li><a href="/invalid-html.html">Invalid HTML Page</a></li>
25
26
  </ul>
26
27
  </nav>
27
28
  </body>
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Invalid HTML Page</title>
6
+ </head>
7
+ <body>
8
+ <h1>Invalid HTML</h1>
9
+ <!-- Duplicate ID (violates no-duplicate-id rule) -->
10
+ <div id="dup">First</div>
11
+ <div id="dup">Second</div>
12
+ <!-- Raw ampersand (violates no-raw-characters rule) -->
13
+ <p>Tom & Jerry</p>
14
+ </body>
15
+ </html>
@@ -0,0 +1,173 @@
1
+ import { workerData, parentPort } from 'node:worker_threads';
2
+ import { parse } from 'node-html-parser';
3
+ import contentType from 'content-type';
4
+ import { HtmlValidate, StaticConfigLoader, staticResolver } from 'html-validate';
5
+ import { unified } from 'unified';
6
+ import remarkParse from 'remark-parse';
7
+ import remarkGfm from 'remark-gfm';
8
+ import remarkRehype from 'remark-rehype';
9
+ import rehypeSlug from 'rehype-slug';
10
+ import rehypeStringify from 'rehype-stringify';
11
+
12
+ /** @type {import('./index.mjs').CrawlWorkerInput} */
13
+ const { pageUrl, options } = workerData;
14
+
15
+ /**
16
+ * Posts the crawl result back to the parent thread.
17
+ * @param {import('./index.mjs').CrawlWorkerOutput} output
18
+ */
19
+ function postResult(output) {
20
+ if (!parentPort) {
21
+ throw new Error('crawlWorker must be run as a worker thread');
22
+ }
23
+ parentPort.postMessage(output);
24
+ }
25
+
26
+ /**
27
+ * Computes the accessible name of an element according to ARIA rules.
28
+ * @param {import('node-html-parser').HTMLElement | null} elm
29
+ * @param {import('node-html-parser').HTMLElement} ownerDocument
30
+ * @returns {string}
31
+ */
32
+ function getAccessibleName(elm, ownerDocument) {
33
+ if (!elm) {
34
+ return '';
35
+ }
36
+
37
+ const ariaLabel = elm.getAttribute('aria-label')?.trim();
38
+ if (ariaLabel) {
39
+ return ariaLabel;
40
+ }
41
+
42
+ const labelledby = elm.getAttribute('aria-labelledby');
43
+ if (labelledby) {
44
+ const labels = [];
45
+ for (const id of labelledby.split(/\s+/)) {
46
+ const label = getAccessibleName(ownerDocument.getElementById(id), ownerDocument);
47
+ if (label) {
48
+ labels.push(label);
49
+ }
50
+ }
51
+ const label = labels.join(' ').trim();
52
+ if (label) {
53
+ return label;
54
+ }
55
+ }
56
+
57
+ if (elm.id) {
58
+ const label = ownerDocument.querySelector(`label[for="${elm.id}"]`);
59
+ if (label) {
60
+ return getAccessibleName(label, ownerDocument);
61
+ }
62
+ }
63
+
64
+ if (elm.tagName === 'IMG') {
65
+ const alt = elm.getAttribute('alt')?.trim();
66
+ if (alt) {
67
+ return alt;
68
+ }
69
+ }
70
+
71
+ return elm.innerText.trim();
72
+ }
73
+
74
+ /**
75
+ * Converts markdown content to HTML using unified pipeline.
76
+ * @param {string} markdown
77
+ * @returns {Promise<string>}
78
+ */
79
+ async function markdownToHtml(markdown) {
80
+ const result = await unified()
81
+ .use(remarkParse)
82
+ .use(remarkGfm)
83
+ .use(remarkRehype)
84
+ .use(rehypeSlug)
85
+ .use(rehypeStringify)
86
+ .process(markdown);
87
+ return String(result);
88
+ }
89
+
90
+ const res = await fetch(new URL(pageUrl, options.host));
91
+
92
+ const contentTypeHeader = res.headers.get('content-type');
93
+ let type = 'text/html';
94
+
95
+ if (contentTypeHeader) {
96
+ try {
97
+ const parsed = contentType.parse(contentTypeHeader);
98
+ type = parsed.type;
99
+ } catch {
100
+ // invalid content-type, default to text/html
101
+ }
102
+ }
103
+
104
+ /** @type {import('./index.mjs').CrawlWorkerPageData} */
105
+ const pageData = {
106
+ url: pageUrl,
107
+ status: res.status,
108
+ targets: [],
109
+ contentType: type,
110
+ };
111
+
112
+ if (pageData.status < 200 || pageData.status >= 400) {
113
+ postResult({ pageData, links: [], htmlValidateResults: null });
114
+ } else if (type.startsWith('image/') || (type !== 'text/html' && type !== 'text/markdown')) {
115
+ postResult({ pageData, links: [], htmlValidateResults: null });
116
+ } else {
117
+ const rawContent = await res.text();
118
+
119
+ const content = type === 'text/markdown' ? await markdownToHtml(rawContent) : rawContent;
120
+
121
+ const dom = parse(content, { parseNoneClosedTags: true });
122
+
123
+ // Extract targets
124
+ for (const target of dom.querySelectorAll('*[id]')) {
125
+ if (!options.ignoredTargets.has(target.id)) {
126
+ pageData.targets.push(`#${target.id}`);
127
+ }
128
+ }
129
+
130
+ // Extract links
131
+ let ignoredSelector = ':not(*)';
132
+ if (options.ignoredContent.length > 0) {
133
+ ignoredSelector = Array.from(options.ignoredContent)
134
+ .flatMap((selector) => [selector, `${selector} *`])
135
+ .join(',');
136
+ }
137
+ const linksSelector = `a[href]:not(${ignoredSelector})`;
138
+
139
+ const links = dom.querySelectorAll(linksSelector).map((a) => ({
140
+ src: pageUrl,
141
+ text: getAccessibleName(a, dom),
142
+ href: a.getAttribute('href') ?? '',
143
+ contentType: type,
144
+ }));
145
+
146
+ // HTML validation
147
+ /** @type {{ pageUrl: string, results: import('html-validate').Result[] } | null} */
148
+ let htmlValidateResults = null;
149
+ if (options.htmlValidate && type === 'text/html') {
150
+ const muiHtmlValidateResolver = staticResolver({
151
+ configs: {
152
+ 'mui:recommended': {
153
+ extends: ['html-validate:standard', 'html-validate:document', 'html-validate:browser'],
154
+ rules: {
155
+ // TODO: Enable when subresource integrity is adopted across projects
156
+ 'require-sri': 'off',
157
+ },
158
+ },
159
+ },
160
+ });
161
+
162
+ const htmlValidator = new HtmlValidate(
163
+ new StaticConfigLoader([muiHtmlValidateResolver], options.htmlValidate),
164
+ );
165
+
166
+ const report = await htmlValidator.validateString(rawContent, pageUrl);
167
+ if (!report.valid) {
168
+ htmlValidateResults = { pageUrl, results: report.results };
169
+ }
170
+ }
171
+
172
+ postResult({ pageData, links, htmlValidateResults });
173
+ }