@amritk/mjst 0.5.1 → 0.6.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/cli.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { execFile } from "node:child_process";
5
- import { mkdir, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
6
- import { dirname as dirname2, join as join8, resolve as resolve3 } from "node:path";
5
+ import { mkdir, readdir, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
6
+ import { basename, dirname as dirname2, join as join8, relative, resolve as resolve3, sep } from "node:path";
7
7
  import { promisify } from "node:util";
8
8
 
9
9
  // ../adapters/dist/get-adapter.js
@@ -90281,12 +90281,13 @@ var buildJsDocBlock = (title, description, commentUrl) => {
90281
90281
  `;
90282
90282
  return block;
90283
90283
  };
90284
- var getTypeScriptType = (schema) => {
90285
- const base = getUnbrandedType(schema);
90284
+ var getTypeScriptType = (schema, options = {}) => {
90285
+ const base = getUnbrandedType(schema, options);
90286
90286
  const brand2 = getMjstBrand(schema);
90287
90287
  return brand2 ? `(${base} & { readonly __brand: '${brand2}' })` : base;
90288
90288
  };
90289
- var getUnbrandedType = (schema) => {
90289
+ var recordType = (keyType, valueType, options) => options.readonly ? `Readonly<Record<${keyType}, ${valueType}>>` : `Record<${keyType}, ${valueType}>`;
90290
+ var getUnbrandedType = (schema, options = {}) => {
90290
90291
  if (typeof schema === "boolean") {
90291
90292
  return getBooleanSubSchemaType(schema);
90292
90293
  }
@@ -90334,29 +90335,29 @@ var getUnbrandedType = (schema) => {
90334
90335
  return multiEnumUnion;
90335
90336
  }
90336
90337
  if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
90337
- let oneOfUnion = getTypeScriptType(schema.oneOf[0]);
90338
+ let oneOfUnion = getTypeScriptType(schema.oneOf[0], options);
90338
90339
  for (let i = 1;i < schema.oneOf.length; i++) {
90339
- oneOfUnion += " | " + getTypeScriptType(schema.oneOf[i]);
90340
+ oneOfUnion += " | " + getTypeScriptType(schema.oneOf[i], options);
90340
90341
  }
90341
90342
  return oneOfUnion;
90342
90343
  }
90343
90344
  if (schema.anyOf && Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
90344
- let anyOfUnion = getTypeScriptType(schema.anyOf[0]);
90345
+ let anyOfUnion = getTypeScriptType(schema.anyOf[0], options);
90345
90346
  for (let i = 1;i < schema.anyOf.length; i++) {
90346
- anyOfUnion += " | " + getTypeScriptType(schema.anyOf[i]);
90347
+ anyOfUnion += " | " + getTypeScriptType(schema.anyOf[i], options);
90347
90348
  }
90348
90349
  return anyOfUnion;
90349
90350
  }
90350
90351
  if (schema.allOf && Array.isArray(schema.allOf) && schema.allOf.length > 0) {
90351
- let intersectionTypes = getTypeScriptType(schema.allOf[0]);
90352
+ let intersectionTypes = getTypeScriptType(schema.allOf[0], options);
90352
90353
  for (let i = 1;i < schema.allOf.length; i++) {
90353
- intersectionTypes += " & " + getTypeScriptType(schema.allOf[i]);
90354
+ intersectionTypes += " & " + getTypeScriptType(schema.allOf[i], options);
90354
90355
  }
90355
90356
  return intersectionTypes;
90356
90357
  }
90357
90358
  const conditionalResult = getConditionalObjectSchema(schema);
90358
90359
  if (conditionalResult) {
90359
- const baseType = getTypeScriptType(conditionalResult.schema);
90360
+ const baseType = getTypeScriptType(conditionalResult.schema, options);
90360
90361
  if (conditionalResult.thenRef) {
90361
90362
  return `(${baseType}) & ${refToName2(conditionalResult.thenRef)}`;
90362
90363
  }
@@ -90365,20 +90366,20 @@ var getUnbrandedType = (schema) => {
90365
90366
  if (!schema.type) {
90366
90367
  if (schema.additionalProperties !== undefined) {
90367
90368
  if (typeof schema.additionalProperties === "boolean") {
90368
- return `Record<string, ${getBooleanSubSchemaType(schema.additionalProperties)}>`;
90369
+ return recordType("string", getBooleanSubSchemaType(schema.additionalProperties), options);
90369
90370
  }
90370
- return `Record<string, ${getTypeScriptType(schema.additionalProperties)}>`;
90371
+ return recordType("string", getTypeScriptType(schema.additionalProperties, options), options);
90371
90372
  }
90372
90373
  if (schema.patternProperties && typeof schema.patternProperties === "object") {
90373
90374
  const firstEntry = Object.entries(schema.patternProperties)[0];
90374
90375
  if (firstEntry) {
90375
90376
  const [pattern2, value10] = firstEntry;
90376
90377
  if (value10 !== undefined) {
90377
- const valueType = typeof value10 === "boolean" ? getBooleanSubSchemaType(value10) : getTypeScriptType(value10);
90378
+ const valueType = typeof value10 === "boolean" ? getBooleanSubSchemaType(value10) : getTypeScriptType(value10, options);
90378
90379
  if (pattern2 === "^x-") {
90379
- return `Record<\`x-\${string}\`, ${valueType}>`;
90380
+ return recordType("`x-${string}`", valueType, options);
90380
90381
  }
90381
- return `Record<string, ${valueType}>`;
90382
+ return recordType("string", valueType, options);
90382
90383
  }
90383
90384
  }
90384
90385
  }
@@ -90431,41 +90432,42 @@ var getUnbrandedType = (schema) => {
90431
90432
  return "boolean";
90432
90433
  case "array":
90433
90434
  if (schema.items) {
90434
- const itemType = getTypeScriptType(schema.items);
90435
+ const itemType = getTypeScriptType(schema.items, options);
90435
90436
  const wrappedItemType = itemType.includes(" | ") ? `(${itemType})` : itemType;
90436
- return `${wrappedItemType}[]`;
90437
+ return options.readonly ? `readonly ${wrappedItemType}[]` : `${wrappedItemType}[]`;
90437
90438
  }
90438
- return "unknown[]";
90439
+ return options.readonly ? "readonly unknown[]" : "unknown[]";
90439
90440
  case "object":
90440
90441
  if (schema.properties) {
90442
+ const readonlyPrefix = options.readonly ? "readonly " : "";
90441
90443
  let properties = "";
90442
90444
  let first5 = true;
90443
90445
  for (const key in schema.properties) {
90444
90446
  const propSchema = schema.properties[key];
90445
90447
  const isRequired = schema.required?.includes(key) ?? false;
90446
90448
  const optional3 = isRequired ? "" : "?";
90447
- const propType = getTypeScriptType(propSchema);
90449
+ const propType = getTypeScriptType(propSchema, options);
90448
90450
  if (!first5)
90449
90451
  properties += "; ";
90450
- properties += safeKey(key) + optional3 + ": " + propType;
90452
+ properties += readonlyPrefix + safeKey(key) + optional3 + ": " + propType;
90451
90453
  first5 = false;
90452
90454
  }
90453
90455
  return "{ " + properties + " }";
90454
90456
  }
90455
90457
  if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
90456
- const additionalPropType = getTypeScriptType(schema.additionalProperties);
90457
- return `Record<string, ${additionalPropType}>`;
90458
+ const additionalPropType = getTypeScriptType(schema.additionalProperties, options);
90459
+ return recordType("string", additionalPropType, options);
90458
90460
  }
90459
90461
  if (schema.patternProperties && typeof schema.patternProperties === "object") {
90460
90462
  const firstEntry = Object.entries(schema.patternProperties)[0];
90461
90463
  if (firstEntry) {
90462
90464
  const [pattern2, patternVal] = firstEntry;
90463
90465
  if (patternVal) {
90464
- const valueType = getTypeScriptType(patternVal);
90466
+ const valueType = getTypeScriptType(patternVal, options);
90465
90467
  if (pattern2 === "^x-") {
90466
- return `Record<\`x-\${string}\`, ${valueType}>`;
90468
+ return recordType("`x-${string}`", valueType, options);
90467
90469
  }
90468
- return `Record<string, ${valueType}>`;
90470
+ return recordType("string", valueType, options);
90469
90471
  }
90470
90472
  }
90471
90473
  }
@@ -90474,9 +90476,10 @@ var getUnbrandedType = (schema) => {
90474
90476
  return "unknown";
90475
90477
  }
90476
90478
  };
90477
- var generateTypeDefinition = (schema, typeName) => {
90479
+ var generateTypeDefinition = (schema, typeName, options = {}) => {
90480
+ const readonlyPrefix = options.readonly ? "readonly " : "";
90478
90481
  if (!isObjectLikeSchema(schema)) {
90479
- const tsType = getTypeScriptType(schema);
90482
+ const tsType = getTypeScriptType(schema, options);
90480
90483
  let result = "";
90481
90484
  if (isSchemaObject2(schema) && schema.$comment && typeof schema.$comment === "string") {
90482
90485
  result += buildJsDocBlock(typeName, schema.$comment);
@@ -90504,23 +90507,23 @@ var generateTypeDefinition = (schema, typeName) => {
90504
90507
  if (firstPatternProperty === undefined) {
90505
90508
  return `export type ${typeName} = Record<string, unknown>;`;
90506
90509
  }
90507
- const patternPropType = typeof firstPatternProperty === "boolean" ? getBooleanSubSchemaType(firstPatternProperty) : getTypeScriptType(firstPatternProperty);
90510
+ const patternPropType = typeof firstPatternProperty === "boolean" ? getBooleanSubSchemaType(firstPatternProperty) : getTypeScriptType(firstPatternProperty, options);
90508
90511
  const keyType = firstPattern === "^x-" ? "`x-${string}`" : "string";
90509
90512
  let result2 = "";
90510
90513
  if (jsDocTitle && jsDocDescription) {
90511
90514
  result2 += buildJsDocBlock(jsDocTitle, jsDocDescription);
90512
90515
  }
90513
- result2 += `export type ${typeName} = Record<${keyType}, ${patternPropType}>;`;
90516
+ result2 += `export type ${typeName} = ${recordType(keyType, patternPropType, options)};`;
90514
90517
  return result2;
90515
90518
  }
90516
90519
  if (!hasProperties2 && hasAdditionalProperties2 && normalizedSchema.additionalProperties) {
90517
- const additionalPropType = getTypeScriptType(normalizedSchema.additionalProperties);
90520
+ const additionalPropType = getTypeScriptType(normalizedSchema.additionalProperties, options);
90518
90521
  let result2 = "";
90519
90522
  if (jsDocTitle && jsDocDescription) {
90520
90523
  result2 += buildJsDocBlock(jsDocTitle, jsDocDescription);
90521
90524
  }
90522
90525
  result2 += `export type ${typeName} = {
90523
- [key: string]: ${additionalPropType};
90526
+ ${readonlyPrefix}[key: string]: ${additionalPropType};
90524
90527
  };`;
90525
90528
  return result2;
90526
90529
  }
@@ -90531,8 +90534,8 @@ var generateTypeDefinition = (schema, typeName) => {
90531
90534
  const propSchema = schemaProps[key];
90532
90535
  const isRequired = normalizedSchema.required?.includes(key) ?? false;
90533
90536
  const optional3 = isRequired ? "" : "?";
90534
- const propType = getTypeScriptType(propSchema);
90535
- const quotedKey = safeKey(key);
90537
+ const propType = getTypeScriptType(propSchema, options);
90538
+ const quotedKey = readonlyPrefix + safeKey(key);
90536
90539
  if (!isFirstProp)
90537
90540
  properties += `
90538
90541
  `;
@@ -90580,31 +90583,32 @@ var PACKAGE_IMPORTS = {
90580
90583
  "validate-record": "import { validateRecord } from '@amritk/helpers/validate-record';",
90581
90584
  "has-ref": "import { hasRef } from '@amritk/helpers/schema-guards';"
90582
90585
  };
90583
- var EMBEDDED_IMPORTS = {
90584
- "is-object": "import { isObject } from './_helpers/is-object';",
90585
- "validate-array": "import { validateArray } from './_helpers/validate-array';",
90586
- "validate-record": "import { validateRecord } from './_helpers/validate-record';",
90587
- "has-ref": "import { hasRef } from './_helpers/has-ref';"
90586
+ var EMBEDDED_NAMED_EXPORTS = {
90587
+ "is-object": "isObject",
90588
+ "validate-array": "validateArray",
90589
+ "validate-record": "validateRecord",
90590
+ "has-ref": "hasRef"
90588
90591
  };
90589
- var collectHelpers = (parserFunction, mode) => {
90592
+ var embeddedImport = (helper, prefix) => `import { ${EMBEDDED_NAMED_EXPORTS[helper]} } from '${prefix}_helpers/${helper}';`;
90593
+ var collectHelpers = (parserFunction, mode, helpersImportPrefix = "./") => {
90590
90594
  const imports = [];
90591
90595
  const used = new Set;
90592
- const table3 = mode === "embedded" ? EMBEDDED_IMPORTS : PACKAGE_IMPORTS;
90596
+ const importFor = (helper) => mode === "embedded" ? embeddedImport(helper, helpersImportPrefix) : PACKAGE_IMPORTS[helper];
90593
90597
  if (parserFunction.includes("validateArray")) {
90594
- imports.push(table3["validate-array"]);
90598
+ imports.push(importFor("validate-array"));
90595
90599
  used.add("validate-array");
90596
90600
  }
90597
90601
  if (parserFunction.includes("validateRecord")) {
90598
- imports.push(table3["validate-record"]);
90602
+ imports.push(importFor("validate-record"));
90599
90603
  used.add("validate-record");
90600
90604
  used.add("is-object");
90601
90605
  }
90602
90606
  if (parserFunction.includes("isObject")) {
90603
- imports.push(table3["is-object"]);
90607
+ imports.push(importFor("is-object"));
90604
90608
  used.add("is-object");
90605
90609
  }
90606
90610
  if (parserFunction.includes("hasRef(")) {
90607
- imports.push(table3["has-ref"]);
90611
+ imports.push(importFor("has-ref"));
90608
90612
  used.add("has-ref");
90609
90613
  }
90610
90614
  return { imports, used };
@@ -92269,7 +92273,7 @@ var generateFile = (schema, typeName, options) => {
92269
92273
  const selfRef = options?.selfRef;
92270
92274
  const rootSchema = options?.rootSchema;
92271
92275
  const helpersMode = options?.helpersMode ?? "package";
92272
- const typeDefinition = generateTypeDefinition(schema, typeName);
92276
+ const typeDefinition = generateTypeDefinition(schema, typeName, { readonly: options?.readonly ?? false });
92273
92277
  if (typesOnly) {
92274
92278
  const imports2 = collectImports(schema, { typesOnly: true, selfRef, rootSchema });
92275
92279
  let result2 = "";
@@ -92294,7 +92298,7 @@ var generateFile = (schema, typeName, options) => {
92294
92298
  const combinedFunctions = `${shapeValidator}
92295
92299
 
92296
92300
  ${parserFunction}`;
92297
- const helpers = collectHelpers(combinedFunctions, helpersMode);
92301
+ const helpers = collectHelpers(combinedFunctions, helpersMode, options?.helpersImportPrefix);
92298
92302
  const imports = [...collectImports(schema, { selfRef, rootSchema }), ...helpers.imports];
92299
92303
  let result = "";
92300
92304
  if (imports.length > 0) {
@@ -92336,7 +92340,7 @@ var extractDynamicAnchorDefs = (schema) => {
92336
92340
  }
92337
92341
  return refs;
92338
92342
  };
92339
- var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings, strict2, helpersMode = "package") => {
92343
+ var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings, strict2, helpersMode = "package", helpersImportPrefix = "./", readonly2 = false) => {
92340
92344
  rootSchema = upgradeDraft07Schema(rootSchema);
92341
92345
  const files = [];
92342
92346
  const processedRefs = new Set;
@@ -92350,6 +92354,8 @@ var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWar
92350
92354
  typesOnly: typesOnly ?? false,
92351
92355
  rootSchema,
92352
92356
  helpersMode,
92357
+ helpersImportPrefix,
92358
+ readonly: readonly2,
92353
92359
  ...logWarnings !== undefined ? { logWarnings } : {},
92354
92360
  ...strict2 !== undefined ? { strict: strict2 } : {}
92355
92361
  });
@@ -92385,6 +92391,8 @@ var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWar
92385
92391
  selfRef: ref,
92386
92392
  rootSchema,
92387
92393
  helpersMode,
92394
+ helpersImportPrefix,
92395
+ readonly: readonly2,
92388
92396
  ...logWarnings !== undefined ? { logWarnings } : {},
92389
92397
  ...strict2 !== undefined ? { strict: strict2 } : {}
92390
92398
  });
@@ -92458,6 +92466,41 @@ var deriveRootTypeName = (schema) => {
92458
92466
  return name || "Document";
92459
92467
  };
92460
92468
 
92469
+ // src/combine-files.ts
92470
+ var IMPORT_RE = /^import\s/;
92471
+ var RELATIVE_IMPORT_RE = /\bfrom\s+['"]\.\.?\//;
92472
+ var combineGeneratedFiles = (files) => {
92473
+ const externalImports = new Set;
92474
+ const bodies = [];
92475
+ for (const file2 of files) {
92476
+ if (file2.filename === "index.ts")
92477
+ continue;
92478
+ const bodyLines = [];
92479
+ for (const line of file2.content.split(`
92480
+ `)) {
92481
+ if (IMPORT_RE.test(line.trimStart())) {
92482
+ if (RELATIVE_IMPORT_RE.test(line))
92483
+ continue;
92484
+ externalImports.add(line.trim());
92485
+ continue;
92486
+ }
92487
+ bodyLines.push(line);
92488
+ }
92489
+ const body = bodyLines.join(`
92490
+ `).trim();
92491
+ if (body)
92492
+ bodies.push(body);
92493
+ }
92494
+ const importBlock = [...externalImports].sort().join(`
92495
+ `);
92496
+ return [importBlock, bodies.join(`
92497
+
92498
+ `)].filter(Boolean).join(`
92499
+
92500
+ `) + `
92501
+ `;
92502
+ };
92503
+
92461
92504
  // src/detect-helpers-mode.ts
92462
92505
  import { createRequire as createRequire2 } from "node:module";
92463
92506
  import { resolve } from "node:path";
@@ -92486,13 +92529,16 @@ var loadConfig = async (configPath) => {
92486
92529
  const obj = parsed;
92487
92530
  return {
92488
92531
  ...typeof obj["schema"] === "string" && { schema: obj["schema"] },
92532
+ ...typeof obj["schemaDir"] === "string" && { schemaDir: obj["schemaDir"] },
92489
92533
  ...typeof obj["outDir"] === "string" && { outDir: obj["outDir"] },
92534
+ ...typeof obj["outFile"] === "string" && { outFile: obj["outFile"] },
92490
92535
  ...isSourceFormat(obj["input"]) && { input: obj["input"] },
92491
92536
  ...typeof obj["export"] === "string" && { export: obj["export"] },
92492
92537
  ...typeof obj["typesOnly"] === "boolean" && { typesOnly: obj["typesOnly"] },
92493
92538
  ...typeof obj["build"] === "boolean" && { build: obj["build"] },
92494
92539
  ...typeof obj["logWarnings"] === "boolean" && { logWarnings: obj["logWarnings"] },
92495
- ...typeof obj["strict"] === "boolean" && { strict: obj["strict"] }
92540
+ ...typeof obj["strict"] === "boolean" && { strict: obj["strict"] },
92541
+ ...typeof obj["readonly"] === "boolean" && { readonly: obj["readonly"] }
92496
92542
  };
92497
92543
  };
92498
92544
 
@@ -92527,92 +92573,106 @@ ${String(error54)}`);
92527
92573
 
92528
92574
  // src/parse-cli-args.ts
92529
92575
  var SOURCE_FORMATS2 = ["json", "typebox", "zod", "valibot", "effect"];
92576
+ var BOOLEAN_KEYS = new Set(["typesOnly", "build", "logWarnings", "strict", "readonly"]);
92577
+ var VALUE_KEYS = new Set([
92578
+ "schema",
92579
+ "schemaDir",
92580
+ "outDir",
92581
+ "outFile",
92582
+ "input",
92583
+ "export",
92584
+ "helpers"
92585
+ ]);
92586
+ var toCamelCase = (key) => key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
92587
+ var parseHelpersValue = (value10) => {
92588
+ if (value10 === "package" || value10 === "embedded")
92589
+ return value10;
92590
+ return;
92591
+ };
92592
+ var parseInputValue = (value10) => SOURCE_FORMATS2.includes(value10) ? value10 : undefined;
92593
+ var assignValue = (config3, key, value10) => {
92594
+ switch (key) {
92595
+ case "schema":
92596
+ config3.schema = value10;
92597
+ return true;
92598
+ case "schemaDir":
92599
+ config3.schemaDir = value10;
92600
+ return true;
92601
+ case "outDir":
92602
+ config3.outDir = value10;
92603
+ return true;
92604
+ case "outFile":
92605
+ config3.outFile = value10;
92606
+ return true;
92607
+ case "export":
92608
+ config3.export = value10;
92609
+ return true;
92610
+ case "input": {
92611
+ const parsed = parseInputValue(value10);
92612
+ if (parsed)
92613
+ config3.input = parsed;
92614
+ return true;
92615
+ }
92616
+ case "helpers": {
92617
+ const parsed = parseHelpersValue(value10);
92618
+ if (parsed)
92619
+ config3.helpers = parsed;
92620
+ return true;
92621
+ }
92622
+ default:
92623
+ return false;
92624
+ }
92625
+ };
92626
+ var assignBoolean = (config3, key, value10) => {
92627
+ switch (key) {
92628
+ case "typesOnly":
92629
+ config3.typesOnly = value10;
92630
+ return true;
92631
+ case "build":
92632
+ config3.build = value10;
92633
+ return true;
92634
+ case "logWarnings":
92635
+ config3.logWarnings = value10;
92636
+ return true;
92637
+ case "strict":
92638
+ config3.strict = value10;
92639
+ return true;
92640
+ case "readonly":
92641
+ config3.readonly = value10;
92642
+ return true;
92643
+ default:
92644
+ return false;
92645
+ }
92646
+ };
92530
92647
  var parseCliArgs = (args2) => {
92531
92648
  const config3 = {};
92532
- const parseHelpersValue = (value10) => {
92533
- if (value10 === "package" || value10 === "embedded")
92534
- return value10;
92535
- return;
92536
- };
92537
- const parseInputValue = (value10) => SOURCE_FORMATS2.includes(value10) ? value10 : undefined;
92538
92649
  for (let i = 0;i < args2.length; i++) {
92539
92650
  const arg = args2[i];
92540
- if (!arg) {
92651
+ if (!arg || !arg.startsWith("--")) {
92541
92652
  continue;
92542
92653
  }
92543
- if (arg.startsWith("--") && arg.includes("=")) {
92544
- const equalsIndex = arg.indexOf("=");
92545
- const key = arg.slice(2, equalsIndex);
92654
+ const equalsIndex = arg.indexOf("=");
92655
+ if (equalsIndex !== -1) {
92656
+ const key2 = toCamelCase(arg.slice(2, equalsIndex));
92546
92657
  const value10 = arg.slice(equalsIndex + 1);
92547
- if (key === "schema") {
92548
- config3.schema = value10;
92549
- } else if (key === "outDir") {
92550
- config3.outDir = value10;
92551
- } else if (key === "input") {
92552
- const parsed = parseInputValue(value10);
92553
- if (parsed)
92554
- config3.input = parsed;
92555
- } else if (key === "export") {
92556
- config3.export = value10;
92557
- } else if (key === "types-only") {
92558
- config3.typesOnly = value10 !== "false";
92559
- } else if (key === "build") {
92560
- config3.build = value10 !== "false";
92561
- } else if (key === "log-warnings") {
92562
- config3.logWarnings = value10 !== "false";
92563
- } else if (key === "strict") {
92564
- config3.strict = value10 !== "false";
92565
- } else if (key === "helpers") {
92566
- const parsed = parseHelpersValue(value10);
92567
- if (parsed)
92568
- config3.helpers = parsed;
92658
+ if (BOOLEAN_KEYS.has(key2)) {
92659
+ assignBoolean(config3, key2, value10 !== "false");
92660
+ } else {
92661
+ assignValue(config3, key2, value10);
92569
92662
  }
92570
92663
  continue;
92571
92664
  }
92572
- if (arg === "--schema") {
92573
- const value10 = args2[i + 1];
92574
- if (value10 && !value10.startsWith("--")) {
92575
- config3.schema = value10;
92576
- i++;
92577
- }
92578
- } else if (arg === "--outDir") {
92579
- const value10 = args2[i + 1];
92580
- if (value10 && !value10.startsWith("--")) {
92581
- config3.outDir = value10;
92582
- i++;
92583
- }
92584
- } else if (arg === "--input") {
92585
- const value10 = args2[i + 1];
92586
- if (value10 && !value10.startsWith("--")) {
92587
- const parsed = parseInputValue(value10);
92588
- if (parsed) {
92589
- config3.input = parsed;
92590
- i++;
92591
- }
92592
- }
92593
- } else if (arg === "--export") {
92665
+ const key = toCamelCase(arg.slice(2));
92666
+ if (BOOLEAN_KEYS.has(key)) {
92667
+ assignBoolean(config3, key, true);
92668
+ continue;
92669
+ }
92670
+ if (VALUE_KEYS.has(key)) {
92594
92671
  const value10 = args2[i + 1];
92595
92672
  if (value10 && !value10.startsWith("--")) {
92596
- config3.export = value10;
92673
+ assignValue(config3, key, value10);
92597
92674
  i++;
92598
92675
  }
92599
- } else if (arg === "--types-only") {
92600
- config3.typesOnly = true;
92601
- } else if (arg === "--build") {
92602
- config3.build = true;
92603
- } else if (arg === "--log-warnings") {
92604
- config3.logWarnings = true;
92605
- } else if (arg === "--strict") {
92606
- config3.strict = true;
92607
- } else if (arg === "--helpers") {
92608
- const value10 = args2[i + 1];
92609
- if (value10 && !value10.startsWith("--")) {
92610
- const parsed = parseHelpersValue(value10);
92611
- if (parsed) {
92612
- config3.helpers = parsed;
92613
- i++;
92614
- }
92615
- }
92616
92676
  }
92617
92677
  }
92618
92678
  return config3;
@@ -92632,77 +92692,186 @@ var extractConfigPath = (args2) => {
92632
92692
  }
92633
92693
  return;
92634
92694
  };
92635
- var run10 = async () => {
92636
- const args2 = process.argv.slice(2);
92637
- const configPath = extractConfigPath(args2);
92638
- const fileConfig = configPath ? await loadConfig(configPath) : {};
92639
- const cliConfig = parseCliArgs(args2);
92640
- const config3 = { ...fileConfig, ...cliConfig };
92641
- if (!config3.schema) {
92642
- console.error("Error: --schema is required. Provide a path to a JSON Schema file.");
92643
- process.exit(1);
92644
- }
92645
- if (!config3.outDir) {
92646
- console.error("Error: --outDir is required. Provide an output directory for generated files.");
92647
- process.exit(1);
92648
- }
92649
- const schemaPath = resolve3(config3.schema);
92695
+ var loadSchema = async (config3, schemaPath) => {
92650
92696
  const inputFormat = config3.input ?? "json";
92651
- let schema;
92652
92697
  if (inputFormat === "json") {
92653
- schema = JSON.parse(await readFile3(schemaPath, "utf-8"));
92654
- } else {
92655
- console.log(`Input format: ${inputFormat}`);
92656
- const source = await loadSchemaModule(schemaPath, config3.export);
92657
- schema = await getAdapter(inputFormat).toJSONSchema(source);
92698
+ return JSON.parse(await readFile3(schemaPath, "utf-8"));
92699
+ }
92700
+ console.log(`Input format: ${inputFormat}`);
92701
+ const source = await loadSchemaModule(schemaPath, config3.export);
92702
+ return getAdapter(inputFormat).toJSONSchema(source);
92703
+ };
92704
+ var writeGeneratedFile = async (baseDir, filename, content) => {
92705
+ const filePath = join8(baseDir, filename);
92706
+ await mkdir(dirname2(filePath), { recursive: true });
92707
+ await writeFile(filePath, content, "utf-8");
92708
+ };
92709
+ var buildOutput = async (outputDir, tsFiles, typesOnly) => {
92710
+ const tsconfigContent = JSON.stringify({
92711
+ compilerOptions: {
92712
+ target: "ESNext",
92713
+ module: "ESNext",
92714
+ moduleResolution: "bundler",
92715
+ declaration: true,
92716
+ emitDeclarationOnly: typesOnly,
92717
+ skipLibCheck: true
92718
+ },
92719
+ include: tsFiles.map((file2) => `./${file2}`)
92720
+ }, null, 2);
92721
+ const tsconfigPath = join8(outputDir, ".tsconfig-mjst-build.json");
92722
+ await writeFile(tsconfigPath, tsconfigContent, "utf-8");
92723
+ try {
92724
+ await execFileAsync("npx", ["tsc", "--project", tsconfigPath]);
92725
+ } catch {
92726
+ throw new Error("TypeScript compilation failed. Check the generated files for errors.");
92727
+ } finally {
92728
+ await unlink(tsconfigPath);
92658
92729
  }
92659
- const outputDir = resolve3(config3.outDir);
92730
+ for (const file2 of tsFiles) {
92731
+ await unlink(join8(outputDir, file2));
92732
+ console.log(`Built: ${file2.replace(/\.ts$/, ".js")}`);
92733
+ console.log(`Built: ${file2.replace(/\.ts$/, ".d.ts")}`);
92734
+ }
92735
+ console.log(`
92736
+ Total files built: ${tsFiles.length * 2}`);
92737
+ };
92738
+ var findJsonSchemas = async (dir3) => {
92739
+ const entries8 = await readdir(dir3, { withFileTypes: true });
92740
+ const results = [];
92741
+ for (const entry of entries8) {
92742
+ const full = join8(dir3, entry.name);
92743
+ if (entry.isDirectory()) {
92744
+ results.push(...await findJsonSchemas(full));
92745
+ } else if (entry.isFile() && entry.name.endsWith(".json")) {
92746
+ results.push(full);
92747
+ }
92748
+ }
92749
+ return results;
92750
+ };
92751
+ var runSingle = async (config3, schemaPath, outputDir) => {
92752
+ const schema = await loadSchema(config3, schemaPath);
92660
92753
  await mkdir(outputDir, { recursive: true });
92661
92754
  const helpersMode = config3.helpers ?? detectHelpersMode(outputDir);
92662
92755
  console.log(`Helpers mode: ${helpersMode}${config3.helpers ? " (explicit)" : " (auto-detected)"}`);
92663
92756
  const rootTypeName = deriveRootTypeName(schema);
92664
92757
  console.log(`Root type: ${rootTypeName}`);
92665
- const files = await buildSchema(schema, rootTypeName, undefined, config3.typesOnly, config3.logWarnings, config3.strict, helpersMode);
92758
+ const files = await buildSchema(schema, rootTypeName, undefined, config3.typesOnly, config3.logWarnings, config3.strict, helpersMode, undefined, config3.readonly);
92666
92759
  for (const file2 of files) {
92667
- const filePath = join8(outputDir, file2.filename);
92668
- await mkdir(dirname2(filePath), { recursive: true });
92669
- await writeFile(filePath, file2.content, "utf-8");
92760
+ await writeGeneratedFile(outputDir, file2.filename, file2.content);
92670
92761
  console.log(`Generated: ${file2.filename}`);
92671
92762
  }
92672
92763
  if (config3.build) {
92673
- const tsconfigContent = JSON.stringify({
92674
- compilerOptions: {
92675
- target: "ESNext",
92676
- module: "ESNext",
92677
- moduleResolution: "bundler",
92678
- declaration: true,
92679
- emitDeclarationOnly: config3.typesOnly,
92680
- skipLibCheck: true
92681
- },
92682
- include: ["./**/*.ts"]
92683
- }, null, 2);
92684
- const tsconfigPath = join8(outputDir, ".tsconfig-mjst-build.json");
92685
- await writeFile(tsconfigPath, tsconfigContent, "utf-8");
92686
- try {
92687
- await execFileAsync("npx", ["tsc", "--project", tsconfigPath]);
92688
- } catch {
92689
- throw new Error("TypeScript compilation failed. Check the generated files for errors.");
92690
- } finally {
92691
- await unlink(tsconfigPath);
92692
- }
92764
+ await buildOutput(outputDir, files.map((f) => f.filename), config3.typesOnly);
92765
+ } else {
92766
+ console.log(`
92767
+ Total files generated: ${files.length}`);
92768
+ }
92769
+ };
92770
+ var runSingleFile = async (config3, schemaPath, outFilePath) => {
92771
+ const schema = await loadSchema(config3, schemaPath);
92772
+ const outputDir = dirname2(outFilePath);
92773
+ await mkdir(outputDir, { recursive: true });
92774
+ const rootTypeName = deriveRootTypeName(schema);
92775
+ console.log(`Root type: ${rootTypeName}`);
92776
+ const files = await buildSchema(schema, rootTypeName, undefined, config3.typesOnly, config3.logWarnings, config3.strict, config3.helpers ?? "package", undefined, config3.readonly);
92777
+ await writeFile(outFilePath, combineGeneratedFiles(files), "utf-8");
92778
+ console.log(`Generated: ${relative(process.cwd(), outFilePath)}`);
92779
+ if (config3.build) {
92780
+ await buildOutput(outputDir, [basename(outFilePath)], config3.typesOnly);
92781
+ } else {
92782
+ console.log(`
92783
+ Total files generated: 1`);
92784
+ }
92785
+ };
92786
+ var runRecursive = async (config3, schemaDir, outputDir) => {
92787
+ if (config3.input && config3.input !== "json") {
92788
+ console.error("Error: --schemaDir only supports JSON Schema files; remove --input or set it to 'json'.");
92789
+ process.exit(1);
92790
+ }
92791
+ const schemaFiles = await findJsonSchemas(schemaDir);
92792
+ if (schemaFiles.length === 0) {
92793
+ console.error(`Error: no .json schema files found under ${schemaDir}.`);
92794
+ process.exit(1);
92795
+ }
92796
+ await mkdir(outputDir, { recursive: true });
92797
+ const helpersMode = config3.helpers ?? detectHelpersMode(outputDir);
92798
+ console.log(`Helpers mode: ${helpersMode}${config3.helpers ? " (explicit)" : " (auto-detected)"}`);
92799
+ const sharedHelpers = new Map;
92800
+ const writtenTsFiles = [];
92801
+ for (const schemaFile of schemaFiles) {
92802
+ const relPath = relative(schemaDir, schemaFile);
92803
+ const relNoExt = relPath.slice(0, -".json".length);
92804
+ const schemaSubDir = join8(outputDir, relNoExt);
92805
+ const depth = relNoExt.split(sep).filter(Boolean).length;
92806
+ const helpersImportPrefix = "../".repeat(depth);
92807
+ const schema = await loadSchema(config3, schemaFile);
92808
+ const rootTypeName = deriveRootTypeName(schema);
92809
+ console.log(`
92810
+ ${relPath} → ${relNoExt}/ (root type: ${rootTypeName})`);
92811
+ const files = await buildSchema(schema, rootTypeName, undefined, config3.typesOnly, config3.logWarnings, config3.strict, helpersMode, helpersImportPrefix, config3.readonly);
92693
92812
  for (const file2 of files) {
92694
- await unlink(join8(outputDir, file2.filename));
92695
- const jsFilename = file2.filename.replace(/\.ts$/, ".js");
92696
- const dtsFilename = file2.filename.replace(/\.ts$/, ".d.ts");
92697
- console.log(`Built: ${jsFilename}`);
92698
- console.log(`Built: ${dtsFilename}`);
92813
+ if (file2.filename.startsWith("_helpers/")) {
92814
+ sharedHelpers.set(file2.filename, file2.content);
92815
+ continue;
92816
+ }
92817
+ await writeGeneratedFile(schemaSubDir, file2.filename, file2.content);
92818
+ const relativeFilename = join8(relNoExt, file2.filename);
92819
+ writtenTsFiles.push(relativeFilename);
92820
+ console.log(`Generated: ${relativeFilename}`);
92699
92821
  }
92700
- console.log(`
92701
- Total files built: ${files.length * 2}`);
92822
+ }
92823
+ for (const [filename, content] of sharedHelpers) {
92824
+ await writeGeneratedFile(outputDir, filename, content);
92825
+ writtenTsFiles.push(filename);
92826
+ console.log(`Generated: ${filename}`);
92827
+ }
92828
+ if (config3.build) {
92829
+ await buildOutput(outputDir, writtenTsFiles, config3.typesOnly);
92702
92830
  } else {
92703
92831
  console.log(`
92704
- Total files generated: ${files.length}`);
92832
+ Total files generated: ${writtenTsFiles.length}`);
92833
+ }
92834
+ };
92835
+ var run10 = async () => {
92836
+ const args2 = process.argv.slice(2);
92837
+ const configPath = extractConfigPath(args2);
92838
+ const fileConfig = configPath ? await loadConfig(configPath) : {};
92839
+ const cliConfig = parseCliArgs(args2);
92840
+ const config3 = { ...fileConfig, ...cliConfig };
92841
+ if (config3.outDir && config3.outFile) {
92842
+ console.error("Error: provide only one of --out-dir or --out-file, not both.");
92843
+ process.exit(1);
92844
+ }
92845
+ if (config3.outFile) {
92846
+ if (!config3.typesOnly) {
92847
+ console.error("Error: --out-file currently supports only --types-only output. Add --types-only or use --out-dir.");
92848
+ process.exit(1);
92849
+ }
92850
+ if (config3.schemaDir) {
92851
+ console.error("Error: --out-file cannot be combined with --schema-dir; use --out-dir for recursive output.");
92852
+ process.exit(1);
92853
+ }
92854
+ if (!config3.schema) {
92855
+ console.error("Error: --schema is required. Provide a path to a JSON Schema.");
92856
+ process.exit(1);
92857
+ }
92858
+ await runSingleFile(config3, resolve3(config3.schema), resolve3(config3.outFile));
92859
+ return;
92860
+ }
92861
+ if (!config3.outDir) {
92862
+ console.error("Error: --out-dir or --out-file is required. Provide an output destination for generated files.");
92863
+ process.exit(1);
92864
+ }
92865
+ const outputDir = resolve3(config3.outDir);
92866
+ if (config3.schemaDir) {
92867
+ await runRecursive(config3, resolve3(config3.schemaDir), outputDir);
92868
+ return;
92869
+ }
92870
+ if (!config3.schema) {
92871
+ console.error("Error: --schema (or --schemaDir) is required. Provide a path to a JSON Schema.");
92872
+ process.exit(1);
92705
92873
  }
92874
+ await runSingle(config3, resolve3(config3.schema), outputDir);
92706
92875
  };
92707
92876
  run10().catch((error54) => {
92708
92877
  console.error(error54 instanceof Error ? error54.message : error54);