@openrewrite/recipes-angular 1.9.0 → 1.10.0-20260813-195315
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 +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +84 -2
- package/dist/index.js.map +1 -1
- package/dist/migration/add-eager-change-detection.d.ts +8 -0
- package/dist/migration/add-eager-change-detection.d.ts.map +1 -0
- package/dist/migration/add-eager-change-detection.js +130 -0
- package/dist/migration/add-eager-change-detection.js.map +1 -0
- package/dist/migration/add-istanbul-instrumenter.d.ts +8 -0
- package/dist/migration/add-istanbul-instrumenter.d.ts.map +1 -0
- package/dist/migration/add-istanbul-instrumenter.js +80 -0
- package/dist/migration/add-istanbul-instrumenter.js.map +1 -0
- package/dist/migration/add-no-incremental-hydration.d.ts +8 -0
- package/dist/migration/add-no-incremental-hydration.d.ts.map +1 -0
- package/dist/migration/add-no-incremental-hydration.js +69 -0
- package/dist/migration/add-no-incremental-hydration.js.map +1 -0
- package/dist/migration/add-strict-templates-false.d.ts +8 -0
- package/dist/migration/add-strict-templates-false.d.ts.map +1 -0
- package/dist/migration/add-strict-templates-false.js +84 -0
- package/dist/migration/add-strict-templates-false.js.map +1 -0
- package/dist/migration/add-trust-proxy-headers.d.ts +8 -0
- package/dist/migration/add-trust-proxy-headers.d.ts.map +1 -0
- package/dist/migration/add-trust-proxy-headers.js +82 -0
- package/dist/migration/add-trust-proxy-headers.js.map +1 -0
- package/dist/migration/add-with-xhr.d.ts +8 -0
- package/dist/migration/add-with-xhr.d.ts.map +1 -0
- package/dist/migration/add-with-xhr.js +70 -0
- package/dist/migration/add-with-xhr.js.map +1 -0
- package/dist/migration/js-support.d.ts +6 -0
- package/dist/migration/js-support.d.ts.map +1 -0
- package/dist/migration/js-support.js +94 -0
- package/dist/migration/js-support.js.map +1 -0
- package/dist/migration/json-support.d.ts +19 -0
- package/dist/migration/json-support.d.ts.map +1 -0
- package/dist/migration/json-support.js +117 -0
- package/dist/migration/json-support.js.map +1 -0
- package/dist/migration/migrate-input-to-signal.d.ts.map +1 -1
- package/dist/migration/migrate-input-to-signal.js +3 -67
- package/dist/migration/migrate-input-to-signal.js.map +1 -1
- package/dist/migration/migrate-model-with-output.d.ts +8 -0
- package/dist/migration/migrate-model-with-output.d.ts.map +1 -0
- package/dist/migration/migrate-model-with-output.js +192 -0
- package/dist/migration/migrate-model-with-output.js.map +1 -0
- package/dist/migration/remove-with-fetch.d.ts +8 -0
- package/dist/migration/remove-with-fetch.d.ts.map +1 -0
- package/dist/migration/remove-with-fetch.js +73 -0
- package/dist/migration/remove-with-fetch.js.map +1 -0
- package/dist/migration/rename-angular-js-globals.d.ts +8 -0
- package/dist/migration/rename-angular-js-globals.d.ts.map +1 -0
- package/dist/migration/rename-angular-js-globals.js +56 -0
- package/dist/migration/rename-angular-js-globals.js.map +1 -0
- package/dist/migration/rename-default-change-detection.d.ts +8 -0
- package/dist/migration/rename-default-change-detection.d.ts.map +1 -0
- package/dist/migration/rename-default-change-detection.js +52 -0
- package/dist/migration/rename-default-change-detection.js.map +1 -0
- package/dist/migration/rename-ssr-experimental-platform.d.ts +8 -0
- package/dist/migration/rename-ssr-experimental-platform.d.ts.map +1 -0
- package/dist/migration/rename-ssr-experimental-platform.js +124 -0
- package/dist/migration/rename-ssr-experimental-platform.js.map +1 -0
- package/dist/migration/replace-create-ng-module-ref.d.ts +8 -0
- package/dist/migration/replace-create-ng-module-ref.d.ts.map +1 -0
- package/dist/migration/replace-create-ng-module-ref.js +51 -0
- package/dist/migration/replace-create-ng-module-ref.js.map +1 -0
- package/dist/migration/suppress-safe-navigation-diagnostics.d.ts +8 -0
- package/dist/migration/suppress-safe-navigation-diagnostics.d.ts.map +1 -0
- package/dist/migration/suppress-safe-navigation-diagnostics.js +55 -0
- package/dist/migration/suppress-safe-navigation-diagnostics.js.map +1 -0
- package/dist/migration/upgrade-to-angular-22.d.ts +14 -0
- package/dist/migration/upgrade-to-angular-22.d.ts.map +1 -0
- package/dist/migration/upgrade-to-angular-22.js +112 -0
- package/dist/migration/upgrade-to-angular-22.js.map +1 -0
- package/dist/search/find-can-match-usage.d.ts +8 -0
- package/dist/search/find-can-match-usage.d.ts.map +1 -0
- package/dist/search/find-can-match-usage.js +53 -0
- package/dist/search/find-can-match-usage.js.map +1 -0
- package/dist/search/find-check-no-changes-usage.d.ts +8 -0
- package/dist/search/find-check-no-changes-usage.d.ts.map +1 -0
- package/dist/search/find-check-no-changes-usage.js +50 -0
- package/dist/search/find-check-no-changes-usage.js.map +1 -0
- package/dist/search/find-http-xhr-backend-usage.d.ts +8 -0
- package/dist/search/find-http-xhr-backend-usage.d.ts.map +1 -0
- package/dist/search/find-http-xhr-backend-usage.js +65 -0
- package/dist/search/find-http-xhr-backend-usage.js.map +1 -0
- package/dist/search/find-implicit-params-inheritance.d.ts +8 -0
- package/dist/search/find-implicit-params-inheritance.d.ts.map +1 -0
- package/dist/search/find-implicit-params-inheritance.js +74 -0
- package/dist/search/find-implicit-params-inheritance.js.map +1 -0
- package/dist/search/find-provide-routes-usage.d.ts +8 -0
- package/dist/search/find-provide-routes-usage.d.ts.map +1 -0
- package/dist/search/find-provide-routes-usage.js +64 -0
- package/dist/search/find-provide-routes-usage.js.map +1 -0
- package/dist/search/find-template-safe-navigation.d.ts +8 -0
- package/dist/search/find-template-safe-navigation.d.ts.map +1 -0
- package/dist/search/find-template-safe-navigation.js +105 -0
- package/dist/search/find-template-safe-navigation.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +60 -0
- package/src/migration/add-eager-change-detection.ts +109 -0
- package/src/migration/add-istanbul-instrumenter.ts +62 -0
- package/src/migration/add-no-incremental-hydration.ts +49 -0
- package/src/migration/add-strict-templates-false.ts +62 -0
- package/src/migration/add-trust-proxy-headers.ts +61 -0
- package/src/migration/add-with-xhr.ts +50 -0
- package/src/migration/js-support.ts +92 -0
- package/src/migration/json-support.ts +119 -0
- package/src/migration/migrate-input-to-signal.ts +1 -67
- package/src/migration/migrate-model-with-output.ts +201 -0
- package/src/migration/remove-with-fetch.ts +53 -0
- package/src/migration/rename-angular-js-globals.ts +37 -0
- package/src/migration/rename-default-change-detection.ts +33 -0
- package/src/migration/rename-ssr-experimental-platform.ts +108 -0
- package/src/migration/replace-create-ng-module-ref.ts +32 -0
- package/src/migration/suppress-safe-navigation-diagnostics.ts +42 -0
- package/src/migration/upgrade-to-angular-22.ts +92 -0
- package/src/search/find-can-match-usage.ts +32 -0
- package/src/search/find-check-no-changes-usage.ts +29 -0
- package/src/search/find-http-xhr-backend-usage.ts +44 -0
- package/src/search/find-implicit-params-inheritance.ts +49 -0
- package/src/search/find-provide-routes-usage.ts +43 -0
- package/src/search/find-template-safe-navigation.ts +72 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026 the original author or authors.
|
|
4
|
+
*
|
|
5
|
+
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.FindHttpXhrBackendUsage = void 0;
|
|
18
|
+
const rewrite_1 = require("@openrewrite/rewrite");
|
|
19
|
+
const javascript_1 = require("@openrewrite/rewrite/javascript");
|
|
20
|
+
const java_1 = require("@openrewrite/rewrite/java");
|
|
21
|
+
class FindHttpXhrBackendUsage extends rewrite_1.Recipe {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(...arguments);
|
|
24
|
+
this.name = "org.openrewrite.angular.search.find-http-xhr-backend-usage";
|
|
25
|
+
this.displayName = "Find `HttpXhrBackend` usage";
|
|
26
|
+
this.description = "Finds imports of `HttpXhrBackend` from `@angular/common/http`. " +
|
|
27
|
+
"Angular 22 uses the Fetch API by default; add `withXhr()` to `provideHttpClient()` to keep using `XMLHttpRequest`, " +
|
|
28
|
+
"which is also required for upload progress reports.";
|
|
29
|
+
}
|
|
30
|
+
editor() {
|
|
31
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
return new class extends javascript_1.JavaScriptVisitor {
|
|
33
|
+
visitImportDeclaration(jsImport, p) {
|
|
34
|
+
const _super = Object.create(null, {
|
|
35
|
+
visitImportDeclaration: { get: () => super.visitImportDeclaration }
|
|
36
|
+
});
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
var _a;
|
|
39
|
+
const imp = yield _super.visitImportDeclaration.call(this, jsImport, p);
|
|
40
|
+
if (!imp.moduleSpecifier)
|
|
41
|
+
return imp;
|
|
42
|
+
const moduleSpec = imp.moduleSpecifier.element;
|
|
43
|
+
if (moduleSpec.kind !== java_1.J.Kind.Literal)
|
|
44
|
+
return imp;
|
|
45
|
+
if (moduleSpec.value !== '@angular/common/http')
|
|
46
|
+
return imp;
|
|
47
|
+
const namedBindings = (_a = imp.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings;
|
|
48
|
+
if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === javascript_1.JS.Kind.NamedImports) {
|
|
49
|
+
const named = namedBindings;
|
|
50
|
+
for (const specifier of named.elements.elements) {
|
|
51
|
+
const spec = specifier.element;
|
|
52
|
+
if ((0, java_1.isIdentifier)(spec.specifier) && spec.specifier.simpleName === 'HttpXhrBackend') {
|
|
53
|
+
return (0, rewrite_1.foundSearchResult)(imp, "HttpXhrBackend is no longer the default in Angular 22. Use provideHttpClient(withXhr()) to keep XMLHttpRequest based requests. See https://angular.dev/api/common/http/withXhr");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return imp;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.FindHttpXhrBackendUsage = FindHttpXhrBackendUsage;
|
|
65
|
+
//# sourceMappingURL=find-http-xhr-backend-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-http-xhr-backend-usage.js","sourceRoot":"","sources":["../../src/search/find-http-xhr-backend-usage.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;AAEH,kDAA8F;AAC9F,gEAAsE;AACtE,oDAA0D;AAE1D,MAAa,uBAAwB,SAAQ,gBAAM;IAAnD;;QACa,SAAI,GAAG,4DAA4D,CAAC;QACpE,gBAAW,GAAW,6BAA6B,CAAC;QACpD,gBAAW,GAAW,iEAAiE;YAC5F,qHAAqH;YACrH,qDAAqD,CAAC;IA4B9D,CAAC;IA1BS,MAAM;;YACR,OAAO,IAAI,KAAM,SAAQ,8BAAmC;gBACxC,sBAAsB,CAAC,QAAmB,EAAE,CAAmB;;;;;;wBAC3E,MAAM,GAAG,GAAG,MAAM,OAAM,sBAAsB,YAAC,QAAQ,EAAE,CAAC,CAAc,CAAC;wBACzE,IAAI,CAAC,GAAG,CAAC,eAAe;4BAAE,OAAO,GAAG,CAAC;wBAErC,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC;wBAC/C,IAAI,UAAU,CAAC,IAAI,KAAK,QAAC,CAAC,IAAI,CAAC,OAAO;4BAAE,OAAO,GAAG,CAAC;wBACnD,IAAK,UAAwB,CAAC,KAAK,KAAK,sBAAsB;4BAAE,OAAO,GAAG,CAAC;wBAE3E,MAAM,aAAa,GAAG,MAAA,GAAG,CAAC,YAAY,0CAAE,aAAa,CAAC;wBACtD,IAAI,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,IAAI,MAAK,eAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;4BAC/C,MAAM,KAAK,GAAG,aAAgC,CAAC;4BAC/C,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gCAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,OAA6B,CAAC;gCACrD,IAAI,IAAA,mBAAY,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,KAAK,gBAAgB,EAAE,CAAC;oCACjF,OAAO,IAAA,2BAAiB,EAAC,GAAG,EACxB,gLAAgL,CAAC,CAAC;gCAC1L,CAAC;4BACL,CAAC;wBACL,CAAC;wBAED,OAAO,GAAG,CAAC;oBACf,CAAC;iBAAA;aACJ,CAAC;QACN,CAAC;KAAA;CACJ;AAjCD,0DAiCC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ExecutionContext, Recipe, TreeVisitor } from "@openrewrite/rewrite";
|
|
2
|
+
export declare class FindImplicitParamsInheritance extends Recipe {
|
|
3
|
+
readonly name = "org.openrewrite.angular.search.find-implicit-params-inheritance";
|
|
4
|
+
readonly displayName: string;
|
|
5
|
+
readonly description: string;
|
|
6
|
+
editor(): Promise<TreeVisitor<any, ExecutionContext>>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=find-implicit-params-inheritance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-implicit-params-inheritance.d.ts","sourceRoot":"","sources":["../../src/search/find-implicit-params-inheritance.ts"],"names":[],"mappings":"AAMA,OAAO,EAAC,gBAAgB,EAAqB,MAAM,EAAE,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAI9F,qBAAa,6BAA8B,SAAQ,MAAM;IACrD,QAAQ,CAAC,IAAI,qEAAqE;IAClF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAkF;IAC9G,QAAQ,CAAC,WAAW,EAAE,MAAM,CAC8G;IAEpI,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;CAkB9D"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026 the original author or authors.
|
|
4
|
+
*
|
|
5
|
+
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.FindImplicitParamsInheritance = void 0;
|
|
18
|
+
const rewrite_1 = require("@openrewrite/rewrite");
|
|
19
|
+
const javascript_1 = require("@openrewrite/rewrite/javascript");
|
|
20
|
+
const java_1 = require("@openrewrite/rewrite/java");
|
|
21
|
+
class FindImplicitParamsInheritance extends rewrite_1.Recipe {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(...arguments);
|
|
24
|
+
this.name = "org.openrewrite.angular.search.find-implicit-params-inheritance";
|
|
25
|
+
this.displayName = "Find router configuration relying on the default `paramsInheritanceStrategy`";
|
|
26
|
+
this.description = "Finds `provideRouter()` and `RouterModule.forRoot()` calls that do not set `paramsInheritanceStrategy`. " +
|
|
27
|
+
"Angular 22 changed the default from `emptyOnly` to `always`, so route parameters and data are now inherited from all parent routes.";
|
|
28
|
+
}
|
|
29
|
+
editor() {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
return new class extends javascript_1.JavaScriptVisitor {
|
|
32
|
+
visitMethodInvocation(method, p) {
|
|
33
|
+
const _super = Object.create(null, {
|
|
34
|
+
visitMethodInvocation: { get: () => super.visitMethodInvocation }
|
|
35
|
+
});
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
const m = yield _super.visitMethodInvocation.call(this, method, p);
|
|
38
|
+
if (!m || !(0, java_1.isIdentifier)(m.name))
|
|
39
|
+
return m;
|
|
40
|
+
const isProvideRouter = !m.select && m.name.simpleName === 'provideRouter';
|
|
41
|
+
const isForRoot = m.name.simpleName === 'forRoot' &&
|
|
42
|
+
!!m.select && (0, java_1.isIdentifier)(m.select.element) && m.select.element.simpleName === 'RouterModule';
|
|
43
|
+
if (!isProvideRouter && !isForRoot)
|
|
44
|
+
return m;
|
|
45
|
+
if (yield declaresParamsInheritanceStrategy(m, p))
|
|
46
|
+
return m;
|
|
47
|
+
return (0, rewrite_1.foundSearchResult)(m, "paramsInheritanceStrategy defaults to 'always' as of Angular 22. Set it to 'emptyOnly' to keep the previous behavior.");
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.FindImplicitParamsInheritance = FindImplicitParamsInheritance;
|
|
55
|
+
function declaresParamsInheritanceStrategy(method, p) {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
var _a, _b;
|
|
58
|
+
let found = false;
|
|
59
|
+
const detector = new class extends javascript_1.JavaScriptVisitor {
|
|
60
|
+
visitIdentifier(identifier, ctx) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
if (identifier.simpleName === 'paramsInheritanceStrategy')
|
|
63
|
+
found = true;
|
|
64
|
+
return identifier;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}();
|
|
68
|
+
for (const element of (_b = (_a = method.arguments) === null || _a === void 0 ? void 0 : _a.elements) !== null && _b !== void 0 ? _b : []) {
|
|
69
|
+
yield detector.visit(element.element, p);
|
|
70
|
+
}
|
|
71
|
+
return found;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=find-implicit-params-inheritance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-implicit-params-inheritance.js","sourceRoot":"","sources":["../../src/search/find-implicit-params-inheritance.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;AAEH,kDAA8F;AAC9F,gEAAkE;AAClE,oDAA0D;AAE1D,MAAa,6BAA8B,SAAQ,gBAAM;IAAzD;;QACa,SAAI,GAAG,iEAAiE,CAAC;QACzE,gBAAW,GAAW,8EAA8E,CAAC;QACrG,gBAAW,GAAW,0GAA0G;YACrI,qIAAqI,CAAC;IAoB9I,CAAC;IAlBS,MAAM;;YACR,OAAO,IAAI,KAAM,SAAQ,8BAAmC;gBACzC,qBAAqB,CAAC,MAA0B,EAAE,CAAmB;;;;;wBAChF,MAAM,CAAC,GAAG,MAAM,OAAM,qBAAqB,YAAC,MAAM,EAAE,CAAC,CAAuB,CAAC;wBAC7E,IAAI,CAAC,CAAC,IAAI,CAAC,IAAA,mBAAY,EAAC,CAAC,CAAC,IAAI,CAAC;4BAAE,OAAO,CAAC,CAAC;wBAE1C,MAAM,eAAe,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,KAAK,eAAe,CAAC;wBAC3E,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS;4BAC7C,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,IAAA,mBAAY,EAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,KAAK,cAAc,CAAC;wBACnG,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS;4BAAE,OAAO,CAAC,CAAC;wBAE7C,IAAI,MAAM,iCAAiC,CAAC,CAAC,EAAE,CAAC,CAAC;4BAAE,OAAO,CAAC,CAAC;wBAE5D,OAAO,IAAA,2BAAiB,EAAC,CAAC,EACtB,uHAAuH,CAAC,CAAC;oBACjI,CAAC;iBAAA;aACJ,CAAC;QACN,CAAC;KAAA;CACJ;AAxBD,sEAwBC;AAED,SAAe,iCAAiC,CAAC,MAA0B,EAAE,CAAmB;;;QAC5F,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,MAAM,QAAQ,GAAG,IAAI,KAAM,SAAQ,8BAAmC;YACnD,eAAe,CAAC,UAAwB,EAAE,GAAqB;;oBAC1E,IAAI,UAAU,CAAC,UAAU,KAAK,2BAA2B;wBAAE,KAAK,GAAG,IAAI,CAAC;oBACxE,OAAO,UAAU,CAAC;gBACtB,CAAC;aAAA;SACJ,EAAE,CAAC;QACJ,KAAK,MAAM,OAAO,IAAI,MAAA,MAAA,MAAM,CAAC,SAAS,0CAAE,QAAQ,mCAAI,EAAE,EAAE,CAAC;YACrD,MAAM,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ExecutionContext, Recipe, TreeVisitor } from "@openrewrite/rewrite";
|
|
2
|
+
export declare class FindProvideRoutesUsage extends Recipe {
|
|
3
|
+
readonly name = "org.openrewrite.angular.search.find-provide-routes-usage";
|
|
4
|
+
readonly displayName: string;
|
|
5
|
+
readonly description: string;
|
|
6
|
+
editor(): Promise<TreeVisitor<any, ExecutionContext>>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=find-provide-routes-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-provide-routes-usage.d.ts","sourceRoot":"","sources":["../../src/search/find-provide-routes-usage.ts"],"names":[],"mappings":"AAMA,OAAO,EAAC,gBAAgB,EAAqB,MAAM,EAAE,WAAW,EAAC,MAAM,sBAAsB,CAAC;AAI9F,qBAAa,sBAAuB,SAAQ,MAAM;IAC9C,QAAQ,CAAC,IAAI,8DAA8D;IAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAgC;IAC5D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAC+C;IAErE,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;CA0B9D"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026 the original author or authors.
|
|
4
|
+
*
|
|
5
|
+
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.FindProvideRoutesUsage = void 0;
|
|
18
|
+
const rewrite_1 = require("@openrewrite/rewrite");
|
|
19
|
+
const javascript_1 = require("@openrewrite/rewrite/javascript");
|
|
20
|
+
const java_1 = require("@openrewrite/rewrite/java");
|
|
21
|
+
class FindProvideRoutesUsage extends rewrite_1.Recipe {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(...arguments);
|
|
24
|
+
this.name = "org.openrewrite.angular.search.find-provide-routes-usage";
|
|
25
|
+
this.displayName = "Find `provideRoutes` usage";
|
|
26
|
+
this.description = "Finds imports of `provideRoutes` from `@angular/router`, which was removed in Angular 22. " +
|
|
27
|
+
"Use `provideRouter()`, or provide the `ROUTES` multi token directly.";
|
|
28
|
+
}
|
|
29
|
+
editor() {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
return new class extends javascript_1.JavaScriptVisitor {
|
|
32
|
+
visitImportDeclaration(jsImport, p) {
|
|
33
|
+
const _super = Object.create(null, {
|
|
34
|
+
visitImportDeclaration: { get: () => super.visitImportDeclaration }
|
|
35
|
+
});
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
var _a;
|
|
38
|
+
const imp = yield _super.visitImportDeclaration.call(this, jsImport, p);
|
|
39
|
+
if (!imp.moduleSpecifier)
|
|
40
|
+
return imp;
|
|
41
|
+
const moduleSpec = imp.moduleSpecifier.element;
|
|
42
|
+
if (moduleSpec.kind !== java_1.J.Kind.Literal)
|
|
43
|
+
return imp;
|
|
44
|
+
if (moduleSpec.value !== '@angular/router')
|
|
45
|
+
return imp;
|
|
46
|
+
const namedBindings = (_a = imp.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings;
|
|
47
|
+
if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === javascript_1.JS.Kind.NamedImports) {
|
|
48
|
+
const named = namedBindings;
|
|
49
|
+
for (const specifier of named.elements.elements) {
|
|
50
|
+
const spec = specifier.element;
|
|
51
|
+
if ((0, java_1.isIdentifier)(spec.specifier) && spec.specifier.simpleName === 'provideRoutes') {
|
|
52
|
+
return (0, rewrite_1.foundSearchResult)(imp, "provideRoutes() was removed in Angular 22. Use provideRouter(), or the ROUTES multi token if necessary.");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return imp;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.FindProvideRoutesUsage = FindProvideRoutesUsage;
|
|
64
|
+
//# sourceMappingURL=find-provide-routes-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-provide-routes-usage.js","sourceRoot":"","sources":["../../src/search/find-provide-routes-usage.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;AAEH,kDAA8F;AAC9F,gEAAsE;AACtE,oDAA0D;AAE1D,MAAa,sBAAuB,SAAQ,gBAAM;IAAlD;;QACa,SAAI,GAAG,0DAA0D,CAAC;QAClE,gBAAW,GAAW,4BAA4B,CAAC;QACnD,gBAAW,GAAW,4FAA4F;YACvH,sEAAsE,CAAC;IA4B/E,CAAC;IA1BS,MAAM;;YACR,OAAO,IAAI,KAAM,SAAQ,8BAAmC;gBACxC,sBAAsB,CAAC,QAAmB,EAAE,CAAmB;;;;;;wBAC3E,MAAM,GAAG,GAAG,MAAM,OAAM,sBAAsB,YAAC,QAAQ,EAAE,CAAC,CAAc,CAAC;wBACzE,IAAI,CAAC,GAAG,CAAC,eAAe;4BAAE,OAAO,GAAG,CAAC;wBAErC,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC;wBAC/C,IAAI,UAAU,CAAC,IAAI,KAAK,QAAC,CAAC,IAAI,CAAC,OAAO;4BAAE,OAAO,GAAG,CAAC;wBACnD,IAAK,UAAwB,CAAC,KAAK,KAAK,iBAAiB;4BAAE,OAAO,GAAG,CAAC;wBAEtE,MAAM,aAAa,GAAG,MAAA,GAAG,CAAC,YAAY,0CAAE,aAAa,CAAC;wBACtD,IAAI,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,IAAI,MAAK,eAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;4BAC/C,MAAM,KAAK,GAAG,aAAgC,CAAC;4BAC/C,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gCAC9C,MAAM,IAAI,GAAG,SAAS,CAAC,OAA6B,CAAC;gCACrD,IAAI,IAAA,mBAAY,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,KAAK,eAAe,EAAE,CAAC;oCAChF,OAAO,IAAA,2BAAiB,EAAC,GAAG,EACxB,yGAAyG,CAAC,CAAC;gCACnH,CAAC;4BACL,CAAC;wBACL,CAAC;wBAED,OAAO,GAAG,CAAC;oBACf,CAAC;iBAAA;aACJ,CAAC;QACN,CAAC;KAAA;CACJ;AAhCD,wDAgCC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Recipe } from "@openrewrite/rewrite";
|
|
2
|
+
export declare class FindTemplateSafeNavigation extends Recipe {
|
|
3
|
+
readonly name = "org.openrewrite.angular.search.find-template-safe-navigation";
|
|
4
|
+
readonly displayName: string;
|
|
5
|
+
readonly description: string;
|
|
6
|
+
recipeList(): Promise<Recipe[]>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=find-template-safe-navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-template-safe-navigation.d.ts","sourceRoot":"","sources":["../../src/search/find-template-safe-navigation.ts"],"names":[],"mappings":"AAMA,OAAO,EAAsC,MAAM,EAAc,MAAM,sBAAsB,CAAC;AAY9F,qBAAa,0BAA2B,SAAQ,MAAM;IAClD,QAAQ,CAAC,IAAI,kEAAkE;IAC/E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAA+C;IAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAGiB;IAEvC,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAGxC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2026 the original author or authors.
|
|
4
|
+
*
|
|
5
|
+
* Moderne Proprietary. Only for use by Moderne customers under the terms of a commercial contract.
|
|
6
|
+
*/
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.FindTemplateSafeNavigation = void 0;
|
|
18
|
+
const rewrite_1 = require("@openrewrite/rewrite");
|
|
19
|
+
const text_1 = require("@openrewrite/rewrite/text");
|
|
20
|
+
const javascript_1 = require("@openrewrite/rewrite/javascript");
|
|
21
|
+
const java_1 = require("@openrewrite/rewrite/java");
|
|
22
|
+
const MESSAGE = "Safe navigation in an Angular template returns undefined rather than null as of Angular 22. " +
|
|
23
|
+
"Review bindings that distinguish the two, such as comparisons against null and pipes that treat null and " +
|
|
24
|
+
"undefined differently. See https://angular.dev/errors/safe-navigation-undefined";
|
|
25
|
+
/** `{{ a?.b }}`, `[x]="a?.b"`, and `@if (a?.b)`, but not `a ?? b` or the `?.` of a TypeScript expression. */
|
|
26
|
+
const SAFE_NAVIGATION = /\?\.(?![.\d])/;
|
|
27
|
+
class FindTemplateSafeNavigation extends rewrite_1.Recipe {
|
|
28
|
+
constructor() {
|
|
29
|
+
super(...arguments);
|
|
30
|
+
this.name = "org.openrewrite.angular.search.find-template-safe-navigation";
|
|
31
|
+
this.displayName = "Find safe navigation in Angular templates";
|
|
32
|
+
this.description = "Finds `?.` in HTML templates and in inline `template` metadata. Angular 22 changed " +
|
|
33
|
+
"safe navigation in templates to return `undefined` instead of `null`, which changes bindings that tell the two " +
|
|
34
|
+
"apart. Angular ships a `$safeNavigationMigration()` wrapper for this; this recipe reports the templates to review " +
|
|
35
|
+
"rather than rewriting the expressions.";
|
|
36
|
+
}
|
|
37
|
+
recipeList() {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
return [new FindHtmlSafeNavigation(), new FindInlineTemplateSafeNavigation()];
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.FindTemplateSafeNavigation = FindTemplateSafeNavigation;
|
|
44
|
+
class FindHtmlSafeNavigation extends rewrite_1.Recipe {
|
|
45
|
+
constructor() {
|
|
46
|
+
super(...arguments);
|
|
47
|
+
this.name = "org.openrewrite.angular.search.find-template-safe-navigation.html";
|
|
48
|
+
this.displayName = "Find safe navigation in HTML templates";
|
|
49
|
+
this.description = "Finds `?.` in `.html` templates.";
|
|
50
|
+
}
|
|
51
|
+
editor() {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
return new class extends text_1.PlainTextVisitor {
|
|
54
|
+
visitText(text, p) {
|
|
55
|
+
const _super = Object.create(null, {
|
|
56
|
+
visitText: { get: () => super.visitText }
|
|
57
|
+
});
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
const t = yield _super.visitText.call(this, text, p);
|
|
60
|
+
if (!t || !t.sourcePath.endsWith('.html'))
|
|
61
|
+
return t;
|
|
62
|
+
if (!SAFE_NAVIGATION.test(t.text))
|
|
63
|
+
return t;
|
|
64
|
+
return (0, rewrite_1.foundSearchResult)(t, MESSAGE);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
class FindInlineTemplateSafeNavigation extends rewrite_1.Recipe {
|
|
72
|
+
constructor() {
|
|
73
|
+
super(...arguments);
|
|
74
|
+
this.name = "org.openrewrite.angular.search.find-template-safe-navigation.inline";
|
|
75
|
+
this.displayName = "Find safe navigation in inline templates";
|
|
76
|
+
this.description = "Finds `?.` in inline `template` metadata of `@Component` decorators.";
|
|
77
|
+
}
|
|
78
|
+
editor() {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
return new class extends javascript_1.JavaScriptVisitor {
|
|
81
|
+
visitPropertyAssignment(property, p) {
|
|
82
|
+
const _super = Object.create(null, {
|
|
83
|
+
visitPropertyAssignment: { get: () => super.visitPropertyAssignment }
|
|
84
|
+
});
|
|
85
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
+
var _a, _b;
|
|
87
|
+
const prop = yield _super.visitPropertyAssignment.call(this, property, p);
|
|
88
|
+
if (!prop)
|
|
89
|
+
return prop;
|
|
90
|
+
const name = (_a = prop.name) === null || _a === void 0 ? void 0 : _a.element;
|
|
91
|
+
if (!(0, java_1.isIdentifier)(name) || name.simpleName !== 'template')
|
|
92
|
+
return prop;
|
|
93
|
+
const initializer = prop.initializer;
|
|
94
|
+
if (!initializer || !(0, java_1.isLiteral)(initializer))
|
|
95
|
+
return prop;
|
|
96
|
+
if (!SAFE_NAVIGATION.test((_b = initializer.valueSource) !== null && _b !== void 0 ? _b : ''))
|
|
97
|
+
return prop;
|
|
98
|
+
return (0, rewrite_1.foundSearchResult)(prop, MESSAGE);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}();
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=find-template-safe-navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-template-safe-navigation.js","sourceRoot":"","sources":["../../src/search/find-template-safe-navigation.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;AAEH,kDAA8F;AAC9F,oDAAsE;AACtE,gEAAkE;AAClE,oDAAqE;AAErE,MAAM,OAAO,GAAG,8FAA8F;IAC1G,2GAA2G;IAC3G,iFAAiF,CAAC;AAEtF,6GAA6G;AAC7G,MAAM,eAAe,GAAG,eAAe,CAAC;AAExC,MAAa,0BAA2B,SAAQ,gBAAM;IAAtD;;QACa,SAAI,GAAG,8DAA8D,CAAC;QACtE,gBAAW,GAAW,2CAA2C,CAAC;QAClE,gBAAW,GAAW,qFAAqF;YAChH,iHAAiH;YACjH,oHAAoH;YACpH,wCAAwC,CAAC;IAKjD,CAAC;IAHS,UAAU;;YACZ,OAAO,CAAC,IAAI,sBAAsB,EAAE,EAAE,IAAI,gCAAgC,EAAE,CAAC,CAAC;QAClF,CAAC;KAAA;CACJ;AAXD,gEAWC;AAED,MAAM,sBAAuB,SAAQ,gBAAM;IAA3C;;QACa,SAAI,GAAG,mEAAmE,CAAC;QAC3E,gBAAW,GAAW,wCAAwC,CAAC;QAC/D,gBAAW,GAAW,kCAAkC,CAAC;IAatE,CAAC;IAXS,MAAM;;YACR,OAAO,IAAI,KAAM,SAAQ,uBAAkC;gBACxC,SAAS,CAAC,IAAe,EAAE,CAAmB;;;;;wBACzD,MAAM,CAAC,GAAG,MAAM,OAAM,SAAS,YAAC,IAAI,EAAE,CAAC,CAAc,CAAC;wBACtD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC;4BAAE,OAAO,CAAC,CAAC;wBACpD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;4BAAE,OAAO,CAAC,CAAC;wBAE5C,OAAO,IAAA,2BAAiB,EAAC,CAAC,EAAE,OAAO,CAAC,CAAC;oBACzC,CAAC;iBAAA;aACJ,EAAE,CAAC;QACR,CAAC;KAAA;CACJ;AAED,MAAM,gCAAiC,SAAQ,gBAAM;IAArD;;QACa,SAAI,GAAG,qEAAqE,CAAC;QAC7E,gBAAW,GAAW,0CAA0C,CAAC;QACjE,gBAAW,GAAW,sEAAsE,CAAC;IAmB1G,CAAC;IAjBS,MAAM;;YACR,OAAO,IAAI,KAAM,SAAQ,8BAAmC;gBACxC,uBAAuB,CAAC,QAAa,EAAE,CAAmB;;;;;;wBACtE,MAAM,IAAI,GAAG,MAAM,OAAM,uBAAuB,YAAC,QAAQ,EAAE,CAAC,CAAQ,CAAC;wBACrE,IAAI,CAAC,IAAI;4BAAE,OAAO,IAAI,CAAC;wBAEvB,MAAM,IAAI,GAAG,MAAA,IAAI,CAAC,IAAI,0CAAE,OAAO,CAAC;wBAChC,IAAI,CAAC,IAAA,mBAAY,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU;4BAAE,OAAO,IAAI,CAAC;wBAEvE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;wBACrC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAA,gBAAS,EAAC,WAAW,CAAC;4BAAE,OAAO,IAAI,CAAC;wBACzD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,MAAA,WAAW,CAAC,WAAW,mCAAI,EAAE,CAAC;4BAAE,OAAO,IAAI,CAAC;wBAEtE,OAAO,IAAA,2BAAiB,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;oBAC5C,CAAC;iBAAA;aACJ,EAAE,CAAC;QACR,CAAC;KAAA;CACJ"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -61,6 +61,7 @@ import {UpgradeToAngular18} from './migration/upgrade-to-angular-18';
|
|
|
61
61
|
import {UpgradeToAngular19} from './migration/upgrade-to-angular-19';
|
|
62
62
|
import {UpgradeToAngular20} from './migration/upgrade-to-angular-20';
|
|
63
63
|
import {UpgradeToAngular21} from './migration/upgrade-to-angular-21';
|
|
64
|
+
import {UpgradeToAngular22} from './migration/upgrade-to-angular-22';
|
|
64
65
|
import {FindAngularDecorator} from './search/find-angular-decorator';
|
|
65
66
|
import {FindZoneJsUsage} from './search/find-zone-js-usage';
|
|
66
67
|
import {FindHammerJsUsage} from './search/find-hammer-js-usage';
|
|
@@ -107,6 +108,25 @@ import {MigrateInputToSignal} from './migration/migrate-input-to-signal';
|
|
|
107
108
|
import {MigrateOutputToSignal} from './migration/migrate-output-to-signal';
|
|
108
109
|
import {MigrateQueryToSignal} from './migration/migrate-query-to-signal';
|
|
109
110
|
import {AddLocalizePolyfill} from './migration/add-localize-polyfill';
|
|
111
|
+
import {FindProvideRoutesUsage} from './search/find-provide-routes-usage';
|
|
112
|
+
import {FindCheckNoChangesUsage} from './search/find-check-no-changes-usage';
|
|
113
|
+
import {FindCanMatchUsage} from './search/find-can-match-usage';
|
|
114
|
+
import {FindHttpXhrBackendUsage} from './search/find-http-xhr-backend-usage';
|
|
115
|
+
import {FindImplicitParamsInheritance} from './search/find-implicit-params-inheritance';
|
|
116
|
+
import {AddEagerChangeDetection} from './migration/add-eager-change-detection';
|
|
117
|
+
import {RenameDefaultChangeDetection} from './migration/rename-default-change-detection';
|
|
118
|
+
import {AddNoIncrementalHydration} from './migration/add-no-incremental-hydration';
|
|
119
|
+
import {AddStrictTemplatesFalse} from './migration/add-strict-templates-false';
|
|
120
|
+
import {SuppressSafeNavigationDiagnostics} from './migration/suppress-safe-navigation-diagnostics';
|
|
121
|
+
import {RemoveWithFetch} from './migration/remove-with-fetch';
|
|
122
|
+
import {AddWithXhr} from './migration/add-with-xhr';
|
|
123
|
+
import {AddTrustProxyHeaders} from './migration/add-trust-proxy-headers';
|
|
124
|
+
import {AddIstanbulInstrumenter} from './migration/add-istanbul-instrumenter';
|
|
125
|
+
import {MigrateModelWithOutput} from './migration/migrate-model-with-output';
|
|
126
|
+
import {FindTemplateSafeNavigation} from './search/find-template-safe-navigation';
|
|
127
|
+
import {ReplaceCreateNgModuleRef} from './migration/replace-create-ng-module-ref';
|
|
128
|
+
import {RenameAngularJsGlobals} from './migration/rename-angular-js-globals';
|
|
129
|
+
import {RenameSsrExperimentalPlatform} from './migration/rename-ssr-experimental-platform';
|
|
110
130
|
import {UpgradeToPrimeNG18} from './libraries/primeng/18/upgrade-to-primeng-18';
|
|
111
131
|
import {UpgradeComponentsTo18} from './libraries/primeng/18/upgrade-components-to-18';
|
|
112
132
|
import {MigratePrimeNgConfigToPrimeNG} from './libraries/primeng/18/migrate-primeng-config';
|
|
@@ -189,6 +209,7 @@ export async function activate(marketplace: RecipeMarketplace) {
|
|
|
189
209
|
await marketplace.install(UpgradeToAngular19, AngularMigration);
|
|
190
210
|
await marketplace.install(UpgradeToAngular20, AngularMigration);
|
|
191
211
|
await marketplace.install(UpgradeToAngular21, AngularMigration);
|
|
212
|
+
await marketplace.install(UpgradeToAngular22, AngularMigration);
|
|
192
213
|
await marketplace.install(FindAngularDecorator, AngularSearch);
|
|
193
214
|
await marketplace.install(FindZoneJsUsage, AngularSearch);
|
|
194
215
|
await marketplace.install(FindHammerJsUsage, AngularSearch);
|
|
@@ -237,6 +258,25 @@ export async function activate(marketplace: RecipeMarketplace) {
|
|
|
237
258
|
await marketplace.install(MigrateOutputToSignal, AngularMigration);
|
|
238
259
|
await marketplace.install(MigrateQueryToSignal, AngularMigration);
|
|
239
260
|
await marketplace.install(AddLocalizePolyfill, AngularMigration);
|
|
261
|
+
await marketplace.install(FindProvideRoutesUsage, AngularSearch);
|
|
262
|
+
await marketplace.install(FindCheckNoChangesUsage, AngularSearch);
|
|
263
|
+
await marketplace.install(FindCanMatchUsage, AngularSearch);
|
|
264
|
+
await marketplace.install(FindHttpXhrBackendUsage, AngularSearch);
|
|
265
|
+
await marketplace.install(FindImplicitParamsInheritance, AngularSearch);
|
|
266
|
+
await marketplace.install(AddEagerChangeDetection, AngularMigration);
|
|
267
|
+
await marketplace.install(RenameDefaultChangeDetection, AngularMigration);
|
|
268
|
+
await marketplace.install(AddNoIncrementalHydration, AngularMigration);
|
|
269
|
+
await marketplace.install(AddStrictTemplatesFalse, AngularMigration);
|
|
270
|
+
await marketplace.install(SuppressSafeNavigationDiagnostics, AngularMigration);
|
|
271
|
+
await marketplace.install(RemoveWithFetch, AngularMigration);
|
|
272
|
+
await marketplace.install(AddWithXhr, AngularMigration);
|
|
273
|
+
await marketplace.install(AddTrustProxyHeaders, AngularMigration);
|
|
274
|
+
await marketplace.install(AddIstanbulInstrumenter, AngularMigration);
|
|
275
|
+
await marketplace.install(MigrateModelWithOutput, AngularMigration);
|
|
276
|
+
await marketplace.install(FindTemplateSafeNavigation, AngularSearch);
|
|
277
|
+
await marketplace.install(ReplaceCreateNgModuleRef, AngularMigration);
|
|
278
|
+
await marketplace.install(RenameAngularJsGlobals, AngularMigration);
|
|
279
|
+
await marketplace.install(RenameSsrExperimentalPlatform, AngularMigration);
|
|
240
280
|
// PrimeNG
|
|
241
281
|
await marketplace.install(UpgradeToPrimeNG18, PrimeNG);
|
|
242
282
|
await marketplace.install(UpgradeComponentsTo18, PrimeNG);
|
|
@@ -314,6 +354,7 @@ export {UpgradeToAngular18, UpgradeToAngular18CodeChanges} from './migration/upg
|
|
|
314
354
|
export {UpgradeToAngular19, UpgradeToAngular19CodeChanges} from './migration/upgrade-to-angular-19';
|
|
315
355
|
export {UpgradeToAngular20, UpgradeToAngular20CodeChanges} from './migration/upgrade-to-angular-20';
|
|
316
356
|
export {UpgradeToAngular21, UpgradeToAngular21CodeChanges} from './migration/upgrade-to-angular-21';
|
|
357
|
+
export {UpgradeToAngular22, UpgradeToAngular22CodeChanges} from './migration/upgrade-to-angular-22';
|
|
317
358
|
export {FindAngularDecorator} from './search/find-angular-decorator';
|
|
318
359
|
export {FindZoneJsUsage} from './search/find-zone-js-usage';
|
|
319
360
|
export {FindHammerJsUsage} from './search/find-hammer-js-usage';
|
|
@@ -362,6 +403,25 @@ export {MigrateInputToSignal} from './migration/migrate-input-to-signal';
|
|
|
362
403
|
export {MigrateOutputToSignal} from './migration/migrate-output-to-signal';
|
|
363
404
|
export {MigrateQueryToSignal} from './migration/migrate-query-to-signal';
|
|
364
405
|
export {AddLocalizePolyfill} from './migration/add-localize-polyfill';
|
|
406
|
+
export {FindProvideRoutesUsage} from './search/find-provide-routes-usage';
|
|
407
|
+
export {FindCheckNoChangesUsage} from './search/find-check-no-changes-usage';
|
|
408
|
+
export {FindCanMatchUsage} from './search/find-can-match-usage';
|
|
409
|
+
export {FindHttpXhrBackendUsage} from './search/find-http-xhr-backend-usage';
|
|
410
|
+
export {FindImplicitParamsInheritance} from './search/find-implicit-params-inheritance';
|
|
411
|
+
export {AddEagerChangeDetection} from './migration/add-eager-change-detection';
|
|
412
|
+
export {RenameDefaultChangeDetection} from './migration/rename-default-change-detection';
|
|
413
|
+
export {AddNoIncrementalHydration} from './migration/add-no-incremental-hydration';
|
|
414
|
+
export {AddStrictTemplatesFalse} from './migration/add-strict-templates-false';
|
|
415
|
+
export {SuppressSafeNavigationDiagnostics} from './migration/suppress-safe-navigation-diagnostics';
|
|
416
|
+
export {RemoveWithFetch} from './migration/remove-with-fetch';
|
|
417
|
+
export {AddWithXhr} from './migration/add-with-xhr';
|
|
418
|
+
export {AddTrustProxyHeaders} from './migration/add-trust-proxy-headers';
|
|
419
|
+
export {AddIstanbulInstrumenter} from './migration/add-istanbul-instrumenter';
|
|
420
|
+
export {MigrateModelWithOutput} from './migration/migrate-model-with-output';
|
|
421
|
+
export {FindTemplateSafeNavigation} from './search/find-template-safe-navigation';
|
|
422
|
+
export {ReplaceCreateNgModuleRef} from './migration/replace-create-ng-module-ref';
|
|
423
|
+
export {RenameAngularJsGlobals} from './migration/rename-angular-js-globals';
|
|
424
|
+
export {RenameSsrExperimentalPlatform} from './migration/rename-ssr-experimental-platform';
|
|
365
425
|
// PrimeNG
|
|
366
426
|
export {UpgradeToPrimeNG18} from './libraries/primeng/18/upgrade-to-primeng-18';
|
|
367
427
|
export {UpgradeComponentsTo18} from './libraries/primeng/18/upgrade-components-to-18';
|
|
@@ -0,0 +1,109 @@
|
|
|
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 {emptyMarkers, ExecutionContext, markers, Marker, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
8
|
+
import {JavaScriptVisitor, JS, maybeAddImport, template} from "@openrewrite/rewrite/javascript";
|
|
9
|
+
import {emptySpace, isIdentifier, J} from "@openrewrite/rewrite/java";
|
|
10
|
+
import {create} from "mutative";
|
|
11
|
+
|
|
12
|
+
export class AddEagerChangeDetection extends Recipe {
|
|
13
|
+
readonly name = "org.openrewrite.angular.migration.add-eager-change-detection";
|
|
14
|
+
readonly displayName: string = "Add `ChangeDetectionStrategy.Eager` to components";
|
|
15
|
+
readonly description: string = "Adds `changeDetection: ChangeDetectionStrategy.Eager` to `@Component` decorators that do not " +
|
|
16
|
+
"specify a change detection strategy. Angular 22 changed the default for such components to " +
|
|
17
|
+
"`ChangeDetectionStrategy.OnPush`; making the previous check-always behavior explicit keeps them working unchanged.";
|
|
18
|
+
|
|
19
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
20
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
21
|
+
private componentFromAngularCore = false;
|
|
22
|
+
|
|
23
|
+
protected async visitImportDeclaration(jsImport: JS.Import, p: ExecutionContext): Promise<J | undefined> {
|
|
24
|
+
const imp = await super.visitImportDeclaration(jsImport, p) as JS.Import;
|
|
25
|
+
if (imp && importsComponentFromAngularCore(imp)) {
|
|
26
|
+
this.componentFromAngularCore = true;
|
|
27
|
+
}
|
|
28
|
+
return imp;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override async visitAnnotation(annotation: J.Annotation, p: ExecutionContext): Promise<J | undefined> {
|
|
32
|
+
const a = await super.visitAnnotation(annotation, p) as J.Annotation;
|
|
33
|
+
if (!a || !this.componentFromAngularCore) return a;
|
|
34
|
+
|
|
35
|
+
const annotType = a.annotationType;
|
|
36
|
+
if (!isIdentifier(annotType) || annotType.simpleName !== 'Component') return a;
|
|
37
|
+
|
|
38
|
+
if (!a.arguments?.elements?.length) return a;
|
|
39
|
+
const firstArg = a.arguments.elements[0].element;
|
|
40
|
+
if (firstArg.kind !== J.Kind.NewClass) return a;
|
|
41
|
+
|
|
42
|
+
const newClass = firstArg as J.NewClass;
|
|
43
|
+
if (!newClass.body) return a;
|
|
44
|
+
|
|
45
|
+
const statements = newClass.body.statements;
|
|
46
|
+
if (statements.length === 0) return a;
|
|
47
|
+
|
|
48
|
+
for (const stmt of statements) {
|
|
49
|
+
const element = stmt.element;
|
|
50
|
+
// A spread may already supply `changeDetection`, which we cannot see from here
|
|
51
|
+
if (element.kind === JS.Kind.Spread) return a;
|
|
52
|
+
if (element.kind !== JS.Kind.PropertyAssignment) continue;
|
|
53
|
+
const propertyName = (element as JS.PropertyAssignment).name.element;
|
|
54
|
+
if (isIdentifier(propertyName) && propertyName.simpleName === 'changeDetection') return a;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
maybeAddImport(this, {
|
|
58
|
+
module: '@angular/core',
|
|
59
|
+
member: 'ChangeDetectionStrategy',
|
|
60
|
+
onlyIfReferenced: false
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const lastStatement = statements[statements.length - 1];
|
|
64
|
+
const obj = await template`({ changeDetection: ChangeDetectionStrategy.Eager })`.apply(a, this.cursor) as any;
|
|
65
|
+
const changeDetectionProp = {
|
|
66
|
+
...obj.tree.element.body.statements[0].element,
|
|
67
|
+
prefix: lastStatement.element.prefix
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// The comma of a trailing comma object belongs to whichever property ends up last
|
|
71
|
+
const trailingComma = lastStatement.markers.markers
|
|
72
|
+
.find((m: Marker) => m.kind === J.Markers.TrailingComma);
|
|
73
|
+
|
|
74
|
+
const wrappedProp: J.RightPadded<any> = {
|
|
75
|
+
kind: J.Kind.RightPadded,
|
|
76
|
+
element: changeDetectionProp,
|
|
77
|
+
after: emptySpace,
|
|
78
|
+
markers: trailingComma ? markers(trailingComma) : emptyMarkers,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return create(a, draft => {
|
|
82
|
+
const body = (draft.arguments!.elements[0].element as any).body!;
|
|
83
|
+
const statements = [...body.statements];
|
|
84
|
+
if (trailingComma) {
|
|
85
|
+
const last = statements[statements.length - 1];
|
|
86
|
+
statements[statements.length - 1] = {
|
|
87
|
+
...last,
|
|
88
|
+
markers: markers(...last.markers.markers.filter((m: Marker) => m.kind !== J.Markers.TrailingComma))
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
body.statements = [...statements, wrappedProp];
|
|
92
|
+
}) as J.Annotation;
|
|
93
|
+
}
|
|
94
|
+
}();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function importsComponentFromAngularCore(jsImport: JS.Import): boolean {
|
|
99
|
+
const moduleSpec = jsImport.moduleSpecifier?.element;
|
|
100
|
+
if (moduleSpec?.kind !== J.Kind.Literal || (moduleSpec as J.Literal).value !== '@angular/core') return false;
|
|
101
|
+
|
|
102
|
+
const namedBindings = jsImport.importClause?.namedBindings;
|
|
103
|
+
if (namedBindings?.kind !== JS.Kind.NamedImports) return false;
|
|
104
|
+
|
|
105
|
+
return (namedBindings as JS.NamedImports).elements.elements.some(specifier => {
|
|
106
|
+
const spec = specifier.element as JS.ImportSpecifier;
|
|
107
|
+
return isIdentifier(spec.specifier) && spec.specifier.simpleName === 'Component';
|
|
108
|
+
});
|
|
109
|
+
}
|