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 +245 -0
- package/README.pd +352 -0
- package/cli.js +103 -81
- package/examples/checks.pd +126 -0
- package/examples/demo.pd +113 -0
- package/examples/deploy.pd +43 -0
- package/index.js +1079 -149
- package/package.json +29 -11
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']
|