@jcoreio/toolchain 5.9.0-beta.3 → 5.10.0
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/package.json +2 -1
- package/plugins/getConfigFiles.cjs +0 -3
- package/plugins/getEslintConfigs.cjs +14 -1
- package/scripts/migrate/migrateEslintEnvComments.cjs +118 -0
- package/scripts/migrate.cjs +2 -0
- package/util/addEslintConfigsCodemod.cjs +73 -0
- package/util/findUps.cjs +2 -1
- package/util/getBabelParseOpts.cjs +151 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jcoreio/toolchain",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.0",
|
|
4
4
|
"description": "base JS build toolchain",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@babel/generator": "^7.27.0",
|
|
18
18
|
"@babel/parser": "^7.27.0",
|
|
19
19
|
"@babel/template": "^7.27.0",
|
|
20
|
+
"@babel/traverse": "^7.26.4",
|
|
20
21
|
"@babel/types": "^7.27.0",
|
|
21
22
|
"@eslint/compat": "^1.2.8",
|
|
22
23
|
"@eslint/js": "^9.23.0",
|
|
@@ -48,7 +48,6 @@ module.exports = [
|
|
|
48
48
|
'toolchain.config.cjs': async (existing) => {
|
|
49
49
|
if (existing) return existing
|
|
50
50
|
return dedent`
|
|
51
|
-
/* eslint-env node, es2018 */
|
|
52
51
|
module.exports = {
|
|
53
52
|
buildIgnore: ${JSON.stringify(await initBuildIgnore(), null, 2)},
|
|
54
53
|
// scripts: {
|
|
@@ -69,7 +68,6 @@ module.exports = [
|
|
|
69
68
|
)
|
|
70
69
|
}
|
|
71
70
|
return dedent`
|
|
72
|
-
/* eslint-env node, es2018 */
|
|
73
71
|
const base = require('${name}/prettierConfig.cjs')
|
|
74
72
|
module.exports = {
|
|
75
73
|
...base,
|
|
@@ -84,7 +82,6 @@ module.exports = [
|
|
|
84
82
|
files[file] = async (existing) =>
|
|
85
83
|
existing && fromVersion ? existing : (
|
|
86
84
|
dedent`
|
|
87
|
-
/* eslint-env node, es2018 */
|
|
88
85
|
const base = require('${name}/${file}')
|
|
89
86
|
module.exports = {
|
|
90
87
|
...base,
|
|
@@ -6,6 +6,7 @@ const path = require('path')
|
|
|
6
6
|
const fs = require('../util/projectFs.cjs')
|
|
7
7
|
const { globSync } = require('../util/glob.cjs')
|
|
8
8
|
const execa = require('../util/execa.cjs')
|
|
9
|
+
const globals = require('globals')
|
|
9
10
|
|
|
10
11
|
module.exports = [
|
|
11
12
|
() => {
|
|
@@ -21,7 +22,8 @@ module.exports = [
|
|
|
21
22
|
if (globalGitignore && fs.pathExistsSync(globalGitignore)) {
|
|
22
23
|
gitignores.push(globalGitignore)
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
+
// eslint-disable-next-line no-unused-vars
|
|
26
|
+
} catch (err) {
|
|
25
27
|
// ignore
|
|
26
28
|
}
|
|
27
29
|
if (fs.pathExistsSync('.eslintignore')) {
|
|
@@ -75,6 +77,17 @@ module.exports = [
|
|
|
75
77
|
],
|
|
76
78
|
},
|
|
77
79
|
},
|
|
80
|
+
{
|
|
81
|
+
files: ['**/*.{js,cjs,mjs,ts,cts,mts}'],
|
|
82
|
+
ignores: ['src/**', 'test/**'],
|
|
83
|
+
languageOptions: {
|
|
84
|
+
ecmaVersion: 2018,
|
|
85
|
+
globals: {
|
|
86
|
+
...globals.es2018,
|
|
87
|
+
...globals.node,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
78
91
|
require('eslint-config-prettier'),
|
|
79
92
|
])
|
|
80
93
|
},
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const { gte } = require('semver')
|
|
2
|
+
|
|
3
|
+
async function migrateEslintEnvComments({ fromVersion }) {
|
|
4
|
+
// istanbul ignore next
|
|
5
|
+
if (fromVersion && gte(fromVersion, '5.10.0')) {
|
|
6
|
+
return
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const fs = require('../../util/projectFs.cjs')
|
|
10
|
+
const { glob } = require('../../util/glob.cjs')
|
|
11
|
+
const path = require('path')
|
|
12
|
+
const replaceRanges = require('../../util/replaceRanges.cjs')
|
|
13
|
+
const getBabelParseOpts = require('../../util/getBabelParseOpts.cjs')
|
|
14
|
+
const chalk = require('chalk')
|
|
15
|
+
const dedent = require('dedent-js')
|
|
16
|
+
const { parse } = require('@babel/parser')
|
|
17
|
+
|
|
18
|
+
/** env name -> array of paths from proj root to file */
|
|
19
|
+
const envFileMap = new Map()
|
|
20
|
+
const warnings = {}
|
|
21
|
+
for (const file of await glob('**/*.{js,jsx,cjs,mjs,ts,cts,mts,tsx}')) {
|
|
22
|
+
function warn(warning) {
|
|
23
|
+
;(warnings[file] || (warnings[file] = [])).push(warning)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const source = await fs.readFile(file, 'utf8')
|
|
27
|
+
let parsed
|
|
28
|
+
try {
|
|
29
|
+
parsed = parse(source, getBabelParseOpts(file))
|
|
30
|
+
} catch (error) {
|
|
31
|
+
warn(`parse error: ${error.message}`)
|
|
32
|
+
continue
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!parsed || !('comments' in parsed) || !Array.isArray(parsed.comments)) {
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const replacements = []
|
|
40
|
+
for (const comment of parsed.comments) {
|
|
41
|
+
const { start, end, value } = comment
|
|
42
|
+
const match = /^\s*eslint-env\s+(.*?)\s*$/.exec(value)
|
|
43
|
+
const envs = match ? match[1].split(/\s*,\s*/g) : undefined
|
|
44
|
+
if (envs == null) continue
|
|
45
|
+
replacements.push({ start, end, value: '' })
|
|
46
|
+
|
|
47
|
+
if (file.startsWith('src/') || file.startsWith('test/')) {
|
|
48
|
+
for (const env of envs) {
|
|
49
|
+
let group = envFileMap.get(env)
|
|
50
|
+
if (!group) envFileMap.set(env, (group = []))
|
|
51
|
+
group.push(file)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!replacements.length) continue
|
|
57
|
+
await fs.writeFile(file, replaceRanges(source, replacements), 'utf8')
|
|
58
|
+
// eslint-disable-next-line no-console
|
|
59
|
+
console.error(
|
|
60
|
+
`removed eslint-env comments from ${path.relative(process.cwd(), file)}`
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (warnings.length) {
|
|
65
|
+
for (const [file, fileWarnings] of Object.entries(warnings)) {
|
|
66
|
+
// eslint-disable-next-line no-console
|
|
67
|
+
console.warn(
|
|
68
|
+
chalk.yellow(
|
|
69
|
+
dedent`
|
|
70
|
+
WARNING: ${file} could not be completely migrated because of the following:
|
|
71
|
+
${fileWarnings.map((w) => `- ${w}`).join('\n ')}
|
|
72
|
+
|
|
73
|
+
`
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!envFileMap.size) return
|
|
79
|
+
|
|
80
|
+
const t = require('@babel/types')
|
|
81
|
+
const addEslintConfigsCodemod = require('../../util/addEslintConfigsCodemod.cjs')
|
|
82
|
+
|
|
83
|
+
const newConfigs = [...envFileMap].map(([env, files]) =>
|
|
84
|
+
t.objectExpression([
|
|
85
|
+
t.objectProperty(
|
|
86
|
+
t.identifier('files'),
|
|
87
|
+
t.arrayExpression(files.map((file) => t.stringLiteral(file)))
|
|
88
|
+
),
|
|
89
|
+
t.objectProperty(
|
|
90
|
+
t.identifier('languageOptions'),
|
|
91
|
+
t.objectExpression([
|
|
92
|
+
t.objectProperty(
|
|
93
|
+
t.identifier('globals'),
|
|
94
|
+
t.memberExpression(
|
|
95
|
+
t.identifier('globals'),
|
|
96
|
+
/^[_a-z$][_a-z0-9$]*$/.test(env) ?
|
|
97
|
+
t.identifier(env)
|
|
98
|
+
: t.stringLiteral(env)
|
|
99
|
+
)
|
|
100
|
+
),
|
|
101
|
+
])
|
|
102
|
+
),
|
|
103
|
+
])
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
await fs.writeFile(
|
|
107
|
+
'eslint.config.cjs',
|
|
108
|
+
await addEslintConfigsCodemod({
|
|
109
|
+
file: 'eslint.config.cjs',
|
|
110
|
+
source: await fs.readFile('eslint.config.cjs', 'utf8'),
|
|
111
|
+
configs: newConfigs,
|
|
112
|
+
requireGlobals: true,
|
|
113
|
+
}),
|
|
114
|
+
'utf8'
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports = migrateEslintEnvComments
|
package/scripts/migrate.cjs
CHANGED
|
@@ -14,6 +14,7 @@ async function migrate(args = []) {
|
|
|
14
14
|
const installGitHooks = require('./install-git-hooks.cjs')
|
|
15
15
|
const migrateProjectPackageJson = require('./migrate/migrateProjectPackageJson.cjs')
|
|
16
16
|
const migrateEslintConfigs = require('./migrate/migrateEslintConfigs.cjs')
|
|
17
|
+
const migrateEslintEnvComments = require('./migrate/migrateEslintEnvComments.cjs')
|
|
17
18
|
const migrateConfigFiles = require('./migrate/migrateConfigFiles.cjs')
|
|
18
19
|
const migrateMoveTypeDefs = require('./migrate/migrateMoveTypeDefs.cjs')
|
|
19
20
|
const migrateGitignore = require('./migrate/migrateGitignore.cjs')
|
|
@@ -32,6 +33,7 @@ async function migrate(args = []) {
|
|
|
32
33
|
}
|
|
33
34
|
await migrateConfigFiles({ fromVersion })
|
|
34
35
|
await migrateEslintConfigs({ fromVersion })
|
|
36
|
+
await migrateEslintEnvComments({ fromVersion })
|
|
35
37
|
if (!fromVersion) await migrateMoveTypeDefs()
|
|
36
38
|
await migrateGitignore({ fromVersion })
|
|
37
39
|
await getPluginsAsyncFunction('migrate')(args, { fromVersion })
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const traverse = require('@babel/traverse').default
|
|
2
|
+
const { generate } = require('@babel/generator')
|
|
3
|
+
const { parse } = require('@babel/parser')
|
|
4
|
+
const getBabelParseOpts = require('./getBabelParseOpts.cjs')
|
|
5
|
+
const { format } = require('prettier')
|
|
6
|
+
const prettierConfig = require('../prettierConfig.cjs')
|
|
7
|
+
const replaceRanges = require('./replaceRanges.cjs')
|
|
8
|
+
|
|
9
|
+
async function addEslintConfigsCodemod({
|
|
10
|
+
file,
|
|
11
|
+
source,
|
|
12
|
+
configs,
|
|
13
|
+
requireGlobals,
|
|
14
|
+
}) {
|
|
15
|
+
const ast = parse(source, getBabelParseOpts(file))
|
|
16
|
+
const replacements = []
|
|
17
|
+
|
|
18
|
+
let needsRequireGlobals = requireGlobals
|
|
19
|
+
|
|
20
|
+
traverse(ast, {
|
|
21
|
+
VariableDeclarator(path) {
|
|
22
|
+
const { id, init } = path.node
|
|
23
|
+
if (
|
|
24
|
+
id.type === 'Identifier' &&
|
|
25
|
+
id.name === 'globals' &&
|
|
26
|
+
init.type === 'CallExpression' &&
|
|
27
|
+
init.callee.type === 'Identifier' &&
|
|
28
|
+
init.callee.name === 'require' &&
|
|
29
|
+
init.arguments.length === 1 &&
|
|
30
|
+
init.arguments[0].type === 'StringLiteral' &&
|
|
31
|
+
init.arguments[0].value === 'globals'
|
|
32
|
+
) {
|
|
33
|
+
needsRequireGlobals = false
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
CallExpression(path) {
|
|
37
|
+
const { callee, arguments: args } = path.node
|
|
38
|
+
const arg0 = args ? args[0] : undefined
|
|
39
|
+
if (
|
|
40
|
+
callee.type !== 'Identifier' ||
|
|
41
|
+
callee.name !== 'defineConfig' ||
|
|
42
|
+
arg0 == null ||
|
|
43
|
+
arg0.type !== 'ArrayExpression'
|
|
44
|
+
) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const { start, end } = arg0
|
|
49
|
+
const needsComma = !/,\s*\]\s*$/.test(source.substring(start, end))
|
|
50
|
+
replacements.push({
|
|
51
|
+
start: end - 1,
|
|
52
|
+
end: end - 1,
|
|
53
|
+
value:
|
|
54
|
+
(needsComma ? ',' : '') +
|
|
55
|
+
configs.map((config) => generate(config).code).join(','),
|
|
56
|
+
})
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
if (needsRequireGlobals) {
|
|
61
|
+
replacements.push({
|
|
62
|
+
start: 0,
|
|
63
|
+
end: 0,
|
|
64
|
+
value: `const globals = require('globals')\n`,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return await format(replaceRanges(source, replacements), {
|
|
69
|
+
...prettierConfig,
|
|
70
|
+
parser: 'babel',
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
module.exports = addEslintConfigsCodemod
|
package/util/findUps.cjs
CHANGED
|
@@ -17,7 +17,8 @@ function matchNamedPackageJson(directory) {
|
|
|
17
17
|
try {
|
|
18
18
|
const json = fs.readJsonSync(Path.join(directory, 'package.json'))
|
|
19
19
|
if (json.name) return 'package.json'
|
|
20
|
-
|
|
20
|
+
// eslint-disable-next-line no-unused-vars
|
|
21
|
+
} catch (err) {
|
|
21
22
|
return undefined
|
|
22
23
|
}
|
|
23
24
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const commonPlugins = [
|
|
2
|
+
'asyncGenerators',
|
|
3
|
+
'bigInt',
|
|
4
|
+
'classProperties',
|
|
5
|
+
'classPrivateProperties',
|
|
6
|
+
'classPrivateMethods',
|
|
7
|
+
'classStaticBlock',
|
|
8
|
+
'functionSent',
|
|
9
|
+
'logicalAssignment',
|
|
10
|
+
'moduleStringNames',
|
|
11
|
+
'nullishCoalescingOperator',
|
|
12
|
+
'numericSeparator',
|
|
13
|
+
'objectRestSpread',
|
|
14
|
+
'optionalCatchBinding',
|
|
15
|
+
'optionalChaining',
|
|
16
|
+
'privateIn',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
const modulePlugins = [
|
|
20
|
+
'dynamicImport',
|
|
21
|
+
'exportNamespaceFrom',
|
|
22
|
+
'exportDefaultFrom',
|
|
23
|
+
'importMeta',
|
|
24
|
+
'topLevelAwait',
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
const babelParseOpts = {
|
|
28
|
+
js: {
|
|
29
|
+
sourceType: 'unambiguous',
|
|
30
|
+
allowImportExportEverywhere: true,
|
|
31
|
+
allowReturnOutsideFunction: true,
|
|
32
|
+
startLine: 1,
|
|
33
|
+
plugins: [
|
|
34
|
+
...commonPlugins,
|
|
35
|
+
...modulePlugins,
|
|
36
|
+
['flow', { all: true }],
|
|
37
|
+
'flowComments',
|
|
38
|
+
'jsx',
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
jsx: {
|
|
42
|
+
sourceType: 'unambiguous',
|
|
43
|
+
allowImportExportEverywhere: true,
|
|
44
|
+
allowReturnOutsideFunction: true,
|
|
45
|
+
startLine: 1,
|
|
46
|
+
plugins: [
|
|
47
|
+
...commonPlugins,
|
|
48
|
+
...modulePlugins,
|
|
49
|
+
['flow', { all: true }],
|
|
50
|
+
'flowComments',
|
|
51
|
+
'jsx',
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
cjs: {
|
|
55
|
+
sourceType: 'commonjs',
|
|
56
|
+
allowReturnOutsideFunction: true,
|
|
57
|
+
startLine: 1,
|
|
58
|
+
},
|
|
59
|
+
mjs: {
|
|
60
|
+
sourceType: 'module',
|
|
61
|
+
allowImportExportEverywhere: true,
|
|
62
|
+
allowReturnOutsideFunction: true,
|
|
63
|
+
startLine: 1,
|
|
64
|
+
plugins: [...commonPlugins, ...modulePlugins],
|
|
65
|
+
},
|
|
66
|
+
ts: {
|
|
67
|
+
sourceType: 'unambiguous',
|
|
68
|
+
allowImportExportEverywhere: true,
|
|
69
|
+
allowReturnOutsideFunction: true,
|
|
70
|
+
startLine: 1,
|
|
71
|
+
plugins: [
|
|
72
|
+
...commonPlugins,
|
|
73
|
+
...modulePlugins,
|
|
74
|
+
'typescript',
|
|
75
|
+
'decorators-legacy',
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
dts: {
|
|
79
|
+
sourceType: 'unambiguous',
|
|
80
|
+
allowImportExportEverywhere: true,
|
|
81
|
+
allowReturnOutsideFunction: true,
|
|
82
|
+
startLine: 1,
|
|
83
|
+
plugins: [
|
|
84
|
+
...commonPlugins,
|
|
85
|
+
...modulePlugins,
|
|
86
|
+
['typescript', { dts: true }],
|
|
87
|
+
'decorators-legacy',
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
tsx: {
|
|
91
|
+
sourceType: 'unambiguous',
|
|
92
|
+
allowImportExportEverywhere: true,
|
|
93
|
+
allowReturnOutsideFunction: true,
|
|
94
|
+
startLine: 1,
|
|
95
|
+
plugins: [
|
|
96
|
+
...commonPlugins,
|
|
97
|
+
...modulePlugins,
|
|
98
|
+
'jsx',
|
|
99
|
+
'typescript',
|
|
100
|
+
'decorators-legacy',
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
cts: {
|
|
104
|
+
sourceType: 'commonjs',
|
|
105
|
+
allowReturnOutsideFunction: true,
|
|
106
|
+
startLine: 1,
|
|
107
|
+
plugins: [...commonPlugins, 'typescript', 'decorators-legacy'],
|
|
108
|
+
},
|
|
109
|
+
dcts: {
|
|
110
|
+
sourceType: 'commonjs',
|
|
111
|
+
allowReturnOutsideFunction: true,
|
|
112
|
+
startLine: 1,
|
|
113
|
+
plugins: [
|
|
114
|
+
...commonPlugins,
|
|
115
|
+
['typescript', { dts: true }],
|
|
116
|
+
'decorators-legacy',
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
mts: {
|
|
120
|
+
sourceType: 'module',
|
|
121
|
+
allowImportExportEverywhere: true,
|
|
122
|
+
allowReturnOutsideFunction: true,
|
|
123
|
+
startLine: 1,
|
|
124
|
+
plugins: [
|
|
125
|
+
...commonPlugins,
|
|
126
|
+
...modulePlugins,
|
|
127
|
+
'typescript',
|
|
128
|
+
'decorators-legacy',
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
dmts: {
|
|
132
|
+
sourceType: 'module',
|
|
133
|
+
allowImportExportEverywhere: true,
|
|
134
|
+
allowReturnOutsideFunction: true,
|
|
135
|
+
startLine: 1,
|
|
136
|
+
plugins: [
|
|
137
|
+
...commonPlugins,
|
|
138
|
+
...modulePlugins,
|
|
139
|
+
['typescript', { dts: true }],
|
|
140
|
+
'decorators-legacy',
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function getBabelParseOpts(file) {
|
|
146
|
+
const match = /\.(js|cjs|mjs|jsx|(d\.)?(ts|cts|mts|tsx))$/i.exec(file)
|
|
147
|
+
const ext = (match ? match[0] : undefined) || 'js'
|
|
148
|
+
return babelParseOpts[ext]
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = getBabelParseOpts
|