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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "papagaio",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "easy yet powerful preprocessor",
5
5
  "main": "src/papagaio.js",
6
6
  "type": "module",
@@ -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 = { pattern: "pattern", context: "context", open: "{", close: "}", sigil: "$" };
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 r1.test(src) || r2.test(src);
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;