@mui/internal-code-infra 0.0.2-canary.29 → 0.0.2-canary.30

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.
@@ -1 +1,2 @@
1
+ #!/usr/bin/env node
1
2
  import '../src/cli/index.mjs';
package/package.json CHANGED
@@ -1,31 +1,40 @@
1
1
  {
2
2
  "name": "@mui/internal-code-infra",
3
- "version": "0.0.2-canary.29",
3
+ "version": "0.0.2-canary.30",
4
4
  "description": "Infra scripts and configs to be used across MUI repos.",
5
5
  "type": "module",
6
+ "license": "MIT",
6
7
  "repository": {
7
8
  "type": "git",
8
- "url": "https://github.com/mui/mui-public.git",
9
+ "url": "git+https://github.com/mui/mui-public.git",
9
10
  "directory": "packages/code-infra"
10
11
  },
11
12
  "sideEffects": false,
12
13
  "exports": {
13
14
  "./package.json": "./package.json",
14
- "./prettier": {
15
- "default": "./src/prettier.mjs"
16
- },
17
- "./eslint": {
18
- "default": "./src/eslint/index.mjs"
19
- }
15
+ "./prettier": "./src/prettier.mjs",
16
+ "./eslint": "./src/eslint/index.mjs",
17
+ "./babel-config": "./src/babel-config.mjs"
20
18
  },
21
19
  "bin": {
22
20
  "code-infra": "./bin/code-infra.mjs"
23
21
  },
24
22
  "dependencies": {
25
23
  "@argos-ci/core": "^3.2.3",
24
+ "@babel/core": "^7.28.0",
25
+ "@babel/plugin-transform-runtime": "^7.28.0",
26
+ "@babel/plugin-syntax-typescript": "^7.27.1",
27
+ "@babel/preset-env": "^7.28.0",
28
+ "@babel/preset-react": "^7.27.1",
29
+ "@babel/preset-typescript": "^7.27.1",
26
30
  "@eslint/compat": "^1.3.2",
27
31
  "@next/eslint-plugin-next": "^15.3.3",
28
32
  "@octokit/rest": "^22.0.0",
33
+ "@pnpm/find-workspace-dir": "^1000.1.0",
34
+ "babel-plugin-optimize-clsx": "^2.6.2",
35
+ "babel-plugin-transform-inline-environment-variables": "^0.4.4",
36
+ "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
37
+ "babel-plugin-transform-remove-imports": "^1.8.0",
29
38
  "chalk": "^5.4.1",
30
39
  "eslint-config-airbnb": "^19.0.4",
31
40
  "eslint-config-airbnb-base": "^15.0.0",
@@ -43,19 +52,26 @@
43
52
  "git-url-parse": "^16.1.0",
44
53
  "globals": "^16.2.0",
45
54
  "globby": "^14.1.0",
55
+ "lodash-es": "^4.17.21",
46
56
  "minimatch": "^10.0.3",
47
57
  "semver": "^7.7.2",
48
58
  "typescript-eslint": "^8.35.1",
49
- "yargs": "^17.7.2"
59
+ "yargs": "^17.7.2",
60
+ "@mui/internal-babel-plugin-display-name": "1.0.4-canary.3",
61
+ "@mui/internal-babel-plugin-minify-errors": "2.0.8-canary.4",
62
+ "@mui/internal-babel-plugin-resolve-imports": "2.0.7-canary.13"
50
63
  },
51
64
  "peerDependencies": {
52
65
  "eslint": "^9.0.0",
53
66
  "prettier": "^3.5.3"
54
67
  },
55
68
  "devDependencies": {
69
+ "@types/babel__core": "^7.20.5",
70
+ "@types/babel__preset-env": "^7.10.0",
56
71
  "@types/eslint-plugin-jsx-a11y": "^6.10.0",
57
72
  "@types/estree": "^1.0.8",
58
73
  "@types/estree-jsx": "^1.0.5",
74
+ "@types/lodash-es": "^4.17.12",
59
75
  "@types/yargs": "^17.0.33",
60
76
  "@typescript-eslint/parser": "^8.35.0",
61
77
  "@typescript-eslint/rule-tester": "^8.35.0",
@@ -64,6 +80,7 @@
64
80
  "typescript-eslint": "^8.35.0"
65
81
  },
66
82
  "files": [
83
+ "bin",
67
84
  "build",
68
85
  "src",
69
86
  "README.md",
@@ -72,9 +89,10 @@
72
89
  "publishConfig": {
73
90
  "access": "public"
74
91
  },
75
- "gitSha": "af8e3c42ded8e5ad328c481f297dd9112b2d8410",
92
+ "gitSha": "01a4b2c7a0dbc772ca3a8d8d458fec5e301ed3d6",
76
93
  "scripts": {
77
94
  "typescript": "tsc -p tsconfig.json",
78
- "test": "pnpm -w test --project @mui/internal-code-infra"
95
+ "test": "pnpm -w test --project @mui/internal-code-infra",
96
+ "test:copy": "rm -rf build && node bin/code-infra.mjs copy-files --glob \"src/cli/*.mjs\" --glob \"src/eslint/**/*.mjs:esm\""
79
97
  }
80
98
  }
@@ -0,0 +1,138 @@
1
+ import pluginTransformRuntime from '@babel/plugin-transform-runtime';
2
+ import presetEnv from '@babel/preset-env';
3
+ import presetReact from '@babel/preset-react';
4
+ import presetTypescript from '@babel/preset-typescript';
5
+ import pluginDisplayName from '@mui/internal-babel-plugin-display-name';
6
+ import pluginResolveImports from '@mui/internal-babel-plugin-resolve-imports';
7
+ import pluginOptimizeClsx from 'babel-plugin-optimize-clsx';
8
+ import pluginTransformInlineEnvVars from 'babel-plugin-transform-inline-environment-variables';
9
+ import pluginRemovePropTypes from 'babel-plugin-transform-react-remove-prop-types';
10
+
11
+ /**
12
+ * @param {Object} param0
13
+ * @param {boolean} [param0.debug]
14
+ * @param {boolean} [param0.optimizeClsx]
15
+ * @param {boolean} [param0.removePropTypes]
16
+ * @param {boolean} [param0.isTest]
17
+ * @param {'cjs' | 'esm'} param0.bundle
18
+ * @param {string | null} param0.outExtension - Specify the output file extension.
19
+ * @param {string} param0.runtimeVersion
20
+ * @returns {import('@babel/core').TransformOptions} The base Babel configuration.
21
+ */
22
+ export function getBaseConfig({
23
+ debug = false,
24
+ optimizeClsx = false,
25
+ removePropTypes = false,
26
+ isTest = false,
27
+ bundle,
28
+ runtimeVersion,
29
+ outExtension,
30
+ }) {
31
+ /**
32
+ * @type {import('@babel/preset-env').Options}
33
+ */
34
+ const presetEnvOptions = {
35
+ bugfixes: true,
36
+ debug,
37
+ modules: bundle === 'esm' ? false : 'commonjs',
38
+ // @TODO
39
+ browserslistEnv: bundle === 'esm' ? 'stable' : 'node',
40
+ };
41
+ /**
42
+ * @type {import('@babel/core').TransformOptions["plugins"]}
43
+ */
44
+ const plugins = [
45
+ [
46
+ pluginTransformRuntime,
47
+ {
48
+ version: runtimeVersion,
49
+ regenerator: false,
50
+ useESModules: bundle === 'esm',
51
+ },
52
+ '@babel/plugin-transform-runtime',
53
+ ],
54
+ [pluginDisplayName, {}, '@mui/internal-babel-plugin-display-name'],
55
+ [
56
+ pluginTransformInlineEnvVars,
57
+ {
58
+ include: [
59
+ 'MUI_VERSION',
60
+ 'MUI_MAJOR_VERSION',
61
+ 'MUI_MINOR_VERSION',
62
+ 'MUI_PATCH_VERSION',
63
+ 'MUI_PRERELEASE',
64
+ ],
65
+ },
66
+ 'babel-plugin-transform-inline-environment-variables',
67
+ ],
68
+ ];
69
+
70
+ if (removePropTypes) {
71
+ plugins.push([
72
+ pluginRemovePropTypes,
73
+ {
74
+ mode: 'unsafe-wrap',
75
+ },
76
+ 'babel-plugin-transform-react-remove-prop-types',
77
+ ]);
78
+ }
79
+
80
+ if (optimizeClsx) {
81
+ plugins.push([pluginOptimizeClsx, {}, 'babel-plugin-optimize-clsx']);
82
+ }
83
+
84
+ if (bundle === 'esm' && !isTest) {
85
+ plugins.push([
86
+ pluginResolveImports,
87
+ { outExtension },
88
+ '@mui/internal-babel-plugin-resolve-imports',
89
+ ]);
90
+ }
91
+
92
+ return {
93
+ assumptions: {
94
+ noDocumentAll: true,
95
+ // With our case these assumptions are safe, and the
96
+ // resulting behavior is equivalent to spec mode.
97
+ setPublicClassFields: true,
98
+ privateFieldsAsProperties: true,
99
+ objectRestNoSymbols: true,
100
+ setSpreadProperties: true,
101
+ },
102
+ ignore: [
103
+ // Fix a Windows issue.
104
+ /@babel[\\|/]runtime/,
105
+ // Fix const foo = /{{(.+?)}}/gs; crashing.
106
+ /prettier/,
107
+ '**/*.template.js',
108
+ ],
109
+ presets: [
110
+ [presetEnv, presetEnvOptions],
111
+ [
112
+ presetReact,
113
+ { runtime: 'automatic', useBuiltIns: bundle === 'esm', useSpread: bundle === 'esm' },
114
+ ],
115
+ [presetTypescript],
116
+ ],
117
+ plugins,
118
+ };
119
+ }
120
+
121
+ /**
122
+ * @type {import('@babel/core').ConfigFunction}
123
+ */
124
+ export default function getBabelConfig(api) {
125
+ const isStable = api.env(['regressions', 'stable']);
126
+ const isTest = api.env('test') || process.env.NODE_ENV === 'test';
127
+
128
+ return getBaseConfig({
129
+ debug: process.env.MUI_BUILD_VERBOSE === 'true',
130
+ bundle: isStable ? 'esm' : 'cjs',
131
+ outExtension: process.env.MUI_OUT_FILE_EXTENSION || null,
132
+ // any package needs to declare 7.25.0 as a runtime dependency. default is ^7.0.0
133
+ runtimeVersion: process.env.MUI_BABEL_RUNTIME_VERSION || '^7.25.0',
134
+ optimizeClsx: process.env.MUI_OPTIMIZE_CLSX === 'true',
135
+ removePropTypes: process.env.MUI_REMOVE_PROP_TYPES === 'true',
136
+ isTest,
137
+ });
138
+ }
@@ -0,0 +1,154 @@
1
+ /* eslint-disable no-console */
2
+ /// <reference types="../untyped-plugins" />
3
+
4
+ import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
5
+ import { globby } from 'globby';
6
+ import * as fs from 'node:fs/promises';
7
+ import * as path from 'node:path';
8
+ import { $ } from 'execa';
9
+
10
+ const TO_TRANSFORM_EXTENSIONS = ['.js', '.ts', '.tsx'];
11
+
12
+ /**
13
+ * @param {string} pkgVersion
14
+ * @returns {Record<string, string>} An object containing version-related environment variables.
15
+ */
16
+ export function getVersionEnvVariables(pkgVersion) {
17
+ if (!pkgVersion) {
18
+ throw new Error('No version found in package.json');
19
+ }
20
+
21
+ const [versionNumber, prerelease] = pkgVersion.split('-');
22
+ const [major, minor, patch] = versionNumber.split('.');
23
+
24
+ if (!major || !minor || !patch) {
25
+ throw new Error(`Couldn't parse version from package.json`);
26
+ }
27
+
28
+ return {
29
+ MUI_VERSION: pkgVersion,
30
+ MUI_MAJOR_VERSION: major,
31
+ MUI_MINOR_VERSION: minor,
32
+ MUI_PATCH_VERSION: patch,
33
+ MUI_PRERELEASE: prerelease,
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Copies CommonJS files from one directory to another.
39
+ * @param {Object} param0
40
+ * @param {string} param0.from - The source directory.
41
+ * @param {string} param0.to - The destination directory.
42
+ * @returns {Promise<void>}
43
+ */
44
+ export async function cjsCopy({ from, to }) {
45
+ if (
46
+ !(await fs
47
+ .stat(to)
48
+ .then(() => true)
49
+ .catch(() => false))
50
+ ) {
51
+ console.warn(`path ${to} does not exists`);
52
+ return;
53
+ }
54
+
55
+ const files = await globby('**/*.cjs', { cwd: from });
56
+ const cmds = files.map((file) => fs.cp(path.resolve(from, file), path.resolve(to, file)));
57
+ await Promise.all(cmds);
58
+ }
59
+
60
+ /**
61
+ * @typedef {Object} ErrorCodeMetadata
62
+ * @property {string} outputPath - The path where the error code file should be written.
63
+ * @property {'annotate' | 'throw' | 'write'} [missingError] - How to handle missing error codes.
64
+ * @property {string} [runtimeModule] - The runtime module to replace the errors with.
65
+ */
66
+
67
+ const BASE_IGNORES = [
68
+ '**/*.test.js',
69
+ '**/*.test.ts',
70
+ '**/*.test.tsx',
71
+ '**/*.spec.js',
72
+ '**/*.spec.ts',
73
+ '**/*.spec.tsx',
74
+ '**/*.d.ts',
75
+ '**/*.test/*.*',
76
+ '**/test-cases/*.*',
77
+ ];
78
+
79
+ /**
80
+ * @param {Object} options
81
+ * @param {boolean} [options.verbose=false] - Whether to enable verbose logging.
82
+ * @param {boolean} [options.optimizeClsx=false] - Whether to enable clsx call optimization transform.
83
+ * @param {boolean} [options.removePropTypes=true] - Whether to enable removal of React prop types.
84
+ * @param {string[]} [options.ignores] - The globs to be ignored by Babel.
85
+ * @param {string} options.cwd - The package root directory.
86
+ * @param {string} options.pkgVersion - The package version.
87
+ * @param {string} options.sourceDir - The source directory to build from.
88
+ * @param {string} options.outDir - The output directory for the build.
89
+ * @param {string} options.outExtension - The output file extension for the build.
90
+ * @param {boolean} options.hasLargeFiles - Whether the build includes large files.
91
+ * @param {import('../utils/build.mjs').BundleType} options.bundle - The bundles to build.
92
+ * @param {string} options.babelRuntimeVersion - The version of @babel/runtime to use.
93
+ * @returns {Promise<void>}
94
+ */
95
+ export async function babelBuild({
96
+ cwd,
97
+ sourceDir,
98
+ outDir,
99
+ babelRuntimeVersion,
100
+ hasLargeFiles,
101
+ bundle,
102
+ pkgVersion,
103
+ outExtension,
104
+ optimizeClsx = false,
105
+ removePropTypes = false,
106
+ verbose = false,
107
+ ignores = [],
108
+ }) {
109
+ console.log(
110
+ `Transpiling files to "${path.relative(path.dirname(sourceDir), outDir)}" for "${bundle}" bundle.`,
111
+ );
112
+ const workspaceDir = await findWorkspaceDir(cwd);
113
+ if (!workspaceDir) {
114
+ throw new Error(`No workspace found for ${cwd}`);
115
+ }
116
+ let configFile = path.join(workspaceDir, 'babel.config.js');
117
+ if (
118
+ !(await fs
119
+ .stat(configFile)
120
+ .then(() => true)
121
+ .catch(() => false))
122
+ ) {
123
+ configFile = path.join(workspaceDir, 'babel.config.mjs');
124
+ }
125
+ const env = {
126
+ NODE_ENV: 'production',
127
+ BABEL_ENV: bundle === 'esm' ? 'stable' : 'node',
128
+ MUI_BUILD_VERBOSE: verbose ? 'true' : undefined,
129
+ MUI_OPTIMIZE_CLSX: optimizeClsx ? 'true' : undefined,
130
+ MUI_REMOVE_PROP_TYPES: removePropTypes ? 'true' : undefined,
131
+ MUI_BABEL_RUNTIME_VERSION: babelRuntimeVersion,
132
+ MUI_OUT_FILE_EXTENSION: outExtension ?? '.js',
133
+ ...getVersionEnvVariables(pkgVersion),
134
+ };
135
+ const res = await $({
136
+ stdio: 'inherit',
137
+ env: {
138
+ ...process.env,
139
+ ...env,
140
+ },
141
+ })`pnpm babel --config-file ${configFile} --extensions ${TO_TRANSFORM_EXTENSIONS.join(',')} ${sourceDir} --out-dir ${outDir} --ignore ${BASE_IGNORES.concat(ignores).join(',')} --out-file-extension ${outExtension !== '.js' ? outExtension : '.js'} --compact ${hasLargeFiles ? 'false' : 'auto'}`;
142
+
143
+ if (res.stderr) {
144
+ throw new Error(`Command: '${res.escapedCommand}' failed with \n${res.stderr}`);
145
+ }
146
+ if (verbose) {
147
+ console.log(`Command: '${res.escapedCommand}' succeeded with \n${res.stdout}`);
148
+ }
149
+
150
+ // cjs for reexporting from commons only modules.
151
+ // If we need to rely more on this we can think about setting up a separate commonjs => commonjs build for .cjs files to .cjs
152
+ // `--extensions-.cjs --out-file-extension .cjs`
153
+ await cjsCopy({ from: sourceDir, to: outDir });
154
+ }
@@ -0,0 +1,438 @@
1
+ /* eslint-disable no-console */
2
+ import { $ } from 'execa';
3
+ import { globby } from 'globby';
4
+ import set from 'lodash-es/set.js';
5
+ import * as fs from 'node:fs/promises';
6
+ import * as path from 'node:path';
7
+ import { getOutExtension, isMjsBuild } from '../utils/build.mjs';
8
+
9
+ /**
10
+ * @typedef {Object} Args
11
+ * @property {import('../utils/build.mjs').BundleType[]} bundle - The bundles to build.
12
+ * @property {boolean} hasLargeFiles - The large files to build.
13
+ * @property {boolean} skipBundlePackageJson - Whether to skip generating a package.json file in the /esm folder.
14
+ * @property {string} cjsOutDir - The directory to copy the cjs files to.
15
+ * @property {boolean} verbose - Whether to enable verbose logging.
16
+ * @property {boolean} buildTypes - Whether to build types for the package.
17
+ * @property {boolean} skipTsc - Whether to build types for the package.
18
+ * @property {boolean} skipBabelRuntimeCheck - Whether to skip checking for Babel runtime dependencies in the package.
19
+ * @property {boolean} skipPackageJson - Whether to skip generating the package.json file in the bundle output.
20
+ * @property {string[]} ignore - Globs to be ignored by Babel.
21
+ */
22
+
23
+ const validBundles = [
24
+ // build for node using commonJS modules
25
+ 'cjs',
26
+ // build with a hardcoded target using ES6 modules
27
+ 'esm',
28
+ ];
29
+
30
+ /**
31
+ * @param {Object} options
32
+ * @param {string} options.name - The name of the package.
33
+ * @param {string} options.version - The version of the package.
34
+ * @param {string} options.license - The license of the package.
35
+ * @param {import('../utils/build.mjs').BundleType} options.bundle
36
+ * @param {string} options.outputDir
37
+ */
38
+ async function addLicense({ name, version, license, bundle, outputDir }) {
39
+ const outExtension = getOutExtension(bundle);
40
+ const file = path.join(outputDir, `index${outExtension}`);
41
+ if (
42
+ !(await fs.stat(file).then(
43
+ (stats) => stats.isFile(),
44
+ () => false,
45
+ ))
46
+ ) {
47
+ return;
48
+ }
49
+ const content = await fs.readFile(file, { encoding: 'utf8' });
50
+ await fs.writeFile(
51
+ file,
52
+ `/**
53
+ * ${name} v${version}
54
+ *
55
+ * @license ${license}
56
+ * This source code is licensed under the ${license} license found in the
57
+ * LICENSE file in the root directory of this source tree.
58
+ */
59
+ ${content}`,
60
+ { encoding: 'utf8' },
61
+ );
62
+ console.log(`License added to ${file}`);
63
+ }
64
+
65
+ /**
66
+ * @param {Object} param0
67
+ * @param {string | Record<string, string>} param0.importPath
68
+ * @param {string} param0.key
69
+ * @param {string} param0.cwd
70
+ * @param {string} param0.dir
71
+ * @param {string} param0.type
72
+ * @param {Object} param0.newExports
73
+ * @param {string} param0.typeOutExtension
74
+ * @param {string} param0.outExtension
75
+ * @param {boolean} param0.addTypes
76
+ * @returns {Promise<{path: string[], importPath: string | Record<string, string | undefined>}>}
77
+ */
78
+ async function createExportsFor({
79
+ importPath,
80
+ key,
81
+ cwd,
82
+ dir,
83
+ type,
84
+ newExports,
85
+ typeOutExtension,
86
+ outExtension,
87
+ addTypes,
88
+ }) {
89
+ let srcPath = typeof importPath === 'string' ? importPath : importPath['mui-src'];
90
+ const rest = typeof importPath === 'string' ? {} : { ...importPath };
91
+ delete rest['mui-src'];
92
+
93
+ const exportFileExists = srcPath.includes('*')
94
+ ? true
95
+ : await fs.stat(path.join(cwd, srcPath)).then(
96
+ (stats) => stats.isFile() || stats.isDirectory(),
97
+ () => false,
98
+ );
99
+ if (!exportFileExists) {
100
+ throw new Error(
101
+ `The import path "${srcPath}" for export "${key}" does not exist in the package. Either remove the export or add the file/folder to the package.`,
102
+ );
103
+ }
104
+ srcPath = srcPath.replace(/\.\/src\//, `./${dir === '.' ? '' : `${dir}/`}`);
105
+ const ext = path.extname(srcPath);
106
+
107
+ if (ext === '.css') {
108
+ set(newExports, [key], srcPath);
109
+ return {
110
+ path: [key],
111
+ importPath: srcPath,
112
+ };
113
+ }
114
+ return {
115
+ path: [key, type === 'cjs' ? 'require' : 'import'],
116
+ importPath: {
117
+ ...rest,
118
+ types: addTypes ? srcPath.replace(ext, typeOutExtension) : undefined,
119
+ default: srcPath.replace(ext, outExtension),
120
+ },
121
+ };
122
+ }
123
+
124
+ /**
125
+ * @param {Object} param0
126
+ * @param {any} param0.packageJson - The package.json content.
127
+ * @param {{type: import('../utils/build.mjs').BundleType; dir: string}[]} param0.bundles
128
+ * @param {string} param0.outputDir
129
+ * @param {string} param0.cwd
130
+ * @param {boolean} param0.addTypes - Whether to add type declarations for the package.
131
+ */
132
+ async function writePackageJson({ packageJson, bundles, outputDir, cwd, addTypes = false }) {
133
+ delete packageJson.scripts;
134
+ delete packageJson.publishConfig?.directory;
135
+ delete packageJson.devDependencies;
136
+ delete packageJson.imports;
137
+
138
+ packageJson.type = packageJson.type || 'commonjs';
139
+
140
+ /**
141
+ * @type {Record<string, string | Record<string, string> | null>}
142
+ */
143
+ const originalExports = packageJson.exports || {};
144
+ delete packageJson.exports;
145
+ /**
146
+ * @type {Record<string, string | Record<string, string> | null>}
147
+ */
148
+ const newExports = {
149
+ './package.json': './package.json',
150
+ };
151
+
152
+ await Promise.all(
153
+ bundles.map(async ({ type, dir }) => {
154
+ const outExtension = getOutExtension(type);
155
+ const typeOutExtension = getOutExtension(type, true);
156
+ const indexFileExists = await fs.stat(path.join(outputDir, dir, `index${outExtension}`)).then(
157
+ (stats) => stats.isFile(),
158
+ () => false,
159
+ );
160
+ const typeFileExists =
161
+ addTypes &&
162
+ (await fs.stat(path.join(outputDir, dir, `index${typeOutExtension}`)).then(
163
+ (stats) => stats.isFile(),
164
+ () => false,
165
+ ));
166
+ const dirPrefix = dir === '.' ? '' : `${dir}/`;
167
+ const exportDir = `./${dirPrefix}index${outExtension}`;
168
+ const typeExportDir = `./${dirPrefix}index${typeOutExtension}`;
169
+
170
+ if (indexFileExists) {
171
+ // skip `packageJson.module` to support parcel and some older bundlers
172
+ if (type === 'cjs') {
173
+ packageJson.main = exportDir;
174
+ }
175
+ set(newExports, ['.', type === 'cjs' ? 'require' : 'import'], {
176
+ types: typeFileExists ? typeExportDir : undefined,
177
+ default: exportDir,
178
+ });
179
+ }
180
+ if (typeFileExists && type === 'cjs') {
181
+ packageJson.types = typeExportDir;
182
+ }
183
+ const exportKeys = Object.keys(originalExports);
184
+ // need to maintain the order of exports
185
+ for (const key of exportKeys) {
186
+ const importPath = originalExports[key];
187
+ if (!importPath) {
188
+ set(newExports, [key], null);
189
+ return;
190
+ }
191
+ // eslint-disable-next-line no-await-in-loop
192
+ const res = await createExportsFor({
193
+ importPath,
194
+ key,
195
+ cwd,
196
+ dir,
197
+ type,
198
+ newExports,
199
+ typeOutExtension,
200
+ outExtension,
201
+ addTypes,
202
+ });
203
+ set(newExports, res.path, res.importPath);
204
+ }
205
+ }),
206
+ );
207
+ bundles.forEach(({ dir }) => {
208
+ if (dir !== '.') {
209
+ newExports[`./${dir}`] = null;
210
+ }
211
+ });
212
+
213
+ packageJson.exports = newExports;
214
+
215
+ await fs.writeFile(
216
+ path.join(outputDir, 'package.json'),
217
+ JSON.stringify(packageJson, null, 2),
218
+ 'utf-8',
219
+ );
220
+ }
221
+
222
+ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
223
+ command: 'build',
224
+ describe: 'Builds the package for publishing.',
225
+ builder(yargs) {
226
+ return yargs
227
+ .option('bundle', {
228
+ array: true,
229
+ demandOption: true,
230
+ type: 'string',
231
+ choices: validBundles,
232
+ description: 'Bundles to output',
233
+ default: ['esm', 'cjs'],
234
+ })
235
+ .option('hasLargeFiles', {
236
+ type: 'boolean',
237
+ default: false,
238
+ describe: 'Set to `true` if you know you are transpiling large files.',
239
+ })
240
+ .option('skipBundlePackageJson', {
241
+ type: 'boolean',
242
+ default: false,
243
+ describe:
244
+ "Set to `true` if you don't want to generate a package.json file in the bundle output.",
245
+ })
246
+ .option('cjsOutDir', {
247
+ default: '.',
248
+ type: 'string',
249
+ description: 'The directory to output the cjs files to.',
250
+ })
251
+ .option('verbose', {
252
+ type: 'boolean',
253
+ default: false,
254
+ description: 'Enable verbose logging.',
255
+ })
256
+ .option('buildTypes', {
257
+ type: 'boolean',
258
+ default: true,
259
+ description: 'Whether to build types for the package.',
260
+ })
261
+ .option('skipTsc', {
262
+ type: 'boolean',
263
+ default: false,
264
+ description: 'Skip running TypeScript compiler (tsc) for building types.',
265
+ })
266
+ .option('ignore', {
267
+ type: 'string',
268
+ array: true,
269
+ description: 'Extra globs to be ignored by Babel.',
270
+ default: [],
271
+ })
272
+ .option('skipBabelRuntimeCheck', {
273
+ type: 'boolean',
274
+ default: false,
275
+ description: 'Skip checking for Babel runtime dependencies in the package.',
276
+ })
277
+ .option('skipPackageJson', {
278
+ type: 'boolean',
279
+ default: false,
280
+ description: 'Skip generating the package.json file in the bundle output.',
281
+ });
282
+ },
283
+ async handler(args) {
284
+ const {
285
+ bundle: bundles,
286
+ hasLargeFiles,
287
+ skipBundlePackageJson,
288
+ cjsOutDir = '.',
289
+ verbose = false,
290
+ ignore: extraIgnores,
291
+ buildTypes,
292
+ skipTsc,
293
+ skipBabelRuntimeCheck = false,
294
+ skipPackageJson = false,
295
+ } = args;
296
+
297
+ const cwd = process.cwd();
298
+ const pkgJsonPath = path.join(cwd, 'package.json');
299
+ const packageJson = JSON.parse(await fs.readFile(pkgJsonPath, { encoding: 'utf8' }));
300
+ const buildDirBase = packageJson.publishConfig?.directory;
301
+ if (!buildDirBase) {
302
+ throw new Error(
303
+ 'No build directory specified in package.json. Specify it in the "publishConfig.directory" field.',
304
+ );
305
+ }
306
+ const buildDir = path.join(cwd, buildDirBase);
307
+
308
+ console.log(`Selected output directory: "${buildDirBase}"`);
309
+
310
+ let babelRuntimeVersion = packageJson.dependencies['@babel/runtime'];
311
+ if (babelRuntimeVersion === 'catalog:') {
312
+ // resolve the version from the given package
313
+ // outputs the pnpm-workspace.yaml config as json
314
+ const { stdout: configStdout } = await $`pnpm config list --json`;
315
+ const pnpmWorkspaceConfig = JSON.parse(configStdout);
316
+ babelRuntimeVersion = pnpmWorkspaceConfig.catalog['@babel/runtime'];
317
+ }
318
+
319
+ if (!babelRuntimeVersion && !skipBabelRuntimeCheck) {
320
+ throw new Error(
321
+ 'package.json needs to have a dependency on `@babel/runtime` when building with `@babel/plugin-transform-runtime`.',
322
+ );
323
+ }
324
+
325
+ if (!bundles.length) {
326
+ console.error('No bundles specified. Use --bundle to specify which bundles to build.');
327
+ return;
328
+ }
329
+
330
+ const babelMod = await import('./babel.mjs');
331
+ const relativeOutDirs = {
332
+ cjs: cjsOutDir,
333
+ esm: 'esm',
334
+ };
335
+ const sourceDir = path.join(cwd, 'src');
336
+
337
+ // js build start
338
+ await Promise.all(
339
+ bundles.map(async (bundle) => {
340
+ const outExtension = getOutExtension(bundle);
341
+ const relativeOutDir = relativeOutDirs[bundle];
342
+ const outputDir = path.join(buildDir, relativeOutDir);
343
+ await fs.mkdir(outputDir, { recursive: true });
344
+
345
+ const promises = [];
346
+
347
+ promises.push(
348
+ babelMod.babelBuild({
349
+ cwd,
350
+ sourceDir,
351
+ outDir: outputDir,
352
+ babelRuntimeVersion,
353
+ hasLargeFiles,
354
+ bundle,
355
+ verbose,
356
+ optimizeClsx:
357
+ packageJson.dependencies.clsx !== undefined ||
358
+ packageJson.dependencies.classnames !== undefined,
359
+ removePropTypes: packageJson.dependencies['prop-types'] !== undefined,
360
+ pkgVersion: packageJson.version,
361
+ ignores: extraIgnores,
362
+ outExtension,
363
+ }),
364
+ );
365
+
366
+ if (buildDir !== outputDir && !skipBundlePackageJson && !isMjsBuild) {
367
+ // @TODO - Not needed if the output extension is .mjs. Remove this before PR merge.
368
+ promises.push(
369
+ fs.writeFile(
370
+ path.join(outputDir, 'package.json'),
371
+ JSON.stringify({
372
+ type: bundle === 'esm' ? 'module' : 'commonjs',
373
+ sideEffects: packageJson.sideEffects || undefined,
374
+ }),
375
+ ),
376
+ );
377
+ }
378
+
379
+ await Promise.all(promises);
380
+ await addLicense({
381
+ bundle,
382
+ license: packageJson.license,
383
+ name: packageJson.name,
384
+ version: packageJson.version,
385
+ outputDir,
386
+ });
387
+ }),
388
+ );
389
+ // js build end
390
+
391
+ if (buildTypes) {
392
+ const tsMod = await import('./typescript.mjs');
393
+ /**
394
+ * @type {{type: import('../utils/build.mjs').BundleType, dir: string}[]};
395
+ */
396
+ const bundleMap = bundles.map((type) => ({
397
+ type,
398
+ dir: relativeOutDirs[type],
399
+ }));
400
+
401
+ await tsMod.createTypes({
402
+ bundles: bundleMap,
403
+ srcDir: sourceDir,
404
+ cwd,
405
+ skipTsc,
406
+ isMjsBuild,
407
+ buildDir,
408
+ });
409
+ }
410
+ if (skipPackageJson) {
411
+ console.log('Skipping package.json generation in the output directory.');
412
+ return;
413
+ }
414
+
415
+ const normalizedCjsOutDir = cjsOutDir === '.' || cjsOutDir === './' ? '.' : cjsOutDir;
416
+ await writePackageJson({
417
+ cwd,
418
+ packageJson,
419
+ bundles: bundles.map((type) => ({
420
+ type,
421
+ dir: type === 'esm' ? 'esm' : normalizedCjsOutDir || '.',
422
+ })),
423
+ outputDir: buildDir,
424
+ addTypes: buildTypes,
425
+ });
426
+
427
+ // cleanup
428
+ const tsbuildinfo = await globby('**/*.tsbuildinfo', {
429
+ absolute: true,
430
+ cwd: buildDir,
431
+ });
432
+ await Promise.all(
433
+ tsbuildinfo.map(async (file) => {
434
+ await fs.rm(file);
435
+ }),
436
+ );
437
+ },
438
+ });
@@ -0,0 +1,217 @@
1
+ /* eslint-disable no-console */
2
+
3
+ import { findWorkspaceDir } from '@pnpm/find-workspace-dir';
4
+ import { globby } from 'globby';
5
+ import fs from 'node:fs/promises';
6
+ import path from 'node:path';
7
+
8
+ /**
9
+ * @typedef {Object} Args
10
+ * @property {boolean} [silent] Run in silent mode without logging
11
+ * @property {boolean} [excludeDefaults] Exclude default files from the copy operation
12
+ * @property {string[]} [glob] Glob patterns to copy
13
+ */
14
+
15
+ /**
16
+ * Check if a file exists.
17
+ * @param {string} filePath
18
+ * @returns {Promise<boolean>}
19
+ */
20
+ async function fileOrDirExists(filePath) {
21
+ try {
22
+ await fs.stat(filePath);
23
+ return true;
24
+ } catch (err) {
25
+ if (/** @type {{ code: string }} */ (err).code === 'ENOENT') {
26
+ return false;
27
+ }
28
+ throw err;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Recursively copies files and directories from a source path to a target path.
34
+ *
35
+ * @async
36
+ * @param {Object} options - The options for copying files.
37
+ * @param {string} options.source - The source path to copy from.
38
+ * @param {string} options.target - The target path to copy to.
39
+ * @param {boolean} [options.silent=false] - If true, suppresses console output.
40
+ * @returns {Promise<boolean>} Resolves when the copy operation is complete.
41
+ * @throws {Error} Throws if an error occurs other than the source not existing.
42
+ */
43
+ async function recursiveCopy({ source, target, silent = false }) {
44
+ try {
45
+ await fs.cp(source, target, { recursive: true });
46
+ if (!silent) {
47
+ console.log(`Copied ${source} to ${target}`);
48
+ }
49
+ return true;
50
+ } catch (err) {
51
+ if (/** @type {{ code: string }} */ (err).code !== 'ENOENT') {
52
+ throw err;
53
+ }
54
+ if (!silent) {
55
+ console.warn(`Source does not exist: ${source}`);
56
+ }
57
+ throw err;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Process glob patterns and copy matching files.
63
+ * @param {Object} param0
64
+ * @param {boolean} [param0.silent=true] - Whether to suppress output.
65
+ * @param {string[]} param0.globs - The glob patterns to process.
66
+ * @param {string} param0.cwd - The current working directory.
67
+ * @param {string} param0.buildDir - The build directory.
68
+ * @returns {Promise<number>}
69
+ */
70
+ async function processGlobs({ globs, cwd, silent = true, buildDir }) {
71
+ const res = globs.map((globPattern) => {
72
+ const [pattern, baseDir] = globPattern.split(':');
73
+ return { pattern, baseDir };
74
+ });
75
+
76
+ /**
77
+ * Avoids redundant globby calls for the same pattern.
78
+ *
79
+ * @type {Map<string, Promise<string[]>>}
80
+ */
81
+ const globToResMap = new Map();
82
+
83
+ const result = await Promise.all(
84
+ res.map(async ({ pattern, baseDir }) => {
85
+ if (!globToResMap.has(pattern)) {
86
+ const promise = globby(pattern, { cwd });
87
+ globToResMap.set(pattern, promise);
88
+ }
89
+ const files = await globToResMap.get(pattern);
90
+ return { files: files ?? [], baseDir };
91
+ }),
92
+ );
93
+ globToResMap.clear();
94
+
95
+ const filesToProcess = result.flatMap(({ files, baseDir }) => {
96
+ return files.map((file) => {
97
+ const sourcePath = path.resolve(cwd, file);
98
+ const pathSegments = file.split(path.sep);
99
+ const relativePath = pathSegments.slice(1).join(path.sep);
100
+ const targetPath = baseDir
101
+ ? path.resolve(buildDir, baseDir, relativePath)
102
+ : path.resolve(buildDir, relativePath);
103
+ const targetDir = path.dirname(targetPath);
104
+ return { targetDir, targetPath, sourcePath };
105
+ });
106
+ });
107
+
108
+ const concurrency = filesToProcess.length > 100 ? 100 : filesToProcess.length;
109
+ const iterator = filesToProcess[Symbol.iterator]();
110
+ const workers = [];
111
+ for (let i = 0; i < concurrency; i += 1) {
112
+ workers.push(
113
+ Promise.resolve().then(async () => {
114
+ for (const file of iterator) {
115
+ // eslint-disable-next-line no-await-in-loop
116
+ await recursiveCopy({ source: file.sourcePath, target: file.targetPath, silent });
117
+ }
118
+ }),
119
+ );
120
+ }
121
+ await Promise.all(workers);
122
+ return filesToProcess.length;
123
+ }
124
+
125
+ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
126
+ command: 'copy-files',
127
+ describe: 'Copy files from source to target paths within the build directory.',
128
+ builder: (yargs) => {
129
+ return yargs
130
+ .option('silent', {
131
+ type: 'boolean',
132
+ default: true,
133
+ description: "Don't log file names.",
134
+ })
135
+ .option('excludeDefaults', {
136
+ type: 'boolean',
137
+ default: false,
138
+ description:
139
+ 'Exclude default files from the copy operation (includes readme, license, changelog).',
140
+ })
141
+ .option('glob', {
142
+ type: 'string',
143
+ array: true,
144
+ description: 'Glob pattern to match files.',
145
+ })
146
+ .positional('_', {
147
+ type: 'string',
148
+ describe: 'Files to copy, can be specified as `source:target` pairs or just `source`.',
149
+ array: true,
150
+ demandOption: true,
151
+ });
152
+ },
153
+ handler: async (args) => {
154
+ const { silent = false, excludeDefaults = false, glob: globs = [] } = args;
155
+ const cwd = process.cwd();
156
+ const pkgJson = JSON.parse(await fs.readFile(path.join(cwd, 'package.json'), 'utf-8'));
157
+ /**
158
+ * @type {string}
159
+ */
160
+ const buildDir = pkgJson.publishConfig?.directory || 'build';
161
+ const extraFiles = /** @type {string[]} */ (args._.slice(1));
162
+ /**
163
+ * @type {string[]}
164
+ */
165
+ const defaultFiles = [];
166
+ const workspaceDir = await findWorkspaceDir(cwd);
167
+ if (!workspaceDir) {
168
+ throw new Error('Workspace directory not found');
169
+ }
170
+ const localOrRootFiles = [
171
+ [path.join(cwd, 'README.md'), path.join(workspaceDir, 'README.md')],
172
+ [path.join(cwd, 'LICENSE'), path.join(workspaceDir, 'LICENSE')],
173
+ [path.join(cwd, 'CHANGELOG.md'), path.join(workspaceDir, 'CHANGELOG.md')],
174
+ ];
175
+ await Promise.all(
176
+ localOrRootFiles.map(async (files) => {
177
+ for (const file of files) {
178
+ // eslint-disable-next-line no-await-in-loop
179
+ if (await fileOrDirExists(file)) {
180
+ defaultFiles.push(file);
181
+ break;
182
+ }
183
+ }
184
+ }),
185
+ );
186
+
187
+ const filesToCopy = excludeDefaults ? extraFiles : [...defaultFiles, ...extraFiles];
188
+ let result = filesToCopy.length;
189
+
190
+ if (filesToCopy.length) {
191
+ await Promise.all(
192
+ filesToCopy.map(async (file) => {
193
+ const [sourcePath, targetPath] = path.isAbsolute(file)
194
+ ? [file, undefined]
195
+ : file.split(':');
196
+ const resolvedSourcePath = path.resolve(cwd, sourcePath);
197
+ const resolvedTargetPath = path.resolve(buildDir, targetPath ?? path.basename(file));
198
+ return recursiveCopy({
199
+ source: resolvedSourcePath,
200
+ target: resolvedTargetPath,
201
+ silent,
202
+ });
203
+ }),
204
+ );
205
+ }
206
+
207
+ if (globs.length) {
208
+ result += await processGlobs({
209
+ globs,
210
+ cwd,
211
+ buildDir,
212
+ silent,
213
+ });
214
+ }
215
+ console.log(`Copied ${result} files.`);
216
+ },
217
+ });
package/src/cli/index.mjs CHANGED
@@ -1,13 +1,18 @@
1
+ import { createRequire } from 'node:module';
1
2
  import yargs from 'yargs';
2
3
  import { hideBin } from 'yargs/helpers';
3
4
 
5
+ import cmdArgosPush from './cmdArgosPush.mjs';
6
+ import cmdBuild from './cmdBuild.mjs';
7
+ import cmdCopyFiles from './cmdCopyFiles.mjs';
8
+ import cmdJsonLint from './cmdJsonLint.mjs';
9
+ import cmdListWorkspaces from './cmdListWorkspaces.mjs';
4
10
  import cmdPublish from './cmdPublish.mjs';
5
11
  import cmdPublishCanary from './cmdPublishCanary.mjs';
6
- import cmdListWorkspaces from './cmdListWorkspaces.mjs';
7
- import cmdJsonLint from './cmdJsonLint.mjs';
8
- import cmdArgosPush from './cmdArgosPush.mjs';
9
12
  import cmdSetVersionOverrides from './cmdSetVersionOverrides.mjs';
10
13
 
14
+ const pkgJson = createRequire(import.meta.url)('../../package.json');
15
+
11
16
  yargs()
12
17
  .command(cmdPublish)
13
18
  .command(cmdPublishCanary)
@@ -15,6 +20,9 @@ yargs()
15
20
  .command(cmdJsonLint)
16
21
  .command(cmdArgosPush)
17
22
  .command(cmdSetVersionOverrides)
23
+ .command(cmdCopyFiles)
24
+ .command(cmdBuild)
18
25
  .demandCommand(1, 'You need at least one command before moving on')
19
26
  .help()
27
+ .version(pkgJson.version)
20
28
  .parse(hideBin(process.argv));
@@ -0,0 +1,165 @@
1
+ /* eslint-disable no-console */
2
+ import * as babel from '@babel/core';
3
+ import pluginTypescriptSyntax from '@babel/plugin-syntax-typescript';
4
+ import pluginResolveImports from '@mui/internal-babel-plugin-resolve-imports';
5
+ import pluginRemoveImports from 'babel-plugin-transform-remove-imports';
6
+ import { $ } from 'execa';
7
+ import { globby } from 'globby';
8
+ import * as fs from 'node:fs/promises';
9
+ import * as os from 'node:os';
10
+ import * as path from 'node:path';
11
+
12
+ const $$ = $({ stdio: 'inherit' });
13
+
14
+ /**
15
+ * Emits TypeScript declaration files.
16
+ * @param {string} tsconfig - The path to the tsconfig.json file.
17
+ * @param {string} outDir - The output directory for the declaration files.
18
+ */
19
+ export async function emitDeclarations(tsconfig, outDir) {
20
+ console.log(`Building types for ${tsconfig} in ${outDir}`);
21
+ await $$`tsc -p ${tsconfig} --outDir ${outDir} --declaration --emitDeclarationOnly`;
22
+ }
23
+
24
+ /**
25
+ * @param {string} sourceDirectory
26
+ * @param {string} destinationDirectory
27
+ */
28
+ export async function copyDeclarations(sourceDirectory, destinationDirectory) {
29
+ const fullSourceDirectory = path.resolve(sourceDirectory);
30
+ const fullDestinationDirectory = path.resolve(destinationDirectory);
31
+
32
+ console.log(`Copying declarations from ${fullSourceDirectory} to ${fullDestinationDirectory}`);
33
+
34
+ await fs.cp(fullSourceDirectory, fullDestinationDirectory, {
35
+ recursive: true,
36
+ filter: async (src) => {
37
+ if (src.startsWith('.')) {
38
+ // ignore dotfiles
39
+ return false;
40
+ }
41
+ const stats = await fs.stat(src);
42
+ if (stats.isDirectory()) {
43
+ return true;
44
+ }
45
+ return src.endsWith('.d.ts') || src.endsWith('.d.mts');
46
+ },
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Post-processes TypeScript declaration files.
52
+ * @param {Object} param0
53
+ * @param {string} param0.directory - The directory containing the declaration files.
54
+ */
55
+ async function postProcessDeclarations({ directory }) {
56
+ const dtsFiles = await globby('**/*.d.ts', {
57
+ absolute: true,
58
+ cwd: directory,
59
+ });
60
+ if (dtsFiles.length === 0) {
61
+ console.log(`No d.ts files found in ${directory}. Skipping post-processing.`);
62
+ return;
63
+ }
64
+
65
+ /**
66
+ * @type {import('@babel/core').PluginItem[]}
67
+ */
68
+ const babelPlugins = [
69
+ [pluginTypescriptSyntax, { dts: true }],
70
+ [pluginResolveImports],
71
+ [pluginRemoveImports, { test: /\.css$/ }],
72
+ ];
73
+
74
+ await Promise.all(
75
+ dtsFiles.map(async (dtsFile) => {
76
+ const result = await babel.transformFileAsync(dtsFile, {
77
+ configFile: false,
78
+ plugins: babelPlugins,
79
+ });
80
+
81
+ if (typeof result?.code === 'string') {
82
+ await fs.writeFile(dtsFile, result.code);
83
+ } else {
84
+ console.error('failed to transform', dtsFile);
85
+ }
86
+ }),
87
+ );
88
+ }
89
+
90
+ /**
91
+ * Renames TypeScript declaration files.
92
+ * @param {Object} param0
93
+ * @param {string} param0.directory - The directory containing the declaration files.
94
+ */
95
+ async function renameDeclarations({ directory }) {
96
+ const dtsFiles = await globby('**/*.d.ts', { absolute: true, cwd: directory });
97
+ if (dtsFiles.length === 0) {
98
+ return;
99
+ }
100
+ console.log(`Renaming d.ts files to d.mts in ${directory}`);
101
+ await Promise.all(
102
+ dtsFiles.map(async (dtsFile) => {
103
+ const newFileName = dtsFile.replace(/\.d\.ts$/, '.d.mts');
104
+ await fs.rename(dtsFile, newFileName);
105
+ }),
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Creates TypeScript declaration files for the specified bundles.
111
+ * Types are first created in a temporary directory and then copied to the appropriate bundle directories parallelly.
112
+ * After copying, babel transformations are applied to the copied files because they need to be alongside the actual js files for proper resolution.
113
+ *
114
+ * @param {Object} param0
115
+ * @param {boolean} [param0.isMjsBuild] - Whether the build is for ESM (ECMAScript Modules).
116
+ * @param {{type: import('../utils/build.mjs').BundleType, dir: string}[]} param0.bundles - The bundles to create declarations for.
117
+ * @param {string} param0.srcDir - The source directory.
118
+ * @param {string} param0.buildDir - The build directory.
119
+ * @param {string} param0.cwd - The current working directory.
120
+ * @param {boolean} param0.skipTsc - Whether to skip running TypeScript compiler (tsc) for building types.
121
+ */
122
+ export async function createTypes({ bundles, srcDir, buildDir, cwd, skipTsc, isMjsBuild }) {
123
+ const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'code-infra-build-tsc-'));
124
+
125
+ try {
126
+ await copyDeclarations(srcDir, tmpDir);
127
+ const tsconfigPath = path.join(cwd, 'tsconfig.build.json');
128
+ const tsconfigExists = await fs.stat(tsconfigPath).then(
129
+ (file) => file.isFile(),
130
+ () => false,
131
+ );
132
+ if (!skipTsc) {
133
+ if (!tsconfigExists) {
134
+ throw new Error(
135
+ 'Unable to find a tsconfig to build this project. ' +
136
+ `The package root needs to contain a 'tsconfig.build.json'. ` +
137
+ `The package root is '${cwd}'`,
138
+ );
139
+ }
140
+ await emitDeclarations(tsconfigPath, tmpDir);
141
+ }
142
+
143
+ for (const bundle of bundles) {
144
+ const { type: bundleType, dir: bundleOutDir } = bundle;
145
+ const fullOutDir = path.join(buildDir, bundleOutDir);
146
+ // eslint-disable-next-line no-await-in-loop
147
+ await fs.cp(tmpDir, fullOutDir, {
148
+ recursive: true,
149
+ force: false,
150
+ });
151
+ // eslint-disable-next-line no-await-in-loop
152
+ await postProcessDeclarations({
153
+ directory: fullOutDir,
154
+ });
155
+ if (bundleType === 'esm' && isMjsBuild) {
156
+ // eslint-disable-next-line no-await-in-loop
157
+ await renameDeclarations({
158
+ directory: fullOutDir,
159
+ });
160
+ }
161
+ }
162
+ } finally {
163
+ await fs.rm(tmpDir, { recursive: true, force: true });
164
+ }
165
+ }
@@ -94,3 +94,56 @@ declare module '@next/eslint-plugin-next' {
94
94
  declare const config: NextEslintPluginConfig;
95
95
  export default config;
96
96
  }
97
+
98
+ declare module '@babel/plugin-transform-runtime' {
99
+ import type { PluginItem } from '@babel/core';
100
+
101
+ declare const plugin: PluginItem;
102
+ export default plugin;
103
+ }
104
+
105
+ declare module '@babel/plugin-syntax-typescript' {
106
+ import type { PluginItem } from '@babel/core';
107
+
108
+ declare const plugin: PluginItem;
109
+ export default plugin;
110
+ }
111
+
112
+ declare module 'babel-plugin-optimize-clsx' {
113
+ import type { PluginItem } from '@babel/core';
114
+
115
+ declare const plugin: PluginItem;
116
+ export default plugin;
117
+ }
118
+
119
+ declare module 'babel-plugin-transform-react-remove-prop-types' {
120
+ import type { PluginItem } from '@babel/core';
121
+
122
+ declare const plugin: PluginItem;
123
+ export default plugin;
124
+ }
125
+
126
+ declare module 'babel-plugin-transform-inline-environment-variables' {
127
+ import type { PluginItem } from '@babel/core';
128
+
129
+ declare const plugin: PluginItem;
130
+ export default plugin;
131
+ }
132
+
133
+ declare module '@babel/preset-react' {
134
+ import type { PluginItem } from '@babel/core';
135
+
136
+ export type Options = {
137
+ runtime: 'string';
138
+ };
139
+
140
+ declare const preset: PluginItem;
141
+ export default preset;
142
+ }
143
+
144
+ declare module '@babel/preset-typescript' {
145
+ import type { PluginItem } from '@babel/core';
146
+
147
+ declare const preset: PluginItem;
148
+ export default preset;
149
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @typedef {'esm' | 'cjs'} BundleType
3
+ */
4
+ export const isMjsBuild = !!process.env.MUI_EXPERIMENTAL_MJS;
5
+
6
+ /**
7
+ * @param {BundleType} bundle
8
+ */
9
+ export function getOutExtension(bundle, isType = false) {
10
+ if (isType) {
11
+ if (!isMjsBuild) {
12
+ return '.d.ts';
13
+ }
14
+ return bundle === 'esm' ? '.d.mts' : '.d.ts';
15
+ }
16
+ if (!isMjsBuild) {
17
+ return '.js';
18
+ }
19
+ return bundle === 'esm' ? '.mjs' : '.js';
20
+ }