papagaio 0.37.3 → 0.39.2

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
@@ -178,6 +178,14 @@ The **`$from`** operator allows you to capture processed content and assign it t
178
178
  2. **Immediate Registration**: The variable is registered as an exact-match rule as soon as it is parsed. This allows for **chained assignments**.
179
179
  3. **Output Suppression**: The entire `$from` directive is removed from the output text.
180
180
 
181
+ ### Lexical Scopes and Sandboxing
182
+
183
+ Every block operator or preprocessing field evaluated dynamically (such as inside `$from`, `$then`, `$else`, `$while`, `$repeat`, and `$until`) is executed in its own **local nested scope**.
184
+
185
+ - **Sandboxing**: Any variable declared inside a local scope (e.g. `$B$from{local_val}` inside `$A$from{...}`) that does *not* exist in a parent scope is treated as a local variable. It will be completely destroyed and freed when the block finishes evaluating (sandboxed).
186
+ - **Shadowing & Upward Updates**: If a variable updated inside a local scope already exists in a parent/ancestor scope, Papagaio avoids shadowing it. Instead, it propagates the update upwards, modifying the existing variable in the parent scope.
187
+ - **Recursive Nesting**: Local scopes can be nested arbitrarily. Each child scope has full read/write access to variables in parent scopes, but parent or sibling scopes do not have access to variables declared exclusively in child scopes.
188
+
181
189
  ### Examples
182
190
 
183
191
  #### Chained Assignments
@@ -218,25 +226,29 @@ Any variable can be treated as a list by accessing it through the `$list` modifi
218
226
  ### Syntax
219
227
 
220
228
  ```
221
- $VARNAME$list$OPERATION{separator}{...arguments}
229
+ $VARNAME$list{separator}$OPERATION{...arguments}
222
230
  ```
223
231
 
224
232
  ### Operations
225
233
 
226
234
  | Operation | Signature | Emits | Mutates |
227
235
  |---|---|---|---|
228
- | `get` | `$V$list$get{sep}{idx}` | Element at index | No |
229
- | `set` | `$V$list$set{sep}{idx}{content}` | Nothing | Yes |
230
- | `push` | `$V$list$push{sep}{content}` | Nothing | Yes |
231
- | `pop` | `$V$list$pop{sep}` | Last element | Yes |
232
- | `shift` | `$V$list$shift{sep}` | First element | Yes |
233
- | `unshift` | `$V$list$unshift{sep}{content}` | Nothing | Yes |
234
- | `insert` | `$V$list$insert{sep}{idx}{content}` | Nothing | Yes |
235
- | `remove` | `$V$list$remove{sep}{idx}` | Nothing | Yes |
236
- | `swap` | `$V$list$swap{sep}{idx_a}{idx_b}` | Nothing | Yes |
237
- | `reverse` | `$V$list$reverse{sep}` | Nothing | Yes |
238
- | `count` | `$V$list$count{sep}` | Number of elements | No |
239
- | `join` | `$V$list$join{sep_orig}{sep_new}` | List with new separator | No |
236
+ | `get` | `$V$list{sep}$get{idx}` | Element at index | No |
237
+ | `set` | `$V$list{sep}$set{idx}{content}` | Nothing | Yes |
238
+ | `push` | `$V$list{sep}$push{content}` | Nothing | Yes |
239
+ | `pop` | `$V$list{sep}$pop` | Last element | Yes |
240
+ | `shift` | `$V$list{sep}$shift` | First element | Yes |
241
+ | `unshift` | `$V$list{sep}$unshift{content}` | Nothing | Yes |
242
+ | `insert` | `$V$list{sep}$insert{idx}{content}` | Nothing | Yes |
243
+ | `remove` | `$V$list{sep}$remove{idx}` | Nothing | Yes |
244
+ | `swap` | `$V$list{sep}$swap{idx_a}{idx_b}` | Nothing | Yes |
245
+ | `reverse` | `$V$list{sep}$reverse` | Nothing | Yes |
246
+ | `count` | `$V$list{sep}$count` | Number of elements | No |
247
+ | `join` | `$V$list{sep_orig}$join{sep_new}` | List with new separator | No |
248
+ | `slice` | `$V$list{sep}$slice{start}{end}` | Sub-list from start to end | No |
249
+ | `find` | `$V$list{sep}$find{pat}` | First **whole element** matching `pat` | No |
250
+ | `contains` | `$V$list{sep}$contains{pat}` | Index of `pat` **within** matching element | No |
251
+ | `replace` | `$V$list{sep}$replace{pat}{rep}` | First match found; updates the **whole element** | Yes |
240
252
 
241
253
  **Index rules**: zero-based; negative indices count from the end (`-1` = last); out-of-range access emits `""` silently.
242
254
 
@@ -245,39 +257,42 @@ $VARNAME$list$OPERATION{separator}{...arguments}
245
257
  ```text
246
258
  $FRUITS$from{apple,banana,orange}
247
259
 
248
- $FRUITS$list$get{,}{0} → apple
249
- $FRUITS$list$get{,}{-1} → orange
250
- $FRUITS$list$count{,} → 3
260
+ $FRUITS$list{,}$get{0} → apple
261
+ $FRUITS$list{,}$get{-1} → orange
262
+ $FRUITS$list{,}$count → 3
251
263
  ```
252
264
 
253
265
  ```text
254
266
  $L$from{a,b,c}
255
- $L$list$push{,}{d}
256
- $L$list$set{,}{1}{B}
267
+ $L$list{,}$push{d}
268
+ $L$list{,}$set{1}{B}
257
269
  $L → a,B,c,d
258
270
  ```
259
271
 
260
272
  ```text
261
273
  $STACK$from{x,y,z}
262
- Popped: $STACK$list$pop{,}
274
+ Popped: $STACK$list{,}$pop
263
275
  Rest: $STACK → Popped: z / Rest: x,y
264
276
  ```
265
277
 
266
278
  ```text
267
279
  $CSV$from{one,two,three}
268
- $CSV$list$join{,}{ | } → one | two | three
280
+ $CSV$list{,}$join{ | } → one | two | three
269
281
  ```
270
282
 
271
283
  ```text
272
284
  $PATH$from{/usr/local/bin}
273
- $PATH$list$get{/}{-1} → bin
285
+ $PATH$list{/}$get{-1} → bin
274
286
  ```
275
287
 
276
288
  ```text
277
289
  /* Dynamic separator from variable */
278
290
  $SEP$from{,}
279
291
  $L$from{x,y,z}
280
- $L$list$get{$SEP}{2} → z
292
+ $L$list{$SEP}$get{2} → z
293
+
294
+ $L$from{a,b,c,d,e}
295
+ $L$list{,}$slice{1}{4} → b,c,d
281
296
  ```
282
297
 
283
298
  ---
@@ -290,6 +305,10 @@ Papagaio provides operators for conditional logic and value chaining. These are
290
305
 
291
306
  ```
292
307
  $VAL$compare{target}
308
+ $VAL$find{pattern}
309
+ $VAL$contains{pattern}
310
+ $VAL$replace{pattern}{replacement}
311
+ $VAL$slice{start}{end}
293
312
  $VAL$then{content}
294
313
  $VAL$else{content}
295
314
  ```
@@ -297,8 +316,12 @@ $VAL$else{content}
297
316
  | Operator | Behavior |
298
317
  |---|---|
299
318
  | **`compare`** | If `$VAL` matches `target`, emits `$VAL`. Otherwise, emits `""`. |
300
- | **`then`** | If `$VAL` is **not empty**, processes and emits `code`. Otherwise, emits `""`. |
301
- | **`else`** | If `$VAL` **is empty**, processes and emits `code`. Otherwise, passes `$VAL` through. |
319
+ | **`find`** | Performs a non-anchored search for `pattern` in `$VAL`. Emits the matched substring. |
320
+ | **`contains`** | Performs a non-anchored search. Emits the character index of the first match (or `""`). |
321
+ | **`replace`** | Replaces the first match of `pattern` with `replacement`. Emits the OLD match. |
322
+ | **`slice`** | Returns a substring from `start` to `end`. Supports negative indices. |
323
+ | **`then`** | If `$VAL` is **not empty**, processes and emits `content`. Otherwise, emits `""`. |
324
+ | **`else`** | If `$VAL` **is empty**, processes and emits `content`. Otherwise, passes `$VAL` through. |
302
325
  | **`repeat`** | `$repeat{N}{code}` | Executes `code` N times. Emits nothing; used for side effects. |
303
326
  | **`while`** | `$while{pat}{code}` | Executes `code` while its result matches `pat`. Emits the last successful result. |
304
327
  | **`until`** | `$until{pat}{code}` | Executes `code` until its result matches `pat`. Emits the match that caused the break. |
@@ -320,6 +343,21 @@ $A$compare{world}$then{Matched!} → (empty)
320
343
  $A$from{abc}
321
344
  $A$compare{abc}$then{YES}$else{NO} → YES
322
345
  $A$compare{xyz}$then{YES}$else{NO} → NO
346
+
347
+ #### Search and Extract:
348
+ ```text
349
+ $A$from{user_id: 12345}
350
+ $A$find{$d+}$ → 12345
351
+ $A$contains{id} → 5
352
+ $A$replace{$d+}{HIDDEN} $A → 12345 user_id: HIDDEN
353
+
354
+ #### Slicing:
355
+ ```text
356
+ $A$from{hello world}
357
+ $A$slice{0}{5} → hello
358
+ $A$slice{-5} → world
359
+ ```
360
+ ```
323
361
  ```
324
362
 
325
363
  ### Standalone and Braced Usage
@@ -330,7 +368,7 @@ $A$compare{xyz}$then{YES}$else{NO} → NO
330
368
  #### Example:
331
369
  ```text
332
370
  $L$from{a,b,c}
333
- $R$from{$L$list$get{,}{0}}
371
+ $R$from{$L$list{,}$get{0}}
334
372
  $R$compare{a}$then{Is A}$else{Not A} → Is A
335
373
  ```
336
374
 
@@ -20,8 +20,6 @@ class Papagaio {
20
20
 
21
21
  registerCommand(name, handler) {
22
22
  // Note: Implementing JS->C callbacks requires addFunction and extra glue.
23
- // For now, we warn that this is not yet supported in the pure WASM wrapper.
24
- console.warn(`[WASM] Warning: registerCommand('${name}') is not supported in JS wrapper yet.`);
25
23
  }
26
24
 
27
25
  setArgs(argv) {
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "papagaio",
3
- "version": "0.37.3",
3
+ "version": "0.39.2",
4
4
  "description": "easy yet powerful preprocessor",
5
5
  "main": "dist/wasm/papagaio.js",
6
6
  "bin": {
@@ -26,7 +26,6 @@
26
26
  "eval",
27
27
  "parser",
28
28
  "codegen",
29
- "regex",
30
29
  "syntax",
31
30
  "easy"
32
31
  ],