@ethlete/cdk 4.70.0 → 5.0.0-next.0

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,9 @@
1
+ {
2
+ "generators": {
3
+ "migrate-to-v5": {
4
+ "factory": "./migrate-to-v5/migration",
5
+ "schema": "./migrate-to-v5/schema.json",
6
+ "description": "A migration to update the cdk to version 5"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,259 @@
1
+ const SYMBOL_MAP = {
2
+ CdkMenuTrigger: 'MenuTriggerDirective',
3
+ CdkMenuItem: 'MenuItemDirective',
4
+ CdkMenu: 'MenuComponent',
5
+ CdkMenuGroup: 'MenuGroupDirective',
6
+ CdkMenuItemCheckbox: 'MenuCheckboxItemComponent',
7
+ CdkMenuItemRadio: 'MenuRadioItemComponent',
8
+ CdkMenuModule: 'MenuImports',
9
+ };
10
+ const CDK_MENU_SYMBOLS = Object.keys(SYMBOL_MAP);
11
+ // These are the et menu symbols that should be consolidated into MenuImports in decorators
12
+ const ET_MENU_SYMBOLS = new Set([
13
+ 'MenuGroupDirective',
14
+ 'MenuCheckboxItemComponent',
15
+ 'MenuRadioItemComponent',
16
+ 'MenuGroupTitleDirective',
17
+ 'MenuItemDirective',
18
+ 'MenuTriggerDirective',
19
+ 'MenuCheckboxGroupDirective',
20
+ 'MenuRadioGroupDirective',
21
+ 'MenuComponent',
22
+ 'MenuSearchTemplateDirective',
23
+ ]);
24
+ export default async function migrateCdkMenu(tree) {
25
+ console.log('\nšŸ”„ Migrating from CDK menu to et menu');
26
+ const files = tree.children('.');
27
+ const warnings = new Map();
28
+ function walkFiles(path) {
29
+ const entries = tree.children(path);
30
+ entries.forEach((entry) => {
31
+ const fullPath = `${path}/${entry}`.replace(/^\//, '');
32
+ if (tree.isFile(fullPath)) {
33
+ if (fullPath.endsWith('.ts') && !fullPath.endsWith('.spec.ts')) {
34
+ migrateTypeScriptFile(fullPath);
35
+ }
36
+ else if (fullPath.endsWith('.html')) {
37
+ migrateHtmlFile(fullPath, warnings);
38
+ }
39
+ }
40
+ else {
41
+ walkFiles(fullPath);
42
+ }
43
+ });
44
+ }
45
+ walkFiles('.');
46
+ // Print warnings at the end
47
+ if (warnings.size > 0) {
48
+ console.log('\nāš ļø Manual migration required for the following files:');
49
+ warnings.forEach((msgs, file) => {
50
+ console.log(`\nšŸ“„ ${file}:`);
51
+ msgs.forEach((msg) => console.log(` - ${msg}`));
52
+ });
53
+ }
54
+ function migrateTypeScriptFile(filePath) {
55
+ let content = tree.read(filePath, 'utf-8');
56
+ if (!content)
57
+ return;
58
+ const originalContent = content;
59
+ // Find all @ethlete/cdk imports
60
+ const importRegex = /import\s*{([^}]*)}\s*from\s*['"]@ethlete\/cdk['"]/g;
61
+ const imports = Array.from(content.matchAll(importRegex));
62
+ if (imports.length === 0)
63
+ return;
64
+ // Process imports and build replacement
65
+ let hasMenuSymbols = false;
66
+ let hasMenuImports = false;
67
+ const importedSymbols = new Set();
68
+ imports.forEach((match) => {
69
+ const importList = match[1];
70
+ const symbols = importList
71
+ .split(',')
72
+ .map((s) => s.trim())
73
+ .filter((s) => s);
74
+ symbols.forEach((symbol) => {
75
+ importedSymbols.add(symbol);
76
+ if (CDK_MENU_SYMBOLS.includes(symbol)) {
77
+ hasMenuSymbols = true;
78
+ }
79
+ if (symbol === 'MenuImports') {
80
+ hasMenuImports = true;
81
+ }
82
+ });
83
+ });
84
+ if (!hasMenuSymbols && !Array.from(importedSymbols).some((s) => ET_MENU_SYMBOLS.has(s)))
85
+ return;
86
+ // Handle decorator imports arrays FIRST (before replacing symbols in code)
87
+ const decoratorRegex = /imports\s*:\s*\[([\s\S]*?)\]/g;
88
+ let usesMenuInDecorator = false;
89
+ const menuSymbolsInDecorator = new Set();
90
+ content = content.replace(decoratorRegex, (match) => {
91
+ let hasMenuSymbol = false;
92
+ let result = match;
93
+ // Check for CDK menu symbols
94
+ CDK_MENU_SYMBOLS.forEach((symbol) => {
95
+ if (result.includes(symbol)) {
96
+ hasMenuSymbol = true;
97
+ menuSymbolsInDecorator.add(symbol);
98
+ result = result.replace(new RegExp(`\\b${symbol}\\b`, 'g'), '');
99
+ }
100
+ });
101
+ // Check for et menu symbols
102
+ ET_MENU_SYMBOLS.forEach((symbol) => {
103
+ if (result.includes(symbol)) {
104
+ hasMenuSymbol = true;
105
+ menuSymbolsInDecorator.add(symbol);
106
+ result = result.replace(new RegExp(`\\b${symbol}\\b`, 'g'), '');
107
+ }
108
+ });
109
+ if (hasMenuSymbol) {
110
+ usesMenuInDecorator = true;
111
+ // Extract the array content and clean it up
112
+ const arrayMatch = result.match(/imports\s*:\s*\[([\s\S]*?)\]/);
113
+ if (arrayMatch) {
114
+ const arrayContent = arrayMatch[1];
115
+ // Split by comma, trim, filter empty strings
116
+ const items = arrayContent
117
+ .split(',')
118
+ .map((item) => item.trim())
119
+ .filter((item) => item && item !== 'MenuImports');
120
+ // Reconstruct with MenuImports
121
+ if (items.length === 0) {
122
+ result = result.replace(/imports\s*:\s*\[([\s\S]*?)\]/, 'imports: [MenuImports]');
123
+ }
124
+ else {
125
+ const newContent = `MenuImports, ${items.join(', ')}`;
126
+ result = result.replace(/imports\s*:\s*\[([\s\S]*?)\]/, `imports: [${newContent}]`);
127
+ }
128
+ }
129
+ }
130
+ return result;
131
+ });
132
+ // Replace imports
133
+ content = content.replace(importRegex, (match, importList) => {
134
+ const symbols = importList
135
+ .split(',')
136
+ .map((s) => s.trim())
137
+ .filter((s) => s);
138
+ const replaced = symbols
139
+ .filter((symbol) => !menuSymbolsInDecorator.has(symbol))
140
+ .map((symbol) => {
141
+ if (CDK_MENU_SYMBOLS.includes(symbol)) {
142
+ return SYMBOL_MAP[symbol];
143
+ }
144
+ return symbol;
145
+ });
146
+ // Add MenuImports if used in decorator and not already present
147
+ if (usesMenuInDecorator && !replaced.includes('MenuImports')) {
148
+ replaced.push('MenuImports');
149
+ }
150
+ // Deduplicate
151
+ const unique = Array.from(new Set(replaced));
152
+ return `import { ${unique.join(', ')} } from '@ethlete/cdk'`;
153
+ });
154
+ // Replace symbol usages in code
155
+ CDK_MENU_SYMBOLS.forEach((oldSymbol) => {
156
+ if (importedSymbols.has(oldSymbol) && !menuSymbolsInDecorator.has(oldSymbol)) {
157
+ const newSymbol = SYMBOL_MAP[oldSymbol];
158
+ content = content.replace(new RegExp(`\\b${oldSymbol}\\b`, 'g'), newSymbol);
159
+ }
160
+ });
161
+ if (content !== originalContent) {
162
+ tree.write(filePath, content);
163
+ }
164
+ }
165
+ function migrateHtmlFile(filePath, warnings) {
166
+ let content = tree.read(filePath, 'utf-8');
167
+ if (!content)
168
+ return;
169
+ const originalContent = content;
170
+ const fileWarnings = [];
171
+ // 1. Replace [cdkMenuTriggerFor] binding with [etMenuTrigger]
172
+ if (content.includes('[cdkMenuTriggerFor]')) {
173
+ content = content.replace(/\[cdkMenuTriggerFor\]/g, '[etMenuTrigger]');
174
+ }
175
+ const cdkMenuRegex = /<(\w+)([^>]*?)\bcdkMenu\b([^>]*)>/g;
176
+ const matches = Array.from(content.matchAll(cdkMenuRegex));
177
+ if (matches.length > 0) {
178
+ fileWarnings.push(`Found ${matches.length} element(s) with cdkMenu directive. ` +
179
+ 'Replaced with <et-menu> component. Verify all attributes and bindings are preserved.');
180
+ // Collect replacements for entire elements
181
+ const replacements = [];
182
+ for (const match of matches) {
183
+ const tagName = match[1];
184
+ const beforeAttrs = match[2];
185
+ const afterAttrs = match[3];
186
+ const allAttrs = (beforeAttrs + afterAttrs)
187
+ .replace(/\s+cdkMenu\s+/, ' ')
188
+ .replace(/\bcdkMenu\b/, '')
189
+ .trim();
190
+ const spacer = allAttrs ? ' ' : '';
191
+ const openingStart = match.index;
192
+ const openingEnd = match.index + match[0].length;
193
+ let count = 1;
194
+ let pos = openingEnd;
195
+ while (pos < content.length && count > 0) {
196
+ if (content.startsWith(`<${tagName}`, pos)) {
197
+ count++;
198
+ }
199
+ else if (content.startsWith(`</${tagName}>`, pos)) {
200
+ count--;
201
+ if (count === 0) {
202
+ const closingStart = pos;
203
+ const closingEnd = pos + `</${tagName}>`.length;
204
+ const innerContent = content.slice(openingEnd, closingStart);
205
+ const replacement = `<et-menu${spacer}${allAttrs}>${innerContent}</et-menu>`;
206
+ replacements.push({ start: openingStart, end: closingEnd, replacement });
207
+ break;
208
+ }
209
+ }
210
+ pos++;
211
+ }
212
+ }
213
+ // Replace in reverse order to maintain positions
214
+ replacements.sort((a, b) => b.start - a.start);
215
+ for (const rep of replacements) {
216
+ content = content.slice(0, rep.start) + rep.replacement + content.slice(rep.end);
217
+ }
218
+ }
219
+ // 3. Replace cdkMenuItem directive with etMenuItem
220
+ if (content.includes('cdkMenuItem')) {
221
+ content = content.replace(/\bcdkMenuItem\b/g, 'etMenuItem');
222
+ }
223
+ // 4. Replace cdkMenuItemCheckbox with et-menu-checkbox-item
224
+ if (content.includes('cdkMenuItemCheckbox')) {
225
+ const checkboxRegex = /<(\w+)([^>]*?)\bcdkMenuItemCheckbox\b([^>]*)>([\s\S]*?)<\/\1>/g;
226
+ content = content.replace(checkboxRegex, (match, tagName, beforeAttrs, afterAttrs, inner) => {
227
+ const allAttrs = (beforeAttrs + afterAttrs)
228
+ .replace(/\s+cdkMenuItemCheckbox\s+/, ' ')
229
+ .replace(/\bcdkMenuItemCheckbox\b/, '')
230
+ .trim();
231
+ const spacer = allAttrs ? ' ' : '';
232
+ return `<et-menu-checkbox-item${spacer}${allAttrs}>${inner}</et-menu-checkbox-item>`;
233
+ });
234
+ }
235
+ // 5. Replace cdkMenuItemRadio with et-menu-radio-item and add warning
236
+ if (content.includes('cdkMenuItemRadio')) {
237
+ const radioRegex = /<(\w+)([^>]*?)\bcdkMenuItemRadio\b([^>]*)>([\s\S]*?)<\/\1>/g;
238
+ content = content.replace(radioRegex, (match, tagName, beforeAttrs, afterAttrs, inner) => {
239
+ const allAttrs = (beforeAttrs + afterAttrs)
240
+ .replace(/\s+cdkMenuItemRadio\s+/, ' ')
241
+ .replace(/\bcdkMenuItemRadio\b/, '')
242
+ .trim();
243
+ const spacer = allAttrs ? ' ' : '';
244
+ fileWarnings.push('Manual migration required: Wrap et-menu-radio-item elements in <div etMenuRadioGroup> and add appropriate value attributes.');
245
+ return `<et-menu-radio-item${spacer}${allAttrs} value="TODO">${inner}</et-menu-radio-item>`;
246
+ });
247
+ }
248
+ if (content !== originalContent) {
249
+ tree.write(filePath, content);
250
+ }
251
+ if (fileWarnings.length > 0) {
252
+ if (!warnings.has(filePath)) {
253
+ warnings.set(filePath, []);
254
+ }
255
+ warnings.get(filePath).push(...fileWarnings);
256
+ }
257
+ }
258
+ }
259
+ //# sourceMappingURL=cdk-menu.js.map
@@ -0,0 +1,221 @@
1
+ import { logger, readJson, visitNotIgnoredFiles, writeJson } from '@nx/devkit';
2
+ // Theming-related exports that moved from @ethlete/theming and @ethlete/cdk to @ethlete/core
3
+ const THEMING_EXPORTS = new Set([
4
+ 'ProvideThemeDirective',
5
+ 'THEME_PROVIDER',
6
+ 'Theme',
7
+ 'ThemeSwatch',
8
+ 'OnThemeColorMap',
9
+ 'ThemeColorMap',
10
+ 'ThemeColor',
11
+ 'ThemeHSLColor',
12
+ 'ThemeRGBColor',
13
+ 'provideThemes',
14
+ 'provideColorThemes',
15
+ ]);
16
+ export default async function migrateColorThemes(tree) {
17
+ console.log('\nšŸ”„ Migrating provideThemes to provideColorThemes and imports to @ethlete/core');
18
+ let filesModified = 0;
19
+ let functionReplacements = 0;
20
+ let importsMoved = 0;
21
+ let importsMerged = 0;
22
+ let packagesRemoved = 0;
23
+ // Migrate TypeScript files
24
+ visitNotIgnoredFiles(tree, '', (filePath) => {
25
+ if (!filePath.endsWith('.ts')) {
26
+ return;
27
+ }
28
+ const content = tree.read(filePath, 'utf-8');
29
+ if (!content) {
30
+ return;
31
+ }
32
+ // Check if file contains provideThemes or imports from @ethlete/theming or @ethlete/cdk
33
+ if (!content.includes('provideThemes') &&
34
+ !content.includes('@ethlete/theming') &&
35
+ !content.includes('@ethlete/cdk')) {
36
+ return;
37
+ }
38
+ let modified = content;
39
+ let fileChanges = 0;
40
+ // Replace provideThemes with provideColorThemes
41
+ const beforeProvideThemesCount = (modified.match(/\bprovideThemes\b/g) || []).length;
42
+ modified = modified.replace(/\bprovideThemes\b/g, 'provideColorThemes');
43
+ fileChanges += beforeProvideThemesCount;
44
+ functionReplacements += beforeProvideThemesCount;
45
+ // Handle import merging from @ethlete/theming and @ethlete/cdk to @ethlete/core
46
+ const themingImportPattern = /import\s*{([^}]*)}\s*from\s*['"]@ethlete\/theming['"]/g;
47
+ const cdkImportPattern = /import\s*{([^}]*)}\s*from\s*['"]@ethlete\/cdk['"]/g;
48
+ const coreImportPattern = /import\s*{([^}]*)}\s*from\s*['"]@ethlete\/core['"]/;
49
+ const themingImportsToMove = [];
50
+ const cdkThemingImportsToMove = [];
51
+ const cdkNonThemingImports = [];
52
+ let themingMatch;
53
+ let cdkMatch;
54
+ // Collect all imports from @ethlete/theming (all should be moved)
55
+ while ((themingMatch = themingImportPattern.exec(modified)) !== null) {
56
+ const imports = themingMatch[1]
57
+ .split(',')
58
+ .map((imp) => imp.trim())
59
+ .filter((imp) => imp.length > 0);
60
+ // Keep the full import string including 'type' keyword and aliases
61
+ themingImportsToMove.push(...imports);
62
+ }
63
+ // Collect imports from @ethlete/cdk and separate theming vs non-theming
64
+ while ((cdkMatch = cdkImportPattern.exec(modified)) !== null) {
65
+ const imports = cdkMatch[1]
66
+ .split(',')
67
+ .map((imp) => imp.trim())
68
+ .filter((imp) => imp.length > 0);
69
+ imports.forEach((imp) => {
70
+ // Extract the actual import name (without 'type' keyword and alias)
71
+ // Handle patterns like: "type Theme as EthleteTheme", "Theme", "type Theme"
72
+ const typeKeywordMatch = imp.match(/^type\s+/);
73
+ const hasTypeKeyword = !!typeKeywordMatch;
74
+ const withoutType = imp.replace(/^type\s+/, '').trim();
75
+ const importName = withoutType.split(/\s+as\s+/)[0]?.trim() || withoutType;
76
+ if (THEMING_EXPORTS.has(importName)) {
77
+ cdkThemingImportsToMove.push(imp); // Keep the original import with type keyword and alias
78
+ }
79
+ else {
80
+ cdkNonThemingImports.push(imp); // Keep the original import with type keyword and alias
81
+ }
82
+ });
83
+ }
84
+ const allThemingImports = [...themingImportsToMove, ...cdkThemingImportsToMove];
85
+ if (allThemingImports.length > 0) {
86
+ // Check if there's already a @ethlete/core import
87
+ const existingCoreImport = modified.match(coreImportPattern);
88
+ if (existingCoreImport) {
89
+ // Merge theming imports with existing @ethlete/core import
90
+ const existingImports = existingCoreImport[1]
91
+ .split(',')
92
+ .map((imp) => imp.trim())
93
+ .filter((imp) => imp.length > 0);
94
+ const allImports = [...existingImports, ...allThemingImports];
95
+ // Remove duplicates while preserving order and type keywords
96
+ // We need to compare the actual import names (without type and aliases) for deduplication
97
+ const seen = new Set();
98
+ const uniqueImports = allImports.filter((imp) => {
99
+ const withoutType = imp.replace(/^type\s+/, '').trim();
100
+ const importName = withoutType.split(/\s+as\s+/)[0]?.trim() || withoutType;
101
+ if (seen.has(importName)) {
102
+ return false;
103
+ }
104
+ seen.add(importName);
105
+ return true;
106
+ });
107
+ // Replace the existing @ethlete/core import with merged imports
108
+ modified = modified.replace(coreImportPattern, `import { ${uniqueImports.join(', ')} } from '@ethlete/core'`);
109
+ importsMerged++;
110
+ fileChanges++;
111
+ }
112
+ else {
113
+ // No existing @ethlete/core import, create a new one
114
+ const uniqueImports = Array.from(new Set(allThemingImports));
115
+ // Find the position of the first theming import to replace
116
+ const firstThemingImport = modified.match(/import\s*{[^}]*}\s*from\s*['"]@ethlete\/theming['"];?\s*\n?/);
117
+ if (firstThemingImport) {
118
+ // Replace first theming import with core import
119
+ modified = modified.replace(/import\s*{[^}]*}\s*from\s*['"]@ethlete\/theming['"];?\s*\n?/, `import { ${uniqueImports.join(', ')} } from '@ethlete/core';\n`);
120
+ }
121
+ else {
122
+ // Add new @ethlete/core import at the beginning (after first import)
123
+ const firstImportMatch = modified.match(/import\s+[^;]+;/);
124
+ if (firstImportMatch) {
125
+ const insertPosition = firstImportMatch.index + firstImportMatch[0].length;
126
+ modified =
127
+ modified.slice(0, insertPosition) +
128
+ `\nimport { ${uniqueImports.join(', ')} } from '@ethlete/core';` +
129
+ modified.slice(insertPosition);
130
+ }
131
+ }
132
+ importsMoved++;
133
+ fileChanges++;
134
+ }
135
+ // Remove all @ethlete/theming imports
136
+ modified = modified.replace(/import\s*{[^}]*}\s*from\s*['"]@ethlete\/theming['"];?\s*\n?/g, '');
137
+ // Handle @ethlete/cdk imports - only process if we found theming imports to move
138
+ if (cdkThemingImportsToMove.length > 0) {
139
+ // Remove all existing @ethlete/cdk imports first
140
+ modified = modified.replace(/import\s*{[^}]*}\s*from\s*['"]@ethlete\/cdk['"];?\s*\n?/g, '');
141
+ if (cdkNonThemingImports.length > 0) {
142
+ // Add back only the non-theming imports after the @ethlete/core import
143
+ const cdkImportStatement = `import { ${cdkNonThemingImports.join(', ')} } from '@ethlete/cdk';\n`;
144
+ const coreImportMatch = modified.match(/import\s*{[^}]*}\s*from\s*['"]@ethlete\/core['"];?\s*\n?/);
145
+ if (coreImportMatch) {
146
+ const insertPosition = coreImportMatch.index + coreImportMatch[0].length;
147
+ modified = modified.slice(0, insertPosition) + cdkImportStatement + modified.slice(insertPosition);
148
+ }
149
+ else {
150
+ // If no core import exists, add after the first import
151
+ const firstImportMatch = modified.match(/import\s+[^;]+;/);
152
+ if (firstImportMatch) {
153
+ const insertPosition = firstImportMatch.index + firstImportMatch[0].length;
154
+ modified = modified.slice(0, insertPosition) + '\n' + cdkImportStatement + modified.slice(insertPosition);
155
+ }
156
+ }
157
+ }
158
+ // Clean up any resulting double newlines
159
+ modified = modified.replace(/\n\n\n+/g, '\n\n');
160
+ fileChanges++;
161
+ }
162
+ }
163
+ if (modified !== content) {
164
+ tree.write(filePath, modified);
165
+ filesModified++;
166
+ console.log(` āœ“ ${filePath} (${fileChanges} change${fileChanges !== 1 ? 's' : ''})`);
167
+ }
168
+ });
169
+ // Remove @ethlete/theming from package.json files (but keep @ethlete/cdk)
170
+ const packageJsonFiles = ['package.json'];
171
+ // Also check for package.json in apps and libs
172
+ visitNotIgnoredFiles(tree, '', (filePath) => {
173
+ if (filePath.endsWith('package.json') && !packageJsonFiles.includes(filePath)) {
174
+ packageJsonFiles.push(filePath);
175
+ }
176
+ });
177
+ for (const packageJsonPath of packageJsonFiles) {
178
+ if (!tree.exists(packageJsonPath)) {
179
+ continue;
180
+ }
181
+ try {
182
+ const packageJson = readJson(tree, packageJsonPath);
183
+ let modified = false;
184
+ // Remove @ethlete/theming from dependencies
185
+ if (packageJson.dependencies && packageJson.dependencies['@ethlete/theming']) {
186
+ delete packageJson.dependencies['@ethlete/theming'];
187
+ modified = true;
188
+ console.log(` āœ“ Removed @ethlete/theming from ${packageJsonPath} dependencies`);
189
+ }
190
+ // Remove @ethlete/theming from devDependencies
191
+ if (packageJson.devDependencies && packageJson.devDependencies['@ethlete/theming']) {
192
+ delete packageJson.devDependencies['@ethlete/theming'];
193
+ modified = true;
194
+ console.log(` āœ“ Removed @ethlete/theming from ${packageJsonPath} devDependencies`);
195
+ }
196
+ // Remove @ethlete/theming from peerDependencies
197
+ if (packageJson.peerDependencies && packageJson.peerDependencies['@ethlete/theming']) {
198
+ delete packageJson.peerDependencies['@ethlete/theming'];
199
+ modified = true;
200
+ console.log(` āœ“ Removed @ethlete/theming from ${packageJsonPath} peerDependencies`);
201
+ }
202
+ if (modified) {
203
+ writeJson(tree, packageJsonPath, packageJson);
204
+ packagesRemoved++;
205
+ }
206
+ }
207
+ catch (error) {
208
+ logger.warn(`Failed to process ${packageJsonPath}: ${error}`);
209
+ }
210
+ }
211
+ console.log(`\nāœ… Color themes migration complete:`);
212
+ console.log(` šŸ“ Files modified: ${filesModified}`);
213
+ console.log(` šŸ”„ Function replacements: ${functionReplacements}`);
214
+ console.log(` šŸ“¦ Imports moved: ${importsMoved}`);
215
+ console.log(` šŸ”— Imports merged: ${importsMerged}`);
216
+ console.log(` šŸ—‘ļø Package.json files updated: ${packagesRemoved}`);
217
+ if (packagesRemoved > 0) {
218
+ console.log(`\nāš ļø Don't forget to run 'yarn install' to update your lock file!`);
219
+ }
220
+ }
221
+ //# sourceMappingURL=color-themes.js.map
@@ -0,0 +1,186 @@
1
+ import { visitNotIgnoredFiles } from '@nx/devkit';
2
+ import * as ts from 'typescript';
3
+ export function migrateCombobox(tree) {
4
+ console.log('\nšŸ”„ Migrating <et-combobox> components...');
5
+ migrateInputs(tree);
6
+ migrateProvideComboboxConfig(tree);
7
+ }
8
+ function migrateInputs(tree) {
9
+ let filesModified = 0;
10
+ let propertiesRenamed = 0;
11
+ visitNotIgnoredFiles(tree, '', (filePath) => {
12
+ if (!filePath.endsWith('.html') && !filePath.endsWith('.component.ts')) {
13
+ return;
14
+ }
15
+ const content = tree.read(filePath, 'utf-8');
16
+ if (!content)
17
+ return;
18
+ const newContent = migrateEmptyTextProperty(content, filePath);
19
+ if (newContent !== content) {
20
+ tree.write(filePath, newContent);
21
+ filesModified++;
22
+ }
23
+ });
24
+ function migrateEmptyTextProperty(content, filePath) {
25
+ let result = content;
26
+ let filePropertiesRenamed = 0;
27
+ // HTML template files
28
+ if (filePath.endsWith('.html')) {
29
+ // Find all <et-combobox> tags and only replace emptyText within them
30
+ const comboboxRegex = /<et-combobox\s[^>]*>/g;
31
+ result = content.replace(comboboxRegex, (match) => {
32
+ let modified = match;
33
+ let localRenames = 0;
34
+ // Replace [emptyText] with [bodyEmptyText]
35
+ const propertyBindingCount = (modified.match(/\[emptyText\]/g) || []).length;
36
+ modified = modified.replace(/\[emptyText\]/g, '[bodyEmptyText]');
37
+ localRenames += propertyBindingCount;
38
+ // Replace emptyText= with bodyEmptyText= (attribute binding)
39
+ const attributeCount = (modified.match(/(\s)emptyText=/g) || []).length;
40
+ modified = modified.replace(/(\s)emptyText=/g, '$1bodyEmptyText=');
41
+ localRenames += attributeCount;
42
+ if (localRenames > 0) {
43
+ filePropertiesRenamed += localRenames;
44
+ }
45
+ return modified;
46
+ });
47
+ }
48
+ // TypeScript component files (inline templates)
49
+ if (filePath.endsWith('.component.ts')) {
50
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
51
+ const replacements = [];
52
+ function visit(node) {
53
+ // Handle template strings in @Component decorator
54
+ if (ts.isPropertyAssignment(node)) {
55
+ if (ts.isIdentifier(node.name) &&
56
+ node.name.text === 'template' &&
57
+ (ts.isStringLiteral(node.initializer) || ts.isNoSubstitutionTemplateLiteral(node.initializer))) {
58
+ const templateContent = node.initializer.getText(sourceFile);
59
+ const templateText = templateContent.slice(1, -1); // Remove quotes
60
+ // Only process if template contains et-combobox
61
+ if (templateText.includes('<et-combobox') && templateText.includes('emptyText')) {
62
+ let newTemplate = templateText;
63
+ let localRenames = 0;
64
+ // Find all <et-combobox> tags and only replace emptyText within them
65
+ const comboboxRegex = /<et-combobox\s[^>]*>/g;
66
+ newTemplate = newTemplate.replace(comboboxRegex, (match) => {
67
+ let modified = match;
68
+ // Replace [emptyText] with [bodyEmptyText]
69
+ const propertyBindingCount = (modified.match(/\[emptyText\]/g) || []).length;
70
+ modified = modified.replace(/\[emptyText\]/g, '[bodyEmptyText]');
71
+ localRenames += propertyBindingCount;
72
+ // Replace emptyText= with bodyEmptyText=
73
+ const attributeCount = (modified.match(/(\s)emptyText=/g) || []).length;
74
+ modified = modified.replace(/(\s)emptyText=/g, '$1bodyEmptyText=');
75
+ localRenames += attributeCount;
76
+ return modified;
77
+ });
78
+ if (localRenames > 0) {
79
+ const quote = templateContent[0];
80
+ replacements.push({
81
+ start: node.initializer.getStart(sourceFile),
82
+ end: node.initializer.getEnd(),
83
+ replacement: `${quote}${newTemplate}${quote}`,
84
+ });
85
+ filePropertiesRenamed += localRenames;
86
+ }
87
+ }
88
+ }
89
+ }
90
+ ts.forEachChild(node, visit);
91
+ }
92
+ visit(sourceFile);
93
+ // Apply replacements in reverse order
94
+ if (replacements.length > 0) {
95
+ replacements.sort((a, b) => b.start - a.start);
96
+ for (const { start, end, replacement } of replacements) {
97
+ result = result.slice(0, start) + replacement + result.slice(end);
98
+ }
99
+ }
100
+ }
101
+ if (filePropertiesRenamed > 0) {
102
+ console.log(` āœ“ ${filePath}: renamed ${filePropertiesRenamed} property(ies)`);
103
+ propertiesRenamed += filePropertiesRenamed;
104
+ }
105
+ return result;
106
+ }
107
+ if (filesModified > 0) {
108
+ console.log(`\nāœ… Migrated ${filesModified} file(s), renamed ${propertiesRenamed} emptyText property(ies) to bodyEmptyText`);
109
+ }
110
+ else {
111
+ console.log('\nāœ… No <et-combobox> components found that need migration');
112
+ }
113
+ }
114
+ function migrateProvideComboboxConfig(tree) {
115
+ let filesModified = 0;
116
+ let configCallsUpdated = 0;
117
+ visitNotIgnoredFiles(tree, '', (filePath) => {
118
+ if (!filePath.endsWith('.ts')) {
119
+ return;
120
+ }
121
+ const content = tree.read(filePath, 'utf-8');
122
+ if (!content)
123
+ return;
124
+ const result = migrateConfigCalls(content, filePath);
125
+ if (result.content !== content) {
126
+ tree.write(filePath, result.content);
127
+ filesModified++;
128
+ configCallsUpdated += result.updatedCount;
129
+ }
130
+ });
131
+ function migrateConfigCalls(content, filePath) {
132
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
133
+ const replacements = [];
134
+ let configsUpdated = 0;
135
+ function visit(node) {
136
+ // Find provideComboboxConfig() calls
137
+ if (ts.isCallExpression(node)) {
138
+ if (ts.isIdentifier(node.expression) &&
139
+ node.expression.text === 'provideComboboxConfig' &&
140
+ node.arguments.length > 0) {
141
+ const configArg = node.arguments[0];
142
+ // Check if the argument is an object literal
143
+ if (ts.isObjectLiteralExpression(configArg)) {
144
+ const emptyTextProp = configArg.properties.find((p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'emptyText');
145
+ if (emptyTextProp) {
146
+ // Check if bodyEmptyText already exists
147
+ const bodyEmptyTextProp = configArg.properties.find((p) => ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'bodyEmptyText');
148
+ if (!bodyEmptyTextProp) {
149
+ // Rename emptyText to bodyEmptyText
150
+ const propStart = emptyTextProp.name.getStart(sourceFile);
151
+ const propEnd = emptyTextProp.name.getEnd();
152
+ replacements.push({
153
+ start: propStart,
154
+ end: propEnd,
155
+ replacement: 'bodyEmptyText',
156
+ });
157
+ configsUpdated++;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ ts.forEachChild(node, visit);
164
+ }
165
+ visit(sourceFile);
166
+ let result = content;
167
+ // Apply replacements in reverse order
168
+ if (replacements.length > 0) {
169
+ replacements.sort((a, b) => b.start - a.start);
170
+ for (const { start, end, replacement } of replacements) {
171
+ result = result.slice(0, start) + replacement + result.slice(end);
172
+ }
173
+ }
174
+ if (configsUpdated > 0) {
175
+ console.log(` āœ“ ${filePath}: updated ${configsUpdated} provideComboboxConfig call(s)`);
176
+ }
177
+ return { content: result, updatedCount: configsUpdated };
178
+ }
179
+ if (filesModified > 0) {
180
+ console.log(`\nāœ… Migrated ${filesModified} file(s), updated ${configCallsUpdated} config call(s)`);
181
+ }
182
+ else {
183
+ console.log('\nāœ… No provideComboboxConfig calls found that need migration');
184
+ }
185
+ }
186
+ //# sourceMappingURL=combobox.js.map