@ethlete/core 5.0.0-next.53 ā 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.
- package/CHANGELOG.md +15 -0
- package/fesm2022/ethlete-core.mjs +638 -542
- package/fesm2022/ethlete-core.mjs.map +1 -1
- package/generators/devtools-about/generator.js +24 -15
- package/generators/generators.json +7 -6
- package/generators/migrate-provider-shape/migration-scope.js +3 -3
- package/generators/migrate-provider-shape/migration.js +0 -1
- package/generators/migrate-provider-shape/provider-shape.js +91 -24
- package/generators/migrate-surface-interaction-swatch/interaction-swatch.js +22 -2
- package/generators/migrate-surface-interaction-swatch/migration.js +8 -1
- package/generators/migrate-to-v5/color-naming.js +15 -20
- package/generators/migrate-to-v5/create-provider.js +14 -10
- package/generators/migrate-to-v5/migration.js +0 -1
- package/generators/migrate-to-v5/router-state-service.js +33 -8
- package/generators/migrate-to-v5/viewport-service.js +41 -59
- package/generators/tailwind-4-color-theme/generator.js +30 -21
- package/generators/tailwind-4-surface-theme/generator.js +60 -30
- package/package.json +2 -10
- package/types/ethlete-core.d.ts +49 -52
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatFiles, joinPathFragments, logger, readProjectConfiguration, updateProjectConfiguration, visitNotIgnoredFiles, } from '@nx/devkit';
|
|
2
|
-
const SCRIPT_PATH = 'tools/generate-build-info.
|
|
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
|
-
|
|
59
|
+
const candidates = [];
|
|
60
60
|
visitNotIgnoredFiles(tree, projectRoot, (file) => {
|
|
61
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
|
29
|
+
for (const root of uniqueRoots) {
|
|
29
30
|
visitNotIgnoredFiles(targetTree, root, callback);
|
|
30
31
|
}
|
|
31
32
|
},
|
|
32
|
-
describe: () =>
|
|
33
|
+
describe: () => uniqueRoots.join(', '),
|
|
33
34
|
};
|
|
34
35
|
};
|
|
35
|
-
//# sourceMappingURL=migration-scope.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 (!
|
|
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
|
-
|
|
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(
|
|
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
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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 =
|
|
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 =
|
|
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)
|
|
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 =
|
|
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
|
-
|
|
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: '
|
|
9
|
-
ColorThemedStylesComponent: '
|
|
10
|
-
SurfaceThemedDirective: '
|
|
11
|
-
SurfaceThemedStylesComponent: '
|
|
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
|
-
['[
|
|
22
|
-
['
|
|
23
|
-
['[
|
|
24
|
-
['
|
|
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-
|
|
37
|
-
['.et-surface-themed', '.et-
|
|
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
|
-
['"
|
|
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')
|
|
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')
|
|
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
|
-
|
|
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.
|
|
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.
|
|
110
|
-
const allImports = [...existingImports,
|
|
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
|
-
|
|
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 =
|
|
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
|