@ngcorex/cli 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @ngcorex/cli
2
2
 
3
+ ![NPM Version](https://img.shields.io/npm/v/%40ngcorex%2Fcli?style=flat-square&logo=npm&labelColor=%23D50100&color=%23000) ![NPM License](https://img.shields.io/npm/l/%40ngcorex%2Fcli?style=flat-square) ![Static Badge](https://img.shields.io/badge/Github-Repo-blue?style=flat-square&logo=github) ![NPM Downloads](https://img.shields.io/npm/dm/%40ngcorex%2Fcli?style=flat-square&logo=npm&logoColor=%23ffffff&labelColor=%23D50100&color=%23000)
4
+
3
5
  Command-line interface for **ngCorex**.
4
6
 
5
7
  This package provides the `ngcorex` CLI used to build CSS from an
@@ -25,16 +27,63 @@ All work happens **at build time**.
25
27
 
26
28
  ---
27
29
 
28
- ## Installation
30
+ ## Getting Started
31
+
32
+ ### Installation
29
33
 
30
34
  Install the CLI as a dev dependency:
31
35
 
32
36
  ```bash
33
- npm install --save-dev @ngcorex/cli
34
- ````
37
+ npm install -D @ngcorex/cli
38
+ ```
35
39
 
36
40
  > The CLI depends on `@ngcorex/css`, which will be installed automatically.
37
41
 
42
+ ### Create tokens.json
43
+
44
+ Create a `tokens.json` file at your project root:
45
+
46
+ ```json
47
+ {
48
+ "spacing": {
49
+ "1": "1rem",
50
+ "2": "2rem"
51
+ },
52
+ "colors": {
53
+ "gray": {
54
+ "100": "#f3f4f6",
55
+ "900": "#111827"
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ If `tokens.json` is present, it is used automatically.
62
+
63
+ ## Configuration File
64
+
65
+ The CLI expects a file named:
66
+
67
+ ### Create ngcorex.config.ts
68
+
69
+ Create a `ngcorex.config.ts` file at your project root:
70
+
71
+ ```ts
72
+ import { defineNgCorexConfig } from '@ngcorex/css';
73
+
74
+ export default defineNgCorexConfig({
75
+ output: {
76
+ file: 'src/styles/ngcorex.css'
77
+ }
78
+ });
79
+ ```
80
+
81
+ ### Important Rules
82
+
83
+ - The config file **must import from npm packages only**
84
+ - Relative imports are **not allowed**
85
+ - The config is transpiled internally using esbuild
86
+
38
87
  ---
39
88
 
40
89
  ## Commands
@@ -45,9 +94,9 @@ npm install --save-dev @ngcorex/cli
45
94
  npx ngcorex build
46
95
  ```
47
96
 
48
- * Loads `ngcorex.config.ts`
49
- * Generates CSS output
50
- * Writes the output file
97
+ - Loads `ngcorex.config.ts`
98
+ - Generates CSS output
99
+ - Writes the output file
51
100
 
52
101
  ---
53
102
 
@@ -57,9 +106,9 @@ npx ngcorex build
57
106
  npx ngcorex build --watch
58
107
  ```
59
108
 
60
- * Watches `ngcorex.config.ts`
61
- * Rebuilds on change
62
- * Does not exit on errors
109
+ - Watches `ngcorex.config.ts`
110
+ - Rebuilds on change
111
+ - Does not exit on errors
63
112
 
64
113
  ---
65
114
 
@@ -69,9 +118,9 @@ npx ngcorex build --watch
69
118
  npx ngcorex build --dry-run
70
119
  ```
71
120
 
72
- * Runs the full pipeline
73
- * Does NOT write any files
74
- * Useful for testing configuration
121
+ - Runs the full pipeline
122
+ - Does NOT write any files
123
+ - Useful for testing configuration
75
124
 
76
125
  ---
77
126
 
@@ -85,37 +134,6 @@ Prints the CLI version.
85
134
 
86
135
  ---
87
136
 
88
- ## Configuration File
89
-
90
- The CLI expects a file named:
91
-
92
- ```
93
- ngcorex.config.ts
94
- ```
95
-
96
- ### Example
97
-
98
- ```ts
99
- import { defineNgCorexConfig } from '@ngcorex/css';
100
-
101
- export default defineNgCorexConfig({
102
- tokens: {
103
- spacing: {
104
- 1: 4,
105
- 2: 8
106
- }
107
- }
108
- });
109
- ```
110
-
111
- ### Important Rules
112
-
113
- * The config file **must import from npm packages only**
114
- * Relative imports are **not allowed**
115
- * The config is transpiled internally using esbuild
116
-
117
- ---
118
-
119
137
  ## Output
120
138
 
121
139
  The CLI generates CSS variables based on your tokens and constraints.
@@ -124,8 +142,10 @@ Example output:
124
142
 
125
143
  ```css
126
144
  :root {
127
- --spacing-1: 4px;
128
- --spacing-2: 8px;
145
+ --nx-spacing-1: 1rem;
146
+ --nx-spacing-2: 2rem;
147
+ --nx-color-gray-100: #f3f4f6;
148
+ --nx-color-gray-900: #111827;
129
149
  }
130
150
  ```
131
151
 
@@ -133,4 +153,4 @@ Example output:
133
153
 
134
154
  ## License
135
155
 
136
- MIT
156
+ MIT
@@ -1,16 +1,151 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
1
3
  import { resolveConfigPath } from '../config/resolve-path.js';
2
4
  import { loadConfig } from '../config/load-config.js';
3
5
  import { writeCss } from '../output/write-css.js';
4
6
  import { buildCssFromConfig } from '@ngcorex/css';
5
7
  import { resolve } from 'node:path';
8
+ let hasShownInlineTokenNotice = false;
6
9
  export async function runBuild(options = {}) {
7
10
  const configPath = resolveConfigPath();
8
11
  const config = await loadConfig(configPath);
9
12
  console.log('✔ Loaded ngcorex.config.ts');
10
- const css = buildCssFromConfig(config);
11
- console.log('✔ Generated CSS');
12
13
  const outputFile = config.output?.file ?? 'src/styles/ngcorex.css';
13
14
  const outputPath = resolve(process.cwd(), outputFile);
15
+ const tokensPath = path.resolve(process.cwd(), 'tokens.json');
16
+ let fileTokens = null;
17
+ // Safe JSON parsing with friendly errors
18
+ if (fs.existsSync(tokensPath)) {
19
+ const raw = fs.readFileSync(tokensPath, 'utf-8');
20
+ try {
21
+ fileTokens = JSON.parse(raw);
22
+ }
23
+ catch (error) {
24
+ console.error('');
25
+ console.error('❌ Invalid tokens.json');
26
+ console.error('Failed to parse JSON.');
27
+ if (error instanceof SyntaxError) {
28
+ console.error(error.message);
29
+ }
30
+ console.error('');
31
+ process.exit(1);
32
+ }
33
+ }
34
+ // Validate top-level token shape
35
+ if (fileTokens !== null) {
36
+ if (typeof fileTokens !== 'object' || Array.isArray(fileTokens)) {
37
+ console.error('');
38
+ console.error('❌ Invalid tokens.json');
39
+ console.error('The file must export a JSON object at the top level.');
40
+ console.error('');
41
+ process.exit(1);
42
+ }
43
+ }
44
+ // Validate known token categories
45
+ if (fileTokens !== null) {
46
+ const tokens = fileTokens;
47
+ if ('spacing' in tokens) {
48
+ if (typeof tokens.spacing !== 'object' ||
49
+ tokens.spacing === null ||
50
+ Array.isArray(tokens.spacing)) {
51
+ console.error('');
52
+ console.error('❌ Invalid tokens.json');
53
+ console.error('The "spacing" token must be an object.');
54
+ console.error('');
55
+ process.exit(1);
56
+ }
57
+ }
58
+ if ('colors' in tokens) {
59
+ if (typeof tokens.colors !== 'object' ||
60
+ tokens.colors === null ||
61
+ Array.isArray(tokens.colors)) {
62
+ console.error('');
63
+ console.error('❌ Invalid tokens.json');
64
+ console.error('The "colors" token must be an object.');
65
+ console.error('');
66
+ process.exit(1);
67
+ }
68
+ }
69
+ }
70
+ // Validate spacing token values
71
+ if (fileTokens !== null) {
72
+ const tokens = fileTokens;
73
+ if (tokens.spacing) {
74
+ const spacing = tokens.spacing;
75
+ for (const [key, value] of Object.entries(spacing)) {
76
+ if (typeof value !== 'number' && typeof value !== 'string') {
77
+ console.error('');
78
+ console.error('❌ Invalid tokens.json');
79
+ console.error(`Invalid spacing value for key "${key}". Expected number or string.`);
80
+ console.error('');
81
+ process.exit(1);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ // Validate color token structure & values
87
+ if (fileTokens !== null) {
88
+ const tokens = fileTokens;
89
+ if (tokens.colors) {
90
+ const colors = tokens.colors;
91
+ for (const [colorName, shades] of Object.entries(colors)) {
92
+ if (typeof shades !== 'object' ||
93
+ shades === null ||
94
+ Array.isArray(shades)) {
95
+ console.error('');
96
+ console.error('❌ Invalid tokens.json');
97
+ console.error(`Color "${colorName}" must be an object of shade values.`);
98
+ console.error('');
99
+ process.exit(1);
100
+ }
101
+ for (const [shade, value] of Object.entries(shades)) {
102
+ // shade keys must be numeric
103
+ if (!/^\d+$/.test(shade)) {
104
+ console.error('');
105
+ console.error('❌ Invalid tokens.json');
106
+ console.error(`Invalid shade key "${shade}" in color "${colorName}". Shade keys must be numeric.`);
107
+ console.error('');
108
+ process.exit(1);
109
+ }
110
+ // value must be a string
111
+ if (typeof value !== 'string') {
112
+ console.error('');
113
+ console.error('❌ Invalid tokens.json');
114
+ console.error(`Invalid value for ${colorName}.${shade}. Expected a color string.`);
115
+ console.error('');
116
+ process.exit(1);
117
+ }
118
+ // very light color format validation (delegate strictness to engine)
119
+ if (!value.startsWith('#') &&
120
+ !value.startsWith('rgb(') &&
121
+ !value.startsWith('rgba(')) {
122
+ console.error('');
123
+ console.error('❌ Invalid tokens.json');
124
+ console.error(`Invalid color format for ${colorName}.${shade}: "${value}".`);
125
+ console.error('');
126
+ process.exit(1);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ const effectiveConfig = fileTokens
133
+ ? {
134
+ ...config,
135
+ tokens: fileTokens
136
+ }
137
+ : config;
138
+ if (!fileTokens &&
139
+ config.tokens &&
140
+ !hasShownInlineTokenNotice) {
141
+ console.info('');
142
+ console.info('ℹ️ Inline tokens detected.');
143
+ console.info(' Using tokens.json is recommended for larger or shared projects.');
144
+ console.info('');
145
+ hasShownInlineTokenNotice = true;
146
+ }
147
+ const css = buildCssFromConfig(effectiveConfig);
148
+ console.log('✔ Generated CSS');
14
149
  writeCss(outputPath, css, { dryRun: options.dryRun });
15
150
  if (!options.dryRun) {
16
151
  console.log(`✔ Output written to ${outputFile}`);
package/package.json CHANGED
@@ -1,7 +1,19 @@
1
1
  {
2
2
  "name": "@ngcorex/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "CLI for ngCorex - Angular-native design token engine",
5
+ "keywords": [
6
+ "design-tokens",
7
+ "css-cli",
8
+ "build-tool",
9
+ "css-build",
10
+ "token-cli",
11
+ "developer-tooling",
12
+ "frontend-tooling",
13
+ "ngcorex",
14
+ "typescript",
15
+ "angular"
16
+ ],
5
17
  "license": "MIT",
6
18
  "type": "module",
7
19
  "bin": {
@@ -18,5 +30,12 @@
18
30
  ],
19
31
  "scripts": {
20
32
  "build": "tsc -p tsconfig.json"
21
- }
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/arkdezin/ngCorex.git",
37
+ "directory": "packages/cli"
38
+ },
39
+
40
+ "homepage": "https://github.com/arkdezin/ngCorex"
22
41
  }