@mui/internal-code-infra 0.0.2-canary.9 → 0.0.2

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/README.md CHANGED
@@ -1,3 +1,3 @@
1
1
  # @mui/internal-code-infra
2
2
 
3
- Build scripts and configs to be used across MUI repos.
3
+ Scripts and configs to be used across MUI repos.
@@ -1 +1,2 @@
1
+ #!/usr/bin/env node
1
2
  import '../src/cli/index.mjs';
package/package.json CHANGED
@@ -1,34 +1,44 @@
1
1
  {
2
2
  "name": "@mui/internal-code-infra",
3
- "version": "0.0.2-canary.9",
3
+ "version": "0.0.2",
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
- "@next/eslint-plugin-next": "^15.3.3",
23
+ "@argos-ci/core": "^4.1.0",
24
+ "@babel/cli": "^7.28.3",
25
+ "@babel/core": "^7.28.3",
26
+ "@babel/plugin-syntax-typescript": "^7.27.1",
27
+ "@babel/plugin-transform-runtime": "^7.28.3",
28
+ "@babel/preset-env": "^7.28.3",
29
+ "@babel/preset-react": "^7.27.1",
30
+ "@babel/preset-typescript": "^7.27.1",
31
+ "@eslint/compat": "^1.3.2",
32
+ "@eslint/js": "^9.34.0",
33
+ "@next/eslint-plugin-next": "^15.5.0",
26
34
  "@octokit/rest": "^22.0.0",
27
- "@eslint/compat": "^1.3.1",
28
- "chalk": "^5.4.1",
29
- "eslint-config-airbnb": "^19.0.4",
30
- "eslint-config-airbnb-base": "^15.0.0",
31
- "eslint-config-prettier": "^10.1.5",
35
+ "@pnpm/find-workspace-dir": "^1000.1.2",
36
+ "babel-plugin-optimize-clsx": "^2.6.2",
37
+ "babel-plugin-transform-inline-environment-variables": "^0.4.4",
38
+ "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
39
+ "babel-plugin-transform-remove-imports": "^1.8.0",
40
+ "chalk": "^5.6.0",
41
+ "eslint-config-prettier": "^10.1.8",
32
42
  "eslint-import-resolver-typescript": "^4.4.4",
33
43
  "eslint-module-utils": "^2.12.1",
34
44
  "eslint-plugin-import": "^2.32.0",
@@ -36,33 +46,42 @@
36
46
  "eslint-plugin-mocha": "^11.1.0",
37
47
  "eslint-plugin-react": "^7.37.5",
38
48
  "eslint-plugin-react-compiler": "^19.1.0-rc.2",
39
- "eslint-plugin-react-hooks": "^6.0.0-rc.1",
40
- "eslint-plugin-testing-library": "^7.5.3",
41
- "execa": "^7.2.0",
49
+ "eslint-plugin-react-hooks": "^6.0.0-rc1",
50
+ "eslint-plugin-testing-library": "^7.6.6",
51
+ "execa": "^9.6.0",
42
52
  "git-url-parse": "^16.1.0",
43
- "globals": "^16.2.0",
53
+ "globals": "^16.3.0",
44
54
  "globby": "^14.1.0",
55
+ "lodash-es": "^4.17.21",
45
56
  "minimatch": "^10.0.3",
46
57
  "semver": "^7.7.2",
47
- "typescript-eslint": "^8.35.1",
48
- "yargs": "^17.7.2"
58
+ "typescript-eslint": "^8.40.0",
59
+ "yargs": "^18.0.0",
60
+ "@mui/internal-babel-plugin-resolve-imports": "2.0.5",
61
+ "@mui/internal-babel-plugin-minify-errors": "2.0.6",
62
+ "@mui/internal-babel-plugin-display-name": "1.0.2"
49
63
  },
50
64
  "peerDependencies": {
51
65
  "eslint": "^9.0.0",
52
- "prettier": "^3.5.3"
66
+ "prettier": "^3.5.3",
67
+ "typescript": "^5.0.0"
53
68
  },
54
69
  "devDependencies": {
70
+ "@types/babel__core": "^7.20.5",
71
+ "@types/babel__preset-env": "^7.10.0",
55
72
  "@types/eslint-plugin-jsx-a11y": "^6.10.0",
56
73
  "@types/estree": "^1.0.8",
57
74
  "@types/estree-jsx": "^1.0.5",
75
+ "@types/lodash-es": "^4.17.12",
58
76
  "@types/yargs": "^17.0.33",
59
- "@typescript-eslint/parser": "^8.35.0",
60
- "@typescript-eslint/rule-tester": "^8.35.0",
61
- "eslint": "^9.29.0",
62
- "prettier": "^3.5.3",
63
- "typescript-eslint": "^8.35.0"
77
+ "@typescript-eslint/parser": "^8.40.0",
78
+ "@typescript-eslint/rule-tester": "^8.40.0",
79
+ "eslint": "^9.34.0",
80
+ "prettier": "^3.6.2",
81
+ "typescript-eslint": "^8.40.0"
64
82
  },
65
83
  "files": [
84
+ "bin",
66
85
  "build",
67
86
  "src",
68
87
  "README.md",
@@ -71,9 +90,9 @@
71
90
  "publishConfig": {
72
91
  "access": "public"
73
92
  },
74
- "gitSha": "7962728a775b7e763a195aef4b222d70cf47e478",
75
93
  "scripts": {
76
94
  "typescript": "tsc -p tsconfig.json",
77
- "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\""
78
97
  }
79
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,156 @@
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
+ preferLocal: true,
138
+ localDir: import.meta.dirname,
139
+ env: {
140
+ ...process.env,
141
+ ...env,
142
+ },
143
+ })`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'}`;
144
+
145
+ if (res.stderr) {
146
+ throw new Error(`Command: '${res.escapedCommand}' failed with \n${res.stderr}`);
147
+ }
148
+ if (verbose) {
149
+ console.log(`Command: '${res.escapedCommand}' succeeded with \n${res.stdout}`);
150
+ }
151
+
152
+ // cjs for reexporting from commons only modules.
153
+ // If we need to rely more on this we can think about setting up a separate commonjs => commonjs build for .cjs files to .cjs
154
+ // `--extensions-.cjs --out-file-extension .cjs`
155
+ await cjsCopy({ from: sourceDir, to: outDir });
156
+ }
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+
3
+ /* eslint-disable no-console */
4
+
5
+ import * as fs from 'node:fs/promises';
6
+ import * as os from 'node:os';
7
+ import * as path from 'node:path';
8
+ import { globby } from 'globby';
9
+ import { upload } from '@argos-ci/core';
10
+
11
+ /**
12
+ * @param {string} name
13
+ * @returns {string}
14
+ */
15
+ function requireEnv(name) {
16
+ const val = process.env[name];
17
+ if (!val) {
18
+ throw new Error(`Missing required env var: ${name}`);
19
+ }
20
+ return val;
21
+ }
22
+
23
+ /**
24
+ * Alternatve to `@argos-ci/cli` that can upload screenshots in batches.
25
+ */
26
+
27
+ const BATCH_SIZE = 200;
28
+
29
+ /**
30
+ * @typedef {Object} Args
31
+ * @property {boolean} [verbose] - Run with verbose logging
32
+ * @property {string} folder - Screenshots folder path
33
+ */
34
+
35
+ export default /** @type {import('yargs').CommandModule<{}, Args>} */ ({
36
+ command: 'argos-push',
37
+ describe: 'Upload screenshots to Argos CI in batches',
38
+ builder: (yargs) => {
39
+ return yargs
40
+ .option('folder', {
41
+ type: 'string',
42
+ demandOption: true,
43
+ description: 'Path to the screenshots folder',
44
+ })
45
+ .option('verbose', {
46
+ alias: 'v',
47
+ type: 'boolean',
48
+ default: false,
49
+ description: 'Run with verbose logging',
50
+ });
51
+ },
52
+ handler: async (argv) => {
53
+ const { folder, verbose = false } = argv;
54
+
55
+ const argosToken = requireEnv('ARGOS_TOKEN');
56
+ const circleSha1 = requireEnv('CIRCLE_SHA1');
57
+ const circleBranch = requireEnv('CIRCLE_BRANCH');
58
+ const circleBuildNum = requireEnv('CIRCLE_BUILD_NUM');
59
+
60
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'argos-screenshots-'));
61
+
62
+ try {
63
+ const screenshots = await globby(`${folder}/**/*`, {
64
+ onlyFiles: true,
65
+ });
66
+
67
+ console.log(`Found ${screenshots.length} screenshots.`);
68
+ if (verbose) {
69
+ console.log('Screenshots found:');
70
+ screenshots.forEach((screenshot) => {
71
+ console.log(` - ${screenshot}`);
72
+ });
73
+ }
74
+
75
+ const batches = [];
76
+ for (let i = 0; i < screenshots.length; i += BATCH_SIZE) {
77
+ batches.push(screenshots.slice(i, i + BATCH_SIZE));
78
+ }
79
+
80
+ await Promise.all(
81
+ batches.map((screenshotBatch, batchIndex) =>
82
+ Promise.all(
83
+ screenshotBatch.map(async (screenshot) => {
84
+ const relativePath = path.relative(folder, screenshot);
85
+ const targetPath = path.join(tempDir, `${batchIndex}`, relativePath);
86
+ const targetDir = path.dirname(targetPath);
87
+
88
+ await fs.mkdir(targetDir, { recursive: true });
89
+ await fs.copyFile(screenshot, targetPath);
90
+ }),
91
+ ),
92
+ ),
93
+ );
94
+
95
+ for (let i = 0; i < batches.length; i += 1) {
96
+ // eslint-disable-next-line no-await-in-loop
97
+ const result = await upload({
98
+ root: `${tempDir}/${i}`,
99
+ commit: circleSha1,
100
+ branch: circleBranch,
101
+ token: argosToken,
102
+ parallel: {
103
+ total: batches.length,
104
+ nonce: circleBuildNum,
105
+ },
106
+ });
107
+
108
+ console.log(
109
+ `Batch of ${batches[i].length} screenshots uploaded. Build URL: ${result.build.url}`,
110
+ );
111
+ }
112
+ } finally {
113
+ await fs.rm(tempDir, { recursive: true, force: true });
114
+ }
115
+ },
116
+ });