@openrewrite/recipes-nodejs 0.51.0-20260922-170911 → 0.51.1
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/migrate/angular-animations/remove-angular-animations-providers.js +7 -7
- package/dist/migrate/angular-animations/remove-angular-animations-providers.js.map +1 -1
- package/dist/migrate/express-request-id/migrate-express-request-id-to-native.d.ts.map +1 -1
- package/dist/migrate/express-request-id/migrate-express-request-id-to-native.js +3 -2
- package/dist/migrate/express-request-id/migrate-express-request-id-to-native.js.map +1 -1
- package/dist/migrate/express-request-id/remove-unused-express-request-id-dependency.d.ts +3 -6
- package/dist/migrate/express-request-id/remove-unused-express-request-id-dependency.d.ts.map +1 -1
- package/dist/migrate/express-request-id/remove-unused-express-request-id-dependency.js +5 -11
- package/dist/migrate/express-request-id/remove-unused-express-request-id-dependency.js.map +1 -1
- package/dist/migrate/find-process-assert.js +2 -2
- package/dist/migrate/find-process-assert.js.map +1 -1
- package/dist/migrate/fs-extra/migrate-fs-extra-to-node-fs.d.ts.map +1 -1
- package/dist/migrate/fs-extra/migrate-fs-extra-to-node-fs.js +4 -2
- package/dist/migrate/fs-extra/migrate-fs-extra-to-node-fs.js.map +1 -1
- package/dist/migrate/fs-extra/remove-unused-fs-extra-dependency.d.ts +4 -6
- package/dist/migrate/fs-extra/remove-unused-fs-extra-dependency.d.ts.map +1 -1
- package/dist/migrate/fs-extra/remove-unused-fs-extra-dependency.js +6 -14
- package/dist/migrate/fs-extra/remove-unused-fs-extra-dependency.js.map +1 -1
- package/dist/migrate/fs-extra/replace-fs-extra-native-methods.js +1 -1
- package/dist/migrate/fs-extra/replace-fs-extra-native-methods.js.map +1 -1
- package/dist/migrate/hpagent/migrate-hpagent-to-https-proxy-agent.d.ts.map +1 -1
- package/dist/migrate/hpagent/migrate-hpagent-to-https-proxy-agent.js +3 -7
- package/dist/migrate/hpagent/migrate-hpagent-to-https-proxy-agent.js.map +1 -1
- package/dist/migrate/hpagent/replace-hpagent.d.ts.map +1 -1
- package/dist/migrate/hpagent/replace-hpagent.js +68 -2
- package/dist/migrate/hpagent/replace-hpagent.js.map +1 -1
- package/dist/migrate/hpagent/swap-hpagent-dependency.d.ts +3 -15
- package/dist/migrate/hpagent/swap-hpagent-dependency.d.ts.map +1 -1
- package/dist/migrate/hpagent/swap-hpagent-dependency.js +11 -62
- package/dist/migrate/hpagent/swap-hpagent-dependency.js.map +1 -1
- package/dist/migrate/package-json-support.d.ts +6 -0
- package/dist/migrate/package-json-support.d.ts.map +1 -0
- package/dist/migrate/package-json-support.js +31 -0
- package/dist/migrate/package-json-support.js.map +1 -0
- package/dist/migrate/path/remove-path-dependency.js +8 -8
- package/dist/migrate/path/remove-path-dependency.js.map +1 -1
- package/dist/migrate/process-exit-code.js +3 -3
- package/dist/migrate/process-exit-code.js.map +1 -1
- package/dist/migrate/process-features-tls.js +1 -1
- package/dist/migrate/process-features-tls.js.map +1 -1
- package/dist/migrate/prop-types/remove-prop-types.js +8 -8
- package/dist/migrate/prop-types/remove-prop-types.js.map +1 -1
- package/dist/migrate/remove-dependencies.d.ts +6 -0
- package/dist/migrate/remove-dependencies.d.ts.map +1 -0
- package/dist/migrate/remove-dependencies.js +23 -0
- package/dist/migrate/remove-dependencies.js.map +1 -0
- package/dist/migrate/source-map-support/enable-source-maps-at-launch.d.ts +19 -0
- package/dist/migrate/source-map-support/enable-source-maps-at-launch.d.ts.map +1 -0
- package/dist/migrate/source-map-support/enable-source-maps-at-launch.js +311 -0
- package/dist/migrate/source-map-support/enable-source-maps-at-launch.js.map +1 -0
- package/dist/migrate/source-map-support/migrate-source-map-support-to-native.d.ts.map +1 -1
- package/dist/migrate/source-map-support/migrate-source-map-support-to-native.js +9 -4
- package/dist/migrate/source-map-support/migrate-source-map-support-to-native.js.map +1 -1
- package/dist/migrate/source-map-support/register-flag.d.ts +4 -0
- package/dist/migrate/source-map-support/register-flag.d.ts.map +1 -1
- package/dist/migrate/source-map-support/register-flag.js +35 -0
- package/dist/migrate/source-map-support/register-flag.js.map +1 -1
- package/dist/migrate/source-map-support/remove-unused-source-map-support-dependency.d.ts +3 -6
- package/dist/migrate/source-map-support/remove-unused-source-map-support-dependency.d.ts.map +1 -1
- package/dist/migrate/source-map-support/remove-unused-source-map-support-dependency.js +5 -12
- package/dist/migrate/source-map-support/remove-unused-source-map-support-dependency.js.map +1 -1
- package/dist/migrate/source-map-support/source-map-support-rewrites.d.ts.map +1 -1
- package/dist/migrate/source-map-support/source-map-support-rewrites.js +2 -0
- package/dist/migrate/source-map-support/source-map-support-rewrites.js.map +1 -1
- package/dist/migrate/upgrade-node-22.d.ts.map +1 -1
- package/dist/migrate/upgrade-node-22.js +2 -0
- package/dist/migrate/upgrade-node-22.js.map +1 -1
- package/dist/migrate/upgrade-node-24.d.ts.map +1 -1
- package/dist/migrate/upgrade-node-24.js +2 -0
- package/dist/migrate/upgrade-node-24.js.map +1 -1
- package/dist/resources/advisories-npm.csv +278 -20
- package/package.json +2 -2
- package/src/index.ts +2 -0
- package/src/migrate/angular-animations/remove-angular-animations-providers.ts +1 -1
- package/src/migrate/express-request-id/migrate-express-request-id-to-native.ts +3 -2
- package/src/migrate/express-request-id/remove-unused-express-request-id-dependency.ts +5 -13
- package/src/migrate/find-process-assert.ts +2 -2
- package/src/migrate/fs-extra/migrate-fs-extra-to-node-fs.ts +4 -2
- package/src/migrate/fs-extra/remove-unused-fs-extra-dependency.ts +6 -16
- package/src/migrate/fs-extra/replace-fs-extra-native-methods.ts +1 -1
- package/src/migrate/hpagent/migrate-hpagent-to-https-proxy-agent.ts +3 -7
- package/src/migrate/hpagent/replace-hpagent.ts +82 -3
- package/src/migrate/hpagent/swap-hpagent-dependency.ts +13 -68
- package/src/migrate/package-json-support.ts +34 -0
- package/src/migrate/path/remove-path-dependency.ts +1 -1
- package/src/migrate/process-exit-code.ts +3 -3
- package/src/migrate/process-features-tls.ts +1 -1
- package/src/migrate/prop-types/remove-prop-types.ts +1 -1
- package/src/migrate/remove-dependencies.ts +21 -0
- package/src/migrate/source-map-support/enable-source-maps-at-launch.ts +289 -0
- package/src/migrate/source-map-support/migrate-source-map-support-to-native.ts +9 -4
- package/src/migrate/source-map-support/register-flag.ts +48 -0
- package/src/migrate/source-map-support/remove-unused-source-map-support-dependency.ts +5 -14
- package/src/migrate/source-map-support/source-map-support-rewrites.ts +3 -0
- package/src/migrate/upgrade-node-22.ts +2 -0
- package/src/migrate/upgrade-node-24.ts +2 -0
- package/dist/migrate/remove-unused-dependency.d.ts +0 -43
- package/dist/migrate/remove-unused-dependency.d.ts.map +0 -1
- package/dist/migrate/remove-unused-dependency.js +0 -257
- package/dist/migrate/remove-unused-dependency.js.map +0 -1
- package/src/migrate/remove-unused-dependency.ts +0 -275
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 the original author or authors.
|
|
3
|
+
*
|
|
4
|
+
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {ExecutionContext, ScanningRecipe, Tree, TreeVisitor} from "@openrewrite/rewrite";
|
|
8
|
+
import {J} from "@openrewrite/rewrite/java";
|
|
9
|
+
import {JavaScriptVisitor, JS, maybeUnbind} from "@openrewrite/rewrite/javascript";
|
|
10
|
+
import {getMemberKeyName, isLiteral, isMember, isObject, Json, JsonVisitor} from "@openrewrite/rewrite/json";
|
|
11
|
+
import {PlainText} from "@openrewrite/rewrite/text";
|
|
12
|
+
import {dirOf, isPackageJson} from "../package-json-support";
|
|
13
|
+
import {addSourceMapsFlag, launchesNode, REGISTER_MODULES, shebangWithSourceMapsFlag} from "./register-flag";
|
|
14
|
+
import {isSourceMapSupport, SourceMapSupportVisitor, sourcePathOf, stringLiteral} from "./source-map-support-support";
|
|
15
|
+
|
|
16
|
+
interface Accumulator {
|
|
17
|
+
/** Files holding an `install()` or `register` entry point the in-place rewrite declines. */
|
|
18
|
+
declined: string[];
|
|
19
|
+
/** `bin` targets each `package.json` declares, as repo-relative paths. */
|
|
20
|
+
binTargets: string[];
|
|
21
|
+
/** Files whose shebang can carry Node's flags. */
|
|
22
|
+
rewritableShebangs: string[];
|
|
23
|
+
/** Packages with a script that runs Node directly, which can take the flag. */
|
|
24
|
+
launchableScripts: string[];
|
|
25
|
+
/** Every `package.json` directory, so a source can be attributed to its package. */
|
|
26
|
+
packageDirs: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The nearest enclosing directory that is a package, for a repo-relative path. */
|
|
30
|
+
function packageOf(path: string, packageDirs: string[]): string | undefined {
|
|
31
|
+
const candidates = packageDirs.filter(dir => dir === '' || path.startsWith(dir + '/'));
|
|
32
|
+
return candidates.sort((a, b) => b.length - a.length)[0];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function joinPath(dir: string, rest: string): string {
|
|
36
|
+
const normalized = rest.replace(/^\.\//, '');
|
|
37
|
+
return dir === '' ? normalized : `${dir}/${normalized}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class EnableSourceMapsAtLaunch extends ScanningRecipe<Accumulator> {
|
|
41
|
+
readonly name = "org.openrewrite.node.migrate.source-map-support.enable-source-maps-at-launch";
|
|
42
|
+
readonly displayName = "Enable native source maps at launch and drop `source-map-support`";
|
|
43
|
+
readonly description = "Where `source-map-support` is installed too late for `process.setSourceMapsEnabled(true)` " +
|
|
44
|
+
"to stand in for it — in an ES module, every `import` is evaluated before any statement runs, so the call " +
|
|
45
|
+
"would only map what loads after it — this puts `--enable-source-maps` on whatever launches the process " +
|
|
46
|
+
"instead, which Node applies before the first module loads. The flag goes into the package's `bin` shebang " +
|
|
47
|
+
"(as `#!/usr/bin/env -S node --enable-source-maps`) and into any `package.json` script that runs `node` or " +
|
|
48
|
+
"`mocha` directly. The `install()` call and `register` import are then redundant and are removed, rather " +
|
|
49
|
+
"than replaced by a call that would map less. A package with no launcher this recipe can reach is left " +
|
|
50
|
+
"alone and reported by `FindSourceMapSupportManualMigrations`.";
|
|
51
|
+
readonly tags = ["source-map-support"];
|
|
52
|
+
|
|
53
|
+
initialValue(_ctx: ExecutionContext): Accumulator {
|
|
54
|
+
return {declined: [], binTargets: [], rewritableShebangs: [], launchableScripts: [], packageDirs: []};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async scanner(acc: Accumulator): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
58
|
+
const js = new class extends SourceMapSupportVisitor<ExecutionContext> {
|
|
59
|
+
protected override async visitShebang(shebang: JS.Shebang, p: ExecutionContext): Promise<J | undefined> {
|
|
60
|
+
if (shebangWithSourceMapsFlag(shebang.text)) acc.rewritableShebangs.push(sourcePathOf(this.cursor));
|
|
61
|
+
return super.visitShebang(shebang, p);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected override async visitImportDeclaration(jsImport: JS.Import, p: ExecutionContext): Promise<J | undefined> {
|
|
65
|
+
if (!jsImport.importClause && REGISTER_MODULES.has(stringLiteral(jsImport.moduleSpecifier?.element) ?? '')) {
|
|
66
|
+
this.recordIfDeclined();
|
|
67
|
+
}
|
|
68
|
+
return super.visitImportDeclaration(jsImport, p);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
protected override async visitMethodInvocation(method: J.MethodInvocation, p: ExecutionContext): Promise<J | undefined> {
|
|
72
|
+
if (this.isInstall(method) || isRegisterRequire(method)) this.recordIfDeclined();
|
|
73
|
+
return super.visitMethodInvocation(method, p);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Only a site the in-place rewrite turns down is this recipe's business. */
|
|
77
|
+
private recordIfDeclined(): void {
|
|
78
|
+
if (this.mapsEverythingLoaded()) return;
|
|
79
|
+
const path = sourcePathOf(this.cursor);
|
|
80
|
+
if (!acc.declined.includes(path)) acc.declined.push(path);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const json = new class extends JsonVisitor<ExecutionContext> {
|
|
85
|
+
protected override async visitDocument(doc: Json.Document, p: ExecutionContext): Promise<Json | undefined> {
|
|
86
|
+
if (!isPackageJson(doc.sourcePath) || !isObject(doc.value)) return doc;
|
|
87
|
+
const dir = dirOf(doc.sourcePath);
|
|
88
|
+
if (!acc.packageDirs.includes(dir)) acc.packageDirs.push(dir);
|
|
89
|
+
const root = doc.value as Json.Object;
|
|
90
|
+
for (const padded of root.members) {
|
|
91
|
+
if (!isMember(padded.element)) continue;
|
|
92
|
+
const member = padded.element as Json.Member;
|
|
93
|
+
const key = getMemberKeyName(member) ?? '';
|
|
94
|
+
if (key === 'bin') {
|
|
95
|
+
for (const target of binTargetsOf(member.value)) acc.binTargets.push(joinPath(dir, target));
|
|
96
|
+
} else if (key === 'scripts' && isObject(member.value)) {
|
|
97
|
+
const launchable = (member.value as Json.Object).members.some(entry => {
|
|
98
|
+
if (!isMember(entry.element)) return false;
|
|
99
|
+
const value = (entry.element as Json.Member).value;
|
|
100
|
+
return isLiteral(value) && typeof value.value === 'string' && launchesNode(value.value);
|
|
101
|
+
});
|
|
102
|
+
if (launchable && !acc.launchableScripts.includes(dir)) acc.launchableScripts.push(dir);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return doc;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return new class extends TreeVisitor<Tree, ExecutionContext> {
|
|
110
|
+
protected override async accept(tree: Tree, p: ExecutionContext): Promise<Tree | undefined> {
|
|
111
|
+
if (tree.kind === JS.Kind.CompilationUnit) return js.visit(tree, p);
|
|
112
|
+
if (tree.kind === Json.Kind.Document) return json.visit(tree, p);
|
|
113
|
+
if (tree.kind === PlainText.Kind.PlainText) {
|
|
114
|
+
const text = tree as PlainText;
|
|
115
|
+
const first = text.text.split('\n', 1)[0];
|
|
116
|
+
if (shebangWithSourceMapsFlag(first)) acc.rewritableShebangs.push(text.sourcePath);
|
|
117
|
+
}
|
|
118
|
+
return tree;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async editorWithData(acc: Accumulator): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
124
|
+
const packageOfPath = (path: string) => enclosingPackage(path, acc.packageDirs);
|
|
125
|
+
|
|
126
|
+
// A package can take the flag if a script runs Node, or if a shebang this recipe can rewrite
|
|
127
|
+
// belongs to it — either the declining file's own or one its `bin` points at.
|
|
128
|
+
const shebangsFor = (dir: string) => acc.rewritableShebangs.filter(path =>
|
|
129
|
+
packageOfPath(path) === dir &&
|
|
130
|
+
(acc.declined.includes(path) || acc.binTargets.includes(path)));
|
|
131
|
+
|
|
132
|
+
const declinedPackages = new Set(acc.declined.map(packageOfPath));
|
|
133
|
+
const flagged = new Set([...declinedPackages].filter(dir =>
|
|
134
|
+
acc.launchableScripts.includes(dir) || shebangsFor(dir).length > 0));
|
|
135
|
+
|
|
136
|
+
const removeSites = new Set(acc.declined.filter(path => flagged.has(packageOfPath(path))));
|
|
137
|
+
const shebangsToFlag = new Set([...flagged].flatMap(shebangsFor));
|
|
138
|
+
// A shebang already puts the flag on the process this package launches, so its scripts —
|
|
139
|
+
// which may run unrelated tools — are left as they are.
|
|
140
|
+
const scriptPackages = new Set([...flagged].filter(dir => shebangsFor(dir).length === 0));
|
|
141
|
+
|
|
142
|
+
const js = new class extends JavaScriptVisitor<ExecutionContext> {
|
|
143
|
+
protected override async visitJsCompilationUnit(cu: JS.CompilationUnit, p: ExecutionContext): Promise<J | undefined> {
|
|
144
|
+
const flagShebang = shebangsToFlag.has(cu.sourcePath);
|
|
145
|
+
const removeHere = removeSites.has(cu.sourcePath);
|
|
146
|
+
if (!flagShebang && !removeHere) return cu;
|
|
147
|
+
|
|
148
|
+
let statements = cu.statements;
|
|
149
|
+
if (flagShebang) {
|
|
150
|
+
statements = statements.map(padded => {
|
|
151
|
+
if (padded.element.kind !== JS.Kind.Shebang) return padded;
|
|
152
|
+
const flagged = shebangWithSourceMapsFlag((padded.element as JS.Shebang).text);
|
|
153
|
+
return flagged ? {...padded, element: {...padded.element, text: flagged} as JS.Shebang} : padded;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (removeHere) {
|
|
157
|
+
statements = withoutStatements(statements, s => isRedundantEntryPoint(s));
|
|
158
|
+
}
|
|
159
|
+
const result = statements === cu.statements ? cu : {...cu, statements} as JS.CompilationUnit;
|
|
160
|
+
const visited = await super.visitJsCompilationUnit(result, p) as JS.CompilationUnit;
|
|
161
|
+
if (removeHere) {
|
|
162
|
+
// The launch flag covers the whole process, so nothing needs the module any more.
|
|
163
|
+
maybeUnbind(this, {module: 'source-map-support'});
|
|
164
|
+
maybeUnbind(this, {module: 'source-map-support', member: 'install'});
|
|
165
|
+
}
|
|
166
|
+
return visited;
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const json = new class extends JsonVisitor<ExecutionContext> {
|
|
171
|
+
protected override async visitDocument(doc: Json.Document, p: ExecutionContext): Promise<Json | undefined> {
|
|
172
|
+
if (!isPackageJson(doc.sourcePath) || !isObject(doc.value)) return doc;
|
|
173
|
+
if (!scriptPackages.has(dirOf(doc.sourcePath))) return doc;
|
|
174
|
+
const root = doc.value as Json.Object;
|
|
175
|
+
let changed = false;
|
|
176
|
+
const members = root.members.map(padded => {
|
|
177
|
+
if (!isMember(padded.element)) return padded;
|
|
178
|
+
const member = padded.element as Json.Member;
|
|
179
|
+
if (getMemberKeyName(member) !== 'scripts' || !isObject(member.value)) return padded;
|
|
180
|
+
const scripts = member.value as Json.Object;
|
|
181
|
+
let sectionChanged = false;
|
|
182
|
+
const entries = scripts.members.map(entry => {
|
|
183
|
+
if (!isMember(entry.element)) return entry;
|
|
184
|
+
const script = entry.element as Json.Member;
|
|
185
|
+
const value = script.value;
|
|
186
|
+
if (!isLiteral(value) || typeof value.value !== 'string') return entry;
|
|
187
|
+
const updated = addSourceMapsFlag(value.value);
|
|
188
|
+
if (updated === value.value) return entry;
|
|
189
|
+
sectionChanged = true;
|
|
190
|
+
return {
|
|
191
|
+
...entry,
|
|
192
|
+
element: {...script, value: {...value, value: updated, source: JSON.stringify(updated)}} as Json.Member
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
if (!sectionChanged) return padded;
|
|
196
|
+
changed = true;
|
|
197
|
+
return {...padded, element: {...member, value: {...scripts, members: entries}} as Json.Member};
|
|
198
|
+
});
|
|
199
|
+
return changed ? {...doc, value: {...root, members}} as Json.Document : doc;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return new class extends TreeVisitor<Tree, ExecutionContext> {
|
|
204
|
+
protected override async accept(tree: Tree, p: ExecutionContext): Promise<Tree | undefined> {
|
|
205
|
+
if (tree.kind === JS.Kind.CompilationUnit) return js.visit(tree, p);
|
|
206
|
+
if (tree.kind === Json.Kind.Document) return json.visit(tree, p);
|
|
207
|
+
if (tree.kind === PlainText.Kind.PlainText) {
|
|
208
|
+
const text = tree as PlainText;
|
|
209
|
+
if (!shebangsToFlag.has(text.sourcePath)) return tree;
|
|
210
|
+
const lines = text.text.split('\n');
|
|
211
|
+
const flagged = shebangWithSourceMapsFlag(lines[0]);
|
|
212
|
+
if (!flagged) return tree;
|
|
213
|
+
return {...text, text: [flagged, ...lines.slice(1)].join('\n')} as PlainText;
|
|
214
|
+
}
|
|
215
|
+
return tree;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Drops the statements `remove` selects, handing the first of a removed run its successor's place
|
|
223
|
+
* in the layout, so the blank line that separated it from what came before isn't left behind. Only
|
|
224
|
+
* the whitespace moves: a comment sits in the prefix of the statement it documents, so taking the
|
|
225
|
+
* successor's prefix wholesale would delete the comment that belongs to it.
|
|
226
|
+
*/
|
|
227
|
+
function withoutStatements(statements: J.RightPadded<any>[], remove: (s: J) => boolean): J.RightPadded<any>[] {
|
|
228
|
+
const kept: J.RightPadded<any>[] = [];
|
|
229
|
+
let pendingWhitespace: string | undefined;
|
|
230
|
+
for (const padded of statements) {
|
|
231
|
+
if (remove(padded.element)) {
|
|
232
|
+
pendingWhitespace ??= (padded.element.prefix as J.Space).whitespace;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
kept.push(pendingWhitespace === undefined ? padded : {
|
|
236
|
+
...padded,
|
|
237
|
+
element: {...padded.element, prefix: {...padded.element.prefix, whitespace: pendingWhitespace}}
|
|
238
|
+
});
|
|
239
|
+
pendingWhitespace = undefined;
|
|
240
|
+
}
|
|
241
|
+
return kept;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** The innermost package a repo-relative path belongs to, of those the scan saw. */
|
|
245
|
+
function enclosingPackage(path: string, packageDirs: string[]): string {
|
|
246
|
+
return packageOf(path, packageDirs) ?? '';
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** `require('source-map-support/register')`, which loads the module for its side effect alone. */
|
|
250
|
+
function isRegisterRequire(m: J.MethodInvocation): boolean {
|
|
251
|
+
return !m.select && m.name.simpleName === 'require' &&
|
|
252
|
+
REGISTER_MODULES.has(stringLiteral(m.arguments.elements[0]?.element) ?? '');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Whether a top-level statement exists only to install source-map-support. */
|
|
256
|
+
function isRedundantEntryPoint(statement: J): boolean {
|
|
257
|
+
if (statement.kind === JS.Kind.Import) {
|
|
258
|
+
const imp = statement as JS.Import;
|
|
259
|
+
return !imp.importClause && isSourceMapSupport(stringLiteral(imp.moduleSpecifier?.element));
|
|
260
|
+
}
|
|
261
|
+
const expression = statement.kind === JS.Kind.ExpressionStatement
|
|
262
|
+
? (statement as JS.ExpressionStatement).expression
|
|
263
|
+
: statement;
|
|
264
|
+
const call = expression?.kind === JS.Kind.Await ? (expression as JS.Await).expression : expression;
|
|
265
|
+
if (call?.kind !== J.Kind.MethodInvocation) return false;
|
|
266
|
+
const m = call as J.MethodInvocation;
|
|
267
|
+
if (isRegisterRequire(m)) return true;
|
|
268
|
+
if (m.name.simpleName !== 'install') return false;
|
|
269
|
+
const select = m.select?.element;
|
|
270
|
+
return select?.kind === J.Kind.MethodInvocation
|
|
271
|
+
? isSourceMapSupport(requiredModuleOf(select as J.MethodInvocation))
|
|
272
|
+
: select !== undefined;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function requiredModuleOf(m: J.MethodInvocation): string | undefined {
|
|
276
|
+
return !m.select && m.name.simpleName === 'require'
|
|
277
|
+
? stringLiteral(m.arguments.elements[0]?.element)
|
|
278
|
+
: undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function binTargetsOf(value: Json.Value): string[] {
|
|
282
|
+
if (isLiteral(value)) return typeof value.value === 'string' ? [value.value] : [];
|
|
283
|
+
if (!isObject(value)) return [];
|
|
284
|
+
return (value as Json.Object).members.flatMap(padded => {
|
|
285
|
+
if (!isMember(padded.element)) return [];
|
|
286
|
+
const entry = (padded.element as Json.Member).value;
|
|
287
|
+
return isLiteral(entry) && typeof entry.value === 'string' ? [entry.value] : [];
|
|
288
|
+
});
|
|
289
|
+
}
|
|
@@ -14,17 +14,22 @@ export class MigrateSourceMapSupportToNative extends Recipe {
|
|
|
14
14
|
readonly displayName = "Migrate `source-map-support` to Node.js native source maps";
|
|
15
15
|
readonly description = "Replaces the `source-map-support` package with Node.js's built-in source map support. " +
|
|
16
16
|
"Where Node is launched from `package.json` scripts or mocha/ava configuration, `source-map-support/register` becomes " +
|
|
17
|
-
"the `--enable-source-maps` flag; in code, `install()` and `register` imports become
|
|
17
|
+
"the `--enable-source-maps` flag; in code, `install()` and `register` imports become " +
|
|
18
|
+
"`process.setSourceMapsEnabled(true)` where that maps everything the module loads. Where it would not " +
|
|
19
|
+
"— in an ES module every `import` is evaluated before any statement runs — the flag goes on the " +
|
|
20
|
+
"launcher instead, in the package's `bin` shebang or a `node` script, and the entry point is removed " +
|
|
21
|
+
"as redundant. " +
|
|
18
22
|
"Uses with no native equivalent (custom `retrieveSourceMap`, browser bundles, webpack banners) are left in place, and " +
|
|
19
|
-
"the dependency is removed from each `package.json` that
|
|
20
|
-
"recorded in the `SourceMapSupportManualMigrationSteps` data table with a
|
|
23
|
+
"the dependency is removed from each `package.json` that declares it, with the lock file updated to match. " +
|
|
24
|
+
"Everything left in place is recorded in the `SourceMapSupportManualMigrationSteps` data table with a " +
|
|
25
|
+
"suggested replacement, and has to be migrated before building, since the dependency is removed regardless.";
|
|
21
26
|
readonly tags = ["source-map-support"];
|
|
22
27
|
|
|
23
28
|
async recipeList(): Promise<Recipe[]> {
|
|
24
29
|
return [
|
|
25
30
|
...sourceMapSupportRewriteRecipes(),
|
|
26
31
|
new FindSourceMapSupportManualMigrations(),
|
|
27
|
-
new RemoveUnusedSourceMapSupportDependency(
|
|
32
|
+
new RemoveUnusedSourceMapSupportDependency(),
|
|
28
33
|
];
|
|
29
34
|
}
|
|
30
35
|
}
|
|
@@ -30,6 +30,54 @@ function commandOf(segment: string): string | undefined {
|
|
|
30
30
|
return undefined;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/** A `#!/usr/bin/env node` line, which `env -S` lets carry Node's own flags. */
|
|
34
|
+
const SHEBANG = /^#!(\s*\S*\/env\s+)(-S\s+)?node(?=\s|$)(.*)$/;
|
|
35
|
+
|
|
36
|
+
const ENABLE_FLAG = '--enable-source-maps';
|
|
37
|
+
|
|
38
|
+
export function hasSourceMapsFlag(text: string): boolean {
|
|
39
|
+
return new RegExp(`(^|\\s)${ENABLE_FLAG}(\\s|$)`).test(text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Whether any part of a shell command launches this package's own code under Node. An inline
|
|
44
|
+
* `node -e` program and a `node_modules/...` entry point are Node processes too, but neither loads
|
|
45
|
+
* the module whose entry point is being removed, so neither is a launcher worth flagging.
|
|
46
|
+
*/
|
|
47
|
+
export function launchesNode(script: string): boolean {
|
|
48
|
+
return script.split(/(\s*(?:&&|\|\||;|\|)\s*)/).some((part, i) => {
|
|
49
|
+
if (i % 2 === 1 || !NODE_FLAG_COMMANDS.has(commandOf(part) ?? '')) return false;
|
|
50
|
+
if (/(^|\s)(?:-e|--eval|-p|--print)(?=\s|$)/.test(part)) return false;
|
|
51
|
+
return !/(^|\s)node_modules\//.test(part);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Adds `--enable-source-maps` to each part of a shell command that runs Node or mocha, so the flag
|
|
57
|
+
* is in place before any module loads. Parts running anything else are left alone, since a flag
|
|
58
|
+
* they don't recognize would fail them.
|
|
59
|
+
*/
|
|
60
|
+
export function addSourceMapsFlag(script: string): string {
|
|
61
|
+
const parts = script.split(/(\s*(?:&&|\|\||;|\|)\s*)/);
|
|
62
|
+
return parts.map((part, i) => {
|
|
63
|
+
if (i % 2 === 1 || !NODE_FLAG_COMMANDS.has(commandOf(part) ?? '') || hasSourceMapsFlag(part)) return part;
|
|
64
|
+
// Straight after the command, where Node's own flags have to sit: anything later is the script's.
|
|
65
|
+
return part.replace(/(^|\s)((?:\S*[\\/])?(?:node|mocha|_mocha))(?=\s|$)/, `$1$2 ${ENABLE_FLAG}`);
|
|
66
|
+
}).join('');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The shebang with `--enable-source-maps` added, or undefined where the line isn't a plain
|
|
71
|
+
* `env node` shebang. `env -S` is what allows an argument at all; without it the kernel hands
|
|
72
|
+
* `node --enable-source-maps` to `env` as a single program name.
|
|
73
|
+
*/
|
|
74
|
+
export function shebangWithSourceMapsFlag(line: string): string | undefined {
|
|
75
|
+
const match = SHEBANG.exec(line);
|
|
76
|
+
if (!match || hasSourceMapsFlag(line)) return undefined;
|
|
77
|
+
const [, env, dashS, rest] = match;
|
|
78
|
+
return `#!${env}${dashS ?? '-S '}node ${ENABLE_FLAG}${rest}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
33
81
|
/**
|
|
34
82
|
* Replaces `-r source-map-support/register` with `--enable-source-maps` in each part of a shell
|
|
35
83
|
* command that runs Node or mocha. Parts that run anything else are left alone, since a flag they
|
|
@@ -4,23 +4,14 @@
|
|
|
4
4
|
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {RemoveUnusedDependency} from "../remove-unused-dependency";
|
|
9
|
-
import {sourceMapSupportRewriteRecipes} from "./source-map-support-rewrites";
|
|
7
|
+
import {RemoveDependencies} from "../remove-dependencies";
|
|
10
8
|
|
|
11
|
-
export class RemoveUnusedSourceMapSupportDependency extends
|
|
9
|
+
export class RemoveUnusedSourceMapSupportDependency extends RemoveDependencies {
|
|
12
10
|
readonly name = "org.openrewrite.node.migrate.source-map-support.remove-unused-source-map-support-dependency";
|
|
13
|
-
readonly displayName = "Remove
|
|
14
|
-
readonly description = "Removes `source-map-support` and `@types/source-map-support` from each `package.json`
|
|
15
|
-
"
|
|
16
|
-
"configuration, or a `.mocharc`/`mocha.opts` file. A webpack banner that injects `require(\"source-map-support\")` " +
|
|
17
|
-
"into a bundle counts as a use. Lock files are not regenerated; run the package manager's install afterwards.";
|
|
11
|
+
readonly displayName = "Remove the `source-map-support` dependency";
|
|
12
|
+
readonly description = "Removes `source-map-support` and `@types/source-map-support` from each `package.json` " +
|
|
13
|
+
"that declares them, and updates the lock file to match.";
|
|
18
14
|
readonly tags = ["source-map-support"];
|
|
19
15
|
|
|
20
|
-
protected readonly module = 'source-map-support';
|
|
21
16
|
protected readonly packages = ['source-map-support', '@types/source-map-support'];
|
|
22
|
-
|
|
23
|
-
protected migrationRecipes(): Recipe[] {
|
|
24
|
-
return sourceMapSupportRewriteRecipes();
|
|
25
|
-
}
|
|
26
17
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {Recipe} from "@openrewrite/rewrite";
|
|
8
|
+
import {EnableSourceMapsAtLaunch} from "./enable-source-maps-at-launch";
|
|
8
9
|
import {ReplaceSourceMapSupportInstall} from "./replace-source-map-support-install";
|
|
9
10
|
import {ReplaceSourceMapSupportRegisterInPackageJson} from "./replace-source-map-support-register-in-package-json";
|
|
10
11
|
import {ReplaceSourceMapSupportRegisterInMochaConfig} from "./replace-source-map-support-register-in-mocha-config";
|
|
@@ -15,5 +16,7 @@ export function sourceMapSupportRewriteRecipes(): Recipe[] {
|
|
|
15
16
|
new ReplaceSourceMapSupportRegisterInPackageJson(),
|
|
16
17
|
new ReplaceSourceMapSupportRegisterInMochaConfig(),
|
|
17
18
|
new ReplaceSourceMapSupportInstall(),
|
|
19
|
+
// Last of the rewrites: it takes the entry points the in-place rewrite turned down.
|
|
20
|
+
new EnableSourceMapsAtLaunch(),
|
|
18
21
|
];
|
|
19
22
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
5
5
|
*/
|
|
6
6
|
import {Recipe} from "@openrewrite/rewrite";
|
|
7
|
+
import {prepareJavaRecipe} from "@openrewrite/rewrite/rpc";
|
|
7
8
|
import {RemovePromisifyOnPromise} from "./promisify-on-promise";
|
|
8
9
|
import {ReplaceIsWebAssemblyCompiledModule} from "./util-types-wasm";
|
|
9
10
|
import {ReplaceCryptoConstructors} from "./crypto-constructors";
|
|
@@ -48,6 +49,7 @@ export class UpgradeNode22 extends Recipe {
|
|
|
48
49
|
return [
|
|
49
50
|
new IncreaseNodeEngineVersion({version: "22"}),
|
|
50
51
|
new IncreaseNodeEngineVersionInGithubActions({version: "22"}),
|
|
52
|
+
await prepareJavaRecipe("org.openrewrite.nodejs.migrate.UpgradeNodeVersion", {version: "22"}),
|
|
51
53
|
...node22EolDeprecations,
|
|
52
54
|
...node22RuntimeDeprecations,
|
|
53
55
|
...olderDeprecations,
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
5
5
|
*/
|
|
6
6
|
import {Recipe} from "@openrewrite/rewrite";
|
|
7
|
+
import {prepareJavaRecipe} from "@openrewrite/rewrite/rpc";
|
|
7
8
|
import {ReplaceUtilLog} from "./util-log";
|
|
8
9
|
import {ReplaceZlibBytesRead} from "./zlib-bytes-read";
|
|
9
10
|
import {ReplaceCryptoFips} from "./crypto-fips";
|
|
@@ -43,6 +44,7 @@ export class UpgradeNode24 extends Recipe {
|
|
|
43
44
|
return [
|
|
44
45
|
new IncreaseNodeEngineVersion({version: "24"}),
|
|
45
46
|
new IncreaseNodeEngineVersionInGithubActions({version: "24"}),
|
|
47
|
+
await prepareJavaRecipe("org.openrewrite.nodejs.migrate.UpgradeNodeVersion", {version: "24"}),
|
|
46
48
|
new UpgradeNode22(),
|
|
47
49
|
...node24EolDeprecations,
|
|
48
50
|
...node24RuntimeDeprecations,
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { DataTable, ExecutionContext, Recipe, ScanningRecipe, TreeVisitor } from "@openrewrite/rewrite";
|
|
2
|
-
import { Json } from "@openrewrite/rewrite/json";
|
|
3
|
-
interface Accumulator {
|
|
4
|
-
referencingFiles: string[];
|
|
5
|
-
parsedFiles: string[];
|
|
6
|
-
replacementFiles: string[];
|
|
7
|
-
}
|
|
8
|
-
export declare class DependencyKept {
|
|
9
|
-
sourcePath: string;
|
|
10
|
-
recipe: string;
|
|
11
|
-
package: string;
|
|
12
|
-
reason: string;
|
|
13
|
-
evidence: string;
|
|
14
|
-
}
|
|
15
|
-
export declare function dependenciesKept(): DataTable<DependencyKept>;
|
|
16
|
-
export declare const KEPT_REASONS: {
|
|
17
|
-
projen: (module: string) => string;
|
|
18
|
-
referenced: (module: string) => string;
|
|
19
|
-
unparsed: string;
|
|
20
|
-
};
|
|
21
|
-
export declare function dirOf(path: string): string;
|
|
22
|
-
export declare function isPackageJson(path: string): boolean;
|
|
23
|
-
export declare function anyBeneath(dir: string, files: string[]): boolean;
|
|
24
|
-
export declare function removeMembers(obj: Json.Object, keys: Set<string>): Json.Object;
|
|
25
|
-
export declare abstract class RemoveUnusedDependency extends ScanningRecipe<Accumulator> {
|
|
26
|
-
protected abstract readonly module: string;
|
|
27
|
-
protected abstract readonly packages: string[];
|
|
28
|
-
protected abstract migrationRecipes(): Recipe[];
|
|
29
|
-
protected replacementModules(): string[];
|
|
30
|
-
private readonly kept;
|
|
31
|
-
protected mockFile(): RegExp;
|
|
32
|
-
private readonly precedingRecipes;
|
|
33
|
-
accountForMigration?: boolean;
|
|
34
|
-
constructor(options?: {
|
|
35
|
-
precedingRecipes?: Recipe[];
|
|
36
|
-
accountForMigration?: boolean;
|
|
37
|
-
});
|
|
38
|
-
initialValue(_ctx: ExecutionContext): Accumulator;
|
|
39
|
-
scanner(acc: Accumulator): Promise<TreeVisitor<any, ExecutionContext>>;
|
|
40
|
-
editorWithData(acc: Accumulator): Promise<TreeVisitor<any, ExecutionContext>>;
|
|
41
|
-
}
|
|
42
|
-
export {};
|
|
43
|
-
//# sourceMappingURL=remove-unused-dependency.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remove-unused-dependency.d.ts","sourceRoot":"","sources":["../../src/migrate/remove-unused-dependency.ts"],"names":[],"mappings":"AAMA,OAAO,EAAS,SAAS,EAAgB,gBAAgB,EAAoB,MAAM,EAAE,cAAc,EAAkC,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAC9K,OAAO,EAAuC,IAAI,EAAkC,MAAM,2BAA2B,CAAC;AAkBtH,UAAU,WAAW;IACjB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,qBAAa,cAAc;IAEvB,UAAU,EAAG,MAAM,CAAC;IAGpB,MAAM,EAAG,MAAM,CAAC;IAGhB,OAAO,EAAG,MAAM,CAAC;IAGjB,MAAM,EAAG,MAAM,CAAC;IAGhB,QAAQ,EAAG,MAAM,CAAC;CACrB;AAED,wBAAgB,gBAAgB,IAAI,SAAS,CAAC,cAAc,CAAC,CAO5D;AAED,eAAO,MAAM,YAAY;qBACJ,MAAM;yBAIF,MAAM;;CAK9B,CAAC;AAEF,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG1C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAEhE;AAkBD,wBAAgB,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAU9E;AAkCD,8BAAsB,sBAAuB,SAAQ,cAAc,CAAC,WAAW,CAAC;IAE5E,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAG3C,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAG/C,SAAS,CAAC,QAAQ,CAAC,gBAAgB,IAAI,MAAM,EAAE;IAO/C,SAAS,CAAC,kBAAkB,IAAI,MAAM,EAAE;IAIxC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;IAG3C,SAAS,CAAC,QAAQ,IAAI,MAAM;IAQ5B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAW;IAQ5C,mBAAmB,CAAC,EAAE,OAAO,CAAC;gBAElB,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAAE;IAKpF,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,WAAW;IAI3C,OAAO,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAwCtE,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;CA0CtF"}
|