@styx-api/core 0.1.0 → 0.3.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/dist/index.cjs +475 -97
- package/dist/index.d.cts +8 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +8 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +475 -98
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/backend/index.ts +7 -1
- package/src/backend/typescript/index.ts +1 -0
- package/src/frontend/detect-format.ts +10 -1
- package/src/frontend/mrtrix/index.ts +1 -0
- package/src/frontend/mrtrix/parser.ts +412 -0
- package/src/index.ts +4 -1
package/dist/index.cjs
CHANGED
|
@@ -9,20 +9,20 @@ function findDeepName$1(node) {
|
|
|
9
9
|
if (name) return name;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
function isObject$
|
|
12
|
+
function isObject$3(x) {
|
|
13
13
|
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
14
14
|
}
|
|
15
|
-
function isString$
|
|
15
|
+
function isString$3(x) {
|
|
16
16
|
return typeof x === "string";
|
|
17
17
|
}
|
|
18
18
|
function isNumber$1(x) {
|
|
19
19
|
return typeof x === "number";
|
|
20
20
|
}
|
|
21
|
-
function isArray$
|
|
21
|
+
function isArray$3(x) {
|
|
22
22
|
return Array.isArray(x);
|
|
23
23
|
}
|
|
24
24
|
function isArgparseMarker(x) {
|
|
25
|
-
return isObject$
|
|
25
|
+
return isObject$3(x) && isString$3(x.__argparse__);
|
|
26
26
|
}
|
|
27
27
|
function isSuppressed(x) {
|
|
28
28
|
return isArgparseMarker(x) && x.__argparse__ === "SUPPRESS";
|
|
@@ -56,7 +56,7 @@ var ArgdumpParser = class {
|
|
|
56
56
|
this.error(e instanceof SyntaxError ? e.message : "Invalid JSON");
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
59
|
-
if (!isObject$
|
|
59
|
+
if (!isObject$3(parsed)) {
|
|
60
60
|
this.error("JSON source is not an object");
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
@@ -64,11 +64,11 @@ var ArgdumpParser = class {
|
|
|
64
64
|
}
|
|
65
65
|
buildAppMeta(descriptor) {
|
|
66
66
|
const prog = descriptor.prog;
|
|
67
|
-
if (!isString$
|
|
67
|
+
if (!isString$3(prog)) return void 0;
|
|
68
68
|
let id = prog || void 0;
|
|
69
69
|
if (!id) {
|
|
70
70
|
const desc = descriptor.description;
|
|
71
|
-
if (isString$
|
|
71
|
+
if (isString$3(desc)) {
|
|
72
72
|
const match = desc.match(/^(\S+)/);
|
|
73
73
|
if (match) id = match[1].replace(/[:;,]+$/, "") || void 0;
|
|
74
74
|
}
|
|
@@ -78,8 +78,8 @@ var ArgdumpParser = class {
|
|
|
78
78
|
const epilog = descriptor.epilog;
|
|
79
79
|
let versionStr;
|
|
80
80
|
const actions = descriptor.actions;
|
|
81
|
-
if (isArray$
|
|
82
|
-
for (const action of actions) if (isObject$
|
|
81
|
+
if (isArray$3(actions)) {
|
|
82
|
+
for (const action of actions) if (isObject$3(action) && action.action_type === "version" && isString$3(action.version)) {
|
|
83
83
|
versionStr = action.version.replace(/%%?\(prog\)s\s*/g, "").trim();
|
|
84
84
|
if (!versionStr) versionStr = void 0;
|
|
85
85
|
break;
|
|
@@ -88,9 +88,9 @@ var ArgdumpParser = class {
|
|
|
88
88
|
return {
|
|
89
89
|
id,
|
|
90
90
|
...versionStr && { version: versionStr },
|
|
91
|
-
...(isString$
|
|
92
|
-
...isString$
|
|
93
|
-
...isString$
|
|
91
|
+
...(isString$3(description) || isString$3(epilog)) && { doc: {
|
|
92
|
+
...isString$3(description) && { description },
|
|
93
|
+
...isString$3(epilog) && { comment: epilog }
|
|
94
94
|
} }
|
|
95
95
|
};
|
|
96
96
|
}
|
|
@@ -98,9 +98,9 @@ var ArgdumpParser = class {
|
|
|
98
98
|
const typeInfo = action.type_info;
|
|
99
99
|
const fileTypeInfo = action.file_type_info;
|
|
100
100
|
const choices = action.choices;
|
|
101
|
-
if (isArray$
|
|
101
|
+
if (isArray$3(choices) && choices.length > 0) {
|
|
102
102
|
const alts = [];
|
|
103
|
-
for (const choice of choices) if (isString$
|
|
103
|
+
for (const choice of choices) if (isString$3(choice) || isNumber$1(choice)) alts.push({
|
|
104
104
|
kind: "literal",
|
|
105
105
|
attrs: { str: String(choice) }
|
|
106
106
|
});
|
|
@@ -111,13 +111,13 @@ var ArgdumpParser = class {
|
|
|
111
111
|
attrs: { alts }
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
|
-
if (isObject$
|
|
114
|
+
if (isObject$3(fileTypeInfo)) return {
|
|
115
115
|
kind: "path",
|
|
116
116
|
attrs: {}
|
|
117
117
|
};
|
|
118
|
-
if (isObject$
|
|
118
|
+
if (isObject$3(typeInfo)) {
|
|
119
119
|
const name = typeInfo.name;
|
|
120
|
-
if (!isString$
|
|
120
|
+
if (!isString$3(name)) return this.inferFromSamples(action) ?? {
|
|
121
121
|
kind: "str",
|
|
122
122
|
attrs: {}
|
|
123
123
|
};
|
|
@@ -166,7 +166,7 @@ var ArgdumpParser = class {
|
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
168
|
resolveByModule(mod) {
|
|
169
|
-
if (!isString$
|
|
169
|
+
if (!isString$3(mod)) return null;
|
|
170
170
|
if (mod === "pathlib" || mod === "os.path" || mod.includes("path")) return {
|
|
171
171
|
kind: "path",
|
|
172
172
|
attrs: {}
|
|
@@ -181,7 +181,7 @@ var ArgdumpParser = class {
|
|
|
181
181
|
inferFromSamples(action) {
|
|
182
182
|
const samples = [];
|
|
183
183
|
const def = action.default;
|
|
184
|
-
if (isArray$
|
|
184
|
+
if (isArray$3(def)) samples.push(...def);
|
|
185
185
|
else samples.push(def);
|
|
186
186
|
samples.push(action.const);
|
|
187
187
|
let sawNumber = false;
|
|
@@ -250,10 +250,10 @@ var ArgdumpParser = class {
|
|
|
250
250
|
const dest = action.dest;
|
|
251
251
|
const help = action.help;
|
|
252
252
|
const defaultVal = action.default;
|
|
253
|
-
const name = this.preferredName(action) ?? (isString$
|
|
253
|
+
const name = this.preferredName(action) ?? (isString$3(dest) ? dest : void 0);
|
|
254
254
|
const hasName = name !== void 0;
|
|
255
|
-
const hasHelp = isString$
|
|
256
|
-
const hasDefault = (isString$
|
|
255
|
+
const hasHelp = isString$3(help) && !isSuppressed(help);
|
|
256
|
+
const hasDefault = (isString$3(defaultVal) || isNumber$1(defaultVal) || typeof defaultVal === "boolean") && !isSuppressed(defaultVal);
|
|
257
257
|
if (!hasName && !hasHelp && !hasDefault) return void 0;
|
|
258
258
|
return {
|
|
259
259
|
...hasName && { name },
|
|
@@ -263,20 +263,20 @@ var ArgdumpParser = class {
|
|
|
263
263
|
}
|
|
264
264
|
getOptionFlag(action) {
|
|
265
265
|
const optionStrings = action.option_strings;
|
|
266
|
-
if (!isArray$
|
|
267
|
-
for (const opt of optionStrings) if (isString$
|
|
266
|
+
if (!isArray$3(optionStrings) || optionStrings.length === 0) return null;
|
|
267
|
+
for (const opt of optionStrings) if (isString$3(opt) && opt.startsWith("--")) return opt;
|
|
268
268
|
const first = optionStrings[0];
|
|
269
|
-
return isString$
|
|
269
|
+
return isString$3(first) ? first : null;
|
|
270
270
|
}
|
|
271
271
|
/** Prefer the first --long flag (without leading dashes) over dest. */
|
|
272
272
|
preferredName(action) {
|
|
273
273
|
const optionStrings = action.option_strings;
|
|
274
|
-
if (!isArray$
|
|
275
|
-
for (const opt of optionStrings) if (isString$
|
|
274
|
+
if (!isArray$3(optionStrings)) return void 0;
|
|
275
|
+
for (const opt of optionStrings) if (isString$3(opt) && opt.startsWith("--") && opt.length > 2) return opt.slice(2);
|
|
276
276
|
}
|
|
277
277
|
isPositional(action) {
|
|
278
278
|
const optionStrings = action.option_strings;
|
|
279
|
-
return !isArray$
|
|
279
|
+
return !isArray$3(optionStrings) || optionStrings.length === 0;
|
|
280
280
|
}
|
|
281
281
|
buildAction(action) {
|
|
282
282
|
const actionType = action.action_type ?? "store";
|
|
@@ -294,7 +294,7 @@ var ArgdumpParser = class {
|
|
|
294
294
|
case "help":
|
|
295
295
|
case "version": return null;
|
|
296
296
|
case "unknown":
|
|
297
|
-
this.warn(`Unknown action type for '${action.dest}'` + (isString$
|
|
297
|
+
this.warn(`Unknown action type for '${action.dest}'` + (isString$3(action.custom_action_class) ? ` (custom class: ${action.custom_action_class})` : "") + ", treating as store");
|
|
298
298
|
return this.buildStore(action);
|
|
299
299
|
default:
|
|
300
300
|
this.warn(`Unrecognized action_type '${actionType}' for '${action.dest}', skipping`);
|
|
@@ -406,20 +406,20 @@ var ArgdumpParser = class {
|
|
|
406
406
|
}
|
|
407
407
|
buildBooleanOptional(action) {
|
|
408
408
|
const optionStrings = action.option_strings;
|
|
409
|
-
if (!isArray$
|
|
409
|
+
if (!isArray$3(optionStrings) || optionStrings.length === 0) {
|
|
410
410
|
this.error(`boolean_optional action '${action.dest}' has no option strings`);
|
|
411
411
|
return null;
|
|
412
412
|
}
|
|
413
413
|
let posFlag = null;
|
|
414
414
|
let negFlag = null;
|
|
415
415
|
for (const opt of optionStrings) {
|
|
416
|
-
if (!isString$
|
|
416
|
+
if (!isString$3(opt)) continue;
|
|
417
417
|
if (opt.startsWith("--no-")) negFlag = opt;
|
|
418
418
|
else if (opt.startsWith("--")) posFlag = opt;
|
|
419
419
|
}
|
|
420
420
|
if (!posFlag) {
|
|
421
|
-
posFlag = isString$
|
|
422
|
-
negFlag = isString$
|
|
421
|
+
posFlag = isString$3(optionStrings[0]) ? optionStrings[0] : null;
|
|
422
|
+
negFlag = isString$3(optionStrings[1]) ? optionStrings[1] : null;
|
|
423
423
|
}
|
|
424
424
|
if (!posFlag) {
|
|
425
425
|
this.error(`boolean_optional action '${action.dest}' has no valid option strings`);
|
|
@@ -546,14 +546,14 @@ var ArgdumpParser = class {
|
|
|
546
546
|
}
|
|
547
547
|
buildSubparsers(action) {
|
|
548
548
|
const subparsers = action.subparsers;
|
|
549
|
-
if (!isObject$
|
|
549
|
+
if (!isObject$3(subparsers)) {
|
|
550
550
|
this.error(`parsers action '${action.dest}' has no subparsers`);
|
|
551
551
|
return null;
|
|
552
552
|
}
|
|
553
|
-
const aliases = isObject$
|
|
553
|
+
const aliases = isObject$3(action.subparsers_aliases) ? action.subparsers_aliases : {};
|
|
554
554
|
const alts = [];
|
|
555
555
|
for (const [name, parserInfo] of Object.entries(subparsers)) {
|
|
556
|
-
if (!isObject$
|
|
556
|
+
if (!isObject$3(parserInfo)) {
|
|
557
557
|
this.warn(`Skipping non-object subparser '${name}'`);
|
|
558
558
|
continue;
|
|
559
559
|
}
|
|
@@ -567,8 +567,8 @@ var ArgdumpParser = class {
|
|
|
567
567
|
}, ...subExpr.attrs.nodes] }
|
|
568
568
|
};
|
|
569
569
|
const subAliases = aliases[name];
|
|
570
|
-
const aliasDoc = isArray$
|
|
571
|
-
const description = isString$
|
|
570
|
+
const aliasDoc = isArray$3(subAliases) && subAliases.length > 0 ? ` (aliases: ${subAliases.filter(isString$3).join(", ")})` : "";
|
|
571
|
+
const description = isString$3(parserInfo.description) ? parserInfo.description : void 0;
|
|
572
572
|
const docStr = description ? description + aliasDoc : aliasDoc ? aliasDoc.slice(1) : void 0;
|
|
573
573
|
seq.meta = {
|
|
574
574
|
name,
|
|
@@ -601,11 +601,11 @@ var ArgdumpParser = class {
|
|
|
601
601
|
applyMutualExclusion(actionsByDest, groups, nodes, nodesByDest) {
|
|
602
602
|
const excluded = /* @__PURE__ */ new Set();
|
|
603
603
|
for (const group of groups) {
|
|
604
|
-
if (!isObject$
|
|
604
|
+
if (!isObject$3(group)) continue;
|
|
605
605
|
const groupActions = group.actions;
|
|
606
|
-
if (!isArray$
|
|
606
|
+
if (!isArray$3(groupActions)) continue;
|
|
607
607
|
const memberDests = [];
|
|
608
|
-
for (const dest of groupActions) if (isString$
|
|
608
|
+
for (const dest of groupActions) if (isString$3(dest) && nodesByDest.has(dest)) memberDests.push(dest);
|
|
609
609
|
if (memberDests.length < 2) continue;
|
|
610
610
|
const altMembers = [];
|
|
611
611
|
for (const dest of memberDests) {
|
|
@@ -635,7 +635,7 @@ var ArgdumpParser = class {
|
|
|
635
635
|
kind: "optional",
|
|
636
636
|
attrs: { node: alt }
|
|
637
637
|
};
|
|
638
|
-
const groupName = (isString$
|
|
638
|
+
const groupName = (isString$3(group.title) ? group.title : void 0) ?? (memberDests.length === 2 ? `${memberDests[0]}_or_${memberDests[1]}` : `${memberDests[0]}_choice`);
|
|
639
639
|
groupNode.meta = {
|
|
640
640
|
...groupNode.meta,
|
|
641
641
|
name: groupName
|
|
@@ -652,7 +652,7 @@ var ArgdumpParser = class {
|
|
|
652
652
|
}
|
|
653
653
|
parseParserInfo(descriptor) {
|
|
654
654
|
const actions = descriptor.actions;
|
|
655
|
-
if (!isArray$
|
|
655
|
+
if (!isArray$3(actions)) return {
|
|
656
656
|
kind: "sequence",
|
|
657
657
|
attrs: { nodes: [] }
|
|
658
658
|
};
|
|
@@ -661,11 +661,11 @@ var ArgdumpParser = class {
|
|
|
661
661
|
const actionsByDest = /* @__PURE__ */ new Map();
|
|
662
662
|
const nodesByDest = /* @__PURE__ */ new Map();
|
|
663
663
|
for (const rawAction of actions) {
|
|
664
|
-
if (!isObject$
|
|
664
|
+
if (!isObject$3(rawAction)) continue;
|
|
665
665
|
const node = this.buildAction(rawAction);
|
|
666
666
|
if (!node) continue;
|
|
667
667
|
const dest = rawAction.dest;
|
|
668
|
-
if (isString$
|
|
668
|
+
if (isString$3(dest)) {
|
|
669
669
|
actionsByDest.set(dest, rawAction);
|
|
670
670
|
nodesByDest.set(dest, node);
|
|
671
671
|
}
|
|
@@ -674,7 +674,7 @@ var ArgdumpParser = class {
|
|
|
674
674
|
}
|
|
675
675
|
let allNodes = [...positionals, ...optionals];
|
|
676
676
|
const mutexGroups = descriptor.mutually_exclusive_groups;
|
|
677
|
-
if (isArray$
|
|
677
|
+
if (isArray$3(mutexGroups) && mutexGroups.length > 0) allNodes = this.applyMutualExclusion(actionsByDest, mutexGroups, allNodes, nodesByDest);
|
|
678
678
|
return {
|
|
679
679
|
kind: "sequence",
|
|
680
680
|
attrs: { nodes: allNodes }
|
|
@@ -716,7 +716,7 @@ var ArgdumpParser = class {
|
|
|
716
716
|
};
|
|
717
717
|
}
|
|
718
718
|
const prog = descriptor.prog;
|
|
719
|
-
if (isString$
|
|
719
|
+
if (isString$3(prog) && prog) expr.attrs.nodes.unshift({
|
|
720
720
|
kind: "literal",
|
|
721
721
|
attrs: { str: prog }
|
|
722
722
|
});
|
|
@@ -848,16 +848,16 @@ function boutiquesSplitCommand(command) {
|
|
|
848
848
|
|
|
849
849
|
//#endregion
|
|
850
850
|
//#region src/frontend/boutiques/parser.ts
|
|
851
|
-
function isObject$
|
|
851
|
+
function isObject$2(x) {
|
|
852
852
|
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
853
853
|
}
|
|
854
|
-
function isString$
|
|
854
|
+
function isString$2(x) {
|
|
855
855
|
return typeof x === "string";
|
|
856
856
|
}
|
|
857
857
|
function isNumber(x) {
|
|
858
858
|
return typeof x === "number";
|
|
859
859
|
}
|
|
860
|
-
function isArray$
|
|
860
|
+
function isArray$2(x) {
|
|
861
861
|
return Array.isArray(x);
|
|
862
862
|
}
|
|
863
863
|
var InputTypePrimitive = /* @__PURE__ */ function(InputTypePrimitive) {
|
|
@@ -899,7 +899,7 @@ var BoutiquesParser = class {
|
|
|
899
899
|
this.error(e instanceof SyntaxError ? e.message : "Invalid JSON");
|
|
900
900
|
return null;
|
|
901
901
|
}
|
|
902
|
-
if (!isObject$
|
|
902
|
+
if (!isObject$2(parsed)) {
|
|
903
903
|
this.error("JSON source is not an object");
|
|
904
904
|
return null;
|
|
905
905
|
}
|
|
@@ -911,9 +911,9 @@ var BoutiquesParser = class {
|
|
|
911
911
|
this.error(`type is missing for input: '${btInput.id}'`);
|
|
912
912
|
return null;
|
|
913
913
|
}
|
|
914
|
-
if (isObject$
|
|
915
|
-
if (isArray$
|
|
916
|
-
const typeName = isString$
|
|
914
|
+
if (isObject$2(btType)) return InputTypePrimitive.SubCommand;
|
|
915
|
+
if (isArray$2(btType)) return InputTypePrimitive.SubCommandUnion;
|
|
916
|
+
const typeName = isString$2(btType) ? btType : String(btType);
|
|
917
917
|
switch (typeName) {
|
|
918
918
|
case "String": return InputTypePrimitive.String;
|
|
919
919
|
case "File": return InputTypePrimitive.File;
|
|
@@ -952,43 +952,43 @@ var BoutiquesParser = class {
|
|
|
952
952
|
const title = btInput.name;
|
|
953
953
|
const description = btInput.description;
|
|
954
954
|
const defaultValue = btInput["default-value"];
|
|
955
|
-
const hasDefault = isString$
|
|
956
|
-
if (!isString$
|
|
955
|
+
const hasDefault = isString$2(defaultValue) || isNumber(defaultValue) || typeof defaultValue === "boolean";
|
|
956
|
+
if (!isString$2(name) && !isString$2(title) && !isString$2(description) && !hasDefault) return;
|
|
957
957
|
return {
|
|
958
|
-
...isString$
|
|
959
|
-
...(isString$
|
|
960
|
-
...isString$
|
|
961
|
-
...isString$
|
|
958
|
+
...isString$2(name) && { name },
|
|
959
|
+
...(isString$2(title) || isString$2(description)) && { doc: {
|
|
960
|
+
...isString$2(title) && { title },
|
|
961
|
+
...isString$2(description) && { description }
|
|
962
962
|
} },
|
|
963
963
|
...hasDefault && { defaultValue }
|
|
964
964
|
};
|
|
965
965
|
}
|
|
966
966
|
buildStreamMeta(bt) {
|
|
967
967
|
const id = bt.id;
|
|
968
|
-
if (!isString$
|
|
968
|
+
if (!isString$2(id)) return void 0;
|
|
969
969
|
const name = bt.name;
|
|
970
970
|
const description = bt.description;
|
|
971
971
|
return {
|
|
972
972
|
name: id,
|
|
973
|
-
...(isString$
|
|
974
|
-
...isString$
|
|
975
|
-
...isString$
|
|
973
|
+
...(isString$2(name) || isString$2(description)) && { doc: {
|
|
974
|
+
...isString$2(name) && { title: name },
|
|
975
|
+
...isString$2(description) && { description }
|
|
976
976
|
} }
|
|
977
977
|
};
|
|
978
978
|
}
|
|
979
979
|
buildOutput(out, lookup, idOptional) {
|
|
980
980
|
const id = out.id;
|
|
981
|
-
if (!isString$
|
|
981
|
+
if (!isString$2(id)) {
|
|
982
982
|
this.error("output-files entry missing id");
|
|
983
983
|
return null;
|
|
984
984
|
}
|
|
985
985
|
const template = out["path-template"];
|
|
986
|
-
if (!isString$
|
|
986
|
+
if (!isString$2(template)) {
|
|
987
987
|
this.error(`output-files entry '${id}' missing path-template`);
|
|
988
988
|
return null;
|
|
989
989
|
}
|
|
990
990
|
const stripRaw = out["path-template-stripped-extensions"];
|
|
991
|
-
const stripExtensions = isArray$
|
|
991
|
+
const stripExtensions = isArray$2(stripRaw) && stripRaw.every(isString$2) && stripRaw.length > 0 ? stripRaw : void 0;
|
|
992
992
|
const tokens = destructTemplate(template, lookup).map((part) => {
|
|
993
993
|
if (typeof part === "string") return {
|
|
994
994
|
kind: "literal",
|
|
@@ -1007,9 +1007,9 @@ var BoutiquesParser = class {
|
|
|
1007
1007
|
name: id,
|
|
1008
1008
|
tokens
|
|
1009
1009
|
};
|
|
1010
|
-
if (isString$
|
|
1011
|
-
...isString$
|
|
1012
|
-
...isString$
|
|
1010
|
+
if (isString$2(title) || isString$2(description)) output.doc = {
|
|
1011
|
+
...isString$2(title) && { title },
|
|
1012
|
+
...isString$2(description) && { description }
|
|
1013
1013
|
};
|
|
1014
1014
|
return { output };
|
|
1015
1015
|
}
|
|
@@ -1020,18 +1020,18 @@ var BoutiquesParser = class {
|
|
|
1020
1020
|
*/
|
|
1021
1021
|
attachOutputs(rootSeq, bt) {
|
|
1022
1022
|
const outputFiles = bt["output-files"];
|
|
1023
|
-
if (!isArray$
|
|
1023
|
+
if (!isArray$2(outputFiles)) return;
|
|
1024
1024
|
const lookup = {};
|
|
1025
1025
|
const idOptional = /* @__PURE__ */ new Set();
|
|
1026
1026
|
const inputs = bt["inputs"];
|
|
1027
|
-
if (isArray$
|
|
1028
|
-
for (const input of inputs) if (isObject$
|
|
1027
|
+
if (isArray$2(inputs)) {
|
|
1028
|
+
for (const input of inputs) if (isObject$2(input) && isString$2(input["value-key"]) && isString$2(input.id)) {
|
|
1029
1029
|
lookup[input["value-key"]] = nodeRef(input.id);
|
|
1030
1030
|
if (input.optional === true) idOptional.add(input.id);
|
|
1031
1031
|
}
|
|
1032
1032
|
}
|
|
1033
1033
|
for (const out of outputFiles) {
|
|
1034
|
-
if (!isObject$
|
|
1034
|
+
if (!isObject$2(out)) {
|
|
1035
1035
|
this.warn("Skipping non-object output-files entry");
|
|
1036
1036
|
continue;
|
|
1037
1037
|
}
|
|
@@ -1043,7 +1043,7 @@ var BoutiquesParser = class {
|
|
|
1043
1043
|
}
|
|
1044
1044
|
buildAppMeta(bt) {
|
|
1045
1045
|
const id = bt.id ?? bt.name;
|
|
1046
|
-
if (!isString$
|
|
1046
|
+
if (!isString$2(id)) return void 0;
|
|
1047
1047
|
const name = bt.name;
|
|
1048
1048
|
const description = bt.description;
|
|
1049
1049
|
const version = bt["tool-version"];
|
|
@@ -1053,26 +1053,26 @@ var BoutiquesParser = class {
|
|
|
1053
1053
|
const stdout = bt["stdout-output"];
|
|
1054
1054
|
const stderr = bt["stderr-output"];
|
|
1055
1055
|
const doc = {
|
|
1056
|
-
...isString$
|
|
1057
|
-
...isString$
|
|
1058
|
-
...isString$
|
|
1059
|
-
...isString$
|
|
1056
|
+
...isString$2(name) && { title: name },
|
|
1057
|
+
...isString$2(description) && { description },
|
|
1058
|
+
...isString$2(author) && { authors: [author] },
|
|
1059
|
+
...isString$2(url) && { urls: [url] }
|
|
1060
1060
|
};
|
|
1061
1061
|
return {
|
|
1062
1062
|
id,
|
|
1063
|
-
...isString$
|
|
1063
|
+
...isString$2(version) && { version },
|
|
1064
1064
|
...Object.keys(doc).length > 0 && { doc },
|
|
1065
|
-
...isObject$
|
|
1065
|
+
...isObject$2(container) && isString$2(container.image) && { container: {
|
|
1066
1066
|
image: container.image,
|
|
1067
|
-
...isString$
|
|
1067
|
+
...isString$2(container.type) && { type: container.type }
|
|
1068
1068
|
} },
|
|
1069
|
-
...isObject$
|
|
1070
|
-
...isObject$
|
|
1069
|
+
...isObject$2(stdout) && { stdout: this.buildStreamMeta(stdout) },
|
|
1070
|
+
...isObject$2(stderr) && { stderr: this.buildStreamMeta(stderr) }
|
|
1071
1071
|
};
|
|
1072
1072
|
}
|
|
1073
1073
|
buildEnumAlternative(choices, meta) {
|
|
1074
1074
|
const alts = [];
|
|
1075
|
-
for (const choice of choices) if (isString$
|
|
1075
|
+
for (const choice of choices) if (isString$2(choice)) alts.push({
|
|
1076
1076
|
kind: "literal",
|
|
1077
1077
|
attrs: { str: choice }
|
|
1078
1078
|
});
|
|
@@ -1093,7 +1093,7 @@ var BoutiquesParser = class {
|
|
|
1093
1093
|
const meta = this.buildNodeMeta(btInput);
|
|
1094
1094
|
if (inputType.isEnum) {
|
|
1095
1095
|
const choices = btInput["value-choices"];
|
|
1096
|
-
if (!isArray$
|
|
1096
|
+
if (!isArray$2(choices)) {
|
|
1097
1097
|
this.error(`Invalid value-choices for '${btInput.id}'`);
|
|
1098
1098
|
return null;
|
|
1099
1099
|
}
|
|
@@ -1147,7 +1147,7 @@ var BoutiquesParser = class {
|
|
|
1147
1147
|
}
|
|
1148
1148
|
case InputTypePrimitive.Flag: {
|
|
1149
1149
|
const flag = btInput["command-line-flag"];
|
|
1150
|
-
if (!isString$
|
|
1150
|
+
if (!isString$2(flag)) {
|
|
1151
1151
|
this.error(`Flag input '${btInput.id}' missing command-line-flag`);
|
|
1152
1152
|
return null;
|
|
1153
1153
|
}
|
|
@@ -1165,7 +1165,7 @@ var BoutiquesParser = class {
|
|
|
1165
1165
|
}
|
|
1166
1166
|
case InputTypePrimitive.SubCommand: {
|
|
1167
1167
|
const nested = btInput.type;
|
|
1168
|
-
if (!isObject$
|
|
1168
|
+
if (!isObject$2(nested)) {
|
|
1169
1169
|
this.error(`Invalid subcommand type for '${btInput.id}'`);
|
|
1170
1170
|
return null;
|
|
1171
1171
|
}
|
|
@@ -1175,14 +1175,14 @@ var BoutiquesParser = class {
|
|
|
1175
1175
|
}
|
|
1176
1176
|
case InputTypePrimitive.SubCommandUnion: {
|
|
1177
1177
|
const alts = btInput.type;
|
|
1178
|
-
if (!isArray$
|
|
1178
|
+
if (!isArray$2(alts)) {
|
|
1179
1179
|
this.error(`Invalid subcommand union type for '${btInput.id}'`);
|
|
1180
1180
|
return null;
|
|
1181
1181
|
}
|
|
1182
1182
|
const parsedAlts = [];
|
|
1183
1183
|
const usedTags = /* @__PURE__ */ new Set();
|
|
1184
1184
|
for (const alt of alts) {
|
|
1185
|
-
if (!isObject$
|
|
1185
|
+
if (!isObject$2(alt)) {
|
|
1186
1186
|
this.warn("Skipping non-object subcommand alternative");
|
|
1187
1187
|
continue;
|
|
1188
1188
|
}
|
|
@@ -1234,7 +1234,7 @@ var BoutiquesParser = class {
|
|
|
1234
1234
|
kind: "repeat",
|
|
1235
1235
|
attrs: {
|
|
1236
1236
|
node,
|
|
1237
|
-
...isString$
|
|
1237
|
+
...isString$2(btInput["list-separator"]) && { join: btInput["list-separator"] },
|
|
1238
1238
|
...isNumber(btInput["min-list-entries"]) && { countMin: btInput["min-list-entries"] },
|
|
1239
1239
|
...isNumber(btInput["max-list-entries"]) && { countMax: btInput["max-list-entries"] }
|
|
1240
1240
|
}
|
|
@@ -1242,7 +1242,7 @@ var BoutiquesParser = class {
|
|
|
1242
1242
|
}
|
|
1243
1243
|
wrapWithFlag(node, btInput) {
|
|
1244
1244
|
const flag = btInput["command-line-flag"];
|
|
1245
|
-
if (!isString$
|
|
1245
|
+
if (!isString$2(flag)) return node;
|
|
1246
1246
|
return {
|
|
1247
1247
|
kind: "sequence",
|
|
1248
1248
|
attrs: { nodes: [{
|
|
@@ -1289,11 +1289,11 @@ var BoutiquesParser = class {
|
|
|
1289
1289
|
parseDescriptor(bt) {
|
|
1290
1290
|
const inputs = bt["inputs"];
|
|
1291
1291
|
const inputsLookup = /* @__PURE__ */ new Map();
|
|
1292
|
-
if (isArray$
|
|
1293
|
-
for (const input of inputs) if (isObject$
|
|
1292
|
+
if (isArray$2(inputs)) {
|
|
1293
|
+
for (const input of inputs) if (isObject$2(input) && isString$2(input["value-key"])) inputsLookup.set(input["value-key"], input);
|
|
1294
1294
|
}
|
|
1295
1295
|
const commandLine = bt["command-line"];
|
|
1296
|
-
const segments = isString$
|
|
1296
|
+
const segments = isString$2(commandLine) ? this.parseCommandLineTemplate(commandLine, inputsLookup) : [];
|
|
1297
1297
|
const rootSeq = {
|
|
1298
1298
|
kind: "sequence",
|
|
1299
1299
|
attrs: { nodes: [] }
|
|
@@ -1306,7 +1306,7 @@ var BoutiquesParser = class {
|
|
|
1306
1306
|
join: ""
|
|
1307
1307
|
}
|
|
1308
1308
|
};
|
|
1309
|
-
for (const elem of segment) if (isObject$
|
|
1309
|
+
for (const elem of segment) if (isObject$2(elem)) {
|
|
1310
1310
|
const inputType = this.getInputType(elem);
|
|
1311
1311
|
if (inputType === null) continue;
|
|
1312
1312
|
let node = this.buildTerminal(elem, inputType);
|
|
@@ -1478,6 +1478,382 @@ function camelCase(s) {
|
|
|
1478
1478
|
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
1479
1479
|
}
|
|
1480
1480
|
|
|
1481
|
+
//#endregion
|
|
1482
|
+
//#region src/frontend/mrtrix/parser.ts
|
|
1483
|
+
function isObject$1(x) {
|
|
1484
|
+
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
1485
|
+
}
|
|
1486
|
+
function isString$1(x) {
|
|
1487
|
+
return typeof x === "string";
|
|
1488
|
+
}
|
|
1489
|
+
function isArray$1(x) {
|
|
1490
|
+
return Array.isArray(x);
|
|
1491
|
+
}
|
|
1492
|
+
/** Coerce a possibly-missing list field to an array. */
|
|
1493
|
+
function asArray$1(x) {
|
|
1494
|
+
return isArray$1(x) ? x : [];
|
|
1495
|
+
}
|
|
1496
|
+
/** Input file types: each maps to a plain path terminal. */
|
|
1497
|
+
const INPUT_TYPES = new Set([
|
|
1498
|
+
"file in",
|
|
1499
|
+
"image in",
|
|
1500
|
+
"directory in",
|
|
1501
|
+
"tracks in"
|
|
1502
|
+
]);
|
|
1503
|
+
/** Output file types: each maps to a `str` (the user-supplied filename) + an `Output`. */
|
|
1504
|
+
const OUTPUT_TYPES = new Set([
|
|
1505
|
+
"file out",
|
|
1506
|
+
"image out",
|
|
1507
|
+
"directory out",
|
|
1508
|
+
"tracks out"
|
|
1509
|
+
]);
|
|
1510
|
+
/** A fresh empty root sequence for error returns (IR passes mutate in place,
|
|
1511
|
+
* so callers must not share a single instance). */
|
|
1512
|
+
function emptyExpr$1() {
|
|
1513
|
+
return {
|
|
1514
|
+
kind: "sequence",
|
|
1515
|
+
attrs: { nodes: [] }
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Parser for MRtrix3 C++ command definitions (`mrtrix.json`), as dumped by the
|
|
1520
|
+
* `__print_usage_json__` hook (see niwrap `extraction/mrtrix/`).
|
|
1521
|
+
*
|
|
1522
|
+
* The format is flat: positional `arguments`, plus `option_groups[].options`
|
|
1523
|
+
* where each option is a single-dash switch (`-id`) carrying 0..N positional
|
|
1524
|
+
* `arguments`. There are no unions, conditionals, or nested options. We lower
|
|
1525
|
+
* it onto the same `Expr` shapes the Boutiques/Workbench parsers emit:
|
|
1526
|
+
*
|
|
1527
|
+
* <command> <positionals...> [-option ...] ...
|
|
1528
|
+
*
|
|
1529
|
+
* - argument (input type) -> typed terminal
|
|
1530
|
+
* - argument (`* out`) -> str terminal + an Output entry referencing it
|
|
1531
|
+
* - option, 0 args -> opt(lit(-switch)) (bool flag)
|
|
1532
|
+
* - option, 1 arg -> opt(seq(lit(-switch), value)) (flat optional)
|
|
1533
|
+
* - option, >1 arg / multi -> opt|rep(seq(lit(-switch), ...)) (sub-struct)
|
|
1534
|
+
*
|
|
1535
|
+
* Type mapping mirrors the v1 `mrt2bt.js` converter's `set_type`. The dump does
|
|
1536
|
+
* not carry choice values, so a `choice` argument degrades to a plain string
|
|
1537
|
+
* (as it did in v1). Per-command quirks v1 hand-coded that the flat dump cannot
|
|
1538
|
+
* express (e.g. dwi2fod/mtnormalise paired in/out args) are intentionally NOT
|
|
1539
|
+
* special-cased here - they are patched on the niwrap side post-dump, keeping
|
|
1540
|
+
* this frontend format-general.
|
|
1541
|
+
*/
|
|
1542
|
+
var MrtrixParser = class {
|
|
1543
|
+
name = "mrtrix";
|
|
1544
|
+
extensions = ["json"];
|
|
1545
|
+
errors = [];
|
|
1546
|
+
warnings = [];
|
|
1547
|
+
usedNames = /* @__PURE__ */ new Set();
|
|
1548
|
+
reset() {
|
|
1549
|
+
this.errors = [];
|
|
1550
|
+
this.warnings = [];
|
|
1551
|
+
this.usedNames = /* @__PURE__ */ new Set();
|
|
1552
|
+
}
|
|
1553
|
+
/** Reserve a unique sibling name, suffixing `_2`, `_3`, ... on collision. */
|
|
1554
|
+
uniqueName(base) {
|
|
1555
|
+
if (!this.usedNames.has(base)) {
|
|
1556
|
+
this.usedNames.add(base);
|
|
1557
|
+
return base;
|
|
1558
|
+
}
|
|
1559
|
+
let n = 2;
|
|
1560
|
+
while (this.usedNames.has(`${base}_${n}`)) n++;
|
|
1561
|
+
const name = `${base}_${n}`;
|
|
1562
|
+
this.usedNames.add(name);
|
|
1563
|
+
this.warn(`Duplicate id '${base}'; renamed a sibling binding to '${name}'`);
|
|
1564
|
+
return name;
|
|
1565
|
+
}
|
|
1566
|
+
error(message, location) {
|
|
1567
|
+
this.errors.push({
|
|
1568
|
+
message,
|
|
1569
|
+
location
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
warn(message, location) {
|
|
1573
|
+
this.warnings.push({
|
|
1574
|
+
message,
|
|
1575
|
+
location
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
parseJSON(source) {
|
|
1579
|
+
let parsed;
|
|
1580
|
+
try {
|
|
1581
|
+
parsed = JSON.parse(source);
|
|
1582
|
+
} catch (e) {
|
|
1583
|
+
this.error(e instanceof SyntaxError ? e.message : "Invalid JSON");
|
|
1584
|
+
return null;
|
|
1585
|
+
}
|
|
1586
|
+
if (!isObject$1(parsed)) {
|
|
1587
|
+
this.error("JSON source is not an object");
|
|
1588
|
+
return null;
|
|
1589
|
+
}
|
|
1590
|
+
return parsed;
|
|
1591
|
+
}
|
|
1592
|
+
docFrom(description) {
|
|
1593
|
+
return isString$1(description) && description.length > 0 ? { description } : void 0;
|
|
1594
|
+
}
|
|
1595
|
+
buildAppMeta(cmd) {
|
|
1596
|
+
const name = cmd.name;
|
|
1597
|
+
if (!isString$1(name) || name.length === 0) {
|
|
1598
|
+
this.error("MRtrix descriptor missing required 'name' string");
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
const synopsis = cmd.synopsis;
|
|
1602
|
+
const paragraphs = asArray$1(cmd.description).filter(isString$1).join("\n\n");
|
|
1603
|
+
const author = cmd.author;
|
|
1604
|
+
const references = asArray$1(cmd.references).filter(isString$1);
|
|
1605
|
+
const version = cmd.version;
|
|
1606
|
+
const doc = {
|
|
1607
|
+
...isString$1(synopsis) && synopsis.length > 0 && { title: synopsis },
|
|
1608
|
+
...paragraphs.length > 0 && { description: paragraphs },
|
|
1609
|
+
...isString$1(author) && author.length > 0 && { authors: [author] },
|
|
1610
|
+
...references.length > 0 && { literature: references },
|
|
1611
|
+
urls: [`https://mrtrix.readthedocs.io/en/latest/reference/commands/${name}.html`]
|
|
1612
|
+
};
|
|
1613
|
+
return {
|
|
1614
|
+
id: name,
|
|
1615
|
+
...isString$1(version) && version.length > 0 && { version },
|
|
1616
|
+
doc
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Lower one MRtrix argument to its terminal node (carrying name + doc) and,
|
|
1621
|
+
* for output types, an accompanying `Output`.
|
|
1622
|
+
*/
|
|
1623
|
+
buildArgTerminal(arg, meta) {
|
|
1624
|
+
const argType = arg.type;
|
|
1625
|
+
if (!isString$1(argType)) {
|
|
1626
|
+
this.error(`MRtrix argument '${String(arg.id)}' missing 'type'`);
|
|
1627
|
+
return null;
|
|
1628
|
+
}
|
|
1629
|
+
const name = meta.name;
|
|
1630
|
+
switch (argType) {
|
|
1631
|
+
case "integer": return { node: int(meta) };
|
|
1632
|
+
case "float": return { node: float(meta) };
|
|
1633
|
+
case "text":
|
|
1634
|
+
case "choice":
|
|
1635
|
+
case "undefined": return { node: str(meta) };
|
|
1636
|
+
case "int seq": {
|
|
1637
|
+
const node = repJoin(",", int());
|
|
1638
|
+
node.meta = meta;
|
|
1639
|
+
return { node };
|
|
1640
|
+
}
|
|
1641
|
+
case "float seq": {
|
|
1642
|
+
const node = repJoin(",", float());
|
|
1643
|
+
node.meta = meta;
|
|
1644
|
+
return { node };
|
|
1645
|
+
}
|
|
1646
|
+
case "various": {
|
|
1647
|
+
const stringArm = seq(str({ name: "obj" }));
|
|
1648
|
+
stringArm.meta = {
|
|
1649
|
+
name: "VariousString",
|
|
1650
|
+
variantTag: "VariousString"
|
|
1651
|
+
};
|
|
1652
|
+
const fileArm = seq(path({ name: "obj" }));
|
|
1653
|
+
fileArm.meta = {
|
|
1654
|
+
name: "VariousFile",
|
|
1655
|
+
variantTag: "VariousFile"
|
|
1656
|
+
};
|
|
1657
|
+
const node = alt(stringArm, fileArm);
|
|
1658
|
+
node.meta = meta;
|
|
1659
|
+
return { node };
|
|
1660
|
+
}
|
|
1661
|
+
default:
|
|
1662
|
+
if (INPUT_TYPES.has(argType)) return { node: path(meta) };
|
|
1663
|
+
if (OUTPUT_TYPES.has(argType)) return {
|
|
1664
|
+
node: str(meta),
|
|
1665
|
+
output: {
|
|
1666
|
+
name,
|
|
1667
|
+
...meta.doc && { doc: meta.doc },
|
|
1668
|
+
tokens: [{
|
|
1669
|
+
kind: "ref",
|
|
1670
|
+
target: nodeRef(name)
|
|
1671
|
+
}],
|
|
1672
|
+
mediaTypes: [`mrtrix/${argType}`]
|
|
1673
|
+
}
|
|
1674
|
+
};
|
|
1675
|
+
this.error(`Unknown MRtrix type '${argType}' for '${name}'`);
|
|
1676
|
+
return null;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* A positional argument: typed terminal, wrapped for cardinality. Output-type
|
|
1681
|
+
* positionals push their `Output` onto the root's `outputs` collector.
|
|
1682
|
+
*/
|
|
1683
|
+
buildPositional(arg, rootOutputs) {
|
|
1684
|
+
if (!isObject$1(arg)) {
|
|
1685
|
+
this.warn("Skipping non-object argument");
|
|
1686
|
+
return null;
|
|
1687
|
+
}
|
|
1688
|
+
const id = arg.id;
|
|
1689
|
+
if (!isString$1(id)) {
|
|
1690
|
+
this.error("MRtrix argument missing 'id'");
|
|
1691
|
+
return null;
|
|
1692
|
+
}
|
|
1693
|
+
const meta = {
|
|
1694
|
+
name: this.uniqueName(snakeCase(id)),
|
|
1695
|
+
...this.docMeta(arg.description)
|
|
1696
|
+
};
|
|
1697
|
+
const built = this.buildArgTerminal(arg, meta);
|
|
1698
|
+
if (!built) return null;
|
|
1699
|
+
if (built.output) rootOutputs.push(built.output);
|
|
1700
|
+
return this.applyCardinality(built.node, arg, built.output !== void 0);
|
|
1701
|
+
}
|
|
1702
|
+
/** Wrap a terminal for `allow_multiple` (repeat) and `optional` (optional). */
|
|
1703
|
+
applyCardinality(node, arg, isOutput) {
|
|
1704
|
+
let result = node;
|
|
1705
|
+
if (arg.allow_multiple === true && !isOutput && result.kind !== "repeat") result = rep(result);
|
|
1706
|
+
else if (arg.allow_multiple === true && isOutput) this.warn(`Output argument '${String(arg.id)}' is allow_multiple; treating as single`);
|
|
1707
|
+
if (arg.optional === true) result = opt(result);
|
|
1708
|
+
return result;
|
|
1709
|
+
}
|
|
1710
|
+
docMeta(description) {
|
|
1711
|
+
const doc = this.docFrom(description);
|
|
1712
|
+
return doc ? { doc } : {};
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* An option `-{id}` with 0..N arguments. Returns the node plus any outputs
|
|
1716
|
+
* that must live on the ROOT (collapsing single-value options); sub-struct
|
|
1717
|
+
* options carry their own outputs on the struct sequence's meta.
|
|
1718
|
+
*/
|
|
1719
|
+
buildOption(option) {
|
|
1720
|
+
if (!isObject$1(option)) {
|
|
1721
|
+
this.warn("Skipping non-object option");
|
|
1722
|
+
return null;
|
|
1723
|
+
}
|
|
1724
|
+
const id = option.id;
|
|
1725
|
+
if (!isString$1(id)) {
|
|
1726
|
+
this.error("MRtrix option missing 'id'");
|
|
1727
|
+
return null;
|
|
1728
|
+
}
|
|
1729
|
+
const flag = `-${id}`;
|
|
1730
|
+
const name = this.uniqueName(snakeCase(id));
|
|
1731
|
+
const optDoc = this.docFrom(option.description);
|
|
1732
|
+
const args = asArray$1(option.arguments);
|
|
1733
|
+
const required = option.optional === false;
|
|
1734
|
+
if (args.length === 0) {
|
|
1735
|
+
if (option.allow_multiple === true) return {
|
|
1736
|
+
node: rep(lit(flag), {
|
|
1737
|
+
name,
|
|
1738
|
+
...optDoc && { doc: optDoc }
|
|
1739
|
+
}),
|
|
1740
|
+
rootOutputs: []
|
|
1741
|
+
};
|
|
1742
|
+
const meta = {
|
|
1743
|
+
name,
|
|
1744
|
+
...optDoc && { doc: optDoc },
|
|
1745
|
+
defaultValue: false
|
|
1746
|
+
};
|
|
1747
|
+
return {
|
|
1748
|
+
node: opt(lit(flag), meta),
|
|
1749
|
+
rootOutputs: []
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
if (args.length === 1 && option.allow_multiple !== true) {
|
|
1753
|
+
const arg = args[0];
|
|
1754
|
+
if (!isObject$1(arg)) {
|
|
1755
|
+
this.error(`MRtrix option '${id}' has a non-object argument`);
|
|
1756
|
+
return null;
|
|
1757
|
+
}
|
|
1758
|
+
const meta = {
|
|
1759
|
+
name,
|
|
1760
|
+
...optDoc && { doc: optDoc }
|
|
1761
|
+
};
|
|
1762
|
+
const built = this.buildArgTerminal(arg, meta);
|
|
1763
|
+
if (!built) return null;
|
|
1764
|
+
const valueNode = this.applyCardinality(built.node, arg, built.output !== void 0);
|
|
1765
|
+
const flagSeq = seq(lit(flag), valueNode);
|
|
1766
|
+
return {
|
|
1767
|
+
node: required ? flagSeq : opt(flagSeq),
|
|
1768
|
+
rootOutputs: built.output ? [built.output] : []
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
const inner = [lit(flag)];
|
|
1772
|
+
const structOutputs = [];
|
|
1773
|
+
for (const rawArg of args) {
|
|
1774
|
+
if (!isObject$1(rawArg)) {
|
|
1775
|
+
this.warn(`Skipping non-object argument of option '${id}'`);
|
|
1776
|
+
continue;
|
|
1777
|
+
}
|
|
1778
|
+
const argId = rawArg.id;
|
|
1779
|
+
if (!isString$1(argId)) {
|
|
1780
|
+
this.error(`MRtrix option '${id}' has an argument missing 'id'`);
|
|
1781
|
+
continue;
|
|
1782
|
+
}
|
|
1783
|
+
const argDoc = this.docFrom(rawArg.description) ?? optDoc;
|
|
1784
|
+
const meta = {
|
|
1785
|
+
name: snakeCase(argId),
|
|
1786
|
+
...argDoc && { doc: argDoc }
|
|
1787
|
+
};
|
|
1788
|
+
const built = this.buildArgTerminal(rawArg, meta);
|
|
1789
|
+
if (!built) continue;
|
|
1790
|
+
const valueNode = this.applyCardinality(built.node, rawArg, built.output !== void 0);
|
|
1791
|
+
inner.push(valueNode);
|
|
1792
|
+
if (built.output) structOutputs.push(built.output);
|
|
1793
|
+
}
|
|
1794
|
+
const structSeq = seq(...inner);
|
|
1795
|
+
structSeq.meta = {
|
|
1796
|
+
name,
|
|
1797
|
+
...structOutputs.length > 0 && { outputs: structOutputs }
|
|
1798
|
+
};
|
|
1799
|
+
const wrapperMeta = optDoc ? { doc: optDoc } : void 0;
|
|
1800
|
+
let node;
|
|
1801
|
+
if (option.allow_multiple === true) node = rep(structSeq, wrapperMeta);
|
|
1802
|
+
else if (required) {
|
|
1803
|
+
if (optDoc) structSeq.meta = {
|
|
1804
|
+
...structSeq.meta,
|
|
1805
|
+
doc: optDoc
|
|
1806
|
+
};
|
|
1807
|
+
node = structSeq;
|
|
1808
|
+
} else node = opt(structSeq, wrapperMeta);
|
|
1809
|
+
return {
|
|
1810
|
+
node,
|
|
1811
|
+
rootOutputs: []
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
parse(source, _filename) {
|
|
1815
|
+
this.reset();
|
|
1816
|
+
const cmd = this.parseJSON(source);
|
|
1817
|
+
if (!cmd) return {
|
|
1818
|
+
expr: emptyExpr$1(),
|
|
1819
|
+
errors: this.errors,
|
|
1820
|
+
warnings: this.warnings
|
|
1821
|
+
};
|
|
1822
|
+
const meta = this.buildAppMeta(cmd);
|
|
1823
|
+
if (!meta || !isString$1(cmd.name)) return {
|
|
1824
|
+
expr: emptyExpr$1(),
|
|
1825
|
+
errors: this.errors,
|
|
1826
|
+
warnings: this.warnings
|
|
1827
|
+
};
|
|
1828
|
+
const nodes = [lit(cmd.name)];
|
|
1829
|
+
const rootOutputs = [];
|
|
1830
|
+
for (const arg of asArray$1(cmd.arguments)) {
|
|
1831
|
+
const node = this.buildPositional(arg, rootOutputs);
|
|
1832
|
+
if (node) nodes.push(node);
|
|
1833
|
+
}
|
|
1834
|
+
for (const group of asArray$1(cmd.option_groups)) {
|
|
1835
|
+
if (!isObject$1(group)) continue;
|
|
1836
|
+
for (const option of asArray$1(group.options)) {
|
|
1837
|
+
const built = this.buildOption(option);
|
|
1838
|
+
if (!built) continue;
|
|
1839
|
+
nodes.push(built.node);
|
|
1840
|
+
rootOutputs.push(...built.rootOutputs);
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
const rootSeq = seq(...nodes);
|
|
1844
|
+
rootSeq.meta = {
|
|
1845
|
+
name: meta.id,
|
|
1846
|
+
...rootOutputs.length > 0 && { outputs: rootOutputs }
|
|
1847
|
+
};
|
|
1848
|
+
return {
|
|
1849
|
+
meta,
|
|
1850
|
+
expr: rootSeq,
|
|
1851
|
+
errors: this.errors,
|
|
1852
|
+
warnings: this.warnings
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
|
|
1481
1857
|
//#endregion
|
|
1482
1858
|
//#region src/frontend/workbench/parser.ts
|
|
1483
1859
|
function isObject(x) {
|
|
@@ -1809,6 +2185,7 @@ function detectFormat(source) {
|
|
|
1809
2185
|
const obj = parsed;
|
|
1810
2186
|
if (typeof obj.$schema === "string" && obj.$schema.includes("argdump")) return "argdump";
|
|
1811
2187
|
if (typeof obj.command === "string" && typeof obj.short_description === "string") return "workbench";
|
|
2188
|
+
if (typeof obj.synopsis === "string" && Array.isArray(obj.option_groups) && Array.isArray(obj.arguments)) return "mrtrix";
|
|
1812
2189
|
if ("command-line" in obj || Array.isArray(obj.inputs) && "name" in obj) return "boutiques";
|
|
1813
2190
|
if (Array.isArray(obj.actions) && "prog" in obj) return "argdump";
|
|
1814
2191
|
return null;
|
|
@@ -7870,7 +8247,7 @@ function compile(source, filenameOrOptions) {
|
|
|
7870
8247
|
errors: [{ message: "Could not detect input format. Specify format explicitly." }],
|
|
7871
8248
|
warnings: []
|
|
7872
8249
|
};
|
|
7873
|
-
return (format === "argdump" ? new ArgdumpParser() : format === "workbench" ? new WorkbenchParser() : new BoutiquesParser()).parse(source, options.filename);
|
|
8250
|
+
return (format === "argdump" ? new ArgdumpParser() : format === "workbench" ? new WorkbenchParser() : format === "mrtrix" ? new MrtrixParser() : new BoutiquesParser()).parse(source, options.filename);
|
|
7874
8251
|
}
|
|
7875
8252
|
|
|
7876
8253
|
//#endregion
|
|
@@ -7884,6 +8261,7 @@ exports.STYXDEFS_COMPAT = STYXDEFS_COMPAT;
|
|
|
7884
8261
|
exports.Scope = Scope;
|
|
7885
8262
|
exports.TypeScriptBackend = TypeScriptBackend;
|
|
7886
8263
|
exports.alt = alt;
|
|
8264
|
+
exports.appEntrypoint = appEntrypoint;
|
|
7887
8265
|
exports.atomKey = atomKey;
|
|
7888
8266
|
exports.buildSigEntries = buildSigEntries;
|
|
7889
8267
|
exports.camelCase = camelCase;
|