papagaio 0.6.2 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "papagaio",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "easy yet powerful preprocessor",
5
5
  "main": "src/papagaio.js",
6
6
  "type": "module",
package/src/papagaio.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // papagaio - https://github.com/jardimdanificado/papagaio
2
2
  function parsePattern(p, pat) {
3
- const t = [], S = p.symbols.sigil, O = p.symbols.open;
3
+ const t = [], S = p.symbols.sigil, O = p.symbols.open, C = p.symbols.close;
4
4
  let i = 0;
5
5
  while (i < pat.length) {
6
6
  if (pat.startsWith(S + p.symbols.regex, i)) {
@@ -17,36 +17,30 @@ function parsePattern(p, pat) {
17
17
  }
18
18
  }
19
19
  }
20
- if (pat.startsWith(S + p.symbols.block, i)) {
21
- let j = i + S.length + p.symbols.block.length;
22
- while (j < pat.length && /\s/.test(pat[j])) j++;
23
- let v = '';
24
- while (j < pat.length && /[A-Za-z0-9_]/.test(pat[j])) v += pat[j++];
25
- if (v) {
26
- while (j < pat.length && /\s/.test(pat[j])) j++;
27
- let od = O, cd = p.symbols.close;
28
- if (pat[j] === O) {
29
- const [c, e] = extractBlock(p, pat, j);
30
- od = unescapeDelim(c.trim()) || O;
31
- j = e; while (j < pat.length && /\s/.test(pat[j])) j++;
32
- }
33
- if (pat[j] === O) {
34
- const [c, e] = extractBlock(p, pat, j);
35
- cd = unescapeDelim(c.trim()) || cd;
36
- j = e;
20
+ if (pat[i] === S) {
21
+ let j = i + S.length;
22
+ const isDouble = pat[j] === S;
23
+ if (isDouble) j++;
24
+ if (pat[j] === O) {
25
+ const [od, e1] = extractBlock(p, pat, j);
26
+ if (pat[e1] === O) {
27
+ const [cd, e2] = extractBlock(p, pat, e1);
28
+ let v = '', k = e2;
29
+ while (k < pat.length && /[A-Za-z0-9_]/.test(pat[k])) v += pat[k++];
30
+ if (v) {
31
+ t.push({ type: isDouble ? 'blockseq' : 'block', varName: v, open: unescapeDelim(od.trim()) || O, close: unescapeDelim(cd.trim()) || C });
32
+ i = k; continue;
33
+ }
37
34
  }
38
- t.push({ type: 'block', varName: v, open: od, close: cd });
39
- i = j; continue;
40
35
  }
41
- }
42
- if (pat[i] === S) {
43
- let j = i + S.length, v = '';
36
+ j = i + S.length;
37
+ let v = '';
44
38
  while (j < pat.length && /[A-Za-z0-9_]/.test(pat[j])) v += pat[j++];
45
- if (v) {
39
+ if (v) {
46
40
  const optional = pat[j] === '?';
47
41
  if (optional) j++;
48
- t.push({ type: 'var', varName: v, optional });
49
- i = j; continue;
42
+ t.push({ type: 'var', varName: v, optional });
43
+ i = j; continue;
50
44
  }
51
45
  t.push({ type: 'lit', value: S }); i += S.length; continue;
52
46
  }
@@ -80,11 +74,9 @@ function matchPattern(p, src, tok, pos = 0) {
80
74
  while (pos < src.length && /\s/.test(src[pos])) pos++;
81
75
  const nx = findNext(tok, ti);
82
76
  let v = '';
83
- if (nx && nx.type === 'block') {
84
- while (pos < src.length && !src.startsWith(nx.open, pos) && src[pos] !== '\n') v += src[pos++];
85
- v = v.trimEnd();
86
- } else if (nx && nx.type === 'lit') {
87
- while (pos < src.length && !src.startsWith(nx.value, pos) && src[pos] !== '\n') v += src[pos++];
77
+ if (nx && (nx.type === 'block' || nx.type === 'lit')) {
78
+ const stop = nx.type === 'block' ? nx.open : nx.value;
79
+ while (pos < src.length && !src.startsWith(stop, pos) && src[pos] !== '\n') v += src[pos++];
88
80
  v = v.trimEnd();
89
81
  } else {
90
82
  while (pos < src.length && !/\s/.test(src[pos])) v += src[pos++];
@@ -93,6 +85,18 @@ function matchPattern(p, src, tok, pos = 0) {
93
85
  cap[p.symbols.sigil + t.varName] = v;
94
86
  continue;
95
87
  }
88
+ if (t.type === 'blockseq') {
89
+ let blocks = [];
90
+ while (pos < src.length && src.startsWith(t.open, pos)) {
91
+ const [c, e] = extractBlock(p, src, pos, t.open, t.close);
92
+ blocks.push(c);
93
+ pos = e;
94
+ while (pos < src.length && /\s/.test(src[pos])) pos++;
95
+ }
96
+ if (!blocks.length) return null;
97
+ cap[p.symbols.sigil + t.varName] = blocks.join(' ');
98
+ continue;
99
+ }
96
100
  if (t.type === 'block') {
97
101
  if (!src.startsWith(t.open, pos)) return null;
98
102
  const [c, e] = extractBlock(p, src, pos, t.open, t.close);
@@ -151,18 +155,15 @@ function extractEvals(p, txt) {
151
155
  const ev = [], S = p.symbols.sigil, O = p.symbols.open;
152
156
  let i = 0, out = txt, off = 0;
153
157
  while (i < txt.length) {
154
- if (txt.substring(i, i + S.length) === S) {
155
- const rest = txt.substring(i + S.length);
156
- if (rest.startsWith(p.symbols.eval)) {
157
- let j = i + S.length + p.symbols.eval.length;
158
- while (j < txt.length && /\s/.test(txt[j])) j++;
159
- if (j < txt.length && txt.substring(j, j + O.length) === O) {
160
- const sp = i, bp = j, [c, ep] = extractBlock(p, txt, bp);
161
- ev.push({ code: c, sp: sp - off, ep: ep - off });
162
- const ph = `__E${ev.length - 1}__`;
163
- out = out.substring(0, sp - off) + ph + out.substring(ep - off);
164
- off += (ep - sp) - ph.length; i = ep; continue;
165
- }
158
+ if (txt.substring(i, i + S.length) === S && txt.substring(i + S.length).startsWith(p.symbols.eval)) {
159
+ let j = i + S.length + p.symbols.eval.length;
160
+ while (j < txt.length && /\s/.test(txt[j])) j++;
161
+ if (j < txt.length && txt.substring(j, j + O.length) === O) {
162
+ const sp = i, bp = j, [c, ep] = extractBlock(p, txt, bp);
163
+ ev.push({ code: c, sp: sp - off, ep: ep - off });
164
+ const ph = `__E${ev.length - 1}__`;
165
+ out = out.substring(0, sp - off) + ph + out.substring(ep - off);
166
+ off += (ep - sp) - ph.length; i = ep; continue;
166
167
  }
167
168
  }
168
169
  i++;
@@ -174,10 +175,8 @@ function applyEvals(p, txt, ev) {
174
175
  let r = txt;
175
176
  for (let i = ev.length - 1; i >= 0; i--) {
176
177
  const ph = `__E${i}__`;
177
- let res;
178
- try { res = String(Function("papagaio", "ctx", `"use strict";return(function(){${ev[i].code}})();`)(p, {})); }
179
- catch (e) { res = "error: " + e.message; }
180
- r = r.replace(ph, res);
178
+ try { r = r.replace(ph, String(Function("papagaio", "ctx", `"use strict";return(function(){${ev[i].code}})();`)(p, {}))); }
179
+ catch (e) { r = r.replace(ph, "error: " + e.message); }
181
180
  }
182
181
  return r;
183
182
  }
@@ -219,8 +218,8 @@ function unescapeDelim(s) {
219
218
  }
220
219
 
221
220
  export class Papagaio {
222
- constructor(sigil = '$', open = '{', close = '}', pattern = 'pattern', evalKw = 'eval', blockKw = 'block', regexKw = 'regex') {
223
- this.symbols = { pattern, open, close, sigil, eval: evalKw, block: blockKw, regex: regexKw };
221
+ constructor(sigil = '$', open = '{', close = '}', pattern = 'pattern', evalKw = 'eval', blockKw = 'recursive', regexKw = 'regex', blockseqKw = 'sequential') {
222
+ this.symbols = { pattern, open, close, sigil, eval: evalKw, block: blockKw, regex: regexKw, blockseq: blockseqKw };
224
223
  this.content = "";
225
224
  this.match = "";
226
225
  }
package/tests/tests.json CHANGED
@@ -15,19 +15,19 @@
15
15
  {
16
16
  "id": 3,
17
17
  "name": "Block with custom delimiters",
18
- "code": "$pattern {$block content {(}{)}} {[$content]}\ndata (hello world)",
18
+ "code": "$pattern {${(}{)}content} {[$content]}\ndata (hello world)",
19
19
  "expected": "data [hello world]"
20
20
  },
21
21
  {
22
22
  "id": 4,
23
23
  "name": "Block with multi-char delimiters",
24
- "code": "$pattern {$block code {<<}{>>}} {CODE[$code]}\n<<console.log()>>",
24
+ "code": "$pattern {${<<}{>>}code} {CODE[$code]}\n<<console.log()>>",
25
25
  "expected": "CODE[console.log()]"
26
26
  },
27
27
  {
28
28
  "id": 5,
29
29
  "name": "Block with nested delimiters",
30
- "code": "$pattern {$block txt {<}{>}} {[$txt]}\nouter <middle <inner> content>",
30
+ "code": "$pattern {${<}{>}txt} {[$txt]}\nouter <middle <inner> content>",
31
31
  "expected": "outer [middle <inner> content]"
32
32
  },
33
33
  {
@@ -63,7 +63,7 @@
63
63
  {
64
64
  "id": 11,
65
65
  "name": "Multiple blocks in one pattern",
66
- "code": "$pattern {$block a {(}{)} and $block b {[}{]}} {$a|$b}\n(first) and [second]",
66
+ "code": "$pattern {${(}{)}a and ${[}{]}b} {$a|$b}\n(first) and [second]",
67
67
  "expected": "first|second"
68
68
  },
69
69
  {
@@ -87,7 +87,7 @@
87
87
  {
88
88
  "id": 15,
89
89
  "name": "Block with angle brackets",
90
- "code": "$pattern {$block inner {<}{>}} {WRAPPED[$inner]}\n<content>",
90
+ "code": "$pattern {${<}{>}inner} {WRAPPED[$inner]}\n<content>",
91
91
  "expected": "WRAPPED[content]"
92
92
  },
93
93
  {
@@ -105,7 +105,7 @@
105
105
  {
106
106
  "id": 18,
107
107
  "name": "Block capturing with square brackets",
108
- "code": "$pattern {$block arr {[}{]}} {ARRAY[$arr]}\n[1, 2, 3]",
108
+ "code": "$pattern {${[}{]}arr} {ARRAY[$arr]}\n[1, 2, 3]",
109
109
  "expected": "ARRAY[1, 2, 3]"
110
110
  },
111
111
  {
@@ -129,31 +129,31 @@
129
129
  {
130
130
  "id": 22,
131
131
  "name": "Block delimiter balancing - parentheses",
132
- "code": "$pattern {$block code {(}{)}} {RESULT[$code]}\n(a (b (c) d) e)",
132
+ "code": "$pattern {${(}{)}code} {RESULT[$code]}\n(a (b (c) d) e)",
133
133
  "expected": "RESULT[a (b (c) d) e]"
134
134
  },
135
135
  {
136
136
  "id": 23,
137
137
  "name": "Block delimiter balancing - angle brackets",
138
- "code": "$pattern {$block inner {<}{>}} {X[$inner]}\n<outer <middle <deep>> more>",
138
+ "code": "$pattern {${<}{>}inner} {X[$inner]}\n<outer <middle <deep>> more>",
139
139
  "expected": "X[outer <middle <deep>> more]"
140
140
  },
141
141
  {
142
142
  "id": 24,
143
143
  "name": "Block delimiter balancing - square brackets",
144
- "code": "$pattern {$block data {[}{]}} {DATA[$data]}\n[outer [inner [deep]] more]",
144
+ "code": "$pattern {${[}{]}data} {DATA[$data]}\n[outer [inner [deep]] more]",
145
145
  "expected": "DATA[outer [inner [deep]] more]"
146
146
  },
147
147
  {
148
148
  "id": 25,
149
149
  "name": "Block delimiter balancing - curly braces",
150
- "code": "$pattern {$block obj {}{}} {OBJ[$obj]}\n{key: {nested: {value}}}",
150
+ "code": "$pattern {${}{}obj} {OBJ[$obj]}\n{key: {nested: {value}}}",
151
151
  "expected": "OBJ[key: {nested: {value}}]"
152
152
  },
153
153
  {
154
154
  "id": 26,
155
155
  "name": "Multiple nested delimiters in same pattern",
156
- "code": "$pattern {$block a {(}{)} $block b {[}{]}} {[$a|$b]}\n(test1) [test2]",
156
+ "code": "$pattern {${(}{)}a ${[}{]}b} {[$a|$b]}\n(test1) [test2]",
157
157
  "expected": "[test1|test2]"
158
158
  },
159
159
  {
@@ -165,25 +165,25 @@
165
165
  {
166
166
  "id": 28,
167
167
  "name": "Block with quotes as delimiters",
168
- "code": "$pattern {$block str {\"}{\"}} {STRING[$str]}\n\"hello world\"",
168
+ "code": "$pattern {${\"}{\"}str} {STRING[$str]}\n\"hello world\"",
169
169
  "expected": "STRING[hello world]"
170
170
  },
171
171
  {
172
172
  "id": 29,
173
173
  "name": "Block with pipe delimiters",
174
- "code": "$pattern {$block val {|}{|}} {PIPE[$val]}\n|content here|",
174
+ "code": "$pattern {${|}{|}val} {PIPE[$val]}\n|content here|",
175
175
  "expected": "PIPE[content here]"
176
176
  },
177
177
  {
178
178
  "id": 30,
179
179
  "name": "Deeply nested block delimiters",
180
- "code": "$pattern {$block deep {<}{>}} {[$deep]}\n<a <b <c <d> c> b> a>",
180
+ "code": "$pattern {${<}{>}deep} {[$deep]}\n<a <b <c <d> c> b> a>",
181
181
  "expected": "[a <b <c <d> c> b> a]"
182
182
  },
183
183
  {
184
184
  "id": 31,
185
185
  "name": "Two sequential patterns",
186
- "code": "$pattern {$block content {(}{)}} {BLOCK [$content]}\n$pattern {BLOCK $x} {RESULT: $x}\n(inner data)",
186
+ "code": "$pattern {${(}{)}content} {BLOCK [$content]}\n$pattern {BLOCK $x} {RESULT: $x}\n(inner data)",
187
187
  "expected": "RESULT: [inner data]"
188
188
  },
189
189
  {
@@ -195,13 +195,13 @@
195
195
  {
196
196
  "id": 33,
197
197
  "name": "Block delimiter edge case - empty content",
198
- "code": "$pattern {$block empty {(}{)}} {EMPTY[$empty]}\n()",
198
+ "code": "$pattern {${(}{)}empty} {EMPTY[$empty]}\n()",
199
199
  "expected": "EMPTY[]"
200
200
  },
201
201
  {
202
202
  "id": 34,
203
203
  "name": "Multi-char delimiters with nesting",
204
- "code": "$pattern {$block code {<<}{>>}} {CODE[$code]}\n<<outer <<inner>> more>>",
204
+ "code": "$pattern {${<<}{>>}code} {CODE[$code]}\n<<outer <<inner>> more>>",
205
205
  "expected": "CODE[outer <<inner>> more]"
206
206
  },
207
207
  {