@ethlete/core 5.0.0-next.52 → 5.0.0-next.54

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.
@@ -1,5 +1,5 @@
1
1
  import { formatFiles, joinPathFragments, logger, readProjectConfiguration, updateProjectConfiguration, visitNotIgnoredFiles, } from '@nx/devkit';
2
- const SCRIPT_PATH = 'tools/generate-build-info.js';
2
+ const SCRIPT_PATH = 'tools/generate-build-info.cjs';
3
3
  const SCRIPT = `const { execSync } = require('child_process');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
@@ -56,24 +56,33 @@ const relativeImport = (from, to) => {
56
56
  };
57
57
  /** Wires the `provideQueryDevtools({ about })` call up to the generated constant, if it can be found. */
58
58
  const wireProvider = (tree, projectRoot, outputPath) => {
59
- let wired = false;
59
+ const candidates = [];
60
60
  visitNotIgnoredFiles(tree, projectRoot, (file) => {
61
- if (wired || !file.endsWith('.ts'))
61
+ if (!file.endsWith('.ts') ||
62
+ file.endsWith('.spec.ts') ||
63
+ file.endsWith('.test.ts') ||
64
+ file.endsWith('.stories.ts')) {
62
65
  return;
66
+ }
63
67
  const contents = tree.read(file, 'utf-8');
64
68
  if (!contents?.includes('provideQueryDevtools('))
65
69
  return;
66
- if (!contents.includes('provideQueryDevtools()')) {
70
+ candidates.push({ file, contents });
71
+ });
72
+ const alreadyWired = candidates.some(({ contents }) => /provideQueryDevtools\(\s*{[\s\S]*?about\s*:\s*APP_BUILD_INFO/.test(contents));
73
+ if (alreadyWired)
74
+ return true;
75
+ const candidate = candidates.find(({ contents }) => contents.includes('provideQueryDevtools()'));
76
+ if (!candidate) {
77
+ for (const { file } of candidates) {
67
78
  logger.warn(`${file} already passes options to provideQueryDevtools() - add \`about: APP_BUILD_INFO\` to them yourself.`);
68
- wired = true;
69
- return;
70
79
  }
71
- const importPath = relativeImport(file, outputPath);
72
- tree.write(file, `import { APP_BUILD_INFO } from '${importPath}';\n` +
73
- contents.replace('provideQueryDevtools()', 'provideQueryDevtools({ about: APP_BUILD_INFO })'));
74
- wired = true;
75
- });
76
- return wired;
80
+ return candidates.length > 0;
81
+ }
82
+ const importPath = relativeImport(candidate.file, outputPath);
83
+ tree.write(candidate.file, `import { APP_BUILD_INFO } from '${importPath}';\n` +
84
+ candidate.contents.replace('provideQueryDevtools()', 'provideQueryDevtools({ about: APP_BUILD_INFO })'));
85
+ return true;
77
86
  };
78
87
  export const devtoolsAboutGenerator = async (tree, options) => {
79
88
  const project = readProjectConfiguration(tree, options.project);
@@ -85,8 +94,9 @@ export const devtoolsAboutGenerator = async (tree, options) => {
85
94
  const gitignore = tree.read('.gitignore', 'utf-8') ?? '';
86
95
  // Regenerated on every build, and its SHA changes with every commit - committing it would put a
87
96
  // one-line diff in every commit that says nothing about the change.
88
- if (!gitignore.includes(outputPath))
89
- tree.write('.gitignore', `${gitignore.trimEnd()}\n${outputPath}\n`);
97
+ if (!gitignore.includes(outputPath)) {
98
+ tree.write('.gitignore', `${gitignore.trimEnd()}${gitignore.trim() ? '\n' : ''}${outputPath}\n`);
99
+ }
90
100
  project.targets ??= {};
91
101
  project.targets['build-info'] = {
92
102
  executor: 'nx:run-commands',
@@ -110,4 +120,3 @@ export const devtoolsAboutGenerator = async (tree, options) => {
110
120
  await formatFiles(tree);
111
121
  };
112
122
  export default devtoolsAboutGenerator;
113
- //# sourceMappingURL=generator.js.map
@@ -1,32 +1,33 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/nx-generators",
2
3
  "generators": {
3
4
  "migrate-to-v5": {
4
- "factory": "./migrate-to-v5/migration",
5
+ "implementation": "./migrate-to-v5/migration",
5
6
  "schema": "./migrate-to-v5/schema.json",
6
7
  "description": "Migrate to v5"
7
8
  },
8
9
  "migrate-provider-shape": {
9
- "factory": "./migrate-provider-shape/migration",
10
+ "implementation": "./migrate-provider-shape/migration",
10
11
  "schema": "./migrate-provider-shape/schema.json",
11
12
  "description": "Rewrite destructured provider tuples into the tree-shakeable definition shape"
12
13
  },
13
14
  "migrate-surface-interaction-swatch": {
14
- "factory": "./migrate-surface-interaction-swatch/migration",
15
+ "implementation": "./migrate-surface-interaction-swatch/migration",
15
16
  "schema": "./migrate-surface-interaction-swatch/schema.json",
16
17
  "description": "Rewrite surface theme interactionColor maps into the { color, onColor, inkColor } swatch shape"
17
18
  },
18
19
  "tailwind-4-color-theme": {
19
- "factory": "./tailwind-4-color-theme/generator",
20
+ "implementation": "./tailwind-4-color-theme/generator",
20
21
  "schema": "./tailwind-4-color-theme/schema.json",
21
22
  "description": "Generate color theming for Tailwind CSS v4"
22
23
  },
23
24
  "tailwind-4-surface-theme": {
24
- "factory": "./tailwind-4-surface-theme/generator",
25
+ "implementation": "./tailwind-4-surface-theme/generator",
25
26
  "schema": "./tailwind-4-surface-theme/schema.json",
26
27
  "description": "Generate surface theming for Tailwind CSS v4"
27
28
  },
28
29
  "devtools-about": {
29
- "factory": "./devtools-about/generator",
30
+ "implementation": "./devtools-about/generator",
30
31
  "schema": "./devtools-about/schema.json",
31
32
  "description": "Generate the app's build info and wire it into provideQueryDevtools({ about })"
32
33
  }
@@ -23,13 +23,13 @@ export const createMigrationScope = (tree, options) => {
23
23
  describe: () => 'the whole workspace',
24
24
  };
25
25
  }
26
+ const uniqueRoots = [...new Set(roots)].filter((root) => !roots.some((candidate) => candidate !== root && (root === candidate || root.startsWith(`${candidate}/`))));
26
27
  return {
27
28
  visit: (targetTree, callback) => {
28
- for (const root of roots) {
29
+ for (const root of uniqueRoots) {
29
30
  visitNotIgnoredFiles(targetTree, root, callback);
30
31
  }
31
32
  },
32
- describe: () => roots.join(', '),
33
+ describe: () => uniqueRoots.join(', '),
33
34
  };
34
35
  };
35
- //# sourceMappingURL=migration-scope.js.map
@@ -48,4 +48,3 @@ export default async function migrateProviderShape(tree, schema) {
48
48
  console.log(`āš ļø ${tasks.length} site(s) need a manual decision - see ${PROVIDER_SHAPE_REPORT_PATH}.`);
49
49
  }
50
50
  }
51
- //# sourceMappingURL=migration.js.map
@@ -48,8 +48,27 @@ const uniqueDefinitionName = (bindingNames, taken) => {
48
48
  taken.add(candidate);
49
49
  return candidate;
50
50
  };
51
+ const collectImportedFactories = (sourceFile) => {
52
+ const importedFactories = new Map();
53
+ for (const statement of sourceFile.statements) {
54
+ if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier))
55
+ continue;
56
+ if (!statement.moduleSpecifier.text.startsWith('@ethlete/'))
57
+ continue;
58
+ const bindings = statement.importClause?.namedBindings;
59
+ if (!bindings || !ts.isNamedImports(bindings))
60
+ continue;
61
+ for (const element of bindings.elements) {
62
+ const importedName = element.propertyName?.text ?? element.name.text;
63
+ if (isKnownFactory(importedName))
64
+ importedFactories.set(element.name.text, importedName);
65
+ }
66
+ }
67
+ return importedFactories;
68
+ };
51
69
  const findTupleSites = (sourceFile) => {
52
70
  const sites = [];
71
+ const importedFactories = collectImportedFactories(sourceFile);
53
72
  for (const statement of sourceFile.statements) {
54
73
  if (!ts.isVariableStatement(statement) || statement.declarationList.declarations.length !== 1)
55
74
  continue;
@@ -59,14 +78,16 @@ const findTupleSites = (sourceFile) => {
59
78
  const call = declaration.initializer;
60
79
  if (!call || !ts.isCallExpression(call) || !ts.isIdentifier(call.expression))
61
80
  continue;
62
- const factory = call.expression.text;
63
- if (!isKnownFactory(factory))
81
+ const factory = importedFactories.get(call.expression.text);
82
+ if (!factory)
64
83
  continue;
65
84
  const bindings = declaration.name.elements.map((element) => {
66
85
  if (ts.isOmittedExpression(element) || !ts.isIdentifier(element.name))
67
86
  return null;
68
87
  return element.name.text;
69
88
  });
89
+ if (bindings.length > POSITION_TO_EXTRACTOR.length)
90
+ continue;
70
91
  sites.push({
71
92
  statement,
72
93
  call,
@@ -108,26 +129,23 @@ const rewriteSite = (content, sourceFile, site, definitionName) => {
108
129
  const rewriteImports = (sourceFile, factoriesUsed, extractorsUsed) => {
109
130
  const rewrites = [];
110
131
  const imports = sourceFile.statements.filter(ts.isImportDeclaration);
111
- /** The declaration the extractors join: the one that already provides them, else any core import. */
132
+ const replacementsUsed = new Set([...factoriesUsed].flatMap((factory) => (FACTORY_TO_DEFINE[factory] ? [FACTORY_TO_DEFINE[factory]] : [])));
112
133
  const extractorHost = imports.find((statement) => namedImportsOf(statement, sourceFile)?.some((name) => extractorsUsed.has(name))) ??
113
- imports.find((statement) => {
114
- const names = namedImportsOf(statement, sourceFile);
115
- return names?.some((name) => FACTORY_TO_DEFINE[name] !== undefined) || isCoreImport(statement);
116
- });
134
+ imports.find(isCoreImport);
117
135
  for (const statement of imports) {
118
136
  const bindings = statement.importClause?.namedBindings;
119
137
  if (!bindings || !ts.isNamedImports(bindings))
120
138
  continue;
121
- const names = bindings.elements.map((element) => element.getText(sourceFile));
122
- // A ref factory keeps its name and its import; only a replaced factory is swapped out.
123
- const replaced = names.filter((name) => factoriesUsed.has(name) && FACTORY_TO_DEFINE[name] !== undefined);
124
- const extractors = statement === extractorHost ? [...extractorsUsed] : [];
125
- if (replaced.length === 0 && extractors.length === 0)
139
+ const elements = bindings.elements.map((element) => ({
140
+ text: element.getText(sourceFile),
141
+ importedName: element.propertyName?.text ?? element.name.text,
142
+ }));
143
+ const replaced = elements.filter((element) => factoriesUsed.has(element.importedName) && FACTORY_TO_DEFINE[element.importedName] !== undefined);
144
+ const additions = statement === extractorHost ? [...replacementsUsed, ...extractorsUsed] : [];
145
+ if (replaced.length === 0 && additions.length === 0)
126
146
  continue;
127
- const kept = names.filter((name) => !replaced.includes(name));
128
- const merged = [
129
- ...new Set([...kept, ...replaced.map((factory) => FACTORY_TO_DEFINE[factory]), ...extractors]),
130
- ].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
147
+ const kept = elements.filter((element) => !replaced.includes(element)).map((element) => element.text);
148
+ const merged = [...new Set([...kept, ...additions])].sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
131
149
  rewrites.push({
132
150
  start: bindings.getStart(sourceFile),
133
151
  end: bindings.getEnd(),
@@ -139,7 +157,7 @@ const rewriteImports = (sourceFile, factoriesUsed, extractorsUsed) => {
139
157
  // Nothing to join - the file only imported a ref factory from another package, so add a core import.
140
158
  const anchor = imports[imports.length - 1];
141
159
  const position = anchor ? anchor.getEnd() : 0;
142
- const statement = `import { ${[...extractorsUsed].sort().join(', ')} } from '@ethlete/core';`;
160
+ const statement = `import { ${[...replacementsUsed, ...extractorsUsed].sort().join(', ')} } from '@ethlete/core';`;
143
161
  rewrites.push({ start: position, end: position, text: anchor ? `\n${statement}` : `${statement}\n` });
144
162
  return rewrites;
145
163
  };
@@ -163,10 +181,7 @@ export const migrateProviderShapeInFile = (filePath, content) => {
163
181
  const tasks = collectTasks(filePath, sourceFile, sites);
164
182
  if (sites.length === 0)
165
183
  return { content, changed: false, tasks };
166
- const taken = new Set(sourceFile.statements
167
- .filter(ts.isVariableStatement)
168
- .flatMap((statement) => statement.declarationList.declarations)
169
- .flatMap((declaration) => (ts.isIdentifier(declaration.name) ? [declaration.name.text] : [])));
184
+ const taken = collectTopLevelNames(sourceFile);
170
185
  const factoriesUsed = new Set(sites.map((site) => site.factory));
171
186
  const extractorsUsed = new Set(sites.flatMap((site) => site.bindings.flatMap((binding, index) => (binding === null ? [] : [POSITION_TO_EXTRACTOR[index]]))));
172
187
  const edits = [
@@ -183,12 +198,40 @@ export const migrateProviderShapeInFile = (filePath, content) => {
183
198
  const collectTasks = (filePath, sourceFile, sites) => {
184
199
  const rewritten = new Set(sites.map((site) => site.statement));
185
200
  const tasks = [];
201
+ const importedFactories = collectImportedFactories(sourceFile);
202
+ for (const statement of sourceFile.statements) {
203
+ if (!ts.isExportDeclaration(statement))
204
+ continue;
205
+ if (!statement.moduleSpecifier || !ts.isStringLiteral(statement.moduleSpecifier))
206
+ continue;
207
+ if (!statement.moduleSpecifier.text.startsWith('@ethlete/') || !statement.exportClause)
208
+ continue;
209
+ if (!ts.isNamedExports(statement.exportClause))
210
+ continue;
211
+ for (const element of statement.exportClause.elements) {
212
+ const exportedName = element.propertyName?.text ?? element.name.text;
213
+ if (!isKnownFactory(exportedName))
214
+ continue;
215
+ const { line } = sourceFile.getLineAndCharacterOfPosition(element.getStart(sourceFile));
216
+ tasks.push({
217
+ id: `provider-shape:${filePath}:${line + 1}`,
218
+ file: filePath,
219
+ line: line + 1,
220
+ message: `The \`${exportedName}\` re-export must be migrated manually because the replacement API returns a provider definition.`,
221
+ });
222
+ }
223
+ }
186
224
  const visit = (node) => {
187
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && isKnownFactory(node.expression.text)) {
225
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
226
+ const importedFactory = importedFactories.get(node.expression.text);
227
+ if (!importedFactory || FACTORY_TO_DEFINE[importedFactory] === undefined) {
228
+ ts.forEachChild(node, visit);
229
+ return;
230
+ }
188
231
  const statement = enclosingStatement(node);
189
232
  if (!statement || !rewritten.has(statement)) {
190
233
  const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
191
- const factory = node.expression.text;
234
+ const factory = importedFactory;
192
235
  const replacement = FACTORY_TO_DEFINE[factory];
193
236
  tasks.push({
194
237
  id: `provider-shape:${filePath}:${line + 1}`,
@@ -205,6 +248,31 @@ const collectTasks = (filePath, sourceFile, sites) => {
205
248
  visit(sourceFile);
206
249
  return tasks;
207
250
  };
251
+ const collectTopLevelNames = (sourceFile) => {
252
+ const names = new Set();
253
+ for (const statement of sourceFile.statements) {
254
+ if (ts.isImportDeclaration(statement)) {
255
+ const clause = statement.importClause;
256
+ if (clause?.name)
257
+ names.add(clause.name.text);
258
+ const bindings = clause?.namedBindings;
259
+ if (bindings && ts.isNamedImports(bindings))
260
+ bindings.elements.forEach((element) => names.add(element.name.text));
261
+ if (bindings && ts.isNamespaceImport(bindings))
262
+ names.add(bindings.name.text);
263
+ }
264
+ else if (ts.isVariableStatement(statement)) {
265
+ for (const declaration of statement.declarationList.declarations) {
266
+ if (ts.isIdentifier(declaration.name))
267
+ names.add(declaration.name.text);
268
+ }
269
+ }
270
+ else if ((ts.isClassDeclaration(statement) || ts.isFunctionDeclaration(statement)) && statement.name) {
271
+ names.add(statement.name.text);
272
+ }
273
+ }
274
+ return names;
275
+ };
208
276
  const enclosingStatement = (node) => {
209
277
  let current = node;
210
278
  while (current && !ts.isSourceFile(current)) {
@@ -214,4 +282,3 @@ const enclosingStatement = (node) => {
214
282
  }
215
283
  return undefined;
216
284
  };
217
- //# sourceMappingURL=provider-shape.js.map
@@ -18,6 +18,16 @@ const findFlatInteractionColor = (sourceFile) => {
18
18
  if (initializer?.isKind(SyntaxKind.ObjectLiteralExpression) && isFlatInteractionColor(initializer)) {
19
19
  return initializer;
20
20
  }
21
+ if (initializer?.isKind(SyntaxKind.Identifier)) {
22
+ const declaration = sourceFile
23
+ .getVariableDeclarations()
24
+ .find((candidate) => candidate.getName() === initializer.getText());
25
+ const referencedInitializer = declaration?.getInitializer();
26
+ if (referencedInitializer?.isKind(SyntaxKind.ObjectLiteralExpression) &&
27
+ isFlatInteractionColor(referencedInitializer)) {
28
+ return referencedInitializer;
29
+ }
30
+ }
21
31
  }
22
32
  return null;
23
33
  };
@@ -38,6 +48,16 @@ export const migrateInteractionSwatchInFile = (filePath, content) => {
38
48
  changed = true;
39
49
  initializer = findFlatInteractionColor(sourceFile);
40
50
  }
41
- return { changed, content: changed ? sourceFile.getFullText() : content };
51
+ const unresolved = sourceFile
52
+ .getDescendantsOfKind(SyntaxKind.PropertyAssignment)
53
+ .filter((property) => property.getName() === 'interactionColor')
54
+ .flatMap((property) => {
55
+ const initializer = property.getInitializer();
56
+ return initializer && !initializer.isKind(SyntaxKind.ObjectLiteralExpression) ? [initializer.getText()] : [];
57
+ });
58
+ return {
59
+ changed,
60
+ content: changed ? sourceFile.getFullText() : content,
61
+ ...(unresolved.length > 0 ? { unresolved } : {}),
62
+ };
42
63
  };
43
- //# sourceMappingURL=interaction-swatch.js.map
@@ -6,6 +6,7 @@ export default async function migrateSurfaceInteractionSwatch(tree, schema) {
6
6
  const scope = createMigrationScope(tree, schema);
7
7
  console.log(` Scope: ${scope.describe()}`);
8
8
  let filesChanged = 0;
9
+ let unresolvedCount = 0;
9
10
  scope.visit(tree, (filePath) => {
10
11
  if (!filePath.endsWith('.ts') || filePath.endsWith('.d.ts'))
11
12
  return;
@@ -13,6 +14,10 @@ export default async function migrateSurfaceInteractionSwatch(tree, schema) {
13
14
  if (!before)
14
15
  return;
15
16
  const result = migrateInteractionSwatchInFile(filePath, before);
17
+ for (const expression of result.unresolved ?? []) {
18
+ unresolvedCount++;
19
+ console.warn(` ⚠ ${filePath}: could not resolve interactionColor value ${expression}`);
20
+ }
16
21
  if (!result.changed)
17
22
  return;
18
23
  tree.write(filePath, result.content);
@@ -22,8 +27,10 @@ export default async function migrateSurfaceInteractionSwatch(tree, schema) {
22
27
  console.log(filesChanged === 0
23
28
  ? ' Nothing to migrate.\n'
24
29
  : `\nāœ… Migrated ${filesChanged} file(s). Regenerate your surface CSS with \`nx g @ethlete/core:tailwind-4-surface-theme\`.\n`);
30
+ if (unresolvedCount > 0) {
31
+ console.warn(` Review ${unresolvedCount} unresolved interactionColor value(s) manually.\n`);
32
+ }
25
33
  if (!schema.skipFormat) {
26
34
  await formatFiles(tree);
27
35
  }
28
36
  }
29
- //# sourceMappingURL=migration.js.map
@@ -5,10 +5,10 @@ import { logger } from '@nx/devkit';
5
5
  const TS_SYMBOL_RENAMES = {
6
6
  ProvideThemeDirective: 'ProvideColorDirective',
7
7
  THEME_PROVIDER: 'COLOR_PROVIDER',
8
- ColorThemedDirective: 'ColoredDirective',
9
- ColorThemedStylesComponent: 'ColoredStylesComponent',
10
- SurfaceThemedDirective: 'SurfacedDirective',
11
- SurfaceThemedStylesComponent: 'SurfacedStylesComponent',
8
+ ColorThemedDirective: 'ColorInteractiveDirective',
9
+ ColorThemedStylesComponent: 'ColorInteractiveStylesComponent',
10
+ SurfaceThemedDirective: 'SurfaceInteractiveDirective',
11
+ SurfaceThemedStylesComponent: 'SurfaceInteractiveStylesComponent',
12
12
  injectThemesPrefix: 'injectColorThemesPrefix',
13
13
  createCssThemeName: 'createCssColorThemeName',
14
14
  };
@@ -18,14 +18,10 @@ const TS_SYMBOL_RENAMES = {
18
18
  const TEMPLATE_REPLACEMENTS = [
19
19
  ['[etProvideTheme]', '[etProvideColor]'],
20
20
  ['etProvideTheme', 'etProvideColor'],
21
- ['[etProvideAltTheme]', '[etProvideAltColor]'],
22
- ['etProvideAltTheme', 'etProvideAltColor'],
23
- ['[etColorThemed]', '[etColored]'],
24
- ['etColorThemed', 'etColored'],
25
- ['[etSurfaceThemed]', '[etSurfaced]'],
26
- ['etSurfaceThemed', 'etSurfaced'],
27
- ['[theme]=', '[color]='],
28
- ['[altTheme]=', '[altColor]='],
21
+ ['[etColorThemed]', '[etColorInteractive]'],
22
+ ['etColorThemed', 'etColorInteractive'],
23
+ ['[etSurfaceThemed]', '[etSurfaceInteractive]'],
24
+ ['etSurfaceThemed', 'etSurfaceInteractive'],
29
25
  ['et-theme-alt--', 'et-color-alt--'],
30
26
  ['et-theme--', 'et-color--'],
31
27
  ];
@@ -33,8 +29,8 @@ const TEMPLATE_REPLACEMENTS = [
33
29
  * CSS class name replacements.
34
30
  */
35
31
  const CSS_REPLACEMENTS = [
36
- ['.et-color-themed', '.et-colored'],
37
- ['.et-surface-themed', '.et-surfaced'],
32
+ ['.et-color-themed', '.et-color-interactive'],
33
+ ['.et-surface-themed', '.et-surface-interactive'],
38
34
  ['.et-theme--', '.et-color--'],
39
35
  ['.et-theme-alt--', '.et-color-alt--'],
40
36
  ];
@@ -43,13 +39,11 @@ const CSS_REPLACEMENTS = [
43
39
  */
44
40
  const HOST_DIRECTIVE_REPLACEMENTS = [
45
41
  ["'etProvideTheme:theme'", "'etProvideColor:color'"],
46
- ["'etProvideAltTheme:altTheme'", "'etProvideAltColor:altColor'"],
47
42
  ["'etProvideTheme:color'", "'etProvideColor:color'"],
48
- ["'etProvideAltTheme:altColor'", "'etProvideAltColor:altColor'"],
49
43
  ['"etProvideTheme:theme"', '"etProvideColor:color"'],
50
- ['"etProvideAltTheme:altTheme"', '"etProvideAltColor:altColor"'],
51
44
  ['"etProvideTheme"', '"etProvideColor"'],
52
- ['"etProvideAltTheme"', '"etProvideAltColor"'],
45
+ ["'etProvideTheme: theme'", "'etProvideColor: color'"],
46
+ ['"etProvideTheme: theme"', '"etProvideColor: color"'],
53
47
  ];
54
48
  export default async function migrateColorNaming(tree) {
55
49
  logger.log('\nšŸ”„ Migrating theme → color naming...\n');
@@ -93,7 +87,7 @@ function findFiles(dir, tree, tsFiles, htmlFiles, cssFiles) {
93
87
  if (tree.isFile(path)) {
94
88
  if (path.includes('node_modules'))
95
89
  continue;
96
- if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {
90
+ if (path.endsWith('.ts')) {
97
91
  tsFiles.push(path);
98
92
  }
99
93
  else if (path.endsWith('.html')) {
@@ -115,6 +109,8 @@ function migrateTypeScriptFile(tree, filePath) {
115
109
  if (!content)
116
110
  return false;
117
111
  const original = content;
112
+ if (!/from\s+['"]@ethlete\/(?:core|cdk)['"]/.test(content))
113
+ return false;
118
114
  // Rename symbols
119
115
  for (const [oldName, newName] of Object.entries(TS_SYMBOL_RENAMES)) {
120
116
  content = replaceWholeWord(content, oldName, newName);
@@ -172,4 +168,3 @@ function replaceWholeWord(content, oldWord, newWord) {
172
168
  function escapeRegex(str) {
173
169
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
174
170
  }
175
- //# sourceMappingURL=color-naming.js.map
@@ -9,11 +9,13 @@ export default async function migrateCreateProvider(tree) {
9
9
  for (const child of children) {
10
10
  const path = dir === '.' ? child : `${dir}/${child}`;
11
11
  if (tree.isFile(path)) {
12
- if (path.endsWith('.ts') && !path.includes('node_modules') && !path.endsWith('.spec.ts')) {
12
+ if (path.endsWith('.ts') && !path.includes('node_modules')) {
13
13
  tsFiles.push(path);
14
14
  }
15
15
  }
16
16
  else {
17
+ if (child === 'node_modules')
18
+ continue;
17
19
  findTsFiles(path);
18
20
  }
19
21
  }
@@ -41,6 +43,7 @@ function migrateCreateProviderInFile(tree, filePath) {
41
43
  const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
42
44
  let cdkImport;
43
45
  let hasCreateProviderInCdk = false;
46
+ let createProviderImport = 'createProvider';
44
47
  // Find relevant imports
45
48
  for (const statement of sourceFile.statements) {
46
49
  if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
@@ -48,7 +51,9 @@ function migrateCreateProviderInFile(tree, filePath) {
48
51
  if (modulePath === '@ethlete/cdk') {
49
52
  cdkImport = statement;
50
53
  if (statement.importClause?.namedBindings && ts.isNamedImports(statement.importClause.namedBindings)) {
51
- hasCreateProviderInCdk = statement.importClause.namedBindings.elements.some((element) => element.name.text === 'createProvider');
54
+ const specifier = statement.importClause.namedBindings.elements.find((element) => (element.propertyName?.text ?? element.name.text) === 'createProvider');
55
+ hasCreateProviderInCdk = !!specifier;
56
+ createProviderImport = specifier?.getText(sourceFile) ?? createProviderImport;
52
57
  }
53
58
  }
54
59
  }
@@ -60,7 +65,7 @@ function migrateCreateProviderInFile(tree, filePath) {
60
65
  // Remove createProvider from @ethlete/cdk import
61
66
  if (cdkImport && cdkImport.importClause?.namedBindings && ts.isNamedImports(cdkImport.importClause.namedBindings)) {
62
67
  const namedBindings = cdkImport.importClause.namedBindings;
63
- const otherImports = namedBindings.elements.filter((element) => element.name.text !== 'createProvider');
68
+ const otherImports = namedBindings.elements.filter((element) => (element.propertyName?.text ?? element.name.text) !== 'createProvider');
64
69
  const importStart = cdkImport.getStart(sourceFile);
65
70
  const importEnd = cdkImport.getEnd();
66
71
  if (otherImports.length === 0) {
@@ -80,7 +85,7 @@ function migrateCreateProviderInFile(tree, filePath) {
80
85
  }
81
86
  else {
82
87
  // Keep other imports
83
- const newImports = otherImports.map((el) => el.name.text).join(', ');
88
+ const newImports = otherImports.map((el) => el.getText(sourceFile)).join(', ');
84
89
  const newImportText = `import { ${newImports} } from '@ethlete/cdk';`;
85
90
  updatedContent = content.slice(0, importStart) + newImportText + content.slice(importEnd);
86
91
  }
@@ -102,12 +107,12 @@ function migrateCreateProviderInFile(tree, filePath) {
102
107
  ts.isNamedImports(updatedCoreImport.importClause.namedBindings)) {
103
108
  const namedBindings = updatedCoreImport.importClause.namedBindings;
104
109
  // Check if createProvider already exists
105
- const hasCreateProvider = namedBindings.elements.some((element) => element.name.text === 'createProvider');
110
+ const hasCreateProvider = namedBindings.elements.some((element) => (element.propertyName?.text ?? element.name.text) === 'createProvider');
106
111
  if (!hasCreateProvider) {
107
112
  const importStart = updatedCoreImport.getStart(intermediateSourceFile);
108
113
  const importEnd = updatedCoreImport.getEnd();
109
- const existingImports = namedBindings.elements.map((el) => el.name.text);
110
- const allImports = [...existingImports, 'createProvider'].sort();
114
+ const existingImports = namedBindings.elements.map((el) => el.getText(intermediateSourceFile));
115
+ const allImports = [...existingImports, createProviderImport].sort();
111
116
  const newImportText = `import { ${allImports.join(', ')} } from '@ethlete/core';`;
112
117
  updatedContent = updatedContent.slice(0, importStart) + newImportText + updatedContent.slice(importEnd);
113
118
  }
@@ -137,12 +142,12 @@ function migrateCreateProviderInFile(tree, filePath) {
137
142
  }
138
143
  updatedContent =
139
144
  updatedContent.slice(0, insertPosition) +
140
- "import { createProvider } from '@ethlete/core';\n" +
145
+ `import { ${createProviderImport} } from '@ethlete/core';\n` +
141
146
  updatedContent.slice(insertPosition);
142
147
  }
143
148
  else {
144
149
  // No imports, add at the beginning
145
- updatedContent = "import { createProvider } from '@ethlete/core';\n\n" + updatedContent;
150
+ updatedContent = `import { ${createProviderImport} } from '@ethlete/core';\n\n` + updatedContent;
146
151
  }
147
152
  }
148
153
  if (updatedContent !== content) {
@@ -151,4 +156,3 @@ function migrateCreateProviderInFile(tree, filePath) {
151
156
  }
152
157
  return false;
153
158
  }
154
- //# sourceMappingURL=create-provider.js.map
@@ -31,4 +31,3 @@ export default async function migrate(tree, schema) {
31
31
  console.log('\nāœ… Migration completed successfully!');
32
32
  }
33
33
  //#endregion
34
- //# sourceMappingURL=migration.js.map