papagaio 0.3.1 → 0.4.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/examples/simple.html +15 -0
- package/package.json +1 -1
- package/src/papagaio-bootstrap.mjs +25 -0
- package/src/papagaio.js +42 -24
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>papagaio test</title>
|
|
7
|
+
</head>
|
|
8
|
+
<script src="src/papagaio-bootstrap.mjs" type="module"></script>
|
|
9
|
+
<script type="papagaio">
|
|
10
|
+
pattern {abc} {$eval{console.log(papagaio)}}
|
|
11
|
+
abc
|
|
12
|
+
</script>
|
|
13
|
+
<body>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/package.json
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// papagaio-bootstrap.js
|
|
2
|
+
import { Papagaio } from "./papagaio.js";
|
|
3
|
+
|
|
4
|
+
(async () => {
|
|
5
|
+
const p = new Papagaio();
|
|
6
|
+
|
|
7
|
+
const nodes = [...document.querySelectorAll('script[type="papagaio"]')];
|
|
8
|
+
|
|
9
|
+
for (const el of nodes) {
|
|
10
|
+
let src = el.textContent;
|
|
11
|
+
|
|
12
|
+
if (el.src) {
|
|
13
|
+
src = await fetch(el.src).then(r => r.text());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const out = p.process(src);
|
|
17
|
+
|
|
18
|
+
const s = document.createElement("script");
|
|
19
|
+
s.type = "module";
|
|
20
|
+
s.textContent = out;
|
|
21
|
+
|
|
22
|
+
// executa no mesmo ponto onde script estava
|
|
23
|
+
el.replaceWith(s);
|
|
24
|
+
}
|
|
25
|
+
})();
|
package/src/papagaio.js
CHANGED
|
@@ -330,25 +330,6 @@ function extractBlock(p, src, openPos, openDelim = p.symbols.open, closeDelim =
|
|
|
330
330
|
return ['', i];
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
-
function processContext(p, src) {
|
|
334
|
-
const r = new RegExp(`\\b${p.symbols.context}\\s*\\${p.symbols.open}`, "g");
|
|
335
|
-
let m, a = [];
|
|
336
|
-
while ((m = r.exec(src)) !== null) a.push({ idx: m.index, pos: m.index + m[0].length - 1 });
|
|
337
|
-
for (let j = a.length - 1; j >= 0; j--) {
|
|
338
|
-
const x = a[j], [c, e] = extractBlock(p, src, x.pos);
|
|
339
|
-
if (!c.trim()) {
|
|
340
|
-
src = src.slice(0, x.idx) + src.slice(e);
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
const r2 = p.process(c);
|
|
344
|
-
let L = src.substring(0, x.idx), R = src.substring(e);
|
|
345
|
-
let pre = L.endsWith("\n") ? "\n" : "";
|
|
346
|
-
if (pre) L = L.slice(0, -1);
|
|
347
|
-
src = L + pre + r2 + R;
|
|
348
|
-
}
|
|
349
|
-
return src;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
333
|
function collectPatterns(p, src) {
|
|
353
334
|
const A = [], r = new RegExp(`\\b${p.symbols.pattern}\\s*\\${p.symbols.open}`, "g");
|
|
354
335
|
let out = src;
|
|
@@ -371,6 +352,34 @@ function collectPatterns(p, src) {
|
|
|
371
352
|
return [A, out];
|
|
372
353
|
}
|
|
373
354
|
|
|
355
|
+
function extractNestedPatterns(p, replaceText) {
|
|
356
|
+
const nested = [];
|
|
357
|
+
const r = new RegExp(`\\${p.symbols.sigil}${escapeRegex(p.symbols.pattern)}\\s*\\${p.symbols.open}`, "g");
|
|
358
|
+
let out = replaceText;
|
|
359
|
+
|
|
360
|
+
while (1) {
|
|
361
|
+
r.lastIndex = 0;
|
|
362
|
+
const m = r.exec(out);
|
|
363
|
+
if (!m) break;
|
|
364
|
+
|
|
365
|
+
const s = m.index, o = m.index + m[0].length - 1;
|
|
366
|
+
const [mp, em] = extractBlock(p, out, o);
|
|
367
|
+
let k = em;
|
|
368
|
+
|
|
369
|
+
while (k < out.length && /\s/.test(out[k])) k++;
|
|
370
|
+
|
|
371
|
+
if (k < out.length && out[k] === p.symbols.open) {
|
|
372
|
+
const [rp, er] = extractBlock(p, out, k);
|
|
373
|
+
nested.push({ match: mp.trim(), replace: rp.trim() });
|
|
374
|
+
out = out.slice(0, s) + out.slice(er);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
out = out.slice(0, s) + out.slice(em);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return [nested, out];
|
|
381
|
+
}
|
|
382
|
+
|
|
374
383
|
function applyPatterns(p, src, pats) {
|
|
375
384
|
let clear = false, last = "", S = p.symbols.sigil;
|
|
376
385
|
for (const pat of pats) {
|
|
@@ -382,10 +391,21 @@ function applyPatterns(p, src, pats) {
|
|
|
382
391
|
ok = true;
|
|
383
392
|
const { captures, endPos } = m;
|
|
384
393
|
let r = pat.replace;
|
|
394
|
+
|
|
395
|
+
// Extrai e processa padrões aninhados ($pattern)
|
|
396
|
+
const [nestedPats, cleanReplace] = extractNestedPatterns(p, r);
|
|
397
|
+
r = cleanReplace;
|
|
398
|
+
|
|
385
399
|
for (const [k, v] of Object.entries(captures)) {
|
|
386
400
|
const e = escapeRegex(k);
|
|
387
401
|
r = r.replace(new RegExp(e + '(?![A-Za-z0-9_])', 'g'), v);
|
|
388
402
|
}
|
|
403
|
+
|
|
404
|
+
// Aplica padrões aninhados ao resultado
|
|
405
|
+
if (nestedPats.length > 0) {
|
|
406
|
+
r = applyPatterns(p, r, nestedPats);
|
|
407
|
+
}
|
|
408
|
+
|
|
389
409
|
const uid = p.unique_id++;
|
|
390
410
|
r = r.replace(new RegExp(`${escapeRegex(S)}unique\\b`, 'g'), () => String(uid));
|
|
391
411
|
r = r.replace(/\$eval\{([^}]*)\}/g, (_, c) => {
|
|
@@ -439,24 +459,22 @@ function unescapeDelimiter(s) {
|
|
|
439
459
|
}
|
|
440
460
|
|
|
441
461
|
export class Papagaio {
|
|
442
|
-
constructor() {
|
|
462
|
+
constructor(sigil = "$", open = "{", close = "}", pattern = "pattern") {
|
|
443
463
|
this.recursion_limit = 512;
|
|
444
464
|
this.unique_id = 0;
|
|
445
|
-
this.symbols = {
|
|
465
|
+
this.symbols = { sigil: sigil, open: open, close: close, pattern: pattern};
|
|
446
466
|
this.content = "";
|
|
447
467
|
}
|
|
448
468
|
process(input) {
|
|
449
469
|
this.content = input;
|
|
450
470
|
let src = input, last = null, it = 0;
|
|
451
471
|
const pend = () => {
|
|
452
|
-
const r1 = new RegExp(`\\b${this.symbols.context}\\s*\\${this.symbols.open}`, "g");
|
|
453
472
|
const r2 = new RegExp(`\\b${this.symbols.pattern}\\s*\\${this.symbols.open}`, "g");
|
|
454
|
-
return
|
|
473
|
+
return r2.test(src);
|
|
455
474
|
};
|
|
456
475
|
while (src !== last && it < this.recursion_limit) {
|
|
457
476
|
it++;
|
|
458
477
|
last = src;
|
|
459
|
-
src = processContext(this, src);
|
|
460
478
|
const [p, s2] = collectPatterns(this, src);
|
|
461
479
|
src = applyPatterns(this, s2, p);
|
|
462
480
|
if (!pend()) break;
|