@mui/internal-code-infra 0.0.4-canary.6 → 0.0.4-canary.60
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/LICENSE +1 -1
- package/README.md +19 -8
- package/build/babel-config.d.mts +11 -3
- package/build/brokenLinksChecker/crawlWorker.d.mts +1 -0
- package/build/brokenLinksChecker/index.d.mts +45 -2
- package/build/changelog/types.d.ts +1 -1
- package/build/cli/cmdArgosPush.d.mts +2 -2
- package/build/cli/cmdBuild.d.mts +3 -2
- package/build/cli/cmdCopyFiles.d.mts +2 -2
- package/build/cli/cmdExtractErrorCodes.d.mts +2 -2
- package/build/cli/cmdGenerateChangelog.d.mts +2 -2
- package/build/cli/cmdGithubAuth.d.mts +2 -2
- package/build/cli/cmdListWorkspaces.d.mts +6 -4
- package/build/cli/cmdNetlifyIgnore.d.mts +3 -2
- package/build/cli/cmdPublish.d.mts +4 -2
- package/build/cli/cmdPublishCanary.d.mts +3 -3
- package/build/cli/cmdPublishNewPackage.d.mts +4 -2
- package/build/cli/cmdSetVersionOverrides.d.mts +2 -2
- package/build/cli/cmdVale.d.mts +46 -0
- package/build/cli/cmdValidateBuiltTypes.d.mts +2 -2
- package/build/eslint/baseConfig.d.mts +3 -1
- package/build/eslint/mui/rules/disallow-react-api-in-server-components.d.mts +2 -2
- package/build/eslint/mui/rules/docgen-ignore-before-comment.d.mts +2 -2
- package/build/eslint/mui/rules/no-guarded-throw.d.mts +31 -0
- package/build/eslint/mui/rules/no-presentation-role.d.mts +5 -0
- package/build/eslint/mui/rules/no-restricted-resolved-imports.d.mts +2 -2
- package/build/eslint/mui/rules/nodeEnvUtils.d.mts +18 -0
- package/build/markdownlint/duplicate-h1.d.mts +1 -1
- package/build/markdownlint/git-diff.d.mts +1 -1
- package/build/markdownlint/index.d.mts +1 -1
- package/build/markdownlint/straight-quotes.d.mts +1 -1
- package/build/markdownlint/table-alignment.d.mts +1 -1
- package/build/markdownlint/terminal-language.d.mts +1 -1
- package/build/remark/config.d.mts +43 -0
- package/build/remark/createLintTester.d.mts +10 -0
- package/build/remark/firstBlockHeading.d.mts +4 -0
- package/build/remark/gitDiff.d.mts +2 -0
- package/build/remark/noSpaceInLinks.d.mts +2 -0
- package/build/remark/straightQuotes.d.mts +2 -0
- package/build/remark/tableAlignment.d.mts +2 -0
- package/build/remark/terminalLanguage.d.mts +2 -0
- package/build/utils/babel.d.mts +1 -1
- package/build/utils/build.d.mts +61 -25
- package/build/utils/github.d.mts +1 -1
- package/build/utils/pnpm.d.mts +68 -2
- package/build/utils/testUtils.d.mts +7 -0
- package/build/utils/typescript.d.mts +2 -2
- package/package.json +61 -34
- package/src/babel-config.mjs +9 -3
- package/src/brokenLinksChecker/__fixtures__/static-site/index.html +1 -0
- package/src/brokenLinksChecker/__fixtures__/static-site/invalid-html.html +15 -0
- package/src/brokenLinksChecker/crawlWorker.mjs +217 -0
- package/src/brokenLinksChecker/index.mjs +217 -164
- package/src/brokenLinksChecker/index.test.ts +50 -13
- package/src/changelog/categorizeCommits.test.ts +5 -5
- package/src/changelog/fetchChangelogs.mjs +6 -2
- package/src/changelog/parseCommitLabels.test.ts +5 -5
- package/src/changelog/renderChangelog.mjs +1 -1
- package/src/changelog/types.ts +1 -1
- package/src/cli/cmdBuild.mjs +39 -16
- package/src/cli/cmdListWorkspaces.mjs +12 -27
- package/src/cli/cmdNetlifyIgnore.mjs +34 -93
- package/src/cli/cmdPublish.mjs +55 -15
- package/src/cli/cmdPublishCanary.mjs +128 -132
- package/src/cli/cmdPublishNewPackage.mjs +27 -6
- package/src/cli/cmdVale.mjs +513 -0
- package/src/cli/cmdVale.test.mjs +644 -0
- package/src/cli/index.mjs +2 -0
- package/src/cli/packageJson.d.ts +1 -1
- package/src/eslint/baseConfig.mjs +45 -20
- package/src/eslint/docsConfig.mjs +4 -2
- package/src/eslint/jsonConfig.mjs +2 -1
- package/src/eslint/mui/config.mjs +24 -4
- package/src/eslint/mui/index.mjs +4 -0
- package/src/eslint/mui/rules/no-guarded-throw.mjs +115 -0
- package/src/eslint/mui/rules/no-guarded-throw.test.mjs +206 -0
- package/src/eslint/mui/rules/no-presentation-role.mjs +60 -0
- package/src/eslint/mui/rules/no-presentation-role.test.mjs +33 -0
- package/src/eslint/mui/rules/nodeEnvUtils.mjs +52 -0
- package/src/eslint/mui/rules/require-dev-wrapper.mjs +25 -40
- package/src/eslint/testConfig.mjs +2 -1
- package/src/estree-typescript.d.ts +1 -1
- package/src/remark/config.mjs +157 -0
- package/src/remark/createLintTester.mjs +19 -0
- package/src/remark/firstBlockHeading.mjs +87 -0
- package/src/remark/firstBlockHeading.test.mjs +107 -0
- package/src/remark/gitDiff.mjs +43 -0
- package/src/remark/gitDiff.test.mjs +45 -0
- package/src/remark/noSpaceInLinks.mjs +42 -0
- package/src/remark/noSpaceInLinks.test.mjs +22 -0
- package/src/remark/straightQuotes.mjs +31 -0
- package/src/remark/straightQuotes.test.mjs +25 -0
- package/src/remark/tableAlignment.mjs +23 -0
- package/src/remark/tableAlignment.test.mjs +28 -0
- package/src/remark/terminalLanguage.mjs +19 -0
- package/src/remark/terminalLanguage.test.mjs +17 -0
- package/src/untyped-plugins.d.ts +11 -11
- package/src/utils/build.mjs +621 -256
- package/src/utils/build.test.mjs +1064 -485
- package/src/utils/git.mjs +16 -7
- package/src/utils/pnpm.mjs +192 -3
- package/src/utils/pnpm.test.mjs +580 -0
- package/src/utils/testUtils.mjs +18 -0
- package/src/utils/typescript.test.mjs +249 -272
- package/vale/.vale.ini +1 -0
- package/vale/styles/MUI/CorrectReferenceAllCases.yml +43 -0
- package/vale/styles/MUI/CorrectRererenceCased.yml +14 -0
- package/vale/styles/MUI/GoogleLatin.yml +11 -0
- package/vale/styles/MUI/MuiBrandName.yml +22 -0
- package/vale/styles/MUI/NoBritish.yml +112 -0
- package/vale/styles/MUI/NoCompanyName.yml +17 -0
|
@@ -0,0 +1,217 @@
|
|
|
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
|
+
* Tests if a value matches any of the patterns in the array.
|
|
17
|
+
* Returns true if patterns is undefined/empty (wildcard behavior).
|
|
18
|
+
* Strings use exact match, RegExp uses .test().
|
|
19
|
+
* @param {string} value
|
|
20
|
+
* @param {(string | RegExp)[] | undefined} patterns
|
|
21
|
+
* @returns {boolean}
|
|
22
|
+
*/
|
|
23
|
+
function matchesAnyPattern(value, patterns) {
|
|
24
|
+
if (!patterns || patterns.length === 0) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return patterns.some((pattern) =>
|
|
28
|
+
typeof pattern === 'string' ? value === pattern : pattern.test(value),
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Posts the crawl result back to the parent thread.
|
|
34
|
+
* @param {import('./index.mjs').CrawlWorkerOutput} output
|
|
35
|
+
*/
|
|
36
|
+
function postResult(output) {
|
|
37
|
+
if (!parentPort) {
|
|
38
|
+
throw new Error('crawlWorker must be run as a worker thread');
|
|
39
|
+
}
|
|
40
|
+
parentPort.postMessage(output);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Computes the accessible name of an element according to ARIA rules.
|
|
45
|
+
* @param {import('node-html-parser').HTMLElement | null} elm
|
|
46
|
+
* @param {import('node-html-parser').HTMLElement} ownerDocument
|
|
47
|
+
* @returns {string}
|
|
48
|
+
*/
|
|
49
|
+
function getAccessibleName(elm, ownerDocument) {
|
|
50
|
+
if (!elm) {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const ariaLabel = elm.getAttribute('aria-label')?.trim();
|
|
55
|
+
if (ariaLabel) {
|
|
56
|
+
return ariaLabel;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const labelledby = elm.getAttribute('aria-labelledby');
|
|
60
|
+
if (labelledby) {
|
|
61
|
+
const labels = [];
|
|
62
|
+
for (const id of labelledby.split(/\s+/)) {
|
|
63
|
+
const label = getAccessibleName(ownerDocument.getElementById(id), ownerDocument);
|
|
64
|
+
if (label) {
|
|
65
|
+
labels.push(label);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const label = labels.join(' ').trim();
|
|
69
|
+
if (label) {
|
|
70
|
+
return label;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (elm.id) {
|
|
75
|
+
const label = ownerDocument.querySelector(`label[for="${elm.id}"]`);
|
|
76
|
+
if (label) {
|
|
77
|
+
return getAccessibleName(label, ownerDocument);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (elm.tagName === 'IMG') {
|
|
82
|
+
const alt = elm.getAttribute('alt')?.trim();
|
|
83
|
+
if (alt) {
|
|
84
|
+
return alt;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return elm.innerText.trim();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Converts markdown content to HTML using unified pipeline.
|
|
93
|
+
* @param {string} markdown
|
|
94
|
+
* @returns {Promise<string>}
|
|
95
|
+
*/
|
|
96
|
+
async function markdownToHtml(markdown) {
|
|
97
|
+
const result = await unified()
|
|
98
|
+
.use(remarkParse)
|
|
99
|
+
.use(remarkGfm)
|
|
100
|
+
.use(remarkRehype)
|
|
101
|
+
.use(rehypeSlug)
|
|
102
|
+
.use(rehypeStringify)
|
|
103
|
+
.process(markdown);
|
|
104
|
+
return String(result);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const res = await fetch(new URL(pageUrl, options.host));
|
|
108
|
+
|
|
109
|
+
const contentTypeHeader = res.headers.get('content-type');
|
|
110
|
+
let type = 'text/html';
|
|
111
|
+
|
|
112
|
+
if (contentTypeHeader) {
|
|
113
|
+
try {
|
|
114
|
+
const parsed = contentType.parse(contentTypeHeader);
|
|
115
|
+
type = parsed.type;
|
|
116
|
+
} catch {
|
|
117
|
+
// invalid content-type, default to text/html
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @type {import('./index.mjs').CrawlWorkerPageData} */
|
|
122
|
+
const pageData = {
|
|
123
|
+
url: pageUrl,
|
|
124
|
+
status: res.status,
|
|
125
|
+
targets: [],
|
|
126
|
+
contentType: type,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
if (pageData.status < 200 || pageData.status >= 400) {
|
|
130
|
+
postResult({ pageData, links: [], htmlValidateResults: null });
|
|
131
|
+
} else if (type.startsWith('image/') || (type !== 'text/html' && type !== 'text/markdown')) {
|
|
132
|
+
postResult({ pageData, links: [], htmlValidateResults: null });
|
|
133
|
+
} else {
|
|
134
|
+
const rawContent = await res.text();
|
|
135
|
+
|
|
136
|
+
const content = type === 'text/markdown' ? await markdownToHtml(rawContent) : rawContent;
|
|
137
|
+
|
|
138
|
+
const dom = parse(content, { parseNoneClosedTags: true });
|
|
139
|
+
|
|
140
|
+
// Extract targets
|
|
141
|
+
for (const target of dom.querySelectorAll('*[id]')) {
|
|
142
|
+
if (!options.ignoredTargets.has(target.id)) {
|
|
143
|
+
pageData.targets.push(`#${target.id}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Extract links
|
|
148
|
+
let ignoredSelector = ':not(*)';
|
|
149
|
+
if (options.ignoredContent.length > 0) {
|
|
150
|
+
ignoredSelector = Array.from(options.ignoredContent)
|
|
151
|
+
.flatMap((selector) => [selector, `${selector} *`])
|
|
152
|
+
.join(',');
|
|
153
|
+
}
|
|
154
|
+
const linksSelector = `a[href]:not(${ignoredSelector})`;
|
|
155
|
+
|
|
156
|
+
const links = dom.querySelectorAll(linksSelector).map((a) => ({
|
|
157
|
+
src: pageUrl,
|
|
158
|
+
text: getAccessibleName(a, dom),
|
|
159
|
+
href: a.getAttribute('href') ?? '',
|
|
160
|
+
contentType: type,
|
|
161
|
+
}));
|
|
162
|
+
|
|
163
|
+
// HTML validation. Every entry whose path matches contributes to the
|
|
164
|
+
// page's config: each is registered as a synthetic preset and the page's
|
|
165
|
+
// root config `extends` `mui:recommended` first, then the matched presets
|
|
166
|
+
// in order. When override configs do not specify their own `extends`,
|
|
167
|
+
// they behave as pure rule patches layered on top of `mui:recommended`,
|
|
168
|
+
// so a later entry can only change the rules it names directly. Override
|
|
169
|
+
// configs are passed through as-is, though, so an entry that declares its
|
|
170
|
+
// own `extends` can still pull in additional presets (including
|
|
171
|
+
// `mui:recommended`) and affect earlier downgrades. html-validate merges
|
|
172
|
+
// `extends` left to right.
|
|
173
|
+
/** @type {{ pageUrl: string, results: import('html-validate').Result[] } | null} */
|
|
174
|
+
let htmlValidateResults = null;
|
|
175
|
+
if (type === 'text/html' && options.htmlValidate.length > 0) {
|
|
176
|
+
const matchedEntries = options.htmlValidate.filter((entry) =>
|
|
177
|
+
matchesAnyPattern(pageUrl, entry.path),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
if (matchedEntries.length > 0) {
|
|
181
|
+
const overridePresets = Object.fromEntries(
|
|
182
|
+
matchedEntries.map((entry, index) => [`mui:override-${index}`, entry.config]),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const muiHtmlValidateResolver = staticResolver({
|
|
186
|
+
configs: {
|
|
187
|
+
'mui:recommended': {
|
|
188
|
+
extends: ['html-validate:standard', 'html-validate:document', 'html-validate:browser'],
|
|
189
|
+
rules: {
|
|
190
|
+
// TODO: Enable when subresource integrity is adopted across projects
|
|
191
|
+
'require-sri': 'off',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
...overridePresets,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const htmlValidator = new HtmlValidate(
|
|
199
|
+
new StaticConfigLoader([muiHtmlValidateResolver], {
|
|
200
|
+
extends: ['mui:recommended', ...Object.keys(overridePresets)],
|
|
201
|
+
}),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (options.verbose) {
|
|
205
|
+
const resolved = await htmlValidator.getConfigFor(pageUrl);
|
|
206
|
+
console.warn(
|
|
207
|
+
`[html-validate config] ${pageUrl}\n${JSON.stringify(resolved.getConfigData(), null, 2)}`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const report = await htmlValidator.validateString(rawContent, pageUrl);
|
|
212
|
+
htmlValidateResults = { pageUrl, results: report.results };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
postResult({ pageData, links, htmlValidateResults });
|
|
217
|
+
}
|