@progress/kendo-angular-inputs 23.4.0-develop.2 → 23.4.0-develop.3

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.
@@ -0,0 +1,1430 @@
1
+ /**-----------------------------------------------------------------------------------------
2
+ * Copyright © 2026 Progress Software Corporation. All rights reserved.
3
+ * Licensed under commercial license. See LICENSE.md in the project root for more information
4
+ *-------------------------------------------------------------------------------------------*/
5
+ "use strict";
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || function (mod) {
23
+ if (mod && mod.__esModule) return mod;
24
+ var result = {};
25
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
26
+ __setModuleDefault(result, mod);
27
+ return result;
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.tsInterfaceTransformer = exports.tsPropertyValueTransformer = exports.tsPropertyTransformer = exports.tsComponentPropertyRemoval = exports.attributeRemoval = exports.attributeValueUpdate = exports.attributeNameValueUpdate = exports.attributeNameUpdate = exports.eventUpdate = exports.htmlTransformer = exports.blockTextElements = void 0;
31
+ exports.hasKendoInTemplate = hasKendoInTemplate;
32
+ exports.isImportedFromPackage = isImportedFromPackage;
33
+ exports.tsPropertyRemoval = tsPropertyRemoval;
34
+ exports.makePattern = makePattern;
35
+ exports.writeInstructionMarker = writeInstructionMarker;
36
+ exports.isApiChangeTarget = isApiChangeTarget;
37
+ exports.isRenderingChangeTarget = isRenderingChangeTarget;
38
+ const fs = __importStar(require("node:fs"));
39
+ const path = __importStar(require("node:path"));
40
+ exports.blockTextElements = {
41
+ script: true,
42
+ noscript: true,
43
+ style: true,
44
+ pre: true,
45
+ };
46
+ function hasKendoInTemplate(source) {
47
+ const kendoPattern = /(<kendo-[^>\s]+|<[^>]*\s+kendo[A-Z][^>\s]*)/g;
48
+ return kendoPattern.test(source);
49
+ }
50
+ /**
51
+ * Checks if a specific type/interface is imported from the given package
52
+ * @param root - The JSCodeshift collection
53
+ * @param j - JSCodeshift instance
54
+ * @param packageName - The package name to check (e.g., '@progress/kendo-angular-dateinputs')
55
+ * @param typeName - The type/interface name to check (e.g., 'DatePickerComponent')
56
+ * @returns true if the type is imported from the package, false otherwise
57
+ */
58
+ function isImportedFromPackage(root, j, packageName, typeName) {
59
+ let isImported = false;
60
+ root.find(j.ImportDeclaration).forEach((path) => {
61
+ if (path.node.source &&
62
+ path.node.source.value === packageName &&
63
+ path.node.specifiers) {
64
+ path.node.specifiers.forEach((specifier) => {
65
+ if (specifier.type === 'ImportSpecifier' &&
66
+ specifier.imported.type === 'Identifier' &&
67
+ specifier.imported.name === typeName) {
68
+ isImported = true;
69
+ }
70
+ });
71
+ }
72
+ });
73
+ return isImported;
74
+ }
75
+ /**
76
+ * Transforms HTML files and inline templates using a provided transformer function
77
+ *
78
+ * @param fileInfo - The file info containing path and source
79
+ * @param api - JSCodeshift API
80
+ * @param transformerFn - The transformer function to apply to template content
81
+ * @returns The transformed source code or undefined if no changes
82
+ */
83
+ const htmlTransformer = (fileInfo, api, transformerFn) => {
84
+ const filePath = fileInfo.path;
85
+ if (filePath.endsWith('.html')) {
86
+ if (hasKendoInTemplate(fileInfo.source)) {
87
+ let updatedContent = fileInfo.source;
88
+ updatedContent = transformerFn(updatedContent);
89
+ return updatedContent;
90
+ }
91
+ return fileInfo.source;
92
+ }
93
+ const j = api.jscodeshift;
94
+ const rootSource = j(fileInfo.source);
95
+ // Transform inline templates using the provided transformer function
96
+ rootSource
97
+ .find(j.ClassDeclaration)
98
+ .forEach(classPath => {
99
+ const classNode = classPath.node;
100
+ if (!classNode.decorators || !classNode.decorators.length)
101
+ return;
102
+ const componentDecorator = classNode.decorators.find((decorator) => {
103
+ if (decorator.expression && decorator.expression.type === 'CallExpression') {
104
+ const callee = decorator.expression.callee;
105
+ if (callee.type === 'Identifier' && callee.name === 'Component') {
106
+ return true;
107
+ }
108
+ if (callee.type === 'MemberExpression' &&
109
+ callee.property &&
110
+ callee.property.type === 'Identifier' &&
111
+ callee.property.name === 'Component') {
112
+ return true;
113
+ }
114
+ }
115
+ return false;
116
+ });
117
+ if (!componentDecorator || !componentDecorator.expression)
118
+ return;
119
+ const expression = componentDecorator.expression;
120
+ if (expression.type !== 'CallExpression' || !expression.arguments.length)
121
+ return;
122
+ const componentOptions = expression.arguments[0];
123
+ if (componentOptions.type !== 'ObjectExpression')
124
+ return;
125
+ const props = componentOptions.properties || [];
126
+ const templateProp = props.find((prop) => (prop.key.type === 'Identifier' && prop.key.name === 'template') ||
127
+ (prop.key.type === 'StringLiteral' && prop.key.value === 'template'));
128
+ if (templateProp) {
129
+ let originalTemplate;
130
+ if (templateProp.value.type === 'StringLiteral' || templateProp.value.type === 'Literal') {
131
+ originalTemplate = templateProp.value.value;
132
+ }
133
+ else if (templateProp.value.type === 'TemplateLiteral') {
134
+ if (templateProp.value.quasis && templateProp.value.quasis.length) {
135
+ originalTemplate = templateProp.value.quasis
136
+ .map((q) => q.value.cooked || q.value.raw)
137
+ .join('');
138
+ }
139
+ else {
140
+ return;
141
+ }
142
+ }
143
+ else {
144
+ return;
145
+ }
146
+ if (hasKendoInTemplate(originalTemplate)) {
147
+ // Apply the provided transformer function
148
+ const transformedTemplate = transformerFn(originalTemplate);
149
+ if (transformedTemplate !== originalTemplate) {
150
+ if (templateProp.value.type === 'TemplateLiteral') {
151
+ templateProp.value = j.templateLiteral([j.templateElement({ cooked: transformedTemplate, raw: transformedTemplate }, true)], []);
152
+ }
153
+ else {
154
+ templateProp.value.value = transformedTemplate;
155
+ }
156
+ }
157
+ }
158
+ }
159
+ });
160
+ return rootSource.toSource();
161
+ };
162
+ exports.htmlTransformer = htmlTransformer;
163
+ const eventUpdate = (templateContent, tagName, oldEventName, newEventName) => {
164
+ // Escape special regex characters in tag name
165
+ const escapedTagName = tagName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
166
+ // Create regex pattern to match the tag with the old event binding
167
+ // Pattern matches: <tagName ...attributes... (oldEventName)="handler" ...>
168
+ const eventPattern = new RegExp(`(<${escapedTagName}[^>]*\\()${oldEventName}(\\)=)`, 'g');
169
+ // Replace old event name with new event name
170
+ const updatedContent = templateContent.replace(eventPattern, `$1${newEventName}$2`);
171
+ return updatedContent;
172
+ };
173
+ exports.eventUpdate = eventUpdate;
174
+ /**
175
+ * Transforms attributes in inline templates using regex patterns.
176
+ * This function handles bound ([attribute]), static (attribute="value"),
177
+ * two-way binding ([(attribute)]), and boolean (attribute) attributes
178
+ * within a specific tag using regular expressions.
179
+ *
180
+ * @param templateContent - The template string content to transform
181
+ * @param tagName - The HTML tag name to target (e.g., 'kendo-datepicker')
182
+ * @param attributeName - The current attribute name to replace
183
+ * @param newAttributeName - The new attribute name
184
+ * @returns The transformed template content
185
+ */
186
+ const attributeNameUpdate = (templateContent, tagName, attributeName, newAttributeName) => {
187
+ // Escape special regex characters in tag and attribute names
188
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
189
+ const escapedTag = escapeRegex(tagName);
190
+ const escapedAttr = escapeRegex(attributeName);
191
+ const escapedNewAttr = escapeRegex(newAttributeName);
192
+ // Pattern to match the opening tag with the attribute
193
+ // This pattern matches: <tagName ... attribute="value" ... > or <tagName ... [attribute]="value" ... >
194
+ // It captures the tag opening, everything before the attribute, the attribute binding type, and everything after
195
+ const boundAttributePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+)\\[${escapedAttr}\\]\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?')([^>]*?>)`, 'gi');
196
+ const staticAttributePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+)${escapedAttr}\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?')([^>]*?>)`, 'gi');
197
+ // Pattern for two-way data binding [(attribute)]="value"
198
+ const twoWayBindingPattern = new RegExp(`(<${escapedTag}[^>]*?\\s+)\\[\\(${escapedAttr}\\)\\]\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?')([^>]*?>)`, 'gi');
199
+ // Pattern for boolean attributes without values (e.g., <tag attribute>)
200
+ const booleanAttributePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+)${escapedAttr}(\\s+[^>=]|\\s*[/>])`, 'gi');
201
+ // Replace two-way data binding [(attribute)]="value"
202
+ let result = templateContent.replace(twoWayBindingPattern, `$1[(${escapedNewAttr})]=$2$3`);
203
+ // Replace bound attributes [attribute]="value"
204
+ result = result.replace(boundAttributePattern, `$1[${escapedNewAttr}]=$2$3`);
205
+ // Replace static attributes attribute="value"
206
+ result = result.replace(staticAttributePattern, `$1${escapedNewAttr}=$2$3`);
207
+ // Replace boolean attributes attribute (without value)
208
+ result = result.replace(booleanAttributePattern, `$1${escapedNewAttr}$2`);
209
+ return result;
210
+ };
211
+ exports.attributeNameUpdate = attributeNameUpdate;
212
+ /**
213
+ * Transforms bound attributes with value property extraction using regex patterns.
214
+ * This function handles bound attributes and extracts a specific property from object literals
215
+ * or appends the property to variable references.
216
+ *
217
+ * @param templateContent - The template string content to transform
218
+ * @param tagName - The HTML tag name to target (e.g., 'kendo-chat')
219
+ * @param attributeName - The current attribute name to replace
220
+ * @param newAttributeName - The new attribute name
221
+ * @param valueProperty - The property to extract (e.g., 'id')
222
+ * @returns The transformed template content
223
+ */
224
+ const attributeNameValueUpdate = (templateContent, tagName, attributeName, newAttributeName, valueProperty) => {
225
+ // Escape special regex characters in tag and attribute names
226
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
227
+ const escapedTag = escapeRegex(tagName);
228
+ const escapedAttr = escapeRegex(attributeName);
229
+ const escapedNewAttr = escapeRegex(newAttributeName);
230
+ // Pattern to match bound attributes [attribute]="value"
231
+ // This captures: opening tag, bound attribute, and closing tag
232
+ const boundAttributePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+)\\[${escapedAttr}\\]\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?'|[^\\s>]+)([^>]*?>)`, 'gi');
233
+ return templateContent.replace(boundAttributePattern, (match, beforeAttr, value, afterAttr) => {
234
+ // Remove quotes from value to analyze it
235
+ const trimmedValue = value.replace(/^["']|["']$/g, '');
236
+ // Check if it's an object literal (starts with { and ends with })
237
+ if (trimmedValue.trim().startsWith('{') && trimmedValue.trim().endsWith('}')) {
238
+ // For object literals like {id: 'foo'} or {id: 'foo', bar: 'baz'}
239
+ // We need to append .id inside the quotes if the value is quoted
240
+ if (value.match(/^["']/)) {
241
+ // Extract quote type and content, then add .id before the closing quote
242
+ const quoteType = value.charAt(0);
243
+ const content = value.slice(1, -1); // Remove quotes
244
+ const newValue = `${quoteType}${content}.${valueProperty}${quoteType}`;
245
+ return `${beforeAttr}[${escapedNewAttr}]=${newValue}${afterAttr}`;
246
+ }
247
+ else {
248
+ // Unquoted object literal
249
+ const newValue = `${value}.${valueProperty}`;
250
+ return `${beforeAttr}[${escapedNewAttr}]=${newValue}${afterAttr}`;
251
+ }
252
+ }
253
+ else {
254
+ // For variable references like "user"
255
+ // We append .id to the variable name
256
+ const newValue = value.replace(/^["'](.*)["']$/, (_match, content) => {
257
+ return `"${content}.${valueProperty}"`;
258
+ });
259
+ // If it's not quoted (bare variable), add quotes and property
260
+ if (!value.match(/^["']/)) {
261
+ return `${beforeAttr}[${escapedNewAttr}]="${trimmedValue}.${valueProperty}"${afterAttr}`;
262
+ }
263
+ return `${beforeAttr}[${escapedNewAttr}]=${newValue}${afterAttr}`;
264
+ }
265
+ });
266
+ };
267
+ exports.attributeNameValueUpdate = attributeNameValueUpdate;
268
+ /**
269
+ * Updates attribute values in HTML templates using regex patterns.
270
+ * This function handles both bound ([attribute]="'value'") and static (attribute="value") attributes
271
+ * and replaces old values with new values within a specific tag.
272
+ *
273
+ * @param templateContent - The template string content to transform
274
+ * @param tagName - The HTML tag name to target (e.g., 'kendo-toolbar')
275
+ * @param attributeName - The attribute name to target (e.g., 'showIcon')
276
+ * @param oldValue - The old attribute value to replace (e.g., 'overflow')
277
+ * @param newValue - The new attribute value (e.g., 'menu')
278
+ * @returns The transformed template content
279
+ */
280
+ const attributeValueUpdate = (templateContent, tagName, attributeName, oldValue, newValue) => {
281
+ // Escape special regex characters in tag, attribute names, and values
282
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
283
+ const escapedTag = escapeRegex(tagName);
284
+ const escapedAttr = escapeRegex(attributeName);
285
+ const escapedOldValue = escapeRegex(oldValue);
286
+ // Pattern for bound attributes [attribute]="'value'" (double quotes containing single quotes)
287
+ const boundDoubleSinglePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+\\[${escapedAttr}\\]\\s*=\\s*")'${escapedOldValue}'("\\s*[^>]*?>)`, 'gi');
288
+ // Pattern for bound attributes [attribute]="\"value\"" (double quotes containing double quotes)
289
+ const boundDoubleDoublePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+\\[${escapedAttr}\\]\\s*=\\s*")\\\\"${escapedOldValue}\\\\"("\\s*[^>]*?>)`, 'gi');
290
+ // Pattern for bound attributes [attribute]='value' (single quotes containing value)
291
+ const boundSinglePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+\\[${escapedAttr}\\]\\s*=\\s*)'${escapedOldValue}'([^>]*?>)`, 'gi');
292
+ // Pattern for static attributes attribute="value"
293
+ const staticAttributePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+${escapedAttr}\\s*=\\s*["'])${escapedOldValue}(["'][^>]*?>)`, 'gi');
294
+ // Replace bound attributes [attribute]="'overflow'" -> [attribute]="'menu'"
295
+ let result = templateContent.replace(boundDoubleSinglePattern, `$1'${newValue}'$2`);
296
+ // Replace bound attributes [attribute]="\"overflow\"" -> [attribute]="\"menu\""
297
+ result = result.replace(boundDoubleDoublePattern, `$1\\"${newValue}\\"$2`);
298
+ // Replace bound attributes [attribute]='overflow' -> [attribute]='menu'
299
+ result = result.replace(boundSinglePattern, `$1'${newValue}'$2`);
300
+ // Replace static attributes showIcon="overflow" -> showIcon="menu"
301
+ result = result.replace(staticAttributePattern, `$1${newValue}$2`);
302
+ return result;
303
+ };
304
+ exports.attributeValueUpdate = attributeValueUpdate;
305
+ /**
306
+ * Removes attributes from HTML templates using regex patterns.
307
+ * This function can remove entire attributes or specific properties from object literal attributes.
308
+ *
309
+ * @param templateContent - The template string content to transform
310
+ * @param tagName - The HTML tag name to target (e.g., 'kendo-chat')
311
+ * @param attributeName - The attribute name to remove or modify
312
+ * @param propertyToRemove - Optional: specific property to remove from object literal attributes
313
+ * @returns The transformed template content
314
+ */
315
+ const attributeRemoval = (templateContent, tagName, attributeName, propertyToRemove) => {
316
+ // Escape special regex characters in tag and attribute names
317
+ const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
318
+ const escapedTag = escapeRegex(tagName);
319
+ const escapedAttr = escapeRegex(attributeName);
320
+ // If no propertyToRemove is specified, remove the entire attribute
321
+ if (!propertyToRemove) {
322
+ // Remove bound attributes [attribute]="value"
323
+ const boundAttributePattern = new RegExp(`(\\s+)\\[${escapedAttr}\\]\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?'|[^\\s>]+)`, 'gi');
324
+ // Remove static attributes attribute="value"
325
+ const staticAttributePattern = new RegExp(`(\\s+)${escapedAttr}\\s*=\\s*("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?'|[^\\s>]+)`, 'gi');
326
+ // Apply removals
327
+ let result = templateContent.replace(boundAttributePattern, '');
328
+ result = result.replace(staticAttributePattern, '');
329
+ return result;
330
+ }
331
+ // Remove specific property from object literal attributes
332
+ const boundAttributePattern = new RegExp(`(<${escapedTag}[^>]*?\\s+\\[${escapedAttr}\\]\\s*=\\s*)("(?:[^"\\\\]|\\\\.)*?"|'(?:[^'\\\\]|\\\\.)*?'|[^\\s>]+)([^>]*?>)`, 'gi');
333
+ return templateContent.replace(boundAttributePattern, (match, beforeAttr, value, afterAttr) => {
334
+ // Remove quotes from value to analyze it
335
+ const trimmedValue = value.replace(/^["']|["']$/g, '');
336
+ // Check if it's an object literal (starts with { and ends with })
337
+ if (trimmedValue.trim().startsWith('{') && trimmedValue.trim().endsWith('}')) {
338
+ const objectLiteral = trimmedValue.trim();
339
+ // Create regex to remove the specific property
340
+ const propRegex = new RegExp(`\\s*${escapeRegex(propertyToRemove)}\\s*:\\s*[^,}]+\\s*(,\\s*)?`, 'g');
341
+ let newObjectLiteral = objectLiteral.replace(propRegex, '');
342
+ // Clean up trailing comma before closing brace
343
+ newObjectLiteral = newObjectLiteral.replace(/,\s*}$/, '}');
344
+ // If the object is now empty, remove the entire attribute
345
+ if (newObjectLiteral === '{}') {
346
+ return beforeAttr.replace(/\s+\[[^\]]+\]\s*=\s*$/, '') + afterAttr;
347
+ }
348
+ else {
349
+ // Restore quotes if the original value was quoted
350
+ if (value.match(/^["']/)) {
351
+ const quoteType = value.charAt(0);
352
+ return `${beforeAttr}${quoteType}${newObjectLiteral}${quoteType}${afterAttr}`;
353
+ }
354
+ else {
355
+ return `${beforeAttr}${newObjectLiteral}${afterAttr}`;
356
+ }
357
+ }
358
+ }
359
+ else {
360
+ // For non-object literals, we can't remove a specific property
361
+ console.warn(`Cannot remove property '${propertyToRemove}' from non-object literal: ${value}`);
362
+ return match; // Return unchanged
363
+ }
364
+ });
365
+ };
366
+ exports.attributeRemoval = attributeRemoval;
367
+ function tsPropertyRemoval(source, rootSource, j, packageName, typeName, propertyName) {
368
+ if (source.includes(typeName)) {
369
+ if (!isImportedFromPackage(rootSource, j, packageName, typeName)) {
370
+ return;
371
+ }
372
+ const typeVariables = new Set();
373
+ // Find function parameters of target type
374
+ rootSource.find(j.Function).forEach((path) => {
375
+ if (path.node.params) {
376
+ path.node.params.forEach((param) => {
377
+ if (param.type === 'Identifier' &&
378
+ param.typeAnnotation &&
379
+ param.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
380
+ param.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
381
+ param.typeAnnotation.typeAnnotation.typeName.name === typeName) {
382
+ typeVariables.add(param.name);
383
+ }
384
+ });
385
+ }
386
+ });
387
+ // Find local variables of target type
388
+ rootSource.find(j.VariableDeclarator).forEach((path) => {
389
+ if (path.node.id.type === 'Identifier' &&
390
+ path.node.id.typeAnnotation &&
391
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
392
+ path.node.id.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
393
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name === typeName) {
394
+ typeVariables.add(path.node.id.name);
395
+ }
396
+ });
397
+ // Find class properties of target type
398
+ rootSource.find(j.ClassProperty).forEach((path) => {
399
+ if (path.node.key.type === 'Identifier' &&
400
+ path.node.typeAnnotation &&
401
+ path.node.typeAnnotation.typeAnnotation &&
402
+ path.node.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
403
+ path.node.typeAnnotation.typeAnnotation.typeName &&
404
+ path.node.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
405
+ path.node.typeAnnotation.typeAnnotation.typeName.name === typeName) {
406
+ typeVariables.add(path.node.key.name);
407
+ }
408
+ });
409
+ // Handle class properties with object expressions
410
+ rootSource
411
+ .find(j.ClassProperty)
412
+ .filter((path) => {
413
+ // Check if the property has the correct type annotation
414
+ return !!(path.node.typeAnnotation &&
415
+ path.node.typeAnnotation.typeAnnotation &&
416
+ path.node.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
417
+ path.node.typeAnnotation.typeAnnotation.typeName &&
418
+ path.node.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
419
+ path.node.typeAnnotation.typeAnnotation.typeName.name === typeName);
420
+ })
421
+ .forEach((path) => {
422
+ if (path.node.value && path.node.value.type === 'ObjectExpression') {
423
+ const properties = path.node.value.properties;
424
+ const propIndex = properties.findIndex((p) => p.type === 'ObjectProperty' &&
425
+ p.key &&
426
+ p.key.type === 'Identifier' &&
427
+ p.key.name === propertyName);
428
+ if (propIndex !== -1) {
429
+ // Just remove the property, leaving an empty object if it was the only one
430
+ properties.splice(propIndex, 1);
431
+ }
432
+ }
433
+ });
434
+ // Handle variable declarations with object literal initializers
435
+ // e.g., const modelFields: ConversationalUIModelFields = { pinnedByField: 'value', id: 'bar' };
436
+ rootSource
437
+ .find(j.VariableDeclarator, {
438
+ id: {
439
+ type: 'Identifier',
440
+ typeAnnotation: {
441
+ typeAnnotation: {
442
+ type: 'TSTypeReference',
443
+ typeName: {
444
+ name: typeName,
445
+ },
446
+ },
447
+ },
448
+ },
449
+ })
450
+ .forEach((path) => {
451
+ if (path.node.init && path.node.init.type === 'ObjectExpression') {
452
+ const properties = path.node.init.properties;
453
+ const propIndex = properties.findIndex((p) => p.type === 'ObjectProperty' &&
454
+ p.key &&
455
+ p.key.type === 'Identifier' &&
456
+ p.key.name === propertyName);
457
+ if (propIndex !== -1) {
458
+ // Just remove the property, leaving an empty object if it was the only one
459
+ properties.splice(propIndex, 1);
460
+ }
461
+ }
462
+ });
463
+ // Handle return statements with object literals
464
+ rootSource.find(j.ReturnStatement).forEach((path) => {
465
+ if (path.node.argument && path.node.argument.type === 'ObjectExpression') {
466
+ const properties = path.node.argument.properties;
467
+ const propIndex = properties.findIndex((p) => p.type === 'ObjectProperty' &&
468
+ p.key &&
469
+ p.key.type === 'Identifier' &&
470
+ p.key.name === propertyName);
471
+ if (propIndex !== -1) {
472
+ properties.splice(propIndex, 1);
473
+ }
474
+ }
475
+ });
476
+ // Handle direct member expression assignments to properties of variables/parameters
477
+ // e.g., fields.pinnedByField = value; or this.chatModelFields.pinnedByField = value;
478
+ rootSource
479
+ .find(j.AssignmentExpression)
480
+ .filter((path) => {
481
+ const { left } = path.node;
482
+ if (left.type === 'MemberExpression' &&
483
+ left.property.type === 'Identifier' &&
484
+ left.property.name === propertyName) {
485
+ // Check if the object is a variable/parameter of our type
486
+ if (left.object.type === 'Identifier' && typeVariables.has(left.object.name)) {
487
+ return true;
488
+ }
489
+ // Check if it's this.property where property is of our type
490
+ if (left.object.type === 'MemberExpression' &&
491
+ left.object.object.type === 'ThisExpression' &&
492
+ left.object.property.type === 'Identifier' &&
493
+ typeVariables.has(left.object.property.name)) {
494
+ return true;
495
+ }
496
+ // Check for type assertions: (expr as Type).property
497
+ if (left.object.type === 'TSAsExpression' &&
498
+ left.object.typeAnnotation.type === 'TSTypeReference' &&
499
+ left.object.typeAnnotation.typeName?.type === 'Identifier' &&
500
+ left.object.typeAnnotation.typeName.name === typeName) {
501
+ return true;
502
+ }
503
+ }
504
+ return false;
505
+ })
506
+ .forEach((path) => {
507
+ // Remove the entire expression statement
508
+ const statement = j(path).closest(j.ExpressionStatement);
509
+ if (statement.length > 0) {
510
+ statement.remove();
511
+ }
512
+ });
513
+ // Handle nested member expressions like chatConfig.chat.modelFields.pinnedByField
514
+ rootSource
515
+ .find(j.AssignmentExpression, {
516
+ left: {
517
+ type: 'MemberExpression',
518
+ object: {
519
+ type: 'MemberExpression',
520
+ },
521
+ property: {
522
+ name: propertyName,
523
+ },
524
+ },
525
+ })
526
+ .forEach((path) => {
527
+ j(path).closest(j.ExpressionStatement).remove();
528
+ });
529
+ return rootSource;
530
+ }
531
+ }
532
+ const tsComponentPropertyRemoval = (source, root, j, packageName, componentType, componentProperty, propertyToRemove) => {
533
+ if (source.includes(componentType)) {
534
+ // Check if componentType is imported from the specified package
535
+ if (!isImportedFromPackage(root, j, packageName, componentType)) {
536
+ return;
537
+ }
538
+ // Find all class properties that are of type componentType
539
+ const properties = new Set();
540
+ root.find(j.ClassProperty, {
541
+ typeAnnotation: {
542
+ typeAnnotation: {
543
+ typeName: {
544
+ name: componentType,
545
+ },
546
+ },
547
+ },
548
+ }).forEach((path) => {
549
+ if (path.node.key.type === 'Identifier') {
550
+ properties.add(path.node.key.name);
551
+ }
552
+ });
553
+ // Find function parameters of type componentType
554
+ const parameters = new Set();
555
+ root.find(j.FunctionDeclaration).forEach((path) => {
556
+ if (path.node.params) {
557
+ path.node.params.forEach((param) => {
558
+ if (param.type === 'Identifier' &&
559
+ param.typeAnnotation &&
560
+ param.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
561
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
562
+ param.typeAnnotation.typeAnnotation.typeName.name === componentType) {
563
+ parameters.add(param.name);
564
+ }
565
+ });
566
+ }
567
+ });
568
+ // Also check method declarations in classes
569
+ root.find(j.ClassMethod).forEach((path) => {
570
+ if (path.node.params) {
571
+ path.node.params.forEach((param) => {
572
+ if (param.type === 'Identifier' &&
573
+ param.typeAnnotation &&
574
+ param.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
575
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
576
+ param.typeAnnotation.typeAnnotation.typeName.name === componentType) {
577
+ parameters.add(param.name);
578
+ }
579
+ });
580
+ }
581
+ });
582
+ // Also check arrow functions
583
+ root.find(j.ArrowFunctionExpression).forEach((path) => {
584
+ if (path.node.params) {
585
+ path.node.params.forEach((param) => {
586
+ if (param.type === 'Identifier' &&
587
+ param.typeAnnotation &&
588
+ param.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
589
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
590
+ param.typeAnnotation.typeAnnotation.typeName.name === componentType) {
591
+ parameters.add(param.name);
592
+ }
593
+ });
594
+ }
595
+ });
596
+ // Find local variable declarations of type componentType
597
+ const localVariables = new Set();
598
+ root.find(j.VariableDeclarator).forEach((path) => {
599
+ if (path.node.id.type === 'Identifier' &&
600
+ path.node.id.typeAnnotation &&
601
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
602
+ path.node.id.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
603
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name === componentType) {
604
+ localVariables.add(path.node.id.name);
605
+ }
606
+ });
607
+ // Find array variables of type componentType[]
608
+ // This handles cases like: const arr: ChatComponent[] = [...]; arr[0].property = value;
609
+ const arrayVariables = new Set();
610
+ root.find(j.VariableDeclarator).forEach((path) => {
611
+ if (path.node.id.type === 'Identifier' &&
612
+ path.node.id.typeAnnotation &&
613
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSArrayType' &&
614
+ path.node.id.typeAnnotation.typeAnnotation.elementType?.type === 'TSTypeReference' &&
615
+ path.node.id.typeAnnotation.typeAnnotation.elementType.typeName?.type === 'Identifier' &&
616
+ path.node.id.typeAnnotation.typeAnnotation.elementType.typeName.name === componentType) {
617
+ arrayVariables.add(path.node.id.name);
618
+ }
619
+ });
620
+ // Find object properties that have componentType (e.g., {chat: ChatComponent})
621
+ // This handles cases like: const config: {chat: ChatComponent} = {...}; config.chat.property = value;
622
+ const objectProperties = new Map(); // Maps variable name to property name
623
+ root.find(j.VariableDeclarator).forEach((path) => {
624
+ if (path.node.id.type === 'Identifier' &&
625
+ path.node.id.typeAnnotation &&
626
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSTypeLiteral') {
627
+ const varName = path.node.id.name;
628
+ const members = path.node.id.typeAnnotation.typeAnnotation.members;
629
+ members.forEach((member) => {
630
+ if (member.type === 'TSPropertySignature' &&
631
+ member.key &&
632
+ member.key.type === 'Identifier' &&
633
+ member.typeAnnotation &&
634
+ member.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
635
+ member.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
636
+ member.typeAnnotation.typeAnnotation.typeName.name === componentType) {
637
+ if (!objectProperties.has(varName)) {
638
+ objectProperties.set(varName, []);
639
+ }
640
+ objectProperties.get(varName).push(member.key.name);
641
+ }
642
+ });
643
+ }
644
+ });
645
+ // If no propertyToRemove is specified, remove the entire componentProperty
646
+ if (!propertyToRemove) {
647
+ // Handle direct property assignments like: foo.scrollable = value;
648
+ root.find(j.AssignmentExpression)
649
+ .filter((path) => {
650
+ const { left } = path.value;
651
+ // Check if this assigns to component.componentProperty
652
+ if (left &&
653
+ left.type === 'MemberExpression' &&
654
+ left.property &&
655
+ left.property.name === componentProperty) {
656
+ // Check if the base object is our component type
657
+ return isComponentTypeMatch(root, j, left.object, componentType);
658
+ }
659
+ return false;
660
+ })
661
+ .forEach((path) => {
662
+ // Remove the entire statement
663
+ j(path).closest(j.ExpressionStatement).remove();
664
+ });
665
+ return root;
666
+ }
667
+ // CASE 1: Handle direct property assignments like: foo.scrollable.mouseScrollSpeed = 3000;
668
+ root.find(j.AssignmentExpression)
669
+ .filter((path) => {
670
+ const { left } = path.value;
671
+ // Check if this is a member expression assignment
672
+ if (left && left.type === 'MemberExpression') {
673
+ // Check if we're accessing the property to remove
674
+ if (left.property && left.property.name === propertyToRemove) {
675
+ // Check if we're accessing it from component.componentProperty
676
+ const obj = left.object;
677
+ if (obj &&
678
+ obj.type === 'MemberExpression' &&
679
+ obj.property &&
680
+ obj.property.name === componentProperty) {
681
+ // Now check if the base object is our component type (includes all cases: this, parameters, variables, casts)
682
+ return isComponentTypeMatch(root, j, obj.object, componentType);
683
+ }
684
+ }
685
+ }
686
+ return false;
687
+ })
688
+ .forEach((path) => {
689
+ // Remove the entire statement
690
+ j(path).closest(j.ExpressionStatement).remove();
691
+ });
692
+ // CASE 2 & 3: Handle object assignments like: foo.scrollable = { mouseScrollSpeed: 3000, ... };
693
+ root.find(j.AssignmentExpression)
694
+ .filter((path) => {
695
+ const { left, right } = path.value;
696
+ // Check if this assigns to component.componentProperty
697
+ if (left &&
698
+ left.type === 'MemberExpression' &&
699
+ left.property &&
700
+ left.property.name === componentProperty &&
701
+ right &&
702
+ right.type === 'ObjectExpression') {
703
+ // Check if the base object is our component type (includes all cases: this, parameters, variables, casts)
704
+ return isComponentTypeMatch(root, j, left.object, componentType);
705
+ }
706
+ return false;
707
+ })
708
+ .forEach((path) => {
709
+ const properties = path.value.right.properties;
710
+ // Find the property we want to remove
711
+ const propIndex = properties.findIndex((p) => p &&
712
+ p.type === 'ObjectProperty' &&
713
+ p.key &&
714
+ p.key.type === 'Identifier' &&
715
+ p.key.name === propertyToRemove);
716
+ if (propIndex !== -1) {
717
+ // Case 2: If it's the only property, remove the entire statement
718
+ if (properties.length === 1) {
719
+ j(path).closest(j.ExpressionStatement).remove();
720
+ }
721
+ // Case 3: If there are other properties, just remove this one property
722
+ else {
723
+ properties.splice(propIndex, 1);
724
+ }
725
+ }
726
+ });
727
+ return root;
728
+ }
729
+ };
730
+ exports.tsComponentPropertyRemoval = tsComponentPropertyRemoval;
731
+ const tsPropertyTransformer = (source, root, j, packageName, componentType, propertyName, newPropertyName, valueProperty) => {
732
+ if (source.includes(componentType)) {
733
+ // Check if componentType is imported from the specified package
734
+ if (!isImportedFromPackage(root, j, packageName, componentType)) {
735
+ return;
736
+ }
737
+ // Find all class properties that are of type componentType
738
+ const properties = new Set();
739
+ // Find properties with type annotations
740
+ root.find(j.ClassProperty, {
741
+ typeAnnotation: {
742
+ typeAnnotation: {
743
+ typeName: {
744
+ name: componentType,
745
+ },
746
+ },
747
+ },
748
+ }).forEach((path) => {
749
+ if (path.node.key.type === 'Identifier') {
750
+ properties.add(path.node.key.name);
751
+ }
752
+ });
753
+ // Find function parameters of type componentType
754
+ const parameters = new Set();
755
+ root.find(j.FunctionDeclaration).forEach((path) => {
756
+ if (path.node.params) {
757
+ path.node.params.forEach((param) => {
758
+ if (param.type === 'Identifier' &&
759
+ param.typeAnnotation &&
760
+ param.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
761
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
762
+ param.typeAnnotation.typeAnnotation.typeName.name === componentType) {
763
+ parameters.add(param.name);
764
+ }
765
+ });
766
+ }
767
+ });
768
+ // Also check method declarations in classes
769
+ root.find(j.ClassMethod).forEach((path) => {
770
+ if (path.node.params) {
771
+ path.node.params.forEach((param) => {
772
+ if (param.type === 'Identifier' &&
773
+ param.typeAnnotation &&
774
+ param.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
775
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
776
+ param.typeAnnotation.typeAnnotation.typeName.name === componentType) {
777
+ parameters.add(param.name);
778
+ }
779
+ });
780
+ }
781
+ });
782
+ // Also check arrow functions
783
+ root.find(j.ArrowFunctionExpression).forEach((path) => {
784
+ if (path.node.params) {
785
+ path.node.params.forEach((param) => {
786
+ if (param.type === 'Identifier' &&
787
+ param.typeAnnotation &&
788
+ param.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
789
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
790
+ param.typeAnnotation.typeAnnotation.typeName.name === componentType) {
791
+ parameters.add(param.name);
792
+ }
793
+ });
794
+ }
795
+ });
796
+ // Find local variable declarations of type componentType
797
+ const localVariables = new Set();
798
+ root.find(j.VariableDeclarator).forEach((path) => {
799
+ if (path.node.id.type === 'Identifier' &&
800
+ path.node.id.typeAnnotation &&
801
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
802
+ path.node.id.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
803
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name === componentType) {
804
+ localVariables.add(path.node.id.name);
805
+ }
806
+ });
807
+ // Find array variables of type componentType[]
808
+ // This handles cases like: const arr: ChatComponent[] = [...]; arr[0].property = value;
809
+ const arrayVariables = new Set();
810
+ root.find(j.VariableDeclarator).forEach((path) => {
811
+ if (path.node.id.type === 'Identifier' &&
812
+ path.node.id.typeAnnotation &&
813
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSArrayType' &&
814
+ path.node.id.typeAnnotation.typeAnnotation.elementType?.type === 'TSTypeReference' &&
815
+ path.node.id.typeAnnotation.typeAnnotation.elementType.typeName?.type === 'Identifier' &&
816
+ path.node.id.typeAnnotation.typeAnnotation.elementType.typeName.name === componentType) {
817
+ arrayVariables.add(path.node.id.name);
818
+ }
819
+ });
820
+ // Find object properties that have componentType (e.g., {chat: ChatComponent})
821
+ // This handles cases like: const config: {chat: ChatComponent} = {...}; config.chat.property = value;
822
+ const objectProperties = new Map(); // Maps variable name to property names
823
+ root.find(j.VariableDeclarator).forEach((path) => {
824
+ if (path.node.id.type === 'Identifier' &&
825
+ path.node.id.typeAnnotation &&
826
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSTypeLiteral') {
827
+ const varName = path.node.id.name;
828
+ const members = path.node.id.typeAnnotation.typeAnnotation.members;
829
+ members.forEach((member) => {
830
+ if (member.type === 'TSPropertySignature' &&
831
+ member.key &&
832
+ member.key.type === 'Identifier' &&
833
+ member.typeAnnotation &&
834
+ member.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
835
+ member.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
836
+ member.typeAnnotation.typeAnnotation.typeName.name === componentType) {
837
+ if (!objectProperties.has(varName)) {
838
+ objectProperties.set(varName, []);
839
+ }
840
+ objectProperties.get(varName).push(member.key.name);
841
+ }
842
+ });
843
+ }
844
+ });
845
+ // Helper function to check if a node is a componentType instance
846
+ const isComponentTypeInstance = (node) => {
847
+ // Direct identifier (parameter or local variable)
848
+ if (node.type === 'Identifier') {
849
+ return parameters.has(node.name) || localVariables.has(node.name);
850
+ }
851
+ // this.property where property is of componentType
852
+ if (node.type === 'MemberExpression' && node.property.type === 'Identifier') {
853
+ if (node.object.type === 'ThisExpression' && properties.has(node.property.name)) {
854
+ return true;
855
+ }
856
+ // Handle nested object properties: objectVar.propertyName where propertyName is of componentType
857
+ if (node.object.type === 'Identifier') {
858
+ const objName = node.object.name;
859
+ const propName = node.property.name;
860
+ if (objectProperties.has(objName)) {
861
+ const props = objectProperties.get(objName);
862
+ return props.includes(propName);
863
+ }
864
+ }
865
+ }
866
+ // Array element access: arrayVar[index]
867
+ if (node.type === 'MemberExpression' &&
868
+ node.object.type === 'Identifier' &&
869
+ arrayVariables.has(node.object.name)) {
870
+ return true;
871
+ }
872
+ // TypeScript type assertions like (this.componentProperty as ComponentType)
873
+ if (node.type === 'TSAsExpression') {
874
+ if (node.typeAnnotation &&
875
+ node.typeAnnotation.type === 'TSTypeReference' &&
876
+ node.typeAnnotation.typeName &&
877
+ node.typeAnnotation.typeName.type === 'Identifier' &&
878
+ node.typeAnnotation.typeName.name === componentType) {
879
+ return true;
880
+ }
881
+ }
882
+ return false;
883
+ };
884
+ // Find all member expressions where propertyName is accessed on any componentType instance
885
+ root.find(j.MemberExpression, {
886
+ property: {
887
+ type: 'Identifier',
888
+ name: propertyName,
889
+ },
890
+ })
891
+ .filter((path) => {
892
+ return isComponentTypeInstance(path.node.object);
893
+ })
894
+ .forEach((path) => {
895
+ // Replace old property name with new property name
896
+ if (path.node.property.type === 'Identifier') {
897
+ path.node.property.name = newPropertyName;
898
+ }
899
+ // If valueProperty is specified and this is part of an assignment,
900
+ // we need to also modify the right-hand side of the assignment
901
+ if (valueProperty) {
902
+ const assignmentExpression = path.parent;
903
+ if (assignmentExpression &&
904
+ assignmentExpression.value &&
905
+ assignmentExpression.value.type === 'AssignmentExpression' &&
906
+ assignmentExpression.value.left === path.node) {
907
+ const rightSide = assignmentExpression.value.right;
908
+ // Case 1: Right side is a member expression (e.g., this.user, obj.user) -> transform to this.user.id, obj.user.id
909
+ // Case 2: Right side is an identifier (e.g., user, foo) -> transform to user.id, foo.id
910
+ if (rightSide.type === 'MemberExpression' || rightSide.type === 'Identifier') {
911
+ const newRightSide = j.memberExpression(rightSide, j.identifier(valueProperty));
912
+ assignmentExpression.value.right = newRightSide;
913
+ }
914
+ // Case 3: Right side is object literal -> extract the valueProperty value
915
+ else if (rightSide.type === 'ObjectExpression') {
916
+ // Find the property that matches valueProperty
917
+ const targetProperty = rightSide.properties.find((prop) => prop.type === 'ObjectProperty' &&
918
+ prop.key &&
919
+ prop.key.type === 'Identifier' &&
920
+ prop.key.name === valueProperty);
921
+ if (targetProperty) {
922
+ // Replace the entire object literal with just the value of the target property
923
+ assignmentExpression.value.right = targetProperty.value;
924
+ }
925
+ }
926
+ }
927
+ }
928
+ });
929
+ // Transform object literal properties in variable declarations and assignments
930
+ // This handles cases like: const obj: ComponentType = { oldProperty: 'value' }
931
+ root.find(j.VariableDeclarator)
932
+ .filter((path) => {
933
+ // Check if the variable has the componentType type annotation
934
+ return Boolean(path.node.id.type === 'Identifier' &&
935
+ path.node.id.typeAnnotation &&
936
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
937
+ path.node.id.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
938
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name === componentType);
939
+ })
940
+ .forEach((path) => {
941
+ // Check if the initializer is an object expression
942
+ if (path.node.init && path.node.init.type === 'ObjectExpression') {
943
+ path.node.init.properties.forEach((prop) => {
944
+ // Rename the property if it matches
945
+ if (prop.type === 'ObjectProperty' &&
946
+ prop.key &&
947
+ prop.key.type === 'Identifier' &&
948
+ prop.key.name === propertyName) {
949
+ prop.key.name = newPropertyName;
950
+ }
951
+ });
952
+ }
953
+ });
954
+ // Transform object literal properties in class properties
955
+ // This handles cases like: customMessages: ComponentType = { oldProperty: 'value' }
956
+ root.find(j.ClassProperty)
957
+ .filter((path) => {
958
+ // Check if the property has the componentType type annotation
959
+ return Boolean(path.node.typeAnnotation &&
960
+ path.node.typeAnnotation.typeAnnotation?.type === 'TSTypeReference' &&
961
+ path.node.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
962
+ path.node.typeAnnotation.typeAnnotation.typeName.name === componentType);
963
+ })
964
+ .forEach((path) => {
965
+ // Check if the value is an object expression
966
+ if (path.node.value && path.node.value.type === 'ObjectExpression') {
967
+ path.node.value.properties.forEach((prop) => {
968
+ // Rename the property if it matches
969
+ if (prop.type === 'ObjectProperty' &&
970
+ prop.key &&
971
+ prop.key.type === 'Identifier' &&
972
+ prop.key.name === propertyName) {
973
+ prop.key.name = newPropertyName;
974
+ }
975
+ });
976
+ }
977
+ });
978
+ // Transform object literal properties in assignment expressions
979
+ // This handles cases like: this.obj = { oldProperty: 'value' }
980
+ root.find(j.AssignmentExpression)
981
+ .filter((path) => {
982
+ // Check if we're assigning an object literal
983
+ return path.node.right.type === 'ObjectExpression';
984
+ })
985
+ .forEach((path) => {
986
+ // We need to determine if the left side is of componentType
987
+ // This is more complex as we need to check the type of the assignment target
988
+ const leftSide = path.node.left;
989
+ let isTargetComponentType = false;
990
+ // Check if it's a property that we know is of componentType
991
+ if (leftSide.type === 'MemberExpression' && leftSide.property.type === 'Identifier') {
992
+ if (leftSide.object.type === 'ThisExpression' && properties.has(leftSide.property.name)) {
993
+ isTargetComponentType = true;
994
+ }
995
+ else if (leftSide.object.type === 'Identifier' && localVariables.has(leftSide.object.name)) {
996
+ isTargetComponentType = true;
997
+ }
998
+ }
999
+ else if (leftSide.type === 'Identifier') {
1000
+ isTargetComponentType = localVariables.has(leftSide.name) || parameters.has(leftSide.name);
1001
+ }
1002
+ if (isTargetComponentType && path.node.right.type === 'ObjectExpression') {
1003
+ path.node.right.properties.forEach((prop) => {
1004
+ // Rename the property if it matches
1005
+ if (prop.type === 'ObjectProperty' &&
1006
+ prop.key &&
1007
+ prop.key.type === 'Identifier' &&
1008
+ prop.key.name === propertyName) {
1009
+ prop.key.name = newPropertyName;
1010
+ }
1011
+ });
1012
+ }
1013
+ });
1014
+ }
1015
+ };
1016
+ exports.tsPropertyTransformer = tsPropertyTransformer;
1017
+ const tsPropertyValueTransformer = (source, root, j, packageName, typeName, oldValue, newValue) => {
1018
+ if (source.includes(typeName)) {
1019
+ // Check if typeName is imported from the specified package
1020
+ if (!isImportedFromPackage(root, j, packageName, typeName)) {
1021
+ return;
1022
+ }
1023
+ root.find(j.ClassProperty)
1024
+ .filter((path) => {
1025
+ if (path.node.typeAnnotation?.typeAnnotation &&
1026
+ path.node.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
1027
+ path.node.typeAnnotation.typeAnnotation.typeName &&
1028
+ path.node.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
1029
+ path.node.typeAnnotation.typeAnnotation.typeName.name === typeName) {
1030
+ return true;
1031
+ }
1032
+ return false;
1033
+ })
1034
+ .forEach((path) => {
1035
+ if (path.node.value && path.node.value.type === 'StringLiteral' && path.node.value.value === oldValue) {
1036
+ path.node.value.value = newValue;
1037
+ }
1038
+ });
1039
+ root.find(j.VariableDeclarator)
1040
+ .filter((path) => {
1041
+ if (path.node.id.type === 'Identifier' &&
1042
+ path.node.id.typeAnnotation?.typeAnnotation &&
1043
+ path.node.id.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
1044
+ path.node.id.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
1045
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name === typeName) {
1046
+ return true;
1047
+ }
1048
+ return false;
1049
+ })
1050
+ .forEach((path) => {
1051
+ if (path.node.id.type === 'Identifier') {
1052
+ if (path.node.init && path.node.init.type === 'StringLiteral' && path.node.init.value === oldValue) {
1053
+ path.node.init.value = newValue;
1054
+ }
1055
+ }
1056
+ });
1057
+ root.find(j.AssignmentExpression)
1058
+ .filter((path) => {
1059
+ return path.node.right.type === 'StringLiteral' && path.node.right.value === oldValue;
1060
+ })
1061
+ .forEach((path) => {
1062
+ path.node.right.value = newValue;
1063
+ });
1064
+ root.find(j.JSXAttribute, {
1065
+ value: {
1066
+ type: 'StringLiteral',
1067
+ value: oldValue,
1068
+ },
1069
+ }).forEach((path) => {
1070
+ if (path.node.value?.type === 'StringLiteral') {
1071
+ path.node.value.value = newValue;
1072
+ }
1073
+ });
1074
+ }
1075
+ };
1076
+ exports.tsPropertyValueTransformer = tsPropertyValueTransformer;
1077
+ const tsInterfaceTransformer = (fileInfo, rootSource, j, packageName, interfaceName, newName) => {
1078
+ const source = fileInfo.source;
1079
+ if (source.includes(interfaceName)) {
1080
+ // Check if interface is imported from the specified package and rename it
1081
+ let isImported = false;
1082
+ rootSource.find(j.ImportDeclaration).forEach((path) => {
1083
+ if (path.node.source &&
1084
+ path.node.source.value === packageName &&
1085
+ path.node.specifiers) {
1086
+ path.node.specifiers.forEach((specifier) => {
1087
+ if (specifier.type === 'ImportSpecifier' &&
1088
+ specifier.imported.type === 'Identifier' &&
1089
+ specifier.imported.name === interfaceName) {
1090
+ isImported = true;
1091
+ specifier.imported.name = newName;
1092
+ }
1093
+ });
1094
+ }
1095
+ });
1096
+ if (!isImported) {
1097
+ return;
1098
+ }
1099
+ rootSource.find(j.ClassProperty).forEach((path) => {
1100
+ if (path.node.typeAnnotation &&
1101
+ path.node.typeAnnotation.typeAnnotation &&
1102
+ path.node.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
1103
+ path.node.typeAnnotation.typeAnnotation.typeName &&
1104
+ path.node.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
1105
+ path.node.typeAnnotation.typeAnnotation.typeName.name === interfaceName) {
1106
+ path.node.typeAnnotation.typeAnnotation.typeName.name = newName;
1107
+ }
1108
+ });
1109
+ rootSource.find(j.VariableDeclarator).forEach((path) => {
1110
+ if (path.node.id.type === 'Identifier' &&
1111
+ path.node.id.typeAnnotation &&
1112
+ path.node.id.typeAnnotation.typeAnnotation &&
1113
+ path.node.id.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
1114
+ path.node.id.typeAnnotation.typeAnnotation.typeName &&
1115
+ path.node.id.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
1116
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name === interfaceName) {
1117
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name = newName;
1118
+ }
1119
+ });
1120
+ rootSource.find(j.FunctionDeclaration).forEach((path) => {
1121
+ if (path.node.params) {
1122
+ path.node.params.forEach((param) => {
1123
+ if (param.type === 'Identifier' &&
1124
+ param.typeAnnotation &&
1125
+ param.typeAnnotation.typeAnnotation &&
1126
+ param.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
1127
+ param.typeAnnotation.typeAnnotation.typeName &&
1128
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
1129
+ param.typeAnnotation.typeAnnotation.typeName.name === interfaceName) {
1130
+ param.typeAnnotation.typeAnnotation.typeName.name = newName;
1131
+ }
1132
+ });
1133
+ }
1134
+ });
1135
+ rootSource.find(j.ArrowFunctionExpression).forEach((path) => {
1136
+ if (path.node.params) {
1137
+ path.node.params.forEach((param) => {
1138
+ if (param.type === 'Identifier' &&
1139
+ param.typeAnnotation &&
1140
+ param.typeAnnotation.typeAnnotation &&
1141
+ param.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
1142
+ param.typeAnnotation.typeAnnotation.typeName &&
1143
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
1144
+ param.typeAnnotation.typeAnnotation.typeName.name === interfaceName) {
1145
+ param.typeAnnotation.typeAnnotation.typeName.name = newName;
1146
+ }
1147
+ });
1148
+ }
1149
+ });
1150
+ rootSource.find(j.ClassMethod).forEach((path) => {
1151
+ if (path.node.params) {
1152
+ path.node.params.forEach((param) => {
1153
+ if (param.type === 'Identifier' &&
1154
+ param.typeAnnotation &&
1155
+ param.typeAnnotation.typeAnnotation &&
1156
+ param.typeAnnotation.typeAnnotation.type === 'TSTypeReference' &&
1157
+ param.typeAnnotation.typeAnnotation.typeName &&
1158
+ param.typeAnnotation.typeAnnotation.typeName.type === 'Identifier' &&
1159
+ param.typeAnnotation.typeAnnotation.typeName.name === interfaceName) {
1160
+ param.typeAnnotation.typeAnnotation.typeName.name = newName;
1161
+ }
1162
+ });
1163
+ }
1164
+ });
1165
+ rootSource.find(j.Function).forEach((path) => {
1166
+ if (path.node.returnType &&
1167
+ path.node.returnType.typeAnnotation &&
1168
+ path.node.returnType.typeAnnotation.type === 'TSTypeReference' &&
1169
+ path.node.returnType.typeAnnotation.typeName &&
1170
+ path.node.returnType.typeAnnotation.typeName.type === 'Identifier' &&
1171
+ path.node.returnType.typeAnnotation.typeName.name === interfaceName) {
1172
+ path.node.returnType.typeAnnotation.typeName.name = newName;
1173
+ }
1174
+ });
1175
+ rootSource.find(j.TSAsExpression).forEach((path) => {
1176
+ if (path.node.typeAnnotation &&
1177
+ path.node.typeAnnotation.type === 'TSTypeReference' &&
1178
+ path.node.typeAnnotation.typeName &&
1179
+ path.node.typeAnnotation.typeName.type === 'Identifier' &&
1180
+ path.node.typeAnnotation.typeName.name === interfaceName) {
1181
+ path.node.typeAnnotation.typeName.name = newName;
1182
+ }
1183
+ });
1184
+ // Handle constructor calls with 'new' keyword
1185
+ rootSource.find(j.NewExpression).forEach((path) => {
1186
+ if (path.node.callee &&
1187
+ path.node.callee.type === 'Identifier' &&
1188
+ path.node.callee.name === interfaceName) {
1189
+ path.node.callee.name = newName;
1190
+ }
1191
+ });
1192
+ // Helper function to recursively transform type references
1193
+ const transformTypeReference = (typeNode) => {
1194
+ if (!typeNode)
1195
+ return;
1196
+ // Handle TSTypeReference (e.g., FileSelectSettings)
1197
+ if (typeNode.type === 'TSTypeReference' &&
1198
+ typeNode.typeName &&
1199
+ typeNode.typeName.type === 'Identifier' &&
1200
+ typeNode.typeName.name === interfaceName) {
1201
+ typeNode.typeName.name = newName;
1202
+ }
1203
+ // Handle TSArrayType (e.g., FileSelectSettings[])
1204
+ if (typeNode.type === 'TSArrayType' && typeNode.elementType) {
1205
+ transformTypeReference(typeNode.elementType);
1206
+ }
1207
+ // Handle generic Array<T> (e.g., Array<FileSelectSettings>)
1208
+ if (typeNode.type === 'TSTypeReference' &&
1209
+ typeNode.typeParameters &&
1210
+ typeNode.typeParameters.params) {
1211
+ typeNode.typeParameters.params.forEach((param) => {
1212
+ transformTypeReference(param);
1213
+ });
1214
+ }
1215
+ // Handle TSTypeLiteral (e.g., { primary: FileSelectSettings })
1216
+ if (typeNode.type === 'TSTypeLiteral' && typeNode.members) {
1217
+ typeNode.members.forEach((member) => {
1218
+ if (member.typeAnnotation && member.typeAnnotation.typeAnnotation) {
1219
+ transformTypeReference(member.typeAnnotation.typeAnnotation);
1220
+ }
1221
+ });
1222
+ }
1223
+ // Handle TSFunctionType (e.g., (settings: FileSelectSettings) => void)
1224
+ if (typeNode.type === 'TSFunctionType') {
1225
+ if (typeNode.parameters) {
1226
+ typeNode.parameters.forEach((param) => {
1227
+ if (param.typeAnnotation && param.typeAnnotation.typeAnnotation) {
1228
+ transformTypeReference(param.typeAnnotation.typeAnnotation);
1229
+ }
1230
+ });
1231
+ }
1232
+ if (typeNode.typeAnnotation && typeNode.typeAnnotation.typeAnnotation) {
1233
+ transformTypeReference(typeNode.typeAnnotation.typeAnnotation);
1234
+ }
1235
+ }
1236
+ };
1237
+ // Apply recursive transformation to all type annotations
1238
+ rootSource.find(j.VariableDeclarator).forEach((path) => {
1239
+ if (path.node.id.type === 'Identifier' &&
1240
+ path.node.id.typeAnnotation &&
1241
+ path.node.id.typeAnnotation.typeAnnotation) {
1242
+ transformTypeReference(path.node.id.typeAnnotation.typeAnnotation);
1243
+ }
1244
+ });
1245
+ rootSource.find(j.ClassProperty).forEach((path) => {
1246
+ if (path.node.typeAnnotation && path.node.typeAnnotation.typeAnnotation) {
1247
+ transformTypeReference(path.node.typeAnnotation.typeAnnotation);
1248
+ }
1249
+ });
1250
+ rootSource.find(j.ClassMethod).forEach((path) => {
1251
+ if (path.node.returnType && path.node.returnType.typeAnnotation) {
1252
+ transformTypeReference(path.node.returnType.typeAnnotation);
1253
+ }
1254
+ // Transform parameter types recursively
1255
+ if (path.node.params) {
1256
+ path.node.params.forEach((param) => {
1257
+ if (param.typeAnnotation && param.typeAnnotation.typeAnnotation) {
1258
+ transformTypeReference(param.typeAnnotation.typeAnnotation);
1259
+ }
1260
+ });
1261
+ }
1262
+ });
1263
+ rootSource.find(j.FunctionDeclaration).forEach((path) => {
1264
+ if (path.node.returnType && path.node.returnType.typeAnnotation) {
1265
+ transformTypeReference(path.node.returnType.typeAnnotation);
1266
+ }
1267
+ // Transform parameter types recursively
1268
+ if (path.node.params) {
1269
+ path.node.params.forEach((param) => {
1270
+ if (param.typeAnnotation && param.typeAnnotation.typeAnnotation) {
1271
+ transformTypeReference(param.typeAnnotation.typeAnnotation);
1272
+ }
1273
+ });
1274
+ }
1275
+ });
1276
+ rootSource.find(j.ArrowFunctionExpression).forEach((path) => {
1277
+ if (path.node.returnType && path.node.returnType.typeAnnotation) {
1278
+ transformTypeReference(path.node.returnType.typeAnnotation);
1279
+ }
1280
+ // Transform parameter types recursively
1281
+ if (path.node.params) {
1282
+ path.node.params.forEach((param) => {
1283
+ if (param.typeAnnotation && param.typeAnnotation.typeAnnotation) {
1284
+ transformTypeReference(param.typeAnnotation.typeAnnotation);
1285
+ }
1286
+ });
1287
+ }
1288
+ });
1289
+ }
1290
+ };
1291
+ exports.tsInterfaceTransformer = tsInterfaceTransformer;
1292
+ // Helper function to check if a node is a component of the specified type
1293
+ function isComponentTypeMatch(root, j, node, componentType) {
1294
+ if (!node)
1295
+ return false;
1296
+ if (node.type === 'ThisExpression') {
1297
+ return true;
1298
+ }
1299
+ if (node.type === 'Identifier') {
1300
+ const paramName = node.name;
1301
+ // Check function parameters
1302
+ let isParameter = false;
1303
+ root.find(j.Function).forEach((path) => {
1304
+ if (path.node.params && path.node.params.some((param) => param.type === 'Identifier' &&
1305
+ param.name === paramName &&
1306
+ param.typeAnnotation?.typeAnnotation?.typeName?.name === componentType)) {
1307
+ isParameter = true;
1308
+ }
1309
+ });
1310
+ if (isParameter)
1311
+ return true;
1312
+ // Check local variable declarations
1313
+ let isLocalVariable = false;
1314
+ root.find(j.VariableDeclarator).forEach((path) => {
1315
+ if (path.node.id.type === 'Identifier' &&
1316
+ path.node.id.name === paramName &&
1317
+ path.node.id.typeAnnotation?.typeAnnotation?.type === 'TSTypeReference' &&
1318
+ path.node.id.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
1319
+ path.node.id.typeAnnotation.typeAnnotation.typeName.name === componentType) {
1320
+ isLocalVariable = true;
1321
+ }
1322
+ });
1323
+ return isLocalVariable;
1324
+ }
1325
+ if (node.type === 'MemberExpression') {
1326
+ if (node.object.type === 'ThisExpression' && node.property.type === 'Identifier') {
1327
+ const propName = node.property.name;
1328
+ return (root
1329
+ .find(j.ClassProperty, {
1330
+ key: { name: propName },
1331
+ typeAnnotation: {
1332
+ typeAnnotation: {
1333
+ typeName: { name: componentType },
1334
+ },
1335
+ },
1336
+ })
1337
+ .size() > 0);
1338
+ }
1339
+ // Handle nested member expressions like chatConfig.chat where chat is ChatComponent
1340
+ if (node.object.type === 'Identifier' && node.property.type === 'Identifier') {
1341
+ const varName = node.object.name;
1342
+ const propName = node.property.name;
1343
+ // Check if this is an object with a property of componentType
1344
+ let hasMatchingProperty = false;
1345
+ root.find(j.VariableDeclarator).forEach((path) => {
1346
+ if (path.node.id.type === 'Identifier' &&
1347
+ path.node.id.name === varName &&
1348
+ path.node.id.typeAnnotation &&
1349
+ path.node.id.typeAnnotation.typeAnnotation?.type === 'TSTypeLiteral') {
1350
+ const members = path.node.id.typeAnnotation.typeAnnotation.members;
1351
+ const found = members.some((member) => {
1352
+ return (member.type === 'TSPropertySignature' &&
1353
+ member.key?.type === 'Identifier' &&
1354
+ member.key.name === propName &&
1355
+ member.typeAnnotation?.typeAnnotation?.type === 'TSTypeReference' &&
1356
+ member.typeAnnotation.typeAnnotation.typeName?.type === 'Identifier' &&
1357
+ member.typeAnnotation.typeAnnotation.typeName.name === componentType);
1358
+ });
1359
+ if (found) {
1360
+ hasMatchingProperty = true;
1361
+ }
1362
+ }
1363
+ });
1364
+ return hasMatchingProperty;
1365
+ }
1366
+ }
1367
+ // Handle array element access like chatComponents[0] where chatComponents is ChatComponent[]
1368
+ // When we have chatComponents[0].property, node is chatComponents[0] which is a MemberExpression with computed: true
1369
+ if (node.type === 'MemberExpression' && node.computed === true && node.object.type === 'Identifier') {
1370
+ const arrayName = node.object.name;
1371
+ // Check if this array is of type ChatComponent[]
1372
+ let isComponentArray = false;
1373
+ root.find(j.VariableDeclarator).forEach((path) => {
1374
+ if (path.node.id.type === 'Identifier' &&
1375
+ path.node.id.name === arrayName &&
1376
+ path.node.id.typeAnnotation?.typeAnnotation?.type === 'TSArrayType' &&
1377
+ path.node.id.typeAnnotation.typeAnnotation.elementType?.type === 'TSTypeReference' &&
1378
+ path.node.id.typeAnnotation.typeAnnotation.elementType.typeName?.type === 'Identifier' &&
1379
+ path.node.id.typeAnnotation.typeAnnotation.elementType.typeName.name === componentType) {
1380
+ isComponentArray = true;
1381
+ }
1382
+ });
1383
+ return isComponentArray;
1384
+ }
1385
+ // Handle TypeScript type assertions like (this.componentProperty as ComponentType)
1386
+ if (node.type === 'TSAsExpression') {
1387
+ // Check if the type assertion is casting to our componentType
1388
+ if (node.typeAnnotation &&
1389
+ node.typeAnnotation.type === 'TSTypeReference' &&
1390
+ node.typeAnnotation.typeName &&
1391
+ node.typeAnnotation.typeName.type === 'Identifier' &&
1392
+ node.typeAnnotation.typeName.name === componentType) {
1393
+ return true;
1394
+ }
1395
+ }
1396
+ return false;
1397
+ }
1398
+ // Matches CSS class names in CSS selectors (.foo) and as whitespace/quote-delimited
1399
+ // tokens within attribute values, covering both single-class ("foo") and multi-class ("foo bar") cases.
1400
+ function makePattern(classes) {
1401
+ return new RegExp(classes.map(c => String.raw `\.${c}\b|(?<=["'\s])${c}(?=["'\s])`).join('|'));
1402
+ }
1403
+ function writeInstructionMarker(instruction, codemodFilename, affectedFile) {
1404
+ // Write to node_modules/.kendo/migration/<basename(codemodFilename)>
1405
+ // kendo-cli reads the marker by looking up basename(codemod.file) in that directory
1406
+ const markerDir = path.join(process.cwd(), 'node_modules', '.kendo', 'migration');
1407
+ const markerPath = path.join(markerDir, path.basename(codemodFilename));
1408
+ try {
1409
+ fs.mkdirSync(markerDir, { recursive: true });
1410
+ const existing = fs.existsSync(markerPath) ? fs.readFileSync(markerPath, 'utf8') : '';
1411
+ let content = existing;
1412
+ if (!existing.includes(instruction)) {
1413
+ content += instruction + '\n';
1414
+ }
1415
+ const fileLine = ` - ${path.relative(process.cwd(), affectedFile)}`;
1416
+ if (!content.includes(fileLine)) {
1417
+ content += fileLine + '\n';
1418
+ }
1419
+ fs.writeFileSync(markerPath, content);
1420
+ }
1421
+ catch { /* suppress error */ }
1422
+ }
1423
+ function isApiChangeTarget(filePath) {
1424
+ const ext = path.extname(filePath);
1425
+ return ext === '.ts' || ext === '.html';
1426
+ }
1427
+ function isRenderingChangeTarget(filePath) {
1428
+ const ext = path.extname(filePath);
1429
+ return ext === '.ts' || ext === '.html' || ext === '.css' || ext === '.scss' || ext === '.sass' || ext === '.less';
1430
+ }