@melcanz85/chaincss 1.9.2 → 1.9.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
@@ -12,17 +12,7 @@ ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful mod
12
12
 
13
13
  **Runtime hooks** → Dynamic, prop-based styles when you need them
14
14
 
15
- "The performance of vanilla CSS with the power of JavaScript — now with **CHOICE.**"
16
15
 
17
- ```javascript
18
- // Same beautiful API, two powerful modes
19
- const button = $()
20
- .color('white')
21
- .backgroundColor('#667eea')
22
- .padding('1rem')
23
- .borderRadius('4px')
24
- .block('.btn');
25
- ````
26
16
  ## Installation
27
17
 
28
18
  ```bash
@@ -30,6 +20,19 @@ ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful mod
30
20
  npm install @melcanz85/chaincss
31
21
  ```
32
22
 
23
+ ### File Structure
24
+
25
+ ```text
26
+ your-project/
27
+ ├── node_module
28
+ ├── src/
29
+ │ ├── main.jcss # Entry point - imports & compiles
30
+ │ └── *.jcss # Your style definitions
31
+ ├── style/ # Generated CSS will be stored stored here
32
+ ├── index.html # Your web page
33
+ └── package.json
34
+ ```
35
+
33
36
  ## Two Powerful Modes - One API
34
37
 
35
38
  ### Mode 1: Build-time (Zero Runtime)
@@ -47,11 +50,31 @@ ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful mod
47
50
 
48
51
  module.exports = { button };
49
52
  ````
53
+ **in your main.jcss**
54
+
55
+ ```javascript
56
+ <@
57
+ const button = get('./button.js');
58
+
59
+ compile(button);
60
+ @>
61
+ ```
62
+ ..then run this in terminal/command prompt
63
+
64
+ ```bash
65
+ npx chaincss ./src/main.jcss ./style --watch
66
+ # ./style/global.css generated!
67
+ ````
68
+ OR with vanilla nodejs project
50
69
 
51
70
  ```bash
52
71
  npx chaincss ./src/main.jcss ./style --watch & node server.js
53
72
  # ./style/global.css generated!
54
73
  ````
74
+ * Note: running `npx chaincss ./src/main.jcss ./style --watch ` for the first time will
75
+ generate chaincss.config.js with default values. You can edit this to
76
+ customize your build!.
77
+
55
78
  ### Mode 2: Runtime (React Hooks)
56
79
 
57
80
  **Perfect for:** Dynamic styles that respond to props, state, or themes.
@@ -148,19 +171,7 @@ ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful mod
148
171
  .boxShadow('0 0 0 3px rgba(102,126,234,0.5)')
149
172
  .block('.btn');
150
173
  ````
151
- ### File Structure
152
174
 
153
- ```text
154
- your-project/
155
- ├── node_module
156
- ├── src/
157
- │ ├── main.jcss # Entry point - imports & compiles
158
- │ └── chain.jcss # Your style definitions
159
-
160
- ├── style/
161
- │ └── global.css # Generated CSS
162
- └── package.json
163
- ```
164
175
  ### Basic Example
165
176
 
166
177
  **chaincss/button.jcss**
@@ -40,7 +40,7 @@ class AtomicOptimizer {
40
40
  this.stats = cache.stats || this.stats;
41
41
 
42
42
  const cacheTime = new Date(cache.timestamp).toLocaleString();
43
- console.log(`Loaded ${this.atomicClasses.size} atomic classes from cache (${cacheTime})`);
43
+ console.log(`--Loaded ${this.atomicClasses.size} atomic classes from cache (${cacheTime})\n`);
44
44
 
45
45
  // Verify config matches
46
46
  if (cache.config) {
@@ -237,8 +237,6 @@ class AtomicOptimizer {
237
237
  }
238
238
 
239
239
  optimize(styles) {
240
- console.log('ChainCSS Atomic Optimizer running...');
241
-
242
240
  // Track usage first
243
241
  this.trackStyles(styles);
244
242
 
@@ -257,10 +255,6 @@ class AtomicOptimizer {
257
255
  // Calculate savings
258
256
  const savings = ((this.stats.totalStyles - this.atomicClasses.size) / this.stats.totalStyles * 100).toFixed(1);
259
257
 
260
- //console.log(`Optimization complete:`);
261
- //console.log(`Atomic classes created: ${this.atomicClasses.size}`);
262
- //console.log(`CSS size reduction: ~${savings}%`);
263
-
264
258
  // Save cache if enabled
265
259
  if (this.options.cache) {
266
260
  this.saveCache();
package/chaincss.js CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
-
3
2
  const {NodeVM} = require('vm2');
4
3
  const path = require('path');
5
4
  const fs = require('fs');
@@ -7,72 +6,179 @@ const chokidar = require('chokidar');
7
6
  const CleanCSS = require('clean-css');
8
7
  const ChainCSSPrefixer = require('./prefixer.js');
9
8
  const fileCache = new Map();
10
-
11
- let prefixerConfig = {
12
- enabled: true,
13
- browsers: ['> 0.5%', 'last 2 versions', 'not dead'],
14
- mode: 'auto' // 'auto', 'lightweight', or 'full'
15
- };
16
- const prefixer = new ChainCSSPrefixer(prefixerConfig);
17
-
18
- // IMPORT THE CORE FROM TRANSPILER - use aliasing
19
- const { $, run, compile: originalCompile, chain } = require('./transpiler');
20
-
21
- // Import atomic optimizer
9
+ const strVal = require('./strVal.js');
22
10
  const { AtomicOptimizer } = require('./atomic-optimizer');
23
11
  const { CacheManager } = require('./cache-manager');
12
+ const { $, run, compile: originalCompile, chain } = require('./transpiler');
24
13
 
25
- // Atomic optimizer instance
14
+ // Atomic optimizer instance (will be initialized after config)
26
15
  let atomicOptimizer = null;
27
16
 
28
- // Configuration
17
+ // Default configuration
29
18
  let config = {
30
19
  atomic: {
31
- enabled: false, // Default off for backward compatibility
20
+ enabled: false,
32
21
  threshold: 3,
33
22
  naming: 'hash',
34
23
  cache: true,
24
+ cachePath: './.chaincss-cache',
35
25
  minify: true
26
+ },
27
+ prefixer: {
28
+ enabled: true,
29
+ mode: 'auto',
30
+ browsers: ['> 0.5%', 'last 2 versions', 'not dead'],
31
+ sourceMap: true,
32
+ sourceMapInline: false
33
+ }
34
+ };
35
+
36
+ // Prefixer instance
37
+ let prefixer = new ChainCSSPrefixer(config.prefixer);
38
+
39
+ // From default to user configuration
40
+ function deft_to_userConf(target, source) {
41
+ const result = { ...target };
42
+
43
+ for (const key in source) {
44
+ if (source[key] instanceof Object && key in target) {
45
+ result[key] = deft_to_userConf(target[key], source[key]);
46
+ } else {
47
+ result[key] = source[key];
48
+ }
49
+ }
50
+
51
+ return result;
52
+ }
53
+
54
+ // Ensure config file exists
55
+ const ensureConfigExists = () => {
56
+ const configPath = path.join(process.cwd(), 'chaincss.config.cjs');
57
+ const configExists = fs.existsSync(configPath);
58
+
59
+ if (!configExists && !process.env.CHAINCSS_SKIP_CONFIG) {
60
+ const defaultConfig = strVal.userConf;
61
+
62
+ fs.writeFileSync(configPath, defaultConfig);
63
+ console.log('-- Successfully created config file: ./chaincss.config.cjs\n');
36
64
  }
37
65
  };
38
66
 
39
- try {
40
- // Try .cjs first (for ES Module projects)
41
- let configPath = path.join(process.cwd(), 'chaincss.config.cjs');
67
+ // Load user config
68
+ const loadUserConfig = () => {
69
+ const configPath = path.join(process.cwd(), 'chaincss.config.cjs');
42
70
 
43
71
  if (fs.existsSync(configPath)) {
44
- const userConfig = require(configPath);
45
- config = { ...config, ...userConfig };
72
+ try {
73
+ const userConfig = require(configPath);
74
+ config = deft_to_userConf(config, userConfig);
75
+
76
+ // CRITICAL: Ensure browsers is ALWAYS an array
77
+ if (config.prefixer) {
78
+ // If browsers is a string, convert to array
79
+ if (typeof config.prefixer.browsers === 'string') {
80
+ config.prefixer.browsers = config.prefixer.browsers.split(',').map(b => b.trim());
81
+ }
82
+ // If browsers is not an array at this point, set default
83
+ if (!Array.isArray(config.prefixer.browsers)) {
84
+ config.prefixer.browsers = ['> 0.5%', 'last 2 versions', 'not dead'];
85
+ }
86
+ }
87
+ } catch (err) {
88
+ console.log('-- Error loading config:', err.message, '\n');
89
+ }
90
+ }
91
+ };
92
+
93
+ // Initialize atomic optimizer based on config
94
+ const initAtomicOptimizer = () => {
95
+ if (config.atomic.enabled) {
96
+ atomicOptimizer = new AtomicOptimizer(config.atomic);
97
+ console.log('-- Atomic optimizer enabled\n');
46
98
  } else {
47
- // Fall back to .js
48
- configPath = path.join(process.cwd(), 'chaincss.config.js');
99
+ console.log('-- Atomic optimizer disabled\n');
100
+ }
101
+ };
102
+
103
+ // Initialization of prefixer object
104
+ const initPrefixer = () => {
105
+ prefixer = new ChainCSSPrefixer(config.prefixer);
106
+ };
107
+
108
+ // Parse CLI arguments
109
+ function parseArgs(args) {
110
+ const result = {
111
+ inputFile: null,
112
+ outputFile: null,
113
+ watchMode: false,
114
+ noPrefix: false,
115
+ browsers: null,
116
+ prefixerMode: null,
117
+ sourceMap: null,
118
+ sourceMapInline: false
119
+ };
120
+
121
+ for (let i = 0; i < args.length; i++) {
122
+ const arg = args[i];
49
123
 
50
- if (fs.existsSync(configPath)) {
51
- const userConfig = require(configPath);
52
- config = { ...config, ...userConfig };
53
- } else {
54
- console.log('No config file found');
124
+ if (arg === '--watch') {
125
+ result.watchMode = true;
126
+ } else if (arg === '--no-prefix') {
127
+ result.noPrefix = true;
128
+ } else if (arg === '--prefixer-mode' && args[i + 1]) {
129
+ result.prefixerMode = args[i + 1];
130
+ i++;
131
+ } else if (arg === '--browsers' && args[i + 1]) {
132
+ result.browsers = args[i + 1].split(',').map(b => b.trim());
133
+ i++;
134
+ } else if (arg === '--no-source-map') {
135
+ result.sourceMap = false;
136
+ } else if (arg === '--source-map-inline') {
137
+ result.sourceMapInline = true;
138
+ } else if (!result.inputFile) {
139
+ result.inputFile = arg;
140
+ } else if (!result.outputFile) {
141
+ result.outputFile = arg;
55
142
  }
56
143
  }
57
144
 
58
- } catch (err) {
59
- console.log('Error loading config:', err.message);
145
+ return result;
60
146
  }
61
147
 
62
- // Initialize atomic optimizer if enabled
63
- if (config.atomic.enabled) {
64
- atomicOptimizer = new AtomicOptimizer(config.atomic);
65
- } else {
66
- console.log('Atomic optimizer disabled (config.atomic.enabled =', config.atomic.enabled, ')');
67
- }
148
+ // Apply CLI options to config
149
+ const applyCliOptions = (cliOptions) => {
150
+ if (cliOptions.sourceMap !== null) {
151
+ config.prefixer.sourceMap = cliOptions.sourceMap;
152
+ }
153
+ if (cliOptions.sourceMapInline) {
154
+ config.prefixer.sourceMapInline = true;
155
+ }
156
+ if (cliOptions.prefixerMode) {
157
+ config.prefixer.mode = cliOptions.prefixerMode;
158
+ }
159
+ if (cliOptions.noPrefix) {
160
+ config.prefixer.enabled = false;
161
+ }
162
+ if (cliOptions.browsers) {
163
+ config.prefixer.browsers = cliOptions.browsers;
164
+ }
165
+ };
68
166
 
167
+ // Watch function
168
+ function watch(inputFile, outputFile) {
169
+ chokidar.watch(inputFile).on('change', async () => {
170
+ try {
171
+ await processor(inputFile, outputFile);
172
+ } catch (err) {
173
+ console.error('Error during watch processing:', err);
174
+ }
175
+ });
176
+ }
69
177
 
70
178
  // Create the wrapped compile function
71
179
  const compile = (obj) => {
72
- // First, do standard compilation to get styles
73
180
  originalCompile(obj);
74
181
 
75
- // If atomic is enabled, optimize
76
182
  if (atomicOptimizer && config.atomic.enabled) {
77
183
  const optimized = atomicOptimizer.optimize(obj);
78
184
  chain.cssOutput = optimized;
@@ -89,22 +195,18 @@ const transpilerModule = {
89
195
  chain
90
196
  };
91
197
 
92
-
93
198
  // Recursive file processing function
94
199
  const processJCSSFile = (filePath) => {
95
- // Check cache first
96
200
  if (fileCache.has(filePath)) {
97
201
  return fileCache.get(filePath);
98
202
  }
99
203
 
100
- // Check if file exists
101
204
  if (!fs.existsSync(filePath)) {
102
205
  throw new Error(`File not found: ${filePath}`);
103
206
  }
104
207
 
105
208
  const content = fs.readFileSync(filePath, 'utf8');
106
209
 
107
- // Create a new VM instance for this file
108
210
  const vm = new NodeVM({
109
211
  console: 'inherit',
110
212
  timeout: 5000,
@@ -127,15 +229,9 @@ const processJCSSFile = (filePath) => {
127
229
  }
128
230
  });
129
231
 
130
- // Wrap the content - DON'T redeclare module!
131
232
  const wrappedContent = `
132
- // Clear any existing exports
133
233
  module.exports = {};
134
-
135
- // Run the actual file content
136
234
  ${content}
137
-
138
- // Return the exports
139
235
  module.exports;
140
236
  `;
141
237
 
@@ -149,52 +245,51 @@ const processJCSSFile = (filePath) => {
149
245
  }
150
246
  };
151
247
 
152
- const processScript = (scriptBlock,filename) => {
153
-
248
+ const processScript = (scriptBlock, filename) => {
154
249
  const vm = new NodeVM({
155
250
  console: 'inherit',
156
251
  timeout: 5000,
157
252
  sandbox: {
158
- ...transpilerModule,
159
- get: (relativePath) => {
160
- const baseDir = path.dirname(filename);
161
- const targetPath = path.resolve(baseDir, relativePath);
162
- return processJCSSFile(targetPath);
163
- },
164
- __filename: filename,
165
- __dirname: path.dirname(filename),
166
- module: { exports: {} },
167
- require: (path) => require(path)
253
+ ...transpilerModule,
254
+ get: (relativePath) => {
255
+ const baseDir = path.dirname(filename);
256
+ const targetPath = path.resolve(baseDir, relativePath);
257
+ return processJCSSFile(targetPath);
258
+ },
259
+ __filename: filename,
260
+ __dirname: path.dirname(filename),
261
+ module: { exports: {} },
262
+ require: (path) => require(path)
168
263
  },
169
264
  require: {
170
- external: true, // Allow some external modules
171
- builtin: ['path', 'fs'], // Allow specific Node built-ins
172
- root: './' // Restrict to project root
265
+ external: true,
266
+ builtin: ['path', 'fs'],
267
+ root: './'
173
268
  }
174
269
  });
175
270
 
176
271
  const jsCode = scriptBlock.trim();
177
272
 
178
273
  try {
179
- const result = vm.run(jsCode, filename);
180
- return transpilerModule.chain.cssOutput;
274
+ const result = vm.run(jsCode, filename);
275
+ return transpilerModule.chain.cssOutput;
181
276
  } catch (err) {
182
- console.error(`Error processing script in ${filename}:`, err.message);
183
- throw err;
277
+ console.error(`Error processing script in ${filename}:`, err.message);
278
+ throw err;
184
279
  }
185
280
  };
186
281
 
187
282
  const processJavascriptBlocks = (content, inputpath) => {
188
283
  const blocks = content.split(/<@([\s\S]*?)@>/gm);
189
284
  let outputCSS = '';
285
+
190
286
  for (let i = 0; i < blocks.length; i++) {
191
287
  if (i % 2 === 0) {
192
- outputCSS += blocks[i]; // Write the existing CSS as is
288
+ outputCSS += blocks[i];
193
289
  } else {
194
290
  const scriptBlock = blocks[i];
195
291
  try {
196
- const outputProcessScript = processScript(scriptBlock,inputpath);
197
-
292
+ const outputProcessScript = processScript(scriptBlock, inputpath);
198
293
  if (typeof outputProcessScript !== 'object' && typeof outputProcessScript !== 'undefined') {
199
294
  outputCSS += outputProcessScript;
200
295
  }
@@ -207,7 +302,7 @@ const processJavascriptBlocks = (content, inputpath) => {
207
302
  return outputCSS.trim();
208
303
  };
209
304
 
210
- // Validate CSS (check for unclosed blocks)
305
+ // Validate CSS
211
306
  const validateCSS = (css) => {
212
307
  const openBraces = (css.match(/{/g) || []).length;
213
308
  const closeBraces = (css.match(/}/g) || []).length;
@@ -218,76 +313,79 @@ const validateCSS = (css) => {
218
313
  return true;
219
314
  };
220
315
 
221
- // Modified minification function with source map support
222
316
  const processAndMinifyCss = async (css, inputFile, outputFile) => {
223
317
  if (!validateCSS(css)) {
224
318
  throw new Error('Invalid CSS syntax - check for missing braces');
225
319
  }
226
320
 
227
- // Step 1: Apply prefixer (if enabled)
228
321
  let processedCss = css;
229
- let sourceMap = null;
230
- if (prefixerConfig.enabled) {
322
+ let sourceMapFromPrefixer = null;
323
+
324
+ if (config.prefixer.enabled) {
231
325
  try {
232
326
  const result = await prefixer.process(css, {
233
327
  from: inputFile,
234
328
  to: outputFile,
235
- map: prefixerConfig.sourceMap !== false
329
+ map: config.prefixer.sourceMap !== false
236
330
  });
237
331
  processedCss = result.css;
238
- sourceMap = result.map;
332
+ sourceMapFromPrefixer = result.map;
239
333
  } catch (err) {
240
- console.error('Prefixer error:', err.message);
334
+ console.error('Prefixer error:', err.message);
241
335
  processedCss = css;
242
336
  }
243
337
  }
244
338
 
245
- // Step 2: Minify
246
- const output = new CleanCSS().minify(processedCss);
339
+ const minifyOptions = {
340
+ sourceMap: config.prefixer.sourceMap === true,
341
+ sourceMapInlineSources: true
342
+ };
343
+
344
+ const output = new CleanCSS(minifyOptions).minify(processedCss);
345
+
247
346
  if (output.errors.length > 0) {
248
347
  console.error('CSS Minification Errors:', output.errors);
249
348
  return { css: null, map: null };
250
349
  }
350
+
251
351
  let finalCss = output.styles;
252
- if (sourceMap && !prefixerConfig.sourceMapInline) {
352
+ let finalSourceMap = output.sourceMap ? JSON.stringify(output.sourceMap) : sourceMapFromPrefixer;
353
+
354
+ if (finalSourceMap && !config.prefixer.sourceMapInline) {
253
355
  const mapFileName = path.basename(`${outputFile}.map`);
254
356
  finalCss += `\n/*# sourceMappingURL=${mapFileName} */`;
255
357
  }
256
- return { css: finalCss, map: sourceMap };
358
+
359
+ return { css: finalCss, map: finalSourceMap };
257
360
  };
258
361
 
259
- // Main processor function - FIXED ORDER
362
+ // Main processor function
260
363
  const processor = async (inputFile, outputFile) => {
261
364
  try {
262
365
  const input = path.resolve(inputFile);
263
366
  const output = path.resolve(outputFile);
264
367
  const content = fs.readFileSync(input, 'utf8');
265
368
 
266
- // STEP 1: Process JavaScript blocks first
267
369
  const processedCSS = processJavascriptBlocks(content, input);
268
- // STEP 2: Validate the CSS
370
+
269
371
  if (!validateCSS(processedCSS)) {
270
372
  throw new Error('Invalid CSS syntax');
271
373
  }
272
374
 
273
- // STEP 3: Apply prefixer and minify with source maps
274
- const stylePath = output + '/global.css';
375
+ const stylePath = path.join(output, 'global.css');
275
376
  const result = await processAndMinifyCss(processedCSS, input, stylePath);
377
+
276
378
  if (result.css) {
277
379
  fs.writeFileSync(stylePath, result.css, 'utf8');
278
-
279
- //Write source map if generated
380
+
280
381
  if (result.map) {
281
382
  const mapFile = `${stylePath}.map`;
282
383
  fs.writeFileSync(mapFile, result.map, 'utf8');
283
384
  }
284
- if (prefixerConfig.enabled) {
285
- console.log(` Prefixer: ${prefixerConfig.mode} mode (${prefixerConfig.browsers.join(', ')})`);
286
- }
287
- //Show source map status
288
- if (result.map) {
289
- console.log(` Source maps: enabled`);
290
- }
385
+
386
+ console.log(`-- Prefixer: ${config.prefixer.mode} mode (${config.prefixer.browsers.join(', ')})\n`);
387
+ console.log(`-- Source maps: ${result.map ? 'enabled' : 'disabled'}\n`);
388
+ console.log(`-- Successfully generated css: ./${path.relative(process.cwd(), stylePath)}\n`);
291
389
  }
292
390
  } catch (err) {
293
391
  console.error(`Failed to process ${inputFile}:`, err.message);
@@ -295,113 +393,37 @@ const processor = async (inputFile, outputFile) => {
295
393
  }
296
394
  };
297
395
 
298
- // Watch function
299
- function watch(inputFile, outputFile) {
300
- chokidar.watch(inputFile).on('change', async () => {
301
- try {
302
- await processor(inputFile, outputFile);
303
- } catch (err) {
304
- console.error('Error during watch processing:', err);
305
- }
306
- });
307
- }
308
-
309
- // Parse CLI arguments
310
- function parseArgs(args) {
311
- const result = {
312
- inputFile: null,
313
- outputFile: null,
314
- watchMode: false,
315
- noPrefix: false,
316
- browsers: null,
317
- prefixerMode: 'auto',
318
- sourceMap: true,
319
- sourceMapInline: false
320
- };
321
-
322
- for (let i = 0; i < args.length; i++) {
323
- const arg = args[i];
324
-
325
- if (arg === '--watch') {
326
- result.watchMode = true;
327
- } else if (arg === '--no-prefix') {
328
- result.noPrefix = true;
329
- } else if (arg === '--prefixer-mode' && args[i + 1]) {
330
- result.prefixerMode = args[i + 1];
331
- i++;
332
- } else if (arg === '--browsers' && args[i + 1]) {
333
- result.browsers = args[i + 1].split(',');
334
- i++;
335
- } else if (arg === '--no-source-map') {
336
- result.sourceMap = false;
337
- } else if (arg === '--source-map-inline') {
338
- result.sourceMapInline = true;
339
- } else if (!result.inputFile) {
340
- result.inputFile = arg;
341
- } else if (!result.outputFile) {
342
- result.outputFile = arg;
343
- }
344
- }
345
-
346
- return result;
347
- }
348
-
349
396
  // Main CLI logic
350
397
  if (require.main === module) {
398
+ // Step 1: Ensure config exists
399
+ ensureConfigExists();
400
+
401
+ // Step 2: Load user config
402
+ loadUserConfig();
403
+
404
+ // Step 3: Parse CLI arguments
351
405
  const args = process.argv.slice(2);
352
406
  const cliOptions = parseArgs(args);
407
+
353
408
  if (!cliOptions.inputFile || !cliOptions.outputFile) {
354
- console.log(`
355
- ChainCSS - JavaScript-powered CSS preprocessor
356
-
357
- Usage:
358
- chaincss <inputFile> <outputFile> [options]
359
-
360
- Options:
361
- --watch Watch for changes
362
- --no-prefix Disable automatic prefixing
363
- --browsers <list> Browser support list (comma-separated)
364
- Example: --browsers ">1%,last 2 versions,not IE 11"
365
-
366
- Examples:
367
- chaincss style.jcss style.css
368
- chaincss style.jcss style.css --watch
369
- chaincss style.jcss style.css --browsers ">5%,last 2 safari versions"
370
- chaincss style.jcss style.css --no-prefix
371
- `);
409
+ console.log(strVal.cli_opt_guide);
372
410
  process.exit(1);
373
411
  }
374
412
 
375
- // sourceMap
376
- if (cliOptions.sourceMap !== undefined) {
377
- prefixerConfig.sourceMap = cliOptions.sourceMap;
378
- }
379
- if (cliOptions.sourceMapInline) {
380
- prefixerConfig.sourceMapInline = true;
381
- }
382
-
383
- // Then apply to prefixer:
384
- if (cliOptions.prefixerMode) {
385
- prefixerConfig.mode = cliOptions.prefixerMode;
386
- }
387
-
388
- // Apply CLI options
389
- if (cliOptions.noPrefix) {
390
- prefixerConfig.enabled = false;
391
- }
413
+ // Step 4: Apply CLI options (overrides config)
414
+ applyCliOptions(cliOptions);
392
415
 
393
- if (cliOptions.browsers) {
394
- prefixerConfig.browsers = cliOptions.browsers;
395
- // Re-initialize prefixer with new config
396
- Object.assign(prefixer, new ChainCSSPrefixer(prefixerConfig));
397
- }
416
+ // Step 5: Initialize components with final config (ONCE)
417
+ initAtomicOptimizer();
418
+ initPrefixer(); // Only called once now!
398
419
 
399
- // Run processor
420
+ // Step 6: Run processor
400
421
  (async () => {
401
422
  try {
402
423
  await processor(cliOptions.inputFile, cliOptions.outputFile);
403
424
 
404
425
  if (cliOptions.watchMode) {
426
+ console.log('-- Watching for changes...\n');
405
427
  watch(cliOptions.inputFile, cliOptions.outputFile);
406
428
  }
407
429
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melcanz85/chaincss",
3
- "version": "1.9.2",
3
+ "version": "1.9.3",
4
4
  "description": "A simple package transpiler for js to css",
5
5
  "main": "index.js",
6
6
  "module": "index.react.js",
package/prefixer.js CHANGED
@@ -58,7 +58,7 @@ class ChainCSSPrefixer {
58
58
  // User explicitly wants full mode but Autoprefixer not installed
59
59
  if (this.config.mode === 'full' && !this.hasAutoprefixer) {
60
60
  console.warn('⚠️ Full mode requested but autoprefixer not installed. Falling back to lightweight mode.');
61
- console.warn(' To use full mode: npm install autoprefixer postcss');
61
+ console.warn(' To use full mode: npm install autoprefixer postcss caniuse-db browserslist\n');
62
62
  return 'lightweight';
63
63
  }
64
64
 
@@ -107,6 +107,7 @@ class ChainCSSPrefixer {
107
107
 
108
108
  // Full mode with Autoprefixer
109
109
  async processWithAutoprefixer(cssString, options, mapOptions) {
110
+
110
111
  const from = options.from || 'input.css';
111
112
  const to = options.to || 'output.css';
112
113
 
@@ -131,10 +132,8 @@ class ChainCSSPrefixer {
131
132
  }
132
133
 
133
134
  this.targetBrowsers = browserslist(this.config.browsers);
134
-
135
135
  const from = options.from || 'input.css';
136
136
  const to = options.to || 'output.css';
137
-
138
137
  const result = await postcss([
139
138
  this.createBuiltInPlugin()
140
139
  ]).process(cssString, {