@amritk/mjst 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/cli.js CHANGED
@@ -2,12 +2,14 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { execFile } from "node:child_process";
5
- import { mkdir, readFile as readFile2, unlink, writeFile } from "node:fs/promises";
6
- import { dirname, join, relative, resolve as resolve2 } from "node:path";
7
- import { fileURLToPath } from "node:url";
5
+ import { mkdir, readFile as readFile3, unlink, writeFile } from "node:fs/promises";
6
+ import { dirname as dirname2, join, resolve as resolve3 } from "node:path";
8
7
  import { promisify } from "node:util";
9
8
 
10
9
  // ../generate-parsers/dist/index.js
10
+ import { readFile } from "node:fs/promises";
11
+ import { createRequire } from "node:module";
12
+ import { dirname, resolve as resolvePath } from "node:path";
11
13
  var isSchemaObject = (schema) => {
12
14
  return typeof schema === "object" && schema !== null && typeof schema !== "boolean";
13
15
  };
@@ -783,21 +785,43 @@ var generateTypeDefinition = (schema, typeName) => {
783
785
  }
784
786
  return "export type " + typeName + " = unknown;";
785
787
  };
786
- var collectHelpers = (parserFunction) => {
788
+ var PACKAGE_IMPORTS = {
789
+ "is-object": "import { isObject } from '@amritk/helpers/is-object';",
790
+ "validate-array": "import { validateArray } from '@amritk/helpers/validate-array';",
791
+ "validate-record": "import { validateRecord } from '@amritk/helpers/validate-record';",
792
+ "has-ref": "import { hasRef } from '@amritk/helpers/schema-guards';"
793
+ };
794
+ var EMBEDDED_IMPORTS = {
795
+ "is-object": "import { isObject } from './_helpers/is-object';",
796
+ "validate-array": "import { validateArray } from './_helpers/validate-array';",
797
+ "validate-record": "import { validateRecord } from './_helpers/validate-record';",
798
+ "has-ref": "import { hasRef } from './_helpers/has-ref';"
799
+ };
800
+ var collectHelpers = (parserFunction, mode) => {
787
801
  const imports = [];
802
+ const used = new Set;
803
+ const table = mode === "embedded" ? EMBEDDED_IMPORTS : PACKAGE_IMPORTS;
788
804
  if (parserFunction.includes("validateArray")) {
789
- imports.push("import { validateArray } from '@amritk/helpers/validate-array';");
805
+ imports.push(table["validate-array"]);
806
+ used.add("validate-array");
790
807
  }
791
808
  if (parserFunction.includes("validateRecord")) {
792
- imports.push("import { validateRecord } from '@amritk/helpers/validate-record';");
809
+ imports.push(table["validate-record"]);
810
+ used.add("validate-record");
811
+ used.add("is-object");
793
812
  }
794
813
  if (parserFunction.includes("isObject")) {
795
- imports.push("import { isObject } from '@amritk/helpers/is-object';");
814
+ imports.push(table["is-object"]);
815
+ used.add("is-object");
796
816
  }
797
817
  if (parserFunction.includes("hasRef(")) {
798
- imports.push("import { hasRef } from '@amritk/helpers/schema-guards';");
818
+ imports.push(table["has-ref"]);
819
+ used.add("has-ref");
799
820
  }
800
- return imports;
821
+ return { imports, used };
822
+ };
823
+ var hasRef = (value) => {
824
+ return typeof value === "object" && value !== null && !Array.isArray(value) && "$ref" in value && typeof value.$ref === "string";
801
825
  };
802
826
  var isSchemaObject3 = (schema) => {
803
827
  return typeof schema === "object" && schema !== null && typeof schema !== "boolean";
@@ -880,9 +904,6 @@ var hasMinProperties = (schema) => {
880
904
  var hasMaxProperties = (schema) => {
881
905
  return isSchemaObject3(schema) && "maxProperties" in schema && typeof schema.maxProperties === "number";
882
906
  };
883
- var hasRef = (schema) => {
884
- return isSchemaObject3(schema) && "$ref" in schema && typeof schema.$ref === "string";
885
- };
886
907
  var getImportPathForFilename = (filename) => `./${filename}`;
887
908
  var collectImports = (schema, options) => {
888
909
  const typesOnly = options?.typesOnly === true;
@@ -1122,6 +1143,117 @@ var getDefaultValue = (schema) => {
1122
1143
  return "undefined";
1123
1144
  }
1124
1145
  };
1146
+ var wrongTypeCondition = (accessor, type) => {
1147
+ switch (type) {
1148
+ case "string":
1149
+ return `typeof ${accessor} !== "string"`;
1150
+ case "number":
1151
+ case "integer":
1152
+ return `typeof ${accessor} !== "number"`;
1153
+ case "boolean":
1154
+ return `typeof ${accessor} !== "boolean"`;
1155
+ case "array":
1156
+ return `!Array.isArray(${accessor})`;
1157
+ case "object":
1158
+ return `!isObject(${accessor})`;
1159
+ default:
1160
+ return null;
1161
+ }
1162
+ };
1163
+ var typeLabel = (type) => type === "integer" ? "number" : type;
1164
+ var escapeRegexPattern = (pattern) => {
1165
+ return pattern.replace(/\\/g, "\\\\").replace(/\//g, "\\/");
1166
+ };
1167
+ var generateConstraintChecks = (acc, propSchema, typeName, key) => {
1168
+ if (!isSchemaObject3(propSchema) || !hasType(propSchema))
1169
+ return [];
1170
+ const t = propSchema.type;
1171
+ const lines = [];
1172
+ if (t === "string") {
1173
+ if (hasPattern(propSchema)) {
1174
+ const pattern = escapeRegexPattern(propSchema.pattern);
1175
+ lines.push(` if (typeof ${acc} === "string" && !/${pattern}/.test(${acc})) throw new Error('[${typeName}] field "${key}" must match pattern ${propSchema.pattern}');`);
1176
+ }
1177
+ if (hasMinLength(propSchema)) {
1178
+ lines.push(` if (typeof ${acc} === "string" && ${acc}.length < ${propSchema.minLength}) throw new Error('[${typeName}] field "${key}" must have at least ${propSchema.minLength} characters');`);
1179
+ }
1180
+ if (hasMaxLength(propSchema)) {
1181
+ lines.push(` if (typeof ${acc} === "string" && ${acc}.length > ${propSchema.maxLength}) throw new Error('[${typeName}] field "${key}" must have at most ${propSchema.maxLength} characters');`);
1182
+ }
1183
+ }
1184
+ if (t === "number" || t === "integer") {
1185
+ if (hasMinimum(propSchema)) {
1186
+ lines.push(` if (typeof ${acc} === "number" && ${acc} < ${propSchema.minimum}) throw new Error('[${typeName}] field "${key}" must be >= ${propSchema.minimum}');`);
1187
+ }
1188
+ if (hasMaximum(propSchema)) {
1189
+ lines.push(` if (typeof ${acc} === "number" && ${acc} > ${propSchema.maximum}) throw new Error('[${typeName}] field "${key}" must be <= ${propSchema.maximum}');`);
1190
+ }
1191
+ if (hasExclusiveMinimum(propSchema)) {
1192
+ lines.push(` if (typeof ${acc} === "number" && ${acc} <= ${propSchema.exclusiveMinimum}) throw new Error('[${typeName}] field "${key}" must be > ${propSchema.exclusiveMinimum}');`);
1193
+ }
1194
+ if (hasExclusiveMaximum(propSchema)) {
1195
+ lines.push(` if (typeof ${acc} === "number" && ${acc} >= ${propSchema.exclusiveMaximum}) throw new Error('[${typeName}] field "${key}" must be < ${propSchema.exclusiveMaximum}');`);
1196
+ }
1197
+ if (hasMultipleOf(propSchema)) {
1198
+ lines.push(` if (typeof ${acc} === "number" && ${acc} % ${propSchema.multipleOf} !== 0) throw new Error('[${typeName}] field "${key}" must be a multiple of ${propSchema.multipleOf}');`);
1199
+ }
1200
+ }
1201
+ return lines;
1202
+ };
1203
+ var generatePropertyAssertion = (key, propSchema, isRequired, typeName) => {
1204
+ const acc = safeAccessor("input", key);
1205
+ const lines = [];
1206
+ if (isRequired) {
1207
+ lines.push(` if (!(${JSON.stringify(key)} in input)) throw new Error('[${typeName}] missing required property "${key}"');`);
1208
+ }
1209
+ if (!isSchemaObject3(propSchema))
1210
+ return lines;
1211
+ if (hasRef(propSchema))
1212
+ return lines;
1213
+ if (hasEnum(propSchema)) {
1214
+ const allowed = JSON.stringify(propSchema.enum);
1215
+ const label = propSchema.enum.map((v) => JSON.stringify(v)).join(", ");
1216
+ if (isRequired) {
1217
+ lines.push(` if (!(${allowed} as readonly unknown[]).includes(${acc})) throw new Error('[${typeName}] field "${key}" must be one of: ${label}');`);
1218
+ } else {
1219
+ lines.push(` if (${acc} !== undefined && !(${allowed} as readonly unknown[]).includes(${acc})) throw new Error('[${typeName}] field "${key}" must be one of: ${label}');`);
1220
+ }
1221
+ return lines;
1222
+ }
1223
+ if (hasType(propSchema)) {
1224
+ const t = propSchema.type;
1225
+ const wrongType = wrongTypeCondition(acc, t);
1226
+ if (wrongType) {
1227
+ if (isRequired) {
1228
+ lines.push(` if (${wrongType}) throw new Error(\`[${typeName}] field "${key}" expected ${typeLabel(t)}, got \${typeof ${acc}}\`);`);
1229
+ } else {
1230
+ lines.push(` if (${acc} !== undefined && (${wrongType})) throw new Error(\`[${typeName}] field "${key}" expected ${typeLabel(t)}, got \${typeof ${acc}}\`);`);
1231
+ }
1232
+ }
1233
+ lines.push(...generateConstraintChecks(acc, propSchema, typeName, key));
1234
+ }
1235
+ return lines;
1236
+ };
1237
+ var generateObjectStrictAssertion = (schema, typeName) => {
1238
+ const lines = [];
1239
+ lines.push(` if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);`);
1240
+ if (!hasProperties(schema) || !isSchemaObject3(schema))
1241
+ return lines;
1242
+ const required = new Set(hasRequired(schema) ? schema.required : []);
1243
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
1244
+ lines.push(...generatePropertyAssertion(key, propSchema, required.has(key), typeName));
1245
+ }
1246
+ return lines;
1247
+ };
1248
+ var generateScalarStrictAssertion = (schema, typeName) => {
1249
+ if (!isSchemaObject3(schema) || !hasType(schema))
1250
+ return null;
1251
+ const t = schema.type;
1252
+ const wrongType = wrongTypeCondition("input", t);
1253
+ if (!wrongType)
1254
+ return null;
1255
+ return ` if (${wrongType}) throw new Error(\`[${typeName}] expected ${typeLabel(t)}, got \${input === null ? "null" : typeof input}\`);`;
1256
+ };
1125
1257
  var findDiscriminator = (schemas) => {
1126
1258
  const propertyValues = new Map;
1127
1259
  for (const schema of schemas) {
@@ -1677,11 +1809,22 @@ var generateFallbackObject = (schema, useRefImports, typeName) => {
1677
1809
  }`;
1678
1810
  return result;
1679
1811
  };
1680
- var generateNonObjectParser = (typeName, schema) => {
1812
+ var generateNonObjectParser = (typeName, schema, strict) => {
1681
1813
  const functionName = generateParserName(typeName);
1682
1814
  if (!isSchemaObject3(schema) || !hasType(schema)) {
1683
1815
  return `export const ${functionName} = (input: unknown): ${typeName} => input as ${typeName};`;
1684
1816
  }
1817
+ if (strict) {
1818
+ const assertion = generateScalarStrictAssertion(schema, typeName);
1819
+ if (assertion === null) {
1820
+ return `export const ${functionName} = (input: unknown): ${typeName} => input as ${typeName};`;
1821
+ }
1822
+ const returnExpr = schema.type === "array" ? `[...(input as readonly unknown[])] as ${typeName}` : `input as ${typeName}`;
1823
+ return `export const ${functionName} = (input: unknown): ${typeName} => {
1824
+ ${assertion}
1825
+ return ${returnExpr};
1826
+ };`;
1827
+ }
1685
1828
  switch (schema.type) {
1686
1829
  case "string":
1687
1830
  return `export const ${functionName} = (input: unknown): ${typeName} => typeof input === "string" ? input as ${typeName} : "" as ${typeName};`;
@@ -1696,8 +1839,14 @@ var generateNonObjectParser = (typeName, schema) => {
1696
1839
  return `export const ${functionName} = (input: unknown): ${typeName} => input as ${typeName};`;
1697
1840
  }
1698
1841
  };
1699
- var generateEmptyObjectParser = (typeName) => {
1842
+ var generateEmptyObjectParser = (typeName, strict) => {
1700
1843
  const functionName = generateParserName(typeName);
1844
+ if (strict) {
1845
+ return `export const ${functionName} = (input: unknown): ${typeName} => {
1846
+ if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);
1847
+ return { ...input } as ${typeName};
1848
+ };`;
1849
+ }
1701
1850
  return `export const ${functionName} = (input: unknown): ${typeName} => isObject(input) ? { ...input } as ${typeName} : {} as ${typeName};`;
1702
1851
  };
1703
1852
  var toVarName = (key) => {
@@ -1726,7 +1875,7 @@ var generatePropertyTypeCheck = (varName, schema, useRefImports) => {
1726
1875
  case "string": {
1727
1876
  checks.push(`typeof ${varName} === "string"`);
1728
1877
  if (hasPattern(schema))
1729
- checks.push(`/${escapeRegexPattern(schema.pattern)}/.test(${varName})`);
1878
+ checks.push(`/${escapeRegexPattern2(schema.pattern)}/.test(${varName})`);
1730
1879
  if (hasMinLength(schema))
1731
1880
  checks.push(`${varName}.length >= ${schema.minLength}`);
1732
1881
  if (hasMaxLength(schema))
@@ -1779,16 +1928,28 @@ var generatePropertyTypeCheck = (varName, schema, useRefImports) => {
1779
1928
  var shouldCacheVariable = (propSchema, _canFastPath, _useRefImports) => {
1780
1929
  return isSchemaObject3(propSchema);
1781
1930
  };
1782
- var generateObjectParser = (schema, typeName, useRefImports, logWarnings) => {
1931
+ var generateObjectParser = (schema, typeName, useRefImports, logWarnings, strict) => {
1783
1932
  const functionName = generateParserName(typeName);
1784
1933
  if (!hasProperties(schema)) {
1934
+ if (strict) {
1935
+ return `export const ${functionName} = (input: unknown): ${typeName} => {
1936
+ if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);
1937
+ return input as ${typeName};
1938
+ };`;
1939
+ }
1785
1940
  return `export const ${functionName} = (input: unknown): ${typeName} => isObject(input) ? input as ${typeName} : {} as ${typeName};`;
1786
1941
  }
1787
1942
  const fallbackObject = generateFallbackObject(schema, useRefImports, typeName);
1788
1943
  const properties = Object.entries(schema.properties);
1789
1944
  const lines = [];
1790
1945
  lines.push(`export const ${functionName} = (input: unknown): ${typeName} => {`);
1791
- lines.push(` if (!isObject(input)) return ${fallbackObject};`);
1946
+ if (strict) {
1947
+ for (const assertionLine of generateObjectStrictAssertion(schema, typeName)) {
1948
+ lines.push(assertionLine);
1949
+ }
1950
+ } else {
1951
+ lines.push(` if (!isObject(input)) return ${fallbackObject};`);
1952
+ }
1792
1953
  const propInfo = [];
1793
1954
  const hasAllOfRefParsers = useRefImports && isSchemaObject3(schema) && hasAllOf(schema) && schema.allOf.some((entry) => isSchemaObject3(entry) && hasRef(entry));
1794
1955
  let canFastPath = !hasAllOfRefParsers;
@@ -1911,7 +2072,7 @@ var generateObjectParser = (schema, typeName, useRefImports, logWarnings) => {
1911
2072
  }
1912
2073
  return result;
1913
2074
  };
1914
- var generateCombinedObjectParser = (schema, typeName, useRefImports, logWarnings) => {
2075
+ var generateCombinedObjectParser = (schema, typeName, useRefImports, logWarnings, strict) => {
1915
2076
  const functionName = generateParserName(typeName);
1916
2077
  const entries = generatePropertyEntries(schema, useRefImports);
1917
2078
  const propertyLines = entries.map((entry) => {
@@ -1921,19 +2082,19 @@ var generateCombinedObjectParser = (schema, typeName, useRefImports, logWarnings
1921
2082
  return ` ${safeKey2(entry.key)}: ${entry.value},`;
1922
2083
  });
1923
2084
  if (!isSchemaObject3(schema) || !("patternProperties" in schema)) {
1924
- return generateObjectParser(schema, typeName, useRefImports, logWarnings);
2085
+ return generateObjectParser(schema, typeName, useRefImports, logWarnings, strict);
1925
2086
  }
1926
2087
  const patternProps = schema.patternProperties;
1927
2088
  const patterns = Object.entries(patternProps);
1928
2089
  const refPattern = patterns.find(([, ps]) => isSchemaObject3(ps) && hasRef(ps));
1929
2090
  if (!refPattern || !useRefImports) {
1930
- return generateObjectParser(schema, typeName, useRefImports, logWarnings);
2091
+ return generateObjectParser(schema, typeName, useRefImports, logWarnings, strict);
1931
2092
  }
1932
2093
  const [pattern, patternSchema] = refPattern;
1933
2094
  const ref = patternSchema.$ref;
1934
2095
  const parserName = generateParserName(refToName(ref));
1935
2096
  const assignmentCode = `(result as Record<string, unknown>)[key] = ${parserName}(value);`;
1936
- const escapedPattern = escapeRegexPattern(pattern);
2097
+ const escapedPattern = escapeRegexPattern2(pattern);
1937
2098
  const inputSpread = " ...input,";
1938
2099
  let objectProperties = inputSpread;
1939
2100
  if (propertyLines.length > 0) {
@@ -1942,9 +2103,10 @@ var generateCombinedObjectParser = (schema, typeName, useRefImports, logWarnings
1942
2103
  ` + line;
1943
2104
  }
1944
2105
  }
2106
+ const notObjectBranch = strict ? ` throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);` : ` return {} as unknown as ${typeName};`;
1945
2107
  return `export const ${functionName} = (input: unknown): ${typeName} => {
1946
2108
  if (!isObject(input)) {
1947
- return {} as unknown as ${typeName};
2109
+ ${notObjectBranch}
1948
2110
  }
1949
2111
  const result = {
1950
2112
  ${objectProperties}
@@ -1958,23 +2120,41 @@ ${objectProperties}
1958
2120
  return result;
1959
2121
  };`;
1960
2122
  };
1961
- var generateAdditionalPropertiesParser = (schema, typeName, useRefImports) => {
2123
+ var generateAdditionalPropertiesParser = (schema, typeName, useRefImports, strict) => {
1962
2124
  const functionName = generateParserName(typeName);
1963
2125
  const additionalProps = schema.additionalProperties;
1964
2126
  if (!additionalProps) {
1965
- return generateEmptyObjectParser(typeName);
2127
+ return generateEmptyObjectParser(typeName, strict);
1966
2128
  }
1967
2129
  if (useRefImports && isSchemaObject3(additionalProps) && hasRef(additionalProps)) {
1968
2130
  const ref = additionalProps.$ref;
1969
2131
  const parserName = generateParserName(refToName(ref));
2132
+ if (strict) {
2133
+ return `export const ${functionName} = (input: unknown): ${typeName} => {
2134
+ if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);
2135
+ return validateRecord(input, ${parserName}) as ${typeName};
2136
+ };`;
2137
+ }
1970
2138
  return `export const ${functionName} = (input: unknown): ${typeName} => validateRecord(input, ${parserName}) as ${typeName};`;
1971
2139
  }
1972
2140
  if (isSchemaObject3(additionalProps) && hasType(additionalProps)) {
1973
2141
  const inlineParser = generateInlineValueParser(additionalProps);
1974
2142
  if (inlineParser) {
2143
+ if (strict) {
2144
+ return `export const ${functionName} = (input: unknown): ${typeName} => {
2145
+ if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);
2146
+ return validateRecord(input, ${inlineParser}) as ${typeName};
2147
+ };`;
2148
+ }
1975
2149
  return `export const ${functionName} = (input: unknown): ${typeName} => validateRecord(input, ${inlineParser}) as ${typeName};`;
1976
2150
  }
1977
2151
  }
2152
+ if (strict) {
2153
+ return `export const ${functionName} = (input: unknown): ${typeName} => {
2154
+ if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);
2155
+ return { ...input } as ${typeName};
2156
+ };`;
2157
+ }
1978
2158
  return `export const ${functionName} = (input: unknown): ${typeName} => isObject(input) ? { ...input } as ${typeName} : {};`;
1979
2159
  };
1980
2160
  var generateInlineValueParser = (schema) => {
@@ -1995,18 +2175,18 @@ var generateInlineValueParser = (schema) => {
1995
2175
  return null;
1996
2176
  }
1997
2177
  };
1998
- var escapeRegexPattern = (pattern) => {
2178
+ var escapeRegexPattern2 = (pattern) => {
1999
2179
  return pattern.replace(/\\/g, "\\\\").replace(/\//g, "\\/");
2000
2180
  };
2001
- var generatePatternPropertiesParser = (schema, typeName, useRefImports) => {
2181
+ var generatePatternPropertiesParser = (schema, typeName, useRefImports, strict) => {
2002
2182
  const functionName = generateParserName(typeName);
2003
2183
  if (!("patternProperties" in schema) || typeof schema.patternProperties !== "object") {
2004
- return generateEmptyObjectParser(typeName);
2184
+ return generateEmptyObjectParser(typeName, strict);
2005
2185
  }
2006
2186
  const patternProps = schema.patternProperties;
2007
2187
  const patterns = Object.entries(patternProps);
2008
2188
  if (patterns.length === 0) {
2009
- return generateEmptyObjectParser(typeName);
2189
+ return generateEmptyObjectParser(typeName, strict);
2010
2190
  }
2011
2191
  const [pattern, patternSchema] = patterns[0];
2012
2192
  let patternAssignment = "(result as Record<string, unknown>)[key] = value;";
@@ -2017,10 +2197,11 @@ var generatePatternPropertiesParser = (schema, typeName, useRefImports) => {
2017
2197
  } else if (patternSchema === false) {
2018
2198
  patternAssignment = "";
2019
2199
  }
2020
- const escapedPattern = escapeRegexPattern(pattern);
2200
+ const escapedPattern = escapeRegexPattern2(pattern);
2201
+ const notObjectBranch = strict ? ` throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);` : ` return {} as unknown as ${typeName};`;
2021
2202
  return `export const ${functionName} = (input: unknown): ${typeName} => {
2022
2203
  if (!isObject(input)) {
2023
- return {} as unknown as ${typeName};
2204
+ ${notObjectBranch}
2024
2205
  }
2025
2206
  const result = {
2026
2207
  ...input,
@@ -2132,43 +2313,44 @@ var generateSchemaObjectParser = (typeName) => {
2132
2313
  var selectParserStrategy = (schema, typeName, options) => {
2133
2314
  const useRefImports = options?.useRefImports ?? false;
2134
2315
  const logWarnings = options?.logWarnings ?? false;
2316
+ const strict = options?.strict ?? false;
2135
2317
  if (typeName === "SchemaObject") {
2136
2318
  return generateSchemaObjectParser(typeName);
2137
2319
  }
2138
2320
  const isObjectLikeSchema2 = isObjectSchema2(schema) || isSchemaObject3(schema) && (("patternProperties" in schema) || ("additionalProperties" in schema));
2139
2321
  if (!isObjectLikeSchema2 && !isSchemaObject3(schema)) {
2140
- return generateNonObjectParser(typeName, schema);
2322
+ return generateNonObjectParser(typeName, schema, strict);
2141
2323
  }
2142
2324
  if (hasProperties(schema) && isSchemaObject3(schema) && "patternProperties" in schema) {
2143
- return generateCombinedObjectParser(schema, typeName, useRefImports, logWarnings);
2325
+ return generateCombinedObjectParser(schema, typeName, useRefImports, logWarnings, strict);
2144
2326
  }
2145
2327
  if (hasProperties(schema)) {
2146
- return generateObjectParser(schema, typeName, useRefImports, logWarnings);
2328
+ return generateObjectParser(schema, typeName, useRefImports, logWarnings, strict);
2147
2329
  }
2148
2330
  if (isSchemaObject3(schema) && "if" in schema && "then" in schema && "else" in schema) {
2149
2331
  return generateConditionalParser(schema, typeName);
2150
2332
  }
2151
2333
  const conditionalObjectSchema = getConditionalObjectSchema2(schema);
2152
2334
  if (conditionalObjectSchema) {
2153
- return generateObjectParser(conditionalObjectSchema, typeName, useRefImports, logWarnings);
2335
+ return generateObjectParser(conditionalObjectSchema, typeName, useRefImports, logWarnings, strict);
2154
2336
  }
2155
2337
  if (!isObjectLikeSchema2) {
2156
- return generateNonObjectParser(typeName, schema);
2338
+ return generateNonObjectParser(typeName, schema, strict);
2157
2339
  }
2158
2340
  if ("patternProperties" in schema) {
2159
- return generatePatternPropertiesParser(schema, typeName, useRefImports);
2341
+ return generatePatternPropertiesParser(schema, typeName, useRefImports, strict);
2160
2342
  }
2161
2343
  if ("additionalProperties" in schema && !hasProperties(schema)) {
2162
2344
  const additionalProps = schema.additionalProperties;
2163
2345
  if (additionalProps === true || additionalProps === false) {
2164
- return generateEmptyObjectParser(typeName);
2346
+ return generateEmptyObjectParser(typeName, strict);
2165
2347
  }
2166
- return generateAdditionalPropertiesParser(schema, typeName, useRefImports);
2348
+ return generateAdditionalPropertiesParser(schema, typeName, useRefImports, strict);
2167
2349
  }
2168
2350
  if ("type" in schema && schema.type === "object" && !hasProperties(schema)) {
2169
- return generateEmptyObjectParser(typeName);
2351
+ return generateEmptyObjectParser(typeName, strict);
2170
2352
  }
2171
- return generateEmptyObjectParser(typeName);
2353
+ return generateEmptyObjectParser(typeName, strict);
2172
2354
  };
2173
2355
  var generateParserFunction = (schema, typeName, options) => {
2174
2356
  return selectParserStrategy(schema, typeName, options);
@@ -2218,6 +2400,7 @@ var generateFile = (schema, typeName, options) => {
2218
2400
  const typesOnly = options?.typesOnly === true;
2219
2401
  const selfRef = options?.selfRef;
2220
2402
  const rootSchema = options?.rootSchema;
2403
+ const helpersMode = options?.helpersMode ?? "package";
2221
2404
  const typeDefinition = generateTypeDefinition(schema, typeName);
2222
2405
  if (typesOnly) {
2223
2406
  const imports2 = collectImports(schema, { typesOnly: true, selfRef, rootSchema });
@@ -2232,17 +2415,19 @@ var generateFile = (schema, typeName, options) => {
2232
2415
 
2233
2416
  `;
2234
2417
  }
2235
- return result2 + typeDefinition;
2418
+ return { content: result2 + typeDefinition, usedHelpers: new Set };
2236
2419
  }
2237
2420
  const parserFunction = generateParserFunction(schema, typeName, {
2238
2421
  useRefImports: true,
2239
- ...options?.logWarnings !== undefined ? { logWarnings: options.logWarnings } : {}
2422
+ ...options?.logWarnings !== undefined ? { logWarnings: options.logWarnings } : {},
2423
+ ...options?.strict !== undefined ? { strict: options.strict } : {}
2240
2424
  });
2241
2425
  const shapeValidator = generateShapeValidator(schema, typeName, true);
2242
2426
  const combinedFunctions = `${shapeValidator}
2243
2427
 
2244
2428
  ${parserFunction}`;
2245
- const imports = [...collectImports(schema, { selfRef, rootSchema }), ...collectHelpers(combinedFunctions)];
2429
+ const helpers = collectHelpers(combinedFunctions, helpersMode);
2430
+ const imports = [...collectImports(schema, { selfRef, rootSchema }), ...helpers.imports];
2246
2431
  let result = "";
2247
2432
  if (imports.length > 0) {
2248
2433
  result += imports[0];
@@ -2254,9 +2439,15 @@ ${parserFunction}`;
2254
2439
 
2255
2440
  `;
2256
2441
  }
2257
- return result + typeDefinition + `
2442
+ return { content: result + typeDefinition + `
2258
2443
 
2259
- ` + combinedFunctions;
2444
+ ` + combinedFunctions, usedHelpers: helpers.used };
2445
+ };
2446
+ var readHelperSource = async (helper) => {
2447
+ const require2 = createRequire(import.meta.url);
2448
+ const helpersPkgPath = require2.resolve("@amritk/helpers/package.json");
2449
+ const helpersRoot = dirname(helpersPkgPath);
2450
+ return readFile(resolvePath(helpersRoot, "src", `${helper}.ts`), "utf-8");
2260
2451
  };
2261
2452
  var extractDynamicAnchorDefs = (schema) => {
2262
2453
  const refs = [];
@@ -2277,26 +2468,31 @@ var extractDynamicAnchorDefs = (schema) => {
2277
2468
  }
2278
2469
  return refs;
2279
2470
  };
2280
- var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings) => {
2471
+ var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWarnings, strict, helpersMode = "package") => {
2281
2472
  rootSchema = upgradeDraft07Schema(rootSchema);
2282
2473
  const files = [];
2283
2474
  const processedRefs = new Set;
2284
2475
  const processedFilenames = new Set;
2285
2476
  const refsToProcess = [];
2477
+ const usedHelpers = new Set;
2286
2478
  const dynamicRefMap = buildDynamicRefMap(rootSchema);
2287
2479
  const processedRootSchema = resolveDynamicRefs(rootSchema, dynamicRefMap);
2288
2480
  const extendedRootSchema = extensions ? applySchemaExtensions(processedRootSchema, rootTypeName.toLowerCase(), extensions) : processedRootSchema;
2289
- const rootContent = generateFile(extendedRootSchema, rootTypeName, {
2481
+ const rootResult = generateFile(extendedRootSchema, rootTypeName, {
2290
2482
  typesOnly: typesOnly ?? false,
2291
2483
  rootSchema,
2292
- ...logWarnings !== undefined ? { logWarnings } : {}
2484
+ helpersMode,
2485
+ ...logWarnings !== undefined ? { logWarnings } : {},
2486
+ ...strict !== undefined ? { strict } : {}
2293
2487
  });
2294
2488
  const rootFilename = rootTypeName.toLowerCase();
2295
2489
  processedFilenames.add(rootFilename);
2296
2490
  files.push({
2297
2491
  filename: `${rootFilename}.ts`,
2298
- content: rootContent
2492
+ content: rootResult.content
2299
2493
  });
2494
+ for (const helper of rootResult.usedHelpers)
2495
+ usedHelpers.add(helper);
2300
2496
  const rootRefs = extractRefs(rootSchema);
2301
2497
  refsToProcess.push(...rootRefs);
2302
2498
  const dynamicAnchorRefs = extractDynamicAnchorDefs(rootSchema);
@@ -2316,19 +2512,23 @@ var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWar
2316
2512
  const filename = refToFilename(ref);
2317
2513
  const processedSchema = resolveDynamicRefs(resolvedSchema, dynamicRefMap);
2318
2514
  const extendedSchema = extensions ? applySchemaExtensions(processedSchema, filename, extensions) : processedSchema;
2319
- const content = generateFile(extendedSchema, typeName, {
2515
+ const fileResult = generateFile(extendedSchema, typeName, {
2320
2516
  typesOnly: typesOnly ?? false,
2321
2517
  selfRef: ref,
2322
2518
  rootSchema,
2323
- ...logWarnings !== undefined ? { logWarnings } : {}
2519
+ helpersMode,
2520
+ ...logWarnings !== undefined ? { logWarnings } : {},
2521
+ ...strict !== undefined ? { strict } : {}
2324
2522
  });
2325
2523
  if (!processedFilenames.has(filename)) {
2326
2524
  processedFilenames.add(filename);
2327
2525
  files.push({
2328
2526
  filename: `${filename}.ts`,
2329
- content
2527
+ content: fileResult.content
2330
2528
  });
2331
2529
  }
2530
+ for (const helper of fileResult.usedHelpers)
2531
+ usedHelpers.add(helper);
2332
2532
  const nestedRefs = extractRefs(resolvedSchema);
2333
2533
  for (const nestedRef of nestedRefs) {
2334
2534
  if (!processedRefs.has(nestedRef)) {
@@ -2336,9 +2536,15 @@ var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWar
2336
2536
  }
2337
2537
  }
2338
2538
  }
2539
+ if (helpersMode === "embedded" && !typesOnly) {
2540
+ for (const helper of usedHelpers) {
2541
+ const source = await readHelperSource(helper);
2542
+ files.push({ filename: `_helpers/${helper}.ts`, content: source });
2543
+ }
2544
+ }
2339
2545
  const TYPE_EXPORT_RE = /^export type (\w+)/gm;
2340
2546
  const CONST_EXPORT_RE = /^export const (\w+)/gm;
2341
- const sortedFiles = [...files].sort((a, b) => a.filename.localeCompare(b.filename));
2547
+ const sortedFiles = [...files].filter((f) => !f.filename.startsWith("_helpers/")).sort((a, b) => a.filename.localeCompare(b.filename));
2342
2548
  let indexContent = "";
2343
2549
  for (const file of sortedFiles) {
2344
2550
  const moduleName = file.filename.replace(/\.ts$/, "");
@@ -2369,12 +2575,25 @@ var buildSchema = async (rootSchema, rootTypeName, extensions, typesOnly, logWar
2369
2575
  return files;
2370
2576
  };
2371
2577
 
2372
- // src/load-config.ts
2373
- import { readFile } from "node:fs/promises";
2578
+ // src/detect-helpers-mode.ts
2579
+ import { createRequire as createRequire2 } from "node:module";
2374
2580
  import { resolve } from "node:path";
2581
+ var detectHelpersMode = (outputDir) => {
2582
+ const req = createRequire2(resolve(outputDir, "noop.js"));
2583
+ try {
2584
+ req.resolve("@amritk/helpers/is-object");
2585
+ return "package";
2586
+ } catch {
2587
+ return "embedded";
2588
+ }
2589
+ };
2590
+
2591
+ // src/load-config.ts
2592
+ import { readFile as readFile2 } from "node:fs/promises";
2593
+ import { resolve as resolve2 } from "node:path";
2375
2594
  var loadConfig = async (configPath) => {
2376
- const absolutePath = resolve(configPath);
2377
- const raw = await readFile(absolutePath, "utf-8");
2595
+ const absolutePath = resolve2(configPath);
2596
+ const raw = await readFile2(absolutePath, "utf-8");
2378
2597
  const parsed = JSON.parse(raw);
2379
2598
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2380
2599
  throw new Error(`Config file must be a JSON object: ${configPath}`);
@@ -2385,13 +2604,19 @@ var loadConfig = async (configPath) => {
2385
2604
  ...typeof obj["outDir"] === "string" && { outDir: obj["outDir"] },
2386
2605
  ...typeof obj["typesOnly"] === "boolean" && { typesOnly: obj["typesOnly"] },
2387
2606
  ...typeof obj["build"] === "boolean" && { build: obj["build"] },
2388
- ...typeof obj["logWarnings"] === "boolean" && { logWarnings: obj["logWarnings"] }
2607
+ ...typeof obj["logWarnings"] === "boolean" && { logWarnings: obj["logWarnings"] },
2608
+ ...typeof obj["strict"] === "boolean" && { strict: obj["strict"] }
2389
2609
  };
2390
2610
  };
2391
2611
 
2392
2612
  // src/parse-cli-args.ts
2393
2613
  var parseCliArgs = (args) => {
2394
2614
  const config = {};
2615
+ const parseHelpersValue = (value) => {
2616
+ if (value === "package" || value === "embedded")
2617
+ return value;
2618
+ return;
2619
+ };
2395
2620
  for (let i = 0;i < args.length; i++) {
2396
2621
  const arg = args[i];
2397
2622
  if (!arg) {
@@ -2411,6 +2636,12 @@ var parseCliArgs = (args) => {
2411
2636
  config.build = value !== "false";
2412
2637
  } else if (key === "log-warnings") {
2413
2638
  config.logWarnings = value !== "false";
2639
+ } else if (key === "strict") {
2640
+ config.strict = value !== "false";
2641
+ } else if (key === "helpers") {
2642
+ const parsed = parseHelpersValue(value);
2643
+ if (parsed)
2644
+ config.helpers = parsed;
2414
2645
  }
2415
2646
  continue;
2416
2647
  }
@@ -2432,6 +2663,17 @@ var parseCliArgs = (args) => {
2432
2663
  config.build = true;
2433
2664
  } else if (arg === "--log-warnings") {
2434
2665
  config.logWarnings = true;
2666
+ } else if (arg === "--strict") {
2667
+ config.strict = true;
2668
+ } else if (arg === "--helpers") {
2669
+ const value = args[i + 1];
2670
+ if (value && !value.startsWith("--")) {
2671
+ const parsed = parseHelpersValue(value);
2672
+ if (parsed) {
2673
+ config.helpers = parsed;
2674
+ i++;
2675
+ }
2676
+ }
2435
2677
  }
2436
2678
  }
2437
2679
  return config;
@@ -2465,21 +2707,21 @@ var run = async () => {
2465
2707
  console.error("Error: --outDir is required. Provide an output directory for generated files.");
2466
2708
  process.exit(1);
2467
2709
  }
2468
- const schemaPath = resolve2(config.schema);
2469
- const raw = await readFile2(schemaPath, "utf-8");
2710
+ const schemaPath = resolve3(config.schema);
2711
+ const raw = await readFile3(schemaPath, "utf-8");
2470
2712
  const schema = JSON.parse(raw);
2471
- const files = await buildSchema(schema, "Document", undefined, config.typesOnly, config.logWarnings);
2472
- const outputDir = resolve2(config.outDir);
2713
+ const outputDir = resolve3(config.outDir);
2473
2714
  await mkdir(outputDir, { recursive: true });
2715
+ const helpersMode = config.helpers ?? detectHelpersMode(outputDir);
2716
+ console.log(`Helpers mode: ${helpersMode}${config.helpers ? " (explicit)" : " (auto-detected)"}`);
2717
+ const files = await buildSchema(schema, "Document", undefined, config.typesOnly, config.logWarnings, config.strict, helpersMode);
2474
2718
  for (const file of files) {
2475
2719
  const filePath = join(outputDir, file.filename);
2476
- await mkdir(dirname(filePath), { recursive: true });
2720
+ await mkdir(dirname2(filePath), { recursive: true });
2477
2721
  await writeFile(filePath, file.content, "utf-8");
2478
2722
  console.log(`Generated: ${file.filename}`);
2479
2723
  }
2480
2724
  if (config.build) {
2481
- const helpersDir = resolve2(dirname(fileURLToPath(import.meta.url)), "../../helpers/dist");
2482
- const helpersRelative = relative(outputDir, helpersDir);
2483
2725
  const tsconfigContent = JSON.stringify({
2484
2726
  compilerOptions: {
2485
2727
  target: "ESNext",
@@ -2487,10 +2729,7 @@ var run = async () => {
2487
2729
  moduleResolution: "bundler",
2488
2730
  declaration: true,
2489
2731
  emitDeclarationOnly: config.typesOnly,
2490
- skipLibCheck: true,
2491
- paths: {
2492
- "@amritk/helpers/*": [`${helpersRelative}/*`]
2493
- }
2732
+ skipLibCheck: true
2494
2733
  },
2495
2734
  include: ["./**/*.ts"]
2496
2735
  }, null, 2);