producs 1.0.1 → 3.0.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/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # ProDucs v3.0
2
+
3
+ **Professional Documentation Shell DSL** — a modular, pipeable terminal scripting language for advanced CLI documentation and automation.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install # install deps
9
+ npm link # optional: install `producs` globally
10
+ ```
11
+
12
+ ## Run
13
+
14
+ ```bash
15
+ node cli.js script.pd # run a .pd file
16
+ node cli.js --demo # built-in feature demo
17
+ node cli.js --ast script.pd # dump AST as JSON
18
+ node cli.js --help # full usage
19
+ ```
20
+
21
+ Or if installed globally:
22
+ ```bash
23
+ producs script.pd
24
+ ```
25
+
26
+ ---
27
+
28
+ ## Syntax
29
+
30
+ ```
31
+ // line comment
32
+
33
+ #$CommandName['arg1','arg2'] inline command
34
+ #$Cmd1 | #$Cmd2 | #$Cmd3 pipe chain (output of each → input of next)
35
+ ${varname} variable interpolation
36
+
37
+ #$BlockName['arg'] open a block
38
+ ...children...
39
+ #$End_BlockName close the block
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Branching
45
+
46
+ ProDucs replaces if/else with an explicit **check → branch** model:
47
+
48
+ 1. A `Check_*` command runs and sets `failed=0` (pass) or `failed=1` (fail)
49
+ 2. `#$Branch` runs its children only when `failed=0`
50
+ 3. `#$BranchElse` runs its children only when `failed=1`
51
+
52
+ ```
53
+ #$Set['score','92']
54
+ #$Check_gte['score','90']
55
+ #$Branch
56
+ #$Color['green','A grade!']
57
+ #$End_Branch
58
+ #$BranchElse
59
+ #$Color['yellow','Below A grade']
60
+ #$End_BranchElse
61
+ ```
62
+
63
+ ---
64
+
65
+ ## All Check Commands
66
+
67
+ ### String checks (operate on `VALUE`)
68
+
69
+ | Command | Description |
70
+ |---|---|
71
+ | `Check_eq['expected']` | Pass if VALUE === expected |
72
+ | `Check_neq['expected']` | Pass if VALUE !== expected |
73
+ | `Check_contains['needle']` | Pass if VALUE contains needle |
74
+ | `Check_not_contains['needle']` | Pass if VALUE does NOT contain needle |
75
+ | `Check_starts['prefix']` | Pass if VALUE starts with prefix |
76
+ | `Check_ends['suffix']` | Pass if VALUE ends with suffix |
77
+ | `Check_matches['regex','flags']` | Pass if VALUE matches regex |
78
+ | `Check_empty` | Pass if VALUE is empty string |
79
+ | `Check_nonempty` | Pass if VALUE is not empty |
80
+
81
+ ### Numeric checks
82
+
83
+ Two forms: `Check_gt['varname','number']` or `Check_gt['number']` (uses VALUE as number).
84
+
85
+ | Command | Description |
86
+ |---|---|
87
+ | `Check_gt['var','n']` | Pass if var > n |
88
+ | `Check_gte['var','n']` | Pass if var >= n |
89
+ | `Check_lt['var','n']` | Pass if var < n |
90
+ | `Check_lte['var','n']` | Pass if var <= n |
91
+ | `Check_num_eq['var','n']` | Pass if var == n (numeric) |
92
+ | `Check_num_neq['var','n']` | Pass if var != n (numeric) |
93
+ | `Check_between['var','lo','hi']` | Pass if lo <= var <= hi |
94
+
95
+ ### Variable comparison
96
+
97
+ | Command | Description |
98
+ |---|---|
99
+ | `Check_var_eq['a','b']` | Pass if var a === var b |
100
+ | `Check_var_neq['a','b']` | Pass if var a !== var b |
101
+
102
+ ### Result checks
103
+
104
+ | Command | Description |
105
+ |---|---|
106
+ | `Check_failed` | Pass if previous result was failed |
107
+ | `Check_passed` | Pass if previous result was passed |
108
+ | `Check_failed_error['msg']` | Throw error if previous result was failed |
109
+ | `Check_passed_error['msg']` | Throw error if previous result passed |
110
+
111
+ ---
112
+
113
+ ## Command Reference
114
+
115
+ ### I/O
116
+ | Command | Description |
117
+ |---|---|
118
+ | `> ['prompt']` | Prompt user for input |
119
+ | `Print['text']` | Print to stdout |
120
+ | `Warn['text']` | Print yellow warning to stderr |
121
+ | `Error_print['text']` | Print red error to stderr |
122
+ | `Pause['msg']` | Block until ENTER |
123
+ | `Confirm['msg','default']` | y/n prompt |
124
+ | `Select['label','opt1',...]` | Numbered menu |
125
+
126
+ ### Variables
127
+ | Command | Description |
128
+ |---|---|
129
+ | `Set['name','value']` | Set a variable |
130
+ | `Unset['name']` | Delete a variable |
131
+ | `Export['name','value']` | Set variable and push to `process.env` |
132
+ | `Env_get['KEY']` | Read `process.env.KEY` → VALUE |
133
+ | `Env_set['KEY']` | Write VALUE → `process.env.KEY` |
134
+
135
+ ### Shell
136
+ | Command | Description |
137
+ |---|---|
138
+ | `Shell_run` | Run VALUE/text child as shell command (inherit stdio) |
139
+ | `Shell_capture` | Run command, capture stdout → VALUE |
140
+
141
+ ### String ops
142
+ `Trim` `Upper` `Lower` `Len` `Replace['pat','rep','flags']`
143
+ `Slice['start','end']` `Split['sep']` `Join['sep']`
144
+ `Default['fallback']` `Concat['suffix',...]`
145
+
146
+ ### Math
147
+ `Int` `Float` `Abs` `Round` `Floor` `Ceil`
148
+ `Math['expr']` `Inc['var','step']` `Dec['var','step']`
149
+
150
+ ### Data
151
+ `Hash['algo']` `Timestamp['iso'|'unix'|'ms']`
152
+ `Json_get['a.b.c']` `Json_set['a.b','val']`
153
+
154
+ ### File I/O
155
+ `Read_file['path']` `Write_file['path']` `Append_file['path']`
156
+
157
+ ### Control
158
+ `Goto['label']` `Label['name']` `Exit['code']`
159
+ `Assert['JS expr','msg']`
160
+ `Require_env['VAR']` `Require_cmd['cmd']`
161
+
162
+ ### Timing
163
+ `Wait['ms']` — blocking sleep in milliseconds
164
+
165
+ ### Blocks
166
+ | Block | Description |
167
+ |---|---|
168
+ | `#$> ['prompt']` | Prompt block |
169
+ | `#$Branch` | Run if last check passed (failed=0) |
170
+ | `#$BranchElse` | Run if last check failed (failed=1) |
171
+ | `#$Repeat['N']` | Loop N times (`_i` = index) |
172
+ | `#$ForEach['var','a','b',...]` | Iterate over items |
173
+ | `#$Try` + `#$Catch` | Error handling (`_error` set in Catch) |
174
+ | `#$Section['title']` | Formatted section heading |
175
+ | `#$Step['desc']` | Auto-numbered step |
176
+ | `#$Group['label']` | Logical grouping with bracket lines |
177
+ | `#$Table` + `#$Row[...]` | ASCII table |
178
+
179
+ ### Visual
180
+ `HR['char']` `Header['title']` `Color['name','text']`
181
+ `Progress['pct','width','label']` `Spinner['msg']` `Status['label']`
182
+
183
+ ### Runtime
184
+ `Debug['on'|'off']` `Strict['on'|'off']` `Color_off`
185
+ `Log['label']` `Dump_log` `Help` `Version`
186
+
187
+ ---
188
+
189
+ ## Example Script
190
+
191
+ ```
192
+ // install.pd — sample deployment doc script
193
+
194
+ #$Header['Deploy Checklist']
195
+ #$Require_cmd['git']
196
+ #$Require_cmd['node']
197
+
198
+ #$Section['Pre-flight']
199
+ #$Shell_capture['git branch --show-current'] | #$Set['branch']
200
+ #$Print['Branch: ${branch}']
201
+ #$Set['branch','${branch}'] | #$Check_eq['main']
202
+ #$BranchElse
203
+ #$Warn['Not on main branch!']
204
+ #$End_BranchElse
205
+ #$End_Section
206
+
207
+ #$Section['Build']
208
+ #$Step['Install dependencies']
209
+ #$Shell_run
210
+ npm ci
211
+ #$End_Shell_run
212
+ #$End_Step
213
+ #$End_Section
214
+
215
+ #$Status['Deploy complete']
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Programmatic API
221
+
222
+ ```js
223
+ const { ProDucs } = require("producs");
224
+
225
+ const prod = new ProDucs({ debug: false, strict: false, noColor: false });
226
+
227
+ // Register custom command
228
+ prod.register("Shout", (node, input) => {
229
+ const msg = input.VALUE.toUpperCase() + "!!!";
230
+ process.stdout.write(msg + "\n");
231
+ return { VALUE: msg, failed: 0 };
232
+ }, { doc: "Uppercase and add exclamation marks" });
233
+
234
+ // Pre-set variables
235
+ prod.set("env", "production");
236
+
237
+ // Run a script
238
+ prod.run(`
239
+ #$Set['greeting','hello']
240
+ #$Set['greeting','${greeting}'] | #$Shout
241
+ `);
242
+
243
+ // Read back vars
244
+ console.log(prod.vars()); // { greeting: "HELLO!!!", env: "production" }
245
+ ```
package/README.pd ADDED
@@ -0,0 +1,352 @@
1
+ // readme.pd — ProDucs interactive README + tutorial
2
+ // Run with: node cli.js examples/readme.pd
3
+
4
+ #$Header['ProDucs v3.0']
5
+ #$Print['Professional Documentation Shell DSL']
6
+ #$Print['A modular, pipeable terminal scripting language.']
7
+ #$HR
8
+
9
+ // ── Welcome ───────────────────────────────────────────────────────
10
+ #$Section['Welcome']
11
+ #$Print['Before we dive into the docs, let us show you how ProDucs works.']
12
+ #$Print['This README will teach you the syntax interactively.']
13
+ #$Print['']
14
+ #$Input['What is your name?'] | #$Set['user']
15
+ #$Color['green','Hey ${user}! Let us get started.']
16
+ #$End_Section
17
+
18
+ // ── Lesson 1: Commands ────────────────────────────────────────────
19
+ #$Section['Lesson 1: Commands']
20
+ #$Print['Every ProDucs command looks like this:']
21
+ #$Print['']
22
+ #$Color['cyan',' #$CommandName[arg1,arg2]']
23
+ #$Print['']
24
+ #$Print['For example, #$Print[hello] prints "hello" to the terminal.']
25
+ #$Print['Let us try it. Type something and we will print it back.']
26
+ #$Print['']
27
+ #$Input['Type anything:'] | #$Set['input1']
28
+ #$Print['']
29
+ #$Color['green',' → ${input1}']
30
+ #$Print['']
31
+ #$Color['dim','That was: #$Print[${input1}]']
32
+ #$Pause['Press ENTER to continue...']
33
+ #$End_Section
34
+
35
+ // ── Lesson 2: Variables ───────────────────────────────────────────
36
+ #$Section['Lesson 2: Variables']
37
+ #$Print['Variables are set with #$Set and referenced with ${name}.']
38
+ #$Print['']
39
+ #$Color['cyan',' #$Set[name,world]']
40
+ #$Color['cyan',' #$Print[Hello ${name}]']
41
+ #$Print['']
42
+ #$Print['Give us a word to store:']
43
+ #$Input['Enter a word:'] | #$Set['word']
44
+ #$Print['']
45
+ #$Color['green',' Stored → word = "${word}"']
46
+ #$Print['']
47
+ #$Print['Now we can use it: Hello ${word}!']
48
+ #$Pause['Press ENTER to continue...']
49
+ #$End_Section
50
+
51
+ // ── Lesson 3: Pipes ───────────────────────────────────────────────
52
+ #$Section['Lesson 3: Pipe Chains']
53
+ #$Print['Pipes pass the output of one command into the next:']
54
+ #$Print['']
55
+ #$Color['cyan',' #$Set[msg, hello world ] | #$Trim | #$Upper | #$Set[msg]']
56
+ #$Print['']
57
+ #$Print['We will run that chain live on your word "${word}".']
58
+ #$Print['Predict the output before you press ENTER.']
59
+ #$Pause['Press ENTER to run it...']
60
+ #$Set['word',' ${word} '] | #$Trim | #$Upper | #$Set['result']
61
+ #$Print['']
62
+ #$Color['green',' → ${result}']
63
+ #$Print['']
64
+ #$Color['dim','Trimmed whitespace, then uppercased. Pipes compose left to right.']
65
+ #$Pause['Press ENTER to continue...']
66
+ #$End_Section
67
+
68
+ // ── Lesson 4: Checks & Branching ─────────────────────────────────
69
+ #$Section['Lesson 4: Checks and Branching']
70
+ #$Print['ProDucs has no if/else. Instead:']
71
+ #$Print['']
72
+ #$Color['dim',' 1. A Check_* command sets failed=0 (pass) or failed=1 (fail)']
73
+ #$Color['dim',' 2. #$Branch runs only when failed=0']
74
+ #$Color['dim',' 3. #$BranchElse runs only when failed=1']
75
+ #$Print['']
76
+ #$Print['Let us try it. Enter a number and we will tell you if it is above 50.']
77
+ #$Print['']
78
+ #$Input['Enter a number:'] | #$Set['num']
79
+ #$Check_gt['num','50']
80
+ #$Branch
81
+ #$Color['green',' ✔ ${num} is greater than 50']
82
+ #$End_Branch
83
+ #$BranchElse
84
+ #$Color['yellow',' ${num} is 50 or below']
85
+ #$End_BranchElse
86
+ #$Pause['Press ENTER to continue...']
87
+ #$End_Section
88
+
89
+ // ── Lesson 5: Write your own ──────────────────────────────────────
90
+ #$Section['Lesson 5: Your Turn']
91
+ #$Print['You have now seen:']
92
+ #$Print[' • Commands #$Print[text]']
93
+ #$Print[' • Variables #$Set[name,value] → ${name}']
94
+ #$Print[' • Pipes #$Cmd1 | #$Cmd2 | #$Cmd3']
95
+ #$Print[' • Branching #$Check_* → #$Branch / #$BranchElse']
96
+ #$Print['']
97
+ #$Print['Here is a mini script to try yourself:']
98
+ #$Print['']
99
+ #$Color['cyan',' #$Set[city,Paris]']
100
+ #$Color['cyan',' #$Set[city,${city}] | #$Upper | #$Set[city]']
101
+ #$Color['cyan',' #$Check_eq[city,PARIS]']
102
+ #$Color['cyan',' #$Branch']
103
+ #$Color['cyan',' #$Color[green,City is PARIS!]']
104
+ #$Color['cyan',' #$End_Branch']
105
+ #$Print['']
106
+ #$Print['Save it as test.pd and run: node cli.js test.pd']
107
+ #$Pause['Press ENTER to finish...']
108
+ #$End_Section
109
+
110
+ // ── Reference ─────────────────────────────────────────────────────
111
+ #$Section['Install']
112
+ #$Table
113
+ #$Row['Command','What it does']
114
+ #$Row['npm install','Install dependencies']
115
+ #$Row['npm link','Install producs globally (optional)']
116
+ #$End_Table
117
+ #$End_Section
118
+
119
+ #$Section['Running Scripts']
120
+ #$Table
121
+ #$Row['Command','What it does']
122
+ #$Row['node cli.js script.pd','Run a .pd file']
123
+ #$Row['node cli.js --demo','Run the built-in feature demo']
124
+ #$Row['node cli.js --ast script.pd','Dump AST as JSON (no execution)']
125
+ #$Row['node cli.js --help','Full usage reference']
126
+ #$Row['producs script.pd','Run globally (after npm link)']
127
+ #$End_Table
128
+ #$End_Section
129
+
130
+ #$Section['Check Commands']
131
+
132
+ #$Group['String checks (operate on VALUE)']
133
+ #$Table
134
+ #$Row['Command','Passes when']
135
+ #$Row['Check_eq[expected]','VALUE === expected']
136
+ #$Row['Check_neq[expected]','VALUE !== expected']
137
+ #$Row['Check_contains[needle]','VALUE contains needle']
138
+ #$Row['Check_not_contains[needle]','VALUE does NOT contain needle']
139
+ #$Row['Check_starts[prefix]','VALUE starts with prefix']
140
+ #$Row['Check_ends[suffix]','VALUE ends with suffix']
141
+ #$Row['Check_matches[regex]','VALUE matches regex']
142
+ #$Row['Check_empty','VALUE is empty string']
143
+ #$Row['Check_nonempty','VALUE is not empty']
144
+ #$End_Table
145
+ #$End_Group
146
+
147
+ #$Group['Numeric checks']
148
+ #$Table
149
+ #$Row['Command','Passes when']
150
+ #$Row['Check_gt[var,n]','var > n']
151
+ #$Row['Check_gte[var,n]','var >= n']
152
+ #$Row['Check_lt[var,n]','var < n']
153
+ #$Row['Check_lte[var,n]','var <= n']
154
+ #$Row['Check_num_eq[var,n]','var == n (numeric)']
155
+ #$Row['Check_num_neq[var,n]','var != n (numeric)']
156
+ #$Row['Check_between[var,lo,hi]','lo <= var <= hi']
157
+ #$End_Table
158
+ #$End_Group
159
+
160
+ #$Group['Variable comparison']
161
+ #$Table
162
+ #$Row['Command','Passes when']
163
+ #$Row['Check_var_eq[a,b]','var a === var b']
164
+ #$Row['Check_var_neq[a,b]','var a !== var b']
165
+ #$End_Table
166
+ #$End_Group
167
+
168
+ #$Group['Result checks']
169
+ #$Table
170
+ #$Row['Command','Passes when']
171
+ #$Row['Check_failed','Previous result was failed']
172
+ #$Row['Check_passed','Previous result was passed']
173
+ #$Row['Check_failed_error[msg]','Throws error if previous result failed']
174
+ #$Row['Check_passed_error[msg]','Throws error if previous result passed']
175
+ #$End_Table
176
+ #$End_Group
177
+
178
+ #$End_Section
179
+
180
+ #$Section['Command Reference']
181
+
182
+ #$Group['I/O']
183
+ #$Table
184
+ #$Row['Command','Description']
185
+ #$Row['> [prompt]','Prompt block (block form, use #$End_>)']
186
+ #$Row['Input[prompt]','Prompt for input, pipeable inline → VALUE']
187
+ #$Row['Print[text]','Print to stdout']
188
+ #$Row['Warn[text]','Print yellow warning to stderr']
189
+ #$Row['Error_print[text]','Print red error to stderr']
190
+ #$Row['Pause[msg]','Block until ENTER']
191
+ #$Row['Confirm[msg,default]','y/n prompt']
192
+ #$Row['Select[label,opt1,...]','Numbered menu']
193
+ #$End_Table
194
+ #$End_Group
195
+
196
+ #$Group['Variables']
197
+ #$Table
198
+ #$Row['Command','Description']
199
+ #$Row['Set[name,value]','Set a variable']
200
+ #$Row['Unset[name]','Delete a variable']
201
+ #$Row['Export[name,value]','Set variable and push to process.env']
202
+ #$Row['Env_get[KEY]','Read process.env.KEY into VALUE']
203
+ #$Row['Env_set[KEY]','Write VALUE into process.env.KEY']
204
+ #$End_Table
205
+ #$End_Group
206
+
207
+ #$Group['Shell']
208
+ #$Table
209
+ #$Row['Command','Description']
210
+ #$Row['Shell_run','Run VALUE/text child as shell command (inherit stdio)']
211
+ #$Row['Shell_capture','Run command and capture stdout into VALUE']
212
+ #$End_Table
213
+ #$End_Group
214
+
215
+ #$Group['String ops']
216
+ #$Table
217
+ #$Row['Command','Description']
218
+ #$Row['Trim','Remove leading/trailing whitespace']
219
+ #$Row['Upper','Uppercase VALUE']
220
+ #$Row['Lower','Lowercase VALUE']
221
+ #$Row['Len','Length of VALUE']
222
+ #$Row['Replace[pat,rep,flags]','Regex replace']
223
+ #$Row['Slice[start,end]','Substring']
224
+ #$Row['Split[sep]','Split VALUE by separator']
225
+ #$Row['Join[sep]','Join VALUE by separator']
226
+ #$Row['Default[fallback]','Use fallback if VALUE is empty']
227
+ #$Row['Concat[suffix,...]','Append to VALUE']
228
+ #$End_Table
229
+ #$End_Group
230
+
231
+ #$Group['Math']
232
+ #$Table
233
+ #$Row['Command','Description']
234
+ #$Row['Int','Truncate VALUE to integer']
235
+ #$Row['Float','Parse VALUE as float']
236
+ #$Row['Abs','Absolute value']
237
+ #$Row['Round / Floor / Ceil','Rounding']
238
+ #$Row['Math[expr]','Evaluate JS expression with vars in scope']
239
+ #$Row['Inc[var,step]','Increment variable']
240
+ #$Row['Dec[var,step]','Decrement variable']
241
+ #$End_Table
242
+ #$End_Group
243
+
244
+ #$Group['Data']
245
+ #$Table
246
+ #$Row['Command','Description']
247
+ #$Row['Hash[algo]','Hash VALUE (md5, sha256, ...)']
248
+ #$Row['Timestamp[iso|unix|ms]','Current timestamp']
249
+ #$Row['Json_get[a.b.c]','Get dot-path from JSON VALUE']
250
+ #$Row['Json_set[a.b,val]','Set dot-path in JSON VALUE']
251
+ #$End_Table
252
+ #$End_Group
253
+
254
+ #$Group['File I/O']
255
+ #$Table
256
+ #$Row['Command','Description']
257
+ #$Row['Read_file[path]','Read file into VALUE']
258
+ #$Row['Write_file[path]','Write VALUE to file']
259
+ #$Row['Append_file[path]','Append VALUE to file']
260
+ #$End_Table
261
+ #$End_Group
262
+
263
+ #$Group['Control']
264
+ #$Table
265
+ #$Row['Command','Description']
266
+ #$Row['Goto[label]','Jump to matching Label']
267
+ #$Row['Label[name]','Jump target for Goto']
268
+ #$Row['Exit[code]','Terminate process']
269
+ #$Row['Assert[expr,msg]','Throw if JS expression is falsy']
270
+ #$Row['Require_env[VAR]','Throw if env var is unset']
271
+ #$Row['Require_cmd[cmd]','Throw if command not on PATH']
272
+ #$Row['Wait[ms]','Blocking sleep in milliseconds']
273
+ #$End_Table
274
+ #$End_Group
275
+
276
+ #$Group['Blocks']
277
+ #$Table
278
+ #$Row['Block','Description']
279
+ #$Row['#$> [prompt]','Prompt block']
280
+ #$Row['#$Branch','Run if last check passed (failed=0)']
281
+ #$Row['#$BranchElse','Run if last check failed (failed=1)']
282
+ #$Row['#$Repeat[N]','Loop N times (_i = index)']
283
+ #$Row['#$ForEach[var,a,b,...]','Iterate over items']
284
+ #$Row['#$Try + #$Catch','Error handling (_error set in Catch)']
285
+ #$Row['#$Section[title]','Formatted section heading']
286
+ #$Row['#$Step[desc]','Auto-numbered step']
287
+ #$Row['#$Group[label]','Logical grouping with bracket lines']
288
+ #$Row['#$Table + #$Row[...]','ASCII table']
289
+ #$End_Table
290
+ #$End_Group
291
+
292
+ #$Group['Visual']
293
+ #$Table
294
+ #$Row['Command','Description']
295
+ #$Row['HR[char]','Full-width horizontal rule']
296
+ #$Row['Header[title]','Prominent banner header']
297
+ #$Row['Color[name,text]','Print in ANSI color']
298
+ #$Row['Progress[pct,width,label]','Progress bar']
299
+ #$Row['Spinner[msg]','Spinner-style status line']
300
+ #$Row['Status[label]','OK/FAIL badge for current result']
301
+ #$End_Table
302
+ #$End_Group
303
+
304
+ #$Group['Runtime']
305
+ #$Table
306
+ #$Row['Command','Description']
307
+ #$Row['Debug[on|off]','Toggle verbose debug output']
308
+ #$Row['Strict[on|off]','Halt on any shell command failure']
309
+ #$Row['Color_off','Disable ANSI colors']
310
+ #$Row['Log[label]','Append VALUE + status to execution log']
311
+ #$Row['Dump_log','Print execution log to stdout']
312
+ #$Row['Help','List all commands with descriptions']
313
+ #$Row['Version','Print ProDucs version']
314
+ #$End_Table
315
+ #$End_Group
316
+
317
+ #$End_Section
318
+
319
+ #$Section['Programmatic API']
320
+ #$Step['Require the module']
321
+ #$Color['cyan','const { ProDucs } = require("producs");']
322
+ #$End_Step
323
+ #$Step['Create an instance']
324
+ #$Color['cyan','const prod = new ProDucs({ debug: false, strict: false, noColor: false });']
325
+ #$End_Step
326
+ #$Step['Register a custom command']
327
+ #$Color['cyan','prod.register("Shout", (node, input) => {']
328
+ #$Color['cyan',' const msg = input.VALUE.toUpperCase() + "!!!";']
329
+ #$Color['cyan',' process.stdout.write(msg + "\\n");']
330
+ #$Color['cyan',' return { VALUE: msg, failed: 0 };']
331
+ #$Color['cyan','}, { doc: "Uppercase and add exclamation marks" });']
332
+ #$End_Step
333
+ #$Step['Pre-set variables and run a script']
334
+ #$Color['cyan','prod.set("env", "production");']
335
+ #$Color['cyan','prod.run(`#$Set[greeting,hello] | #$Shout`);']
336
+ #$Color['cyan','console.log(prod.vars()); // { greeting: "HELLO!!!", env: "production" }']
337
+ #$End_Step
338
+ #$End_Section
339
+
340
+ // ── Live footer ───────────────────────────────────────────────────
341
+ #$Section['About this file']
342
+ #$Print['This README is a valid ProDucs script.']
343
+ #$Print['Every section, table, and lesson above was rendered by ProDucs itself.']
344
+ #$HR['-']
345
+ #$Timestamp['iso'] | #$Set['now']
346
+ #$Color['green','✔ Rendered at ${now}']
347
+ #$Version
348
+ #$End_Section
349
+
350
+ #$HR['═']
351
+ #$Color['green','Thanks for going through it, ${user}!']
352
+ #$Status['ProDucs README']