@styx-api/core 0.6.0 → 0.6.1
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/dist/index.cjs +20 -9
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +20 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/backend/boutiques/boutiques.ts +19 -5
- package/src/backend/python/arg-builder.ts +8 -0
- package/src/frontend/boutiques/parser.ts +10 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@styx-api/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Styx compiler core: parses CLI tool descriptors (e.g. Boutiques), optimizes an IR, solves typed parameter bindings, and generates type-safe wrappers (TypeScript, Python, JSON Schema). Part of the Styx/NiWrap ecosystem.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"styx",
|
|
@@ -297,7 +297,10 @@ class BoutiquesEmitter {
|
|
|
297
297
|
}
|
|
298
298
|
if (peeled.flag) {
|
|
299
299
|
input["command-line-flag"] = peeled.flag;
|
|
300
|
-
|
|
300
|
+
// Emit the separator whenever the flag is fused with its value, including
|
|
301
|
+
// the empty (direct-concatenation) case; absent means the default space.
|
|
302
|
+
if (peeled.flagSeparator !== undefined)
|
|
303
|
+
input["command-line-flag-separator"] = peeled.flagSeparator;
|
|
301
304
|
}
|
|
302
305
|
if (mapped.integer) input.integer = true;
|
|
303
306
|
if (mapped.minimum !== undefined) input.minimum = mapped.minimum;
|
|
@@ -547,7 +550,10 @@ class BoutiquesEmitter {
|
|
|
547
550
|
// Flag
|
|
548
551
|
if (peeled.flag) {
|
|
549
552
|
input["command-line-flag"] = peeled.flag;
|
|
550
|
-
|
|
553
|
+
// Emit the separator whenever the flag is fused with its value, including
|
|
554
|
+
// the empty (direct-concatenation) case; absent means the default space.
|
|
555
|
+
if (peeled.flagSeparator !== undefined)
|
|
556
|
+
input["command-line-flag-separator"] = peeled.flagSeparator;
|
|
551
557
|
}
|
|
552
558
|
|
|
553
559
|
// Constraints from mapped type
|
|
@@ -650,9 +656,17 @@ class BoutiquesEmitter {
|
|
|
650
656
|
const nodes = node.attrs.nodes;
|
|
651
657
|
if (nodes.length === 2 && nodes[0]!.kind === "literal") {
|
|
652
658
|
const flagLit = nodes[0]!.attrs.str;
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
659
|
+
if (node.attrs.join !== undefined) {
|
|
660
|
+
// Joined: flag + value form one argv token, so a trailing `=` (or an
|
|
661
|
+
// empty separator for direct concatenation) is the flag-separator.
|
|
662
|
+
const { flag, separator } = this.splitFlagLiteral(flagLit);
|
|
663
|
+
result.flag = flag;
|
|
664
|
+
result.flagSeparator = separator; // may be "" (direct concatenation)
|
|
665
|
+
} else {
|
|
666
|
+
// Not joined: flag and value are separate argv tokens, so the whole
|
|
667
|
+
// literal is the flag with no separator.
|
|
668
|
+
result.flag = flagLit;
|
|
669
|
+
}
|
|
656
670
|
this.peelNodeInner(nodes[1]!, type, result);
|
|
657
671
|
}
|
|
658
672
|
// Otherwise don't peel further (it's a struct sequence or similar)
|
|
@@ -25,6 +25,14 @@ export function resultToStmt(r: ArgResult): string {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function appendLines(cb: CodeBuilder, code: string): void {
|
|
28
|
+
// Every caller emits `code` as an indented branch body (an `if`/`elif`/`else`
|
|
29
|
+
// or optional block). A union variant or optional can legitimately contribute
|
|
30
|
+
// no command-line arguments (e.g. an "off"/"none" mode), leaving `code` empty -
|
|
31
|
+
// emit `pass` so the block is valid Python instead of an empty, un-indented one.
|
|
32
|
+
if (code.trim() === "") {
|
|
33
|
+
cb.line("pass");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
28
36
|
for (const line of code.split("\n")) cb.line(line);
|
|
29
37
|
}
|
|
30
38
|
|
|
@@ -510,13 +510,21 @@ export class BoutiquesParser implements Frontend {
|
|
|
510
510
|
const flag = btInput["command-line-flag"];
|
|
511
511
|
if (!isString(flag)) return node;
|
|
512
512
|
|
|
513
|
+
// A non-space separator (e.g. `=` or `""`) fuses the flag and value into a
|
|
514
|
+
// single argv token (`--flag=value` / `--flagvalue`), so the sequence is
|
|
515
|
+
// joined. The default/space separator keeps them as separate argv elements
|
|
516
|
+
// (`--flag value`).
|
|
513
517
|
const flagSep = btInput["command-line-flag-separator"];
|
|
518
|
+
const fused = isString(flagSep) && flagSep !== " ";
|
|
514
519
|
const prefix: Literal = {
|
|
515
520
|
kind: "literal",
|
|
516
|
-
attrs: { str: flag +
|
|
521
|
+
attrs: { str: fused ? flag + flagSep : flag },
|
|
517
522
|
};
|
|
518
523
|
|
|
519
|
-
return {
|
|
524
|
+
return {
|
|
525
|
+
kind: "sequence",
|
|
526
|
+
attrs: { nodes: [prefix, node], ...(fused && { join: "" }) },
|
|
527
|
+
};
|
|
520
528
|
}
|
|
521
529
|
|
|
522
530
|
private wrapWithOptional(node: Expr): Optional {
|