fscss 1.1.20 → 1.1.22

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.
@@ -18,26 +18,79 @@ function procCntInit(ntc,stc){
18
18
  })
19
19
  return text;
20
20
  }
21
- function procNum(css){
22
- const regex = /num\((.*?)\)/g;
23
- function evaluateExpression(expression) {
24
- try {
25
- // function instead
26
- return new Function(`return ${expression}`)();
27
- } catch (e) {
28
- console.error('Invalid expression:', expression);
29
- return expression;
21
+ function parseMath(expr) {
22
+ const str = expr.replace(/\s+/g, '');
23
+ let pos = 0;
24
+
25
+ function parseExpr() {
26
+ let left = parseTerm();
27
+ while (pos < str.length && (str[pos] === '+' || str[pos] === '-')) {
28
+ const op = str[pos++];
29
+ const right = parseTerm();
30
+ left = op === '+' ? left + right : left - right;
31
+ }
32
+ return left;
33
+ }
34
+
35
+ function parseTerm() {
36
+ let left = parsePower();
37
+ while (pos < str.length && (str[pos] === '*' || str[pos] === '/')) {
38
+ const op = str[pos++];
39
+ const right = parsePower();
40
+ left = op === '*' ? left * right : left / right;
41
+ }
42
+ return left;
30
43
  }
44
+
45
+ function parsePower() {
46
+ let base = parseUnary();
47
+ if (pos < str.length && str[pos] === '*' && str[pos + 1] === '*') {
48
+ pos += 2;
49
+ const exp = parseUnary(); // right-associative
50
+ return Math.pow(base, exp);
51
+ }
52
+ return base;
53
+ }
54
+
55
+ function parseUnary() {
56
+ if (str[pos] === '-') { pos++; return -parsePrimary(); }
57
+ if (str[pos] === '+') { pos++; return parsePrimary(); }
58
+ return parsePrimary();
59
+ }
60
+
61
+ function parsePrimary() {
62
+ if (str[pos] === '(') {
63
+ pos++; // skip '('
64
+ const val = parseExpr();
65
+ if (str[pos] !== ')') throw new Error('Missing closing )');
66
+ pos++; // skip ')'
67
+ return val;
68
+ }
69
+
70
+ const numMatch = str.slice(pos).match(/^[0-9]*\.?[0-9]+/);
71
+ if (!numMatch) throw new Error(`Unexpected token at pos ${pos}: "${str[pos]}"`);
72
+ pos += numMatch[0].length;
73
+ return parseFloat(numMatch[0]);
74
+ }
75
+
76
+ const result = parseExpr();
77
+ if (pos !== str.length) throw new Error(`Unexpected token: "${str[pos]}"`);
78
+ return result;
31
79
  }
32
80
 
81
+ function procNum(css) {
82
+ const regex = /num\((.*?)\)/g;
33
83
 
34
- const processedCSS = css.replace(regex, (match, expression) => {
35
-
36
- return evaluateExpression(expression);
37
- });
84
+ return css.replace(regex, (match, expression) => {
85
+ try {
86
+ return parseMath(expression);
87
+ } catch (e) {
88
+ console.error('Invalid math expression:', expression);
89
+ return expression;
90
+ }
91
+ });
92
+ }
38
93
 
39
- return (processedCSS);
40
- }
41
94
  const arraysExfscss = {}; //the global variable
42
95
  const orderedxFscssRandom = {};
43
96
 
@@ -70,42 +123,37 @@ function parseConditionBlocks(block) {
70
123
  }
71
124
  return blocks;
72
125
  }
126
+
73
127
  function procExC(css) {
74
128
  const regex = /exec\((_log|_error|_warn|_info),\s*(?:"([^"]*)"|'([^']*)'|([^)]*))\)/g;
75
- let jsCode = '';
76
- let match;
77
-
78
- // Replace exec(...) with nothing (remove from CSS) while collecting code
129
+
130
+ const methodMap = {
131
+ _log: console.log,
132
+ _error: console.error,
133
+ _warn: console.warn,
134
+ _info: console.info,
135
+ };
136
+
79
137
  const cleanedCSS = css.replace(regex, (full, method, dQ, sQ, raw) => {
80
- const arg = dQ || sQ || raw;
81
-
82
- if (!['_log', '_error', '_warn', '_info'].includes(method)) {
138
+ const arg = dQ ?? sQ ?? raw;
139
+
140
+ if (!methodMap[method]) {
83
141
  console.warn(`fscss[exec(console)]: Unsupported method: ${method}`);
84
- return ''; // strip it from CSS
142
+ return '';
85
143
  }
86
-
144
+
87
145
  if (!arg) {
88
146
  console.warn(`fscss[exec(console)]: Empty argument for method: ${method}`);
89
- return ''; // strip it from CSS
147
+ return '';
90
148
  }
91
-
92
- jsCode += `console.${method.slice(1)}("${arg.replace(/"/g, '\\"')}");\n`;
93
- return ''; // ensure CSS isn’t broken
149
+
150
+ methodMap[method](arg);
151
+ return '';
94
152
  });
95
-
96
- // Run console code safely
97
- if (jsCode) {
98
- try {
99
- new Function(jsCode)();
100
- } catch (e) {
101
- console.error("fscss[exec(console)]: Error executing transformed code:", e);
102
- }
103
- }
104
-
153
+
105
154
  return cleanedCSS;
106
155
  }
107
156
 
108
-
109
157
  function procEv(css) {
110
158
  const functionMap = {};
111
159
  const funcDefRegex = /@event\s+([\w-]+)\(([^)]*)\)\s*:?{/g;
@@ -1286,124 +1334,12 @@ function applyFscssTransformations(css) {
1286
1334
  .replace(/\$\(([^\:^\)]*)\)/gi, '[$1]');
1287
1335
  return css;
1288
1336
  }
1289
- async function impSel(text) {
1290
- const validImpExt = [".fscss", ".css", ".txt", ".scss", ".less", "xfscss"]
1291
- const regex = /@import\(exec\(([^)]+)\)\s*\.\s*(?:pick|find)\(([^)]+)\)\)/g;
1292
- const matches = [...text.matchAll(regex)];
1293
-
1294
- let result = text;
1295
-
1296
- for (const match of matches) {
1297
- const [fullMatch, urlSrc, part] = match;
1298
- try {
1299
- const impUrl = urlSrc.replace(/["']/g, "");
1300
- const impExt = impUrl.slice(impUrl.lastIndexOf(".")).toLowerCase();
1301
- if (impUrl.trim().startsWith("_init") && impUrl.includes(" ")) {
1302
- console.warn(`fscss[@import] library not found for: ${impUrl}`);
1303
- return;
1304
- }
1305
-
1306
- if (!validImpExt.includes(impExt)) {
1307
- console.warn(`fscss[@import] invalid extension for: ${impUrl}`);
1308
- return;
1309
- }
1310
-
1311
- const response = await fetch(impUrl);
1312
- if (!response.ok) throw new Error(`fscss[@import] HTTP ${response.status} for ${urlSrc}`);
1313
- const resText = await response.text();
1314
- const extracted = extractOnlyBlock(resText, part.trim());
1315
- result = result.replace(fullMatch, extracted);
1316
- } catch (err) {
1317
- console.error(`fscss[@import] Failed: ${urlSrc} `, err);
1318
- result = result.replace(fullMatch, `/* Failed import: ${urlSrc} */`);
1319
-
1320
- }
1321
- }
1322
-
1323
- return result;
1324
- }
1325
-
1326
- function extractOnlyBlock(cssText, blockName) {
1327
- const regex = new RegExp(`${blockName}\\s*{[^}]*}`, "g");
1328
- const match = cssText.match(regex);
1329
- return match ? match.join("\n") : console.warn(`fscss[@import pick] No block matches: ${blockName} `);
1330
- }
1331
-
1332
- const VALID_EXTENSIONS = ['.fscss', '.css', '.txt', '.scss', '.less', '.xfscss'];
1333
-
1334
- async function processImports(cssText, depth = 0, baseURL = window.location.href) {
1335
- if (depth > exfMAX_DEPTH) {
1336
- console.warn('fscss[@import]\n Maximum import depth exceeded. Skipping further imports.');
1337
- return cssText;
1338
- }
1339
-
1340
- const importRegex = /@import\s*\(\s*exec\s*\(\s*((?:'[^']*'|"[^"]*"|[^'")]\S*)\s*)\)\s*\)/g;
1341
- const matches = Array.from(cssText.matchAll(importRegex));
1342
-
1343
- if (matches.length === 0) return cssText;
1344
-
1345
- const fetchedContents = await Promise.all(
1346
- matches.map(async (match) => {
1347
- const [fullMatch, urlSpec] = match;
1348
- try {
1349
- const cleanUrl = urlSpec.replace(/^['"](.*)['"]$/, '$1').trim();
1350
- const absoluteUrl = new URL(cleanUrl, baseURL).href;
1351
-
1352
- // --- New code for extension validation ---
1353
- const urlPath = new URL(absoluteUrl).pathname;
1354
- const extension = urlPath.slice(urlPath.lastIndexOf('.')).toLowerCase();
1355
-
1356
- if (absoluteUrl.trim().startsWith("_init") && absoluteUrl.includes(" ")){
1357
- console.warn(`fscss[@import] library not found for: ${absoluteUrl}`);
1358
- return;
1359
- }
1360
1337
 
1361
- if (!VALID_EXTENSIONS.includes(extension)) {
1362
- console.warn(`fscss[@import] \n Invalid import URL extension "${extension}" for "${absoluteUrl}". Only ${VALID_EXTENSIONS.join(', ')} are allowed.`);
1363
- return `/* Invalid extension for "${absoluteUrl}" */`;
1364
- }
1365
- // --- End of new code ---
1366
-
1367
- const response = await fetch(absoluteUrl);
1368
- if (!response.ok) throw new Error(`HTTP ${response.status} for ${absoluteUrl}`);
1369
-
1370
- const importedText = await response.text();
1371
- return processImports(importedText, depth + 1, absoluteUrl);
1372
- } catch (error) {
1373
- console.warn(`fscss[@import]\n Failed to import "${urlSpec}" from "${baseURL}":`, error);
1374
- return `/* Error importing "${urlSpec}": ${error.message} */`;
1375
- }
1376
- })
1377
- );
1378
-
1379
- let lastIndex = 0;
1380
- let result = '';
1381
- matches.forEach((match, i) => {
1382
- result += cssText.slice(lastIndex, match.index);
1383
- result += fetchedContents[i];
1384
- lastIndex = match.index + match[0].length;
1385
- });
1386
- result += cssText.slice(lastIndex);
1387
-
1388
- return result;
1389
- }
1390
-
1391
- async function procImp(css) {
1392
- try {
1393
- const processedCSS = await processImports(css);
1394
- return processedCSS;
1395
- } catch (error) {
1396
- console.warn('fscss[]\n Processing failed:', error);
1397
- console.warn(`fscss[@import] Warning: can't resolve imports`);
1398
- return css;
1399
- }
1400
- }
1401
-
1402
1338
  function execObj(css){
1403
1339
  return css.replace(/exec\.obj\.block\([^\)\n]*\)\;?/g, "");
1404
1340
  }
1405
1341
 
1406
1342
  export { initlibraries,
1407
- impSel, procImp, replaceRe, procExt, procVar,procFun, procFunObj, procArr, procEv, procRan, transformCssValues, procNum, vfc, applyFscssTransformations,procExC, procCnt, procDef, procChe, execObj
1343
+ replaceRe, procExt, procVar,procFun, procFunObj, procArr, procEv, procRan, transformCssValues, procNum, vfc, applyFscssTransformations,procExC, procCnt, procDef, procChe, execObj
1408
1344
  }
1409
1345
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fscss",
3
3
  "description": "Figured Shorthand Cascading Style Sheet",
4
- "version": "1.1.20",
4
+ "version": "1.1.22",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "bin": {
@@ -29,14 +29,14 @@
29
29
  "bugs": {
30
30
  "url": "https://github.com/Figsh/xfscss/issues"
31
31
  },
32
- "homepage": "https://github.com/Figsh/xfscss#readme",
32
+ "homepage": "https://fscss.devtem.org",
33
33
  "dependencies": {
34
- "express": "^4.18.2",
35
- "dotenv": "^16.0.3"
34
+ "dotenv": "^16.0.3",
35
+ "express": "^4.18.2"
36
36
  },
37
37
  "devDependencies": {
38
- "mocha": "^10.0.0",
39
- "chai": "^4.3.4"
38
+ "chai": "^4.3.4",
39
+ "mocha": "^10.0.0"
40
40
  },
41
41
  "directories": {
42
42
  "lib": "lib"