@openrewrite/recipes-nodejs 0.35.0-20251125-102139 → 0.35.0-20251125-132554

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 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAWpD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,cAAc,QAWhD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAYpD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,cAAc,QAYhD"}
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ const crypto_fips_1 = require("./migrate/crypto-fips");
11
11
  const slow_buffer_1 = require("./migrate/slow-buffer");
12
12
  const fs_access_constants_1 = require("./migrate/fs-access-constants");
13
13
  const promisify_on_promise_1 = require("./migrate/promisify-on-promise");
14
+ const process_exit_code_1 = require("./migrate/process-exit-code");
14
15
  function activate(registry) {
15
16
  registry.register(util_type_checking_1.UseNativeTypeCheckingMethods);
16
17
  registry.register(buffer_slice_1.ReplaceDeprecatedBufferSlice);
@@ -22,5 +23,6 @@ function activate(registry) {
22
23
  registry.register(slow_buffer_1.ReplaceSlowBuffer);
23
24
  registry.register(fs_access_constants_1.ReplaceFsAccessConstants);
24
25
  registry.register(promisify_on_promise_1.RemovePromisifyOnPromise);
26
+ registry.register(process_exit_code_1.AvoidImplicitCoercionOfExitCode);
25
27
  }
26
28
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAaA,4BAWC;AAxBD,qEAA0E;AAC1E,yDAAoE;AAEpE,yEAAwF;AACxF,uEAAwE;AACxE,iDAAkD;AAClD,uDAAwD;AACxD,uDAAwD;AACxD,uDAAwD;AACxD,uEAAuE;AACvE,yEAAwE;AAGxE,SAAgB,QAAQ,CAAC,QAAwB;IAC7C,QAAQ,CAAC,QAAQ,CAAC,iDAA4B,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,2CAA4B,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,+DAAwC,CAAC,CAAC;IAC5D,QAAQ,CAAC,QAAQ,CAAC,+CAAyB,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,yBAAc,CAAC,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,+BAAiB,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,+BAAiB,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,+BAAiB,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,8CAAwB,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,CAAC,+CAAwB,CAAC,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAcA,4BAYC;AA1BD,qEAA0E;AAC1E,yDAAoE;AAEpE,yEAAwF;AACxF,uEAAwE;AACxE,iDAAkD;AAClD,uDAAwD;AACxD,uDAAwD;AACxD,uDAAwD;AACxD,uEAAuE;AACvE,yEAAwE;AACxE,mEAA4E;AAG5E,SAAgB,QAAQ,CAAC,QAAwB;IAC7C,QAAQ,CAAC,QAAQ,CAAC,iDAA4B,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,2CAA4B,CAAC,CAAC;IAChD,QAAQ,CAAC,QAAQ,CAAC,+DAAwC,CAAC,CAAC;IAC5D,QAAQ,CAAC,QAAQ,CAAC,+CAAyB,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,yBAAc,CAAC,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,+BAAiB,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,+BAAiB,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,+BAAiB,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,8CAAwB,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,CAAC,+CAAwB,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,CAAC,mDAA+B,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { ExecutionContext, Recipe, TreeVisitor } from "@openrewrite/rewrite";
2
+ export declare class AvoidImplicitCoercionOfExitCode extends Recipe {
3
+ readonly name = "org.openrewrite.node.migrate.process.coerce-process-exit-code";
4
+ readonly displayName: string;
5
+ readonly description: string;
6
+ readonly tags: string[];
7
+ editor(): Promise<TreeVisitor<any, ExecutionContext>>;
8
+ }
9
+ //# sourceMappingURL=process-exit-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-exit-code.d.ts","sourceRoot":"","sources":["../../src/migrate/process-exit-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,gBAAgB,EAAgB,MAAM,EAAE,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAQvG,qBAAa,+BAAgC,SAAQ,MAAM;IACvD,QAAQ,CAAC,IAAI,mEAAkE;IAC/E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAA+D;IAC3F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAC2E;IACvG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAe;IAEhC,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;CAmH9D"}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AvoidImplicitCoercionOfExitCode = void 0;
13
+ const rewrite_1 = require("@openrewrite/rewrite");
14
+ const javascript_1 = require("@openrewrite/rewrite/javascript");
15
+ const java_1 = require("@openrewrite/rewrite/java");
16
+ class AvoidImplicitCoercionOfExitCode extends rewrite_1.Recipe {
17
+ constructor() {
18
+ super(...arguments);
19
+ this.name = "org.openrewrite.node.migrate.process.coerce-process-exit-code";
20
+ this.displayName = "Coerce `process.exit()` and `process.exitCode` to integer";
21
+ this.description = "Wraps non-integer values passed to `process.exit()` or assigned to `process.exitCode` " +
22
+ "with `Math.trunc()` to avoid the DEP0164 deprecation warning about implicit coercion to integer.";
23
+ this.tags = ["DEP0164"];
24
+ }
25
+ editor() {
26
+ return __awaiter(this, void 0, void 0, function* () {
27
+ return new class extends javascript_1.JavaScriptVisitor {
28
+ constructor() {
29
+ super(...arguments);
30
+ this.exitMatcher = new javascript_1.MethodMatcher("Process exit(..)");
31
+ }
32
+ isProcessExitCodeAccess(fieldAccess) {
33
+ if (fieldAccess.name.element.simpleName !== "exitCode") {
34
+ return false;
35
+ }
36
+ if (fieldAccess.target.kind === java_1.J.Kind.Identifier) {
37
+ const identifier = fieldAccess.target;
38
+ const idType = identifier.type;
39
+ if ((idType === null || idType === void 0 ? void 0 : idType.kind) === java_1.Type.Kind.Class) {
40
+ const classType = idType;
41
+ return classType.fullyQualifiedName === "global.NodeJS.Process";
42
+ }
43
+ }
44
+ return false;
45
+ }
46
+ needsCoercion(expr) {
47
+ const exprType = expr.type;
48
+ if (!exprType || exprType.kind !== java_1.Type.Kind.Primitive) {
49
+ return true;
50
+ }
51
+ if (expr.kind == java_1.J.Kind.Literal && exprType == java_1.Type.Primitive.Double) {
52
+ const literal = expr;
53
+ if (literal.value === Math.trunc(Number(literal.value))) {
54
+ return false;
55
+ }
56
+ }
57
+ return true;
58
+ }
59
+ convertToIntExpression(expr) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ var _a, _b;
62
+ if (((_a = expr.type) === null || _a === void 0 ? void 0 : _a.kind) == java_1.Type.Kind.Primitive && expr.type == java_1.Type.Primitive.String) {
63
+ if (expr.kind === java_1.J.Kind.Literal) {
64
+ const literal = expr;
65
+ if (literal && Number.isInteger(Number(literal.value))) {
66
+ const numberValue = Number(literal.value);
67
+ return (yield (0, rewrite_1.produceAsync)(literal, (draft) => __awaiter(this, void 0, void 0, function* () {
68
+ draft.value = numberValue;
69
+ draft.valueSource = (numberValue).toString();
70
+ })));
71
+ }
72
+ else {
73
+ const justZero = yield (0, javascript_1.template) `0`.apply(expr, this.cursor);
74
+ return (yield (0, rewrite_1.produceAsync)(justZero, (draft) => __awaiter(this, void 0, void 0, function* () {
75
+ var _a;
76
+ draft.prefix.comments.push({
77
+ kind: java_1.J.Kind.TextComment,
78
+ multiline: true,
79
+ text: ((_a = literal.value) !== null && _a !== void 0 ? _a : "").toString(),
80
+ suffix: " ",
81
+ markers: rewrite_1.emptyMarkers
82
+ });
83
+ })));
84
+ }
85
+ }
86
+ }
87
+ if (((_b = expr.type) === null || _b === void 0 ? void 0 : _b.kind) == java_1.Type.Kind.Primitive && expr.type == java_1.Type.Primitive.Boolean) {
88
+ const ret = (yield (0, javascript_1.template) `${expr} ? 1 : 0`.apply(expr, this.cursor));
89
+ return (yield (0, rewrite_1.produceAsync)(ret, (draft) => __awaiter(this, void 0, void 0, function* () {
90
+ draft.prefix.whitespace = "";
91
+ })));
92
+ }
93
+ const wrapped = yield (0, javascript_1.template) `Math.trunc(${expr})`.apply(expr, this.cursor);
94
+ return (yield (0, rewrite_1.produceAsync)(wrapped, (draft) => __awaiter(this, void 0, void 0, function* () {
95
+ draft.prefix.whitespace = "";
96
+ })));
97
+ });
98
+ }
99
+ visitMethodInvocation(method, p) {
100
+ const _super = Object.create(null, {
101
+ visitMethodInvocation: { get: () => super.visitMethodInvocation }
102
+ });
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ const m = yield _super.visitMethodInvocation.call(this, method, p);
105
+ if (this.exitMatcher.matches(m.methodType)) {
106
+ const args = m.arguments.elements;
107
+ if (args.length === 1) {
108
+ const arg = args[0].element;
109
+ if (this.needsCoercion(arg)) {
110
+ const replacement = yield this.convertToIntExpression(m.arguments.elements[0].element);
111
+ return (0, rewrite_1.produceAsync)(m, (draft) => __awaiter(this, void 0, void 0, function* () {
112
+ draft.arguments.elements[0].element = replacement;
113
+ }));
114
+ }
115
+ }
116
+ }
117
+ return m;
118
+ });
119
+ }
120
+ visitAssignment(assignment, p) {
121
+ const _super = Object.create(null, {
122
+ visitAssignment: { get: () => super.visitAssignment }
123
+ });
124
+ return __awaiter(this, void 0, void 0, function* () {
125
+ const assign = yield _super.visitAssignment.call(this, assignment, p);
126
+ if (assign.variable.kind === java_1.J.Kind.FieldAccess) {
127
+ const fieldAccess = assign.variable;
128
+ if (this.isProcessExitCodeAccess(fieldAccess)) {
129
+ const value = assign.assignment.element;
130
+ if (this.needsCoercion(value)) {
131
+ const replacement = yield this.convertToIntExpression(assign.assignment.element);
132
+ return (0, rewrite_1.produceAsync)(assign, (draft) => __awaiter(this, void 0, void 0, function* () {
133
+ draft.assignment.element = replacement;
134
+ }));
135
+ }
136
+ }
137
+ }
138
+ return assign;
139
+ });
140
+ }
141
+ };
142
+ });
143
+ }
144
+ }
145
+ exports.AvoidImplicitCoercionOfExitCode = AvoidImplicitCoercionOfExitCode;
146
+ //# sourceMappingURL=process-exit-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-exit-code.js","sourceRoot":"","sources":["../../src/migrate/process-exit-code.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,kDAAuG;AACvG,gEAA2F;AAC3F,oDAA2E;AAM3E,MAAa,+BAAgC,SAAQ,gBAAM;IAA3D;;QACa,SAAI,GAAG,+DAA+D,CAAA;QACtE,gBAAW,GAAW,2DAA2D,CAAC;QAClF,gBAAW,GAAW,wFAAwF;YACnH,kGAAkG,CAAC;QAC9F,SAAI,GAAa,CAAC,SAAS,CAAC,CAAC;IAqH1C,CAAC;IAnHS,MAAM;;YACR,OAAO,IAAI,KAAM,SAAQ,8BAAmC;gBAAjD;;oBACP,gBAAW,GAAG,IAAI,0BAAa,CAAC,kBAAkB,CAAC,CAAC;gBA+GxD,CAAC;gBA7GW,uBAAuB,CAAC,WAA0B;oBACtD,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;wBACrD,OAAO,KAAK,CAAC;oBACjB,CAAC;oBAED,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,KAAK,QAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;wBAChD,MAAM,UAAU,GAAG,WAAW,CAAC,MAAsB,CAAC;wBACtD,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC;wBAE/B,IAAI,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,MAAK,WAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;4BACnC,MAAM,SAAS,GAAG,MAAoB,CAAC;4BACvC,OAAO,SAAS,CAAC,kBAAkB,KAAK,uBAAuB,CAAC;wBACpE,CAAC;oBACL,CAAC;oBAED,OAAO,KAAK,CAAC;gBACjB,CAAC;gBAEO,aAAa,CAAC,IAAgB;oBAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;oBAC3B,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;wBACrD,OAAO,IAAI,CAAC;oBAChB,CAAC;oBACD,IAAI,IAAI,CAAC,IAAI,IAAI,QAAC,CAAC,IAAI,CAAC,OAAO,IAAI,QAAQ,IAAI,WAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;wBACnE,MAAM,OAAO,GAAG,IAAiB,CAAC;wBAClC,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BACtD,OAAO,KAAK,CAAC;wBACjB,CAAC;oBACL,CAAC;oBACD,OAAO,IAAI,CAAC;gBAChB,CAAC;gBAEa,sBAAsB,CAAC,IAAgB;;;wBACjD,IAAI,CAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,IAAI,KAAI,WAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,IAAI,WAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;4BAC/E,IAAI,IAAI,CAAC,IAAI,KAAK,QAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gCAC/B,MAAM,OAAO,GAAG,IAAiB,CAAC;gCAClC,IAAI,OAAO,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oCACrD,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;oCAC1C,OAAO,CAAC,MAAM,IAAA,sBAAY,EAAC,OAAO,EAAE,CAAM,KAAK,EAAC,EAAE;wCAC/C,KAAK,CAAC,KAAK,GAAG,WAAW,CAAC;wCAC1B,KAAK,CAAC,WAAW,GAAG,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;oCAChD,CAAC,CAAA,CAAC,CAAE,CAAC;gCACT,CAAC;qCAAM,CAAC;oCACJ,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAQ,EAAA,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAuB,CAAC;oCAClF,OAAO,CAAC,MAAM,IAAA,sBAAY,EAAC,QAAQ,EAAE,CAAM,KAAK,EAAC,EAAE;;wCAC/C,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;4CACvB,IAAI,EAAE,QAAC,CAAC,IAAI,CAAC,WAAW;4CACxB,SAAS,EAAE,IAAI;4CACf,IAAI,EAAE,CAAC,MAAA,OAAO,CAAC,KAAK,mCAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;4CACtC,MAAM,EAAE,GAAG;4CACX,OAAO,EAAE,sBAAY;yCACa,CAAC,CAAC;oCAC5C,CAAC,CAAA,CAAC,CAAE,CAAC;gCACT,CAAC;4BACL,CAAC;wBACL,CAAC;wBACD,IAAI,CAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,IAAI,KAAI,WAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,IAAI,WAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;4BAChF,MAAM,GAAG,GAAG,CAAC,MAAM,IAAA,qBAAQ,EAAA,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAE,CAAC;4BAExE,OAAO,CAAC,MAAM,IAAA,sBAAY,EAAC,GAAG,EAAE,CAAM,KAAK,EAAC,EAAE;gCAC1C,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC;4BACjC,CAAC,CAAA,CAAC,CAAE,CAAC;wBACT,CAAC;wBAED,MAAM,OAAO,GAAG,MAAM,IAAA,qBAAQ,EAAA,cAAc,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAuB,CAAC;wBAEnG,OAAO,CAAC,MAAM,IAAA,sBAAY,EAAC,OAAO,EAAE,CAAM,KAAK,EAAC,EAAE;4BAC/C,KAAK,CAAC,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC;wBAChC,CAAC,CAAA,CAAC,CAAE,CAAC;oBACT,CAAC;iBAAA;gBAEe,qBAAqB,CAAC,MAA0B,EAAE,CAAmB;;;;;wBACjF,MAAM,CAAC,GAAG,MAAM,OAAM,qBAAqB,YAAC,MAAM,EAAE,CAAC,CAAuB,CAAC;wBAE7E,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC;4BACzC,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC;4BAClC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gCACpB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,OAAqB,CAAC;gCAC1C,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;oCAC1B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;oCACvF,OAAO,IAAA,sBAAY,EAAC,CAAC,EAAE,CAAM,KAAK,EAAC,EAAE;wCACjC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,WAAW,CAAC;oCACtD,CAAC,CAAA,CAAC,CAAC;gCACP,CAAC;4BACL,CAAC;wBACL,CAAC;wBAED,OAAO,CAAC,CAAC;oBACb,CAAC;iBAAA;gBAEe,eAAe,CAAC,UAAwB,EAAE,CAAmB;;;;;wBACzE,MAAM,MAAM,GAAG,MAAM,OAAM,eAAe,YAAC,UAAU,EAAE,CAAC,CAAiB,CAAC;wBAE1E,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;4BAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,QAAyB,CAAC;4BAErD,IAAI,IAAI,CAAC,uBAAuB,CAAC,WAAW,CAAC,EAAE,CAAC;gCAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,OAAqB,CAAC;gCACtD,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;oCAC5B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;oCACjF,OAAO,IAAA,sBAAY,EAAC,MAAM,EAAE,CAAM,KAAK,EAAC,EAAE;wCACtC,KAAK,CAAC,UAAU,CAAC,OAAO,GAAG,WAAW,CAAC;oCAC3C,CAAC,CAAA,CAAC,CAAC;gCACP,CAAC;4BACL,CAAC;wBACL,CAAC;wBAED,OAAO,MAAM,CAAC;oBAClB,CAAC;iBAAA;aACJ,CAAC;QACN,CAAC;KAAA;CACJ;AA1HD,0EA0HC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openrewrite/recipes-nodejs",
3
- "version": "0.35.0-20251125-102139",
3
+ "version": "0.35.0-20251125-132554",
4
4
  "license": "Moderne Source Available License",
5
5
  "description": "OpenRewrite recipes for Node.js library migrations.",
6
6
  "homepage": "https://github.com/moderneinc/rewrite-node",
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import {ReplaceCryptoFips} from "./migrate/crypto-fips";
9
9
  import {ReplaceSlowBuffer} from "./migrate/slow-buffer";
10
10
  import {ReplaceFsAccessConstants} from "./migrate/fs-access-constants";
11
11
  import {RemovePromisifyOnPromise} from "./migrate/promisify-on-promise";
12
+ import {AvoidImplicitCoercionOfExitCode} from "./migrate/process-exit-code";
12
13
 
13
14
 
14
15
  export function activate(registry: RecipeRegistry) {
@@ -22,4 +23,5 @@ export function activate(registry: RecipeRegistry) {
22
23
  registry.register(ReplaceSlowBuffer);
23
24
  registry.register(ReplaceFsAccessConstants);
24
25
  registry.register(RemovePromisifyOnPromise);
26
+ registry.register(AvoidImplicitCoercionOfExitCode);
25
27
  }
@@ -0,0 +1,131 @@
1
+ import {emptyMarkers, ExecutionContext, produceAsync, Recipe, TreeVisitor} from "@openrewrite/rewrite";
2
+ import {JavaScriptVisitor, MethodMatcher, template} from "@openrewrite/rewrite/javascript";
3
+ import {Expression, J, TextComment, Type} from "@openrewrite/rewrite/java";
4
+
5
+
6
+ /**
7
+ * Wrap non-integer exit codes with Math.trunc() to avoid DEP0164 deprecation warning.
8
+ */
9
+ export class AvoidImplicitCoercionOfExitCode extends Recipe {
10
+ readonly name = "org.openrewrite.node.migrate.process.coerce-process-exit-code"
11
+ readonly displayName: string = "Coerce `process.exit()` and `process.exitCode` to integer";
12
+ readonly description: string = "Wraps non-integer values passed to `process.exit()` or assigned to `process.exitCode` " +
13
+ "with `Math.trunc()` to avoid the DEP0164 deprecation warning about implicit coercion to integer.";
14
+ readonly tags: string[] = ["DEP0164"];
15
+
16
+ async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
17
+ return new class extends JavaScriptVisitor<ExecutionContext> {
18
+ exitMatcher = new MethodMatcher("Process exit(..)");
19
+
20
+ private isProcessExitCodeAccess(fieldAccess: J.FieldAccess): boolean {
21
+ if (fieldAccess.name.element.simpleName !== "exitCode") {
22
+ return false;
23
+ }
24
+
25
+ if (fieldAccess.target.kind === J.Kind.Identifier) {
26
+ const identifier = fieldAccess.target as J.Identifier;
27
+ const idType = identifier.type;
28
+
29
+ if (idType?.kind === Type.Kind.Class) {
30
+ const classType = idType as Type.Class;
31
+ return classType.fullyQualifiedName === "global.NodeJS.Process";
32
+ }
33
+ }
34
+
35
+ return false;
36
+ }
37
+
38
+ private needsCoercion(expr: Expression): boolean {
39
+ const exprType = expr.type;
40
+ if (!exprType || exprType.kind !== Type.Kind.Primitive) {
41
+ return true;
42
+ }
43
+ if (expr.kind == J.Kind.Literal && exprType == Type.Primitive.Double) {
44
+ const literal = expr as J.Literal;
45
+ if (literal.value === Math.trunc(Number(literal.value))) {
46
+ return false;
47
+ }
48
+ }
49
+ return true;
50
+ }
51
+
52
+ private async convertToIntExpression(expr: Expression): Promise<Expression> {
53
+ if (expr.type?.kind == Type.Kind.Primitive && expr.type == Type.Primitive.String) {
54
+ if (expr.kind === J.Kind.Literal) {
55
+ const literal = expr as J.Literal;
56
+ if (literal && Number.isInteger(Number(literal.value))) {
57
+ const numberValue = Number(literal.value);
58
+ return (await produceAsync(literal, async draft => {
59
+ draft.value = numberValue;
60
+ draft.valueSource = (numberValue).toString();
61
+ }))!;
62
+ } else {
63
+ const justZero = await template`0`.apply(expr, this.cursor) as J.MethodInvocation;
64
+ return (await produceAsync(justZero, async draft => {
65
+ draft.prefix.comments.push({
66
+ kind: J.Kind.TextComment,
67
+ multiline: true,
68
+ text: (literal.value ?? "").toString(),
69
+ suffix: " ",
70
+ markers: emptyMarkers
71
+ } satisfies TextComment as TextComment);
72
+ }))!;
73
+ }
74
+ }
75
+ }
76
+ if (expr.type?.kind == Type.Kind.Primitive && expr.type == Type.Primitive.Boolean) {
77
+ const ret = (await template`${expr} ? 1 : 0`.apply(expr, this.cursor))!;
78
+ // TODO this is some upstream minor problem with formatting/prefixes, somehow a newline is added before
79
+ return (await produceAsync(ret, async draft => {
80
+ draft.prefix.whitespace = "";
81
+ }))!;
82
+ }
83
+
84
+ const wrapped = await template`Math.trunc(${expr})`.apply(expr, this.cursor) as J.MethodInvocation;
85
+ // TODO this is some upstream minor problem with formatting/prefixes, somehow a newline is added before
86
+ return (await produceAsync(wrapped, async draft => {
87
+ draft.prefix.whitespace = "";
88
+ }))!;
89
+ }
90
+
91
+ protected async visitMethodInvocation(method: J.MethodInvocation, p: ExecutionContext): Promise<J | undefined> {
92
+ const m = await super.visitMethodInvocation(method, p) as J.MethodInvocation;
93
+
94
+ if (this.exitMatcher.matches(m.methodType)) {
95
+ const args = m.arguments.elements;
96
+ if (args.length === 1) {
97
+ const arg = args[0].element as Expression;
98
+ if (this.needsCoercion(arg)) {
99
+ const replacement = await this.convertToIntExpression(m.arguments.elements[0].element);
100
+ return produceAsync(m, async draft => {
101
+ draft.arguments.elements[0].element = replacement;
102
+ });
103
+ }
104
+ }
105
+ }
106
+
107
+ return m;
108
+ }
109
+
110
+ protected async visitAssignment(assignment: J.Assignment, p: ExecutionContext): Promise<J | undefined> {
111
+ const assign = await super.visitAssignment(assignment, p) as J.Assignment;
112
+
113
+ if (assign.variable.kind === J.Kind.FieldAccess) {
114
+ const fieldAccess = assign.variable as J.FieldAccess;
115
+
116
+ if (this.isProcessExitCodeAccess(fieldAccess)) {
117
+ const value = assign.assignment.element as Expression;
118
+ if (this.needsCoercion(value)) {
119
+ const replacement = await this.convertToIntExpression(assign.assignment.element);
120
+ return produceAsync(assign, async draft => {
121
+ draft.assignment.element = replacement;
122
+ });
123
+ }
124
+ }
125
+ }
126
+
127
+ return assign;
128
+ }
129
+ };
130
+ }
131
+ }