@openrewrite/recipes-angular 1.1.4 → 1.1.5
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 +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +76 -1
- package/dist/index.js.map +1 -1
- package/dist/libraries/primeng/18/add-primeng-provider.d.ts +45 -0
- package/dist/libraries/primeng/18/add-primeng-provider.d.ts.map +1 -0
- package/dist/libraries/primeng/18/add-primeng-provider.js +354 -0
- package/dist/libraries/primeng/18/add-primeng-provider.js.map +1 -0
- package/dist/libraries/primeng/18/index.d.ts +19 -0
- package/dist/libraries/primeng/18/index.d.ts.map +1 -0
- package/dist/libraries/primeng/18/index.js +45 -0
- package/dist/libraries/primeng/18/index.js.map +1 -0
- package/dist/libraries/primeng/18/manual-migration-steps.d.ts +19 -0
- package/dist/libraries/primeng/18/manual-migration-steps.d.ts.map +1 -0
- package/dist/libraries/primeng/18/manual-migration-steps.js +45 -0
- package/dist/libraries/primeng/18/manual-migration-steps.js.map +1 -0
- package/dist/libraries/primeng/18/mark-deprecated-components.d.ts +9 -0
- package/dist/libraries/primeng/18/mark-deprecated-components.d.ts.map +1 -0
- package/dist/libraries/primeng/18/mark-deprecated-components.js +125 -0
- package/dist/libraries/primeng/18/mark-deprecated-components.js.map +1 -0
- package/dist/libraries/primeng/18/mark-deprecated-css-classes.d.ts +15 -0
- package/dist/libraries/primeng/18/mark-deprecated-css-classes.d.ts.map +1 -0
- package/dist/libraries/primeng/18/mark-deprecated-css-classes.js +108 -0
- package/dist/libraries/primeng/18/mark-deprecated-css-classes.js.map +1 -0
- package/dist/libraries/primeng/18/mark-drawer-size.d.ts +16 -0
- package/dist/libraries/primeng/18/mark-drawer-size.d.ts.map +1 -0
- package/dist/libraries/primeng/18/mark-drawer-size.js +90 -0
- package/dist/libraries/primeng/18/mark-drawer-size.js.map +1 -0
- package/dist/libraries/primeng/18/mark-removed-primeng-modules.d.ts +9 -0
- package/dist/libraries/primeng/18/mark-removed-primeng-modules.d.ts.map +1 -0
- package/dist/libraries/primeng/18/mark-removed-primeng-modules.js +186 -0
- package/dist/libraries/primeng/18/mark-removed-primeng-modules.js.map +1 -0
- package/dist/libraries/primeng/18/migrate-messages-to-message-loop.d.ts +15 -0
- package/dist/libraries/primeng/18/migrate-messages-to-message-loop.d.ts.map +1 -0
- package/dist/libraries/primeng/18/migrate-messages-to-message-loop.js +78 -0
- package/dist/libraries/primeng/18/migrate-messages-to-message-loop.js.map +1 -0
- package/dist/libraries/primeng/18/migrate-p-fluid-to-wrapper.d.ts +27 -0
- package/dist/libraries/primeng/18/migrate-p-fluid-to-wrapper.d.ts.map +1 -0
- package/dist/libraries/primeng/18/migrate-p-fluid-to-wrapper.js +495 -0
- package/dist/libraries/primeng/18/migrate-p-fluid-to-wrapper.js.map +1 -0
- package/dist/libraries/primeng/18/migrate-primeng-config.d.ts +8 -0
- package/dist/libraries/primeng/18/migrate-primeng-config.d.ts.map +1 -0
- package/dist/libraries/primeng/18/migrate-primeng-config.js +154 -0
- package/dist/libraries/primeng/18/migrate-primeng-config.js.map +1 -0
- package/dist/libraries/primeng/18/migrate-primeng-signal-assignments.d.ts +12 -0
- package/dist/libraries/primeng/18/migrate-primeng-signal-assignments.d.ts.map +1 -0
- package/dist/libraries/primeng/18/migrate-primeng-signal-assignments.js +112 -0
- package/dist/libraries/primeng/18/migrate-primeng-signal-assignments.js.map +1 -0
- package/dist/libraries/primeng/18/rename-calendar-to-datepicker.d.ts +8 -0
- package/dist/libraries/primeng/18/rename-calendar-to-datepicker.d.ts.map +1 -0
- package/dist/libraries/primeng/18/rename-calendar-to-datepicker.js +114 -0
- package/dist/libraries/primeng/18/rename-calendar-to-datepicker.js.map +1 -0
- package/dist/libraries/primeng/18/rename-dropdown-to-select.d.ts +8 -0
- package/dist/libraries/primeng/18/rename-dropdown-to-select.d.ts.map +1 -0
- package/dist/libraries/primeng/18/rename-dropdown-to-select.js +114 -0
- package/dist/libraries/primeng/18/rename-dropdown-to-select.js.map +1 -0
- package/dist/libraries/primeng/18/rename-inputswitch-to-toggleswitch.d.ts +8 -0
- package/dist/libraries/primeng/18/rename-inputswitch-to-toggleswitch.d.ts.map +1 -0
- package/dist/libraries/primeng/18/rename-inputswitch-to-toggleswitch.js +114 -0
- package/dist/libraries/primeng/18/rename-inputswitch-to-toggleswitch.js.map +1 -0
- package/dist/libraries/primeng/18/rename-message-interface.d.ts +8 -0
- package/dist/libraries/primeng/18/rename-message-interface.d.ts.map +1 -0
- package/dist/libraries/primeng/18/rename-message-interface.js +107 -0
- package/dist/libraries/primeng/18/rename-message-interface.js.map +1 -0
- package/dist/libraries/primeng/18/rename-overlaypanel-to-popover.d.ts +8 -0
- package/dist/libraries/primeng/18/rename-overlaypanel-to-popover.d.ts.map +1 -0
- package/dist/libraries/primeng/18/rename-overlaypanel-to-popover.js +114 -0
- package/dist/libraries/primeng/18/rename-overlaypanel-to-popover.js.map +1 -0
- package/dist/libraries/primeng/18/rename-sidebar-to-drawer.d.ts +8 -0
- package/dist/libraries/primeng/18/rename-sidebar-to-drawer.d.ts.map +1 -0
- package/dist/libraries/primeng/18/rename-sidebar-to-drawer.js +114 -0
- package/dist/libraries/primeng/18/rename-sidebar-to-drawer.js.map +1 -0
- package/dist/libraries/primeng/18/rename-template-selectors.d.ts +12 -0
- package/dist/libraries/primeng/18/rename-template-selectors.d.ts.map +1 -0
- package/dist/libraries/primeng/18/rename-template-selectors.js +79 -0
- package/dist/libraries/primeng/18/rename-template-selectors.js.map +1 -0
- package/dist/libraries/primeng/18/upgrade-components-to-18.d.ts +8 -0
- package/dist/libraries/primeng/18/upgrade-components-to-18.d.ts.map +1 -0
- package/dist/libraries/primeng/18/upgrade-components-to-18.js +73 -0
- package/dist/libraries/primeng/18/upgrade-components-to-18.js.map +1 -0
- package/dist/libraries/primeng/18/upgrade-to-primeng-18.d.ts +8 -0
- package/dist/libraries/primeng/18/upgrade-to-primeng-18.d.ts.map +1 -0
- package/dist/libraries/primeng/18/upgrade-to-primeng-18.js +68 -0
- package/dist/libraries/primeng/18/upgrade-to-primeng-18.js.map +1 -0
- package/dist/migration/replace-untyped-forms.d.ts +14 -2
- package/dist/migration/replace-untyped-forms.d.ts.map +1 -1
- package/dist/migration/replace-untyped-forms.js +108 -36
- package/dist/migration/replace-untyped-forms.js.map +1 -1
- package/dist/migration/upgrade-angular-peer-libs-to-18.d.ts +17 -0
- package/dist/migration/upgrade-angular-peer-libs-to-18.d.ts.map +1 -0
- package/dist/migration/upgrade-angular-peer-libs-to-18.js +49 -0
- package/dist/migration/upgrade-angular-peer-libs-to-18.js.map +1 -0
- package/dist/migration/upgrade-to-angular-18.d.ts.map +1 -1
- package/dist/migration/upgrade-to-angular-18.js +16 -7
- package/dist/migration/upgrade-to-angular-18.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +57 -0
- package/src/libraries/primeng/18/add-primeng-provider.ts +359 -0
- package/src/libraries/primeng/18/index.ts +24 -0
- package/src/libraries/primeng/18/manual-migration-steps.ts +37 -0
- package/src/libraries/primeng/18/mark-deprecated-components.ts +128 -0
- package/src/libraries/primeng/18/mark-deprecated-css-classes.ts +109 -0
- package/src/libraries/primeng/18/mark-drawer-size.ts +85 -0
- package/src/libraries/primeng/18/mark-removed-primeng-modules.ts +198 -0
- package/src/libraries/primeng/18/migrate-messages-to-message-loop.ts +72 -0
- package/src/libraries/primeng/18/migrate-p-fluid-to-wrapper.ts +439 -0
- package/src/libraries/primeng/18/migrate-primeng-config.ts +112 -0
- package/src/libraries/primeng/18/migrate-primeng-signal-assignments.ts +83 -0
- package/src/libraries/primeng/18/rename-calendar-to-datepicker.ts +81 -0
- package/src/libraries/primeng/18/rename-dropdown-to-select.ts +81 -0
- package/src/libraries/primeng/18/rename-inputswitch-to-toggleswitch.ts +81 -0
- package/src/libraries/primeng/18/rename-message-interface.ts +78 -0
- package/src/libraries/primeng/18/rename-overlaypanel-to-popover.ts +81 -0
- package/src/libraries/primeng/18/rename-sidebar-to-drawer.ts +81 -0
- package/src/libraries/primeng/18/rename-template-selectors.ts +63 -0
- package/src/libraries/primeng/18/upgrade-components-to-18.ts +57 -0
- package/src/libraries/primeng/18/upgrade-to-primeng-18.ts +52 -0
- package/src/migration/replace-untyped-forms.ts +111 -39
- package/src/migration/upgrade-angular-peer-libs-to-18.ts +33 -0
- package/src/migration/upgrade-to-angular-18.ts +16 -7
|
@@ -0,0 +1,85 @@
|
|
|
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 {DataTable, ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
8
|
+
import {PlainText, PlainTextVisitor} from "@openrewrite/rewrite/text";
|
|
9
|
+
import {
|
|
10
|
+
ManualMigrationStep,
|
|
11
|
+
MANUAL_MIGRATION_STEPS_DESCRIPTION,
|
|
12
|
+
MANUAL_MIGRATION_STEPS_DISPLAY_NAME,
|
|
13
|
+
MANUAL_MIGRATION_STEPS_NAME,
|
|
14
|
+
} from "./manual-migration-steps";
|
|
15
|
+
|
|
16
|
+
const TARGET_TAGS = ['p-drawer', 'p-sidebar'];
|
|
17
|
+
const TODO_TEXT = "PrimeNG 18 removed the `size` input on `<p-drawer>`/`<p-sidebar>`. Replace `[size]=\"...\"` / `size=\"...\"` with a responsive CSS utility on the `[style]` input or `styleClass`.";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Mark `<p-drawer>` and `<p-sidebar>` elements that bind the removed `size` input in
|
|
21
|
+
* templates. Adds an HTML TODO comment immediately before the element and writes a row
|
|
22
|
+
* to the `ManualMigrationSteps` data table. The attribute itself is left in place because
|
|
23
|
+
* the right replacement is template-context-dependent (responsive style class, fixed
|
|
24
|
+
* width, etc.).
|
|
25
|
+
*/
|
|
26
|
+
export class MarkDrawerSize extends Recipe {
|
|
27
|
+
readonly name = "org.openrewrite.primeng.MarkDrawerSize";
|
|
28
|
+
readonly displayName = "Mark `<p-drawer>` / `<p-sidebar>` `size` usages with TODO comments";
|
|
29
|
+
readonly description = "Inserts an HTML `<!-- TODO: ... -->` comment before any `<p-drawer>` or " +
|
|
30
|
+
"`<p-sidebar>` element that binds the removed `size` input, and records the site in the " +
|
|
31
|
+
"`ManualMigrationSteps` data table. Both `[size]=\"...\"` and `size=\"...\"` attribute forms are " +
|
|
32
|
+
"matched. The attribute is left untouched — the v18 replacement (responsive CSS via `[style]` / " +
|
|
33
|
+
"`styleClass`) depends on the desired layout and needs manual review.";
|
|
34
|
+
|
|
35
|
+
private dataTable = new DataTable<ManualMigrationStep>(
|
|
36
|
+
MANUAL_MIGRATION_STEPS_NAME,
|
|
37
|
+
MANUAL_MIGRATION_STEPS_DISPLAY_NAME,
|
|
38
|
+
MANUAL_MIGRATION_STEPS_DESCRIPTION,
|
|
39
|
+
ManualMigrationStep,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
43
|
+
const recipeName = this.name;
|
|
44
|
+
const dataTable = this.dataTable;
|
|
45
|
+
return new class extends PlainTextVisitor<ExecutionContext> {
|
|
46
|
+
override async visitText(text: PlainText, p: ExecutionContext): Promise<PlainText | undefined> {
|
|
47
|
+
const t = await super.visitText(text, p) as PlainText;
|
|
48
|
+
if (!t) return t;
|
|
49
|
+
if (!t.sourcePath.endsWith('.html')) return t;
|
|
50
|
+
|
|
51
|
+
let updated = t.text;
|
|
52
|
+
let modified = false;
|
|
53
|
+
|
|
54
|
+
for (const tag of TARGET_TAGS) {
|
|
55
|
+
// Match opening tags of the target component that include a [size]="…" or
|
|
56
|
+
// size="…" attribute. We only mark — the attribute stays in place.
|
|
57
|
+
const re = new RegExp(`(^|\\n)([ \\t]*)(<${tag}\\b[^>]*?(?:\\[size\\]|\\bsize)\\s*=\\s*["'][^"']*["'][^>]*>)`, 'g');
|
|
58
|
+
const todoMarker = `<!-- TODO: PrimeNG 18 — ${TODO_TEXT} -->`;
|
|
59
|
+
updated = updated.replace(re, (match, lead, indent, fullTag) => {
|
|
60
|
+
const before = updated.slice(0, updated.indexOf(match));
|
|
61
|
+
if (before.endsWith(todoMarker + '\n' + indent) || before.endsWith(todoMarker + indent)) {
|
|
62
|
+
return match;
|
|
63
|
+
}
|
|
64
|
+
modified = true;
|
|
65
|
+
dataTable.insertRow(p, {
|
|
66
|
+
sourcePath: t.sourcePath,
|
|
67
|
+
recipe: recipeName,
|
|
68
|
+
subject: `<${tag} ... size="...">`,
|
|
69
|
+
reason: "`size` input removed in PrimeNG 18.",
|
|
70
|
+
action: TODO_TEXT,
|
|
71
|
+
});
|
|
72
|
+
return `${lead}${indent}${todoMarker}\n${indent}${fullTag}`;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!modified) return t;
|
|
77
|
+
return {
|
|
78
|
+
...t,
|
|
79
|
+
text: updated,
|
|
80
|
+
snippets: [],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
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 {DataTable, ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
8
|
+
import {JavaScriptVisitor, JS, Template} from "@openrewrite/rewrite/javascript";
|
|
9
|
+
import {J, isIdentifier} from "@openrewrite/rewrite/java";
|
|
10
|
+
import {create} from "mutative";
|
|
11
|
+
import {
|
|
12
|
+
ManualMigrationStep,
|
|
13
|
+
MANUAL_MIGRATION_STEPS_DESCRIPTION,
|
|
14
|
+
MANUAL_MIGRATION_STEPS_DISPLAY_NAME,
|
|
15
|
+
MANUAL_MIGRATION_STEPS_NAME,
|
|
16
|
+
} from "./manual-migration-steps";
|
|
17
|
+
|
|
18
|
+
interface RemovedModule {
|
|
19
|
+
members: string[];
|
|
20
|
+
todo: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Modules removed entirely in PrimeNG 18 — their packages no longer exist on disk.
|
|
24
|
+
const REMOVED_MODULES: Record<string, RemovedModule> = {
|
|
25
|
+
'primeng/chips': {
|
|
26
|
+
members: ['ChipsModule', 'Chips'],
|
|
27
|
+
todo: "PrimeNG 18 — `Chips` was removed. Replace `<p-chips>` with `<p-autoComplete [multiple]=\"true\" [typeahead]=\"false\">`.",
|
|
28
|
+
},
|
|
29
|
+
'primeng/tristatecheckbox': {
|
|
30
|
+
members: ['TriStateCheckboxModule', 'TriStateCheckbox'],
|
|
31
|
+
todo: "PrimeNG 18 — `TriStateCheckbox` was removed. Replace `<p-triStateCheckbox>` with `<p-checkbox [indeterminate]=\"true\">`.",
|
|
32
|
+
},
|
|
33
|
+
'primeng/messages': {
|
|
34
|
+
members: ['MessagesModule', 'Messages'],
|
|
35
|
+
todo: "PrimeNG 18 — `Messages` was removed. Replace `<p-messages [value]=\"X\">` with `@for (m of X; track m) { <p-message [severity]=\"m.severity\" [text]=\"m.detail\"></p-message> }` and import `MessageModule` from `primeng/message`.",
|
|
36
|
+
},
|
|
37
|
+
'primeng/dataviewlayoutoptions': {
|
|
38
|
+
members: ['DataViewLayoutOptions'],
|
|
39
|
+
todo: "PrimeNG 18 — `DataViewLayoutOptions` was removed. Replace `<p-dataViewLayoutOptions>` with `<p-selectButton>` bound to a layout `'list'|'grid'` value.",
|
|
40
|
+
},
|
|
41
|
+
'primeng/animate': {
|
|
42
|
+
members: ['AnimateModule', 'Animate'],
|
|
43
|
+
todo: "PrimeNG 18 — the `pAnimate` directive was removed. Replace `pAnimate` usages with `pAnimateOnScroll` and import from `primeng/animateonscroll`.",
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// All identifiers that should be stripped from @NgModule imports / declarations / exports arrays
|
|
48
|
+
// because they refer to components / modules that no longer exist as runtime values.
|
|
49
|
+
const REMOVED_IDENTIFIERS = new Set<string>(
|
|
50
|
+
Object.values(REMOVED_MODULES).flatMap(m => m.members)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
export class MarkRemovedPrimengModules extends Recipe {
|
|
54
|
+
readonly name = "org.openrewrite.primeng.MarkRemovedPrimengModules";
|
|
55
|
+
readonly displayName = "Mark imports of removed PrimeNG modules with TODO stubs";
|
|
56
|
+
readonly description = "For each `import` of a PrimeNG module that no longer exists in v18 " +
|
|
57
|
+
"(`primeng/chips`, `primeng/tristatecheckbox`, `primeng/messages`, `primeng/dataviewlayoutoptions`), " +
|
|
58
|
+
"replaces the broken import statement with a `const <Name>: any = null;` stub annotated by a TODO " +
|
|
59
|
+
"comment that describes the v18 replacement. Also strips the corresponding entries from `@NgModule` " +
|
|
60
|
+
"`imports`, `declarations`, and `exports` arrays since Angular's compiler rejects `null` values there. " +
|
|
61
|
+
"Each flagged site is also recorded in the `ManualMigrationSteps` data table so downstream tooling " +
|
|
62
|
+
"can enumerate the remaining work.";
|
|
63
|
+
|
|
64
|
+
private dataTable = new DataTable<ManualMigrationStep>(
|
|
65
|
+
MANUAL_MIGRATION_STEPS_NAME,
|
|
66
|
+
MANUAL_MIGRATION_STEPS_DISPLAY_NAME,
|
|
67
|
+
MANUAL_MIGRATION_STEPS_DESCRIPTION,
|
|
68
|
+
ManualMigrationStep,
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
72
|
+
const recipeName = this.name;
|
|
73
|
+
const dataTable = this.dataTable;
|
|
74
|
+
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
75
|
+
protected async visitImportDeclaration(jsImport: JS.Import, p: ExecutionContext): Promise<J | undefined> {
|
|
76
|
+
const imp = await super.visitImportDeclaration(jsImport, p) as JS.Import;
|
|
77
|
+
if (!imp?.moduleSpecifier) return imp;
|
|
78
|
+
|
|
79
|
+
const moduleSpec = imp.moduleSpecifier.element;
|
|
80
|
+
if (moduleSpec.kind !== J.Kind.Literal) return imp;
|
|
81
|
+
|
|
82
|
+
const moduleName = (moduleSpec as J.Literal).value as string;
|
|
83
|
+
const removed = REMOVED_MODULES[moduleName];
|
|
84
|
+
if (!removed) return imp;
|
|
85
|
+
|
|
86
|
+
const importedNames: string[] = [];
|
|
87
|
+
const namedBindings = imp.importClause?.namedBindings;
|
|
88
|
+
if (namedBindings?.kind === JS.Kind.NamedImports) {
|
|
89
|
+
for (const specifier of (namedBindings as JS.NamedImports).elements.elements) {
|
|
90
|
+
const spec = specifier.element as JS.ImportSpecifier;
|
|
91
|
+
if (isIdentifier(spec.specifier)) {
|
|
92
|
+
importedNames.push((spec.specifier as J.Identifier).simpleName);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (importedNames.length === 0) return imp;
|
|
97
|
+
|
|
98
|
+
const replacementCode = importedNames
|
|
99
|
+
.map(name => `const ${name}: any = null;`)
|
|
100
|
+
.join('\n');
|
|
101
|
+
|
|
102
|
+
const replacement = await Template.builder()
|
|
103
|
+
.code(replacementCode)
|
|
104
|
+
.build()
|
|
105
|
+
.apply(imp, this.cursor) as any;
|
|
106
|
+
|
|
107
|
+
const sourcePath = (this.cursor.firstEnclosing<any>((o: any): o is any => !!o?.sourcePath)?.sourcePath) ?? '';
|
|
108
|
+
for (const name of importedNames) {
|
|
109
|
+
dataTable.insertRow(p, {
|
|
110
|
+
sourcePath,
|
|
111
|
+
recipe: recipeName,
|
|
112
|
+
subject: `${name} (${moduleName})`,
|
|
113
|
+
reason: "Module removed in PrimeNG 18; package no longer exists.",
|
|
114
|
+
action: removed.todo,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const todoComment = {
|
|
119
|
+
kind: J.Kind.TextComment,
|
|
120
|
+
multiline: true,
|
|
121
|
+
text: ` TODO: ${removed.todo} (was \`import { ${importedNames.join(', ')} } from '${moduleName}'\`) `,
|
|
122
|
+
suffix: '\n',
|
|
123
|
+
markers: {kind: 'org.openrewrite.marker.Markers', id: imp.id, markers: []},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const originalPrefix = imp.prefix ?? {kind: J.Kind.Space, whitespace: '', comments: []};
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
...replacement,
|
|
130
|
+
prefix: {
|
|
131
|
+
...originalPrefix,
|
|
132
|
+
comments: [...(originalPrefix.comments ?? []), todoComment],
|
|
133
|
+
},
|
|
134
|
+
} as J;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
override async visitAnnotation(annotation: J.Annotation, p: ExecutionContext): Promise<J | undefined> {
|
|
138
|
+
const a = await super.visitAnnotation(annotation, p) as J.Annotation;
|
|
139
|
+
if (!a) return a;
|
|
140
|
+
|
|
141
|
+
const annotType = a.annotationType;
|
|
142
|
+
if (!isIdentifier(annotType)) return a;
|
|
143
|
+
if (annotType.simpleName !== 'NgModule' && annotType.simpleName !== 'Component') return a;
|
|
144
|
+
|
|
145
|
+
if (!a.arguments?.elements?.length) return a;
|
|
146
|
+
const firstArg = a.arguments.elements[0].element;
|
|
147
|
+
if (firstArg.kind !== J.Kind.NewClass) return a;
|
|
148
|
+
|
|
149
|
+
const newClass = firstArg as J.NewClass;
|
|
150
|
+
if (!newClass.body) return a;
|
|
151
|
+
|
|
152
|
+
let modified = false;
|
|
153
|
+
const newStatements = newClass.body.statements.map(stmtEl => {
|
|
154
|
+
const stmt = stmtEl.element;
|
|
155
|
+
if (stmt.kind !== JS.Kind.PropertyAssignment) return stmtEl;
|
|
156
|
+
const prop = stmt as JS.PropertyAssignment;
|
|
157
|
+
const nameExpr = prop.name.element;
|
|
158
|
+
if (!isIdentifier(nameExpr)) return stmtEl;
|
|
159
|
+
if (!['imports', 'declarations', 'exports'].includes(nameExpr.simpleName)) return stmtEl;
|
|
160
|
+
|
|
161
|
+
const initializer = prop.initializer as any;
|
|
162
|
+
const arr = initializer;
|
|
163
|
+
if (!arr?.initializer?.elements?.length) return stmtEl;
|
|
164
|
+
|
|
165
|
+
const filteredElems = arr.initializer.elements.filter((el: any) => {
|
|
166
|
+
const expr = el.element;
|
|
167
|
+
if (!isIdentifier(expr)) return true;
|
|
168
|
+
return !REMOVED_IDENTIFIERS.has((expr as J.Identifier).simpleName);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (filteredElems.length === arr.initializer.elements.length) return stmtEl;
|
|
172
|
+
|
|
173
|
+
modified = true;
|
|
174
|
+
return {
|
|
175
|
+
...stmtEl,
|
|
176
|
+
element: {
|
|
177
|
+
...prop,
|
|
178
|
+
initializer: {
|
|
179
|
+
...arr,
|
|
180
|
+
initializer: {
|
|
181
|
+
...arr.initializer,
|
|
182
|
+
elements: filteredElems
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (!modified) return a;
|
|
190
|
+
|
|
191
|
+
return create(a, draft => {
|
|
192
|
+
const body = (draft.arguments!.elements[0].element as any).body!;
|
|
193
|
+
body.statements = newStatements;
|
|
194
|
+
}) as J.Annotation;
|
|
195
|
+
}
|
|
196
|
+
}();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
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 {DataTable, ExecutionContext, Recipe, TreeVisitor} from "@openrewrite/rewrite";
|
|
8
|
+
import {PlainText, PlainTextVisitor} from "@openrewrite/rewrite/text";
|
|
9
|
+
import {
|
|
10
|
+
ManualMigrationStep,
|
|
11
|
+
MANUAL_MIGRATION_STEPS_DESCRIPTION,
|
|
12
|
+
MANUAL_MIGRATION_STEPS_DISPLAY_NAME,
|
|
13
|
+
MANUAL_MIGRATION_STEPS_NAME,
|
|
14
|
+
} from "./manual-migration-steps";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Rewrite `<p-messages [value]="X"...></p-messages>` to a `@for` loop over `<p-message>`,
|
|
18
|
+
* matching the v18 replacement pattern. Handles both self-closing and paired tags, single-
|
|
19
|
+
* or double-quoted bound values, and any other attributes (which are dropped — they don't
|
|
20
|
+
* apply to the new component).
|
|
21
|
+
*/
|
|
22
|
+
export class MigrateMessagesToMessageLoop extends Recipe {
|
|
23
|
+
readonly name = "org.openrewrite.primeng.MigrateMessagesToMessageLoop";
|
|
24
|
+
readonly displayName = "Migrate `<p-messages>` to `<p-message>` with `@for` loop";
|
|
25
|
+
readonly description = "Rewrites `<p-messages [value]=\"expr\">…</p-messages>` to " +
|
|
26
|
+
"`@for (msg of expr; track msg) { <p-message [severity]=\"msg.severity\" [text]=\"msg.detail\"></p-message> }`. " +
|
|
27
|
+
"The `Messages` component was removed in PrimeNG 18 in favor of looping over the new `Message` component. " +
|
|
28
|
+
"Each rewritten site is recorded in the `ManualMigrationSteps` data table for follow-up review.";
|
|
29
|
+
|
|
30
|
+
private dataTable = new DataTable<ManualMigrationStep>(
|
|
31
|
+
MANUAL_MIGRATION_STEPS_NAME,
|
|
32
|
+
MANUAL_MIGRATION_STEPS_DISPLAY_NAME,
|
|
33
|
+
MANUAL_MIGRATION_STEPS_DESCRIPTION,
|
|
34
|
+
ManualMigrationStep,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
38
|
+
const recipeName = this.name;
|
|
39
|
+
const dataTable = this.dataTable;
|
|
40
|
+
return new class extends PlainTextVisitor<ExecutionContext> {
|
|
41
|
+
override async visitText(text: PlainText, p: ExecutionContext): Promise<PlainText | undefined> {
|
|
42
|
+
const t = await super.visitText(text, p) as PlainText;
|
|
43
|
+
if (!t) return t;
|
|
44
|
+
if (!t.sourcePath.endsWith('.html')) return t;
|
|
45
|
+
if (!t.text.includes('<p-messages')) return t;
|
|
46
|
+
|
|
47
|
+
const re = /<p-messages\b([^>]*?)\[value\]=["']([^"']+)["']([^>]*)>(?:\s*<\/p-messages>)?/g;
|
|
48
|
+
|
|
49
|
+
let modified = false;
|
|
50
|
+
const updated = t.text.replace(re, (_match, _before, expr, _after) => {
|
|
51
|
+
modified = true;
|
|
52
|
+
dataTable.insertRow(p, {
|
|
53
|
+
sourcePath: t.sourcePath,
|
|
54
|
+
recipe: recipeName,
|
|
55
|
+
subject: `<p-messages [value]="${expr}">`,
|
|
56
|
+
reason: "Messages component removed in PrimeNG 18; replaced by automated rewrite to <p-message> + @for loop.",
|
|
57
|
+
action: "Review the generated severity/text bindings against the original message shape (closable, life, etc. no longer apply). Confirm the iterable shape matches `{ severity, summary, detail }`.",
|
|
58
|
+
});
|
|
59
|
+
return `<!-- TODO: PrimeNG 18 — \`Messages\` was removed. The block below is an automated rewrite to the new \`Message\` + \`@for\` pattern; review severity/text/closable bindings against the original message shape. -->\n@for (msg of ${expr}; track msg) {\n <p-message [severity]="msg.severity" [text]="msg.detail"></p-message>\n}`;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (!modified) return t;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
...t,
|
|
66
|
+
text: updated,
|
|
67
|
+
snippets: [],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}();
|
|
71
|
+
}
|
|
72
|
+
}
|