@ngcorex/cli 0.1.5 → 0.1.7
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/LICENSE.md +2 -2
- package/README.md +221 -18
- package/dist/commands/init.js +68 -5
- package/dist/commands/run-build.js +241 -47
- package/dist/output/write-css.js +1 -1
- package/dist/utils/logger.js +246 -2
- package/package.json +8 -3
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
MIT License
|
|
1
|
+
# MIT License
|
|
2
2
|
|
|
3
|
-
Copyright
|
|
3
|
+
Copyright © 2026 Ajay Kumar Sharma
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
6
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ngcorex/cli
|
|
2
2
|
|
|
3
|
-
   
|
|
3
|
+
    
|
|
4
4
|
|
|
5
5
|
Command-line interface for **ngCorex**.
|
|
6
6
|
|
|
@@ -63,19 +63,169 @@ Create a `tokens.json` file at your project root:
|
|
|
63
63
|
```json
|
|
64
64
|
{
|
|
65
65
|
"spacing": {
|
|
66
|
-
"
|
|
67
|
-
"
|
|
66
|
+
"xs": "0.25rem",
|
|
67
|
+
"sm": "0.5rem",
|
|
68
|
+
"md": "1rem",
|
|
69
|
+
"lg": "1.5rem",
|
|
70
|
+
"xl": "2rem"
|
|
68
71
|
},
|
|
69
72
|
"colors": {
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
+
"neutral": {
|
|
74
|
+
"0": "#ffffff",
|
|
75
|
+
"100": "#f5f5f5",
|
|
76
|
+
"300": "#d4d4d4",
|
|
77
|
+
"500": "#737373",
|
|
78
|
+
"700": "#404040",
|
|
79
|
+
"900": "#171717"
|
|
80
|
+
},
|
|
81
|
+
"primary": {
|
|
82
|
+
"500": "#2563eb"
|
|
73
83
|
}
|
|
84
|
+
},
|
|
85
|
+
"radius": {
|
|
86
|
+
"sm": "0.25rem",
|
|
87
|
+
"md": "0.5rem",
|
|
88
|
+
"lg": "0.75rem",
|
|
89
|
+
"xl": "1rem",
|
|
90
|
+
"full": "9999px"
|
|
91
|
+
},
|
|
92
|
+
"zIndex": {
|
|
93
|
+
"base": "0",
|
|
94
|
+
"dropdown": "1000",
|
|
95
|
+
"sticky": "1020",
|
|
96
|
+
"fixed": "1030",
|
|
97
|
+
"modal-backdrop": "1040",
|
|
98
|
+
"modal": "1050",
|
|
99
|
+
"popover": "1060",
|
|
100
|
+
"tooltip": "1070"
|
|
101
|
+
},
|
|
102
|
+
"typography": {
|
|
103
|
+
"fontSize": {
|
|
104
|
+
"xs": "0.75rem",
|
|
105
|
+
"sm": "0.875rem",
|
|
106
|
+
"base": "1rem",
|
|
107
|
+
"lg": "1.125rem",
|
|
108
|
+
"xl": "1.25rem",
|
|
109
|
+
"2xl": "1.5rem",
|
|
110
|
+
"3xl": "1.875rem",
|
|
111
|
+
"4xl": "2.25rem"
|
|
112
|
+
},
|
|
113
|
+
"fontWeight": {
|
|
114
|
+
"light": "300",
|
|
115
|
+
"normal": "400",
|
|
116
|
+
"medium": "500",
|
|
117
|
+
"semibold": "600",
|
|
118
|
+
"bold": "700",
|
|
119
|
+
"extrabold": "800"
|
|
120
|
+
},
|
|
121
|
+
"lineHeight": {
|
|
122
|
+
"none": "1",
|
|
123
|
+
"tight": "1.25",
|
|
124
|
+
"snug": "1.375",
|
|
125
|
+
"normal": "1.5",
|
|
126
|
+
"relaxed": "1.625",
|
|
127
|
+
"loose": "2"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"shadows": {
|
|
131
|
+
"sm": "0 1px 2px 0 rgb(0 0 0 / 0.05)",
|
|
132
|
+
"base": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
|
|
133
|
+
"md": "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
|
|
134
|
+
"lg": "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
135
|
+
"xl": "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
|
|
136
|
+
"2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)"
|
|
74
137
|
}
|
|
75
138
|
}
|
|
76
139
|
```
|
|
77
140
|
|
|
78
|
-
|
|
141
|
+
### Supported Token Categories
|
|
142
|
+
|
|
143
|
+
ngCorex supports the following design token categories:
|
|
144
|
+
|
|
145
|
+
| Category | Description | Example Values |
|
|
146
|
+
| ---------- | ------------- | ---------------- |
|
|
147
|
+
| `spacing` | Spacing scale for margins, padding, gaps | `"4px"`, `"1rem"`, `"0.5em"` |
|
|
148
|
+
| `colors` | Color palette with nested shades | `"#f3f4f6"`, `"rgb(37, 99, 235)"` |
|
|
149
|
+
| `radius` | Border radius values | `"4px"`, `"8px"`, `"16px"`, `"full"` |
|
|
150
|
+
| `zIndex` | Z-index layer values | `"1000"`, `"2000"`, `"3000"` |
|
|
151
|
+
| `typography` | Font properties (fontSize, fontWeight, lineHeight) | See below |
|
|
152
|
+
| `shadows` | Box shadow values | `"0 1px 2px 0 rgba(0,0,0,0.05)"` |
|
|
153
|
+
|
|
154
|
+
#### Typography Sub-categories
|
|
155
|
+
|
|
156
|
+
| Sub-category | Description | Example Values |
|
|
157
|
+
| ------------- | ------------- | ---------------- |
|
|
158
|
+
| `fontSize` | Font size values | `"0.75rem"`, `"16px"`, `"1.25em"` |
|
|
159
|
+
| `fontWeight` | Font weight values | `"400"`, `"500"`, `"bold"`, `"700"` |
|
|
160
|
+
| `lineHeight` | Line height values | `"1.25"`, `"1.5"`, `"1.75"` |
|
|
161
|
+
|
|
162
|
+
### Constraint Configuration
|
|
163
|
+
|
|
164
|
+
You can configure constraint levels in your `ngcorex.config.ts`:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { defineNgCorexConfig } from '@ngcorex/css';
|
|
168
|
+
|
|
169
|
+
export default defineNgCorexConfig({
|
|
170
|
+
constraints: {
|
|
171
|
+
spacing: {
|
|
172
|
+
unit: 'warning', // Warn about unitless numbers
|
|
173
|
+
format: 'error', // Error on invalid formats
|
|
174
|
+
type: 'error' // Error on wrong types
|
|
175
|
+
},
|
|
176
|
+
colors: {
|
|
177
|
+
format: 'error',
|
|
178
|
+
shadeKey: 'error',
|
|
179
|
+
type: 'error'
|
|
180
|
+
},
|
|
181
|
+
radius: {
|
|
182
|
+
unit: 'warning',
|
|
183
|
+
format: 'error',
|
|
184
|
+
type: 'error'
|
|
185
|
+
},
|
|
186
|
+
zIndex: {
|
|
187
|
+
format: 'error',
|
|
188
|
+
type: 'error'
|
|
189
|
+
},
|
|
190
|
+
typography: {
|
|
191
|
+
fontSize: {
|
|
192
|
+
format: 'error',
|
|
193
|
+
type: 'error'
|
|
194
|
+
},
|
|
195
|
+
fontWeight: {
|
|
196
|
+
format: 'error',
|
|
197
|
+
type: 'error'
|
|
198
|
+
},
|
|
199
|
+
lineHeight: {
|
|
200
|
+
format: 'error',
|
|
201
|
+
type: 'error'
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
shadows: {
|
|
205
|
+
format: 'error',
|
|
206
|
+
type: 'error'
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Available constraint levels: `'error'`, `'warning'`, `'off'`.
|
|
213
|
+
|
|
214
|
+
### Output Layer Configuration
|
|
215
|
+
|
|
216
|
+
You can optionally wrap generated CSS in a CSS layer for better organization and specificity control:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import { defineNgCorexConfig } from '@ngcorex/css';
|
|
220
|
+
|
|
221
|
+
export default defineNgCorexConfig({
|
|
222
|
+
output: {
|
|
223
|
+
layer: 'tokens', // Wraps CSS in @layer tokens { ... }
|
|
224
|
+
file: 'src/styles/ngcorex.css'
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
79
229
|
|
|
80
230
|
## Configuration File
|
|
81
231
|
|
|
@@ -95,6 +245,18 @@ export default defineNgCorexConfig({
|
|
|
95
245
|
});
|
|
96
246
|
```
|
|
97
247
|
|
|
248
|
+
In case you want to output in layer
|
|
249
|
+
**add:**
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
export default defineNgCorexConfig({
|
|
253
|
+
output: {
|
|
254
|
+
layer: 'layer-name',
|
|
255
|
+
file: 'src/styles/ngcorex.css'
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
98
260
|
### Important Rules
|
|
99
261
|
|
|
100
262
|
- The config file **must import from npm packages only**
|
|
@@ -107,12 +269,12 @@ export default defineNgCorexConfig({
|
|
|
107
269
|
|
|
108
270
|
The ngCorex CLI supports the following commands:
|
|
109
271
|
|
|
110
|
-
- `ngcorex init`
|
|
111
|
-
- `ngcorex build`
|
|
112
|
-
- `ngcorex build --watch`
|
|
113
|
-
- `ngcorex build --dry-run`
|
|
114
|
-
- `ngcorex version` / `--version` / `-v`
|
|
115
|
-
- `ngcorex --help` / `-h`
|
|
272
|
+
- `ngcorex init` - create starter config and tokens
|
|
273
|
+
- `ngcorex build` - generate CSS from tokens
|
|
274
|
+
- `ngcorex build --watch` - rebuild on file changes
|
|
275
|
+
- `ngcorex build --dry-run` - validate without writing files
|
|
276
|
+
- `ngcorex version` / `--version` / `-v` - print CLI version
|
|
277
|
+
- `ngcorex --help` / `-h` - show help information
|
|
116
278
|
|
|
117
279
|
## Commands
|
|
118
280
|
|
|
@@ -187,11 +349,52 @@ The CLI generates CSS variables based on your tokens and constraints.
|
|
|
187
349
|
Example output:
|
|
188
350
|
|
|
189
351
|
```css
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
352
|
+
@layer tokens {
|
|
353
|
+
:root {
|
|
354
|
+
/* Spacing */
|
|
355
|
+
--nx-spacing-xs: 0.25rem;
|
|
356
|
+
--nx-spacing-sm: 0.5rem;
|
|
357
|
+
--nx-spacing-md: 1rem;
|
|
358
|
+
--nx-spacing-lg: 1.5rem;
|
|
359
|
+
--nx-spacing-xl: 2rem;
|
|
360
|
+
|
|
361
|
+
/* Colors */
|
|
362
|
+
--nx-color-neutral-0: #ffffff;
|
|
363
|
+
--nx-color-neutral-100: #f5f5f5;
|
|
364
|
+
--nx-color-neutral-500: #737373;
|
|
365
|
+
--nx-color-neutral-900: #171717;
|
|
366
|
+
--nx-color-primary-500: #2563eb;
|
|
367
|
+
|
|
368
|
+
/* Radius */
|
|
369
|
+
--nx-radius-sm: 0.25rem;
|
|
370
|
+
--nx-radius-md: 0.5rem;
|
|
371
|
+
--nx-radius-lg: 0.75rem;
|
|
372
|
+
--nx-radius-xl: 1rem;
|
|
373
|
+
--nx-radius-full: 9999px;
|
|
374
|
+
|
|
375
|
+
/* Z-Index */
|
|
376
|
+
--nx-zIndex-base: 0;
|
|
377
|
+
--nx-zIndex-dropdown: 1000;
|
|
378
|
+
--nx-zIndex-modal: 1050;
|
|
379
|
+
--nx-zIndex-tooltip: 1070;
|
|
380
|
+
|
|
381
|
+
/* Typography */
|
|
382
|
+
--nx-fontSize-xs: 0.75rem;
|
|
383
|
+
--nx-fontSize-base: 1rem;
|
|
384
|
+
--nx-fontSize-xl: 1.25rem;
|
|
385
|
+
--nx-fontSize-3xl: 1.875rem;
|
|
386
|
+
--nx-fontWeight-normal: 400;
|
|
387
|
+
--nx-fontWeight-bold: 700;
|
|
388
|
+
--nx-lineHeight-normal: 1.5;
|
|
389
|
+
--nx-lineHeight-loose: 2;
|
|
390
|
+
|
|
391
|
+
/* Shadows */
|
|
392
|
+
--nx-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
393
|
+
--nx-shadow-base: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
394
|
+
--nx-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
395
|
+
--nx-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
396
|
+
--nx-shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
397
|
+
}
|
|
195
398
|
}
|
|
196
399
|
```
|
|
197
400
|
|
package/dist/commands/init.js
CHANGED
|
@@ -9,14 +9,77 @@ export async function initCommand() {
|
|
|
9
9
|
if (!fs.existsSync(tokensPath)) {
|
|
10
10
|
fs.writeFileSync(tokensPath, JSON.stringify({
|
|
11
11
|
spacing: {
|
|
12
|
-
"xs": "
|
|
13
|
-
"sm": "
|
|
12
|
+
"xs": "0.25rem",
|
|
13
|
+
"sm": "0.5rem",
|
|
14
|
+
"md": "1rem",
|
|
15
|
+
"lg": "1.5rem",
|
|
16
|
+
"xl": "2rem"
|
|
14
17
|
},
|
|
15
18
|
colors: {
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
+
neutral: {
|
|
20
|
+
"0": "#ffffff",
|
|
21
|
+
"100": "#f5f5f5",
|
|
22
|
+
"300": "#d4d4d4",
|
|
23
|
+
"500": "#737373",
|
|
24
|
+
"700": "#404040",
|
|
25
|
+
"900": "#171717"
|
|
26
|
+
},
|
|
27
|
+
primary: {
|
|
28
|
+
"500": "#2563eb"
|
|
19
29
|
}
|
|
30
|
+
},
|
|
31
|
+
radius: {
|
|
32
|
+
"sm": "0.25rem",
|
|
33
|
+
"md": "0.5rem",
|
|
34
|
+
"lg": "0.75rem",
|
|
35
|
+
"xl": "1rem",
|
|
36
|
+
"full": "9999px"
|
|
37
|
+
},
|
|
38
|
+
zIndex: {
|
|
39
|
+
"base": "0",
|
|
40
|
+
"dropdown": "1000",
|
|
41
|
+
"sticky": "1020",
|
|
42
|
+
"fixed": "1030",
|
|
43
|
+
"modal-backdrop": "1040",
|
|
44
|
+
"modal": "1050",
|
|
45
|
+
"popover": "1060",
|
|
46
|
+
"tooltip": "1070"
|
|
47
|
+
},
|
|
48
|
+
typography: {
|
|
49
|
+
fontSize: {
|
|
50
|
+
"xs": "0.75rem",
|
|
51
|
+
"sm": "0.875rem",
|
|
52
|
+
"base": "1rem",
|
|
53
|
+
"lg": "1.125rem",
|
|
54
|
+
"xl": "1.25rem",
|
|
55
|
+
"2xl": "1.5rem",
|
|
56
|
+
"3xl": "1.875rem",
|
|
57
|
+
"4xl": "2.25rem"
|
|
58
|
+
},
|
|
59
|
+
fontWeight: {
|
|
60
|
+
"light": "300",
|
|
61
|
+
"normal": "400",
|
|
62
|
+
"medium": "500",
|
|
63
|
+
"semibold": "600",
|
|
64
|
+
"bold": "700",
|
|
65
|
+
"extrabold": "800"
|
|
66
|
+
},
|
|
67
|
+
lineHeight: {
|
|
68
|
+
"none": "1",
|
|
69
|
+
"tight": "1.25",
|
|
70
|
+
"snug": "1.375",
|
|
71
|
+
"normal": "1.5",
|
|
72
|
+
"relaxed": "1.625",
|
|
73
|
+
"loose": "2"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
shadows: {
|
|
77
|
+
"sm": "0 1px 2px 0 rgb(0 0 0 / 0.05)",
|
|
78
|
+
"base": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
|
|
79
|
+
"md": "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
|
|
80
|
+
"lg": "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
81
|
+
"xl": "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
|
|
82
|
+
"2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)"
|
|
20
83
|
}
|
|
21
84
|
}, null, 2));
|
|
22
85
|
console.info('✔ Created tokens.json');
|
|
@@ -3,13 +3,15 @@ import path from 'node:path';
|
|
|
3
3
|
import { resolveConfigPath } from '../config/resolve-path.js';
|
|
4
4
|
import { loadConfig } from '../config/load-config.js';
|
|
5
5
|
import { writeCss } from '../output/write-css.js';
|
|
6
|
-
import { buildCssFromConfig } from '@ngcorex/css';
|
|
6
|
+
import { buildCssFromConfig, runValidations, printValidationResults, hasValidationResults, hasValidationErrors } from '@ngcorex/css';
|
|
7
7
|
import { resolve } from 'node:path';
|
|
8
|
+
import { BuildSummary, success, info, warning, error, section } from '../utils/logger.js';
|
|
8
9
|
let hasShownInlineTokenNotice = false;
|
|
9
10
|
export async function runBuild(options = {}) {
|
|
11
|
+
const buildSummary = new BuildSummary();
|
|
10
12
|
const configPath = resolveConfigPath();
|
|
11
13
|
const config = await loadConfig(configPath);
|
|
12
|
-
|
|
14
|
+
success('Loaded ngcorex.config.ts');
|
|
13
15
|
const outputFile = config.output?.file ?? 'src/styles/ngcorex.css';
|
|
14
16
|
const outputPath = resolve(process.cwd(), outputFile);
|
|
15
17
|
const tokensPath = path.resolve(process.cwd(), 'tokens.json');
|
|
@@ -20,24 +22,19 @@ export async function runBuild(options = {}) {
|
|
|
20
22
|
try {
|
|
21
23
|
fileTokens = JSON.parse(raw);
|
|
22
24
|
}
|
|
23
|
-
catch (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (error instanceof SyntaxError) {
|
|
28
|
-
console.error(error.message);
|
|
25
|
+
catch (err) {
|
|
26
|
+
error('Invalid tokens.json');
|
|
27
|
+
if (err instanceof SyntaxError) {
|
|
28
|
+
console.log(` Details: ${err.message}`);
|
|
29
29
|
}
|
|
30
|
-
console.error('');
|
|
31
30
|
process.exit(1);
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
// Validate top-level token shape
|
|
35
34
|
if (fileTokens !== null) {
|
|
36
35
|
if (typeof fileTokens !== 'object' || Array.isArray(fileTokens)) {
|
|
37
|
-
|
|
38
|
-
console.
|
|
39
|
-
console.error('The file must export a JSON object at the top level.');
|
|
40
|
-
console.error('');
|
|
36
|
+
error('Invalid tokens.json');
|
|
37
|
+
console.log(' Details: The file must export a JSON object at the top level.');
|
|
41
38
|
process.exit(1);
|
|
42
39
|
}
|
|
43
40
|
}
|
|
@@ -48,10 +45,8 @@ export async function runBuild(options = {}) {
|
|
|
48
45
|
if (typeof tokens.spacing !== 'object' ||
|
|
49
46
|
tokens.spacing === null ||
|
|
50
47
|
Array.isArray(tokens.spacing)) {
|
|
51
|
-
|
|
52
|
-
console.
|
|
53
|
-
console.error('The "spacing" token must be an object.');
|
|
54
|
-
console.error('');
|
|
48
|
+
error('Invalid tokens.json');
|
|
49
|
+
console.log(' Details: The "spacing" token must be an object.');
|
|
55
50
|
process.exit(1);
|
|
56
51
|
}
|
|
57
52
|
}
|
|
@@ -59,10 +54,44 @@ export async function runBuild(options = {}) {
|
|
|
59
54
|
if (typeof tokens.colors !== 'object' ||
|
|
60
55
|
tokens.colors === null ||
|
|
61
56
|
Array.isArray(tokens.colors)) {
|
|
62
|
-
|
|
63
|
-
console.
|
|
64
|
-
|
|
65
|
-
|
|
57
|
+
error('Invalid tokens.json');
|
|
58
|
+
console.log(' Details: The "colors" token must be an object.');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if ('radius' in tokens) {
|
|
63
|
+
if (typeof tokens.radius !== 'object' ||
|
|
64
|
+
tokens.radius === null ||
|
|
65
|
+
Array.isArray(tokens.radius)) {
|
|
66
|
+
error('Invalid tokens.json');
|
|
67
|
+
console.log(' Details: The "radius" token must be an object.');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if ('zIndex' in tokens) {
|
|
72
|
+
if (typeof tokens.zIndex !== 'object' ||
|
|
73
|
+
tokens.zIndex === null ||
|
|
74
|
+
Array.isArray(tokens.zIndex)) {
|
|
75
|
+
error('Invalid tokens.json');
|
|
76
|
+
console.log(' Details: The "zIndex" token must be an object.');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if ('typography' in tokens) {
|
|
81
|
+
if (typeof tokens.typography !== 'object' ||
|
|
82
|
+
tokens.typography === null ||
|
|
83
|
+
Array.isArray(tokens.typography)) {
|
|
84
|
+
error('Invalid tokens.json');
|
|
85
|
+
console.log(' Details: The "typography" token must be an object.');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if ('shadows' in tokens) {
|
|
90
|
+
if (typeof tokens.shadows !== 'object' ||
|
|
91
|
+
tokens.shadows === null ||
|
|
92
|
+
Array.isArray(tokens.shadows)) {
|
|
93
|
+
error('Invalid tokens.json');
|
|
94
|
+
console.log(' Details: The "shadows" token must be an object.');
|
|
66
95
|
process.exit(1);
|
|
67
96
|
}
|
|
68
97
|
}
|
|
@@ -74,14 +103,112 @@ export async function runBuild(options = {}) {
|
|
|
74
103
|
const spacing = tokens.spacing;
|
|
75
104
|
for (const [key, value] of Object.entries(spacing)) {
|
|
76
105
|
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
77
|
-
|
|
78
|
-
console.
|
|
79
|
-
console.error(`Invalid spacing value for key "${key}". Expected number or string.`);
|
|
80
|
-
console.error('');
|
|
106
|
+
error('Invalid tokens.json');
|
|
107
|
+
console.log(` Details: Invalid spacing value for key "${key}". Expected number or string.`);
|
|
81
108
|
process.exit(1);
|
|
82
109
|
}
|
|
83
110
|
}
|
|
84
111
|
}
|
|
112
|
+
// Validate radius token values
|
|
113
|
+
if (fileTokens !== null) {
|
|
114
|
+
const tokens = fileTokens;
|
|
115
|
+
if (tokens.radius) {
|
|
116
|
+
const radius = tokens.radius;
|
|
117
|
+
for (const [key, value] of Object.entries(radius)) {
|
|
118
|
+
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
119
|
+
error('Invalid tokens.json');
|
|
120
|
+
console.log(` Details: Invalid radius value for key "${key}". Expected number or string.`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Validate z-index token values
|
|
127
|
+
if (fileTokens !== null) {
|
|
128
|
+
const tokens = fileTokens;
|
|
129
|
+
if (tokens.zIndex) {
|
|
130
|
+
const zIndex = tokens.zIndex;
|
|
131
|
+
for (const [key, value] of Object.entries(zIndex)) {
|
|
132
|
+
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
133
|
+
error('Invalid tokens.json');
|
|
134
|
+
console.log(` Details: Invalid zIndex value for key "${key}". Expected number or string.`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Validate typography token structure
|
|
141
|
+
if (fileTokens !== null) {
|
|
142
|
+
const tokens = fileTokens;
|
|
143
|
+
if (tokens.typography) {
|
|
144
|
+
const typography = tokens.typography;
|
|
145
|
+
if (typography.fontSize) {
|
|
146
|
+
if (typeof typography.fontSize !== 'object' ||
|
|
147
|
+
typography.fontSize === null ||
|
|
148
|
+
Array.isArray(typography.fontSize)) {
|
|
149
|
+
error('Invalid tokens.json');
|
|
150
|
+
console.log(' Details: The "typography.fontSize" token must be an object.');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
const fontSize = typography.fontSize;
|
|
154
|
+
for (const [key, value] of Object.entries(fontSize)) {
|
|
155
|
+
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
156
|
+
error('Invalid tokens.json');
|
|
157
|
+
console.log(` Details: Invalid typography.fontSize value for key "${key}". Expected number or string.`);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (typography.fontWeight) {
|
|
163
|
+
if (typeof typography.fontWeight !== 'object' ||
|
|
164
|
+
typography.fontWeight === null ||
|
|
165
|
+
Array.isArray(typography.fontWeight)) {
|
|
166
|
+
error('Invalid tokens.json');
|
|
167
|
+
console.log(' Details: The "typography.fontWeight" token must be an object.');
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
const fontWeight = typography.fontWeight;
|
|
171
|
+
for (const [key, value] of Object.entries(fontWeight)) {
|
|
172
|
+
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
173
|
+
error('Invalid tokens.json');
|
|
174
|
+
console.log(` Details: Invalid typography.fontWeight value for key "${key}". Expected number or string.`);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (typography.lineHeight) {
|
|
180
|
+
if (typeof typography.lineHeight !== 'object' ||
|
|
181
|
+
typography.lineHeight === null ||
|
|
182
|
+
Array.isArray(typography.lineHeight)) {
|
|
183
|
+
error('Invalid tokens.json');
|
|
184
|
+
console.log(' Details: The "typography.lineHeight" token must be an object.');
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
const lineHeight = typography.lineHeight;
|
|
188
|
+
for (const [key, value] of Object.entries(lineHeight)) {
|
|
189
|
+
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
190
|
+
error('Invalid tokens.json');
|
|
191
|
+
console.log(` Details: Invalid typography.lineHeight value for key "${key}". Expected number or string.`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Validate shadows token values
|
|
199
|
+
if (fileTokens !== null) {
|
|
200
|
+
const tokens = fileTokens;
|
|
201
|
+
if (tokens.shadows) {
|
|
202
|
+
const shadows = tokens.shadows;
|
|
203
|
+
for (const [key, value] of Object.entries(shadows)) {
|
|
204
|
+
if (typeof value !== 'string') {
|
|
205
|
+
error('Invalid tokens.json');
|
|
206
|
+
console.log(` Details: Invalid shadows value for key "${key}". Expected string.`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
85
212
|
}
|
|
86
213
|
// Validate color token structure & values
|
|
87
214
|
if (fileTokens !== null) {
|
|
@@ -92,43 +219,56 @@ export async function runBuild(options = {}) {
|
|
|
92
219
|
if (typeof shades !== 'object' ||
|
|
93
220
|
shades === null ||
|
|
94
221
|
Array.isArray(shades)) {
|
|
95
|
-
|
|
96
|
-
console.
|
|
97
|
-
console.error(`Color "${colorName}" must be an object of shade values.`);
|
|
98
|
-
console.error('');
|
|
222
|
+
error('Invalid tokens.json');
|
|
223
|
+
console.log(` Details: Color "${colorName}" must be an object of shade values.`);
|
|
99
224
|
process.exit(1);
|
|
100
225
|
}
|
|
101
226
|
for (const [shade, value] of Object.entries(shades)) {
|
|
102
227
|
// shade keys must be numeric
|
|
103
228
|
if (!/^\d+$/.test(shade)) {
|
|
104
|
-
|
|
105
|
-
console.
|
|
106
|
-
console.error(`Invalid shade key "${shade}" in color "${colorName}". Shade keys must be numeric.`);
|
|
107
|
-
console.error('');
|
|
229
|
+
error('Invalid tokens.json');
|
|
230
|
+
console.log(` Details: Invalid shade key "${shade}" in color "${colorName}". Shade keys must be numeric.`);
|
|
108
231
|
process.exit(1);
|
|
109
232
|
}
|
|
110
233
|
// value must be a string
|
|
111
234
|
if (typeof value !== 'string') {
|
|
112
|
-
|
|
113
|
-
console.
|
|
114
|
-
console.error(`Invalid value for ${colorName}.${shade}. Expected a color string.`);
|
|
115
|
-
console.error('');
|
|
235
|
+
error('Invalid tokens.json');
|
|
236
|
+
console.log(` Details: Invalid value for ${colorName}.${shade}. Expected a color string.`);
|
|
116
237
|
process.exit(1);
|
|
117
238
|
}
|
|
118
239
|
// very light color format validation (delegate strictness to engine)
|
|
119
240
|
if (!value.startsWith('#') &&
|
|
120
241
|
!value.startsWith('rgb(') &&
|
|
121
242
|
!value.startsWith('rgba(')) {
|
|
122
|
-
|
|
123
|
-
console.
|
|
124
|
-
console.error(`Invalid color format for ${colorName}.${shade}: "${value}".`);
|
|
125
|
-
console.error('');
|
|
243
|
+
error('Invalid tokens.json');
|
|
244
|
+
console.log(` Details: Invalid color format for ${colorName}.${shade}: "${value}".`);
|
|
126
245
|
process.exit(1);
|
|
127
246
|
}
|
|
128
247
|
}
|
|
129
248
|
}
|
|
130
249
|
}
|
|
131
250
|
}
|
|
251
|
+
// Run non-blocking validations
|
|
252
|
+
if (fileTokens !== null) {
|
|
253
|
+
section('Token Validation');
|
|
254
|
+
const validationReport = runValidations(fileTokens);
|
|
255
|
+
if (hasValidationResults(validationReport)) {
|
|
256
|
+
if (hasValidationErrors(validationReport)) {
|
|
257
|
+
error('Blocking validation errors found');
|
|
258
|
+
console.log(' Details: Please fix the errors below before proceeding.');
|
|
259
|
+
printValidationResults(validationReport);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
warning('Non-blocking validation warnings found');
|
|
264
|
+
console.log(' Details: Review the warnings below for potential improvements.');
|
|
265
|
+
printValidationResults(validationReport);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
success('Token validation passed');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
132
272
|
const effectiveConfig = fileTokens
|
|
133
273
|
? {
|
|
134
274
|
...config,
|
|
@@ -138,16 +278,70 @@ export async function runBuild(options = {}) {
|
|
|
138
278
|
if (!fileTokens &&
|
|
139
279
|
config.tokens &&
|
|
140
280
|
!hasShownInlineTokenNotice) {
|
|
141
|
-
|
|
142
|
-
console.
|
|
143
|
-
console.info(' Using tokens.json is recommended for larger or shared projects.');
|
|
144
|
-
console.info('');
|
|
281
|
+
info('Inline tokens detected');
|
|
282
|
+
console.log(' Details: Using tokens.json is recommended for larger or shared projects.');
|
|
145
283
|
hasShownInlineTokenNotice = true;
|
|
146
284
|
}
|
|
285
|
+
section('Building CSS');
|
|
147
286
|
const css = buildCssFromConfig(effectiveConfig);
|
|
148
|
-
|
|
287
|
+
success('Generated CSS');
|
|
288
|
+
// Count tokens for build summary
|
|
289
|
+
if (effectiveConfig.tokens) {
|
|
290
|
+
if (effectiveConfig.tokens.spacing) {
|
|
291
|
+
buildSummary.addTokenCategory('spacing', Object.keys(effectiveConfig.tokens.spacing).length);
|
|
292
|
+
}
|
|
293
|
+
if (effectiveConfig.tokens.colors) {
|
|
294
|
+
const colorCount = countNestedTokens(effectiveConfig.tokens.colors);
|
|
295
|
+
buildSummary.addTokenCategory('colors', colorCount);
|
|
296
|
+
}
|
|
297
|
+
if (effectiveConfig.tokens.radius) {
|
|
298
|
+
buildSummary.addTokenCategory('radius', Object.keys(effectiveConfig.tokens.radius).length);
|
|
299
|
+
}
|
|
300
|
+
if (effectiveConfig.tokens.zIndex) {
|
|
301
|
+
buildSummary.addTokenCategory('zIndex', Object.keys(effectiveConfig.tokens.zIndex).length);
|
|
302
|
+
}
|
|
303
|
+
if (effectiveConfig.tokens.typography) {
|
|
304
|
+
const typography = effectiveConfig.tokens.typography;
|
|
305
|
+
if (typography.fontSize) {
|
|
306
|
+
buildSummary.addTokenCategory('typography.fontSize', Object.keys(typography.fontSize).length);
|
|
307
|
+
}
|
|
308
|
+
if (typography.fontWeight) {
|
|
309
|
+
buildSummary.addTokenCategory('typography.fontWeight', Object.keys(typography.fontWeight).length);
|
|
310
|
+
}
|
|
311
|
+
if (typography.lineHeight) {
|
|
312
|
+
buildSummary.addTokenCategory('typography.lineHeight', Object.keys(typography.lineHeight).length);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (effectiveConfig.tokens.shadows) {
|
|
316
|
+
buildSummary.addTokenCategory('shadows', Object.keys(effectiveConfig.tokens.shadows).length);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
buildSummary.setOutputFile(outputFile);
|
|
149
320
|
writeCss(outputPath, css, { dryRun: options.dryRun });
|
|
150
321
|
if (!options.dryRun) {
|
|
151
|
-
|
|
322
|
+
success(`Output written to ${outputFile}`);
|
|
323
|
+
// Get output file size
|
|
324
|
+
const stats = fs.statSync(outputPath);
|
|
325
|
+
buildSummary.setOutputSize(stats.size);
|
|
326
|
+
}
|
|
327
|
+
// Print build summary
|
|
328
|
+
buildSummary.print();
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Count tokens in a nested structure (like colors)
|
|
332
|
+
*/
|
|
333
|
+
function countNestedTokens(obj) {
|
|
334
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
335
|
+
return 0;
|
|
336
|
+
}
|
|
337
|
+
let count = 0;
|
|
338
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
339
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
340
|
+
count += countNestedTokens(value);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
count++;
|
|
344
|
+
}
|
|
152
345
|
}
|
|
346
|
+
return count;
|
|
153
347
|
}
|
package/dist/output/write-css.js
CHANGED
|
@@ -2,7 +2,7 @@ import { mkdirSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { dirname } from 'node:path';
|
|
3
3
|
export function writeCss(filePath, css, options = {}) {
|
|
4
4
|
if (options.dryRun) {
|
|
5
|
-
console.log(
|
|
5
|
+
console.log(`i Dry run - skipping write to ${filePath}`);
|
|
6
6
|
return;
|
|
7
7
|
}
|
|
8
8
|
const dir = dirname(filePath);
|
package/dist/utils/logger.js
CHANGED
|
@@ -1,8 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced logger for ngCorex CLI with improved developer experience
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Build summary tracker
|
|
6
|
+
*/
|
|
7
|
+
export class BuildSummary {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.tokensProcessed = new Map();
|
|
10
|
+
this.warnings = [];
|
|
11
|
+
this.errors = [];
|
|
12
|
+
this.startTime = Date.now();
|
|
13
|
+
this.options = {};
|
|
14
|
+
this.options = options;
|
|
15
|
+
}
|
|
16
|
+
addTokenCategory(category, count) {
|
|
17
|
+
this.tokensProcessed.set(category, count);
|
|
18
|
+
}
|
|
19
|
+
addWarning(message) {
|
|
20
|
+
this.warnings.push({
|
|
21
|
+
timestamp: Date.now(),
|
|
22
|
+
message
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
addError(message) {
|
|
26
|
+
this.errors.push({
|
|
27
|
+
timestamp: Date.now(),
|
|
28
|
+
message
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
setOutputFile(file) {
|
|
32
|
+
this.options.outputFile = file;
|
|
33
|
+
}
|
|
34
|
+
setOutputSize(size) {
|
|
35
|
+
this.options.outputSize = size;
|
|
36
|
+
}
|
|
37
|
+
getWarnings() {
|
|
38
|
+
return this.warnings;
|
|
39
|
+
}
|
|
40
|
+
getErrors() {
|
|
41
|
+
return this.errors;
|
|
42
|
+
}
|
|
43
|
+
getTokensProcessed() {
|
|
44
|
+
return this.tokensProcessed;
|
|
45
|
+
}
|
|
46
|
+
getDuration() {
|
|
47
|
+
return Date.now() - this.startTime;
|
|
48
|
+
}
|
|
49
|
+
hasWarnings() {
|
|
50
|
+
return this.warnings.length > 0;
|
|
51
|
+
}
|
|
52
|
+
hasErrors() {
|
|
53
|
+
return this.errors.length > 0;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Format file size in human-readable format
|
|
57
|
+
*/
|
|
58
|
+
formatFileSize(bytes) {
|
|
59
|
+
if (bytes < 1024)
|
|
60
|
+
return `${bytes} B`;
|
|
61
|
+
if (bytes < 1024 * 1024)
|
|
62
|
+
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
63
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Format duration in human-readable format
|
|
67
|
+
*/
|
|
68
|
+
formatDuration(ms) {
|
|
69
|
+
if (ms < 1000)
|
|
70
|
+
return `${ms}ms`;
|
|
71
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Print the build summary
|
|
75
|
+
*/
|
|
76
|
+
print() {
|
|
77
|
+
const duration = this.getDuration();
|
|
78
|
+
const totalTokens = Array.from(this.tokensProcessed.values()).reduce((a, b) => a + b, 0);
|
|
79
|
+
console.log('');
|
|
80
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
81
|
+
console.log(' 📦 Build Summary');
|
|
82
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
83
|
+
console.log('');
|
|
84
|
+
// Tokens processed
|
|
85
|
+
if (this.tokensProcessed.size > 0) {
|
|
86
|
+
console.log(' Tokens Processed:');
|
|
87
|
+
for (const [category, count] of this.tokensProcessed.entries()) {
|
|
88
|
+
console.log(` • ${category.padEnd(12)} ${count.toString().padStart(4)} tokens`);
|
|
89
|
+
}
|
|
90
|
+
console.log(` ${'─'.repeat(20)}`);
|
|
91
|
+
console.log(` ${'Total'.padEnd(12)} ${totalTokens.toString().padStart(4)} tokens`);
|
|
92
|
+
console.log('');
|
|
93
|
+
}
|
|
94
|
+
// Output file
|
|
95
|
+
if (this.options.outputFile) {
|
|
96
|
+
console.log(' Output:');
|
|
97
|
+
console.log(` • File: ${this.options.outputFile}`);
|
|
98
|
+
if (this.options.outputSize) {
|
|
99
|
+
console.log(` • Size: ${this.formatFileSize(this.options.outputSize)}`);
|
|
100
|
+
}
|
|
101
|
+
console.log('');
|
|
102
|
+
}
|
|
103
|
+
// Duration
|
|
104
|
+
console.log(` Duration: ${this.formatDuration(duration)}`);
|
|
105
|
+
console.log('');
|
|
106
|
+
// Warnings and errors
|
|
107
|
+
if (this.hasWarnings() || this.hasErrors()) {
|
|
108
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
109
|
+
if (this.hasWarnings()) {
|
|
110
|
+
console.log(` ⚠️ ${this.warnings.length} Warning${this.warnings.length > 1 ? 's' : ''}`);
|
|
111
|
+
}
|
|
112
|
+
if (this.hasErrors()) {
|
|
113
|
+
console.log(` ❌ ${this.errors.length} Error${this.errors.length > 1 ? 's' : ''}`);
|
|
114
|
+
}
|
|
115
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
116
|
+
console.log('');
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
console.log(' ✅ Build completed successfully!');
|
|
120
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
121
|
+
console.log('');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Print detailed warnings
|
|
126
|
+
*/
|
|
127
|
+
printWarnings() {
|
|
128
|
+
if (!this.hasWarnings())
|
|
129
|
+
return;
|
|
130
|
+
console.log('');
|
|
131
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
132
|
+
console.log(' ⚠️ Warnings');
|
|
133
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
134
|
+
console.log('');
|
|
135
|
+
for (const entry of this.warnings) {
|
|
136
|
+
const { message } = entry;
|
|
137
|
+
console.log(` ${getIcon(message.type)} ${message.message}`);
|
|
138
|
+
if (message.location) {
|
|
139
|
+
console.log(` Location: ${message.location}`);
|
|
140
|
+
}
|
|
141
|
+
if (message.details) {
|
|
142
|
+
console.log(` Details: ${message.details}`);
|
|
143
|
+
}
|
|
144
|
+
if (message.suggestion) {
|
|
145
|
+
console.log(` 💡 ${message.suggestion}`);
|
|
146
|
+
}
|
|
147
|
+
console.log('');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Print detailed errors
|
|
152
|
+
*/
|
|
153
|
+
printErrors() {
|
|
154
|
+
if (!this.hasErrors())
|
|
155
|
+
return;
|
|
156
|
+
console.log('');
|
|
157
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
158
|
+
console.log(' ❌ Errors');
|
|
159
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
160
|
+
console.log('');
|
|
161
|
+
for (const entry of this.errors) {
|
|
162
|
+
const { message } = entry;
|
|
163
|
+
console.log(` ${getIcon(message.type)} ${message.message}`);
|
|
164
|
+
if (message.location) {
|
|
165
|
+
console.log(` Location: ${message.location}`);
|
|
166
|
+
}
|
|
167
|
+
if (message.details) {
|
|
168
|
+
console.log(` Details: ${message.details}`);
|
|
169
|
+
}
|
|
170
|
+
if (message.suggestion) {
|
|
171
|
+
console.log(` 💡 ${message.suggestion}`);
|
|
172
|
+
}
|
|
173
|
+
console.log('');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get icon for log level
|
|
179
|
+
*/
|
|
180
|
+
function getIcon(level) {
|
|
181
|
+
const icons = {
|
|
182
|
+
success: '✅',
|
|
183
|
+
info: 'ℹ️',
|
|
184
|
+
warning: '⚠️',
|
|
185
|
+
error: '❌'
|
|
186
|
+
};
|
|
187
|
+
return icons[level] || '•';
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Log a success message
|
|
191
|
+
*/
|
|
192
|
+
export function success(message) {
|
|
193
|
+
console.log(`✅ ${message}`);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Log an info message
|
|
197
|
+
*/
|
|
198
|
+
export function info(message) {
|
|
199
|
+
console.log(`ℹ️ ${message}`);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Log a warning message
|
|
203
|
+
*/
|
|
204
|
+
export function warning(message) {
|
|
205
|
+
console.log('');
|
|
206
|
+
console.log(`⚠️ ${message}`);
|
|
207
|
+
console.log('');
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Log an error message
|
|
211
|
+
*/
|
|
212
|
+
export function error(message) {
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log(`❌ ${message}`);
|
|
215
|
+
console.log('');
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Handle CLI errors with improved formatting
|
|
219
|
+
*/
|
|
1
220
|
export function handleCliError(error) {
|
|
221
|
+
console.log('');
|
|
222
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
223
|
+
console.log(' ❌ Error');
|
|
224
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
225
|
+
console.log('');
|
|
2
226
|
if (error instanceof Error) {
|
|
3
|
-
console.
|
|
227
|
+
console.log(` ${error.message}`);
|
|
4
228
|
}
|
|
5
229
|
else {
|
|
6
|
-
console.
|
|
230
|
+
console.log(' Unknown error occurred');
|
|
7
231
|
}
|
|
232
|
+
console.log('');
|
|
233
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
234
|
+
console.log('');
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Log a section header
|
|
238
|
+
*/
|
|
239
|
+
export function section(title) {
|
|
240
|
+
console.log('');
|
|
241
|
+
console.log(`━━━ ${title} ━━━`);
|
|
242
|
+
console.log('');
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Log a sub-section header
|
|
246
|
+
*/
|
|
247
|
+
export function subsection(title) {
|
|
248
|
+
console.log('');
|
|
249
|
+
console.log(` ${title}`);
|
|
250
|
+
console.log(` ${'─'.repeat(title.length)}`);
|
|
251
|
+
console.log('');
|
|
8
252
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngcorex/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "CLI for ngCorex - Angular-native design token engine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design-tokens",
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
"frontend-tooling",
|
|
13
13
|
"ngcorex",
|
|
14
14
|
"typescript",
|
|
15
|
-
"angular"
|
|
15
|
+
"angular",
|
|
16
|
+
"css-variables",
|
|
17
|
+
"utility-css",
|
|
18
|
+
"build-time",
|
|
19
|
+
"design-system",
|
|
20
|
+
"theming"
|
|
16
21
|
],
|
|
17
22
|
"license": "MIT",
|
|
18
23
|
"type": "module",
|
|
@@ -37,5 +42,5 @@
|
|
|
37
42
|
"directory": "packages/cli"
|
|
38
43
|
},
|
|
39
44
|
|
|
40
|
-
"homepage": "https://github.com/arkdezin/ngCorex"
|
|
45
|
+
"homepage": "https://github.com/arkdezin/ngCorex/blob/main/README.md"
|
|
41
46
|
}
|