styimat 8.6.0 → 9.1.0

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.
@@ -0,0 +1,1653 @@
1
+ /*!
2
+ * MIT License
3
+ * Copyright (c) 2025 王小玗
4
+ */
5
+ /**
6
+ * CSS 变量预处理库 - 增强版
7
+ * 支持 CSS 变量预处理、嵌套选择器和嵌套变量
8
+ * 支持 Lab 和 LCH 颜色空间转换为 RGB(CSS标准格式)
9
+ * 支持 lab# 和 lch# 十六进制语法
10
+ * 支持 Display P3 广色域显示器
11
+ * 增强 math() 函数,支持复杂数学计算
12
+ * 支持配置头
13
+ * 支持 @import 语法
14
+ * 支持 @alias 语法
15
+ * 支持 @macro 宏定义系统
16
+ */
17
+
18
+
19
+ const styimat = (function() {
20
+ // 默认配置
21
+ let defaultConfig = {
22
+ rootSelector: ':root',
23
+ variablePrefix: '--',
24
+ preserveOriginal: false,
25
+ indentSize: 4,
26
+ enableNesting: true,
27
+ autoProcessStyleTags: true,
28
+ styleTagAttribute: 'e',
29
+ convertLabToRGB: true,
30
+ convertLchToRGB: true,
31
+ enableP3: true,
32
+ enableMath: true,
33
+ importBaseUrl: '',
34
+ importCache: true,
35
+ importTimeout: 5000,
36
+ enableAlias: true,
37
+ enableMacros: true
38
+ };
39
+
40
+ const REGEX = {
41
+ IMPORT: /@import\s+([^;]+?)\s*;/g,
42
+ ALIAS: /^@alias\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+(.+?)\s*;$/,
43
+ MACRO: /^@macro\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*\{$/,
44
+ COMMENT: /\/\*[\s\S]*?\*\//g,
45
+ MATH_SYMBOL: /([\da-z])([+-])(-?[\da-z])/g,
46
+ MATH: /math\(([^)]+)\)/gi,
47
+ COLOR: /(lab|lch)\([^)]+\)/gi,
48
+ HEXLAB: /lab#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/gi,
49
+ HEXLCH: /lch#([0-9a-f]{2})([0-9a-f]{2})(\d{1,3})/gi,
50
+ SPACE: /\s+/g,
51
+ AND: /&/g,
52
+ HYPHEN: /-([a-z])/g,
53
+ VARIABLE: /(?:\$\$|\$)([a-zA-Z_][a-zA-Z0-9_]*)(?=[^a-zA-Z0-9_])/g
54
+ }
55
+
56
+ // 全局P3支持检测结果
57
+ let p3Supported = null;
58
+
59
+ // 导入文件缓存
60
+ const importCache = new Map();
61
+
62
+ // 别名映射表
63
+ const aliasMap = new Map();
64
+
65
+ // 宏定义存储
66
+ const macroRegistry = new Map();
67
+
68
+ const pluginMap = new Map();
69
+
70
+ function splitLines(str, splitChar = "\n") {
71
+ const lines = [];
72
+ const splitCharCode = splitChar.charCodeAt(0);
73
+ let start = 0;
74
+
75
+ for (let i = 0, length = str.length; i < length; i++) {
76
+ if (str.charCodeAt(i) === splitCharCode) {
77
+ if (i > start || str.charAt(start) !== '\r') {
78
+ lines.push(str.slice(start, i));
79
+ }
80
+ start = i + 1;
81
+ }
82
+ }
83
+
84
+ // 处理最后一行
85
+ if (start < str.length) {
86
+ lines.push(str.substring(start));
87
+ } else if (start === str.length && str.charCodeAt(str.length - 1) === 10) {
88
+ lines.push('');
89
+ }
90
+
91
+ return lines;
92
+ }
93
+
94
+ /**
95
+ * 解析配置头
96
+ */
97
+ function parseConfigHeader(cssText) {
98
+ const config = { ...defaultConfig };
99
+ const lines = splitLines(cssText);
100
+ const cleanLines = [];
101
+
102
+ for (let line of lines) {
103
+ const trimmed = line.trim();
104
+
105
+ if (trimmed.startsWith('#')) {
106
+ const configLine = trimmed.substring(1).trim();
107
+ const firstSpace = configLine.indexOf(' ');
108
+
109
+ if (~firstSpace) {
110
+ const key = configLine.substring(0, firstSpace).trim();
111
+ const value = configLine.substring(firstSpace + 1).trim();
112
+
113
+ const configKey = camelCase(key);
114
+
115
+
116
+ if (value === 'true' || value === 'false') {
117
+ config[configKey] = value === 'true';
118
+ } else if (!isNaN(value) && value.trim() !== '') {
119
+ config[configKey] = Number(value);
120
+ } else {
121
+ config[configKey] = value;
122
+ }
123
+ } else {
124
+ console.warn(`无效的配置行: ${trimmed}`);
125
+ }
126
+ } else {
127
+ cleanLines.push(line);
128
+ }
129
+ }
130
+
131
+ return {
132
+ config,
133
+ css: cleanLines.join('\n')
134
+ };
135
+ }
136
+
137
+ /**
138
+ * 解析 @alias 语句
139
+ */
140
+ function parseAliasStatements(cssText) {
141
+ const aliases = new Map();
142
+ const lines = splitLines(cssText);
143
+ const cleanLines = [];
144
+
145
+ for (let line of lines) {
146
+ const trimmed = line.trim();
147
+
148
+ if (trimmed.startsWith('@alias')) {
149
+ const aliasMatch = trimmed.match(REGEX.ALIAS);
150
+ if (aliasMatch) {
151
+ const aliasName = aliasMatch[1];
152
+ const originalProperty = aliasMatch[2];
153
+
154
+ aliases.set(aliasName, originalProperty);
155
+ continue;
156
+ }
157
+ }
158
+
159
+ cleanLines.push(line);
160
+ }
161
+
162
+ return {
163
+ aliases,
164
+ css: cleanLines.join('\n')
165
+ };
166
+ }
167
+
168
+ /**
169
+ * 解析 @macro 语句
170
+ */
171
+ function parseMacroStatements(cssText, config) {
172
+ if (!config.enableMacros) {
173
+ return { macros: new Map(), css: cssText };
174
+ }
175
+
176
+ const macros = new Map();
177
+ const lines = splitLines(cssText);
178
+ const cleanLines = [];
179
+ let inMacroDefinition = false;
180
+ let currentMacroName = '';
181
+ let currentMacroParams = [];
182
+ let currentMacroBody = [];
183
+ let braceDepth = 0;
184
+
185
+ for (let line of lines) {
186
+ const trimmed = line.trim();
187
+
188
+ if (!inMacroDefinition && trimmed.startsWith('@macro')) {
189
+ const macroMatch = trimmed.match(REGEX.MACRO);
190
+ if (macroMatch) {
191
+ inMacroDefinition = true;
192
+ currentMacroName = macroMatch[1];
193
+ currentMacroParams = splitLines(macroMatch[2], ',')
194
+ .map(param => param.trim())
195
+ .filter(param => param)
196
+ .map(param => {
197
+ const paramParts = splitLines(param, ':').map(p => p.trim());
198
+ return {
199
+ name: paramParts[0].slice(1),
200
+ defaultValue: paramParts[1] || null
201
+ };
202
+ });
203
+ currentMacroBody = [];
204
+ braceDepth = 1;
205
+ continue;
206
+ }
207
+ }
208
+
209
+ if (inMacroDefinition) {
210
+ for (const char of line) {
211
+ if (char === '{') braceDepth++;
212
+ if (char === '}') braceDepth--;
213
+ }
214
+
215
+ if (braceDepth === 0) {
216
+ macros.set(currentMacroName, {
217
+ params: currentMacroParams,
218
+ body: currentMacroBody.join('\n')
219
+ });
220
+
221
+ inMacroDefinition = false;
222
+ currentMacroName = '';
223
+ currentMacroParams = [];
224
+ currentMacroBody = [];
225
+ } else {
226
+ currentMacroBody.push(line);
227
+ }
228
+ continue;
229
+ }
230
+
231
+ cleanLines.push(line);
232
+ }
233
+
234
+ return {
235
+ macros,
236
+ css: cleanLines.join('\n')
237
+ };
238
+ }
239
+
240
+ /**
241
+ * 解析宏参数
242
+ */
243
+ function parseMacroArguments(argsStr, paramDefs, splitChar = ',') {
244
+ const argsMap = new Map();
245
+ const argValues = parseArgumentList(argsStr, splitChar);
246
+
247
+ for (let i = 0, length = paramDefs.length; i < length; i++) {
248
+ const param = paramDefs[i];
249
+ let value;
250
+
251
+ if (i < argValues.length) {
252
+ value = argValues[i];
253
+ } else if (param.defaultValue !== null) {
254
+ value = param.defaultValue;
255
+ } else {
256
+ value = 'none';
257
+ }
258
+
259
+ argsMap.set(param.name, value);
260
+ }
261
+
262
+ return argsMap;
263
+ }
264
+
265
+ /**
266
+ * 解析参数列表
267
+ */
268
+ function parseArgumentList(argsStr, splitChar) {
269
+ const args = [];
270
+ let currentArg = '';
271
+ let inQuotes = false;
272
+ let quoteChar = '';
273
+ let parenDepth = 0;
274
+ let bracketDepth = 0;
275
+
276
+ for (let i = 0, length = argsStr.length; i < length; i++) {
277
+ const char = argsStr[i];
278
+
279
+ if ((char === '"' || char === "'") && !inQuotes) {
280
+ inQuotes = true;
281
+ quoteChar = char;
282
+ } else if (char === quoteChar && inQuotes) {
283
+ inQuotes = false;
284
+ quoteChar = '';
285
+ }
286
+
287
+ if (!inQuotes) {
288
+ if (char === '(') parenDepth++;
289
+ if (char === ')') parenDepth--;
290
+ if (char === '[') bracketDepth++;
291
+ if (char === ']') bracketDepth--;
292
+ }
293
+
294
+ if (char === splitChar && !inQuotes && parenDepth === 0 && bracketDepth === 0) {
295
+ args.push(currentArg.trim());
296
+ currentArg = '';
297
+ } else {
298
+ currentArg += char;
299
+ }
300
+ }
301
+
302
+ if (currentArg.trim()) {
303
+ args.push(currentArg.trim());
304
+ }
305
+
306
+ return args;
307
+ }
308
+
309
+ /**
310
+ * 应用宏替换
311
+ */
312
+ function applyMacro(macroBody, args, config) {
313
+ let result = macroBody;
314
+
315
+ result = result.replace(REGEX.VARIABLE, (match, paramName) => {
316
+ const paramValue = args.get(paramName);
317
+ if (paramValue) return args.get(paramName);
318
+ return match;
319
+ });
320
+
321
+ result = processCSSValue(result, config);
322
+
323
+ return result;
324
+ }
325
+
326
+ /**
327
+ * 将连字符分隔的字符串转换为驼峰命名
328
+ */
329
+ function camelCase(str) {
330
+ return str.replace(REGEX.HYPHEN, function(match, letter) {
331
+ return letter.toUpperCase();
332
+ });
333
+ }
334
+
335
+ /**
336
+ * 检测浏览器是否支持 Display P3
337
+ */
338
+ function detectP3Support() {
339
+ if (p3Supported !== null) return p3Supported;
340
+
341
+ if (typeof window === 'undefined' || !window.CSS) {
342
+ p3Supported = false;
343
+ return false;
344
+ }
345
+
346
+ try {
347
+ p3Supported = CSS.supports('color', 'color(display-p3 1 0 0)');
348
+ } catch (error) {
349
+ p3Supported = false;
350
+ }
351
+
352
+ return p3Supported;
353
+ }
354
+
355
+ /**
356
+ * 解析一行CSS
357
+ */
358
+ function parseSingleLineCSS(cssString, aliases, macros) {
359
+ let str = cssString.trim();
360
+
361
+ if (str.endsWith(';')) {
362
+ str = str.slice(0, -1);
363
+ }
364
+
365
+ if (!str) {
366
+ return [];
367
+ }
368
+
369
+ const declarations = [];
370
+ let currentDeclaration = '';
371
+ let inParens = 0;
372
+ let inQuotes = false;
373
+ let quoteChar = '';
374
+
375
+ for (let i = 0, length = str.length; i < length; i++) {
376
+ const char = str[i];
377
+
378
+ if ((char === '"' || char === "'") && !inQuotes) {
379
+ inQuotes = true;
380
+ quoteChar = char;
381
+ } else if (char === quoteChar && inQuotes) {
382
+ inQuotes = false;
383
+ quoteChar = '';
384
+ }
385
+
386
+ if (!inQuotes) {
387
+ if (char === '(') {
388
+ inParens++;
389
+ } else if (char === ')') {
390
+ inParens--;
391
+ }
392
+ }
393
+
394
+ if (char === ';' && !inQuotes && inParens === 0) {
395
+ if (currentDeclaration.trim()) {
396
+ declarations.push(currentDeclaration.trim());
397
+ currentDeclaration = '';
398
+ }
399
+ } else {
400
+ currentDeclaration += char;
401
+ }
402
+ }
403
+
404
+ if (currentDeclaration.trim()) {
405
+ declarations.push(currentDeclaration.trim());
406
+ }
407
+
408
+ const result = [];
409
+
410
+ for (let declaration of declarations) {
411
+ declaration = declaration.replace(REGEX.COMMENT, '');
412
+ if (!declaration.trim()) continue;
413
+
414
+ const colonIndex = findFirstColonOutsideQuotes(declaration);
415
+
416
+ if (!~colonIndex) {
417
+ console.warn(`无效的CSS声明: "${declaration}"`);
418
+ continue;
419
+ }
420
+
421
+ let property = declaration.substring(0, colonIndex).trim();
422
+ let value = declaration.substring(colonIndex + 1).trim();
423
+
424
+ if (value.endsWith(';')) {
425
+ value = value.slice(0, -1).trim();
426
+ }
427
+
428
+ if (property.startsWith('$')) {
429
+ property = "--" + property.slice(1);
430
+ }
431
+
432
+ property = aliases.get(property) ?? property;
433
+
434
+ if (property.startsWith("@") && macros.get(property.slice(1))) {
435
+ const macro = macros.get(property.slice(1));
436
+ const args = parseMacroArguments(value, macro.params, ' ');
437
+ property = applyMacro(macro.body, args, config);
438
+ value = "";
439
+ }
440
+
441
+ result.push({ [property]: value });
442
+ }
443
+
444
+ return result;
445
+ }
446
+
447
+ /**
448
+ * 查找不在引号内的第一个冒号位置
449
+ */
450
+ function findFirstColonOutsideQuotes(str) {
451
+ let inQuotes = false;
452
+ let quoteChar = '';
453
+
454
+ for (let i = 0, length = str.length; i < length; i++) {
455
+ const char = str[i];
456
+
457
+ if ((char === '"' || char === "'") && !inQuotes) {
458
+ inQuotes = true;
459
+ quoteChar = char;
460
+ } else if (char === quoteChar && inQuotes) {
461
+ inQuotes = false;
462
+ quoteChar = '';
463
+ }
464
+
465
+ if (char === ':' && !inQuotes) {
466
+ return i;
467
+ }
468
+ }
469
+
470
+ return -1;
471
+ }
472
+
473
+ /**
474
+ * 增强的数学表达式解析和计算
475
+ */
476
+ function evaluateMathExpression(expression, config) {
477
+ let cleanExpr = expression.replace(REGEX.SPACE, '');
478
+
479
+ return parseMathExpression(cleanExpr);
480
+ }
481
+
482
+ /**
483
+ * 解析数学表达式
484
+ */
485
+ function parseMathExpression(expr) {
486
+ return `calc(${expr
487
+ .replace(REGEX.MATH_SYMBOL, '$1 $2 $3')})`;
488
+ }
489
+
490
+ /**
491
+ * 处理所有的math()函数
492
+ */
493
+ function processMathFunctions(cssValue, config) {
494
+ let result = cssValue;
495
+
496
+ const processMath = (str) => {
497
+ return str.replace(REGEX.MATH, (match, expression) => {
498
+ return evaluateMathExpression(expression, config);
499
+ });
500
+ };
501
+
502
+ result = processMath(result);
503
+
504
+ return result;
505
+ }
506
+
507
+ /**
508
+ * 解析并转换所有的 Lab 和 LCH 颜色
509
+ */
510
+ function convertAllLabLchColors(cssValue, config) {
511
+ if (!config.convertLabToRGB && !config.convertLchToRGB) {
512
+ return cssValue;
513
+ }
514
+
515
+ let result = cssValue;
516
+ result = parseHexColorFormats(result, config);
517
+
518
+ const processedColors = new Map();
519
+
520
+ const processColorFunctions = (str) => {
521
+ return str.replace(REGEX.COLOR, (match) => {
522
+ if (processedColors.has(match)) {
523
+ return processedColors.get(match);
524
+ }
525
+
526
+ let converted = match;
527
+
528
+ if (match.toLowerCase().startsWith('lab(')) {
529
+ if (config.convertLabToRGB) {
530
+ converted = convertSingleLabColor(match, config);
531
+ }
532
+ } else if (match.toLowerCase().startsWith('lch(')) {
533
+ if (config.convertLchToRGB) {
534
+ converted = convertSingleLchColor(match, config);
535
+ }
536
+ }
537
+
538
+ processedColors.set(match, converted);
539
+ return converted;
540
+ });
541
+ };
542
+
543
+ let lastResult;
544
+ do {
545
+ lastResult = result;
546
+ result = processColorFunctions(result);
547
+ } while (result !== lastResult);
548
+
549
+ return result;
550
+ }
551
+
552
+ /**
553
+ * 解析十六进制颜色格式
554
+ */
555
+ function parseHexColorFormats(value, config) {
556
+ let result = value;
557
+
558
+ const processedHexColors = new Map();
559
+
560
+ result = result.replace(REGEX.HEXLAB, (match, L_hex, A_hex, B_hex) => {
561
+ if (processedHexColors.has(match)) {
562
+ return processedHexColors.get(match);
563
+ }
564
+
565
+ try {
566
+ const L = parseInt(L_hex, 16) / 255 * 100;
567
+ const A = (parseInt(A_hex, 16) - 128) * 1.5;
568
+ const B = (parseInt(B_hex, 16) - 128) * 1.5;
569
+
570
+ const converted = generateColorString(L, A, B, config);
571
+ processedHexColors.set(match, converted);
572
+ return converted;
573
+ } catch (error) {
574
+ console.warn(`无法解析lab#十六进制颜色: ${match}`, error);
575
+ return match;
576
+ }
577
+ });
578
+
579
+ result = result.replace(REGEX.HEXLCH, (match, L_hex, C_hex, H_dec) => {
580
+ if (processedHexColors.has(match)) {
581
+ return processedHexColors.get(match);
582
+ }
583
+
584
+ try {
585
+ const L = parseInt(L_hex, 16) / 255 * 100;
586
+ const C = parseInt(C_hex, 16) / 255 * 150;
587
+ const H = parseInt(H_dec) / 100 * 360;
588
+
589
+ const lab = lchToLab(L, C, H);
590
+ const converted = generateColorString(lab.L, lab.a, lab.b, config);
591
+ processedHexColors.set(match, converted);
592
+ return converted;
593
+ } catch (error) {
594
+ console.warn(`无法解析lch#十六进制颜色: ${match}`, error);
595
+ return match;
596
+ }
597
+ });
598
+
599
+ return result;
600
+ }
601
+
602
+ /**
603
+ * 转换单个 lab() 颜色函数
604
+ */
605
+ function convertSingleLabColor(labString, config) {
606
+ const labRegex = /lab\(\s*([\d.]+)(%?)\s+([\d.-]+)\s+([\d.-]+)(?:\s*\/\s*([\d.%]+))?\s*\)/i;
607
+ const match = labString.match(labRegex);
608
+
609
+ if (!match) {
610
+ return labString;
611
+ }
612
+
613
+ try {
614
+ let L = parseFloat(match[1]);
615
+
616
+ if (match[2] !== '%') {
617
+ if (L < 0) L = 0;
618
+ if (L > 100) L = 100;
619
+ }
620
+
621
+ const A = parseFloat(match[3]);
622
+ const B = parseFloat(match[4]);
623
+
624
+ const alphaValue = match[5] !== undefined
625
+ ? match[5].includes('%')
626
+ ? parseFloat(match[5]) / 100
627
+ : parseFloat(match[5])
628
+ : null;
629
+
630
+ return generateColorString(L, A, B, config, alphaValue);
631
+ } catch (error) {
632
+ console.warn(`无法转换LAB颜色: ${labString}`, error);
633
+ return labString;
634
+ }
635
+ }
636
+
637
+ /**
638
+ * 转换单个 lch() 颜色函数
639
+ */
640
+ function convertSingleLchColor(lchString, config) {
641
+ const lchRegex = /lch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)(deg)?(?:\s*\/\s*([\d.%]+))?\s*\)/i;
642
+ const match = lchString.match(lchRegex);
643
+
644
+ if (!match) {
645
+ return lchString;
646
+ }
647
+
648
+ try {
649
+ let L = parseFloat(match[1]);
650
+
651
+ if (match[2] === '%') {
652
+ L = L;
653
+ } else {
654
+ if (L < 0) L = 0;
655
+ if (L > 100) L = 100;
656
+ }
657
+
658
+ const C = parseFloat(match[3]);
659
+ let H = parseFloat(match[4]);
660
+
661
+ if (C < 0) {
662
+ console.warn(`LCH中的C值不能为负: ${C}`);
663
+ }
664
+
665
+ H = ((H % 360) + 360) % 360;
666
+
667
+ const lab = lchToLab(L, C, H);
668
+
669
+ const alphaValue = match[6] !== undefined
670
+ ? match[6].includes('%')
671
+ ? parseFloat(match[6]) / 100
672
+ : parseFloat(match[6])
673
+ : null;
674
+
675
+ return generateColorString(lab.L, lab.a, lab.b, config, alphaValue);
676
+ } catch (error) {
677
+ console.warn(`无法转换LCH颜色: ${lchString}`, error);
678
+ return lchString;
679
+ }
680
+ }
681
+
682
+ /**
683
+ * LCH 转换为 Lab
684
+ */
685
+ function lchToLab(L, C, H) {
686
+ const H_rad = H * Math.PI / 180;
687
+ const a = C * Math.cos(H_rad);
688
+ const b = C * Math.sin(H_rad);
689
+
690
+ return { L, a, b };
691
+ }
692
+
693
+ /**
694
+ * Lab -> sRGB 转换函数
695
+ */
696
+ function preciseLabToRGB(L, a, b) {
697
+ const labToXyz = (L, a, b) => {
698
+ const refX = 0.95047;
699
+ const refY = 1.00000;
700
+ const refZ = 1.08883;
701
+
702
+ const epsilon = 0.008856;
703
+ const kappa = 903.3;
704
+
705
+ const fy = (L + 16) / 116;
706
+ const fx = a / 500 + fy;
707
+ const fz = fy - b / 200;
708
+
709
+ const xr = fx ** 3 > epsilon ? fx ** 3 : (116 * fx - 16) / kappa;
710
+ const yr = L > kappa * epsilon ? ((L + 16) / 116) ** 3 : L / kappa;
711
+ const zr = fz ** 3 > epsilon ? fz ** 3 : (116 * fz - 16) / kappa;
712
+
713
+ return [
714
+ xr * refX,
715
+ yr * refY,
716
+ zr * refZ
717
+ ];
718
+ };
719
+
720
+ const xyzToLinearRgb = (x, y, z) => {
721
+ const M = [
722
+ [ 3.2404542, -1.5371385, -0.4985314],
723
+ [-0.9692660, 1.8760108, 0.0415560],
724
+ [ 0.0556434, -0.2040259, 1.0572252]
725
+ ];
726
+
727
+ const r = M[0][0] * x + M[0][1] * y + M[0][2] * z;
728
+ const g = M[1][0] * x + M[1][1] * y + M[1][2] * z;
729
+ const b = M[2][0] * x + M[2][1] * y + M[2][2] * z;
730
+
731
+ return [r, g, b];
732
+ };
733
+
734
+ const applyGamma = (c) => {
735
+ const sign = c < 0 ? -1 : 1;
736
+ const absC = sign * c;
737
+
738
+ if (absC <= 0.0031308) {
739
+ return 12.92 * absC;
740
+ } else {
741
+ return sign * (1.055 * Math.pow(absC, 1/2.4) - 0.055);
742
+ }
743
+ };
744
+
745
+ const clamp = (value) => {
746
+ return Math.max(0, Math.min(255, value * 255 |0));
747
+ };
748
+
749
+ const [X, Y, Z] = labToXyz(L, a, b);
750
+ const [linearR, linearG, linearB] = xyzToLinearRgb(X, Y, Z);
751
+
752
+ const r = applyGamma(linearR);
753
+ const g = applyGamma(linearG);
754
+ const bOut = applyGamma(linearB);
755
+
756
+ return {
757
+ r: clamp(r),
758
+ g: clamp(g),
759
+ b: clamp(bOut)
760
+ };
761
+ }
762
+
763
+ /**
764
+ * Lab -> Display P3 转换
765
+ */
766
+ function labToP3(L, a, b) {
767
+ const labToXyz = (L, a, b) => {
768
+ const refX = 0.95047;
769
+ const refY = 1.00000;
770
+ const refZ = 1.08883;
771
+
772
+ const epsilon = 0.008856;
773
+ const kappa = 903.3;
774
+
775
+ const fy = (L + 16) / 116;
776
+ const fx = a / 500 + fy;
777
+ const fz = fy - b / 200;
778
+
779
+ const xr = fx ** 3 > epsilon ? fx ** 3 : (116 * fx - 16) / kappa;
780
+ const yr = L > kappa * epsilon ? ((L + 16) / 116) ** 3 : L / kappa;
781
+ const zr = fz ** 3 > epsilon ? fz ** 3 : (116 * fz - 16) / kappa;
782
+
783
+ return [
784
+ xr * refX,
785
+ yr * refY,
786
+ zr * refZ
787
+ ];
788
+ };
789
+
790
+ const xyzToLinearP3 = (x, y, z) => {
791
+ const M = [
792
+ [ 2.493496911941425, -0.9313836179191239, -0.40271078445071684],
793
+ [-0.8294889695615747, 1.7626640603183463, 0.023624685841943577],
794
+ [ 0.03584583024378447, -0.07617238926804182, 0.9568845240076872]
795
+ ];
796
+
797
+ const r = M[0][0] * x + M[0][1] * y + M[0][2] * z;
798
+ const g = M[1][0] * x + M[1][1] * y + M[1][2] * z;
799
+ const b = M[2][0] * x + M[2][1] * y + M[2][2] * z;
800
+
801
+ return [r, g, b];
802
+ };
803
+
804
+ const applyGamma = (c) => {
805
+ const sign = c < 0 ? -1 : 1;
806
+ const absC = Math.abs(c);
807
+
808
+ if (absC <= 0.0031308) {
809
+ return sign * 12.92 * absC;
810
+ } else {
811
+ return sign * (1.055 * Math.pow(absC, 1/2.4) - 0.055);
812
+ }
813
+ };
814
+
815
+ const clamp = (value) => {
816
+ return Math.max(0, Math.min(255, value * 255 |0));
817
+ };
818
+
819
+ try {
820
+ const [X, Y, Z] = labToXyz(L, a, b);
821
+ const [linearR, linearG, linearB] = xyzToLinearP3(X, Y, Z);
822
+
823
+ const r = applyGamma(linearR);
824
+ const g = applyGamma(linearG);
825
+ const bOut = applyGamma(linearB);
826
+
827
+ return {
828
+ r: Math.max(0, Math.min(1, r)),
829
+ g: Math.max(0, Math.min(1, g)),
830
+ b: Math.max(0, Math.min(1, bOut))
831
+ };
832
+ } catch (error) {
833
+ console.warn('P3转换失败:', error);
834
+ const rgb = preciseLabToRGB(L, a, b);
835
+ return {
836
+ r: rgb.r / 255,
837
+ g: rgb.g / 255,
838
+ b: rgb.b / 255
839
+ };
840
+ }
841
+ }
842
+
843
+ /**
844
+ * 生成颜色字符串
845
+ */
846
+ function generateColorString(L, a, b, config, alpha = null) {
847
+ if (!config.enableP3 || !detectP3Support()) {
848
+ const rgb = preciseLabToRGB(L, a, b);
849
+ if (alpha !== null) {
850
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`;
851
+ }
852
+ return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
853
+ } else {
854
+ const p3 = labToP3(L, a, b);
855
+ if (alpha !== null) {
856
+ return `color(display-p3 ${p3.r.toFixed(4)} ${p3.g.toFixed(4)} ${p3.b.toFixed(4)} / ${alpha})`;
857
+ }
858
+ return `color(display-p3 ${p3.r.toFixed(4)} ${p3.g.toFixed(4)} ${p3.b.toFixed(4)})`;
859
+ }
860
+ }
861
+
862
+ /**
863
+ * 处理CSS值
864
+ */
865
+ function processCSSValue(value, config) {
866
+ let result = value;
867
+
868
+ if (config.enableMath) {
869
+ result = processMathFunctions(result, config);
870
+ }
871
+
872
+ if (config.convertLabToRGB || config.convertLchToRGB) {
873
+ result = convertAllLabLchColors(result, config);
874
+ }
875
+
876
+ return result;
877
+ }
878
+
879
+ /**
880
+ * 状态机解析嵌套规则(包含变量提取)
881
+ */
882
+ function parseNestedRules(cssText, config, aliases, macros) {
883
+ const rootRules = [];
884
+ const stack = [];
885
+ const globalVariables = {}; // 存储全局变量
886
+
887
+ let currentRule = null;
888
+ let currentLine = '';
889
+ let inRuleBlock = false;
890
+ let braceDepth = 0;
891
+ let isGlobalScope = true; // 标记是否在全局作用域
892
+
893
+ for (let i = 0, length = cssText.length; i < length; i++) {
894
+ const char = cssText[i];
895
+ const charCode = cssText.charCodeAt(i);
896
+
897
+ if (charCode === 123) { // 123: "{"的码点
898
+ braceDepth++;
899
+
900
+ // 在处理{之前,检查当前行是否有变量定义(仅限全局作用域)
901
+ if (isGlobalScope && currentLine.trim()) {
902
+ const varMatch = currentLine.trim().match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+?);?$/);
903
+ if (varMatch) {
904
+ const [, varName, varValue] = varMatch;
905
+ globalVariables[varName] = processCSSValue(varValue.trim(), config);
906
+ currentLine = '';
907
+ continue;
908
+ }
909
+ }
910
+
911
+ if (!inRuleBlock) {
912
+ // 新规则开始
913
+ currentRule = {
914
+ selector: currentLine.trim(),
915
+ properties: [],
916
+ children: []
917
+ };
918
+ stack.push(currentRule);
919
+ inRuleBlock = true;
920
+ isGlobalScope = false; // 进入选择器块,不再是全局作用域
921
+ } else {
922
+ // 嵌套规则开始,需要先处理当前行的属性
923
+ if (currentLine.trim() && currentLine.includes(':')) {
924
+ const parsed = parseSingleLineCSS(currentLine.trim(), aliases, macros);
925
+ parsed.forEach(obj => {
926
+ const key = Object.keys(obj)[0];
927
+ const value = processCSSValue(obj[key], config);
928
+ if (currentRule) {
929
+ currentRule.properties.push(!value.length ? key : `${key}: ${value}`);
930
+ }
931
+ });
932
+ }
933
+ // 开始嵌套规则
934
+ const nestedRule = {
935
+ selector: currentLine.trim(),
936
+ properties: [],
937
+ children: []
938
+ };
939
+ stack.push(nestedRule);
940
+ currentRule = nestedRule;
941
+ }
942
+ currentLine = '';
943
+ } else if (charCode === 125) { // 125: "}"的码点
944
+ braceDepth--;
945
+
946
+ // 处理当前行的属性(在}之前的属性)
947
+ if (currentLine.trim() && currentLine.includes(':')) {
948
+ const parsed = parseSingleLineCSS(currentLine.trim(), aliases, macros);
949
+ parsed.forEach(obj => {
950
+ const key = Object.keys(obj)[0];
951
+ const value = processCSSValue(obj[key], config);
952
+ if (currentRule) {
953
+ currentRule.properties.push(!value.length ? key : `${key}: ${value}`);
954
+ }
955
+ });
956
+ }
957
+
958
+ // 规则结束
959
+ const finishedRule = stack.pop();
960
+
961
+ if (stack.length === 0) {
962
+ rootRules.push(finishedRule);
963
+ inRuleBlock = false;
964
+ currentRule = null;
965
+ isGlobalScope = true; // 回到全局作用域
966
+ } else {
967
+ const parentRule = stack[stack.length - 1];
968
+ if (!parentRule.children) {
969
+ parentRule.children = [];
970
+ }
971
+ parentRule.children.push(finishedRule);
972
+ currentRule = parentRule;
973
+ }
974
+
975
+ currentLine = '';
976
+
977
+ if (braceDepth === 0) {
978
+ inRuleBlock = false;
979
+ isGlobalScope = true;
980
+ }
981
+ } else if (charCode === 10 || charCode === 59) {
982
+ // 行结束,处理当前行的属性或变量
983
+ if (inRuleBlock && currentLine.trim() && currentLine.includes(':')) {
984
+ const parsed = parseSingleLineCSS(currentLine.trim(), aliases, macros);
985
+ parsed.forEach(obj => {
986
+ const key = Object.keys(obj)[0];
987
+ const value = processCSSValue(obj[key], config);
988
+ if (currentRule) {
989
+ currentRule.properties.push(!value.length ? key : `${key}: ${value}`);
990
+ }
991
+ });
992
+ } else if (isGlobalScope && currentLine.trim()) {
993
+ // 全局作用域中检查变量定义
994
+ const varMatch = currentLine.trim().match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+?);?$/);
995
+ if (varMatch) {
996
+ const [, varName, varValue] = varMatch;
997
+ globalVariables[varName] = processCSSValue(varValue.trim(), config);
998
+ currentLine = '';
999
+ continue;
1000
+ }
1001
+ }
1002
+ currentLine = '';
1003
+ } else {
1004
+ currentLine += char;
1005
+ }
1006
+ }
1007
+
1008
+ // 处理最后一行(可能在全局作用域中的变量)
1009
+ if (isGlobalScope && currentLine.trim()) {
1010
+ const varMatch = currentLine.trim().match(/^\$([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+?);?$/);
1011
+ if (varMatch) {
1012
+ const [, varName, varValue] = varMatch;
1013
+ globalVariables[varName] = processCSSValue(varValue.trim(), config);
1014
+ }
1015
+ } else if (inRuleBlock && currentLine.trim() && currentLine.includes(':')) {
1016
+ const parsed = parseSingleLineCSS(currentLine.trim(), aliases, macros);
1017
+ parsed.forEach(obj => {
1018
+ const key = Object.keys(obj)[0];
1019
+ const value = processCSSValue(obj[key], config);
1020
+ if (currentRule) {
1021
+ currentRule.properties.push(!value.length ? key : `${key}: ${value}`);
1022
+ }
1023
+ });
1024
+ }
1025
+
1026
+ // 如果存在全局变量,创建:root规则并添加到rootRules开头
1027
+ if (Object.keys(globalVariables).length > 0) {
1028
+ const rootVarsRule = {
1029
+ selector: config.rootSelector,
1030
+ properties: [],
1031
+ children: []
1032
+ };
1033
+
1034
+ // 将变量转换为CSS属性
1035
+ Object.entries(globalVariables).forEach(([name, value]) => {
1036
+ rootVarsRule.properties.push(`--${name}: ${value}`);
1037
+ });
1038
+
1039
+ // 添加到rootRules的开头
1040
+ rootRules.unshift(rootVarsRule);
1041
+ }
1042
+
1043
+ return convertRulesToCSS(rootRules, config, '', aliases, macros);
1044
+ }
1045
+
1046
+ /**
1047
+ * 将规则树转换为CSS
1048
+ */
1049
+ function convertRulesToCSS(rules, config, parentSelector = '', aliases, macros, isRootAt = false) {
1050
+ let result = '';
1051
+
1052
+ for (const rule of rules) {
1053
+ const isAt = rule.selector.startsWith("@");
1054
+
1055
+ if (isAt) {
1056
+ result += rule.selector + " {\n";
1057
+ }
1058
+
1059
+ let fullSelector = rule.selector;
1060
+
1061
+ if (parentSelector) {
1062
+ if (fullSelector.includes('&')) {
1063
+ fullSelector = fullSelector.replace(REGEX.AND, parentSelector);
1064
+ } else if (fullSelector.trim().startsWith(':')) {
1065
+ fullSelector = parentSelector + fullSelector;
1066
+ } else {
1067
+ fullSelector = parentSelector + " " + fullSelector;
1068
+ }
1069
+ }
1070
+
1071
+ fullSelector = fullSelector;
1072
+
1073
+ if (rule.properties.length > 0) {
1074
+ result += (isRootAt ? " ".repeat(config.indentSize) : '') + fullSelector + ' {\n';
1075
+ for (const prop of rule.properties) {
1076
+ const parsed = parseSingleLineCSS(prop, aliases, macros);
1077
+ parsed.forEach(obj => {
1078
+ const key = Object.keys(obj)[0];
1079
+ const value = processCSSValue(obj[key], config);
1080
+ result += (isRootAt ? " ".repeat(config.indentSize) : '') + " ".repeat(config.indentSize) + (!value.length ? key : `${key}: ${value};\n`);
1081
+ });
1082
+ }
1083
+ result += isRootAt ? " ".repeat(config.indentSize) + '}\n' : '}\n\n';
1084
+ }
1085
+
1086
+ if (rule.children && rule.children.length > 0) {
1087
+ result += convertRulesToCSS(rule.children, config, (isAt ? "" : fullSelector), aliases, macros, isRootAt || isAt);
1088
+ }
1089
+
1090
+ if (isAt) {
1091
+ result += "}\n\n";
1092
+ }
1093
+ }
1094
+
1095
+ return result;
1096
+ }
1097
+
1098
+ /**
1099
+ * 替换变量使用
1100
+ */
1101
+ function replaceVariableUses(cssText, config) {
1102
+ let result = cssText;
1103
+ result = result.replace(REGEX.VARIABLE, (match, varName) => {
1104
+ return match.startsWith('$$') ? `attr(${varName})` : `var(--${varName})`;
1105
+ });
1106
+
1107
+ result = processCSSValue(result, config);
1108
+
1109
+ return result;
1110
+ }
1111
+
1112
+ /**
1113
+ * 处理 @import 语句
1114
+ */
1115
+ async function processImports(cssText, config) {
1116
+ const importRegex = REGEX.IMPORT;
1117
+
1118
+ const processRecursive = async (text) => {
1119
+ const importPromises = [];
1120
+
1121
+ const processedText = text.replace(importRegex, (match, url) => {
1122
+ const importPromise = fetchImportContent(url, config)
1123
+ .then(importedCSS => {
1124
+ return processImports(importedCSS, config);
1125
+ })
1126
+ .catch(error => {
1127
+ console.warn(`无法导入CSS文件: ${url}`, error);
1128
+ return '';
1129
+ });
1130
+
1131
+ importPromises.push(importPromise);
1132
+
1133
+ return `__IMPORT_PLACEHOLDER_${importPromises.length - 1}__`;
1134
+ });
1135
+
1136
+ if (importPromises.length > 0) {
1137
+ const importedContents = await Promise.all(importPromises);
1138
+
1139
+ let finalText = processedText;
1140
+ for (let i = importedContents.length; i--;) {
1141
+ finalText = finalText.replace(`__IMPORT_PLACEHOLDER_${i}__`, importedContents[i]);
1142
+ }
1143
+
1144
+ return finalText;
1145
+ }
1146
+
1147
+ return processedText;
1148
+ };
1149
+
1150
+ return processRecursive(cssText);
1151
+ }
1152
+
1153
+ /**
1154
+ * 获取导入的CSS内容
1155
+ */
1156
+ async function fetchImportContent(url, config) {
1157
+ if (config.importCache && importCache.has(url)) {
1158
+ return importCache.get(url);
1159
+ }
1160
+
1161
+ const fullUrl = config.importBaseUrl
1162
+ ? new URL(url, config.importBaseUrl).href
1163
+ : url;
1164
+
1165
+ let content;
1166
+
1167
+ const isNode = typeof process !== 'undefined' &&
1168
+ process.versions &&
1169
+ process.versions.node;
1170
+
1171
+ if (isNode && typeof require !== 'undefined') {
1172
+ try {
1173
+ const fs = require('fs');
1174
+ const path = require('path');
1175
+
1176
+ let filePath = fullUrl;
1177
+ if (fullUrl.startsWith('.')) {
1178
+ filePath = path.join(process.cwd(), fullUrl);
1179
+ }
1180
+
1181
+ content = fs.readFileSync(filePath, 'utf-8');
1182
+ } catch (error) {
1183
+ throw new Error(`Node.js文件读取失败: ${fullUrl} - ${error.message}`);
1184
+ }
1185
+ } else {
1186
+ try {
1187
+ const controller = new AbortController();
1188
+ const timeoutId = setTimeout(() => controller.abort(), config.importTimeout);
1189
+
1190
+ const response = await fetch(fullUrl, {
1191
+ signal: controller.signal,
1192
+ headers: {
1193
+ 'Accept': 'text/css'
1194
+ }
1195
+ });
1196
+
1197
+ clearTimeout(timeoutId);
1198
+
1199
+ if (!response.ok) {
1200
+ throw new Error(`HTTP错误: ${response.status} ${response.statusText}`);
1201
+ }
1202
+
1203
+ content = await response.text();
1204
+ } catch (error) {
1205
+ if (error.name === 'AbortError') {
1206
+ throw new Error(`导入超时: ${fullUrl}`);
1207
+ }
1208
+ throw new Error(`无法获取CSS: ${fullUrl} - ${error.message}`);
1209
+ }
1210
+ }
1211
+
1212
+ if (config.importCache) {
1213
+ importCache.set(url, content);
1214
+ }
1215
+
1216
+ return content;
1217
+ }
1218
+
1219
+ /**
1220
+ * 主转换函数
1221
+ */
1222
+ async function convert(cssText, customConfig = {}) {
1223
+ let { config: headerConfig, css: cleanedCSS } = parseConfigHeader(cssText);
1224
+ const finalConfig = { ...defaultConfig, ...customConfig, ...headerConfig };
1225
+ cleanedCSS = await processImports(cleanedCSS, finalConfig);
1226
+
1227
+ let cssWithAliases = cleanedCSS;
1228
+ let aliases = new Map();
1229
+ if (finalConfig.enableAlias) {
1230
+ const { aliases: parsedAliases, css: cssWithoutAliases } = parseAliasStatements(cssWithAliases);
1231
+ aliases = parsedAliases;
1232
+ cssWithAliases = cssWithoutAliases;
1233
+ }
1234
+
1235
+ let cssWithMacros = cssWithAliases;
1236
+ let macros = new Map();
1237
+ if (finalConfig.enableMacros) {
1238
+ const { macros: parsedMacros, css: cssWithoutMacros } = parseMacroStatements(cssWithMacros, finalConfig);
1239
+ macros = parsedMacros;
1240
+ cssWithMacros = cssWithoutMacros;
1241
+
1242
+ for (const [name, macro] of macros) {
1243
+ macroRegistry.set(name, macro);
1244
+ }
1245
+ }
1246
+
1247
+ let processedCSS = cssWithMacros.trim();
1248
+ if (finalConfig.enableNesting && cssWithMacros.includes('{')) {
1249
+ try {
1250
+ processedCSS = parseNestedRules(cssWithMacros, finalConfig, aliases, macros);
1251
+ } catch (error) {
1252
+ console.warn('嵌套解析失败,使用原始CSS:', error);
1253
+ }
1254
+ }
1255
+
1256
+ let finalCSS = processedCSS;
1257
+
1258
+ finalCSS = replaceVariableUses(finalCSS, finalConfig);
1259
+
1260
+ for (const [name, plugin] of pluginMap) {
1261
+ try {
1262
+ finalCSS = plugin.convert(finalCSS, finalConfig);
1263
+ } catch (error) {
1264
+ console.error('插件处理失败:', error);
1265
+ }
1266
+ }
1267
+
1268
+ return finalCSS;
1269
+ }
1270
+
1271
+ /**
1272
+ * 自动处理带有特定属性的 style 标签
1273
+ */
1274
+ function autoProcessStyleTags(customConfig = {}) {
1275
+ const config = { ...defaultConfig, ...customConfig };
1276
+ const styleTags = document.querySelectorAll(`style[${config.styleTagAttribute || 'e'}]`);
1277
+
1278
+ styleTags.forEach(styleTag => {
1279
+ let originalCSS = styleTag.textContent;
1280
+
1281
+ const processStyleTag = async () => {
1282
+ try {
1283
+ if (styleTag.getAttribute("src")){
1284
+ originalCSS = "@import "+styleTag.getAttribute("src")+";";
1285
+ }
1286
+ const convertedCSS = await convert(originalCSS, config);
1287
+
1288
+ const newStyleTag = document.createElement('style');
1289
+ newStyleTag.textContent = convertedCSS;
1290
+
1291
+ styleTag.parentNode.insertBefore(newStyleTag, styleTag.nextSibling);
1292
+
1293
+ if (!config.preserveOriginal) {
1294
+ styleTag.remove();
1295
+ } else {
1296
+ styleTag.style.display = 'none';
1297
+ }
1298
+ } catch (error) {
1299
+ console.error('处理style标签失败:', error);
1300
+ }
1301
+ };
1302
+
1303
+ processStyleTag();
1304
+ });
1305
+
1306
+ return styleTags.length;
1307
+ }
1308
+
1309
+ function config(config = {}) {
1310
+ defaultConfig = { ...defaultConfig, ...config };
1311
+ }
1312
+
1313
+ /**
1314
+ * 应用CSS到页面
1315
+ */
1316
+ function apply(cssText, customConfig = {}) {
1317
+ const config = { ...defaultConfig, ...customConfig };
1318
+
1319
+ if (cssText) {
1320
+ return (async () => {
1321
+ try {
1322
+ const converted = await convert(cssText, config);
1323
+ const styleEl = document.createElement('style');
1324
+ styleEl.textContent = converted;
1325
+ document.head.appendChild(styleEl);
1326
+ return styleEl;
1327
+ } catch (error) {
1328
+ console.error('应用CSS失败:', error);
1329
+ return null;
1330
+ }
1331
+ })();
1332
+ } else {
1333
+ if (document.readyState === 'loading') {
1334
+ document.addEventListener('DOMContentLoaded', () => {
1335
+ autoProcessStyleTags(config);
1336
+ });
1337
+ } else {
1338
+ autoProcessStyleTags(config);
1339
+ }
1340
+ }
1341
+ }
1342
+
1343
+ // 创建公共 API
1344
+ const api = {
1345
+ convert,
1346
+ apply,
1347
+ config,
1348
+
1349
+ supportsP3: detectP3Support(),
1350
+
1351
+ detectP3Support: detectP3Support,
1352
+
1353
+ imports: {
1354
+ clearCache: function() {
1355
+ importCache.clear();
1356
+ },
1357
+ setBaseUrl: function(baseUrl) {
1358
+ defaultConfig.importBaseUrl = baseUrl;
1359
+ },
1360
+ setCacheEnabled: function(enabled) {
1361
+ defaultConfig.importCache = enabled;
1362
+ },
1363
+ setTimeout: function(timeout) {
1364
+ defaultConfig.importTimeout = timeout;
1365
+ }
1366
+ },
1367
+
1368
+ plugins: {
1369
+ use(plugin) {
1370
+ const pluginObj = new plugin();
1371
+ pluginMap.set(pluginObj.name ?? plugin.name, pluginObj);
1372
+ return true;
1373
+ },
1374
+ remove(name) {
1375
+ if (pluginMap.get(name)?.destroy) {
1376
+ pluginMap.get(name).destroy();
1377
+ }
1378
+ pluginMap.delete(name);
1379
+ return true;
1380
+ },
1381
+ getAll: function() {
1382
+ return Array.from(pluginMap.entries());
1383
+ },
1384
+ clear: function() {
1385
+ pluginMap.clear();
1386
+ }
1387
+ },
1388
+
1389
+ aliases: {
1390
+ add: function(alias, property) {
1391
+ aliasMap.set(alias, property);
1392
+ },
1393
+ remove: function(alias) {
1394
+ aliasMap.delete(alias);
1395
+ },
1396
+ getAll: function() {
1397
+ return Array.from(aliasMap.entries());
1398
+ },
1399
+ clear: function() {
1400
+ aliasMap.clear();
1401
+ }
1402
+ },
1403
+
1404
+ macros: {
1405
+ define: function(name, body, params = []) {
1406
+ if (typeof body === 'function') {
1407
+ const funcString = body.toString();
1408
+ const bodyMatch = funcString.match(/{([\s\S]*)}/);
1409
+ if (bodyMatch) {
1410
+ macroRegistry.set(name, {
1411
+ params: params.map(p => typeof p === 'string' ? { name: p } : p),
1412
+ body: bodyMatch[1].trim()
1413
+ });
1414
+ }
1415
+ } else {
1416
+ macroRegistry.set(name, {
1417
+ params: params.map(p => typeof p === 'string' ? { name: p } : p),
1418
+ body: body
1419
+ });
1420
+ }
1421
+ },
1422
+
1423
+ call: function(name, ...args) {
1424
+ const macro = macroRegistry.get(name);
1425
+ if (!macro) {
1426
+ throw new Error(`未定义的宏: ${name}`);
1427
+ }
1428
+
1429
+ const argsMap = new Map();
1430
+ for (let i = 0, length = macro.params.length; i < length; i++) {
1431
+ const param = macro.params[i];
1432
+ const value = i < args.length ? args[i] : param.defaultValue;
1433
+ if (value === undefined && param.defaultValue === null) {
1434
+ throw new Error(`缺少必需参数: ${param.name}`);
1435
+ }
1436
+ argsMap.set(param.name, value !== undefined ? value : '');
1437
+ }
1438
+
1439
+ return applyMacro(macro.body, argsMap, defaultConfig);
1440
+ },
1441
+
1442
+ getAll: function() {
1443
+ return Array.from(macroRegistry.entries());
1444
+ },
1445
+
1446
+ remove: function(name) {
1447
+ macroRegistry.delete(name);
1448
+ },
1449
+
1450
+ clear: function() {
1451
+ macroRegistry.clear();
1452
+ },
1453
+
1454
+ parse: function(cssText) {
1455
+ const { macros } = parseMacroStatements(cssText, defaultConfig);
1456
+ for (const [name, macro] of macros) {
1457
+ macroRegistry.set(name, macro);
1458
+ }
1459
+ }
1460
+ },
1461
+
1462
+ math: {
1463
+ evaluate: function(expression) {
1464
+ return evaluateMathExpression(expression, defaultConfig);
1465
+ }
1466
+ },
1467
+
1468
+ colorUtils: {
1469
+ labToRGB: preciseLabToRGB,
1470
+ lchToLab: lchToLab,
1471
+ lchToRGB: function(L, C, H) {
1472
+ const lab = lchToLab(L, C, H);
1473
+ return preciseLabToRGB(lab.L, lab.a, lab.b);
1474
+ },
1475
+ labToP3: labToP3,
1476
+ lchToP3: function(L, C, H) {
1477
+ const lab = lchToLab(L, C, H);
1478
+ return labToP3(lab.L, lab.a, lab.b);
1479
+ },
1480
+ parseHexLab: function(hexString) {
1481
+ const match = hexString.match(/lab#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i);
1482
+ if (!match) return null;
1483
+
1484
+ const L_hex = match[1];
1485
+ const A_hex = match[2];
1486
+ const B_hex = match[3];
1487
+
1488
+ const L = parseInt(L_hex, 16) / 255 * 100;
1489
+ const A = (parseInt(A_hex, 16) - 128) * 1.5;
1490
+ const B = (parseInt(B_hex, 16) - 128) * 1.5;
1491
+
1492
+ return preciseLabToRGB(L, A, B);
1493
+ },
1494
+ parseHexLch: function(hexString) {
1495
+ const match = hexString.match(/lch#([0-9a-f]{2})([0-9a-f]{2})(\d{1,3})/i);
1496
+ if (!match) return null;
1497
+
1498
+ const L_hex = match[1];
1499
+ const C_hex = match[2];
1500
+ const H_dec = match[3];
1501
+
1502
+ const L = parseInt(L_hex, 16) / 255 * 100;
1503
+ const C = parseInt(C_hex, 16) / 255 * 150;
1504
+ const H = parseInt(H_dec) / 100 * 360;
1505
+
1506
+ const lab = lchToLab(L, C, H);
1507
+ return preciseLabToRGB(lab.L, lab.a, lab.b);
1508
+ },
1509
+ generateColor: function(L, a, b, alpha = null, useP3 = true) {
1510
+ return generateColorString(L, a, b, { enableP3: useP3 }, alpha);
1511
+ },
1512
+ parseColor: function(colorString) {
1513
+ try {
1514
+ const labMatch = colorString.match(/lab\(\s*([\d.]+)(%?)\s+([\d.-]+)\s+([\d.-]+)(?:\s*\/\s*([\d.%]+))?\s*\)/i);
1515
+ if (labMatch) {
1516
+ let L = parseFloat(labMatch[1]);
1517
+ const A = parseFloat(labMatch[3]);
1518
+ const B = parseFloat(labMatch[4]);
1519
+ const alpha = labMatch[5] ?
1520
+ (labMatch[5].includes('%') ? parseFloat(labMatch[5]) / 100 : parseFloat(labMatch[5])) :
1521
+ null;
1522
+
1523
+ const colorStr = generateColorString(L, A, B, defaultConfig, alpha);
1524
+
1525
+ return {
1526
+ L, A, B, alpha,
1527
+ rgb: preciseLabToRGB(L, A, B),
1528
+ p3: labToP3(L, A, B),
1529
+ colorString: colorStr
1530
+ };
1531
+ }
1532
+
1533
+ const lchMatch = colorString.match(/lch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)(deg)?(?:\s*\/\s*([\d.%]+))?\s*\)/i);
1534
+ if (lchMatch) {
1535
+ let L = parseFloat(lchMatch[1]);
1536
+ const C = parseFloat(lchMatch[3]);
1537
+ let H = parseFloat(lchMatch[4]);
1538
+ const alpha = lchMatch[6] ?
1539
+ (lchMatch[6].includes('%') ? parseFloat(lchMatch[6]) / 100 : parseFloat(lchMatch[6])) :
1540
+ null;
1541
+
1542
+ const lab = lchToLab(L, C, H);
1543
+ const colorStr = generateColorString(lab.L, lab.a, lab.b, defaultConfig, alpha);
1544
+
1545
+ return {
1546
+ L, C, H, alpha,
1547
+ lab: lab,
1548
+ rgb: preciseLabToRGB(lab.L, lab.a, lab.b),
1549
+ p3: labToP3(lab.L, lab.a, lab.b),
1550
+ colorString: colorStr
1551
+ };
1552
+ }
1553
+
1554
+ return null;
1555
+ } catch (error) {
1556
+ console.warn('无法解析颜色:', colorString, error);
1557
+ return null;
1558
+ }
1559
+ }
1560
+ }
1561
+ };
1562
+
1563
+ // 创建主函数
1564
+ const styimat = async function(...args) {
1565
+ if (args.length > 1 || (args[0] && args[0].raw)) {
1566
+ return await handleTemplateTag(...args);
1567
+ }
1568
+
1569
+ const firstArg = args[0];
1570
+
1571
+ if (typeof firstArg === 'string') {
1572
+ const result = await convert(firstArg, args[1]);
1573
+
1574
+ if (result && typeof result.then === 'function') {
1575
+ return result;
1576
+ }
1577
+ return result;
1578
+ }
1579
+
1580
+ if (typeof firstArg === 'object' && firstArg !== null) {
1581
+ defaultConfig = { ...defaultConfig, ...firstArg };
1582
+ return styimat;
1583
+ }
1584
+
1585
+ if (args.length === 0) {
1586
+ return apply();
1587
+ }
1588
+
1589
+ return styimat;
1590
+ };
1591
+
1592
+ async function handleTemplateTag(strings, ...values) {
1593
+ let cssText = strings[0];
1594
+
1595
+ for (let i = 0, length = values.length; i < length; i++) {
1596
+ const value = values[i];
1597
+ let result = '';
1598
+
1599
+ if (typeof value === 'function') {
1600
+ result = value();
1601
+ } else if (Array.isArray(value)) {
1602
+ result = value.join(' ');
1603
+ } else {
1604
+ result = String(value != null ? value : 'none');
1605
+ }
1606
+
1607
+ cssText += result + strings[i + 1];
1608
+ }
1609
+
1610
+ const result = await convert(cssText, defaultConfig);
1611
+
1612
+ if (result && typeof result.then === 'function') {
1613
+ return result;
1614
+ }
1615
+ return result;
1616
+ }
1617
+
1618
+ Object.assign(styimat, api);
1619
+
1620
+ // 自动初始化
1621
+ if (typeof window !== 'undefined') {
1622
+ apply();
1623
+ Object.defineProperty(window.HTMLElement.prototype, 'cssVar', {
1624
+ get() {
1625
+ const element = this;
1626
+ return new Proxy(() => {}, {
1627
+ get(target, prop) {
1628
+ const varName = prop.startsWith('--') ? prop : `--${prop}`;
1629
+ return element.style.getPropertyValue(varName);
1630
+ },
1631
+
1632
+ set(target, prop, value) {
1633
+ const varName = prop.startsWith('--') ? prop : `--${prop}`;
1634
+ element.style.setProperty(varName, value);
1635
+ return true;
1636
+ },
1637
+
1638
+ apply(target, thisArg, argumentsList) {
1639
+ const prop = argumentsList[0];
1640
+ const value = argumentsList[1];
1641
+ const varName = prop.startsWith('--') ? prop : `--${prop}`;
1642
+ if (value === undefined) return element.style.getPropertyValue(varName);
1643
+ element.style.setProperty(varName, value);
1644
+ }
1645
+ });
1646
+ }
1647
+ });
1648
+ }
1649
+
1650
+ return styimat;
1651
+ })();
1652
+
1653
+ define([], _=>styimat);