papagaio 0.4.2 → 0.5.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/src/louro.js DELETED
@@ -1,259 +0,0 @@
1
- function parsePattern(papagaio, pattern) {
2
- const tokens = []; let i = 0;
3
- const S = papagaio.symbols.sigil, S2 = S + S;
4
- while (i < pattern.length) {
5
- if (pattern.startsWith(S2 + S, i)) {
6
- let j = i + S2.length + S.length, varName = '';
7
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
8
- if (varName) { tokens.push({ type: 'var-ws-optional', varName }); i = j; continue; }
9
- }
10
- if (pattern.startsWith(S2, i)) {
11
- let j = i + S2.length, varName = '';
12
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
13
- if (varName) { tokens.push({ type: 'var-ws', varName }); i = j; continue; }
14
- tokens.push({ type: 'whitespace-optional' }); i += S2.length; continue;
15
- }
16
- if (pattern.startsWith(S + 'block', i)) {
17
- let j = i + S.length + 'block'.length;
18
- while (j < pattern.length && /\s/.test(pattern[j])) j++;
19
- let varName = '';
20
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
21
- if (varName) {
22
- while (j < pattern.length && /\s/.test(pattern[j])) j++;
23
- let openDelim = papagaio.symbols.open;
24
- if (j < pattern.length && pattern[j] === papagaio.symbols.open) {
25
- const [c, e] = extractBlock(papagaio, pattern, j);
26
- openDelim = unescapeDelimiter(c.trim()) || papagaio.symbols.open;
27
- j = e; while (j < pattern.length && /\s/.test(pattern[j])) j++;
28
- }
29
- let closeDelim = papagaio.symbols.close;
30
- if (j < pattern.length && pattern[j] === papagaio.symbols.open) {
31
- const [c, e] = extractBlock(papagaio, pattern, j);
32
- closeDelim = unescapeDelimiter(c.trim()) || papagaio.symbols.close;
33
- j = e;
34
- }
35
- tokens.push({ type: 'block', varName, openDelim, closeDelim }); i = j; continue;
36
- }
37
- }
38
- if (pattern[i] === S) {
39
- let j = i + S.length, varName = '';
40
- while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) varName += pattern[j++];
41
- if (varName) { tokens.push({ type: 'var', varName }); i = j; continue; }
42
- tokens.push({ type: 'literal', value: S }); i += S.length; continue;
43
- }
44
- if (/\s/.test(pattern[i])) {
45
- while (i < pattern.length && /\s/.test(pattern[i])) i++;
46
- tokens.push({ type: 'whitespace-optional' }); continue;
47
- }
48
- let literal = '';
49
- while (i < pattern.length && !pattern.startsWith(S, i) && !/\s/.test(pattern[i])) literal += pattern[i++];
50
- if (literal) tokens.push({ type: 'literal', value: literal });
51
- }
52
- return tokens;
53
- }
54
-
55
- function matchPattern(papagaio, src, tokens, startPos = 0) {
56
- let pos = startPos, captures = {};
57
- for (let ti = 0; ti < tokens.length; ti++) {
58
- const token = tokens[ti];
59
- if (token.type === 'whitespace-optional') { while (pos < src.length && /\s/.test(src[pos])) pos++; continue; }
60
- if (token.type === 'literal') { if (!src.startsWith(token.value, pos)) return null; pos += token.value.length; continue; }
61
- if (token.type === 'var') {
62
- const nextToken = findNextSignificantToken(tokens, ti);
63
- let v = '';
64
-
65
- // Se o próximo token é um block, captura até o delimitador de abertura
66
- if (nextToken && nextToken.type === 'block') {
67
- while (pos < src.length && !src.startsWith(nextToken.openDelim, pos) && !/\s/.test(src[pos])) {
68
- v += src[pos++];
69
- }
70
- } else {
71
- while (pos < src.length && !/\s/.test(src[pos])) v += src[pos++];
72
- }
73
-
74
- if (!v) return null;
75
- captures[papagaio.symbols.sigil + token.varName] = v;
76
- continue;
77
- }
78
- if (token.type === 'var-ws' || token.type === 'var-ws-optional') {
79
- while (pos < src.length && /\s/.test(src[pos])) pos++;
80
- const n = findNextSignificantToken(tokens, ti);
81
- let v = '';
82
-
83
- // Se o próximo token é um block, captura até o delimitador de abertura
84
- if (n && n.type === 'block') {
85
- while (pos < src.length && !src.startsWith(n.openDelim, pos) && src[pos] !== '\n') {
86
- v += src[pos++];
87
- }
88
- v = v.trimEnd();
89
- } else if (!n || ['var','var-ws','var-ws-optional'].includes(n.type)) {
90
- while (pos < src.length && !/\s/.test(src[pos])) v += src[pos++];
91
- } else if (n.type === 'literal') {
92
- while (pos < src.length && !src.startsWith(n.value, pos) && src[pos] !== '\n') v += src[pos++];
93
- v = v.trimEnd();
94
- }
95
-
96
- if (token.type === 'var-ws' && !v) return null;
97
- captures[papagaio.symbols.sigil + token.varName] = v;
98
- continue;
99
- }
100
- if (token.type === 'block') {
101
- const { varName, openDelim, closeDelim } = token;
102
- if (!src.startsWith(openDelim, pos)) return null;
103
- const [c, e] = extractBlock(papagaio, src, pos, openDelim, closeDelim);
104
- captures[papagaio.symbols.sigil + varName] = c; pos = e; continue;
105
- }
106
- }
107
- return { captures, endPos: pos };
108
- }
109
-
110
- function findNextSignificantToken(t, i) { for (let k = i + 1; k < t.length; k++) if (t[k].type !== 'whitespace-optional') return t[k]; return null; }
111
-
112
- function extractBlock(p, src, openPos, openDelim = p.symbols.open, closeDelim = p.symbols.close) {
113
- let i = openPos;
114
- if (openDelim.length > 1 || closeDelim.length > 1) {
115
- if (src.substring(i, i + openDelim.length) === openDelim) {
116
- i += openDelim.length; const s = i; let d = 0;
117
- while (i < src.length) {
118
- if (src.substring(i, i + openDelim.length) === openDelim) { d++; i += openDelim.length; }
119
- else if (src.substring(i, i + closeDelim.length) === closeDelim) {
120
- if (!d) return [src.substring(s, i), i + closeDelim.length];
121
- d--; i += closeDelim.length;
122
- } else i++;
123
- }
124
- return [src.substring(s), src.length];
125
- }
126
- }
127
- if (src[i] === openDelim) {
128
- i++; const s = i;
129
- if (openDelim === closeDelim) { while (i < src.length && src[i] !== closeDelim) i++; return [src.substring(s, i), i + 1]; }
130
- let d = 1;
131
- while (i < src.length && d > 0) { if (src[i] === openDelim) d++; else if (src[i] === closeDelim) d--; if (d > 0) i++; }
132
- return [src.substring(s, i), i + 1];
133
- }
134
- return ['', i];
135
- }
136
-
137
- function collectPatterns(p, src) {
138
- const A = [], r = new RegExp(`(?:^|\\b)${p.symbols.pattern}\\s*\\${p.symbols.open}`, "g"); let out = src;
139
- while (1) {
140
- r.lastIndex = 0; const m = r.exec(out); if (!m) break;
141
- const s = m.index, o = m.index + m[0].length - 1;
142
- const [mp, em] = extractBlock(p, out, o); let k = em;
143
- while (k < out.length && /\s/.test(out[k])) k++;
144
- if (k < out.length && out[k] === p.symbols.open) {
145
- const [rp, er] = extractBlock(p, out, k);
146
- A.push({ match: mp.trim(), replace: rp.trim() });
147
- out = out.slice(0, s) + out.slice(er); continue;
148
- }
149
- out = out.slice(0, s) + out.slice(em);
150
- }
151
- return [A, out];
152
- }
153
-
154
- function extractNestedPatterns(p, replaceText) {
155
- const nested = [];
156
- const r = new RegExp(`\\${p.symbols.sigil}${p.symbols.pattern}\\s*\\${p.symbols.open}`, "g");
157
- let out = replaceText;
158
-
159
- while (1) {
160
- r.lastIndex = 0;
161
- const m = r.exec(out);
162
- if (!m) break;
163
-
164
- const s = m.index, o = m.index + m[0].length - 1;
165
- const [mp, em] = extractBlock(p, out, o);
166
- let k = em;
167
-
168
- while (k < out.length && /\s/.test(out[k])) k++;
169
-
170
- if (k < out.length && out[k] === p.symbols.open) {
171
- const [rp, er] = extractBlock(p, out, k);
172
- nested.push({ match: mp.trim(), replace: rp.trim() });
173
- out = out.slice(0, s) + out.slice(er);
174
- continue;
175
- }
176
- out = out.slice(0, s) + out.slice(em);
177
- }
178
-
179
- return [nested, out];
180
- }
181
-
182
- function applyPatterns(p, src, pats) {
183
- let clear = false, last = "", S = p.symbols.sigil;
184
- for (const pat of pats) {
185
- const t = parsePattern(p, pat.match); let n = '', pos = 0, ok = false;
186
- while (pos < src.length) {
187
- const m = matchPattern(p, src, t, pos);
188
- if (m) {
189
- ok = true; const { captures, endPos } = m;
190
- let r = pat.replace;
191
-
192
- // Extrai e processa padrões aninhados ($pattern)
193
- const [nestedPats, cleanReplace] = extractNestedPatterns(p, r);
194
- r = cleanReplace;
195
-
196
- for (const [k, v] of Object.entries(captures)) {
197
- const e = escapeRegex(k); r = r.replace(new RegExp(e + '(?![A-Za-z0-9_])', 'g'), v);
198
- }
199
-
200
- // Aplica padrões aninhados ao resultado
201
- if (nestedPats.length > 0) {
202
- r = applyPatterns(p, r, nestedPats);
203
- }
204
-
205
- const uid = p.unique_id++; r = r.replace(new RegExp(`${escapeRegex(S)}unique\\b`, 'g'), () => String(uid));
206
- r = r.replace(/\$eval\{([^}]*)\}/g, (_, c) => { try {
207
- return String(Function("papagaio", "ctx", `"use strict";return(function(){${c}})();`)(p, {}));
208
- } catch { return ""; } });
209
- r = r.replace(new RegExp(escapeRegex(S + S), 'g'), '');
210
- if (new RegExp(`${escapeRegex(S)}clear\\b`, 'g').test(r)) {
211
- r = r.replace(new RegExp(`${escapeRegex(S)}clear\\b\\s?`, 'g'), ''); clear = true;
212
- }
213
- const ms = pos, me = endPos;
214
- r = r
215
- .replace(new RegExp(`${escapeRegex(S)}prefix\\b`, 'g'), src.slice(0, ms))
216
- .replace(new RegExp(`${escapeRegex(S)}suffix\\b`, 'g'), src.slice(me))
217
- .replace(new RegExp(`${escapeRegex(S)}match\\b`, 'g'), src.slice(ms, me));
218
- n += r; last = r; pos = endPos;
219
- } else { n += src[pos]; pos++; }
220
- }
221
- if (ok) { src = clear ? last : n; clear = false; }
222
- }
223
- return src;
224
- }
225
-
226
- function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\""']/g, '\\$&'); }
227
-
228
- function unescapeDelimiter(s) {
229
- let r = ''; for (let i = 0; i < s.length; i++) {
230
- if (s[i] === '\\' && i + 1 < s.length) {
231
- const n = s[i + 1];
232
- if (n === '"' || n === "'" || n === '\\') { r += n; i++; }
233
- else r += s[i];
234
- } else r += s[i];
235
- }
236
- return r;
237
- }
238
-
239
- export class Papagaio {
240
- constructor(sigil = '$', open = '{', close = '}', pattern = 'pattern') {
241
- this.recursion_limit = 512;
242
- this.unique_id = 0;
243
- this.symbols = { pattern: pattern, open: open, close: close, sigil: sigil };
244
- this.content = "";
245
- }
246
- process(input) {
247
- this.content = input; let src = input, last = null, it = 0;
248
- const pend = () => {
249
- const r2 = new RegExp(`(?:^|\\b)${this.symbols.pattern}\\s*\\${this.symbols.open}`, "g");
250
- return r2.test(src);
251
- };
252
- while (src !== last && it < this.recursion_limit) {
253
- it++; last = src;
254
- const [p, s2] = collectPatterns(this, src); src = applyPatterns(this, s2, p);
255
- if (!pend()) break;
256
- }
257
- return this.content = src, src;
258
- }
259
- }