@mui/internal-code-infra 0.0.4-canary.8 → 0.0.4-canary.81
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 +5 -1
- 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-floating-cleanup.d.mts +5 -0
- 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/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 +56 -37
- package/build/utils/git.d.mts +7 -0
- package/build/utils/github.d.mts +1 -1
- package/build/utils/pnpm.d.mts +81 -2
- package/build/utils/testUtils.d.mts +7 -0
- package/build/utils/typescript.d.mts +6 -16
- package/package.json +66 -42
- package/src/babel-config.mjs +3 -1
- package/src/brokenLinksChecker/crawlWorker.mjs +240 -0
- package/src/brokenLinksChecker/index.mjs +263 -188
- package/src/changelog/fetchChangelogs.mjs +6 -2
- package/src/changelog/renderChangelog.mjs +1 -1
- package/src/changelog/types.ts +1 -1
- package/src/cli/cmdBuild.mjs +51 -85
- package/src/cli/cmdListWorkspaces.mjs +12 -27
- package/src/cli/cmdNetlifyIgnore.mjs +34 -93
- package/src/cli/cmdPublish.mjs +95 -20
- package/src/cli/cmdPublishCanary.mjs +128 -132
- package/src/cli/cmdPublishNewPackage.mjs +27 -6
- package/src/cli/cmdSetVersionOverrides.mjs +8 -9
- package/src/cli/cmdVale.mjs +513 -0
- package/src/cli/index.mjs +2 -0
- package/src/cli/packageJson.d.ts +1 -1
- package/src/eslint/baseConfig.mjs +51 -19
- package/src/eslint/docsConfig.mjs +2 -1
- package/src/eslint/mui/config.mjs +24 -4
- package/src/eslint/mui/index.mjs +6 -0
- package/src/eslint/mui/rules/no-floating-cleanup.mjs +187 -0
- package/src/eslint/mui/rules/no-guarded-throw.mjs +115 -0
- package/src/eslint/mui/rules/no-presentation-role.mjs +60 -0
- package/src/eslint/mui/rules/nodeEnvUtils.mjs +52 -0
- package/src/eslint/mui/rules/require-dev-wrapper.mjs +25 -40
- 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/gitDiff.mjs +43 -0
- package/src/remark/noSpaceInLinks.mjs +42 -0
- package/src/remark/straightQuotes.mjs +31 -0
- package/src/remark/tableAlignment.mjs +23 -0
- package/src/remark/terminalLanguage.mjs +19 -0
- package/src/untyped-plugins.d.ts +11 -11
- package/src/utils/build.mjs +604 -270
- package/src/utils/git.mjs +27 -7
- package/src/utils/pnpm.mjs +277 -10
- package/src/utils/testUtils.mjs +18 -0
- package/src/utils/typescript.mjs +23 -42
- package/vale/.vale.ini +1 -0
- package/vale/styles/MUI/CorrectReferenceAllCases.yml +42 -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
- package/build/markdownlint/duplicate-h1.d.mts +0 -56
- package/build/markdownlint/git-diff.d.mts +0 -11
- package/build/markdownlint/index.d.mts +0 -52
- package/build/markdownlint/straight-quotes.d.mts +0 -11
- package/build/markdownlint/table-alignment.d.mts +0 -11
- package/build/markdownlint/terminal-language.d.mts +0 -11
- package/src/brokenLinksChecker/__fixtures__/static-site/broken-links.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/broken-targets.html +0 -22
- package/src/brokenLinksChecker/__fixtures__/static-site/example.md +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/external-links.html +0 -21
- package/src/brokenLinksChecker/__fixtures__/static-site/ignored-page.html +0 -17
- package/src/brokenLinksChecker/__fixtures__/static-site/index.html +0 -28
- package/src/brokenLinksChecker/__fixtures__/static-site/known-targets.json +0 -5
- package/src/brokenLinksChecker/__fixtures__/static-site/nested/page.html +0 -21
- package/src/brokenLinksChecker/__fixtures__/static-site/orphaned-page.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-api-links.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-custom-targets.html +0 -24
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-ignored-content.html +0 -28
- package/src/brokenLinksChecker/__fixtures__/static-site/page-with-known-target-links.html +0 -19
- package/src/brokenLinksChecker/__fixtures__/static-site/unclosed-tags.html +0 -1
- package/src/brokenLinksChecker/__fixtures__/static-site/valid.html +0 -20
- package/src/brokenLinksChecker/__fixtures__/static-site/with-anchors.html +0 -31
- package/src/brokenLinksChecker/index.test.ts +0 -261
- package/src/changelog/categorizeCommits.test.ts +0 -319
- package/src/changelog/filterCommits.test.ts +0 -363
- package/src/changelog/parseCommitLabels.test.ts +0 -509
- package/src/changelog/renderChangelog.test.ts +0 -378
- package/src/changelog/sortSections.test.ts +0 -199
- package/src/eslint/mui/rules/add-undef-to-optional.test.mjs +0 -361
- package/src/eslint/mui/rules/consistent-production-guard.test.mjs +0 -162
- package/src/eslint/mui/rules/disallow-active-elements-as-key-event-target.test.mjs +0 -66
- package/src/eslint/mui/rules/disallow-react-api-in-server-components.test.mjs +0 -305
- package/src/eslint/mui/rules/docgen-ignore-before-comment.test.mjs +0 -52
- package/src/eslint/mui/rules/flatten-parentheses.test.mjs +0 -245
- package/src/eslint/mui/rules/mui-name-matches-component-name.test.mjs +0 -247
- package/src/eslint/mui/rules/no-empty-box.test.mjs +0 -40
- package/src/eslint/mui/rules/no-styled-box.test.mjs +0 -73
- package/src/eslint/mui/rules/require-dev-wrapper.test.mjs +0 -265
- package/src/eslint/mui/rules/rules-of-use-theme-variants.test.mjs +0 -149
- package/src/eslint/mui/rules/straight-quotes.test.mjs +0 -67
- package/src/markdownlint/duplicate-h1.mjs +0 -69
- package/src/markdownlint/git-diff.mjs +0 -31
- package/src/markdownlint/index.mjs +0 -62
- package/src/markdownlint/straight-quotes.mjs +0 -26
- package/src/markdownlint/table-alignment.mjs +0 -42
- package/src/markdownlint/terminal-language.mjs +0 -19
- package/src/utils/build.test.mjs +0 -705
- package/src/utils/template.test.mjs +0 -133
- package/src/utils/typescript.test.mjs +0 -380
package/src/utils/build.mjs
CHANGED
|
@@ -1,27 +1,51 @@
|
|
|
1
1
|
import * as fs from 'node:fs/promises';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { globby } from 'globby';
|
|
4
|
-
import { minimatch } from 'minimatch';
|
|
5
4
|
import * as semver from 'semver';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @typedef {'esm' | 'cjs'} BundleType
|
|
9
8
|
*/
|
|
10
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} BundleMeta
|
|
12
|
+
* @property {BundleType} type
|
|
13
|
+
* @property {string} dir
|
|
14
|
+
* @property {'import' | 'require'} condition - The package.json condition this bundle maps to.
|
|
15
|
+
* @property {string} outExtension
|
|
16
|
+
* @property {string} typeOutExtension
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Source files in JS/TS-like languages that the build compiles. These are the
|
|
21
|
+
* only leaves that get an extension swap + `import`/`require`/`types` conditions.
|
|
22
|
+
* Other files under `src/` (e.g. `.css`, `.json`) are copied verbatim and only
|
|
23
|
+
* get their `./src/` prefix rewritten.
|
|
24
|
+
*/
|
|
25
|
+
const JS_TS_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs']);
|
|
26
|
+
|
|
27
|
+
export const BASE_IGNORES = [
|
|
28
|
+
'**/*.test.js',
|
|
29
|
+
'**/*.test.ts',
|
|
30
|
+
'**/*.test.tsx',
|
|
31
|
+
'**/*.spec.js',
|
|
32
|
+
'**/*.spec.ts',
|
|
33
|
+
'**/*.spec.tsx',
|
|
34
|
+
'**/*.d.ts',
|
|
35
|
+
'**/*.test/*.*',
|
|
36
|
+
'**/test-cases/*.*',
|
|
37
|
+
];
|
|
38
|
+
|
|
11
39
|
/**
|
|
12
40
|
* @param {BundleType} bundle
|
|
13
41
|
* @param {Object} [options]
|
|
14
42
|
* @param {boolean} [options.isType=false] - Whether to get the extension for type declaration files.
|
|
15
|
-
* @param {boolean} [options.isFlat=false] - Whether to get the extension for a flat build structure.
|
|
16
43
|
* @param {'module' | 'commonjs'} [options.packageType='commonjs'] - The package.json type field.
|
|
17
44
|
* @returns {string}
|
|
18
45
|
*/
|
|
19
46
|
export function getOutExtension(bundle, options = {}) {
|
|
20
|
-
const { isType = false,
|
|
47
|
+
const { isType = false, packageType = 'commonjs' } = options;
|
|
21
48
|
const normalizedPackageType = packageType === 'module' ? 'module' : 'commonjs';
|
|
22
|
-
if (!isFlat) {
|
|
23
|
-
return isType ? '.d.ts' : '.js';
|
|
24
|
-
}
|
|
25
49
|
if (isType) {
|
|
26
50
|
if (normalizedPackageType === 'module') {
|
|
27
51
|
return bundle === 'esm' ? '.d.ts' : '.d.cts';
|
|
@@ -35,215 +59,524 @@ export function getOutExtension(bundle, options = {}) {
|
|
|
35
59
|
}
|
|
36
60
|
|
|
37
61
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* @param {string}
|
|
41
|
-
* @
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
62
|
+
* Returns a new object with `import` first, `require` second, `default` last,
|
|
63
|
+
* and any other condition keys preserved in their original relative order in between.
|
|
64
|
+
* @param {Record<string, any>} conditions
|
|
65
|
+
* @returns {Record<string, any>}
|
|
66
|
+
*/
|
|
67
|
+
function sortExportConditions(conditions) {
|
|
68
|
+
/** @type {Record<string, number | undefined>} */
|
|
69
|
+
const order = { import: 0, require: 1, default: 3 };
|
|
70
|
+
return Object.fromEntries(
|
|
71
|
+
Object.entries(conditions).sort(([a], [b]) => (order[a] ?? 2) - (order[b] ?? 2)),
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Recursively fills in the `default` condition and stabilizes key order for a
|
|
77
|
+
* single condition value. Bundles run in parallel, so `import`/`require`
|
|
78
|
+
* insertion order would otherwise depend on Promise timing. Nested condition
|
|
79
|
+
* objects (e.g. `{ node: {...}, default: {...} }`) are handled at every level
|
|
80
|
+
* that carries `import`/`require`. Non-condition values (plain strings, bare
|
|
81
|
+
* specifiers, `null`) are returned untouched.
|
|
82
|
+
* @param {any} value
|
|
83
|
+
* @param {boolean} addTypes
|
|
84
|
+
* @param {string} kind - Used for error messages, e.g. `export` or `import`.
|
|
85
|
+
* @param {string} key - Used for error messages.
|
|
86
|
+
* @returns {any}
|
|
49
87
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
type,
|
|
56
|
-
newExports,
|
|
57
|
-
typeOutExtension,
|
|
58
|
-
outExtension,
|
|
59
|
-
addTypes,
|
|
60
|
-
}) {
|
|
61
|
-
if (Array.isArray(importPath)) {
|
|
88
|
+
function finalizeConditionValue(value, addTypes, kind, key) {
|
|
89
|
+
if (value === null || typeof value !== 'object') {
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(value)) {
|
|
62
93
|
throw new Error(
|
|
63
|
-
`Array form of package.json
|
|
94
|
+
`Array form of package.json ${kind}s is not supported yet. Found in ${kind} "${key}".`,
|
|
64
95
|
);
|
|
65
96
|
}
|
|
66
97
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
98
|
+
for (const childKey of Object.keys(value)) {
|
|
99
|
+
value[childKey] = finalizeConditionValue(value[childKey], addTypes, kind, key);
|
|
100
|
+
}
|
|
70
101
|
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
)
|
|
102
|
+
if (value.import || value.require) {
|
|
103
|
+
// Synthesize `default` from import/require (preferring ESM), but never clobber
|
|
104
|
+
// a user-authored `default` condition that sits alongside them.
|
|
105
|
+
if (value.default === undefined) {
|
|
106
|
+
const defaultExport = value.import || value.require;
|
|
107
|
+
if (addTypes) {
|
|
108
|
+
value.default = defaultExport;
|
|
109
|
+
} else {
|
|
110
|
+
value.default =
|
|
111
|
+
defaultExport && typeof defaultExport === 'object' && 'default' in defaultExport
|
|
112
|
+
? defaultExport.default
|
|
113
|
+
: defaultExport;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return sortExportConditions(value);
|
|
75
117
|
}
|
|
76
118
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Applies {@link finalizeConditionValue} to every entry of a conditions map.
|
|
124
|
+
* @param {import('../cli/packageJson').PackageJson.ExportConditions} conditionsMap
|
|
125
|
+
* @param {boolean} addTypes
|
|
126
|
+
* @param {string} kind - Used for error messages, e.g. `export` or `import`.
|
|
127
|
+
* @returns {void}
|
|
128
|
+
*/
|
|
129
|
+
function finalizeConditions(conditionsMap, addTypes, kind) {
|
|
130
|
+
for (const key of Object.keys(conditionsMap)) {
|
|
131
|
+
conditionsMap[key] = finalizeConditionValue(conditionsMap[key], addTypes, kind, key);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Returns the path relative to `src/` if `leaf` points inside the source tree
|
|
137
|
+
* (accepting both `./src/…` and `src/…`), otherwise `null`.
|
|
138
|
+
* @param {string} leaf
|
|
139
|
+
* @returns {string | null}
|
|
140
|
+
*/
|
|
141
|
+
function srcRelative(leaf) {
|
|
142
|
+
if (leaf.startsWith('./src/')) {
|
|
143
|
+
return leaf.slice('./src/'.length);
|
|
144
|
+
}
|
|
145
|
+
if (leaf.startsWith('src/')) {
|
|
146
|
+
return leaf.slice('src/'.length);
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Maps a source-relative path to its built location, optionally swapping the
|
|
153
|
+
* extension. `*` wildcards are preserved verbatim (Node resolves them at runtime).
|
|
154
|
+
* @param {string} rel - Path relative to `src/`.
|
|
155
|
+
* @param {string} dir - The bundle output dir (`.` for the root).
|
|
156
|
+
* @param {string} ext - The current extension (from `path.extname`).
|
|
157
|
+
* @param {string | null} newExt - The replacement extension, or `null` to keep `ext`.
|
|
158
|
+
* @returns {string}
|
|
159
|
+
*/
|
|
160
|
+
function buildOutPath(rel, dir, ext, newExt) {
|
|
161
|
+
const dirPrefix = dir === '.' ? '' : `${dir}/`;
|
|
162
|
+
const base = `./${dirPrefix}${rel}`;
|
|
163
|
+
return newExt ? `${base.slice(0, base.length - ext.length)}${newExt}` : base;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {string} target
|
|
168
|
+
* @returns {Promise<boolean>}
|
|
169
|
+
*/
|
|
170
|
+
function fileExists(target) {
|
|
171
|
+
return fs.stat(target).then(
|
|
172
|
+
(stats) => stats.isFile(),
|
|
173
|
+
() => false,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {string} target
|
|
179
|
+
* @returns {Promise<boolean>}
|
|
180
|
+
*/
|
|
181
|
+
function fileOrDirExists(target) {
|
|
182
|
+
return fs.stat(target).then(
|
|
183
|
+
(stats) => stats.isFile() || stats.isDirectory(),
|
|
184
|
+
() => false,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Rewrites a single leaf path for every bundle. A source JS/TS path becomes a
|
|
190
|
+
* per-bundle `{ types?, default }` (or bare out-path string when not adding
|
|
191
|
+
* types). A source asset (e.g. `.css`) gets only its `./src/` prefix rewritten.
|
|
192
|
+
* Anything else (a path already in the build output, or a bare specifier) is
|
|
193
|
+
* passed through verbatim — the escape hatch for `--copy`'d/custom paths.
|
|
194
|
+
* @param {string} leaf
|
|
195
|
+
* @param {Object} ctx
|
|
196
|
+
* @param {BundleMeta[]} ctx.bundleMetas
|
|
197
|
+
* @param {boolean} ctx.addTypes
|
|
198
|
+
* @param {string} ctx.cwd
|
|
199
|
+
* @param {string} [ctx.outputDir]
|
|
200
|
+
* @param {string} ctx.key
|
|
201
|
+
* @param {string} ctx.kind
|
|
202
|
+
* @returns {Promise<any>}
|
|
203
|
+
*/
|
|
204
|
+
async function rewriteLeaf(leaf, ctx) {
|
|
205
|
+
const { bundleMetas, addTypes, cwd, outputDir, key, kind } = ctx;
|
|
206
|
+
const rel = srcRelative(leaf);
|
|
207
|
+
|
|
208
|
+
if (rel === null) {
|
|
209
|
+
// Not a source path: it already names a path present in the published
|
|
210
|
+
// output (via `--copy` or because it's there literally), or a bare
|
|
211
|
+
// specifier (external package). Emit verbatim.
|
|
212
|
+
if (outputDir && leaf.startsWith('.') && !leaf.includes('*')) {
|
|
213
|
+
const exists = await fileOrDirExists(path.join(outputDir, leaf));
|
|
214
|
+
if (!exists) {
|
|
215
|
+
// `--copy` runs after package.json generation, so the file may legitimately
|
|
216
|
+
// not be on disk yet — warn rather than fail.
|
|
217
|
+
console.warn(
|
|
218
|
+
`The ${kind} path "${leaf}" for "${key}" was not found in the build output. Ensure it is generated or copied into the output directory.`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return leaf;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const hasGlob = leaf.includes('*');
|
|
226
|
+
if (!hasGlob) {
|
|
227
|
+
const exists = await fileOrDirExists(path.join(cwd, leaf));
|
|
228
|
+
if (!exists) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`The path "${leaf}" for ${kind} "${key}" does not exist in the package. Either remove the ${kind} or add the file/folder to the package.`,
|
|
82
231
|
);
|
|
83
|
-
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const ext = path.extname(rel);
|
|
236
|
+
if (!JS_TS_EXTENSIONS.has(ext)) {
|
|
237
|
+
// Asset copied verbatim into the output: only rewrite the `./src/` prefix.
|
|
238
|
+
const meta = bundleMetas.find((bundle) => bundle.dir === '.') ?? bundleMetas[0];
|
|
239
|
+
return buildOutPath(rel, meta.dir, ext, null);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** @type {Record<string, any>} */
|
|
243
|
+
const result = {};
|
|
244
|
+
for (const meta of bundleMetas) {
|
|
245
|
+
const outPath = buildOutPath(rel, meta.dir, ext, meta.outExtension);
|
|
246
|
+
result[meta.condition] = addTypes
|
|
247
|
+
? { types: buildOutPath(rel, meta.dir, ext, meta.typeOutExtension), default: outPath }
|
|
248
|
+
: outPath;
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Recursively rewrites an export/import entry value, rewriting every source-path
|
|
255
|
+
* leaf (including those nested inside standard condition objects) into its built
|
|
256
|
+
* equivalent. Condition keys and their order are preserved (conditions stay
|
|
257
|
+
* outer; the build-owned `import`/`require` split lives at the leaves).
|
|
258
|
+
* @param {import('../cli/packageJson').PackageJson.Exports} value
|
|
259
|
+
* @param {Object} ctx
|
|
260
|
+
* @param {BundleMeta[]} ctx.bundleMetas
|
|
261
|
+
* @param {boolean} ctx.addTypes
|
|
262
|
+
* @param {string} ctx.cwd
|
|
263
|
+
* @param {string} [ctx.outputDir]
|
|
264
|
+
* @param {string} ctx.key
|
|
265
|
+
* @param {string} ctx.kind
|
|
266
|
+
* @returns {Promise<any>}
|
|
267
|
+
*/
|
|
268
|
+
async function rewriteEntryValue(value, ctx) {
|
|
269
|
+
if (value === null) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
if (Array.isArray(value)) {
|
|
84
273
|
throw new Error(
|
|
85
|
-
`
|
|
274
|
+
`Array form of package.json ${ctx.kind}s is not supported yet. Found in ${ctx.kind} "${ctx.key}".`,
|
|
86
275
|
);
|
|
87
276
|
}
|
|
88
|
-
|
|
89
|
-
|
|
277
|
+
if (typeof value === 'string') {
|
|
278
|
+
return rewriteLeaf(value, ctx);
|
|
279
|
+
}
|
|
280
|
+
if (typeof value === 'object') {
|
|
281
|
+
const entries = Object.entries(value);
|
|
282
|
+
const results = await Promise.all(entries.map(([, child]) => rewriteEntryValue(child, ctx)));
|
|
283
|
+
/** @type {Record<string, any>} */
|
|
284
|
+
const out = {};
|
|
285
|
+
entries.forEach(([condition], index) => {
|
|
286
|
+
out[condition] = results[index];
|
|
287
|
+
});
|
|
288
|
+
return out;
|
|
289
|
+
}
|
|
290
|
+
throw new Error(`Unsupported ${ctx.kind} value for "${ctx.key}".`);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Rewrites every entry of a conditions map, preserving declared key order.
|
|
295
|
+
* @param {import('../cli/packageJson').PackageJson.ExportConditions} conditionsMap
|
|
296
|
+
* @param {Object} baseCtx - The {@link rewriteEntryValue} context minus `key`.
|
|
297
|
+
* @param {BundleMeta[]} baseCtx.bundleMetas
|
|
298
|
+
* @param {boolean} baseCtx.addTypes
|
|
299
|
+
* @param {string} baseCtx.cwd
|
|
300
|
+
* @param {string} [baseCtx.outputDir]
|
|
301
|
+
* @param {string} baseCtx.kind
|
|
302
|
+
* @returns {Promise<import('../cli/packageJson').PackageJson.ExportConditions>}
|
|
303
|
+
*/
|
|
304
|
+
async function rewriteConditionsMap(conditionsMap, baseCtx) {
|
|
305
|
+
const keys = Object.keys(conditionsMap);
|
|
306
|
+
const rewritten = await Promise.all(
|
|
307
|
+
keys.map((key) => rewriteEntryValue(conditionsMap[key], { ...baseCtx, key })),
|
|
308
|
+
);
|
|
309
|
+
/** @type {import('../cli/packageJson').PackageJson.ExportConditions} */
|
|
310
|
+
const result = {};
|
|
311
|
+
keys.forEach((key, index) => {
|
|
312
|
+
result[key] = rewritten[index];
|
|
313
|
+
});
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Splits a pattern around its first `*` wildcard.
|
|
319
|
+
* @param {string} pattern
|
|
320
|
+
* @returns {{ prefix: string; suffix: string }}
|
|
321
|
+
*/
|
|
322
|
+
function splitStar(pattern) {
|
|
323
|
+
const star = pattern.indexOf('*');
|
|
324
|
+
return { prefix: pattern.slice(0, star), suffix: pattern.slice(star + 1) };
|
|
325
|
+
}
|
|
90
326
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
327
|
+
/**
|
|
328
|
+
* Finds the source glob to expand inside an entry value: the plain string, else
|
|
329
|
+
* the `default` condition, else the first leaf that carries a `*`. The captured
|
|
330
|
+
* stem is applied to every sibling leaf so all conditions expand consistently.
|
|
331
|
+
* @param {import('../cli/packageJson').PackageJson.Exports} value
|
|
332
|
+
* @returns {string | undefined}
|
|
333
|
+
*/
|
|
334
|
+
function primarySourcePattern(value) {
|
|
335
|
+
if (typeof value === 'string') {
|
|
336
|
+
return value.includes('*') ? value : undefined;
|
|
337
|
+
}
|
|
338
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
339
|
+
if (typeof value.default === 'string' && value.default.includes('*')) {
|
|
340
|
+
return value.default;
|
|
341
|
+
}
|
|
342
|
+
for (const child of Object.values(value)) {
|
|
343
|
+
const found = primarySourcePattern(child);
|
|
344
|
+
if (found) {
|
|
345
|
+
return found;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
94
348
|
}
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
95
351
|
|
|
96
|
-
|
|
97
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Substitutes the matched stem into the `*` of every leaf string in a value.
|
|
354
|
+
* @param {import('../cli/packageJson').PackageJson.Exports} value
|
|
355
|
+
* @param {string} stem
|
|
356
|
+
* @returns {any}
|
|
357
|
+
*/
|
|
358
|
+
function substituteStem(value, stem) {
|
|
359
|
+
if (typeof value === 'string') {
|
|
360
|
+
return value.replace('*', stem);
|
|
98
361
|
}
|
|
362
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
363
|
+
/** @type {Record<string, any>} */
|
|
364
|
+
const out = {};
|
|
365
|
+
for (const [condition, child] of Object.entries(value)) {
|
|
366
|
+
out[condition] = substituteStem(child, stem);
|
|
367
|
+
}
|
|
368
|
+
return out;
|
|
369
|
+
}
|
|
370
|
+
return value;
|
|
371
|
+
}
|
|
99
372
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
373
|
+
/**
|
|
374
|
+
* Drops source-path conditions whose file is missing for a glob-expanded entry,
|
|
375
|
+
* so a sibling glob that doesn't match every stem of the primary pattern omits
|
|
376
|
+
* that condition for the unmatched stems instead of failing the build. Only used
|
|
377
|
+
* on glob-expanded values; explicit (non-glob) entries still validate strictly.
|
|
378
|
+
* @param {import('../cli/packageJson').PackageJson.Exports} value
|
|
379
|
+
* @param {string} cwd
|
|
380
|
+
* @returns {Promise<any>}
|
|
381
|
+
*/
|
|
382
|
+
async function pruneMissingSourceConditions(value, cwd) {
|
|
383
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
384
|
+
return value;
|
|
385
|
+
}
|
|
386
|
+
const entries = Object.entries(value);
|
|
387
|
+
const resolved = await Promise.all(
|
|
388
|
+
entries.map(async ([condition, child]) => {
|
|
389
|
+
if (typeof child === 'string') {
|
|
390
|
+
const rel = srcRelative(child);
|
|
391
|
+
if (
|
|
392
|
+
rel !== null &&
|
|
393
|
+
!child.includes('*') &&
|
|
394
|
+
!(await fileOrDirExists(path.join(cwd, child)))
|
|
395
|
+
) {
|
|
396
|
+
return undefined;
|
|
113
397
|
}
|
|
114
|
-
|
|
398
|
+
return /** @type {[string, any]} */ ([condition, child]);
|
|
399
|
+
}
|
|
400
|
+
const pruned = await pruneMissingSourceConditions(child, cwd);
|
|
401
|
+
if (
|
|
402
|
+
pruned &&
|
|
403
|
+
typeof pruned === 'object' &&
|
|
404
|
+
!Array.isArray(pruned) &&
|
|
405
|
+
Object.keys(pruned).length === 0
|
|
406
|
+
) {
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
return /** @type {[string, any]} */ ([condition, pruned]);
|
|
410
|
+
}),
|
|
411
|
+
);
|
|
412
|
+
/** @type {Record<string, any>} */
|
|
413
|
+
const out = {};
|
|
414
|
+
for (const entry of resolved) {
|
|
415
|
+
if (entry) {
|
|
416
|
+
out[entry[0]] = entry[1];
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return out;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Tests whether a subpath-pattern (or exact) key matches a concrete subpath.
|
|
424
|
+
* @param {string} key
|
|
425
|
+
* @param {string} subpath
|
|
426
|
+
* @returns {boolean}
|
|
427
|
+
*/
|
|
428
|
+
function keyMatches(key, subpath) {
|
|
429
|
+
const star = key.indexOf('*');
|
|
430
|
+
if (star === -1) {
|
|
431
|
+
return key === subpath;
|
|
432
|
+
}
|
|
433
|
+
const base = key.slice(0, star);
|
|
434
|
+
const suffix = key.slice(star + 1);
|
|
435
|
+
return (
|
|
436
|
+
subpath.length >= base.length + suffix.length &&
|
|
437
|
+
subpath.startsWith(base) &&
|
|
438
|
+
subpath.endsWith(suffix)
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Selects the most-specific key that matches `subpath`, mirroring Node's
|
|
444
|
+
* resolution: an exact key beats any pattern, and among patterns the longest
|
|
445
|
+
* base (substring before `*`) wins, tie-broken by the longest suffix.
|
|
446
|
+
* @param {string} subpath
|
|
447
|
+
* @param {string[]} keys
|
|
448
|
+
* @returns {string | null}
|
|
449
|
+
*/
|
|
450
|
+
function selectMostSpecificKey(subpath, keys) {
|
|
451
|
+
/** @type {string | null} */
|
|
452
|
+
let best = null;
|
|
453
|
+
let bestBase = -1;
|
|
454
|
+
let bestSuffix = -1;
|
|
455
|
+
for (const key of keys) {
|
|
456
|
+
if (!keyMatches(key, subpath)) {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const star = key.indexOf('*');
|
|
460
|
+
const base = star === -1 ? Infinity : star;
|
|
461
|
+
const suffix = star === -1 ? 0 : key.length - star - 1;
|
|
462
|
+
if (base > bestBase || (base === bestBase && suffix > bestSuffix)) {
|
|
463
|
+
best = key;
|
|
464
|
+
bestBase = base;
|
|
465
|
+
bestSuffix = suffix;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return best;
|
|
115
469
|
}
|
|
116
470
|
|
|
117
471
|
/**
|
|
118
|
-
* Expands glob patterns (containing `*`) in
|
|
119
|
-
*
|
|
472
|
+
* Expands glob patterns (containing `*`) in export/import keys into concrete
|
|
473
|
+
* entries resolved against files on disk. Each `*` matches a single path segment
|
|
474
|
+
* (use `--no-expand` to keep the pattern as a Node runtime subpath, whose `*`
|
|
475
|
+
* matches across `/`). Negation (`null`) keys are applied via most-specific-key
|
|
476
|
+
* selection rather than cascade-subtraction, so a deeper positive pattern still
|
|
477
|
+
* resolves under a shallower `null`, and a zero-match pattern warns instead of
|
|
478
|
+
* silently dropping.
|
|
120
479
|
* @param {import('../cli/packageJson').PackageJson.ExportConditions} originalExports
|
|
121
480
|
* @param {string} cwd
|
|
122
481
|
* @returns {Promise<import('../cli/packageJson').PackageJson.ExportConditions>}
|
|
123
482
|
*/
|
|
124
483
|
async function expandExportGlobs(originalExports, cwd) {
|
|
484
|
+
const allKeys = Object.keys(originalExports);
|
|
125
485
|
/** @type {import('../cli/packageJson').PackageJson.ExportConditions} */
|
|
126
486
|
const expandedExports = {};
|
|
127
487
|
|
|
128
|
-
/**
|
|
129
|
-
* @typedef {{
|
|
130
|
-
* value: import('../cli/packageJson').PackageJson.Exports;
|
|
131
|
-
* srcPattern: string;
|
|
132
|
-
* srcPrefix: string;
|
|
133
|
-
* srcSuffix: string;
|
|
134
|
-
* keyPrefix: string;
|
|
135
|
-
* keySuffix: string;
|
|
136
|
-
* }} GlobEntry
|
|
137
|
-
*/
|
|
138
|
-
|
|
139
|
-
// Collect entries that need glob expansion
|
|
140
|
-
/** @type {GlobEntry[]} */
|
|
488
|
+
/** @type {{ key: string; value: import('../cli/packageJson').PackageJson.Exports; srcPattern: string }[]} */
|
|
141
489
|
const globEntries = [];
|
|
142
490
|
|
|
143
|
-
// Collect negation patterns (glob keys with null values)
|
|
144
|
-
/** @type {string[]} */
|
|
145
|
-
const negationPatterns = [];
|
|
146
|
-
|
|
147
491
|
for (const [key, value] of Object.entries(originalExports)) {
|
|
148
|
-
// Null value acts as a negation/exclusion
|
|
149
|
-
if (value === null) {
|
|
150
|
-
if (key.includes('*')) {
|
|
151
|
-
negationPatterns.push(key);
|
|
152
|
-
} else {
|
|
153
|
-
delete expandedExports[key];
|
|
154
|
-
}
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
492
|
if (!key.includes('*')) {
|
|
493
|
+
// Exact keys (including exact `null` blocks) pass straight through.
|
|
159
494
|
expandedExports[key] = value;
|
|
160
495
|
continue;
|
|
161
496
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
let srcPattern;
|
|
166
|
-
if (typeof value === 'string') {
|
|
167
|
-
srcPattern = value;
|
|
168
|
-
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
169
|
-
srcPattern = /** @type {string | undefined} */ (value['mui-src']);
|
|
497
|
+
if (value === null) {
|
|
498
|
+
// Negation pattern: carried through after expansion (see below).
|
|
499
|
+
continue;
|
|
170
500
|
}
|
|
171
|
-
|
|
172
|
-
if (typeof srcPattern !== 'string'
|
|
501
|
+
const srcPattern = primarySourcePattern(value);
|
|
502
|
+
if (typeof srcPattern !== 'string') {
|
|
503
|
+
// Glob key whose value has no wildcard: pass through unchanged.
|
|
173
504
|
expandedExports[key] = value;
|
|
174
505
|
continue;
|
|
175
506
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const keyStarIndex = key.indexOf('*');
|
|
183
|
-
const keyPrefix = key.substring(0, keyStarIndex);
|
|
184
|
-
const keySuffix = key.substring(keyStarIndex + 1);
|
|
185
|
-
|
|
186
|
-
globEntries.push({
|
|
187
|
-
value,
|
|
188
|
-
srcPattern,
|
|
189
|
-
srcPrefix,
|
|
190
|
-
srcSuffix,
|
|
191
|
-
keyPrefix,
|
|
192
|
-
keySuffix,
|
|
193
|
-
});
|
|
507
|
+
if (srcPattern.indexOf('*') !== srcPattern.lastIndexOf('*')) {
|
|
508
|
+
console.warn(
|
|
509
|
+
`The pattern "${srcPattern}" for "${key}" contains multiple "*" wildcards; only the first is supported.`,
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
globEntries.push({ key, value, srcPattern });
|
|
194
513
|
}
|
|
195
514
|
|
|
196
|
-
// Resolve all globby calls in parallel
|
|
197
515
|
const globResults = await Promise.all(
|
|
198
|
-
globEntries.map(({ srcPattern }) => globby(srcPattern, { cwd })),
|
|
516
|
+
globEntries.map(({ srcPattern }) => globby(srcPattern, { cwd, ignore: BASE_IGNORES })),
|
|
199
517
|
);
|
|
200
518
|
|
|
519
|
+
/** @type {Set<string>} */
|
|
520
|
+
const usedNegations = new Set();
|
|
521
|
+
/** @type {string[]} */
|
|
522
|
+
const expandedObjectKeys = [];
|
|
523
|
+
|
|
201
524
|
for (let i = 0; i < globEntries.length; i += 1) {
|
|
202
|
-
const {
|
|
203
|
-
const
|
|
525
|
+
const { key, value, srcPattern } = globEntries[i];
|
|
526
|
+
const { prefix: srcPrefix, suffix: srcSuffix } = splitStar(srcPattern);
|
|
527
|
+
const { prefix: keyPrefix, suffix: keySuffix } = splitStar(key);
|
|
204
528
|
|
|
205
529
|
const stems = [];
|
|
206
|
-
for (const match of
|
|
530
|
+
for (const match of globResults[i]) {
|
|
207
531
|
if (match.startsWith(srcPrefix) && match.endsWith(srcSuffix)) {
|
|
208
|
-
const stem =
|
|
209
|
-
|
|
210
|
-
? match.substring(srcPrefix.length, match.length - srcSuffix.length)
|
|
211
|
-
: match.substring(srcPrefix.length);
|
|
212
|
-
if (stem.length > 0) {
|
|
532
|
+
const stem = match.slice(srcPrefix.length, match.length - srcSuffix.length);
|
|
533
|
+
if (stem) {
|
|
213
534
|
stems.push(stem);
|
|
214
535
|
}
|
|
215
536
|
}
|
|
216
537
|
}
|
|
217
|
-
|
|
218
538
|
stems.sort();
|
|
219
539
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
540
|
+
if (stems.length === 0) {
|
|
541
|
+
console.warn(`No files matched the pattern "${srcPattern}" for "${key}".`);
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
223
544
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
545
|
+
for (const stem of stems) {
|
|
546
|
+
const concreteKey = `${keyPrefix}${stem}${keySuffix}`;
|
|
547
|
+
// Honour Node's most-specific-wins resolution: only emit this concrete
|
|
548
|
+
// entry when this positive pattern is the most-specific match. A deeper
|
|
549
|
+
// positive pattern emits its own entries; a `null` blocks it entirely.
|
|
550
|
+
const winner = selectMostSpecificKey(concreteKey, allKeys);
|
|
551
|
+
if (winner !== key) {
|
|
552
|
+
if (winner !== null && originalExports[winner] === null) {
|
|
553
|
+
usedNegations.add(winner);
|
|
554
|
+
}
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
expandedExports[concreteKey] = substituteStem(value, stem);
|
|
558
|
+
if (value && typeof value === 'object') {
|
|
559
|
+
expandedObjectKeys.push(concreteKey);
|
|
231
560
|
}
|
|
232
561
|
}
|
|
233
562
|
}
|
|
234
563
|
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
564
|
+
// For glob-expanded condition objects, drop any condition whose source file is
|
|
565
|
+
// absent for this stem (a sibling glob need not match every primary stem).
|
|
566
|
+
await Promise.all(
|
|
567
|
+
expandedObjectKeys.map(async (concreteKey) => {
|
|
568
|
+
expandedExports[concreteKey] = await pruneMissingSourceConditions(
|
|
569
|
+
expandedExports[concreteKey],
|
|
570
|
+
cwd,
|
|
571
|
+
);
|
|
572
|
+
}),
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
// Carry through negation patterns that didn't claim any expanded entry so they
|
|
576
|
+
// still block their subtree at runtime.
|
|
577
|
+
for (const [key, value] of Object.entries(originalExports)) {
|
|
578
|
+
if (value === null && key.includes('*') && !usedNegations.has(key)) {
|
|
579
|
+
expandedExports[key] = null;
|
|
247
580
|
}
|
|
248
581
|
}
|
|
249
582
|
|
|
@@ -251,24 +584,36 @@ async function expandExportGlobs(originalExports, cwd) {
|
|
|
251
584
|
}
|
|
252
585
|
|
|
253
586
|
/**
|
|
254
|
-
*
|
|
255
|
-
*
|
|
256
|
-
* @param {
|
|
257
|
-
* @param {
|
|
258
|
-
* @
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
587
|
+
* Builds the per-bundle metadata (output extensions + the `import`/`require`
|
|
588
|
+
* condition each bundle maps to).
|
|
589
|
+
* @param {BundleType[]} bundles
|
|
590
|
+
* @param {'module' | 'commonjs'} packageType
|
|
591
|
+
* @returns {BundleMeta[]}
|
|
592
|
+
*/
|
|
593
|
+
function createBundleMetas(bundles, packageType) {
|
|
594
|
+
return bundles.map((type) => ({
|
|
595
|
+
type,
|
|
596
|
+
dir: '.',
|
|
597
|
+
condition: type === 'cjs' ? 'require' : 'import',
|
|
598
|
+
outExtension: getOutExtension(type, { packageType }),
|
|
599
|
+
typeOutExtension: getOutExtension(type, { isType: true, packageType }),
|
|
600
|
+
}));
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* @param {import('../cli/packageJson').PackageJson['exports']} packageExports
|
|
605
|
+
* @param {Object} options
|
|
606
|
+
* @param {BundleType[]} options.bundles
|
|
607
|
+
* @param {string} options.outputDir
|
|
608
|
+
* @param {string} options.cwd
|
|
609
|
+
* @param {boolean} [options.addTypes]
|
|
610
|
+
* @param {boolean} [options.expand] - Whether to enumerate glob patterns into concrete entries.
|
|
611
|
+
* @param {'module' | 'commonjs'} [options.packageType]
|
|
262
612
|
*/
|
|
263
|
-
export async function createPackageExports(
|
|
264
|
-
|
|
265
|
-
bundles,
|
|
266
|
-
|
|
267
|
-
cwd,
|
|
268
|
-
addTypes = false,
|
|
269
|
-
isFlat = false,
|
|
270
|
-
packageType = 'commonjs',
|
|
271
|
-
}) {
|
|
613
|
+
export async function createPackageExports(
|
|
614
|
+
packageExports,
|
|
615
|
+
{ bundles, outputDir, cwd, addTypes = false, expand = true, packageType = 'commonjs' },
|
|
616
|
+
) {
|
|
272
617
|
const resolvedPackageType = packageType === 'module' ? 'module' : 'commonjs';
|
|
273
618
|
/**
|
|
274
619
|
* @type {import('../cli/packageJson').PackageJson.ExportConditions}
|
|
@@ -277,7 +622,8 @@ export async function createPackageExports({
|
|
|
277
622
|
typeof packageExports === 'string' || Array.isArray(packageExports)
|
|
278
623
|
? { '.': packageExports }
|
|
279
624
|
: packageExports || {};
|
|
280
|
-
const originalExports =
|
|
625
|
+
const originalExports = expand ? await expandExportGlobs(rawExports, cwd) : rawExports;
|
|
626
|
+
const bundleMetas = createBundleMetas(bundles, resolvedPackageType);
|
|
281
627
|
/**
|
|
282
628
|
* @type {import('../cli/packageJson').PackageJson.ExportConditions}
|
|
283
629
|
*/
|
|
@@ -291,124 +637,124 @@ export async function createPackageExports({
|
|
|
291
637
|
exports: newExports,
|
|
292
638
|
};
|
|
293
639
|
|
|
640
|
+
// Derive the `.` index entry (plus `main`/`types`) from the built index files.
|
|
294
641
|
await Promise.all(
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
packageType: resolvedPackageType,
|
|
299
|
-
});
|
|
300
|
-
const typeOutExtension = getOutExtension(type, {
|
|
301
|
-
isFlat,
|
|
302
|
-
isType: true,
|
|
303
|
-
packageType: resolvedPackageType,
|
|
304
|
-
});
|
|
305
|
-
const indexFileExists = await fs.stat(path.join(outputDir, dir, `index${outExtension}`)).then(
|
|
306
|
-
(stats) => stats.isFile(),
|
|
307
|
-
() => false,
|
|
642
|
+
bundleMetas.map(async (meta) => {
|
|
643
|
+
const indexFileExists = await fileExists(
|
|
644
|
+
path.join(outputDir, meta.dir, `index${meta.outExtension}`),
|
|
308
645
|
);
|
|
309
646
|
const typeFileExists =
|
|
310
647
|
addTypes &&
|
|
311
|
-
(await
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const dirPrefix = dir === '.' ? '' : `${dir}/`;
|
|
316
|
-
const exportDir = `./${dirPrefix}index${outExtension}`;
|
|
317
|
-
const typeExportDir = `./${dirPrefix}index${typeOutExtension}`;
|
|
648
|
+
(await fileExists(path.join(outputDir, meta.dir, `index${meta.typeOutExtension}`)));
|
|
649
|
+
const dirPrefix = meta.dir === '.' ? '' : `${meta.dir}/`;
|
|
650
|
+
const exportDir = `./${dirPrefix}index${meta.outExtension}`;
|
|
651
|
+
const typeExportDir = `./${dirPrefix}index${meta.typeOutExtension}`;
|
|
318
652
|
|
|
319
653
|
if (indexFileExists) {
|
|
320
654
|
// skip `packageJson.module` to support parcel and some older bundlers
|
|
321
|
-
if (type === 'cjs') {
|
|
655
|
+
if (meta.type === 'cjs') {
|
|
322
656
|
result.main = exportDir;
|
|
323
657
|
}
|
|
324
|
-
|
|
325
658
|
if (typeof newExports['.'] === 'string' || Array.isArray(newExports['.'])) {
|
|
326
659
|
throw new Error(`The export "." is already defined as a string or Array.`);
|
|
327
660
|
}
|
|
328
|
-
|
|
329
661
|
newExports['.'] ??= {};
|
|
330
|
-
newExports['.'][
|
|
331
|
-
? {
|
|
332
|
-
types: typeExportDir,
|
|
333
|
-
default: exportDir,
|
|
334
|
-
}
|
|
662
|
+
newExports['.'][meta.condition] = typeFileExists
|
|
663
|
+
? { types: typeExportDir, default: exportDir }
|
|
335
664
|
: exportDir;
|
|
336
665
|
}
|
|
337
|
-
if (typeFileExists && type === 'cjs') {
|
|
666
|
+
if (typeFileExists && meta.type === 'cjs') {
|
|
338
667
|
result.types = typeExportDir;
|
|
339
668
|
}
|
|
340
|
-
const exportKeys = Object.keys(originalExports);
|
|
341
|
-
// need to maintain the order of exports
|
|
342
|
-
for (const key of exportKeys) {
|
|
343
|
-
const importPath = originalExports[key];
|
|
344
|
-
if (!importPath) {
|
|
345
|
-
newExports[key] = null;
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
// eslint-disable-next-line no-await-in-loop
|
|
349
|
-
await createExportsFor({
|
|
350
|
-
importPath,
|
|
351
|
-
key,
|
|
352
|
-
cwd,
|
|
353
|
-
dir,
|
|
354
|
-
type,
|
|
355
|
-
newExports,
|
|
356
|
-
typeOutExtension,
|
|
357
|
-
outExtension,
|
|
358
|
-
addTypes,
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
669
|
}),
|
|
362
670
|
);
|
|
363
671
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
672
|
+
// Rewrite the user-configured entries, preserving their declared order.
|
|
673
|
+
Object.assign(
|
|
674
|
+
newExports,
|
|
675
|
+
await rewriteConditionsMap(originalExports, {
|
|
676
|
+
bundleMetas,
|
|
677
|
+
addTypes,
|
|
678
|
+
cwd,
|
|
679
|
+
outputDir,
|
|
680
|
+
kind: 'export',
|
|
681
|
+
}),
|
|
682
|
+
);
|
|
369
683
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
684
|
+
finalizeConditions(newExports, addTypes, 'export');
|
|
685
|
+
|
|
686
|
+
return result;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Generates the package.json `imports` field for the built package, rewriting
|
|
691
|
+
* internal subpath imports (keys starting with `#`) that point at source files
|
|
692
|
+
* into their built equivalents with `import`/`require`/`types` conditions.
|
|
693
|
+
*
|
|
694
|
+
* Mirrors {@link createPackageExports} but without the `.` / `package.json` /
|
|
695
|
+
* `main` / `types` index handling that only applies to public exports. Entries
|
|
696
|
+
* that resolve to bare specifiers (e.g. an external package) are passed through
|
|
697
|
+
* unchanged, since the `imports` field commonly aliases dependencies.
|
|
698
|
+
* @param {import('../cli/packageJson').PackageJson['imports']} packageImports
|
|
699
|
+
* @param {Object} options
|
|
700
|
+
* @param {BundleType[]} options.bundles
|
|
701
|
+
* @param {string} options.cwd
|
|
702
|
+
* @param {string} [options.outputDir] - Used to verify non-source passthrough paths exist in the build output.
|
|
703
|
+
* @param {boolean} [options.addTypes]
|
|
704
|
+
* @param {boolean} [options.expand] - Whether to enumerate glob patterns into concrete entries.
|
|
705
|
+
* @param {'module' | 'commonjs'} [options.packageType]
|
|
706
|
+
* @returns {Promise<import('../cli/packageJson').PackageJson.Imports | undefined>}
|
|
707
|
+
*/
|
|
708
|
+
export async function createPackageImports(
|
|
709
|
+
packageImports,
|
|
710
|
+
{ bundles, cwd, outputDir, addTypes = false, expand = true, packageType = 'commonjs' },
|
|
711
|
+
) {
|
|
712
|
+
if (!packageImports || Object.keys(packageImports).length === 0) {
|
|
713
|
+
return undefined;
|
|
714
|
+
}
|
|
715
|
+
for (const key of Object.keys(packageImports)) {
|
|
716
|
+
if (!key.startsWith('#')) {
|
|
374
717
|
throw new Error(
|
|
375
|
-
`
|
|
718
|
+
`Invalid import "${key}": all package.json "imports" keys must start with "#".`,
|
|
376
719
|
);
|
|
377
720
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
721
|
+
}
|
|
722
|
+
const resolvedPackageType = packageType === 'module' ? 'module' : 'commonjs';
|
|
723
|
+
// `Imports` uses `#`-prefixed keys; treat it as a generic conditions map so the
|
|
724
|
+
// same glob/condition helpers used for exports can process it.
|
|
725
|
+
const rawImports = /** @type {import('../cli/packageJson').PackageJson.ExportConditions} */ (
|
|
726
|
+
packageImports
|
|
727
|
+
);
|
|
728
|
+
const originalImports = expand ? await expandExportGlobs(rawImports, cwd) : rawImports;
|
|
729
|
+
const bundleMetas = createBundleMetas(bundles, resolvedPackageType);
|
|
730
|
+
|
|
731
|
+
const newImports = await rewriteConditionsMap(originalImports, {
|
|
732
|
+
bundleMetas,
|
|
733
|
+
addTypes,
|
|
734
|
+
cwd,
|
|
735
|
+
outputDir,
|
|
736
|
+
kind: 'import',
|
|
391
737
|
});
|
|
392
738
|
|
|
393
|
-
|
|
739
|
+
finalizeConditions(newImports, addTypes, 'import');
|
|
740
|
+
|
|
741
|
+
return newImports;
|
|
394
742
|
}
|
|
395
743
|
|
|
396
744
|
/**
|
|
397
|
-
* @param {
|
|
398
|
-
* @param {
|
|
399
|
-
* @param {
|
|
400
|
-
* @param {string}
|
|
401
|
-
* @param {
|
|
402
|
-
* @param {'module' | 'commonjs'} [param0.packageType]
|
|
745
|
+
* @param {import('../cli/packageJson').PackageJson['bin']} bin
|
|
746
|
+
* @param {Object} options
|
|
747
|
+
* @param {BundleType[]} options.bundles
|
|
748
|
+
* @param {string} options.cwd
|
|
749
|
+
* @param {'module' | 'commonjs'} [options.packageType]
|
|
403
750
|
*/
|
|
404
|
-
export async function createPackageBin(
|
|
751
|
+
export async function createPackageBin(bin, { bundles, cwd, packageType }) {
|
|
405
752
|
if (!bin) {
|
|
406
753
|
return undefined;
|
|
407
754
|
}
|
|
408
755
|
// Use mjs files if present, otherwise fallback to the first bundle type
|
|
409
|
-
const bundleToUse = bundles.find((
|
|
410
|
-
const binOutExtension = getOutExtension(bundleToUse
|
|
411
|
-
isFlat,
|
|
756
|
+
const bundleToUse = bundles.find((type) => type === 'esm') || bundles[0];
|
|
757
|
+
const binOutExtension = getOutExtension(bundleToUse, {
|
|
412
758
|
packageType,
|
|
413
759
|
});
|
|
414
760
|
|
|
@@ -436,7 +782,7 @@ export async function createPackageBin({ bin, bundles, cwd, isFlat = false, pack
|
|
|
436
782
|
}
|
|
437
783
|
const ext = path.extname(binPath);
|
|
438
784
|
newBin[binKey] = binPath
|
|
439
|
-
.replace(/(\.\/)?src\//,
|
|
785
|
+
.replace(/(\.\/)?src\//, './')
|
|
440
786
|
.replace(new RegExp(`\\${ext}$`), binOutExtension);
|
|
441
787
|
}
|
|
442
788
|
// eslint-disable-next-line no-underscore-dangle
|
|
@@ -549,18 +895,6 @@ export function measureFn(label) {
|
|
|
549
895
|
return performance.measure(label, startMark, endMark);
|
|
550
896
|
}
|
|
551
897
|
|
|
552
|
-
export const BASE_IGNORES = [
|
|
553
|
-
'**/*.test.js',
|
|
554
|
-
'**/*.test.ts',
|
|
555
|
-
'**/*.test.tsx',
|
|
556
|
-
'**/*.spec.js',
|
|
557
|
-
'**/*.spec.ts',
|
|
558
|
-
'**/*.spec.tsx',
|
|
559
|
-
'**/*.d.ts',
|
|
560
|
-
'**/*.test/*.*',
|
|
561
|
-
'**/test-cases/*.*',
|
|
562
|
-
];
|
|
563
|
-
|
|
564
898
|
/**
|
|
565
899
|
* A utility to map a function over an array of items in a worker pool.
|
|
566
900
|
*
|