shellscriptor 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,761 @@
1
+ Metadata-Version: 2.1
2
+ Name: shellscriptor
3
+ Version: 0.1.0
4
+ Summary: Programmatic shell script generator with argparse, logging, validation, and structured output
5
+ Author: RepoDynamics
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/RepoDynamics/ShellScriptor
8
+ Project-URL: Repository, https://github.com/RepoDynamics/ShellScriptor
9
+ Keywords: shell,bash,script,codegen,argparse
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Topic :: Software Development :: Code Generators
14
+ Classifier: Topic :: System :: Shells
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: pydantic >=2.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest >=8.0 ; extra == 'dev'
20
+ Provides-Extra: yaml
21
+ Requires-Dist: pyyaml >=6.0 ; extra == 'yaml'
22
+
23
+ # ShellScriptor
24
+
25
+ Programmatic shell script generator with argument parsing, logging, validation,
26
+ and structured output — driven by Python dicts or YAML/JSON definition files.
27
+
28
+ ---
29
+
30
+ ## Contents
31
+
32
+ - [ShellScriptor](#shellscriptor)
33
+ - [Contents](#contents)
34
+ - [Overview](#overview)
35
+ - [Installation](#installation)
36
+ - [Quick start](#quick-start)
37
+ - [Python](#python)
38
+ - [CLI](#cli)
39
+ - [Definition format](#definition-format)
40
+ - [Script definition (`ScriptDef`)](#script-definition-scriptdef)
41
+ - [Function definition (`FunctionDef`)](#function-definition-functiondef)
42
+ - [Parameter definition (`ParameterDef`)](#parameter-definition-parameterdef)
43
+ - [Validation rules (`ValidationDef`)](#validation-rules-validationdef)
44
+ - [Return value definition (`ReturnDef`)](#return-value-definition-returndef)
45
+ - [Script types](#script-types)
46
+ - [`shell_src` — sourced library](#shell_src--sourced-library)
47
+ - [`shell_exec` — executable script](#shell_exec--executable-script)
48
+ - [Parameter types](#parameter-types)
49
+ - [Argument parsing](#argument-parsing)
50
+ - [Required vs optional parameters](#required-vs-optional-parameters)
51
+ - [Short flag aliases](#short-flag-aliases)
52
+ - [Help / usage output](#help--usage-output)
53
+ - [Environment variable fallback (`shell_exec`)](#environment-variable-fallback-shell_exec)
54
+ - [Validation](#validation)
55
+ - [Enum (allowed values)](#enum-allowed-values)
56
+ - [Path existence](#path-existence)
57
+ - [Integer range](#integer-range)
58
+ - [Regex pattern](#regex-pattern)
59
+ - [Custom shell lines](#custom-shell-lines)
60
+ - [Return values / structured output](#return-values--structured-output)
61
+ - [Embedded functions](#embedded-functions)
62
+ - [Global function pool](#global-function-pool)
63
+ - [Logging](#logging)
64
+ - [Body sections](#body-sections)
65
+ - [CLI usage](#cli-usage)
66
+ - [Definition file formats](#definition-file-formats)
67
+ - [Python API](#python-api)
68
+ - [`create_script(name, data, script_type, global_functions=None) -> str`](#create_scriptname-data-script_type-global_functionsnone---str)
69
+ - [`create_function(name, data, script_type) -> list[str]`](#create_functionname-data-script_type---liststr)
70
+ - [Low-level generators](#low-level-generators)
71
+ - [Examples](#examples)
72
+ - [Required string parameter with short flag](#required-string-parameter-with-short-flag)
73
+ - [All four parameter types](#all-four-parameter-types)
74
+ - [Enum + path validation](#enum--path-validation)
75
+ - [Integer range](#integer-range-1)
76
+ - [Regex pattern](#regex-pattern-1)
77
+ - [Return values](#return-values)
78
+ - [Genuinely optional parameter (no default, no required check)](#genuinely-optional-parameter-no-default-no-required-check)
79
+
80
+ ---
81
+
82
+ ## Overview
83
+
84
+ `shellscriptor` generates complete, production-quality shell scripts from a
85
+ structured description. You provide a dict (or a YAML/JSON file) that declares
86
+ parameters, validation rules, embedded functions, and body code; the library
87
+ assembles the boilerplate so you don't have to:
88
+
89
+ | Feature | `shell_src` | `shell_exec` |
90
+ |---|---|---|
91
+ | `while/case` argparse loop | ✓ | ✓ |
92
+ | `--help` / `__usage__` | ✓ (when descriptions present) | ✓ |
93
+ | Validation checks | ✓ | ✓ |
94
+ | Entry / exit log markers | — | ✓ |
95
+ | Argument-read logs | — | ✓ |
96
+ | `tee` log capture to `$LOGFILE` | — | ✓ |
97
+ | `trap __cleanup__ EXIT` | — | ✓ |
98
+ | `set -x` when `$DEBUG=true` | — | ✓ |
99
+ | Env-var fallback (called with no args) | — | ✓ |
100
+
101
+ ---
102
+
103
+ ## Installation
104
+
105
+ ```bash
106
+ pip install shellscriptor
107
+ ```
108
+
109
+ YAML definition files require the optional `pyyaml` dependency:
110
+
111
+ ```bash
112
+ pip install "shellscriptor[yaml]"
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Quick start
118
+
119
+ ### Python
120
+
121
+ ```python
122
+ from shellscriptor import create_script
123
+
124
+ script = create_script(
125
+ name="greet",
126
+ script_type="shell_src",
127
+ data={
128
+ "interpreter": "usr/bin/env bash",
129
+ "parameter": {
130
+ "name": {"type": "string", "description": "Name to greet"},
131
+ },
132
+ "body": 'echo "Hello, $NAME!"',
133
+ },
134
+ )
135
+ print(script)
136
+ ```
137
+
138
+ ### CLI
139
+
140
+ ```bash
141
+ # Write to stdout
142
+ shellscriptor greet.yaml
143
+
144
+ # Write to a file
145
+ shellscriptor greet.yaml --output dist/greet.sh
146
+ ```
147
+
148
+ `greet.yaml`:
149
+
150
+ ```yaml
151
+ name: greet
152
+ type: shell_src
153
+ script:
154
+ interpreter: usr/bin/env bash
155
+ parameter:
156
+ name:
157
+ type: string
158
+ description: Name to greet
159
+ body: 'echo "Hello, $NAME!"'
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Definition format
165
+
166
+ ### Script definition (`ScriptDef`)
167
+
168
+ Top-level keys accepted by `create_script()` and by the CLI wrapper format:
169
+
170
+ | Key | Type | Description |
171
+ |---|---|---|
172
+ | `interpreter` | `str \| null` | Shebang path without the leading `#!`. `"usr/bin/env bash"` → `#!/usr/bin/env bash`. Omit for no shebang. |
173
+ | `flags` | `str \| null` | Arguments passed to `set` after the shebang, e.g. `"-euo pipefail"`. |
174
+ | `import` | `list[str]` | Names of functions to pull in from the `global_functions` pool passed to `create_script()`. |
175
+ | `function` | `dict[str, FunctionDef]` | Locally defined functions embedded in the script. |
176
+ | `parameter` | `dict[str, ParameterDef]` | Script-level parameters accepted on the command line (or from env vars in `shell_exec` mode). |
177
+ | `body` | body form | Main script body executed after argument parsing and validation. |
178
+ | `return` | `list[ReturnDef]` | Values written to stdout on exit (`shell_exec` only). |
179
+
180
+ ### Function definition (`FunctionDef`)
181
+
182
+ Accepted inside `function` and by `create_function()`:
183
+
184
+ | Key | Type | Description |
185
+ |---|---|---|
186
+ | `parameter` | `dict[str, ParameterDef]` | Parameters accepted by the function. |
187
+ | `body` | body form | Function body. |
188
+ | `return` | `list[ReturnDef]` | Values written to stdout when the function returns. |
189
+
190
+ ### Parameter definition (`ParameterDef`)
191
+
192
+ | Key | Type | Default | Description |
193
+ |---|---|---|---|
194
+ | `type` | `"string" \| "boolean" \| "integer" \| "array"` | **required** | Shell type. |
195
+ | `default` | `str \| list[str] \| null` | `null` | Default value. `null` with no explicit `required` field implies the parameter is required. |
196
+ | `required` | `bool \| null` | `null` | Explicit required flag. `null` → inferred from `default`. |
197
+ | `description` | `str` | `""` | Human-readable description for `--help` output. Triggers `--help`/`__usage__` generation when non-empty on any parameter. |
198
+ | `short` | `str` | `""` | Single-character short flag alias, e.g. `"o"` creates `-o` alongside `--<name>`. |
199
+ | `array_delimiter` | `str` | `" "` | Delimiter used when reading an array from a single environment variable (env-var fallback, `shell_exec` only). |
200
+ | `validation` | `ValidationDef \| null` | `null` | Optional validation rules. |
201
+
202
+ **Required vs optional — rules:**
203
+
204
+ | `required` | `default` | Behaviour |
205
+ |---|---|---|
206
+ | `null` (omitted) | `null` | Required — exits if missing. |
207
+ | `null` (omitted) | `"value"` | Optional — assigns default if missing. |
208
+ | `true` | any | Required — exits if missing; default ignored. |
209
+ | `false` | `"value"` | Optional — assigns default if missing. |
210
+ | `false` | `null` | Genuinely optional — no check emitted; variable may remain empty. |
211
+
212
+ ### Validation rules (`ValidationDef`)
213
+
214
+ Nested inside `ParameterDef.validation`:
215
+
216
+ | Key | Type | Description |
217
+ |---|---|---|
218
+ | `enum` | `list[str]` | Exhaustive list of accepted values. A value not in the list causes `exit 1`. |
219
+ | `path_existence` | `PathExistenceDef` | Assert the value is a path satisfying an existence condition. |
220
+ | `integer_range` | `IntegerRangeDef` | Assert the value is an integer within an inclusive numeric range. |
221
+ | `regex` | `str` | ERE pattern the full value must match. Non-matching values cause `exit 1`. |
222
+ | `custom` | `list[str]` | Verbatim shell lines appended after all other checks. |
223
+
224
+ **`PathExistenceDef`**:
225
+
226
+ | Key | Type | Description |
227
+ |---|---|---|
228
+ | `must_exist` | `bool` | `true` → path must exist; `false` → path must not exist. |
229
+ | `type` | `"dir" \| "exec" \| "file" \| "symlink" \| null` | Kind of filesystem entry to test. `null` accepts any entry. |
230
+
231
+ **`IntegerRangeDef`**:
232
+
233
+ | Key | Type | Description |
234
+ |---|---|---|
235
+ | `min` | `int \| null` | Inclusive lower bound. `null` for no lower bound. |
236
+ | `max` | `int \| null` | Inclusive upper bound. `null` for no upper bound. |
237
+
238
+ ### Return value definition (`ReturnDef`)
239
+
240
+ | Key | Type | Description |
241
+ |---|---|---|
242
+ | `name` | `str` | Human-readable label used in log messages. |
243
+ | `variable` | `str` | Shell variable name whose value is written to stdout. |
244
+ | `type` | `"string" \| "boolean" \| "integer" \| "array"` | Type of the return value; drives encoding. |
245
+
246
+ ---
247
+
248
+ ## Script types
249
+
250
+ ### `shell_src` — sourced library
251
+
252
+ Generates a lean script intended to be sourced (`. script.sh`).
253
+
254
+ - Functions and top-level `while/case` argument parsing are emitted.
255
+ - No logging boilerplate, no `trap`, no `tee`.
256
+ - Good for utility libraries and helper functions.
257
+
258
+ ### `shell_exec` — executable script
259
+
260
+ Generates a self-contained, directly executable script with:
261
+
262
+ - **Entry/exit log markers** for the script and every function.
263
+ - **Tee log capture**: all output is mirrored to a temp file; when `$LOGFILE`
264
+ is set, the capture is flushed to it on exit via the `__cleanup__` trap.
265
+ - **`$DEBUG` flag**: `set -x` is enabled when `DEBUG=true` is passed.
266
+ - **Env-var fallback**: when the script is called with no arguments, each
267
+ parameter is read from the corresponding environment variable instead.
268
+
269
+ ---
270
+
271
+ ## Parameter types
272
+
273
+ | Type | Shell representation | Argparse | Env-var fallback |
274
+ |---|---|---|---|
275
+ | `string` | `VAR=""` | `--name) shift; VAR="$1"; shift;;` | `${VAR+defined}` one-liner |
276
+ | `integer` | `VAR=""` | Same as `string` (validation handles numeric check) | Same as `string` |
277
+ | `boolean` | `VAR=""` | `--flag) shift; VAR=true;;` (no value consumed) | `${VAR+defined}` one-liner |
278
+ | `array` | `VAR=()` | Reads all following non-`--` words into `VAR` | `IFS="<delim>" read -ra VAR` |
279
+
280
+ Variable names are derived from parameter names: hyphens become underscores, and
281
+ for script-level parameters (global scope) names are uppercased.
282
+ Function-local parameters stay lowercase.
283
+
284
+ ---
285
+
286
+ ## Argument parsing
287
+
288
+ Every script or function with parameters gets a `while [[ $# -gt 0 ]]; do … done`
289
+ loop. Unknown flags emit `⛔ Unknown option: '<flag>'` to stderr and exit 1.
290
+ Positional (non-flag) arguments emit `⛔ Unexpected argument: '<arg>'` and exit 1.
291
+
292
+ ### Required vs optional parameters
293
+
294
+ See the [parameter definition table](#parameter-definition-parameterdef) for the
295
+ full matrix. The generated check for a required parameter:
296
+
297
+ ```bash
298
+ [ -z "${OUTPUT_DIR-}" ] && { echo "⛔ Missing required argument 'OUTPUT_DIR'." >&2; exit 1; }
299
+ ```
300
+
301
+ For an optional parameter with a default value:
302
+
303
+ ```bash
304
+ [ -z "${COUNT-}" ] && { echo "ℹ️ Argument 'COUNT' set to default value '1'." >&2; COUNT="1"; }
305
+ ```
306
+
307
+ ### Short flag aliases
308
+
309
+ Set `short: "o"` to generate a `-o` arm alongside `--output-dir`:
310
+
311
+ ```bash
312
+ --output-dir|-o) shift; OUTPUT_DIR="$1"; ...;;
313
+ ```
314
+
315
+ ### Help / usage output
316
+
317
+ When **any** parameter in a parameter set carries a non-empty `description`,
318
+ shellscriptor:
319
+
320
+ 1. Generates a `__usage__()` function that prints a summary table to stderr
321
+ and exits with code 0.
322
+ 2. Adds a `--help|-h)` arm to the argparse loop that calls `__usage__`.
323
+
324
+ For script-level parameters `__usage__` is defined at the top of the script
325
+ (before all other functions). For function parameters it is defined at the
326
+ start of the function body, before the argparse loop.
327
+
328
+ Example output:
329
+
330
+ ```
331
+ Usage:
332
+ -o, --output-dir (string): Directory to write results into
333
+ ```
334
+
335
+ ### Environment variable fallback (`shell_exec`)
336
+
337
+ When a `shell_exec` script is invoked with no arguments it reads parameters
338
+ from environment variables. Variable names mirror the script-level variable
339
+ name (uppercase, hyphens → underscores). The env-var block only imports a
340
+ variable when it is already set in the environment (`${VAR+defined}` test), so
341
+ unset variables are not silently turned into empty strings.
342
+
343
+ For array parameters the env var is split on `array_delimiter` using
344
+ `IFS` + `read -ra`.
345
+
346
+ ---
347
+
348
+ ## Validation
349
+
350
+ Validation checks are applied after argument parsing, in this order:
351
+
352
+ 1. Missing-arg / default assignment
353
+ 2. Enum membership
354
+ 3. Path existence
355
+ 4. Integer range
356
+ 5. Regex pattern
357
+ 6. Custom lines
358
+
359
+ For `array` parameters, checks 2–5 are run per element inside a
360
+ `for elem in "${VAR[@]}"; do … done` loop.
361
+
362
+ ### Enum (allowed values)
363
+
364
+ ```yaml
365
+ validation:
366
+ enum: [read, write, delete]
367
+ ```
368
+
369
+ Generated shell:
370
+
371
+ ```bash
372
+ case "${MODE}" in
373
+ "read"|"write"|"delete");;
374
+ *) echo "⛔ Invalid value for argument '--MODE': '${MODE}'" >&2; exit 1;;
375
+ esac
376
+ ```
377
+
378
+ ### Path existence
379
+
380
+ ```yaml
381
+ validation:
382
+ path_existence:
383
+ must_exist: true
384
+ type: file
385
+ ```
386
+
387
+ Generated shell (`must_exist: true`, `type: file`):
388
+
389
+ ```bash
390
+ [ ! -f "${INPUT_FILE}" ] && { echo "⛔ File argument to parameter 'INPUT_FILE' not found: '${INPUT_FILE}'" >&2; exit 1; }
391
+ ```
392
+
393
+ Available `type` values: `"file"` (`-f`), `"dir"` (`-d`), `"symlink"` (`-L`),
394
+ `"exec"` (`-x`), `null` (uses `-e`, accepts any entry).
395
+
396
+ `must_exist: false` inverts the check — the path must **not** exist.
397
+
398
+ ### Integer range
399
+
400
+ ```yaml
401
+ validation:
402
+ integer_range:
403
+ min: 1
404
+ max: 100
405
+ ```
406
+
407
+ Generates checks for both bounds independently (omit either for an open-ended
408
+ range). `min` and `max` must satisfy `min <= max` when both are given.
409
+
410
+ ### Regex pattern
411
+
412
+ ```yaml
413
+ validation:
414
+ regex: "^[a-z][a-z0-9_-]{2,31}$"
415
+ ```
416
+
417
+ Uses `[[ "$VAR" =~ <pattern> ]]`:
418
+
419
+ ```bash
420
+ [[ ! "${SLUG}" =~ ^[a-z][a-z0-9_-]{2,31}$ ]] && { echo "⛔ ..." >&2; exit 1; }
421
+ ```
422
+
423
+ ### Custom shell lines
424
+
425
+ ```yaml
426
+ validation:
427
+ custom:
428
+ - '[ -w "${OUTPUT_DIR}" ] || { echo "⛔ Directory is not writable." >&2; exit 1; }'
429
+ ```
430
+
431
+ Custom lines are appended verbatim after all other validation checks.
432
+
433
+ ---
434
+
435
+ ## Return values / structured output
436
+
437
+ `return` (or `return_` in Python) accepts a list of `ReturnDef` entries.
438
+ shellscriptor encodes return values so that callers can unpack them
439
+ unambiguously:
440
+
441
+ | Situation | Encoding | Caller idiom |
442
+ |---|---|---|
443
+ | Single scalar | `echo "$VAR"` | `val=$(fn)` |
444
+ | Single array | `printf '%s\0' "${VAR[@]}"` | `mapfile -d '' -t arr < <(fn)` |
445
+ | Multiple values (scalars and/or arrays) | Each value followed by `\0`; array elements delimited by `\x1F` internally | `IFS= read -r -d $'\0'` per value |
446
+
447
+ In `shell_exec` mode each return value also emits a write-log line.
448
+
449
+ ---
450
+
451
+ ## Embedded functions
452
+
453
+ Functions defined under `function` are emitted before the script body.
454
+ Each function is generated by `create_function()` and follows the same rules
455
+ as the top-level script: parameters get an argparse loop, validation checks
456
+ are emitted, and in `shell_exec` mode entry/exit log markers are added.
457
+
458
+ ```yaml
459
+ function:
460
+ greet:
461
+ parameter:
462
+ person:
463
+ type: string
464
+ required: true
465
+ description: Name to greet
466
+ body: 'echo "Hello, ${person}!"'
467
+ ```
468
+
469
+ Generated:
470
+
471
+ ```bash
472
+ greet() {
473
+ echo "↪️ Function entry: greet" >&2
474
+ __usage__() {
475
+ echo "Usage:" >&2
476
+ echo " --person (string): Name to greet" >&2
477
+ exit 0
478
+ }
479
+ local person=""
480
+ while [[ $# -gt 0 ]]; do
481
+ case $1 in
482
+ --person) shift; person="$1"; ...; shift;;
483
+ --help|-h) __usage__;;
484
+ ...
485
+ esac
486
+ done
487
+ [ -z "${person-}" ] && { echo "⛔ Missing required argument 'person'." >&2; exit 1; }
488
+ echo "Hello, ${person}!"
489
+ echo "↩️ Function exit: greet" >&2
490
+ }
491
+ ```
492
+
493
+ ---
494
+
495
+ ## Global function pool
496
+
497
+ `create_script()` accepts an optional `global_functions` argument — a dict of
498
+ `FunctionDef`-compatible dicts keyed by function name. Only functions listed
499
+ in `import` (or `import_`) are pulled in:
500
+
501
+ ```python
502
+ GLOBALS = {
503
+ "check_root": {"body": 'if [ "$(id -u)" -ne 0 ]; then echo "must be root" >&2; exit 1; fi'},
504
+ }
505
+
506
+ script = create_script(
507
+ name="setup",
508
+ script_type="shell_exec",
509
+ data={"import": ["check_root"], "body": "check_root"},
510
+ global_functions=GLOBALS,
511
+ )
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Logging
517
+
518
+ The `log()` function and related helpers generate consistent `echo … >&2`
519
+ statements.
520
+
521
+ | Function | Output |
522
+ |---|---|
523
+ | `log(msg)` | `echo "<msg>" >&2` |
524
+ | `log(msg, "info")` | `echo "ℹ️ <msg>" >&2` |
525
+ | `log(msg, "warn")` | `echo "⚠️ <msg>" >&2` |
526
+ | `log(msg, "error")` | `echo "❌ <msg>" >&2; return 1` |
527
+ | `log(msg, "critical")` | `echo "⛔ <msg>" >&2; exit 1` |
528
+ | `log_endpoint("fn", "function", "entry")` | `echo "↪️ Function entry: fn" >&2` |
529
+ | `log_arg_read("param", "VAR")` | `echo "📩 Read argument 'param': '${VAR}'" >&2` |
530
+ | `log_arg_write("result", "RESULT")` | `echo "📤 Write output 'result': '${RESULT}'" >&2` |
531
+
532
+ ---
533
+
534
+ ## Body sections
535
+
536
+ The `body` field is flexible. All three forms are equivalent:
537
+
538
+ ```python
539
+ # Plain string
540
+ body = 'echo hello\necho world'
541
+
542
+ # List of strings
543
+ body = ["echo hello", "echo world"]
544
+
545
+ # List of section dicts (YAML-friendly; only "content" is used)
546
+ body = [
547
+ {"summary": "Greet", "content": "echo hello"},
548
+ {"content": "echo world"},
549
+ ]
550
+ ```
551
+
552
+ Comments (`#`) and blank lines are stripped by default by `sanitize_code()`.
553
+
554
+ ---
555
+
556
+ ## CLI usage
557
+
558
+ ```
559
+ shellscriptor DEFINITION_FILE [--output PATH] [--type {shell_src,shell_exec}] [--name NAME]
560
+ ```
561
+
562
+ | Option | Description |
563
+ |---|---|
564
+ | `DEFINITION_FILE` | Path to a YAML or JSON definition file. |
565
+ | `--output`, `-o` | Write the generated script to this path (default: stdout). |
566
+ | `--type`, `-t` | Override the script type (`shell_src` or `shell_exec`). Required when the file does not contain a top-level `type` key. |
567
+ | `--name`, `-n` | Script name used in log messages. Defaults to the file stem. |
568
+
569
+ ### Definition file formats
570
+
571
+ **Wrapper format** (recommended for YAML):
572
+
573
+ ```yaml
574
+ name: deploy
575
+ type: shell_exec
576
+ script:
577
+ interpreter: usr/bin/env bash
578
+ flags: "-euo pipefail"
579
+ parameter:
580
+ env:
581
+ type: string
582
+ required: true
583
+ description: Target environment
584
+ body: echo "Deploying to $ENV"
585
+ ```
586
+
587
+ **Bare format** (must pass `--type` and optionally `--name` on the CLI):
588
+
589
+ ```json
590
+ {
591
+ "interpreter": "usr/bin/env bash",
592
+ "parameter": {
593
+ "env": {"type": "string", "required": true}
594
+ },
595
+ "body": "echo \"Deploying to $ENV\""
596
+ }
597
+ ```
598
+
599
+ ---
600
+
601
+ ## Python API
602
+
603
+ ### `create_script(name, data, script_type, global_functions=None) -> str`
604
+
605
+ Generate a complete shell script string.
606
+
607
+ ```python
608
+ from shellscriptor import create_script
609
+
610
+ code = create_script(
611
+ name="deploy",
612
+ data={...}, # dict or ScriptDef
613
+ script_type="shell_exec",
614
+ global_functions={}, # optional pool
615
+ )
616
+ ```
617
+
618
+ ### `create_function(name, data, script_type) -> list[str]`
619
+
620
+ Generate lines for a single shell function definition.
621
+
622
+ ```python
623
+ from shellscriptor import create_function
624
+
625
+ lines = create_function("greet", {"body": ['echo "hi"']}, script_type="shell_src")
626
+ ```
627
+
628
+ ### Low-level generators
629
+
630
+ These are exported from `shellscriptor` and can be combined freely to build
631
+ custom script snippets:
632
+
633
+ | Function | Returns |
634
+ |---|---|
635
+ | `create_validation_block(parameters, *, local, script_type)` | Validation lines for all parameters |
636
+ | `validate_variable(var_name, var_type, default, required, validations, script_type)` | Validation lines for one variable |
637
+ | `validate_missing_arg(var_name, var_type, default, script_type)` | One-liner: required-or-default check |
638
+ | `validate_enum(var_name, enum)` | `case` block for allowed values |
639
+ | `validate_path_existence(var_name, must_exist, path_type)` | `[ -f/-d/… ]` check |
640
+ | `validate_integer_range(var_name, min_val, max_val)` | Numeric bound checks |
641
+ | `validate_regex(var_name, pattern)` | `[[ =~ ]]` check |
642
+ | `create_output(returns, script_type)` | Output/return encoding lines |
643
+ | `log(msg, level, code, indent_level)` | `echo … >&2` command string |
644
+ | `log_arg_read(param_name, var_name)` | Read-log string |
645
+ | `log_arg_write(param_name, var_name)` | Write-log string |
646
+ | `log_endpoint(name, typ, stage)` | Entry/exit-log string |
647
+ | `indent(code, level)` | Indent a string or list of lines |
648
+ | `sanitize_code(code, ...)` | Strip comments, blank lines, trailing whitespace |
649
+
650
+ ---
651
+
652
+ ## Examples
653
+
654
+ ### Required string parameter with short flag
655
+
656
+ ```python
657
+ create_script(
658
+ name="build",
659
+ script_type="shell_exec",
660
+ data={
661
+ "interpreter": "usr/bin/env bash",
662
+ "flags": "-euo pipefail",
663
+ "parameter": {
664
+ "output-dir": {
665
+ "type": "string",
666
+ "required": True,
667
+ "description": "Directory to write build artefacts into",
668
+ "short": "o",
669
+ },
670
+ },
671
+ "body": 'mkdir -p "$OUTPUT_DIR"',
672
+ },
673
+ )
674
+ ```
675
+
676
+ ### All four parameter types
677
+
678
+ ```yaml
679
+ parameter:
680
+ name:
681
+ type: string
682
+ required: true
683
+ description: Name to greet
684
+ count:
685
+ type: integer
686
+ default: "1"
687
+ description: How many times to greet
688
+ verbose:
689
+ type: boolean
690
+ description: Enable verbose output
691
+ tags:
692
+ type: array
693
+ description: Additional tags
694
+ array_delimiter: ","
695
+ ```
696
+
697
+ ### Enum + path validation
698
+
699
+ ```yaml
700
+ parameter:
701
+ action:
702
+ type: string
703
+ required: true
704
+ validation:
705
+ enum: [copy, move, delete]
706
+ source:
707
+ type: string
708
+ required: true
709
+ validation:
710
+ path_existence:
711
+ must_exist: true
712
+ type: file
713
+ ```
714
+
715
+ ### Integer range
716
+
717
+ ```yaml
718
+ parameter:
719
+ workers:
720
+ type: integer
721
+ default: "4"
722
+ validation:
723
+ integer_range:
724
+ min: 1
725
+ max: 32
726
+ ```
727
+
728
+ ### Regex pattern
729
+
730
+ ```yaml
731
+ parameter:
732
+ slug:
733
+ type: string
734
+ required: true
735
+ validation:
736
+ regex: "^[a-z][a-z0-9_-]{2,31}$"
737
+ ```
738
+
739
+ ### Return values
740
+
741
+ ```python
742
+ data = {
743
+ "body": 'result="hello"',
744
+ "return": [{"name": "result", "variable": "result", "type": "string"}],
745
+ }
746
+ ```
747
+
748
+ Caller:
749
+
750
+ ```bash
751
+ output=$(my_function --arg value)
752
+ ```
753
+
754
+ ### Genuinely optional parameter (no default, no required check)
755
+
756
+ ```yaml
757
+ parameter:
758
+ comment:
759
+ type: string
760
+ required: false # variable may remain empty; no exit-1 check emitted
761
+ ```