@melcanz85/chaincss 1.11.0 → 1.11.1
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 +114 -45
- package/browser/index.js +1 -1
- package/browser/react-hooks.jsx +1 -63
- package/browser/rtt.js +1 -45
- package/node/atomic-optimizer.js +2 -67
- package/node/btt.js +348 -84
- package/node/cache-manager.js +0 -12
- package/node/chaincss.js +14 -99
- package/node/index.js +2 -13
- package/node/prefixer.js +2 -61
- package/node/strVal.js +1 -1
- package/package.json +1 -1
- package/types.d.ts +0 -26
- package/node/css-properties.json +0 -633
package/node/chaincss.js
CHANGED
|
@@ -4,17 +4,13 @@ const path = require('path');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const chokidar = require('chokidar');
|
|
6
6
|
const CleanCSS = require('clean-css');
|
|
7
|
+
const { $, run, compile: originalCompile, chain } = require('./btt');
|
|
7
8
|
const ChainCSSPrefixer = require('./prefixer.js');
|
|
8
|
-
const fileCache = new Map();
|
|
9
9
|
const strVal = require('./strVal.js');
|
|
10
10
|
const { AtomicOptimizer } = require('./atomic-optimizer');
|
|
11
11
|
const { CacheManager } = require('./cache-manager');
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
// Atomic optimizer instance (will be initialized after config)
|
|
12
|
+
const fileCache = new Map();
|
|
15
13
|
let atomicOptimizer = null;
|
|
16
|
-
|
|
17
|
-
// Default configuration
|
|
18
14
|
let config = {
|
|
19
15
|
atomic: {
|
|
20
16
|
enabled: false,
|
|
@@ -31,15 +27,10 @@ let config = {
|
|
|
31
27
|
sourceMap: true,
|
|
32
28
|
sourceMapInline: false
|
|
33
29
|
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// Prefixer instance
|
|
30
|
+
};
|
|
37
31
|
let prefixer = new ChainCSSPrefixer(config.prefixer);
|
|
38
|
-
|
|
39
|
-
// From default to user configuration
|
|
40
32
|
function deft_to_userConf(target, source) {
|
|
41
33
|
const result = { ...target };
|
|
42
|
-
|
|
43
34
|
for (const key in source) {
|
|
44
35
|
if (source[key] instanceof Object && key in target) {
|
|
45
36
|
result[key] = deft_to_userConf(target[key], source[key]);
|
|
@@ -50,36 +41,25 @@ function deft_to_userConf(target, source) {
|
|
|
50
41
|
|
|
51
42
|
return result;
|
|
52
43
|
}
|
|
53
|
-
|
|
54
|
-
// Ensure config file exists
|
|
55
44
|
const ensureConfigExists = () => {
|
|
56
45
|
const configPath = path.join(process.cwd(), 'chaincss.config.cjs');
|
|
57
46
|
const configExists = fs.existsSync(configPath);
|
|
58
|
-
|
|
59
47
|
if (!configExists && !process.env.CHAINCSS_SKIP_CONFIG) {
|
|
60
48
|
const defaultConfig = strVal.userConf;
|
|
61
|
-
|
|
62
49
|
fs.writeFileSync(configPath, defaultConfig);
|
|
63
50
|
console.log('-- Successfully created config file: ./chaincss.config.cjs\n');
|
|
64
51
|
}
|
|
65
52
|
};
|
|
66
|
-
|
|
67
|
-
// Load user config
|
|
68
53
|
const loadUserConfig = () => {
|
|
69
54
|
const configPath = path.join(process.cwd(), 'chaincss.config.cjs');
|
|
70
|
-
|
|
71
55
|
if (fs.existsSync(configPath)) {
|
|
72
56
|
try {
|
|
73
57
|
const userConfig = require(configPath);
|
|
74
58
|
config = deft_to_userConf(config, userConfig);
|
|
75
|
-
|
|
76
|
-
// CRITICAL: Ensure browsers is ALWAYS an array
|
|
77
59
|
if (config.prefixer) {
|
|
78
|
-
// If browsers is a string, convert to array
|
|
79
60
|
if (typeof config.prefixer.browsers === 'string') {
|
|
80
61
|
config.prefixer.browsers = config.prefixer.browsers.split(',').map(b => b.trim());
|
|
81
62
|
}
|
|
82
|
-
// If browsers is not an array at this point, set default
|
|
83
63
|
if (!Array.isArray(config.prefixer.browsers)) {
|
|
84
64
|
config.prefixer.browsers = ['> 0.5%', 'last 2 versions', 'not dead'];
|
|
85
65
|
}
|
|
@@ -89,23 +69,16 @@ const loadUserConfig = () => {
|
|
|
89
69
|
}
|
|
90
70
|
}
|
|
91
71
|
};
|
|
92
|
-
|
|
93
|
-
// Initialize atomic optimizer based on config
|
|
94
72
|
const initAtomicOptimizer = () => {
|
|
95
73
|
if (config.atomic.enabled) {
|
|
96
74
|
atomicOptimizer = new AtomicOptimizer(config.atomic);
|
|
97
|
-
console.log('-- Atomic optimizer enabled\n');
|
|
98
75
|
} else {
|
|
99
76
|
console.log('-- Atomic optimizer disabled\n');
|
|
100
77
|
}
|
|
101
78
|
};
|
|
102
|
-
|
|
103
|
-
// Initialization of prefixer object
|
|
104
79
|
const initPrefixer = () => {
|
|
105
80
|
prefixer = new ChainCSSPrefixer(config.prefixer);
|
|
106
81
|
};
|
|
107
|
-
|
|
108
|
-
// Parse CLI arguments
|
|
109
82
|
function parseArgs(args) {
|
|
110
83
|
const result = {
|
|
111
84
|
inputFile: null,
|
|
@@ -141,11 +114,8 @@ function parseArgs(args) {
|
|
|
141
114
|
result.outputFile = arg;
|
|
142
115
|
}
|
|
143
116
|
}
|
|
144
|
-
|
|
145
117
|
return result;
|
|
146
118
|
}
|
|
147
|
-
|
|
148
|
-
// Apply CLI options to config
|
|
149
119
|
const applyCliOptions = (cliOptions) => {
|
|
150
120
|
if (cliOptions.sourceMap !== null) {
|
|
151
121
|
config.prefixer.sourceMap = cliOptions.sourceMap;
|
|
@@ -163,8 +133,6 @@ const applyCliOptions = (cliOptions) => {
|
|
|
163
133
|
config.prefixer.browsers = cliOptions.browsers;
|
|
164
134
|
}
|
|
165
135
|
};
|
|
166
|
-
|
|
167
|
-
// Watch function
|
|
168
136
|
function watch(inputFile, outputFile) {
|
|
169
137
|
chokidar.watch(inputFile).on('change', async () => {
|
|
170
138
|
try {
|
|
@@ -174,39 +142,29 @@ function watch(inputFile, outputFile) {
|
|
|
174
142
|
}
|
|
175
143
|
});
|
|
176
144
|
}
|
|
177
|
-
|
|
178
|
-
// Create the wrapped compile function
|
|
179
145
|
const compile = (obj) => {
|
|
180
146
|
originalCompile(obj);
|
|
181
|
-
|
|
147
|
+
let css = chain.cssOutput || '';
|
|
182
148
|
if (atomicOptimizer && config.atomic.enabled) {
|
|
183
|
-
|
|
184
|
-
chain.cssOutput =
|
|
185
|
-
return optimized;
|
|
149
|
+
css = atomicOptimizer.optimize(obj);
|
|
150
|
+
chain.cssOutput = css;
|
|
186
151
|
}
|
|
187
|
-
return
|
|
152
|
+
return css;
|
|
188
153
|
};
|
|
189
|
-
|
|
190
|
-
// Create a combined module for VM sandbox
|
|
191
154
|
const transpilerModule = {
|
|
192
155
|
$,
|
|
193
156
|
run,
|
|
194
|
-
compile,
|
|
157
|
+
compile: originalCompile,
|
|
195
158
|
chain
|
|
196
159
|
};
|
|
197
|
-
|
|
198
|
-
// Recursive file processing function
|
|
199
160
|
const processJCSSFile = (filePath) => {
|
|
200
161
|
if (fileCache.has(filePath)) {
|
|
201
162
|
return fileCache.get(filePath);
|
|
202
163
|
}
|
|
203
|
-
|
|
204
164
|
if (!fs.existsSync(filePath)) {
|
|
205
165
|
throw new Error(`File not found: ${filePath}`);
|
|
206
166
|
}
|
|
207
|
-
|
|
208
167
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
209
|
-
|
|
210
168
|
const vm = new NodeVM({
|
|
211
169
|
console: 'inherit',
|
|
212
170
|
timeout: 5000,
|
|
@@ -228,13 +186,11 @@ const processJCSSFile = (filePath) => {
|
|
|
228
186
|
root: './'
|
|
229
187
|
}
|
|
230
188
|
});
|
|
231
|
-
|
|
232
189
|
const wrappedContent = `
|
|
233
190
|
module.exports = {};
|
|
234
191
|
${content}
|
|
235
192
|
module.exports;
|
|
236
193
|
`;
|
|
237
|
-
|
|
238
194
|
try {
|
|
239
195
|
const exports = vm.run(wrappedContent, filePath);
|
|
240
196
|
fileCache.set(filePath, exports);
|
|
@@ -244,7 +200,6 @@ const processJCSSFile = (filePath) => {
|
|
|
244
200
|
throw err;
|
|
245
201
|
}
|
|
246
202
|
};
|
|
247
|
-
|
|
248
203
|
const processScript = (scriptBlock, filename) => {
|
|
249
204
|
const vm = new NodeVM({
|
|
250
205
|
console: 'inherit',
|
|
@@ -267,18 +222,16 @@ const processScript = (scriptBlock, filename) => {
|
|
|
267
222
|
root: './'
|
|
268
223
|
}
|
|
269
224
|
});
|
|
270
|
-
|
|
271
225
|
const jsCode = scriptBlock.trim();
|
|
272
|
-
|
|
273
226
|
try {
|
|
274
227
|
const result = vm.run(jsCode, filename);
|
|
275
|
-
|
|
228
|
+
const css = vm.sandbox.chain?.cssOutput || '';
|
|
229
|
+
return css;
|
|
276
230
|
} catch (err) {
|
|
277
231
|
console.error(`Error processing script in ${filename}:`, err.message);
|
|
278
232
|
throw err;
|
|
279
233
|
}
|
|
280
234
|
};
|
|
281
|
-
|
|
282
235
|
const processJavascriptBlocks = (content, inputpath) => {
|
|
283
236
|
const blocks = content.split(/<@([\s\S]*?)@>/gm);
|
|
284
237
|
let outputCSS = '';
|
|
@@ -289,9 +242,9 @@ const processJavascriptBlocks = (content, inputpath) => {
|
|
|
289
242
|
} else {
|
|
290
243
|
const scriptBlock = blocks[i];
|
|
291
244
|
try {
|
|
292
|
-
const
|
|
293
|
-
if (typeof
|
|
294
|
-
outputCSS +=
|
|
245
|
+
const blockCSS = processScript(scriptBlock, inputpath);
|
|
246
|
+
if (typeof blockCSS !== 'object' && typeof blockCSS !== 'undefined') {
|
|
247
|
+
outputCSS += blockCSS;
|
|
295
248
|
}
|
|
296
249
|
} catch (err) {
|
|
297
250
|
console.error(`Error processing script block:`, err.stack);
|
|
@@ -301,8 +254,6 @@ const processJavascriptBlocks = (content, inputpath) => {
|
|
|
301
254
|
}
|
|
302
255
|
return outputCSS.trim();
|
|
303
256
|
};
|
|
304
|
-
|
|
305
|
-
// Validate CSS
|
|
306
257
|
const validateCSS = (css) => {
|
|
307
258
|
const openBraces = (css.match(/{/g) || []).length;
|
|
308
259
|
const closeBraces = (css.match(/}/g) || []).length;
|
|
@@ -312,15 +263,12 @@ const validateCSS = (css) => {
|
|
|
312
263
|
}
|
|
313
264
|
return true;
|
|
314
265
|
};
|
|
315
|
-
|
|
316
266
|
const processAndMinifyCss = async (css, inputFile, outputFile) => {
|
|
317
267
|
if (!validateCSS(css)) {
|
|
318
268
|
throw new Error('Invalid CSS syntax - check for missing braces');
|
|
319
269
|
}
|
|
320
|
-
|
|
321
270
|
let processedCss = css;
|
|
322
271
|
let sourceMapFromPrefixer = null;
|
|
323
|
-
|
|
324
272
|
if (config.prefixer.enabled) {
|
|
325
273
|
try {
|
|
326
274
|
const result = await prefixer.process(css, {
|
|
@@ -335,93 +283,61 @@ const processAndMinifyCss = async (css, inputFile, outputFile) => {
|
|
|
335
283
|
processedCss = css;
|
|
336
284
|
}
|
|
337
285
|
}
|
|
338
|
-
|
|
339
286
|
const minifyOptions = {
|
|
340
287
|
sourceMap: config.prefixer.sourceMap === true,
|
|
341
288
|
sourceMapInlineSources: true
|
|
342
289
|
};
|
|
343
|
-
|
|
344
290
|
const output = new CleanCSS(minifyOptions).minify(processedCss);
|
|
345
|
-
|
|
346
291
|
if (output.errors.length > 0) {
|
|
347
292
|
console.error('CSS Minification Errors:', output.errors);
|
|
348
293
|
return { css: null, map: null };
|
|
349
294
|
}
|
|
350
|
-
|
|
351
295
|
let finalCss = output.styles;
|
|
352
296
|
let finalSourceMap = output.sourceMap ? JSON.stringify(output.sourceMap) : sourceMapFromPrefixer;
|
|
353
|
-
|
|
354
297
|
if (finalSourceMap && !config.prefixer.sourceMapInline) {
|
|
355
298
|
const mapFileName = path.basename(`${outputFile}.map`);
|
|
356
299
|
finalCss += `\n/*# sourceMappingURL=${mapFileName} */`;
|
|
357
300
|
}
|
|
358
|
-
|
|
359
301
|
return { css: finalCss, map: finalSourceMap };
|
|
360
302
|
};
|
|
361
|
-
|
|
362
|
-
// Main processor function
|
|
363
303
|
const processor = async (inputFile, outputFile) => {
|
|
364
304
|
try {
|
|
365
305
|
const input = path.resolve(inputFile);
|
|
366
306
|
const output = path.resolve(outputFile);
|
|
367
307
|
const content = fs.readFileSync(input, 'utf8');
|
|
368
|
-
|
|
369
308
|
const processedCSS = processJavascriptBlocks(content, input);
|
|
370
|
-
|
|
371
309
|
if (!validateCSS(processedCSS)) {
|
|
372
310
|
throw new Error('Invalid CSS syntax');
|
|
373
311
|
}
|
|
374
|
-
|
|
375
312
|
const stylePath = path.join(output, 'global.css');
|
|
376
313
|
const result = await processAndMinifyCss(processedCSS, input, stylePath);
|
|
377
|
-
|
|
378
314
|
if (result.css) {
|
|
379
315
|
fs.writeFileSync(stylePath, result.css, 'utf8');
|
|
380
|
-
|
|
381
316
|
if (result.map) {
|
|
382
317
|
const mapFile = `${stylePath}.map`;
|
|
383
318
|
fs.writeFileSync(mapFile, result.map, 'utf8');
|
|
384
319
|
}
|
|
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`);
|
|
389
320
|
}
|
|
390
321
|
} catch (err) {
|
|
391
322
|
console.error(`Failed to process ${inputFile}:`, err.message);
|
|
392
323
|
throw err;
|
|
393
324
|
}
|
|
394
325
|
};
|
|
395
|
-
|
|
396
|
-
// Main CLI logic
|
|
397
326
|
if (require.main === module) {
|
|
398
|
-
// Step 1: Ensure config exists
|
|
399
327
|
ensureConfigExists();
|
|
400
|
-
|
|
401
|
-
// Step 2: Load user config
|
|
402
328
|
loadUserConfig();
|
|
403
|
-
|
|
404
|
-
// Step 3: Parse CLI arguments
|
|
405
329
|
const args = process.argv.slice(2);
|
|
406
330
|
const cliOptions = parseArgs(args);
|
|
407
|
-
|
|
408
331
|
if (!cliOptions.inputFile || !cliOptions.outputFile) {
|
|
409
332
|
console.log(strVal.cli_opt_guide);
|
|
410
333
|
process.exit(1);
|
|
411
334
|
}
|
|
412
|
-
|
|
413
|
-
// Step 4: Apply CLI options (overrides config)
|
|
414
335
|
applyCliOptions(cliOptions);
|
|
415
|
-
|
|
416
|
-
// Step 5: Initialize components with final config (ONCE)
|
|
417
336
|
initAtomicOptimizer();
|
|
418
|
-
initPrefixer();
|
|
419
|
-
|
|
420
|
-
// Step 6: Run processor
|
|
337
|
+
initPrefixer();
|
|
421
338
|
(async () => {
|
|
422
339
|
try {
|
|
423
340
|
await processor(cliOptions.inputFile, cliOptions.outputFile);
|
|
424
|
-
|
|
425
341
|
if (cliOptions.watchMode) {
|
|
426
342
|
console.log('-- Watching for changes...\n');
|
|
427
343
|
watch(cliOptions.inputFile, cliOptions.outputFile);
|
|
@@ -432,7 +348,6 @@ if (require.main === module) {
|
|
|
432
348
|
}
|
|
433
349
|
})();
|
|
434
350
|
}
|
|
435
|
-
|
|
436
351
|
module.exports = {
|
|
437
352
|
processor,
|
|
438
353
|
watch,
|
package/node/index.js
CHANGED
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
const {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
module.exports = {
|
|
5
|
-
$,
|
|
6
|
-
run,
|
|
7
|
-
compile,
|
|
8
|
-
processor,
|
|
9
|
-
watch,
|
|
10
|
-
chain,
|
|
11
|
-
tokens,
|
|
12
|
-
createTokens
|
|
13
|
-
};
|
|
1
|
+
const {$,run,compile,chain,tokens,createTokens} = require('./btt');
|
|
2
|
+
module.exports = {$,run,compile,chain,tokens,createTokens};
|
package/node/prefixer.js
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
let postcss, browserslist, caniuse, autoprefixer;
|
|
2
|
-
|
|
3
|
-
// Try to load optional dependencies
|
|
4
2
|
try {
|
|
5
3
|
postcss = require('postcss');
|
|
6
4
|
browserslist = require('browserslist');
|
|
7
5
|
caniuse = require('caniuse-db/fulldata-json/data-2.0.json');
|
|
8
6
|
} catch (err) {
|
|
9
|
-
// Optional deps not installed - will use lightweight mode
|
|
10
7
|
}
|
|
11
|
-
|
|
12
|
-
// Try to load Autoprefixer (optional)
|
|
13
8
|
try {
|
|
14
9
|
autoprefixer = require('autoprefixer');
|
|
15
10
|
} catch (err) {
|
|
16
|
-
// Autoprefixer not installed - will use built-in
|
|
17
11
|
}
|
|
18
|
-
|
|
19
12
|
class ChainCSSPrefixer {
|
|
20
13
|
constructor(config = {}) {
|
|
21
14
|
this.config = {
|
|
@@ -26,15 +19,9 @@ class ChainCSSPrefixer {
|
|
|
26
19
|
sourceMapInline: config.sourceMapInline || false,
|
|
27
20
|
...config
|
|
28
21
|
};
|
|
29
|
-
|
|
30
|
-
// Check what's available
|
|
31
22
|
this.hasBuiltInDeps = !!(postcss && browserslist && caniuse);
|
|
32
23
|
this.hasAutoprefixer = !!autoprefixer;
|
|
33
|
-
|
|
34
|
-
// Determine which mode to use
|
|
35
24
|
this.prefixerMode = this.determineMode();
|
|
36
|
-
|
|
37
|
-
// Built-in prefixer data
|
|
38
25
|
this.caniuseData = caniuse ? caniuse.data : null;
|
|
39
26
|
this.commonProperties = this.getCommonProperties();
|
|
40
27
|
this.specialValues = {
|
|
@@ -42,75 +29,53 @@ class ChainCSSPrefixer {
|
|
|
42
29
|
'background-clip': ['text'],
|
|
43
30
|
'position': ['sticky']
|
|
44
31
|
};
|
|
45
|
-
|
|
46
32
|
this.browserPrefixMap = {
|
|
47
33
|
'chrome': 'webkit', 'safari': 'webkit', 'firefox': 'moz',
|
|
48
34
|
'ie': 'ms', 'edge': 'webkit', 'ios_saf': 'webkit',
|
|
49
35
|
'and_chr': 'webkit', 'android': 'webkit', 'opera': 'webkit',
|
|
50
36
|
'op_mob': 'webkit', 'samsung': 'webkit', 'and_ff': 'moz'
|
|
51
37
|
};
|
|
52
|
-
|
|
53
38
|
this.targetBrowsers = null;
|
|
54
39
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
40
|
determineMode() {
|
|
58
|
-
// User explicitly wants full mode but Autoprefixer not installed
|
|
59
41
|
if (this.config.mode === 'full' && !this.hasAutoprefixer) {
|
|
60
42
|
console.warn('⚠️ Full mode requested but autoprefixer not installed. Falling back to lightweight mode.');
|
|
61
43
|
console.warn(' To use full mode: npm install autoprefixer postcss caniuse-db browserslist\n');
|
|
62
44
|
return 'lightweight';
|
|
63
45
|
}
|
|
64
|
-
|
|
65
|
-
// User explicitly wants lightweight mode
|
|
66
46
|
if (this.config.mode === 'lightweight') {
|
|
67
47
|
return 'lightweight';
|
|
68
48
|
}
|
|
69
|
-
|
|
70
|
-
// User wants full mode and it's available
|
|
71
49
|
if (this.config.mode === 'full' && this.hasAutoprefixer) {
|
|
72
50
|
return 'full';
|
|
73
51
|
}
|
|
74
|
-
|
|
75
|
-
// Auto mode: use full if available, otherwise lightweight
|
|
76
52
|
if (this.config.mode === 'auto') {
|
|
77
53
|
return this.hasAutoprefixer ? 'full' : 'lightweight';
|
|
78
54
|
}
|
|
79
|
-
|
|
80
55
|
return 'lightweight';
|
|
81
56
|
}
|
|
82
|
-
|
|
83
57
|
async process(cssString, options = {}) {
|
|
84
58
|
if (!this.config.enabled) {
|
|
85
59
|
return { css: cssString, map: null };
|
|
86
60
|
}
|
|
87
|
-
|
|
88
61
|
try {
|
|
89
|
-
// Set up source map options
|
|
90
62
|
const mapOptions = {
|
|
91
63
|
inline: this.config.sourceMapInline,
|
|
92
64
|
annotation: false,
|
|
93
65
|
sourcesContent: true
|
|
94
66
|
};
|
|
95
|
-
|
|
96
67
|
if (this.prefixerMode === 'full') {
|
|
97
68
|
return await this.processWithAutoprefixer(cssString, options, mapOptions);
|
|
98
69
|
}
|
|
99
|
-
|
|
100
70
|
return await this.processWithBuiltIn(cssString, options, mapOptions);
|
|
101
|
-
|
|
102
71
|
} catch (err) {
|
|
103
72
|
console.error('Prefixer error:', err.message);
|
|
104
73
|
return { css: cssString, map: null };
|
|
105
74
|
}
|
|
106
75
|
}
|
|
107
|
-
|
|
108
|
-
// Full mode with Autoprefixer
|
|
109
|
-
async processWithAutoprefixer(cssString, options, mapOptions) {
|
|
110
|
-
|
|
76
|
+
async processWithAutoprefixer(cssString, options, mapOptions) {
|
|
111
77
|
const from = options.from || 'input.css';
|
|
112
78
|
const to = options.to || 'output.css';
|
|
113
|
-
|
|
114
79
|
const result = await postcss([
|
|
115
80
|
autoprefixer({ overrideBrowserslist: this.config.browsers })
|
|
116
81
|
]).process(cssString, {
|
|
@@ -118,19 +83,15 @@ class ChainCSSPrefixer {
|
|
|
118
83
|
to,
|
|
119
84
|
map: this.config.sourceMap ? mapOptions : false
|
|
120
85
|
});
|
|
121
|
-
|
|
122
86
|
return {
|
|
123
87
|
css: result.css,
|
|
124
88
|
map: result.map ? result.map.toString() : null
|
|
125
89
|
};
|
|
126
90
|
}
|
|
127
|
-
|
|
128
|
-
// Lightweight mode with built-in prefixer
|
|
129
91
|
async processWithBuiltIn(cssString, options, mapOptions) {
|
|
130
92
|
if (!this.hasBuiltInDeps) {
|
|
131
93
|
return { css: cssString, map: null };
|
|
132
94
|
}
|
|
133
|
-
|
|
134
95
|
this.targetBrowsers = browserslist(this.config.browsers);
|
|
135
96
|
const from = options.from || 'input.css';
|
|
136
97
|
const to = options.to || 'output.css';
|
|
@@ -141,13 +102,11 @@ class ChainCSSPrefixer {
|
|
|
141
102
|
to,
|
|
142
103
|
map: this.config.sourceMap ? mapOptions : false
|
|
143
104
|
});
|
|
144
|
-
|
|
145
105
|
return {
|
|
146
106
|
css: result.css,
|
|
147
107
|
map: result.map ? result.map.toString() : null
|
|
148
108
|
};
|
|
149
109
|
}
|
|
150
|
-
|
|
151
110
|
createBuiltInPlugin() {
|
|
152
111
|
return (root) => {
|
|
153
112
|
root.walkDecls(decl => {
|
|
@@ -155,40 +114,30 @@ class ChainCSSPrefixer {
|
|
|
155
114
|
});
|
|
156
115
|
};
|
|
157
116
|
}
|
|
158
|
-
|
|
159
117
|
processBuiltInDeclaration(decl) {
|
|
160
118
|
const { prop, value } = decl;
|
|
161
|
-
|
|
162
119
|
if (this.commonProperties.includes(prop)) {
|
|
163
120
|
this.addPrefixesFromCaniuse(decl);
|
|
164
121
|
}
|
|
165
|
-
|
|
166
122
|
if (this.specialValues[prop]?.includes(value)) {
|
|
167
123
|
this.addSpecialValuePrefixes(decl);
|
|
168
124
|
}
|
|
169
125
|
}
|
|
170
|
-
|
|
171
126
|
addPrefixesFromCaniuse(decl) {
|
|
172
127
|
if (!this.caniuseData) return;
|
|
173
|
-
|
|
174
128
|
const feature = this.findFeature(decl.prop);
|
|
175
129
|
if (!feature) return;
|
|
176
|
-
|
|
177
130
|
const prefixes = new Set();
|
|
178
|
-
|
|
179
131
|
this.targetBrowsers.forEach(browser => {
|
|
180
132
|
const [id, versionStr] = browser.split(' ');
|
|
181
133
|
const version = parseFloat(versionStr.split('-')[0]);
|
|
182
134
|
const stats = feature.stats[id];
|
|
183
|
-
|
|
184
135
|
if (stats) {
|
|
185
136
|
const versions = Object.keys(stats)
|
|
186
137
|
.map(v => parseFloat(v.split('-')[0]))
|
|
187
138
|
.filter(v => !isNaN(v))
|
|
188
139
|
.sort((a, b) => a - b);
|
|
189
|
-
|
|
190
140
|
const closestVersion = versions.find(v => v <= version) || versions[0];
|
|
191
|
-
|
|
192
141
|
if (closestVersion) {
|
|
193
142
|
const support = stats[closestVersion.toString()];
|
|
194
143
|
if (support && support.includes('x')) {
|
|
@@ -206,10 +155,8 @@ class ChainCSSPrefixer {
|
|
|
206
155
|
});
|
|
207
156
|
});
|
|
208
157
|
}
|
|
209
|
-
|
|
210
158
|
addSpecialValuePrefixes(decl) {
|
|
211
159
|
const { prop, value } = decl;
|
|
212
|
-
|
|
213
160
|
if (prop === 'display') {
|
|
214
161
|
if (value === 'flex' || value === 'inline-flex') {
|
|
215
162
|
decl.cloneBefore({ prop: 'display', value: `-webkit-${value}` });
|
|
@@ -225,19 +172,16 @@ class ChainCSSPrefixer {
|
|
|
225
172
|
});
|
|
226
173
|
}
|
|
227
174
|
}
|
|
228
|
-
|
|
229
175
|
if (prop === 'background-clip' && value === 'text') {
|
|
230
176
|
decl.cloneBefore({ prop: '-webkit-background-clip', value: 'text' });
|
|
231
177
|
}
|
|
232
|
-
|
|
233
178
|
if (prop === 'position' && value === 'sticky') {
|
|
234
179
|
decl.cloneBefore({ prop: 'position', value: '-webkit-sticky' });
|
|
235
180
|
}
|
|
236
181
|
}
|
|
237
182
|
|
|
238
183
|
findFeature(property) {
|
|
239
|
-
if (!this.caniuseData) return null;
|
|
240
|
-
|
|
184
|
+
if (!this.caniuseData) return null;
|
|
241
185
|
const featureMap = {
|
|
242
186
|
'transform': 'transforms2d',
|
|
243
187
|
'transform-origin': 'transforms2d',
|
|
@@ -267,11 +211,9 @@ class ChainCSSPrefixer {
|
|
|
267
211
|
'grid-column': 'css-grid',
|
|
268
212
|
'grid-row': 'css-grid'
|
|
269
213
|
};
|
|
270
|
-
|
|
271
214
|
const featureId = featureMap[property];
|
|
272
215
|
return featureId ? this.caniuseData[featureId] : null;
|
|
273
216
|
}
|
|
274
|
-
|
|
275
217
|
getCommonProperties() {
|
|
276
218
|
return [
|
|
277
219
|
'transform', 'transform-origin', 'transform-style',
|
|
@@ -292,5 +234,4 @@ class ChainCSSPrefixer {
|
|
|
292
234
|
];
|
|
293
235
|
}
|
|
294
236
|
}
|
|
295
|
-
|
|
296
237
|
module.exports = ChainCSSPrefixer;
|
package/node/strVal.js
CHANGED