papagaio 0.1.8 → 0.2.3

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 CHANGED
@@ -1,336 +1,357 @@
1
- # Papagaio Preprocessor
1
+ # Papagaio
2
2
 
3
- Papagaio is a lightweight, class‑based text preprocessor designed to support pattern rewriting, macro expansion, scoped transforms, and embedded JavaScript evaluation. It is engineered to be predictable, recursion‑safe, and easily embeddable in any JavaScript runtime.
4
-
5
- ---
6
-
7
- ## Overview
8
-
9
- Papagaio processes an input string through a deterministic multi‑stage pipeline:
10
-
11
- 1. **Scope blocks** (recursive processing)
12
- 2. **Eval blocks** (JS execution)
13
- 3. **Macro collection**
14
- 4. **Pattern collection**
15
- 5. **Pattern application**
16
- 6. **Macro expansion**
17
-
18
- The engine runs until it reaches a fixed point or hits the recursion limit.
19
-
20
- Papagaio supports **nested delimiters**, **custom sigils**, and **configurable keywords**.
21
-
22
- ---
3
+ Minimal yet powerful text preprocessor.
23
4
 
24
5
  ## Installation
25
6
 
26
- Papagaio ships as a standalone ES module.
27
-
28
- ```js
29
- import { Papagaio } from "./papagaio.js";
7
+ ```javascript
8
+ import { Papagaio } from './src/papagaio.js';
9
+ const p = new Papagaio();
10
+ const result = p.process(input);
30
11
  ```
31
12
 
32
- ---
33
-
34
- ## Basic Usage
13
+ ## Configuration
35
14
 
36
- ```js
37
- const p = new Papagaio();
38
- const output = p.process("pattern {a} {b} a a a");
39
- console.log(output); // "b b b"
15
+ ```javascript
16
+ p.open = "{"; // opening delimiter
17
+ p.close = "}"; // closing delimiter
18
+ p.sigil = "$"; // variable marker
19
+ p.maxRecursion = 512; // iteration limit
40
20
  ```
41
21
 
42
22
  ---
43
23
 
44
- ## Core Features
24
+ ## Core Concepts
45
25
 
46
- ### 1. Pattern Blocks
47
-
48
- Patterns rewrite text using a match → replacement structure:
26
+ ### 1. Simple Variables
49
27
 
50
28
  ```
51
- pattern { MATCH } { REPLACEMENT }
29
+ pattern {$x} {$x}
30
+ hello
52
31
  ```
32
+ Output: `hello`
53
33
 
54
- Patterns are collected once per iteration and applied globally.
34
+ Variables capture words (non-whitespace sequences).
55
35
 
56
- Example:
36
+ ### 2. Multiple Variables
57
37
 
58
38
  ```
59
- pattern {hello} {hi}
60
- hello world
39
+ pattern {$x $y $z} {$z, $y, $x}
40
+ apple banana cherry
61
41
  ```
42
+ Output: `cherry, banana, apple`
62
43
 
63
- Output:
44
+ ### 3. Flexible Whitespace (`$$`)
64
45
 
65
46
  ```
66
- hi world
47
+ pattern {$x$$and$$$y} {$x & $y}
48
+ hello and world
49
+ hello and world
67
50
  ```
51
+ Output: `hello & world` (both)
68
52
 
69
- #### Variables
53
+ `$$` = zero or more spaces/tabs/newlines.
70
54
 
71
- Variables use the configured **sigil** (default `$`).
55
+ ### 4. Literal Output (`$$`)
72
56
 
73
57
  ```
74
- pattern {say $x} {[$x]}
75
- say hello
58
+ Price: $$50
76
59
  ```
60
+ Output: `Price: $50`
77
61
 
78
- `[hello]`
62
+ Use `$$` for literal `$` output.
79
63
 
80
- #### Balanced Block Variables
81
-
82
- Papagaio supports deep matching of balanced blocks:
83
-
84
- ```
85
- pattern {($x)} {[BLOCK:$x]}
86
- (do something)
87
- ```
64
+ ---
88
65
 
89
- `[BLOCK:do something]`
66
+ ## Blocks
90
67
 
91
- #### Spread Variables
68
+ Capture content between delimiters.
92
69
 
93
- Spread variables capture until a terminating token:
70
+ ### Syntax
94
71
 
95
72
  ```
96
- pattern {from $x...to} {$x}
97
- from A B C to
73
+ $block name {open}{close}
98
74
  ```
99
75
 
100
- `A B C`
101
-
102
- #### Metavariables
103
-
104
- Papagaio provides special `$keywords` inside replacements:
105
-
106
- | Variable | Meaning |
107
- | --------- | ------------------------------------------ |
108
- | `$match` | Full matched text |
109
- | `$pre` | Text before match |
110
- | `$post` | Text after match |
111
- | `$unique` | Auto‑increment unique token |
112
- | `$$` | Whitespace wildcard in patterns |
113
- | `$clear` | Triggers clear‑rewrite of last replacement |
114
-
115
- Example:
76
+ ### Example
116
77
 
117
78
  ```
118
- pattern {x} {$pre[${unique}]$post}
119
- abcxdef
79
+ pattern {$block content {(}{)}} {[$content]}
80
+ data ( hello world )
120
81
  ```
82
+ Output: `[hello world]`
121
83
 
122
- ---
123
-
124
- ### 2. Macro Blocks
125
-
126
- Macros behave like simple template functions.
84
+ ### Custom Delimiters
127
85
 
128
86
  ```
129
- macro name { BODY }
130
- name(arg1, arg2)
87
+ pattern {$block data {<<}{>>}} {DATA: $data}
88
+ <<json stuff>>
131
89
  ```
90
+ Output: `DATA: json stuff`
132
91
 
133
- Example:
92
+ ### Multiple Blocks
134
93
 
135
94
  ```
136
- macro wrap {[$1][$2]}
137
- wrap(a, b)
95
+ pattern {$block a {(}{)}, $block b {[}{]}} {$a|$b}
96
+ (first), [second]
138
97
  ```
98
+ Output: `first|second`
139
99
 
140
- → `[a][b]`
141
-
142
- #### Argument Mapping
100
+ ---
143
101
 
144
- Arguments map to `$1`, `$2`, … automatically. `$0` expands to the macro name.
102
+ ## Patterns
145
103
 
146
- Example:
104
+ ### Basic
147
105
 
148
106
  ```
149
- macro tag {<$0 $1>}
150
- tag(title)
107
+ pattern {match} {replace}
151
108
  ```
152
109
 
153
- `<tag title>`
154
-
155
- ---
156
-
157
- ### 3. Eval Blocks
158
-
159
- Executes embedded JavaScript and returns the result as a string.
110
+ ### Real Example
160
111
 
161
112
  ```
162
- eval { return 3 + 7 }
113
+ pattern {# $title} {<h1>$title</h1>}
114
+ # Welcome
163
115
  ```
116
+ Output: `<h1>Welcome</h1>`
164
117
 
165
- `10`
166
-
167
- Eval executes inside a strict IIFE.
168
-
169
- You may access:
170
-
171
- * `papagaio` → the processor instance
172
- * `ctx` → an empty object for temporary state
173
-
174
- Example:
118
+ ### Multiple Patterns
175
119
 
176
120
  ```
177
- pattern {sum $a $b} {eval { return Number($a) + Number($b) }}
178
- sum 2 8
121
+ pattern {a} {b}
122
+ pattern {b} {c}
123
+ pattern {c} {d}
124
+ a
179
125
  ```
180
-
181
- → `10`
126
+ Output: `d` (automatic cascade)
182
127
 
183
128
  ---
184
129
 
185
- ### 4. Scope Blocks
130
+ ## Contexts
186
131
 
187
- Scope blocks create isolated processing regions using the same pipeline.
132
+ Recursive processing scope.
188
133
 
189
134
  ```
190
- scope {
191
- pattern {x} {y}
192
- x x x
135
+ context {
136
+ pattern {$x} {<$x>}
137
+
138
+ apple
139
+ banana
193
140
  }
194
141
  ```
142
+ Output:
143
+ ```
144
+ <apple>
145
+ <banana>
146
+ ```
195
147
 
196
- `y y y`
197
-
198
- Scopes do not leak macros or patterns to the outside.
148
+ **Empty contexts are automatically removed.**
199
149
 
200
150
  ---
201
151
 
202
- ## Delimiters
152
+ ## Special Keywords
203
153
 
204
- Papagaio supports configurable opening/closing pairs.
154
+ ### $unique
155
+ Generate unique incremental IDs.
205
156
 
206
- ```js
207
- p.delimiters = [["{", "}"], ["(", ")"]];
208
157
  ```
158
+ pattern {item} {item_$unique}
159
+ item
160
+ item
161
+ item
162
+ ```
163
+ Output: `item_u0`, `item_u1`, `item_u2`
209
164
 
210
- Balanced variable matching works across all registered delimiter pairs.
211
-
212
- ---
213
-
214
- ## Recursion Model
215
-
216
- Papagaio runs a fixed‑point loop:
217
-
218
- 1. Process scopes
219
- 2. Process eval blocks
220
- 3. Collect macros
221
- 4. Collect top‑level patterns
222
- 5. Apply patterns
223
- 6. Expand macros
165
+ ### $match
166
+ Return the full match.
224
167
 
225
- If any Papagaio keyword remains in the output, it repeats.
168
+ ```
169
+ pattern {[$x]} {FOUND: $match}
170
+ [data]
171
+ ```
172
+ Output: `FOUND: [data]`
226
173
 
227
- You can configure the iteration cap:
174
+ ### $prefix / $suffix
175
+ Text before and after the match.
228
176
 
229
- ```js
230
- p.maxRecursion = 256;
231
177
  ```
178
+ pattern {$x} {BEFORE:$prefix | AFTER:$suffix}
179
+ hello world test
180
+ ```
181
+ Output: `BEFORE: | AFTER: world test`
232
182
 
233
- ---
183
+ ### $clear
184
+ Remove everything before the match.
234
185
 
235
- ## Error Handling
186
+ ```
187
+ pattern {SKIP $x} {$clear KEEP: $x}
188
+ IGNORE_THIS SKIP keep_this
189
+ ```
190
+ Output: `KEEP: keep_this`
236
191
 
237
- Eval blocks are wrapped in a try/catch. Exceptions produce empty output.
192
+ ### $eval
193
+ Execute JavaScript code.
238
194
 
239
- Pattern/macro recursion halts upon reaching `maxRecursion`.
195
+ ```
196
+ pattern {$x} {$eval{return parseInt($x) * 2;}}
197
+ 5
198
+ ```
199
+ Output: `10`
240
200
 
241
201
  ---
242
202
 
243
- ## Advanced Examples
203
+ ## Practical Examples
244
204
 
245
- ### Nested Macros
205
+ ### Markdown → HTML
246
206
 
247
207
  ```
248
- macro A {($1)}
249
- macro B {A($1)}
250
- B(hello)
208
+ context {
209
+ pattern {# $t} {<h1>$t</h1>}
210
+ pattern {## $t} {<h2>$t</h2>}
211
+ pattern {**$t**} {<strong>$t</strong>}
212
+ pattern {*$t*} {<em>$t</em>}
213
+ pattern {- $i} {<li>$i</li>}
214
+
215
+ # Title
216
+ **bold** and *italic*
217
+ - item1
218
+ - item2
219
+ }
251
220
  ```
252
221
 
253
- `(hello)`
254
-
255
- ### Dynamic Rewriting with `$unique`
222
+ ### CSV JSON
256
223
 
257
224
  ```
258
- pattern {node} {id_$unique}
259
- node node node
225
+ pattern {$a,$b,$c} {{ id: '$a', name: '$b', role: '$c' }}
226
+ 1,Alice,Engineer
227
+ 2,Bob,Designer
260
228
  ```
261
229
 
262
- → `id_0 id_1 id_2`
230
+ Output:
231
+ ```
232
+ { id: '1', name: 'Alice', role: 'Engineer' }
233
+ { id: '2', name: 'Bob', role: 'Designer' }
234
+ ```
263
235
 
264
- ### Working with Pre/Post Context
236
+ ### Config Parser
265
237
 
266
238
  ```
267
- pattern {x} {$pre|X|$post}
268
- a x b
239
+ pattern {$key = $value} {const $key = '$value';}
240
+ host = localhost
241
+ port = 3000
269
242
  ```
270
243
 
271
- → `a |X| b`
244
+ Output:
245
+ ```
246
+ const host = 'localhost';
247
+ const port = '3000';
248
+ ```
272
249
 
273
- ### Spread Matching
250
+ ### HTML Generator
274
251
 
275
252
  ```
276
- pattern {let $name = $v...;} {[decl $name $v]}
277
- let x = 1 + 2 + 3;
253
+ pattern {$tag $content} {<$tag>$content</$tag>}
254
+ div HelloWorld
255
+ span Test
278
256
  ```
279
257
 
280
- → `[decl x 1 + 2 + 3]`
258
+ Output:
259
+ ```
260
+ <div>HelloWorld</div>
261
+ <span>Test</span>
262
+ ```
281
263
 
282
264
  ---
283
265
 
284
- ## API Reference
285
-
286
- ### Class: `Papagaio`
287
-
288
- #### `process(input: string): string`
289
-
290
- Runs the full pipeline and returns the transformed text.
266
+ ## Important Rules
291
267
 
292
- #### `delimiters: Array<[string, string]>`
268
+ ### Matching
269
+ - Variables (`$x`) capture **one word** (no spaces)
270
+ - `$$` = flexible whitespace (0+ spaces/tabs/newlines)
271
+ - Patterns apply **globally** each iteration
272
+ - Auto-recursion until: max 512 iterations OR no changes
293
273
 
294
- List of opening/closing delimiter pairs.
274
+ ### Block Matching
275
+ - `$block name {open}{close}` captures between delimiters
276
+ - Supports nested delimiters automatically
277
+ - Multiple blocks in one pattern work
295
278
 
296
- #### `sigil: string`
279
+ ### Variables
280
+ - Names: `[A-Za-z0-9_]`
281
+ - Reuse: `$x` appears multiple times in replace
282
+ - Undefined: becomes empty string
297
283
 
298
- Variable prefix. Default `$`.
299
-
300
- #### `keywords`
284
+ ---
301
285
 
302
- Keyword configuration:
286
+ ## Troubleshooting
303
287
 
304
- * `pattern`
305
- * `macro`
306
- * `eval`
307
- * `scope`
288
+ | Problem | Solution |
289
+ |---------|----------|
290
+ | Pattern doesn't match | Use `$$` between elements for flexible whitespace |
291
+ | Variable not captured | Check space between variables |
292
+ | Block not working | Verify balanced delimiters `{` `}` |
293
+ | Infinite recursion | Use `$clear` or reduce `maxRecursion` |
294
+ | $eval not working | Errors return empty string, use try-catch |
308
295
 
309
- #### Internal State
296
+ ---
310
297
 
311
- For debugging only:
298
+ ## Performance
312
299
 
313
- * `content` latest processed text
314
- * `#matchContent`
315
- * `#scopeContent`
316
- * `#evalContent`
300
+ - Simple patterns > complex patterns
301
+ - Blocks have minor overhead
302
+ - Avoid unlimited recursion
303
+ - For large inputs, use multiple contexts
317
304
 
318
305
  ---
319
306
 
320
- ## Embedding
307
+ ## Syntax Reference
321
308
 
322
- Papagaio is pure JS and safe to embed in build pipelines, CLIs, game engines, or runtime scripting layers.
309
+ ```
310
+ pattern {$x $y} {$y, $x} # basic pattern
311
+ pattern {$x$$y} {$x-$y} # flexible whitespace
312
+ pattern {$block n {o}{c}} {$n} # block
313
+ context { ... } # recursive scope
314
+ $$literal # output literal $
315
+ $unique # unique ID
316
+ $match # full match
317
+ $prefix / $suffix # before/after
318
+ $clear # clear before
319
+ $eval{code} # execute JS
320
+ ```
323
321
 
324
- Example minimal CLI wrapper:
322
+ ---
325
323
 
326
- ```js
327
- #!/usr/bin/env node
328
- const fs = require("fs");
329
- const { Papagaio } = require("./papagaio");
324
+ ## Complete Example
325
+
326
+ ```
327
+ context {
328
+ # Markdown headers
329
+ pattern {# $title} {<h1>$title</h1>}
330
+ pattern {## $title} {<h2>$title</h2>}
331
+
332
+ # Lists
333
+ pattern {- $item} {<li>$item</li>}
334
+
335
+ # Inline formatting
336
+ pattern {**$text**} {<strong>$text</strong>}
337
+ pattern {*$text*} {<em>$text</em>}
338
+
339
+ # Process content
340
+ # Welcome
341
+ ## Getting Started
342
+ This is **important** and *italic*
343
+ - First item
344
+ - Second item
345
+ }
346
+ ```
330
347
 
331
- const input = fs.readFileSync(0, "utf8");
332
- const out = new Papagaio().process(input);
333
- process.stdout.write(out);
348
+ Output:
349
+ ```html
350
+ <h1>Welcome</h1>
351
+ <h2>Getting Started</h2>
352
+ This is <strong>important</strong> and <em>italic</em>
353
+ <li>First item</li>
354
+ <li>Second item</li>
334
355
  ```
335
356
 
336
- ---
357
+ ---
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { Papagaio } from "./papagaio.js";
2
+ import { Papagaio } from "../src/papagaio.js";
3
3
  import fs from "fs";
4
4
  import { createRequire } from "module";
5
5
  const require = createRequire(import.meta.url);
6
- const pkg = require("./package.json");
6
+ const pkg = require("../package.json");
7
7
 
8
8
 
9
9
  // Help & Version
package/index.html CHANGED
@@ -301,7 +301,7 @@
301
301
  </div>
302
302
 
303
303
  <script type="module">
304
- import { Papagaio } from './papagaio.js';
304
+ import { Papagaio } from './src/papagaio.js';
305
305
 
306
306
  let processor = null;
307
307
 
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "papagaio",
3
- "version": "0.1.8",
3
+ "version": "0.2.3",
4
4
  "description": "easy yet powerful preprocessor",
5
- "main": "papagaio.js",
5
+ "main": "src/papagaio.js",
6
6
  "type": "module",
7
+ "scripts": {
8
+ "test": "node tests/test.js"
9
+ },
7
10
  "repository": {
8
11
  "type": "git",
9
12
  "url": "git+https://github.com/jardimdanificado/papagaio.git"
@@ -13,16 +16,14 @@
13
16
  "macro",
14
17
  "pattern",
15
18
  "eval",
16
- "isolate",
17
19
  "parser"
18
20
  ],
19
21
  "author": "jardimdanificado",
20
22
  "bugs": {
21
23
  "url": "https://github.com/jardimdanificado/papagaio/issues"
22
24
  },
23
- "homepage": "https://github.com/jardimdanificado/papagaio#readme"
24
- ,
25
+ "homepage": "https://github.com/jardimdanificado/papagaio#readme",
25
26
  "bin": {
26
- "papagaio": "./cli.js"
27
+ "papagaio": "./bin/cli.js"
27
28
  }
28
- }
29
+ }