styimat 4.2.1 → 5.0.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.
package/dist/styimat.js CHANGED
@@ -29,12 +29,11 @@ const styimat = (function() {
29
29
  convertLchToRGB: true,
30
30
  enableP3: true,
31
31
  enableMath: true,
32
- mathPrecision: 6,
33
32
  importBaseUrl: '',
34
33
  importCache: true,
35
34
  importTimeout: 5000,
36
35
  enableAlias: true,
37
- enableMacros: true,
36
+ enableMacros: true
38
37
  };
39
38
 
40
39
  // 全局P3支持检测结果
@@ -49,6 +48,8 @@ const styimat = (function() {
49
48
  // 宏定义存储
50
49
  const macroRegistry = new Map();
51
50
 
51
+ const pluginMap = new Map();
52
+
52
53
  /**
53
54
  * 解析配置头
54
55
  */
@@ -386,7 +387,7 @@ const styimat = (function() {
386
387
  /**
387
388
  * 解析一行CSS
388
389
  */
389
- function parseSingleLineCSS(cssString, aliases=[]) {
390
+ function parseSingleLineCSS(cssString, aliases, macros) {
390
391
  let str = cssString.trim();
391
392
 
392
393
  if (str.endsWith(';')) {
@@ -459,6 +460,13 @@ const styimat = (function() {
459
460
  property = aliases.get(property);
460
461
  }
461
462
 
463
+ if (property.startsWith("@") && macros.get(property.slice(1))) {
464
+ const macro = macros.get(property.slice(1));
465
+ const args = parseMacroArguments(value.split(" ").join(","), macro.params);
466
+ property = applyMacro(macro.body, args, config);
467
+ value = "";
468
+ }
469
+
462
470
  result.push({ [property]: value });
463
471
  }
464
472
 
@@ -501,71 +509,23 @@ const styimat = (function() {
501
509
 
502
510
  try {
503
511
  let cleanExpr = expression.replace(/\s+/g, '');
504
- const result = parseMathExpression(cleanExpr, config);
505
512
 
506
- if (hasUnits(cleanExpr)) {
507
- return processUnitExpression(cleanExpr, result);
508
- } else {
509
- return roundNumber(result, config.mathPrecision);
510
- }
513
+ return parseMathExpression(cleanExpr, config.enableMath);
511
514
  } catch (error) {
512
515
  console.warn('math()表达式解析失败:', expression, error);
513
- return `math(${expression})`;
516
+ return `calc(${expression})`;
514
517
  }
515
518
  }
516
519
 
517
520
  /**
518
521
  * 解析数学表达式
519
522
  */
520
- function parseMathExpression(expr, config) {
521
- while (expr.includes('(') && expr.includes(')')) {
522
- const start = expr.lastIndexOf('(');
523
- const end = expr.indexOf(')', start);
524
-
525
- if (end === -1) break;
526
-
527
- const inner = expr.substring(start + 1, end);
528
- const innerResult = parseMathExpression(inner, config);
529
-
530
- expr = expr.substring(0, start) + innerResult + expr.substring(end + 1);
531
- }
532
-
533
- return evaluateSimpleExpression(expr, config);
534
- }
535
-
536
- /**
537
- * 评估简单表达式(无括号)
538
- */
539
- function evaluateSimpleExpression(expr, config) {
540
- const operators = [
541
- { regex: /([\d.]+(?:[a-zA-Z%]+)?)\*([\d.]+(?:[a-zA-Z%]+)?)/, handler: multiply },
542
- { regex: /([\d.]+(?:[a-zA-Z%]+)?)\/([\d.]+(?:[a-zA-Z%]+)?)/, handler: divide },
543
- { regex: /([\d.]+(?:[a-zA-Z%]+)?)\+([\d.]+(?:[a-zA-Z%]+)?)/, handler: add },
544
- { regex: /([\d.]+(?:[a-zA-Z%]+)?)-([\d.]+(?:[a-zA-Z%]+)?)/, handler: subtract }
545
- ];
546
-
547
- let lastExpr = expr;
548
-
549
- for (const op of operators) {
550
- let match;
551
- while ((match = expr.match(op.regex)) !== null) {
552
- const left = parseValueWithUnit(match[1]);
553
- const right = parseValueWithUnit(match[2]);
554
- const result = op.handler(left, right);
555
-
556
- expr = expr.substring(0, match.index) +
557
- result.value +
558
- expr.substring(match.index + match[0].length);
559
- }
560
- }
561
-
562
- if (expr !== lastExpr) {
563
- return evaluateSimpleExpression(expr, config);
564
- }
565
-
566
- const parsed = parseValueWithUnit(expr);
567
- return parsed.value;
523
+ function parseMathExpression(expr, enableMath) {
524
+ return `calc(${expr
525
+ .replace(/([\da-z])([+-])(-?[\da-z])/g, '$1 $2 $3')
526
+ .replace(/([\da-z])([+-])(-?[\da-z])/g, '$1 $2 $3')})`;
568
527
  }
528
+
569
529
 
570
530
  /**
571
531
  * 解析带单位的数值
@@ -583,30 +543,6 @@ const styimat = (function() {
583
543
  return { value, unit };
584
544
  }
585
545
 
586
- /**
587
- * 检查表达式是否包含单位
588
- */
589
- function hasUnits(expr) {
590
- return /[a-zA-Z%]/.test(expr);
591
- }
592
-
593
- /**
594
- * 处理带单位的表达式
595
- */
596
- function processUnitExpression(originalExpr, result) {
597
- const unitMatch = originalExpr.match(/([a-zA-Z%]+)(?!.*[a-zA-Z%])/);
598
-
599
- if (unitMatch) {
600
- return result + unitMatch[1];
601
- }
602
-
603
- if (originalExpr.includes('%')) {
604
- return result + '%';
605
- }
606
-
607
- return result + 'px';
608
- }
609
-
610
546
  // 数学运算函数
611
547
  function multiply(a, b) {
612
548
  if (a.unit === b.unit || (!a.unit && !b.unit)) {
@@ -673,6 +609,7 @@ const styimat = (function() {
673
609
 
674
610
  const processMath = (str) => {
675
611
  return str.replace(mathRegex, (match, expression) => {
612
+
676
613
  return evaluateMathExpression(expression, config);
677
614
  });
678
615
  };
@@ -1143,7 +1080,7 @@ const styimat = (function() {
1143
1080
  /**
1144
1081
  * 解析嵌套规则
1145
1082
  */
1146
- function parseNestedRules(cssText, config, aliases) {
1083
+ function parseNestedRules(cssText, config, aliases, macros) {
1147
1084
  const lines = cssText.split('\n');
1148
1085
  const stack = [];
1149
1086
  const rootRules = [];
@@ -1188,11 +1125,12 @@ const styimat = (function() {
1188
1125
  if (!trimmed.includes('{') && !trimmed.includes('}') && trimmed.includes(':')) {
1189
1126
  if (stack.length > 0) {
1190
1127
  const currentRule = stack[stack.length - 1];
1191
- const parsed = parseSingleLineCSS(trimmed, aliases);
1128
+ const parsed = parseSingleLineCSS(trimmed, aliases, macros);
1192
1129
  parsed.forEach(obj => {
1193
1130
  const key = Object.keys(obj)[0];
1194
1131
  const value = processCSSValue(obj[key], config);
1195
- currentRule.properties.push(`${key}: ${value}`);
1132
+
1133
+ currentRule.properties.push(value === "" ? key : `${key}: ${value}`);
1196
1134
  });
1197
1135
  }
1198
1136
  continue;
@@ -1210,13 +1148,13 @@ const styimat = (function() {
1210
1148
  }
1211
1149
  }
1212
1150
 
1213
- return convertRulesToCSS(rootRules, config, '', aliases);
1151
+ return convertRulesToCSS(rootRules, config, '', aliases, macros);
1214
1152
  }
1215
1153
 
1216
1154
  /**
1217
1155
  * 将规则树转换为CSS字符串
1218
1156
  */
1219
- function convertRulesToCSS(rules, config, parentSelector = '', aliases=[]) {
1157
+ function convertRulesToCSS(rules, config, parentSelector = '', aliases, macros) {
1220
1158
  let result = '';
1221
1159
  const isParentAt = parentSelector.startsWith("@");
1222
1160
 
@@ -1241,18 +1179,18 @@ const styimat = (function() {
1241
1179
  if (rule.properties.length > 0) {
1242
1180
  result += (isAt ? "" : fullSelector) + ' {\n';
1243
1181
  for (const prop of rule.properties) {
1244
- const parsed = parseSingleLineCSS(prop, aliases);
1182
+ const parsed = parseSingleLineCSS(prop, aliases, macros);
1245
1183
  parsed.forEach(obj => {
1246
1184
  const key = Object.keys(obj)[0];
1247
1185
  const value = processCSSValue(obj[key], config);
1248
- result += (isParentAt ? " ".repeat(config.indentSize) : '') + " ".repeat(config.indentSize) +`${key}: ${value};\n`;
1186
+ result += (isParentAt ? " ".repeat(config.indentSize) : '') + " ".repeat(config.indentSize) + (value === "" ? key : `${key}: ${value};\n`);
1249
1187
  });
1250
1188
  }
1251
1189
  result += isParentAt ? " ".repeat(config.indentSize) + '}\n' : '}\n\n';
1252
1190
  }
1253
1191
 
1254
1192
  if (rule.children && rule.children.length > 0) {
1255
- result += convertRulesToCSS(rule.children, config, fullSelector, aliases);
1193
+ result += convertRulesToCSS(rule.children, config, fullSelector, aliases, macros);
1256
1194
  }
1257
1195
 
1258
1196
  if (isParentAt){
@@ -1327,13 +1265,6 @@ const styimat = (function() {
1327
1265
  }
1328
1266
 
1329
1267
  if (trimmed === '}' && currentSelector) {
1330
- if (selectorVariables.has(currentSelector)) {
1331
- const vars = selectorVariables.get(currentSelector);
1332
- const indent = line.match(/^(\s*)/)[0];
1333
- for (const [varName, varValue] of Object.entries(vars)) {
1334
- result += ' --' + varName + ': ' + varValue + ';\n';
1335
- }
1336
- }
1337
1268
  currentSelector = null;
1338
1269
  }
1339
1270
 
@@ -1453,76 +1384,68 @@ const styimat = (function() {
1453
1384
  /**
1454
1385
  * 主转换函数
1455
1386
  */
1456
- function convert(cssText, customConfig = {}) {
1457
- const syncConvert = (cssText, config) => {
1458
- const { config: headerConfig, css: cleanedCSS } = parseConfigHeader(cssText);
1459
- const finalConfig = { ...defaultConfig, ...customConfig,...headerConfig };
1460
-
1461
- let cssWithAliases = cleanedCSS;
1462
- let aliases = new Map();
1463
- if (finalConfig.enableAlias) {
1464
- const { aliases: parsedAliases, css: cssWithoutAliases } = parseAliasStatements(cssWithAliases);
1465
- aliases = parsedAliases;
1466
- cssWithAliases = cssWithoutAliases;
1467
- }
1387
+ async function convert(cssText, customConfig = {}) {
1388
+ let { config: headerConfig, css: cleanedCSS } = parseConfigHeader(cssText);
1389
+ const finalConfig = { ...defaultConfig, ...customConfig, ...headerConfig };
1390
+ cleanedCSS = await processImports(cleanedCSS, finalConfig);
1391
+
1392
+ let cssWithAliases = cleanedCSS;
1393
+ let aliases = new Map();
1394
+ if (finalConfig.enableAlias) {
1395
+ const { aliases: parsedAliases, css: cssWithoutAliases } = parseAliasStatements(cssWithAliases);
1396
+ aliases = parsedAliases;
1397
+ cssWithAliases = cssWithoutAliases;
1398
+ }
1468
1399
 
1469
- let cssWithMacros = cssWithAliases;
1470
- let macros = new Map();
1471
- if (finalConfig.enableMacros) {
1472
- const { macros: parsedMacros, css: cssWithoutMacros } = parseMacroStatements(cssWithMacros, finalConfig);
1473
- macros = parsedMacros;
1474
- cssWithMacros = cssWithoutMacros;
1400
+ let cssWithMacros = cssWithAliases;
1401
+ let macros = new Map();
1402
+ if (finalConfig.enableMacros) {
1403
+ const { macros: parsedMacros, css: cssWithoutMacros } = parseMacroStatements(cssWithMacros, finalConfig);
1404
+ macros = parsedMacros;
1405
+ cssWithMacros = cssWithoutMacros;
1475
1406
 
1476
- for (const [name, macro] of macros) {
1477
- macroRegistry.set(name, macro);
1478
- }
1407
+ for (const [name, macro] of macros) {
1408
+ macroRegistry.set(name, macro);
1479
1409
  }
1410
+ }
1411
+
1412
+ let cssAfterMacros = cssWithMacros;
1413
+ if (finalConfig.enableMacros && macros.size > 0) {
1414
+ cssAfterMacros = applyMacroCalls(cssAfterMacros, macros, finalConfig);
1415
+ }
1416
+
1417
+ const { globalVariables, selectorVariables, cssWithoutVars } =
1418
+ extractVariablesAndCSS(cssAfterMacros, finalConfig);
1480
1419
 
1481
- let cssAfterMacros = cssWithMacros;
1482
- if (finalConfig.enableMacros && macros.size > 0) {
1483
- cssAfterMacros = applyMacroCalls(cssAfterMacros, macros, finalConfig);
1484
- }
1485
-
1486
- const { globalVariables, selectorVariables, cssWithoutVars } =
1487
- extractVariablesAndCSS(cssAfterMacros, finalConfig);
1488
-
1489
- let processedCSS = cssWithoutVars.trim();
1490
- if (finalConfig.enableNesting && cssWithoutVars.includes('{')) {
1491
- try {
1492
- processedCSS = parseNestedRules(cssWithoutVars, finalConfig, aliases);
1493
- } catch (error) {
1494
- console.warn('嵌套解析失败,使用原始CSS:', error);
1495
- }
1420
+ let processedCSS = cssWithoutVars.trim();
1421
+ if (finalConfig.enableNesting && cssWithoutVars.includes('{')) {
1422
+ try {
1423
+ processedCSS = parseNestedRules(cssWithoutVars, finalConfig, aliases, macros);
1424
+ } catch (error) {
1425
+ console.warn('嵌套解析失败,使用原始CSS:', error);
1496
1426
  }
1427
+ }
1428
+
1429
+ const rootRule = generateRootRule(globalVariables, finalConfig);
1430
+
1431
+ let finalCSS = processedCSS;
1432
+ if (selectorVariables.size > 0) {
1433
+ finalCSS = injectSelectorVariables(processedCSS, selectorVariables, finalConfig);
1434
+ }
1435
+
1436
+ finalCSS = replaceVariableUses(finalCSS, globalVariables, selectorVariables, finalConfig);
1497
1437
 
1498
- const rootRule = generateRootRule(globalVariables, finalConfig);
1499
-
1500
- let finalCSS = processedCSS;
1501
- if (selectorVariables.size > 0) {
1502
- finalCSS = injectSelectorVariables(processedCSS, selectorVariables, finalConfig);
1438
+ for (const [name, plugin] of pluginMap) {
1439
+ try {
1440
+ if(plugin.enable) finalCSS = plugin.convert(finalCSS, finalConfig);
1441
+ } catch (error) {
1442
+ console.error('插件处理失败:', error);
1503
1443
  }
1444
+ }
1504
1445
 
1505
- finalCSS = replaceVariableUses(finalCSS, globalVariables, selectorVariables, finalConfig);
1506
-
1507
- return rootRule + finalCSS;
1508
- };
1509
-
1510
- const hasImports = cssText && /@import\s+([^;]+?)\s*;/g.test(cssText);
1511
- const finalConfig = { ...defaultConfig, ...customConfig };
1446
+ let fullCSS = rootRule + finalCSS;
1512
1447
 
1513
- if (!hasImports) {
1514
- return syncConvert(cssText, finalConfig);
1515
- } else {
1516
- return (async () => {
1517
- try {
1518
- const processedWithImports = await processImports(cssText, finalConfig);
1519
- return syncConvert(processedWithImports, finalConfig);
1520
- } catch (error) {
1521
- console.error('@import处理失败:', error);
1522
- return syncConvert(cssText, finalConfig);
1523
- }
1524
- })();
1525
- }
1448
+ return fullCSS;
1526
1449
  }
1527
1450
 
1528
1451
  /**
@@ -1574,28 +1497,18 @@ const styimat = (function() {
1574
1497
  const config = { ...defaultConfig, ...customConfig };
1575
1498
 
1576
1499
  if (cssText) {
1577
- const hasImports = /@import\s+([^;]+?)\s*;/g.test(cssText);
1578
-
1579
- if (hasImports) {
1580
- return (async () => {
1581
- try {
1582
- const converted = await convert(cssText, config);
1583
- const styleEl = document.createElement('style');
1584
- styleEl.textContent = converted;
1585
- document.head.appendChild(styleEl);
1586
- return styleEl;
1587
- } catch (error) {
1588
- console.error('应用CSS失败:', error);
1589
- return null;
1590
- }
1591
- })();
1592
- } else {
1593
- const converted = convert(cssText, config);
1594
- const styleEl = document.createElement('style');
1595
- styleEl.textContent = converted;
1596
- document.head.appendChild(styleEl);
1597
- return styleEl;
1598
- }
1500
+ return (async () => {
1501
+ try {
1502
+ const converted = await convert(cssText, config);
1503
+ const styleEl = document.createElement('style');
1504
+ styleEl.textContent = converted;
1505
+ document.head.appendChild(styleEl);
1506
+ return styleEl;
1507
+ } catch (error) {
1508
+ console.error('应用CSS失败:', error);
1509
+ return null;
1510
+ }
1511
+ })();
1599
1512
  } else {
1600
1513
  if (document.readyState === 'loading') {
1601
1514
  document.addEventListener('DOMContentLoaded', () => {
@@ -1632,6 +1545,40 @@ const styimat = (function() {
1632
1545
  }
1633
1546
  },
1634
1547
 
1548
+ plugins: new Proxy({},{
1549
+ set(target, name, plugin) {
1550
+ const createdFunc = plugin.created ?? (() => {});
1551
+ createdFunc();
1552
+ pluginMap.set(name, plugin);
1553
+ return true;
1554
+ },
1555
+ get(target, name) {
1556
+ return pluginMap.get(name);
1557
+ },
1558
+ deleteProperty(target, name) {
1559
+ pluginMap.get(name)?.deleted();
1560
+ pluginMap.delete(name);
1561
+ return true;
1562
+ },
1563
+ has(terget, name) {
1564
+ return pluginMap.has(name);
1565
+ },
1566
+ ownKeys() {
1567
+ return Array.from(pluginMap.keys());
1568
+ },
1569
+ getOwnPropertyDescriptor(target, prop) {
1570
+ if (pluginMap.has(prop)) {
1571
+ return {
1572
+ enumerable: true,
1573
+ configurable: true,
1574
+ writable: true,
1575
+ value: pluginMap.get(prop)
1576
+ };
1577
+ }
1578
+ return undefined;
1579
+ }
1580
+ }),
1581
+
1635
1582
  aliases: {
1636
1583
  add: function(alias, property) {
1637
1584
  aliasMap.set(alias, property);
@@ -1827,15 +1774,15 @@ const styimat = (function() {
1827
1774
  };
1828
1775
 
1829
1776
  // 创建主函数
1830
- const styimat = function(...args) {
1777
+ const styimat = async function(...args) {
1831
1778
  if (args.length > 1 || (args[0] && args[0].raw)) {
1832
- return handleTemplateTag(...args);
1779
+ return await handleTemplateTag(...args);
1833
1780
  }
1834
1781
 
1835
1782
  const firstArg = args[0];
1836
1783
 
1837
1784
  if (typeof firstArg === 'string') {
1838
- const result = convert(firstArg, { ...defaultConfig, ...args[1] });
1785
+ const result = await convert(firstArg, { ...defaultConfig, ...args[1] });
1839
1786
 
1840
1787
  if (result && typeof result.then === 'function') {
1841
1788
  return result;
@@ -1855,7 +1802,7 @@ const styimat = (function() {
1855
1802
  return styimat;
1856
1803
  };
1857
1804
 
1858
- function handleTemplateTag(strings, ...values) {
1805
+ async function handleTemplateTag(strings, ...values) {
1859
1806
  let cssText = strings[0];
1860
1807
 
1861
1808
  for (let i = 0; i < values.length; i++) {
@@ -1873,7 +1820,7 @@ const styimat = (function() {
1873
1820
  cssText += result + strings[i + 1];
1874
1821
  }
1875
1822
 
1876
- const result = convert(cssText, defaultConfig);
1823
+ const result = await convert(cssText, defaultConfig);
1877
1824
 
1878
1825
  if (result && typeof result.then === 'function') {
1879
1826
  return result;
@@ -1918,7 +1865,7 @@ const styimat = (function() {
1918
1865
  })();
1919
1866
 
1920
1867
  if (typeof define === 'function' && define.amd) {
1921
- define([], ()=>styimat);
1868
+ define([], _=>styimat);
1922
1869
  } else if (typeof module === 'object' && module.exports) {
1923
1870
  module.exports = styimat;
1924
1871
  } else {