@ethlete/core 4.30.0 ā 5.0.0-beta.11
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 +153 -0
- package/fesm2022/ethlete-core.mjs +5591 -4969
- package/fesm2022/ethlete-core.mjs.map +1 -1
- package/generators/generators.json +19 -0
- package/generators/migrate-to-v5/color-naming.js +173 -0
- package/generators/migrate-to-v5/create-provider.js +158 -0
- package/generators/migrate-to-v5/migration.js +34 -0
- package/generators/migrate-to-v5/router-state-service.js +1064 -0
- package/generators/migrate-to-v5/schema.json +34 -0
- package/generators/migrate-to-v5/viewport-service.js +1678 -0
- package/generators/tailwind-4-color-theme/generator.js +513 -0
- package/generators/tailwind-4-color-theme/schema.json +32 -0
- package/generators/tailwind-4-surface-theme/generator.js +368 -0
- package/generators/tailwind-4-surface-theme/schema.json +32 -0
- package/package.json +20 -12
- package/types/ethlete-core.d.ts +2622 -0
- package/index.d.ts +0 -1968
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generators": {
|
|
3
|
+
"migrate-to-v5": {
|
|
4
|
+
"factory": "./migrate-to-v5/migration",
|
|
5
|
+
"schema": "./migrate-to-v5/schema.json",
|
|
6
|
+
"description": "Migrate to v5"
|
|
7
|
+
},
|
|
8
|
+
"tailwind-4-color-theme": {
|
|
9
|
+
"factory": "./tailwind-4-color-theme/generator",
|
|
10
|
+
"schema": "./tailwind-4-color-theme/schema.json",
|
|
11
|
+
"description": "Generate color theming for Tailwind CSS v4"
|
|
12
|
+
},
|
|
13
|
+
"tailwind-4-surface-theme": {
|
|
14
|
+
"factory": "./tailwind-4-surface-theme/generator",
|
|
15
|
+
"schema": "./tailwind-4-surface-theme/schema.json",
|
|
16
|
+
"description": "Generate surface theming for Tailwind CSS v4"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { logger } from '@nx/devkit';
|
|
2
|
+
/**
|
|
3
|
+
* Symbol renames in TypeScript files (imports + usage).
|
|
4
|
+
*/
|
|
5
|
+
const TS_SYMBOL_RENAMES = {
|
|
6
|
+
ProvideThemeDirective: 'ProvideColorDirective',
|
|
7
|
+
THEME_PROVIDER: 'COLOR_PROVIDER',
|
|
8
|
+
ColorThemedDirective: 'ColoredDirective',
|
|
9
|
+
ColorThemedStylesComponent: 'ColoredStylesComponent',
|
|
10
|
+
SurfaceThemedDirective: 'SurfacedDirective',
|
|
11
|
+
SurfaceThemedStylesComponent: 'SurfacedStylesComponent',
|
|
12
|
+
injectThemesPrefix: 'injectColorThemesPrefix',
|
|
13
|
+
createCssThemeName: 'createCssColorThemeName',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* String replacements applied to HTML templates and inline templates.
|
|
17
|
+
*/
|
|
18
|
+
const TEMPLATE_REPLACEMENTS = [
|
|
19
|
+
['[etProvideTheme]', '[etProvideColor]'],
|
|
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]='],
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* CSS class name replacements.
|
|
32
|
+
*/
|
|
33
|
+
const CSS_REPLACEMENTS = [
|
|
34
|
+
['.et-color-themed', '.et-colored'],
|
|
35
|
+
['.et-surface-themed', '.et-surfaced'],
|
|
36
|
+
['.et-theme--', '.et-color--'],
|
|
37
|
+
['.et-theme-alt--', '.et-color-alt--'],
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Host directive input alias replacements in TypeScript files.
|
|
41
|
+
*/
|
|
42
|
+
const HOST_DIRECTIVE_REPLACEMENTS = [
|
|
43
|
+
["'etProvideTheme:theme'", "'etProvideColor:color'"],
|
|
44
|
+
["'etProvideAltTheme:altTheme'", "'etProvideAltColor:altColor'"],
|
|
45
|
+
["'etProvideTheme:color'", "'etProvideColor:color'"],
|
|
46
|
+
["'etProvideAltTheme:altColor'", "'etProvideAltColor:altColor'"],
|
|
47
|
+
['"etProvideTheme:theme"', '"etProvideColor:color"'],
|
|
48
|
+
['"etProvideAltTheme:altTheme"', '"etProvideAltColor:altColor"'],
|
|
49
|
+
['"etProvideTheme"', '"etProvideColor"'],
|
|
50
|
+
['"etProvideAltTheme"', '"etProvideAltColor"'],
|
|
51
|
+
];
|
|
52
|
+
export default async function migrateColorNaming(tree) {
|
|
53
|
+
logger.log('\nš Migrating theme ā color naming...\n');
|
|
54
|
+
const tsFiles = [];
|
|
55
|
+
const htmlFiles = [];
|
|
56
|
+
const cssFiles = [];
|
|
57
|
+
findFiles('.', tree, tsFiles, htmlFiles, cssFiles);
|
|
58
|
+
let filesModified = 0;
|
|
59
|
+
for (const filePath of tsFiles) {
|
|
60
|
+
const wasModified = migrateTypeScriptFile(tree, filePath);
|
|
61
|
+
if (wasModified) {
|
|
62
|
+
filesModified++;
|
|
63
|
+
logger.log(` ā ${filePath}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const filePath of htmlFiles) {
|
|
67
|
+
const wasModified = migrateTemplateFile(tree, filePath);
|
|
68
|
+
if (wasModified) {
|
|
69
|
+
filesModified++;
|
|
70
|
+
logger.log(` ā ${filePath}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
for (const filePath of cssFiles) {
|
|
74
|
+
const wasModified = migrateCssFile(tree, filePath);
|
|
75
|
+
if (wasModified) {
|
|
76
|
+
filesModified++;
|
|
77
|
+
logger.log(` ā ${filePath}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (filesModified > 0) {
|
|
81
|
+
logger.log(`\nā
Successfully migrated color naming in ${filesModified} file(s)\n`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
logger.log('\nā¹ļø No files needed migration\n');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function findFiles(dir, tree, tsFiles, htmlFiles, cssFiles) {
|
|
88
|
+
const children = tree.children(dir);
|
|
89
|
+
for (const child of children) {
|
|
90
|
+
const path = dir === '.' ? child : `${dir}/${child}`;
|
|
91
|
+
if (tree.isFile(path)) {
|
|
92
|
+
if (path.includes('node_modules'))
|
|
93
|
+
continue;
|
|
94
|
+
if (path.endsWith('.ts') && !path.endsWith('.spec.ts')) {
|
|
95
|
+
tsFiles.push(path);
|
|
96
|
+
}
|
|
97
|
+
else if (path.endsWith('.html')) {
|
|
98
|
+
htmlFiles.push(path);
|
|
99
|
+
}
|
|
100
|
+
else if (path.endsWith('.css') || path.endsWith('.scss')) {
|
|
101
|
+
cssFiles.push(path);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
if (child === 'node_modules')
|
|
106
|
+
continue;
|
|
107
|
+
findFiles(path, tree, tsFiles, htmlFiles, cssFiles);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function migrateTypeScriptFile(tree, filePath) {
|
|
112
|
+
let content = tree.read(filePath, 'utf-8');
|
|
113
|
+
if (!content)
|
|
114
|
+
return false;
|
|
115
|
+
const original = content;
|
|
116
|
+
// Rename symbols
|
|
117
|
+
for (const [oldName, newName] of Object.entries(TS_SYMBOL_RENAMES)) {
|
|
118
|
+
content = replaceWholeWord(content, oldName, newName);
|
|
119
|
+
}
|
|
120
|
+
// Rename host directive input aliases
|
|
121
|
+
for (const [oldStr, newStr] of HOST_DIRECTIVE_REPLACEMENTS) {
|
|
122
|
+
content = content.replaceAll(oldStr, newStr);
|
|
123
|
+
}
|
|
124
|
+
// Handle inline templates in TypeScript files
|
|
125
|
+
for (const [oldStr, newStr] of TEMPLATE_REPLACEMENTS) {
|
|
126
|
+
content = content.replaceAll(oldStr, newStr);
|
|
127
|
+
}
|
|
128
|
+
// Handle CSS in TypeScript files
|
|
129
|
+
for (const [oldStr, newStr] of CSS_REPLACEMENTS) {
|
|
130
|
+
content = content.replaceAll(oldStr, newStr);
|
|
131
|
+
}
|
|
132
|
+
if (content !== original) {
|
|
133
|
+
tree.write(filePath, content);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
function migrateTemplateFile(tree, filePath) {
|
|
139
|
+
let content = tree.read(filePath, 'utf-8');
|
|
140
|
+
if (!content)
|
|
141
|
+
return false;
|
|
142
|
+
const original = content;
|
|
143
|
+
for (const [oldStr, newStr] of TEMPLATE_REPLACEMENTS) {
|
|
144
|
+
content = content.replaceAll(oldStr, newStr);
|
|
145
|
+
}
|
|
146
|
+
if (content !== original) {
|
|
147
|
+
tree.write(filePath, content);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
function migrateCssFile(tree, filePath) {
|
|
153
|
+
let content = tree.read(filePath, 'utf-8');
|
|
154
|
+
if (!content)
|
|
155
|
+
return false;
|
|
156
|
+
const original = content;
|
|
157
|
+
for (const [oldStr, newStr] of CSS_REPLACEMENTS) {
|
|
158
|
+
content = content.replaceAll(oldStr, newStr);
|
|
159
|
+
}
|
|
160
|
+
if (content !== original) {
|
|
161
|
+
tree.write(filePath, content);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
function replaceWholeWord(content, oldWord, newWord) {
|
|
167
|
+
const regex = new RegExp(`\\b${escapeRegex(oldWord)}\\b`, 'g');
|
|
168
|
+
return content.replace(regex, newWord);
|
|
169
|
+
}
|
|
170
|
+
function escapeRegex(str) {
|
|
171
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=color-naming.js.map
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { logger } from '@nx/devkit';
|
|
2
|
+
import * as ts from 'typescript';
|
|
3
|
+
export default async function migrateCreateProvider(tree) {
|
|
4
|
+
logger.log('\nš Migrating createProvider imports from @ethlete/cdk to @ethlete/core...\n');
|
|
5
|
+
const tsFiles = [];
|
|
6
|
+
// Recursively find all TypeScript files
|
|
7
|
+
function findTsFiles(dir) {
|
|
8
|
+
const children = tree.children(dir);
|
|
9
|
+
for (const child of children) {
|
|
10
|
+
const path = dir === '.' ? child : `${dir}/${child}`;
|
|
11
|
+
if (tree.isFile(path)) {
|
|
12
|
+
if (path.endsWith('.ts') && !path.includes('node_modules') && !path.endsWith('.spec.ts')) {
|
|
13
|
+
tsFiles.push(path);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
findTsFiles(path);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
findTsFiles('.');
|
|
22
|
+
let filesModified = 0;
|
|
23
|
+
for (const filePath of tsFiles) {
|
|
24
|
+
const wasModified = migrateCreateProviderInFile(tree, filePath);
|
|
25
|
+
if (wasModified) {
|
|
26
|
+
filesModified++;
|
|
27
|
+
logger.log(` ā ${filePath}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (filesModified > 0) {
|
|
31
|
+
logger.log(`\nā
Successfully migrated createProvider in ${filesModified} file(s)\n`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
logger.log('\nā¹ļø No files needed migration\n');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function migrateCreateProviderInFile(tree, filePath) {
|
|
38
|
+
const content = tree.read(filePath, 'utf-8');
|
|
39
|
+
if (!content || !content.includes('createProvider'))
|
|
40
|
+
return false;
|
|
41
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
|
|
42
|
+
let cdkImport;
|
|
43
|
+
let coreImport;
|
|
44
|
+
let hasCreateProviderInCdk = false;
|
|
45
|
+
// Find relevant imports
|
|
46
|
+
for (const statement of sourceFile.statements) {
|
|
47
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
48
|
+
const modulePath = statement.moduleSpecifier.text;
|
|
49
|
+
if (modulePath === '@ethlete/cdk') {
|
|
50
|
+
cdkImport = statement;
|
|
51
|
+
if (statement.importClause?.namedBindings && ts.isNamedImports(statement.importClause.namedBindings)) {
|
|
52
|
+
hasCreateProviderInCdk = statement.importClause.namedBindings.elements.some((element) => element.name.text === 'createProvider');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (modulePath === '@ethlete/core') {
|
|
56
|
+
coreImport = statement;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// If createProvider is not imported from @ethlete/cdk, nothing to do
|
|
61
|
+
if (!hasCreateProviderInCdk)
|
|
62
|
+
return false;
|
|
63
|
+
let updatedContent = content;
|
|
64
|
+
// Remove createProvider from @ethlete/cdk import
|
|
65
|
+
if (cdkImport && cdkImport.importClause?.namedBindings && ts.isNamedImports(cdkImport.importClause.namedBindings)) {
|
|
66
|
+
const namedBindings = cdkImport.importClause.namedBindings;
|
|
67
|
+
const otherImports = namedBindings.elements.filter((element) => element.name.text !== 'createProvider');
|
|
68
|
+
const importStart = cdkImport.getStart(sourceFile);
|
|
69
|
+
const importEnd = cdkImport.getEnd();
|
|
70
|
+
if (otherImports.length === 0) {
|
|
71
|
+
// Remove entire import line including newline
|
|
72
|
+
let lineStart = importStart;
|
|
73
|
+
while (lineStart > 0 && content[lineStart - 1] !== '\n') {
|
|
74
|
+
lineStart--;
|
|
75
|
+
}
|
|
76
|
+
let lineEnd = importEnd;
|
|
77
|
+
while (lineEnd < content.length && content[lineEnd] !== '\n') {
|
|
78
|
+
lineEnd++;
|
|
79
|
+
}
|
|
80
|
+
if (content[lineEnd] === '\n') {
|
|
81
|
+
lineEnd++;
|
|
82
|
+
}
|
|
83
|
+
updatedContent = content.slice(0, lineStart) + content.slice(lineEnd);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Keep other imports
|
|
87
|
+
const newImports = otherImports.map((el) => el.name.text).join(', ');
|
|
88
|
+
const newImportText = `import { ${newImports} } from '@ethlete/cdk';`;
|
|
89
|
+
updatedContent = content.slice(0, importStart) + newImportText + content.slice(importEnd);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Re-parse after first modification
|
|
93
|
+
const intermediateSourceFile = ts.createSourceFile(filePath, updatedContent, ts.ScriptTarget.Latest, true);
|
|
94
|
+
// Find @ethlete/core import in the updated content
|
|
95
|
+
let updatedCoreImport;
|
|
96
|
+
for (const statement of intermediateSourceFile.statements) {
|
|
97
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
98
|
+
if (statement.moduleSpecifier.text === '@ethlete/core') {
|
|
99
|
+
updatedCoreImport = statement;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Add createProvider to @ethlete/core import
|
|
105
|
+
if (updatedCoreImport?.importClause?.namedBindings &&
|
|
106
|
+
ts.isNamedImports(updatedCoreImport.importClause.namedBindings)) {
|
|
107
|
+
const namedBindings = updatedCoreImport.importClause.namedBindings;
|
|
108
|
+
// Check if createProvider already exists
|
|
109
|
+
const hasCreateProvider = namedBindings.elements.some((element) => element.name.text === 'createProvider');
|
|
110
|
+
if (!hasCreateProvider) {
|
|
111
|
+
const importStart = updatedCoreImport.getStart(intermediateSourceFile);
|
|
112
|
+
const importEnd = updatedCoreImport.getEnd();
|
|
113
|
+
const existingImports = namedBindings.elements.map((el) => el.name.text);
|
|
114
|
+
const allImports = [...existingImports, 'createProvider'].sort();
|
|
115
|
+
const newImportText = `import { ${allImports.join(', ')} } from '@ethlete/core';`;
|
|
116
|
+
updatedContent = updatedContent.slice(0, importStart) + newImportText + updatedContent.slice(importEnd);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Add new import from @ethlete/core at the top
|
|
121
|
+
const firstImportIndex = updatedContent.indexOf('import');
|
|
122
|
+
if (firstImportIndex !== -1) {
|
|
123
|
+
// Add after other imports
|
|
124
|
+
let insertPosition;
|
|
125
|
+
let lastImportEnd = firstImportIndex;
|
|
126
|
+
for (const statement of intermediateSourceFile.statements) {
|
|
127
|
+
if (ts.isImportDeclaration(statement)) {
|
|
128
|
+
lastImportEnd = statement.getEnd();
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
insertPosition = lastImportEnd;
|
|
135
|
+
// Find end of line
|
|
136
|
+
while (insertPosition < updatedContent.length && updatedContent[insertPosition] !== '\n') {
|
|
137
|
+
insertPosition++;
|
|
138
|
+
}
|
|
139
|
+
if (updatedContent[insertPosition] === '\n') {
|
|
140
|
+
insertPosition++;
|
|
141
|
+
}
|
|
142
|
+
updatedContent =
|
|
143
|
+
updatedContent.slice(0, insertPosition) +
|
|
144
|
+
"import { createProvider } from '@ethlete/core';\n" +
|
|
145
|
+
updatedContent.slice(insertPosition);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// No imports, add at the beginning
|
|
149
|
+
updatedContent = "import { createProvider } from '@ethlete/core';\n\n" + updatedContent;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (updatedContent !== content) {
|
|
153
|
+
tree.write(filePath, updatedContent);
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=create-provider.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { formatFiles } from '@nx/devkit';
|
|
2
|
+
import migrateColorNaming from './color-naming.js';
|
|
3
|
+
import migrateCreateProvider from './create-provider.js';
|
|
4
|
+
import migrateRouterStateService from './router-state-service.js';
|
|
5
|
+
import migrateViewportService from './viewport-service.js';
|
|
6
|
+
export default async function migrate(tree, schema) {
|
|
7
|
+
console.log('\nš Starting core v5 migration...');
|
|
8
|
+
const shouldMigrateViewportService = schema.migrateViewportService !== false;
|
|
9
|
+
const shouldMigrateCreateProvider = schema.migrateCreateProvider !== false;
|
|
10
|
+
const shouldMigrateRouterStateService = schema.migrateRouterStateService !== false;
|
|
11
|
+
if (shouldMigrateViewportService) {
|
|
12
|
+
console.log(' ⢠Migrating viewport service...');
|
|
13
|
+
await migrateViewportService(tree);
|
|
14
|
+
}
|
|
15
|
+
if (shouldMigrateCreateProvider) {
|
|
16
|
+
console.log(' ⢠Migrating create provider...');
|
|
17
|
+
await migrateCreateProvider(tree);
|
|
18
|
+
}
|
|
19
|
+
if (shouldMigrateRouterStateService) {
|
|
20
|
+
await migrateRouterStateService(tree);
|
|
21
|
+
}
|
|
22
|
+
const shouldMigrateColorNaming = schema.migrateColorNaming !== false;
|
|
23
|
+
if (shouldMigrateColorNaming) {
|
|
24
|
+
console.log(' ⢠Migrating theme ā color naming...');
|
|
25
|
+
await migrateColorNaming(tree);
|
|
26
|
+
}
|
|
27
|
+
if (!schema.skipFormat) {
|
|
28
|
+
console.log(' ⢠Formatting files...');
|
|
29
|
+
await formatFiles(tree);
|
|
30
|
+
}
|
|
31
|
+
console.log('\nā
Migration completed successfully!');
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//# sourceMappingURL=migration.js.map
|