Skip to content

Commit 04d94b3

Browse files
committed
feat(schematics): add new data models for input names and pattern replacements
1 parent 8ec0a4d commit 04d94b3

File tree

5 files changed

+237
-34
lines changed

5 files changed

+237
-34
lines changed

projects/element-ng/schematics/migrations/data/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { ATTRIBUTE_SELECTORS_MIGRATION } from './attribute-selectors.js';
77
import { COMPONENT_NAMES_MIGRATION } from './component-names.js';
88
import { ELEMENT_SELECTORS_MIGRATION } from './element-selectors.js';
9+
import { INPUT_NAMES_MIGRATION } from './input-names.js';
910
import { OUTPUT_NAMES_MIGRATION } from './output-names.js';
1011
import { SYMBOL_REMOVALS_MIGRATION } from './symbol-removals.js';
1112

@@ -15,18 +16,21 @@ export type ElementMigrationData = {
1516
elementSelectorChanges: typeof ELEMENT_SELECTORS_MIGRATION;
1617
symbolRemovalChanges: typeof SYMBOL_REMOVALS_MIGRATION;
1718
outputNameChanges: typeof OUTPUT_NAMES_MIGRATION;
19+
inputNameChanges: typeof INPUT_NAMES_MIGRATION;
1820
};
1921

2022
export const getElementMigrationData = (): ElementMigrationData => ({
2123
attributeSelectorChanges: ATTRIBUTE_SELECTORS_MIGRATION,
2224
componentNameChanges: COMPONENT_NAMES_MIGRATION,
2325
elementSelectorChanges: ELEMENT_SELECTORS_MIGRATION,
2426
symbolRemovalChanges: SYMBOL_REMOVALS_MIGRATION,
25-
outputNameChanges: OUTPUT_NAMES_MIGRATION
27+
outputNameChanges: OUTPUT_NAMES_MIGRATION,
28+
inputNameChanges: INPUT_NAMES_MIGRATION
2629
});
2730

2831
export type { ComponentNamesInstruction } from './component-names.js';
2932
export type { AttributeSelectorInstruction } from './attribute-selectors.js';
3033
export type { ElementSelectorInstruction } from './element-selectors.js';
34+
export type { InputNamesInstruction } from './input-names.js';
3135
export type { OutputNamesInstruction } from './output-names.js';
3236
export type { SymbolRemovalInstruction } from './symbol-removals.js';
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright (c) Siemens 2016 - 2025
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
export interface InputNamesInstruction {
6+
/** Regex to match module import path */
7+
module: RegExp;
8+
/** HTML element selector */
9+
elementSelector: string;
10+
/** HTML attribute selector */
11+
attributeSelector?: string;
12+
/** Array of input renames: [from, to] or [from, [to1, to2]] for splitting */
13+
apiMappings: { replace: string; replaceWith: string | string[] }[];
14+
}
15+
16+
export const INPUT_NAMES_MIGRATION: InputNamesInstruction[] = [
17+
// v48 to v49
18+
{
19+
module: /@(siemens|simpl)\/element-ng/,
20+
elementSelector: 'si-filtered-search',
21+
apiMappings: [{ replace: 'readonly', replaceWith: 'disabled' }]
22+
},
23+
{
24+
module: /@(siemens|simpl)\/charts-ng/,
25+
elementSelector: 'si-chart-gauge',
26+
apiMappings: [
27+
{ replace: 'numberOfDecimals', replaceWith: ['minNumberOfDecimals', 'maxNumberOfDecimals'] }
28+
]
29+
},
30+
{
31+
module: /@(siemens|simpl)\/element-ng(\/(info-page|unauthorized-page))?/,
32+
elementSelector: 'si-unauthorized-page',
33+
apiMappings: [
34+
{ replace: 'heading', replaceWith: 'titleText' },
35+
{ replace: 'subHeading', replaceWith: 'copyText' },
36+
{ replace: 'description', replaceWith: 'instructions' }
37+
]
38+
}
39+
];

projects/element-ng/schematics/migrations/element-migration/element-migration.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@ export const elementMigrationRule = (
4040
let recorder: UpdateRecorder | undefined = undefined;
4141
let printer: ts.Printer | undefined = undefined;
4242

43+
if (migrationData.inputNameChanges) {
44+
recorder ??= tree.beginUpdate(filePath);
45+
46+
for (const change of migrationData.inputNameChanges) {
47+
renameApi({
48+
tree,
49+
recorder,
50+
sourceFile,
51+
filePath,
52+
elementName: change.elementSelector,
53+
apis: change.apiMappings
54+
});
55+
}
56+
}
57+
4358
// Remove the ifs when it grows a bit more and split into multiple functions
4459
if (migrationData.componentNameChanges) {
4560
const changeInstructions = renameIdentifier({
@@ -83,7 +98,8 @@ export const elementMigrationRule = (
8398
sourceFile,
8499
filePath,
85100
fromName: change.replace,
86-
toName: change.replaceWith
101+
toName: change.replaceWith,
102+
defaultAttributes: change.defaultAttributes
87103
});
88104
}
89105
}

projects/element-ng/schematics/utils/template-utils.ts

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,15 @@ const renameElementTagInTemplate = ({
8282
offset,
8383
recorder,
8484
fromName,
85-
toName
85+
toName,
86+
defaultAttributes
8687
}: {
8788
recorder: UpdateRecorder;
8889
template: string;
8990
offset: number;
9091
fromName: string;
9192
toName: string;
93+
defaultAttributes?: { name: string; value: string }[];
9294
}): void => {
9395
findElement(template, element => element.name === fromName).forEach(el => {
9496
recorder.remove(el.startSourceSpan.start.offset + 1 + offset, fromName.length);
@@ -97,6 +99,17 @@ const renameElementTagInTemplate = ({
9799
recorder.remove(el.endSourceSpan?.start.offset + 2 + offset, fromName.length);
98100
recorder.insertLeft(el.endSourceSpan?.start.offset + 2 + offset, toName);
99101
}
102+
103+
if (defaultAttributes && defaultAttributes.length > 0) {
104+
const existingAttrNames = new Set(el.attrs.map(attr => attr.name));
105+
const attrsToAdd = defaultAttributes.filter(attr => !existingAttrNames.has(attr.name));
106+
107+
if (attrsToAdd.length > 0) {
108+
const insertPosition = el.startSourceSpan.start.offset + 1 + offset + toName.length;
109+
const attrsString = attrsToAdd.map(attr => ` ${attr.name}="${attr.value}"`).join('');
110+
recorder.insertLeft(insertPosition, attrsString);
111+
}
112+
}
100113
});
101114
};
102115

@@ -130,15 +143,55 @@ const renameApiInTemplate = ({
130143
template: string;
131144
offset: number;
132145
elementName: string;
133-
apis: { replace: string; replaceWith: string }[];
146+
apis: { replace: string; replaceWith: string | string[] }[];
134147
}): void => {
135148
findElement(template, element => element.name === elementName).forEach(el => {
136149
for (const api of apis) {
137150
el.attrs
138-
.filter(attr => attr.name === api.replace)
151+
.filter(
152+
attr =>
153+
attr.name === api.replace ||
154+
attr.name === `[${api.replace}]` ||
155+
attr.name === `(${api.replace})`
156+
)
139157
.forEach(attr => {
140-
recorder.remove(attr.sourceSpan.start.offset + offset, api.replace.length);
141-
recorder.insertLeft(attr.sourceSpan.start.offset + offset, api.replaceWith);
158+
const hasBrackets = attr.name.startsWith('[') || attr.name.startsWith('(');
159+
const isArray = Array.isArray(api.replaceWith);
160+
161+
if (isArray) {
162+
const valueStart = attr.valueSpan?.start.offset;
163+
const valueEnd = attr.valueSpan?.end.offset;
164+
165+
if (!valueStart || !valueEnd) {
166+
return;
167+
}
168+
169+
const value = template.substring(valueStart, valueEnd);
170+
const attrLength = attr.sourceSpan.toString().length;
171+
172+
// Remove the original attribute
173+
recorder.remove(attr.sourceSpan.start.offset + offset, attrLength);
174+
175+
// Insert new attributes
176+
const newAttrs = (api.replaceWith as string[])
177+
.map((newName: string) => {
178+
const attrName = hasBrackets ? `[${newName}]` : newName;
179+
return `${attrName}="${value}"`;
180+
})
181+
.join(' ');
182+
183+
recorder.insertLeft(attr.sourceSpan.start.offset + offset, newAttrs);
184+
} else {
185+
const newName = api.replaceWith as string;
186+
if (hasBrackets) {
187+
const startOffset = attr.sourceSpan.start.offset + offset + 1;
188+
recorder.remove(startOffset, api.replace.length);
189+
recorder.insertLeft(startOffset, newName);
190+
} else {
191+
recorder.remove(attr.sourceSpan.start.offset + offset, api.replace.length);
192+
recorder.insertLeft(attr.sourceSpan.start.offset + offset, newName);
193+
}
194+
}
142195
});
143196
}
144197
});
@@ -187,6 +240,7 @@ interface RenameElementTagParams {
187240
recorder: UpdateRecorder;
188241
fromName: string;
189242
toName: string;
243+
defaultAttributes?: { name: string; value: string }[];
190244
}
191245

192246
export const renameElementTag = ({
@@ -195,15 +249,17 @@ export const renameElementTag = ({
195249
sourceFile,
196250
recorder,
197251
fromName,
198-
toName
252+
toName,
253+
defaultAttributes
199254
}: RenameElementTagParams): void => {
200255
getInlineTemplates(sourceFile).forEach(template =>
201256
renameElementTagInTemplate({
202257
template: sourceFile.text.substring(template.getStart() + 1, template.getEnd() - 1),
203258
offset: template.getStart() + 1,
204259
toName,
205260
fromName,
206-
recorder
261+
recorder,
262+
defaultAttributes
207263
})
208264
);
209265
getTemplateUrl(sourceFile).forEach(templateUrl => {
@@ -215,7 +271,8 @@ export const renameElementTag = ({
215271
offset: 0,
216272
toName,
217273
fromName,
218-
recorder: templateRecorder
274+
recorder: templateRecorder,
275+
defaultAttributes
219276
});
220277
tree.commitUpdate(templateRecorder);
221278
});
@@ -266,7 +323,7 @@ export const renameApi = ({
266323
sourceFile: ts.SourceFile;
267324
recorder: UpdateRecorder;
268325
elementName: string;
269-
apis: { replace: string; replaceWith: string }[];
326+
apis: { replace: string; replaceWith: string | string[] }[];
270327
}): void => {
271328
getInlineTemplates(sourceFile).forEach(template =>
272329
renameApiInTemplate({

0 commit comments

Comments
 (0)