producs
v3.0.1
Published
Professional Documentation Shell DSL — a modular, pipeable terminal scripting language
Maintainers
Readme
ProDucs v3.0
Professional Documentation Shell DSL — a modular, pipeable terminal scripting language for advanced CLI documentation and automation.
Install
npm install # install deps
npm link # optional: install `producs` globallyRun
node cli.js script.pd # run a .pd file
node cli.js --demo # built-in feature demo
node cli.js --ast script.pd # dump AST as JSON
node cli.js --help # full usageOr if installed globally:
producs script.pdSyntax
// line comment
#$CommandName['arg1','arg2'] inline command
#$Cmd1 | #$Cmd2 | #$Cmd3 pipe chain (output of each → input of next)
${varname} variable interpolation
#$BlockName['arg'] open a block
...children...
#$End_BlockName close the blockBranching
ProDucs replaces if/else with an explicit check → branch model:
- A
Check_*command runs and setsfailed=0(pass) orfailed=1(fail) #$Branchruns its children only whenfailed=0#$BranchElseruns its children only whenfailed=1
#$Set['score','92']
#$Check_gte['score','90']
#$Branch
#$Color['green','A grade!']
#$End_Branch
#$BranchElse
#$Color['yellow','Below A grade']
#$End_BranchElseAll Check Commands
String checks (operate on VALUE)
| Command | Description |
|---|---|
| Check_eq['expected'] | Pass if VALUE === expected |
| Check_neq['expected'] | Pass if VALUE !== expected |
| Check_contains['needle'] | Pass if VALUE contains needle |
| Check_not_contains['needle'] | Pass if VALUE does NOT contain needle |
| Check_starts['prefix'] | Pass if VALUE starts with prefix |
| Check_ends['suffix'] | Pass if VALUE ends with suffix |
| Check_matches['regex','flags'] | Pass if VALUE matches regex |
| Check_empty | Pass if VALUE is empty string |
| Check_nonempty | Pass if VALUE is not empty |
Numeric checks
Two forms: Check_gt['varname','number'] or Check_gt['number'] (uses VALUE as number).
| Command | Description |
|---|---|
| Check_gt['var','n'] | Pass if var > n |
| Check_gte['var','n'] | Pass if var >= n |
| Check_lt['var','n'] | Pass if var < n |
| Check_lte['var','n'] | Pass if var <= n |
| Check_num_eq['var','n'] | Pass if var == n (numeric) |
| Check_num_neq['var','n'] | Pass if var != n (numeric) |
| Check_between['var','lo','hi'] | Pass if lo <= var <= hi |
Variable comparison
| Command | Description |
|---|---|
| Check_var_eq['a','b'] | Pass if var a === var b |
| Check_var_neq['a','b'] | Pass if var a !== var b |
Result checks
| Command | Description |
|---|---|
| Check_failed | Pass if previous result was failed |
| Check_passed | Pass if previous result was passed |
| Check_failed_error['msg'] | Throw error if previous result was failed |
| Check_passed_error['msg'] | Throw error if previous result passed |
Command Reference
I/O
| Command | Description |
|---|---|
| > ['prompt'] | Prompt user for input |
| Print['text'] | Print to stdout |
| Warn['text'] | Print yellow warning to stderr |
| Error_print['text'] | Print red error to stderr |
| Pause['msg'] | Block until ENTER |
| Confirm['msg','default'] | y/n prompt |
| Select['label','opt1',...] | Numbered menu |
Variables
| Command | Description |
|---|---|
| Set['name','value'] | Set a variable |
| Unset['name'] | Delete a variable |
| Export['name','value'] | Set variable and push to process.env |
| Env_get['KEY'] | Read process.env.KEY → VALUE |
| Env_set['KEY'] | Write VALUE → process.env.KEY |
Shell
| Command | Description |
|---|---|
| Shell_run | Run VALUE/text child as shell command (inherit stdio) |
| Shell_capture | Run command, capture stdout → VALUE |
String ops
Trim Upper Lower Len Replace['pat','rep','flags']
Slice['start','end'] Split['sep'] Join['sep']
Default['fallback'] Concat['suffix',...]
Math
Int Float Abs Round Floor Ceil
Math['expr'] Inc['var','step'] Dec['var','step']
Data
Hash['algo'] Timestamp['iso'|'unix'|'ms']
Json_get['a.b.c'] Json_set['a.b','val']
File I/O
Read_file['path'] Write_file['path'] Append_file['path']
Control
Goto['label'] Label['name'] Exit['code']
Assert['JS expr','msg']
Require_env['VAR'] Require_cmd['cmd']
Timing
Wait['ms'] — blocking sleep in milliseconds
Blocks
| Block | Description |
|---|---|
| #$> ['prompt'] | Prompt block |
| #$Branch | Run if last check passed (failed=0) |
| #$BranchElse | Run if last check failed (failed=1) |
| #$Repeat['N'] | Loop N times (_i = index) |
| #$ForEach['var','a','b',...] | Iterate over items |
| #$Try + #$Catch | Error handling (_error set in Catch) |
| #$Section['title'] | Formatted section heading |
| #$Step['desc'] | Auto-numbered step |
| #$Group['label'] | Logical grouping with bracket lines |
| #$Table + #$Row[...] | ASCII table |
Visual
HR['char'] Header['title'] Color['name','text']
Progress['pct','width','label'] Spinner['msg'] Status['label']
Runtime
Debug['on'|'off'] Strict['on'|'off'] Color_off
Log['label'] Dump_log Help Version
Example Script
// install.pd — sample deployment doc script
#$Header['Deploy Checklist']
#$Require_cmd['git']
#$Require_cmd['node']
#$Section['Pre-flight']
#$Shell_capture['git branch --show-current'] | #$Set['branch']
#$Print['Branch: ${branch}']
#$Set['branch','${branch}'] | #$Check_eq['main']
#$BranchElse
#$Warn['Not on main branch!']
#$End_BranchElse
#$End_Section
#$Section['Build']
#$Step['Install dependencies']
#$Shell_run
npm ci
#$End_Shell_run
#$End_Step
#$End_Section
#$Status['Deploy complete']Programmatic API
const { ProDucs } = require("producs");
const prod = new ProDucs({ debug: false, strict: false, noColor: false });
// Register custom command
prod.register("Shout", (node, input) => {
const msg = input.VALUE.toUpperCase() + "!!!";
process.stdout.write(msg + "\n");
return { VALUE: msg, failed: 0 };
}, { doc: "Uppercase and add exclamation marks" });
// Pre-set variables
prod.set("env", "production");
// Run a script
prod.run(`
#$Set['greeting','hello']
#$Set['greeting','${greeting}'] | #$Shout
`);
// Read back vars
console.log(prod.vars()); // { greeting: "HELLO!!!", env: "production" }