@styx-api/cli 0.3.0 → 0.5.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/bin.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_write = require('./write-CpqGjb9N.cjs');
2
+ const require_write = require('./write-B8IfXD3y.cjs');
3
3
  let cac = require("cac");
4
4
 
5
5
  //#region src/command.ts
package/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as build, n as knownBackends, r as resolveBackends, t as writeFiles } from "./write-BSYxLVtX.mjs";
2
+ import { i as build, n as knownBackends, r as resolveBackends, t as writeFiles } from "./write-DydpQpbm.mjs";
3
3
  import { cac } from "cac";
4
4
 
5
5
  //#region src/command.ts
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_write = require('./write-CpqGjb9N.cjs');
1
+ const require_write = require('./write-B8IfXD3y.cjs');
2
2
 
3
3
  exports.build = require_write.build;
4
4
  exports.detectLevel = require_write.detectLevel;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/build.ts","../src/catalog.ts","../src/backends.ts","../src/write.ts"],"mappings":";;;KAoBY,SAAA;AAAA,UAUK,YAAA;EAVL;EAYV,KAAA;;EAEA,OAAA;EAdmB;EAgBnB,GAAA;EAN2B;EAQ3B,QAAA,EAAU,OAAA;EAEK;EAAf,IAAA,EAAM,SAAA;AAAA;;UAIS,SAAA;EANL;EAQV,IAAA;EACA,OAAA;AAAA;;UAIe,UAAA;EACf,YAAA;EACA,UAAA;EACA,WAAA;AAAA;AAAA,UAGe,WAAA;EACf,KAAA,EAAO,SAAA;EACP,MAAA;EACA,QAAA;EARA;EAUA,KAAA,GAAQ,UAAA;AAAA;;;AALV;;;iBAkBgB,KAAA,CAAM,OAAA,EAAS,YAAA,GAAe,WAAA;;;;;AAvD9C;;;UCViB,cAAA;EACf,IAAA,EAAM,WAAA;EACN,QAAA,EAAU,cAAA;EDkBiB;EChB3B,QAAA;AAAA;AAAA,UAGe,cAAA;EACf,IAAA,EAAM,WAAA;EACN,IAAA,EAAM,UAAA;AAAA;AAAA,UAGS,UAAA;EDkBf;EChBA,IAAA;EDgBe;ECdf,UAAA;EACA,YAAA;AAAA;;;;ADwBF;;KC2CY,YAAA;AAAA,iBAEI,WAAA,CAAY,GAAA,WAAc,YAAA;;;;;;iBAmH1B,WAAA,CAAY,IAAA,WAAe,cAAA;;;cC9L9B,aAAA;AAAA,iBAEG,eAAA,CAAgB,KAAA;EAAoB,QAAA,EAAU,OAAA;EAAW,OAAA;AAAA;;;iBClBzD,UAAA,CAAW,KAAA,EAAO,SAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/build.ts","../src/catalog.ts","../src/backends.ts","../src/write.ts"],"mappings":";;;KAoBY,SAAA;AAAA,UAUK,YAAA;EAVL;EAYV,KAAA;;EAEA,OAAA;EAdmB;EAgBnB,GAAA;EAN2B;EAQ3B,QAAA,EAAU,OAAA;EAEK;EAAf,IAAA,EAAM,SAAA;AAAA;;UAIS,SAAA;EANL;EAQV,IAAA;EACA,OAAA;AAAA;;UAIe,UAAA;EACf,YAAA;EACA,UAAA;EACA,WAAA;AAAA;AAAA,UAGe,WAAA;EACf,KAAA,EAAO,SAAA;EACP,MAAA;EACA,QAAA;EARA;EAUA,KAAA,GAAQ,UAAA;AAAA;;;AALV;;;iBAkBgB,KAAA,CAAM,OAAA,EAAS,YAAA,GAAe,WAAA;;;;;AAvD9C;;;UCViB,cAAA;EACf,IAAA,EAAM,WAAA;EACN,QAAA,EAAU,cAAA;EDkBiB;EChB3B,QAAA;AAAA;AAAA,UAGe,cAAA;EACf,IAAA,EAAM,WAAA;EACN,IAAA,EAAM,UAAA;AAAA;AAAA,UAGS,UAAA;EDkBf;EChBA,IAAA;EDgBe;ECdf,UAAA;EACA,YAAA;AAAA;;;;ADwBF;;KC2CY,YAAA;AAAA,iBAEI,WAAA,CAAY,GAAA,WAAc,YAAA;;;;;;iBAmH1B,WAAA,CAAY,IAAA,WAAe,cAAA;;;cC1L9B,aAAA;AAAA,iBAEG,eAAA,CAAgB,KAAA;EAAoB,QAAA,EAAU,OAAA;EAAW,OAAA;AAAA;;;iBCtBzD,UAAA,CAAW,KAAA,EAAO,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/build.ts","../src/catalog.ts","../src/backends.ts","../src/write.ts"],"mappings":";;;KAoBY,SAAA;AAAA,UAUK,YAAA;EAVL;EAYV,KAAA;;EAEA,OAAA;EAdmB;EAgBnB,GAAA;EAN2B;EAQ3B,QAAA,EAAU,OAAA;EAEK;EAAf,IAAA,EAAM,SAAA;AAAA;;UAIS,SAAA;EANL;EAQV,IAAA;EACA,OAAA;AAAA;;UAIe,UAAA;EACf,YAAA;EACA,UAAA;EACA,WAAA;AAAA;AAAA,UAGe,WAAA;EACf,KAAA,EAAO,SAAA;EACP,MAAA;EACA,QAAA;EARA;EAUA,KAAA,GAAQ,UAAA;AAAA;;;AALV;;;iBAkBgB,KAAA,CAAM,OAAA,EAAS,YAAA,GAAe,WAAA;;;;;AAvD9C;;;UCViB,cAAA;EACf,IAAA,EAAM,WAAA;EACN,QAAA,EAAU,cAAA;EDkBiB;EChB3B,QAAA;AAAA;AAAA,UAGe,cAAA;EACf,IAAA,EAAM,WAAA;EACN,IAAA,EAAM,UAAA;AAAA;AAAA,UAGS,UAAA;EDkBf;EChBA,IAAA;EDgBe;ECdf,UAAA;EACA,YAAA;AAAA;;;;ADwBF;;KC2CY,YAAA;AAAA,iBAEI,WAAA,CAAY,GAAA,WAAc,YAAA;;;;;;iBAmH1B,WAAA,CAAY,IAAA,WAAe,cAAA;;;cC9L9B,aAAA;AAAA,iBAEG,eAAA,CAAgB,KAAA;EAAoB,QAAA,EAAU,OAAA;EAAW,OAAA;AAAA;;;iBClBzD,UAAA,CAAW,KAAA,EAAO,SAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/build.ts","../src/catalog.ts","../src/backends.ts","../src/write.ts"],"mappings":";;;KAoBY,SAAA;AAAA,UAUK,YAAA;EAVL;EAYV,KAAA;;EAEA,OAAA;EAdmB;EAgBnB,GAAA;EAN2B;EAQ3B,QAAA,EAAU,OAAA;EAEK;EAAf,IAAA,EAAM,SAAA;AAAA;;UAIS,SAAA;EANL;EAQV,IAAA;EACA,OAAA;AAAA;;UAIe,UAAA;EACf,YAAA;EACA,UAAA;EACA,WAAA;AAAA;AAAA,UAGe,WAAA;EACf,KAAA,EAAO,SAAA;EACP,MAAA;EACA,QAAA;EARA;EAUA,KAAA,GAAQ,UAAA;AAAA;;;AALV;;;iBAkBgB,KAAA,CAAM,OAAA,EAAS,YAAA,GAAe,WAAA;;;;;AAvD9C;;;UCViB,cAAA;EACf,IAAA,EAAM,WAAA;EACN,QAAA,EAAU,cAAA;EDkBiB;EChB3B,QAAA;AAAA;AAAA,UAGe,cAAA;EACf,IAAA,EAAM,WAAA;EACN,IAAA,EAAM,UAAA;AAAA;AAAA,UAGS,UAAA;EDkBf;EChBA,IAAA;EDgBe;ECdf,UAAA;EACA,YAAA;AAAA;;;;ADwBF;;KC2CY,YAAA;AAAA,iBAEI,WAAA,CAAY,GAAA,WAAc,YAAA;;;;;;iBAmH1B,WAAA,CAAY,IAAA,WAAe,cAAA;;;cC1L9B,aAAA;AAAA,iBAEG,eAAA,CAAgB,KAAA;EAAoB,QAAA,EAAU,OAAA;EAAW,OAAA;AAAA;;;iBCtBzD,UAAA,CAAW,KAAA,EAAO,SAAA"}
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { a as detectLevel, i as build, n as knownBackends, o as loadCatalog, r as resolveBackends, t as writeFiles } from "./write-BSYxLVtX.mjs";
1
+ import { a as detectLevel, i as build, n as knownBackends, o as loadCatalog, r as resolveBackends, t as writeFiles } from "./write-DydpQpbm.mjs";
2
2
 
3
3
  export { build, detectLevel, knownBackends, loadCatalog, resolveBackends, writeFiles };
@@ -406,7 +406,9 @@ const registry = {
406
406
  ts: () => new _styx_api_core.TypeScriptBackend(),
407
407
  schema: () => new _styx_api_core.JsonSchemaBackend(),
408
408
  "json-schema": () => new _styx_api_core.JsonSchemaBackend(),
409
- boutiques: () => new _styx_api_core.BoutiquesBackend()
409
+ boutiques: () => new _styx_api_core.BoutiquesBackend(),
410
+ nipype: () => new _styx_api_core.NipypeBackend(),
411
+ pydra: () => new _styx_api_core.PydraBackend()
410
412
  };
411
413
  const knownBackends = Object.keys(registry);
412
414
  function resolveBackends(names) {
@@ -1,6 +1,6 @@
1
1
  import { mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
2
2
  import * as path from "node:path";
3
- import { BoutiquesBackend, JsonSchemaBackend, PythonBackend, TypeScriptBackend, compile, createContext, defaultPipeline, resolveOutputs, solve } from "@styx-api/core";
3
+ import { BoutiquesBackend, JsonSchemaBackend, NipypeBackend, PydraBackend, PythonBackend, TypeScriptBackend, compile, createContext, defaultPipeline, resolveOutputs, solve } from "@styx-api/core";
4
4
 
5
5
  //#region src/catalog.ts
6
6
  function readJson(file) {
@@ -378,7 +378,9 @@ const registry = {
378
378
  ts: () => new TypeScriptBackend(),
379
379
  schema: () => new JsonSchemaBackend(),
380
380
  "json-schema": () => new JsonSchemaBackend(),
381
- boutiques: () => new BoutiquesBackend()
381
+ boutiques: () => new BoutiquesBackend(),
382
+ nipype: () => new NipypeBackend(),
383
+ pydra: () => new PydraBackend()
382
384
  };
383
385
  const knownBackends = Object.keys(registry);
384
386
  function resolveBackends(names) {
@@ -413,4 +415,4 @@ function writeFiles(files) {
413
415
 
414
416
  //#endregion
415
417
  export { detectLevel as a, build as i, knownBackends as n, loadCatalog as o, resolveBackends as r, writeFiles as t };
416
- //# sourceMappingURL=write-BSYxLVtX.mjs.map
418
+ //# sourceMappingURL=write-DydpQpbm.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"write-BSYxLVtX.mjs","names":[],"sources":["../src/catalog.ts","../src/build.ts","../src/backends.ts","../src/write.ts"],"sourcesContent":["import { readFileSync, readdirSync, statSync } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport type { Documentation, PackageMeta, ProjectMeta } from \"@styx-api/core\";\n\n/**\n * Loaded catalog: a project containing packages, each holding one or more\n * apps. We always normalize to project > package > app even when the catalog\n * root only describes a subset of the hierarchy (e.g. a single version dir).\n */\nexport interface CatalogProject {\n meta: ProjectMeta;\n packages: CatalogPackage[];\n /** Non-fatal issues found while walking the catalog (e.g. skipped stub apps). */\n warnings: string[];\n}\n\nexport interface CatalogPackage {\n meta: PackageMeta;\n apps: CatalogApp[];\n}\n\nexport interface CatalogApp {\n /** Stable identifier from `app.json#name`, used for the emitted module slug. */\n name: string;\n /** Absolute path to the descriptor file referenced by `app.json#source`. */\n sourcePath: string;\n sourceFormat?: string;\n}\n\ninterface ProjectJson {\n name?: string;\n version?: string;\n license?: string;\n packages?: string[];\n docs?: Documentation;\n}\n\ninterface PackageJson {\n name?: string;\n versions?: string[];\n default?: string;\n docs?: Documentation;\n}\n\ninterface VersionJson {\n name?: string;\n container?: string;\n apps?: string[];\n executables?: { required?: string[]; ignored?: string[] };\n}\n\ninterface AppJson {\n name?: string;\n source?: { type?: string; path?: string };\n docs?: Documentation;\n}\n\nfunction readJson<T>(file: string): T {\n let raw: string;\n try {\n raw = readFileSync(file, \"utf8\");\n } catch (e) {\n throw new Error(`${file}: ${e instanceof Error ? e.message : String(e)}`);\n }\n try {\n return JSON.parse(raw) as T;\n } catch (e) {\n throw new Error(`${file}: invalid JSON: ${e instanceof Error ? e.message : String(e)}`);\n }\n}\n\nfunction exists(p: string): boolean {\n try {\n statSync(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isDir(p: string): boolean {\n try {\n return statSync(p).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Detect what level of the niwrap catalog a directory describes.\n * Project dirs contain `project.json`, package dirs contain `package.json`,\n * version dirs contain `version.json`, app dirs contain `app.json`.\n */\nexport type CatalogLevel = \"project\" | \"package\" | \"version\" | \"app\";\n\nexport function detectLevel(dir: string): CatalogLevel | null {\n if (exists(path.join(dir, \"project.json\"))) return \"project\";\n if (exists(path.join(dir, \"package.json\"))) return \"package\";\n if (exists(path.join(dir, \"version.json\"))) return \"version\";\n if (exists(path.join(dir, \"app.json\"))) return \"app\";\n return null;\n}\n\n/**\n * Load one app descriptor. When `warnings` is supplied (catalog-walk mode), a\n * stub app (`app.json` present but no `source.path`) is skipped with a warning\n * instead of aborting the whole build - real catalogs list not-yet-wrapped tools\n * alongside wrapped ones. Without `warnings` (a direct single-app target) the\n * missing source is a hard error, since the user pointed straight at it.\n */\nfunction loadApp(appDir: string, warnings?: string[]): CatalogApp | null {\n const appJsonPath = path.join(appDir, \"app.json\");\n if (!exists(appJsonPath)) return null;\n const app = readJson<AppJson>(appJsonPath);\n const name = app.name ?? path.basename(appDir);\n const sourceRel = app.source?.path;\n if (!sourceRel) {\n if (warnings) {\n warnings.push(`${appJsonPath}: skipped (no source.path - not yet wrapped)`);\n return null;\n }\n throw new Error(`${appJsonPath}: missing source.path`);\n }\n return {\n name,\n sourcePath: path.resolve(appDir, sourceRel),\n sourceFormat: app.source?.type,\n };\n}\n\nfunction loadVersion(versionDir: string, warnings?: string[]): CatalogPackage | null {\n const versionPath = path.join(versionDir, \"version.json\");\n if (!exists(versionPath)) return null;\n const version = readJson<VersionJson>(versionPath);\n\n // Sort the directory fallback so app order (and thus any shared-scope name\n // dodging) is deterministic regardless of filesystem iteration order.\n const appNames = version.apps ?? listSubdirs(versionDir).sort();\n const apps: CatalogApp[] = [];\n for (const appName of appNames) {\n const appDir = path.join(versionDir, appName);\n if (!isDir(appDir)) continue;\n const app = loadApp(appDir, warnings);\n if (app) apps.push(app);\n }\n\n // Try to enrich with the parent package.json if there is one (package > version layout).\n const parentPkg = path.join(versionDir, \"..\", \"package.json\");\n let pkgName: string | undefined;\n let pkgDoc: Documentation | undefined;\n if (exists(parentPkg)) {\n const pkg = readJson<PackageJson>(parentPkg);\n pkgName = pkg.name;\n pkgDoc = pkg.docs;\n }\n pkgName ??= path.basename(path.dirname(versionDir));\n\n return {\n meta: {\n name: pkgName,\n version: version.name,\n docker: version.container,\n doc: pkgDoc,\n },\n apps,\n };\n}\n\nfunction loadPackage(pkgDir: string, warnings?: string[]): CatalogPackage | null {\n const pkgPath = path.join(pkgDir, \"package.json\");\n if (!exists(pkgPath)) return null;\n const pkg = readJson<PackageJson>(pkgPath);\n\n const versionName = pkg.default ?? pkg.versions?.[0] ?? firstVersionDir(pkgDir);\n if (!versionName) return null;\n const versionDir = path.join(pkgDir, versionName);\n if (!isDir(versionDir)) return null;\n\n const loaded = loadVersion(versionDir, warnings);\n if (!loaded) return null;\n\n return {\n meta: {\n name: pkg.name ?? path.basename(pkgDir),\n version: versionName,\n docker: loaded.meta.docker,\n doc: pkg.docs ?? loaded.meta.doc,\n },\n apps: loaded.apps,\n };\n}\n\nfunction listSubdirs(dir: string): string[] {\n return readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n}\n\nfunction firstVersionDir(pkgDir: string): string | null {\n for (const name of listSubdirs(pkgDir)) {\n if (exists(path.join(pkgDir, name, \"version.json\"))) return name;\n }\n return null;\n}\n\n/**\n * Load a catalog from any niwrap layout level. The level is auto-detected from\n * which `*.json` index file is present in `root`. Always returns a normalized\n * `project > package > app` shape, synthesizing missing layers as needed.\n */\nexport function loadCatalog(root: string): CatalogProject {\n const level = detectLevel(root);\n if (!level) {\n throw new Error(\n `${root}: no project.json / package.json / version.json / app.json found - not a catalog root`,\n );\n }\n\n const warnings: string[] = [];\n\n if (level === \"project\") {\n const project = readJson<ProjectJson>(path.join(root, \"project.json\"));\n const packageNames = project.packages ?? listSubdirs(root);\n const packages: CatalogPackage[] = [];\n for (const name of packageNames) {\n const pkgDir = path.join(root, name);\n const pkg = loadPackage(pkgDir, warnings);\n if (pkg) packages.push(pkg);\n }\n return {\n meta: {\n name: project.name,\n version: project.version,\n doc: project.docs,\n license: project.license ? { description: project.license } : undefined,\n },\n packages,\n warnings,\n };\n }\n\n if (level === \"package\") {\n const pkg = loadPackage(root, warnings);\n if (!pkg) throw new Error(`${root}: package.json present but no resolvable version`);\n return { meta: { name: pkg.meta.name }, packages: [pkg], warnings };\n }\n\n if (level === \"version\") {\n const pkg = loadVersion(root, warnings);\n if (!pkg) throw new Error(`${root}: version.json present but failed to load`);\n return { meta: { name: pkg.meta.name }, packages: [pkg], warnings };\n }\n\n // level === \"app\": a direct single-app target, so a missing source is fatal.\n const app = loadApp(root);\n if (!app) throw new Error(`${root}: app.json present but missing source.path`);\n return {\n meta: {},\n packages: [\n {\n meta: { name: path.basename(path.dirname(root)) },\n apps: [app],\n },\n ],\n warnings,\n };\n}\n","import { readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport {\n compile,\n createContext,\n defaultPipeline,\n resolveOutputs,\n solve,\n type Backend,\n type EmitResult,\n type EmittedApp,\n type EmittedPackage,\n type FormatName,\n type PackageMeta,\n type ProjectMeta,\n} from \"@styx-api/core\";\n\nimport { loadCatalog, type CatalogProject } from \"./catalog.js\";\n\nexport type BuildMode = \"scripts\" | \"single\" | \"multi\";\n\n/** Frontend formats the compiler can parse; others are skipped with a warning. */\nconst SUPPORTED_FORMATS: ReadonlySet<string> = new Set<FormatName>([\n \"boutiques\",\n \"argdump\",\n \"workbench\",\n \"mrtrix\",\n]);\n\nexport interface BuildOptions {\n /** Single-descriptor input file (mutually exclusive with `catalog`). */\n input?: string;\n /** Catalog directory (mutually exclusive with `input`). */\n catalog?: string;\n /** Output directory; per-backend files end up under `<out>/<backend.target>/...`. */\n out: string;\n /** Backends to run (instances pre-resolved by the caller). */\n backends: Backend[];\n /** Which emit tiers to run. */\n mode: BuildMode;\n}\n\n/** A single file from a backend run, keyed by destination path. */\nexport interface BuiltFile {\n /** Absolute destination path. */\n path: string;\n content: string;\n}\n\n/** Per-tool tallies for a catalog build (undefined for single-descriptor builds). */\nexport interface BuildStats {\n appsCompiled: number;\n appsFailed: number;\n appsSkipped: number;\n}\n\nexport interface BuildResult {\n files: BuiltFile[];\n errors: string[];\n warnings: string[];\n /** Catalog-build tallies; set only by `--catalog` builds. */\n stats?: BuildStats;\n}\n\n/** Render an unknown thrown value as a message string. */\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Run the build. Returns the assembled file map and diagnostics; the caller\n * is responsible for actually writing to disk (so tests can introspect the\n * map directly).\n */\nexport function build(options: BuildOptions): BuildResult {\n if (options.input && options.catalog) {\n return { files: [], errors: [\"--input and --catalog are mutually exclusive\"], warnings: [] };\n }\n if (!options.input && !options.catalog) {\n return {\n files: [],\n errors: [\"missing input: pass a descriptor path or --catalog\"],\n warnings: [],\n };\n }\n\n if (options.input) return buildSingle(options.input, options);\n return buildCatalog(options.catalog!, options);\n}\n\nfunction buildSingle(inputPath: string, options: BuildOptions): BuildResult {\n const result: BuildResult = { files: [], errors: [], warnings: [] };\n\n const ctx = readAndCompile(inputPath, undefined, undefined, undefined, result);\n if (!ctx) return result;\n\n for (const backend of options.backends) {\n let emitted;\n try {\n emitted = backend.emitApp(ctx);\n } catch (e) {\n result.errors.push(`[${backend.name}] ${errMsg(e)}`);\n continue;\n }\n appendEmitMessages(result, emitted, backend);\n for (const [name, content] of emitted.files) {\n result.files.push({\n path: path.resolve(options.out, backend.target, name),\n content,\n });\n }\n }\n return result;\n}\n\nfunction buildCatalog(catalogPath: string, options: BuildOptions): BuildResult {\n const result: BuildResult = {\n files: [],\n errors: [],\n warnings: [],\n stats: { appsCompiled: 0, appsFailed: 0, appsSkipped: 0 },\n };\n let catalog: CatalogProject;\n try {\n catalog = loadCatalog(catalogPath);\n } catch (e) {\n result.errors.push(e instanceof Error ? e.message : String(e));\n return result;\n }\n result.warnings.push(...catalog.warnings);\n\n // Skip/empty warnings are backend-independent, so only the first backend pass\n // records them - otherwise they'd be duplicated once per backend.\n options.backends.forEach((backend, i) => {\n runBackendOverCatalog(backend, catalog, options.mode, options.out, result, i === 0);\n });\n return result;\n}\n\n/**\n * Parse a descriptor, run the default optimization pipeline, solve to\n * bindings, and build a `CodegenContext` wired up with the supplied\n * package/project meta. Returns null on read failure (with the error already\n * appended to `result`). Parse-level errors/warnings are also appended.\n */\nfunction readAndCompile(\n sourcePath: string,\n format: string | undefined,\n pkg: PackageMeta | undefined,\n proj: ProjectMeta | undefined,\n result: BuildResult,\n): ReturnType<typeof createContext> | null {\n let source: string;\n try {\n source = readFileSync(sourcePath, \"utf8\");\n } catch (e) {\n result.errors.push(`${sourcePath}: ${errMsg(e)}`);\n return null;\n }\n\n // Isolate the compile pipeline: a single descriptor that makes the solver or\n // a downstream pass throw is recorded as an error and skipped, so one bad tool\n // can't crash a whole-catalog build.\n try {\n // Honor the catalog's declared format when it's one we support, so we don't\n // fall back to content sniffing (and get a clearer error if it mis-parses).\n const parsed = compile(\n source,\n format && SUPPORTED_FORMATS.has(format)\n ? { filename: sourcePath, format: format as FormatName }\n : sourcePath,\n );\n for (const e of parsed.errors) result.errors.push(`${sourcePath}: ${e.message}`);\n for (const w of parsed.warnings) result.warnings.push(`${sourcePath}: ${w.message}`);\n\n const piped = defaultPipeline.apply(parsed.expr);\n if (piped.warnings) {\n for (const w of piped.warnings) result.warnings.push(`${sourcePath}: ${w}`);\n }\n\n const solveResult = solve(piped.expr);\n const outputs = resolveOutputs(piped.expr, solveResult);\n return createContext(piped.expr, solveResult, outputs, {\n app: parsed.meta,\n package: pkg,\n project: proj,\n });\n } catch (e) {\n result.errors.push(`${sourcePath}: ${errMsg(e)}`);\n return null;\n }\n}\n\nfunction runBackendOverCatalog(\n backend: Backend,\n catalog: CatalogProject,\n mode: BuildMode,\n outRoot: string,\n result: BuildResult,\n recordWarnings: boolean,\n): void {\n const backendRoot = path.resolve(outRoot, backend.target);\n const packagesEmitted: EmittedPackage[] = [];\n\n for (const pkg of catalog.packages) {\n const pkgDir = pkg.meta.name ?? \"package\";\n const appsEmitted: EmittedApp[] = [];\n let skipped = 0;\n // One scope shared across every tool in the suite so top-level names stay\n // unique across the package's flat barrel re-exports.\n const pkgScope = backend.newPackageScope?.();\n\n for (const app of pkg.apps) {\n // A tool can declare a format we have no frontend for yet (e.g. Workbench).\n // Skip it with a warning rather than failing the whole catalog build.\n if (app.sourceFormat && !SUPPORTED_FORMATS.has(app.sourceFormat)) {\n skipped++;\n if (recordWarnings) {\n if (result.stats) result.stats.appsSkipped++;\n result.warnings.push(\n `${app.sourcePath}: skipped (unsupported source format \"${app.sourceFormat}\")`,\n );\n }\n continue;\n }\n\n const ctx = readAndCompile(app.sourcePath, app.sourceFormat, pkg.meta, catalog.meta, result);\n if (!ctx) {\n if (recordWarnings && result.stats) result.stats.appsFailed++;\n continue;\n }\n\n // Isolate emit so one tool that makes a backend throw doesn't crash the run.\n let emitted: EmittedApp;\n try {\n emitted = backend.emitApp(ctx, pkgScope);\n } catch (e) {\n result.errors.push(`[${backend.name} ${pkg.meta.name}/${app.name}] ${errMsg(e)}`);\n if (recordWarnings && result.stats) result.stats.appsFailed++;\n continue;\n }\n appendEmitMessages(result, emitted, backend, `${pkg.meta.name}/${app.name}`);\n appsEmitted.push(emitted);\n if (recordWarnings && result.stats) result.stats.appsCompiled++;\n\n for (const [name, content] of emitted.files) {\n result.files.push({ path: path.join(backendRoot, pkgDir, name), content });\n }\n }\n\n // A suite whose every tool was skipped (e.g. all-Workbench) emits nothing;\n // don't synthesize an empty package or wire it into the project metadata.\n // Only warn when emptiness is due to skips - genuine failures already errored.\n if (appsEmitted.length === 0) {\n if (recordWarnings && skipped > 0 && skipped === pkg.apps.length) {\n result.warnings.push(`${pkgDir}: all ${skipped} tool(s) skipped, package omitted`);\n }\n continue;\n }\n\n if (mode !== \"scripts\" && backend.emitPackage) {\n try {\n const pkgEmit = backend.emitPackage(pkg.meta, appsEmitted);\n appendEmitMessages(result, pkgEmit, backend, pkg.meta.name);\n packagesEmitted.push(pkgEmit);\n for (const [name, content] of pkgEmit.files) {\n result.files.push({ path: path.join(backendRoot, pkgDir, name), content });\n }\n } catch (e) {\n result.errors.push(`[${backend.name} ${pkgDir}] package emit failed: ${errMsg(e)}`);\n }\n }\n }\n\n if (mode === \"multi\" && backend.emitProject && packagesEmitted.length > 0) {\n try {\n const projEmit = backend.emitProject(catalog.meta, packagesEmitted);\n appendEmitMessages(result, projEmit, backend, catalog.meta.name);\n for (const [name, content] of projEmit.files) {\n result.files.push({ path: path.join(backendRoot, name), content });\n }\n } catch (e) {\n result.errors.push(`[${backend.name}] project emit failed: ${errMsg(e)}`);\n }\n }\n}\n\nfunction appendEmitMessages(\n result: BuildResult,\n emit: EmitResult,\n backend: Backend,\n scope?: string,\n): void {\n const tag = scope ? `[${backend.name} ${scope}]` : `[${backend.name}]`;\n for (const e of emit.errors) result.errors.push(`${tag} ${e.message}`);\n for (const w of emit.warnings) result.warnings.push(`${tag} ${w.message}`);\n}\n","import {\n BoutiquesBackend,\n JsonSchemaBackend,\n PythonBackend,\n TypeScriptBackend,\n type Backend,\n} from \"@styx-api/core\";\n\n/**\n * Registry of backends keyed by CLI alias. The alias is what users pass to\n * `-b`; the backend's `name`/`target` is what we use for the output subdir.\n */\nconst registry: Record<string, () => Backend> = {\n python: () => new PythonBackend(),\n typescript: () => new TypeScriptBackend(),\n ts: () => new TypeScriptBackend(),\n schema: () => new JsonSchemaBackend(),\n \"json-schema\": () => new JsonSchemaBackend(),\n boutiques: () => new BoutiquesBackend(),\n};\n\nexport const knownBackends = Object.keys(registry);\n\nexport function resolveBackends(names: string[]): { backends: Backend[]; unknown: string[] } {\n const backends: Backend[] = [];\n const seen = new Set<string>();\n const unknown: string[] = [];\n for (const name of names) {\n const factory = registry[name];\n if (!factory) {\n unknown.push(name);\n continue;\n }\n const backend = factory();\n if (seen.has(backend.name)) continue;\n seen.add(backend.name);\n backends.push(backend);\n }\n return { backends, unknown };\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport type { BuiltFile } from \"./build.js\";\n\nexport function writeFiles(files: BuiltFile[]): void {\n for (const file of files) {\n mkdirSync(path.dirname(file.path), { recursive: true });\n writeFileSync(file.path, file.content, \"utf8\");\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"write-DydpQpbm.mjs","names":[],"sources":["../src/catalog.ts","../src/build.ts","../src/backends.ts","../src/write.ts"],"sourcesContent":["import { readFileSync, readdirSync, statSync } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport type { Documentation, PackageMeta, ProjectMeta } from \"@styx-api/core\";\n\n/**\n * Loaded catalog: a project containing packages, each holding one or more\n * apps. We always normalize to project > package > app even when the catalog\n * root only describes a subset of the hierarchy (e.g. a single version dir).\n */\nexport interface CatalogProject {\n meta: ProjectMeta;\n packages: CatalogPackage[];\n /** Non-fatal issues found while walking the catalog (e.g. skipped stub apps). */\n warnings: string[];\n}\n\nexport interface CatalogPackage {\n meta: PackageMeta;\n apps: CatalogApp[];\n}\n\nexport interface CatalogApp {\n /** Stable identifier from `app.json#name`, used for the emitted module slug. */\n name: string;\n /** Absolute path to the descriptor file referenced by `app.json#source`. */\n sourcePath: string;\n sourceFormat?: string;\n}\n\ninterface ProjectJson {\n name?: string;\n version?: string;\n license?: string;\n packages?: string[];\n docs?: Documentation;\n}\n\ninterface PackageJson {\n name?: string;\n versions?: string[];\n default?: string;\n docs?: Documentation;\n}\n\ninterface VersionJson {\n name?: string;\n container?: string;\n apps?: string[];\n executables?: { required?: string[]; ignored?: string[] };\n}\n\ninterface AppJson {\n name?: string;\n source?: { type?: string; path?: string };\n docs?: Documentation;\n}\n\nfunction readJson<T>(file: string): T {\n let raw: string;\n try {\n raw = readFileSync(file, \"utf8\");\n } catch (e) {\n throw new Error(`${file}: ${e instanceof Error ? e.message : String(e)}`);\n }\n try {\n return JSON.parse(raw) as T;\n } catch (e) {\n throw new Error(`${file}: invalid JSON: ${e instanceof Error ? e.message : String(e)}`);\n }\n}\n\nfunction exists(p: string): boolean {\n try {\n statSync(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isDir(p: string): boolean {\n try {\n return statSync(p).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Detect what level of the niwrap catalog a directory describes.\n * Project dirs contain `project.json`, package dirs contain `package.json`,\n * version dirs contain `version.json`, app dirs contain `app.json`.\n */\nexport type CatalogLevel = \"project\" | \"package\" | \"version\" | \"app\";\n\nexport function detectLevel(dir: string): CatalogLevel | null {\n if (exists(path.join(dir, \"project.json\"))) return \"project\";\n if (exists(path.join(dir, \"package.json\"))) return \"package\";\n if (exists(path.join(dir, \"version.json\"))) return \"version\";\n if (exists(path.join(dir, \"app.json\"))) return \"app\";\n return null;\n}\n\n/**\n * Load one app descriptor. When `warnings` is supplied (catalog-walk mode), a\n * stub app (`app.json` present but no `source.path`) is skipped with a warning\n * instead of aborting the whole build - real catalogs list not-yet-wrapped tools\n * alongside wrapped ones. Without `warnings` (a direct single-app target) the\n * missing source is a hard error, since the user pointed straight at it.\n */\nfunction loadApp(appDir: string, warnings?: string[]): CatalogApp | null {\n const appJsonPath = path.join(appDir, \"app.json\");\n if (!exists(appJsonPath)) return null;\n const app = readJson<AppJson>(appJsonPath);\n const name = app.name ?? path.basename(appDir);\n const sourceRel = app.source?.path;\n if (!sourceRel) {\n if (warnings) {\n warnings.push(`${appJsonPath}: skipped (no source.path - not yet wrapped)`);\n return null;\n }\n throw new Error(`${appJsonPath}: missing source.path`);\n }\n return {\n name,\n sourcePath: path.resolve(appDir, sourceRel),\n sourceFormat: app.source?.type,\n };\n}\n\nfunction loadVersion(versionDir: string, warnings?: string[]): CatalogPackage | null {\n const versionPath = path.join(versionDir, \"version.json\");\n if (!exists(versionPath)) return null;\n const version = readJson<VersionJson>(versionPath);\n\n // Sort the directory fallback so app order (and thus any shared-scope name\n // dodging) is deterministic regardless of filesystem iteration order.\n const appNames = version.apps ?? listSubdirs(versionDir).sort();\n const apps: CatalogApp[] = [];\n for (const appName of appNames) {\n const appDir = path.join(versionDir, appName);\n if (!isDir(appDir)) continue;\n const app = loadApp(appDir, warnings);\n if (app) apps.push(app);\n }\n\n // Try to enrich with the parent package.json if there is one (package > version layout).\n const parentPkg = path.join(versionDir, \"..\", \"package.json\");\n let pkgName: string | undefined;\n let pkgDoc: Documentation | undefined;\n if (exists(parentPkg)) {\n const pkg = readJson<PackageJson>(parentPkg);\n pkgName = pkg.name;\n pkgDoc = pkg.docs;\n }\n pkgName ??= path.basename(path.dirname(versionDir));\n\n return {\n meta: {\n name: pkgName,\n version: version.name,\n docker: version.container,\n doc: pkgDoc,\n },\n apps,\n };\n}\n\nfunction loadPackage(pkgDir: string, warnings?: string[]): CatalogPackage | null {\n const pkgPath = path.join(pkgDir, \"package.json\");\n if (!exists(pkgPath)) return null;\n const pkg = readJson<PackageJson>(pkgPath);\n\n const versionName = pkg.default ?? pkg.versions?.[0] ?? firstVersionDir(pkgDir);\n if (!versionName) return null;\n const versionDir = path.join(pkgDir, versionName);\n if (!isDir(versionDir)) return null;\n\n const loaded = loadVersion(versionDir, warnings);\n if (!loaded) return null;\n\n return {\n meta: {\n name: pkg.name ?? path.basename(pkgDir),\n version: versionName,\n docker: loaded.meta.docker,\n doc: pkg.docs ?? loaded.meta.doc,\n },\n apps: loaded.apps,\n };\n}\n\nfunction listSubdirs(dir: string): string[] {\n return readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n}\n\nfunction firstVersionDir(pkgDir: string): string | null {\n for (const name of listSubdirs(pkgDir)) {\n if (exists(path.join(pkgDir, name, \"version.json\"))) return name;\n }\n return null;\n}\n\n/**\n * Load a catalog from any niwrap layout level. The level is auto-detected from\n * which `*.json` index file is present in `root`. Always returns a normalized\n * `project > package > app` shape, synthesizing missing layers as needed.\n */\nexport function loadCatalog(root: string): CatalogProject {\n const level = detectLevel(root);\n if (!level) {\n throw new Error(\n `${root}: no project.json / package.json / version.json / app.json found - not a catalog root`,\n );\n }\n\n const warnings: string[] = [];\n\n if (level === \"project\") {\n const project = readJson<ProjectJson>(path.join(root, \"project.json\"));\n const packageNames = project.packages ?? listSubdirs(root);\n const packages: CatalogPackage[] = [];\n for (const name of packageNames) {\n const pkgDir = path.join(root, name);\n const pkg = loadPackage(pkgDir, warnings);\n if (pkg) packages.push(pkg);\n }\n return {\n meta: {\n name: project.name,\n version: project.version,\n doc: project.docs,\n license: project.license ? { description: project.license } : undefined,\n },\n packages,\n warnings,\n };\n }\n\n if (level === \"package\") {\n const pkg = loadPackage(root, warnings);\n if (!pkg) throw new Error(`${root}: package.json present but no resolvable version`);\n return { meta: { name: pkg.meta.name }, packages: [pkg], warnings };\n }\n\n if (level === \"version\") {\n const pkg = loadVersion(root, warnings);\n if (!pkg) throw new Error(`${root}: version.json present but failed to load`);\n return { meta: { name: pkg.meta.name }, packages: [pkg], warnings };\n }\n\n // level === \"app\": a direct single-app target, so a missing source is fatal.\n const app = loadApp(root);\n if (!app) throw new Error(`${root}: app.json present but missing source.path`);\n return {\n meta: {},\n packages: [\n {\n meta: { name: path.basename(path.dirname(root)) },\n apps: [app],\n },\n ],\n warnings,\n };\n}\n","import { readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport {\n compile,\n createContext,\n defaultPipeline,\n resolveOutputs,\n solve,\n type Backend,\n type EmitResult,\n type EmittedApp,\n type EmittedPackage,\n type FormatName,\n type PackageMeta,\n type ProjectMeta,\n} from \"@styx-api/core\";\n\nimport { loadCatalog, type CatalogProject } from \"./catalog.js\";\n\nexport type BuildMode = \"scripts\" | \"single\" | \"multi\";\n\n/** Frontend formats the compiler can parse; others are skipped with a warning. */\nconst SUPPORTED_FORMATS: ReadonlySet<string> = new Set<FormatName>([\n \"boutiques\",\n \"argdump\",\n \"workbench\",\n \"mrtrix\",\n]);\n\nexport interface BuildOptions {\n /** Single-descriptor input file (mutually exclusive with `catalog`). */\n input?: string;\n /** Catalog directory (mutually exclusive with `input`). */\n catalog?: string;\n /** Output directory; per-backend files end up under `<out>/<backend.target>/...`. */\n out: string;\n /** Backends to run (instances pre-resolved by the caller). */\n backends: Backend[];\n /** Which emit tiers to run. */\n mode: BuildMode;\n}\n\n/** A single file from a backend run, keyed by destination path. */\nexport interface BuiltFile {\n /** Absolute destination path. */\n path: string;\n content: string;\n}\n\n/** Per-tool tallies for a catalog build (undefined for single-descriptor builds). */\nexport interface BuildStats {\n appsCompiled: number;\n appsFailed: number;\n appsSkipped: number;\n}\n\nexport interface BuildResult {\n files: BuiltFile[];\n errors: string[];\n warnings: string[];\n /** Catalog-build tallies; set only by `--catalog` builds. */\n stats?: BuildStats;\n}\n\n/** Render an unknown thrown value as a message string. */\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Run the build. Returns the assembled file map and diagnostics; the caller\n * is responsible for actually writing to disk (so tests can introspect the\n * map directly).\n */\nexport function build(options: BuildOptions): BuildResult {\n if (options.input && options.catalog) {\n return { files: [], errors: [\"--input and --catalog are mutually exclusive\"], warnings: [] };\n }\n if (!options.input && !options.catalog) {\n return {\n files: [],\n errors: [\"missing input: pass a descriptor path or --catalog\"],\n warnings: [],\n };\n }\n\n if (options.input) return buildSingle(options.input, options);\n return buildCatalog(options.catalog!, options);\n}\n\nfunction buildSingle(inputPath: string, options: BuildOptions): BuildResult {\n const result: BuildResult = { files: [], errors: [], warnings: [] };\n\n const ctx = readAndCompile(inputPath, undefined, undefined, undefined, result);\n if (!ctx) return result;\n\n for (const backend of options.backends) {\n let emitted;\n try {\n emitted = backend.emitApp(ctx);\n } catch (e) {\n result.errors.push(`[${backend.name}] ${errMsg(e)}`);\n continue;\n }\n appendEmitMessages(result, emitted, backend);\n for (const [name, content] of emitted.files) {\n result.files.push({\n path: path.resolve(options.out, backend.target, name),\n content,\n });\n }\n }\n return result;\n}\n\nfunction buildCatalog(catalogPath: string, options: BuildOptions): BuildResult {\n const result: BuildResult = {\n files: [],\n errors: [],\n warnings: [],\n stats: { appsCompiled: 0, appsFailed: 0, appsSkipped: 0 },\n };\n let catalog: CatalogProject;\n try {\n catalog = loadCatalog(catalogPath);\n } catch (e) {\n result.errors.push(e instanceof Error ? e.message : String(e));\n return result;\n }\n result.warnings.push(...catalog.warnings);\n\n // Skip/empty warnings are backend-independent, so only the first backend pass\n // records them - otherwise they'd be duplicated once per backend.\n options.backends.forEach((backend, i) => {\n runBackendOverCatalog(backend, catalog, options.mode, options.out, result, i === 0);\n });\n return result;\n}\n\n/**\n * Parse a descriptor, run the default optimization pipeline, solve to\n * bindings, and build a `CodegenContext` wired up with the supplied\n * package/project meta. Returns null on read failure (with the error already\n * appended to `result`). Parse-level errors/warnings are also appended.\n */\nfunction readAndCompile(\n sourcePath: string,\n format: string | undefined,\n pkg: PackageMeta | undefined,\n proj: ProjectMeta | undefined,\n result: BuildResult,\n): ReturnType<typeof createContext> | null {\n let source: string;\n try {\n source = readFileSync(sourcePath, \"utf8\");\n } catch (e) {\n result.errors.push(`${sourcePath}: ${errMsg(e)}`);\n return null;\n }\n\n // Isolate the compile pipeline: a single descriptor that makes the solver or\n // a downstream pass throw is recorded as an error and skipped, so one bad tool\n // can't crash a whole-catalog build.\n try {\n // Honor the catalog's declared format when it's one we support, so we don't\n // fall back to content sniffing (and get a clearer error if it mis-parses).\n const parsed = compile(\n source,\n format && SUPPORTED_FORMATS.has(format)\n ? { filename: sourcePath, format: format as FormatName }\n : sourcePath,\n );\n for (const e of parsed.errors) result.errors.push(`${sourcePath}: ${e.message}`);\n for (const w of parsed.warnings) result.warnings.push(`${sourcePath}: ${w.message}`);\n\n const piped = defaultPipeline.apply(parsed.expr);\n if (piped.warnings) {\n for (const w of piped.warnings) result.warnings.push(`${sourcePath}: ${w}`);\n }\n\n const solveResult = solve(piped.expr);\n const outputs = resolveOutputs(piped.expr, solveResult);\n return createContext(piped.expr, solveResult, outputs, {\n app: parsed.meta,\n package: pkg,\n project: proj,\n });\n } catch (e) {\n result.errors.push(`${sourcePath}: ${errMsg(e)}`);\n return null;\n }\n}\n\nfunction runBackendOverCatalog(\n backend: Backend,\n catalog: CatalogProject,\n mode: BuildMode,\n outRoot: string,\n result: BuildResult,\n recordWarnings: boolean,\n): void {\n const backendRoot = path.resolve(outRoot, backend.target);\n const packagesEmitted: EmittedPackage[] = [];\n\n for (const pkg of catalog.packages) {\n const pkgDir = pkg.meta.name ?? \"package\";\n const appsEmitted: EmittedApp[] = [];\n let skipped = 0;\n // One scope shared across every tool in the suite so top-level names stay\n // unique across the package's flat barrel re-exports.\n const pkgScope = backend.newPackageScope?.();\n\n for (const app of pkg.apps) {\n // A tool can declare a format we have no frontend for yet (e.g. Workbench).\n // Skip it with a warning rather than failing the whole catalog build.\n if (app.sourceFormat && !SUPPORTED_FORMATS.has(app.sourceFormat)) {\n skipped++;\n if (recordWarnings) {\n if (result.stats) result.stats.appsSkipped++;\n result.warnings.push(\n `${app.sourcePath}: skipped (unsupported source format \"${app.sourceFormat}\")`,\n );\n }\n continue;\n }\n\n const ctx = readAndCompile(app.sourcePath, app.sourceFormat, pkg.meta, catalog.meta, result);\n if (!ctx) {\n if (recordWarnings && result.stats) result.stats.appsFailed++;\n continue;\n }\n\n // Isolate emit so one tool that makes a backend throw doesn't crash the run.\n let emitted: EmittedApp;\n try {\n emitted = backend.emitApp(ctx, pkgScope);\n } catch (e) {\n result.errors.push(`[${backend.name} ${pkg.meta.name}/${app.name}] ${errMsg(e)}`);\n if (recordWarnings && result.stats) result.stats.appsFailed++;\n continue;\n }\n appendEmitMessages(result, emitted, backend, `${pkg.meta.name}/${app.name}`);\n appsEmitted.push(emitted);\n if (recordWarnings && result.stats) result.stats.appsCompiled++;\n\n for (const [name, content] of emitted.files) {\n result.files.push({ path: path.join(backendRoot, pkgDir, name), content });\n }\n }\n\n // A suite whose every tool was skipped (e.g. all-Workbench) emits nothing;\n // don't synthesize an empty package or wire it into the project metadata.\n // Only warn when emptiness is due to skips - genuine failures already errored.\n if (appsEmitted.length === 0) {\n if (recordWarnings && skipped > 0 && skipped === pkg.apps.length) {\n result.warnings.push(`${pkgDir}: all ${skipped} tool(s) skipped, package omitted`);\n }\n continue;\n }\n\n if (mode !== \"scripts\" && backend.emitPackage) {\n try {\n const pkgEmit = backend.emitPackage(pkg.meta, appsEmitted);\n appendEmitMessages(result, pkgEmit, backend, pkg.meta.name);\n packagesEmitted.push(pkgEmit);\n for (const [name, content] of pkgEmit.files) {\n result.files.push({ path: path.join(backendRoot, pkgDir, name), content });\n }\n } catch (e) {\n result.errors.push(`[${backend.name} ${pkgDir}] package emit failed: ${errMsg(e)}`);\n }\n }\n }\n\n if (mode === \"multi\" && backend.emitProject && packagesEmitted.length > 0) {\n try {\n const projEmit = backend.emitProject(catalog.meta, packagesEmitted);\n appendEmitMessages(result, projEmit, backend, catalog.meta.name);\n for (const [name, content] of projEmit.files) {\n result.files.push({ path: path.join(backendRoot, name), content });\n }\n } catch (e) {\n result.errors.push(`[${backend.name}] project emit failed: ${errMsg(e)}`);\n }\n }\n}\n\nfunction appendEmitMessages(\n result: BuildResult,\n emit: EmitResult,\n backend: Backend,\n scope?: string,\n): void {\n const tag = scope ? `[${backend.name} ${scope}]` : `[${backend.name}]`;\n for (const e of emit.errors) result.errors.push(`${tag} ${e.message}`);\n for (const w of emit.warnings) result.warnings.push(`${tag} ${w.message}`);\n}\n","import {\n BoutiquesBackend,\n JsonSchemaBackend,\n NipypeBackend,\n PydraBackend,\n PythonBackend,\n TypeScriptBackend,\n type Backend,\n} from \"@styx-api/core\";\n\n/**\n * Registry of backends keyed by CLI alias. The alias is what users pass to\n * `-b`; the backend's `name`/`target` is what we use for the output subdir.\n */\nconst registry: Record<string, () => Backend> = {\n python: () => new PythonBackend(),\n typescript: () => new TypeScriptBackend(),\n ts: () => new TypeScriptBackend(),\n schema: () => new JsonSchemaBackend(),\n \"json-schema\": () => new JsonSchemaBackend(),\n boutiques: () => new BoutiquesBackend(),\n nipype: () => new NipypeBackend(),\n pydra: () => new PydraBackend(),\n};\n\nexport const knownBackends = Object.keys(registry);\n\nexport function resolveBackends(names: string[]): { backends: Backend[]; unknown: string[] } {\n const backends: Backend[] = [];\n const seen = new Set<string>();\n const unknown: string[] = [];\n for (const name of names) {\n const factory = registry[name];\n if (!factory) {\n unknown.push(name);\n continue;\n }\n const backend = factory();\n if (seen.has(backend.name)) continue;\n seen.add(backend.name);\n backends.push(backend);\n }\n return { backends, unknown };\n}\n","import { mkdirSync, writeFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport type { BuiltFile } from \"./build.js\";\n\nexport function writeFiles(files: BuiltFile[]): void {\n for (const file of files) {\n mkdirSync(path.dirname(file.path), { recursive: true });\n writeFileSync(file.path, file.content, \"utf8\");\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@styx-api/cli",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Command-line interface for the Styx compiler (@styx-api/core): build typed wrappers from CLI tool descriptors and catalogs.",
5
5
  "keywords": [
6
6
  "styx",
@@ -49,7 +49,7 @@
49
49
  "prepublishOnly": "tsdown"
50
50
  },
51
51
  "dependencies": {
52
- "@styx-api/core": "0.3.0",
52
+ "@styx-api/core": "0.5.0",
53
53
  "cac": "^6.7.14"
54
54
  },
55
55
  "devDependencies": {
package/src/backends.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  BoutiquesBackend,
3
3
  JsonSchemaBackend,
4
+ NipypeBackend,
5
+ PydraBackend,
4
6
  PythonBackend,
5
7
  TypeScriptBackend,
6
8
  type Backend,
@@ -17,6 +19,8 @@ const registry: Record<string, () => Backend> = {
17
19
  schema: () => new JsonSchemaBackend(),
18
20
  "json-schema": () => new JsonSchemaBackend(),
19
21
  boutiques: () => new BoutiquesBackend(),
22
+ nipype: () => new NipypeBackend(),
23
+ pydra: () => new PydraBackend(),
20
24
  };
21
25
 
22
26
  export const knownBackends = Object.keys(registry);