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.
- package/README.md +10 -1
- package/bin/fscss.js +0 -0
- package/e/exec.js +1696 -2
- package/e/xfscss.js +1721 -2
- package/exec.js +1696 -2
- package/lib/functions/all.js +88 -152
- package/package.json +6 -6
- package/xfscss.js +1720 -1
package/lib/functions/all.js
CHANGED
|
@@ -18,26 +18,79 @@ function procCntInit(ntc,stc){
|
|
|
18
18
|
})
|
|
19
19
|
return text;
|
|
20
20
|
}
|
|
21
|
-
function
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
81
|
-
|
|
82
|
-
if (![
|
|
138
|
+
const arg = dQ ?? sQ ?? raw;
|
|
139
|
+
|
|
140
|
+
if (!methodMap[method]) {
|
|
83
141
|
console.warn(`fscss[exec(console)]: Unsupported method: ${method}`);
|
|
84
|
-
return '';
|
|
142
|
+
return '';
|
|
85
143
|
}
|
|
86
|
-
|
|
144
|
+
|
|
87
145
|
if (!arg) {
|
|
88
146
|
console.warn(`fscss[exec(console)]: Empty argument for method: ${method}`);
|
|
89
|
-
return '';
|
|
147
|
+
return '';
|
|
90
148
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return '';
|
|
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
|
-
|
|
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.
|
|
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://
|
|
32
|
+
"homepage": "https://fscss.devtem.org",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"
|
|
35
|
-
"
|
|
34
|
+
"dotenv": "^16.0.3",
|
|
35
|
+
"express": "^4.18.2"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
38
|
+
"chai": "^4.3.4",
|
|
39
|
+
"mocha": "^10.0.0"
|
|
40
40
|
},
|
|
41
41
|
"directories": {
|
|
42
42
|
"lib": "lib"
|