typebars 1.0.12 → 1.0.14

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.
Files changed (39) hide show
  1. package/dist/cjs/analyzer.js +1 -1
  2. package/dist/cjs/analyzer.js.map +1 -1
  3. package/dist/cjs/compiled-template.js +1 -1
  4. package/dist/cjs/compiled-template.js.map +1 -1
  5. package/dist/cjs/executor.d.ts +3 -1
  6. package/dist/cjs/executor.js +1 -1
  7. package/dist/cjs/executor.js.map +1 -1
  8. package/dist/cjs/helpers/collection-helpers.d.ts +9 -0
  9. package/dist/cjs/helpers/collection-helpers.js +2 -0
  10. package/dist/cjs/helpers/collection-helpers.js.map +1 -0
  11. package/dist/cjs/helpers/index.d.ts +1 -0
  12. package/dist/cjs/helpers/index.js +1 -1
  13. package/dist/cjs/helpers/index.js.map +1 -1
  14. package/dist/cjs/parser.js +1 -1
  15. package/dist/cjs/parser.js.map +1 -1
  16. package/dist/cjs/schema-resolver.js +1 -1
  17. package/dist/cjs/schema-resolver.js.map +1 -1
  18. package/dist/cjs/typebars.js +1 -1
  19. package/dist/cjs/typebars.js.map +1 -1
  20. package/dist/esm/analyzer.js +1 -1
  21. package/dist/esm/analyzer.js.map +1 -1
  22. package/dist/esm/compiled-template.js +1 -1
  23. package/dist/esm/compiled-template.js.map +1 -1
  24. package/dist/esm/executor.d.ts +3 -1
  25. package/dist/esm/executor.js +1 -1
  26. package/dist/esm/executor.js.map +1 -1
  27. package/dist/esm/helpers/collection-helpers.d.ts +9 -0
  28. package/dist/esm/helpers/collection-helpers.js +2 -0
  29. package/dist/esm/helpers/collection-helpers.js.map +1 -0
  30. package/dist/esm/helpers/index.d.ts +1 -0
  31. package/dist/esm/helpers/index.js +1 -1
  32. package/dist/esm/helpers/index.js.map +1 -1
  33. package/dist/esm/parser.js +1 -1
  34. package/dist/esm/parser.js.map +1 -1
  35. package/dist/esm/schema-resolver.js +1 -1
  36. package/dist/esm/schema-resolver.js.map +1 -1
  37. package/dist/esm/typebars.js +1 -1
  38. package/dist/esm/typebars.js.map +1 -1
  39. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/schema-resolver.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport { UnsupportedSchemaError } from \"./errors.ts\";\nimport { deepEqual } from \"./utils.ts\";\n\n// ─── JSON Schema Resolver ────────────────────────────────────────────────────\n// Utility for navigating a JSON Schema Draft v7 by following a property path\n// (e.g. [\"user\", \"address\", \"city\"]).\n//\n// Handles:\n// - `$ref` resolution (internal references #/definitions/...)\n// - Navigation through `properties`\n// - Navigation through `items` (array elements)\n// - Combinators `allOf`, `anyOf`, `oneOf` (searches each branch)\n// - `additionalProperties` when the property is not explicitly declared\n//\n// Rejects:\n// - Conditional schemas (`if/then/else`) — non-resolvable without runtime data\n\n// ─── Conditional Schema Detection ────────────────────────────────────────────\n// JSON Schema Draft v7 introduced `if/then/else` conditional schemas.\n// These are fundamentally non-resolvable during static analysis because\n// they depend on runtime data values. Rather than silently ignoring them\n// (which would produce incorrect results — missing properties, wrong types),\n// we fail fast with a clear error pointing to the exact location in the schema.\n\n/**\n * Recursively validates that a JSON Schema does not contain `if/then/else`\n * conditional keywords. Throws an `UnsupportedSchemaError` if any are found.\n *\n * This check traverses the entire schema tree, including:\n * - `properties` values\n * - `additionalProperties` (when it's a schema)\n * - `items` (single schema or tuple)\n * - `allOf`, `anyOf`, `oneOf` branches\n * - `not`\n * - `definitions` / `$defs` values\n *\n * A `Set<object>` is used to track visited schemas and prevent infinite loops\n * from circular structures.\n *\n * @param schema - The JSON Schema to validate\n * @param path - The current JSON pointer path (for error reporting)\n * @param visited - Set of already-visited schema objects (cycle protection)\n *\n * @throws {UnsupportedSchemaError} if `if`, `then`, or `else` is found\n *\n * @example\n * ```\n * // Throws UnsupportedSchemaError:\n * assertNoConditionalSchema({\n * type: \"object\",\n * if: { properties: { kind: { const: \"a\" } } },\n * then: { properties: { a: { type: \"string\" } } },\n * });\n *\n * // OK — no conditional keywords:\n * assertNoConditionalSchema({\n * type: \"object\",\n * properties: { name: { type: \"string\" } },\n * });\n * ```\n */\nexport function assertNoConditionalSchema(\n\tschema: JSONSchema7,\n\tpath = \"\",\n\tvisited: Set<object> = new Set(),\n): void {\n\t// Cycle protection — avoid infinite loops on circular schema structures\n\tif (visited.has(schema)) return;\n\tvisited.add(schema);\n\n\t// ── Detect if/then/else at the current level ─────────────────────────\n\tif (schema.if !== undefined) {\n\t\tthrow new UnsupportedSchemaError(\"if/then/else\", path || \"/\");\n\t}\n\t// `then` or `else` without `if` is unusual but still unsupported\n\tif (schema.then !== undefined) {\n\t\tthrow new UnsupportedSchemaError(\"if/then/else\", path || \"/\");\n\t}\n\tif (schema.else !== undefined) {\n\t\tthrow new UnsupportedSchemaError(\"if/then/else\", path || \"/\");\n\t}\n\n\t// ── Recurse into properties ──────────────────────────────────────────\n\tif (schema.properties) {\n\t\tfor (const [key, prop] of Object.entries(schema.properties)) {\n\t\t\tif (prop && typeof prop !== \"boolean\") {\n\t\t\t\tassertNoConditionalSchema(prop, `${path}/properties/${key}`, visited);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into additionalProperties ────────────────────────────────\n\tif (\n\t\tschema.additionalProperties &&\n\t\ttypeof schema.additionalProperties === \"object\"\n\t) {\n\t\tassertNoConditionalSchema(\n\t\t\tschema.additionalProperties,\n\t\t\t`${path}/additionalProperties`,\n\t\t\tvisited,\n\t\t);\n\t}\n\n\t// ── Recurse into items ───────────────────────────────────────────────\n\tif (schema.items) {\n\t\tif (Array.isArray(schema.items)) {\n\t\t\tfor (let i = 0; i < schema.items.length; i++) {\n\t\t\t\tconst item = schema.items[i];\n\t\t\t\tif (item && typeof item !== \"boolean\") {\n\t\t\t\t\tassertNoConditionalSchema(item, `${path}/items/${i}`, visited);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof schema.items !== \"boolean\") {\n\t\t\tassertNoConditionalSchema(schema.items, `${path}/items`, visited);\n\t\t}\n\t}\n\n\t// ── Recurse into combinators ─────────────────────────────────────────\n\tfor (const keyword of [\"allOf\", \"anyOf\", \"oneOf\"] as const) {\n\t\tconst branches = schema[keyword];\n\t\tif (branches) {\n\t\t\tfor (let i = 0; i < branches.length; i++) {\n\t\t\t\tconst branch = branches[i];\n\t\t\t\tif (branch && typeof branch !== \"boolean\") {\n\t\t\t\t\tassertNoConditionalSchema(branch, `${path}/${keyword}/${i}`, visited);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into not ─────────────────────────────────────────────────\n\tif (schema.not && typeof schema.not !== \"boolean\") {\n\t\tassertNoConditionalSchema(schema.not, `${path}/not`, visited);\n\t}\n\n\t// ── Recurse into definitions / $defs ─────────────────────────────────\n\tfor (const defsKey of [\"definitions\", \"$defs\"] as const) {\n\t\tconst defs = schema[defsKey];\n\t\tif (defs) {\n\t\t\tfor (const [name, def] of Object.entries(defs)) {\n\t\t\t\tif (def && typeof def !== \"boolean\") {\n\t\t\t\t\tassertNoConditionalSchema(def, `${path}/${defsKey}/${name}`, visited);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ─── $ref Resolution ─────────────────────────────────────────────────────────\n// Only supports internal references in the format `#/definitions/Foo`\n// or `#/$defs/Foo` (JSON Schema Draft 2019+). Remote $refs (URLs) are\n// not supported — that is outside the scope of a template engine.\n\n/**\n * Recursively resolves `$ref` in a schema using the root schema as the\n * source of definitions.\n */\nexport function resolveRef(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 {\n\tif (!schema.$ref) return schema;\n\n\tconst ref = schema.$ref;\n\n\t// Expected format: #/definitions/Name or #/$defs/Name\n\tconst match = ref.match(/^#\\/(definitions|\\$defs)\\/(.+)$/);\n\tif (!match) {\n\t\tthrow new Error(\n\t\t\t`Unsupported $ref format: \"${ref}\". Only internal #/definitions/ references are supported.`,\n\t\t);\n\t}\n\n\tconst defsKey = match[1] as \"definitions\" | \"$defs\";\n\tconst name = match[2] ?? \"\";\n\n\tconst defs = defsKey === \"definitions\" ? root.definitions : root.$defs;\n\n\tif (!defs || !(name in defs)) {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve $ref \"${ref}\": definition \"${name}\" not found.`,\n\t\t);\n\t}\n\n\t// Recursive resolution in case the definition itself contains a $ref\n\tconst def = defs[name];\n\tif (!def || typeof def === \"boolean\") {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve $ref \"${ref}\": definition \"${name}\" not found.`,\n\t\t);\n\t}\n\treturn resolveRef(def, root);\n}\n\n// ─── Single-Segment Path Navigation ─────────────────────────────────────────\n\n/**\n * Resolves a single path segment (a property name) within a schema.\n * Returns the corresponding sub-schema, or `undefined` if the path is invalid.\n *\n * @param schema - The current schema (already resolved, no $ref)\n * @param segment - The property name to resolve\n * @param root - The root schema (for resolving any internal $refs)\n */\nfunction resolveSegment(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// 1. Explicit properties\n\tif (resolved.properties && segment in resolved.properties) {\n\t\tconst prop = resolved.properties[segment];\n\t\tif (prop && typeof prop !== \"boolean\") return resolveRef(prop, root);\n\t\tif (prop === true) return {};\n\t}\n\n\t// 2. additionalProperties (when the property is not declared)\n\tif (\n\t\tresolved.additionalProperties !== undefined &&\n\t\tresolved.additionalProperties !== false\n\t) {\n\t\tif (resolved.additionalProperties === true) {\n\t\t\t// additionalProperties: true → type is unknown\n\t\t\treturn {};\n\t\t}\n\t\treturn resolveRef(resolved.additionalProperties, root);\n\t}\n\n\t// 3. Intrinsic array properties (e.g. `.length`)\n\tconst schemaType = resolved.type;\n\tconst isArray =\n\t\tschemaType === \"array\" ||\n\t\t(Array.isArray(schemaType) && schemaType.includes(\"array\"));\n\n\tif (isArray && segment === \"length\") {\n\t\treturn { type: \"integer\" };\n\t}\n\n\t// 4. Combinators — search within each branch\n\tconst combinatorResult = resolveInCombinators(resolved, segment, root);\n\tif (combinatorResult) return combinatorResult;\n\n\treturn undefined;\n}\n\n/**\n * Searches for a segment within `allOf`, `anyOf`, `oneOf` branches.\n * Returns the first matching sub-schema, or `undefined`.\n * For `allOf`, found results are merged into a single `allOf`.\n */\nfunction resolveInCombinators(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\t// allOf: the property can be defined in any branch, and all constraints\n\t// apply simultaneously.\n\tif (schema.allOf) {\n\t\tconst matches = schema.allOf\n\t\t\t.filter((b): b is JSONSchema7 => typeof b !== \"boolean\")\n\t\t\t.map((branch) => resolveSegment(branch, segment, root))\n\t\t\t.filter((s): s is JSONSchema7 => s !== undefined);\n\n\t\tif (matches.length === 1) return matches[0] as JSONSchema7;\n\t\tif (matches.length > 1) return { allOf: matches };\n\t}\n\n\t// anyOf / oneOf: the property can come from any branch.\n\tfor (const key of [\"anyOf\", \"oneOf\"] as const) {\n\t\tif (!schema[key]) continue;\n\t\tconst matches = schema[key]\n\t\t\t.filter((b): b is JSONSchema7 => typeof b !== \"boolean\")\n\t\t\t.map((branch) => resolveSegment(branch, segment, root))\n\t\t\t.filter((s): s is JSONSchema7 => s !== undefined);\n\n\t\tif (matches.length === 1) return matches[0] as JSONSchema7;\n\t\tif (matches.length > 1) return { [key]: matches };\n\t}\n\n\treturn undefined;\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Resolves a full path (e.g. [\"user\", \"address\", \"city\"]) within a JSON\n * Schema and returns the corresponding sub-schema.\n *\n * @param schema - The root schema describing the template context\n * @param path - Array of segments (property names)\n * @returns The sub-schema at the end of the path, or `undefined` if the path\n * cannot be resolved.\n *\n * @example\n * ```\n * const schema = {\n * type: \"object\",\n * properties: {\n * user: {\n * type: \"object\",\n * properties: {\n * name: { type: \"string\" }\n * }\n * }\n * }\n * };\n * resolveSchemaPath(schema, [\"user\", \"name\"]);\n * // → { type: \"string\" }\n * ```\n */\nexport function resolveSchemaPath(\n\tschema: JSONSchema7,\n\tpath: string[],\n): JSONSchema7 | undefined {\n\tif (path.length === 0) return resolveRef(schema, schema);\n\n\tlet current: JSONSchema7 = resolveRef(schema, schema);\n\tconst root = schema;\n\n\tfor (const segment of path) {\n\t\tconst next = resolveSegment(current, segment, root);\n\t\tif (next === undefined) return undefined;\n\t\tcurrent = next;\n\t}\n\n\treturn current;\n}\n\n/**\n * Resolves the item schema of an array.\n * If the schema is not of type `array` or has no `items`, returns `undefined`.\n *\n * @param schema - The array schema\n * @param root - The root schema (for resolving $refs)\n */\nexport function resolveArrayItems(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// Verify that it's actually an array\n\tconst schemaType = resolved.type;\n\tconst isArray =\n\t\tschemaType === \"array\" ||\n\t\t(Array.isArray(schemaType) && schemaType.includes(\"array\"));\n\n\tif (!isArray && resolved.items === undefined) {\n\t\treturn undefined;\n\t}\n\n\tif (resolved.items === undefined) {\n\t\t// array without items → element type is unknown\n\t\treturn {};\n\t}\n\n\t// items can be a boolean (true = anything, false = nothing)\n\tif (typeof resolved.items === \"boolean\") {\n\t\treturn {};\n\t}\n\n\t// items can be a single schema or a tuple (array of schemas).\n\t// For template loops, we handle the single-schema case.\n\tif (Array.isArray(resolved.items)) {\n\t\t// Tuple: create a oneOf of all possible types\n\t\tconst schemas = resolved.items\n\t\t\t.filter((item): item is JSONSchema7 => typeof item !== \"boolean\")\n\t\t\t.map((item) => resolveRef(item, root));\n\t\tif (schemas.length === 0) return {};\n\t\treturn { oneOf: schemas };\n\t}\n\n\treturn resolveRef(resolved.items, root);\n}\n\n/**\n * Simplifies an output schema to avoid unnecessarily complex constructs\n * (e.g. `oneOf` with a single element, duplicates, etc.).\n *\n * Uses `deepEqual` for deduplication — more robust and performant than\n * `JSON.stringify` (independent of key order, no intermediate string\n * allocations).\n */\nexport function simplifySchema(schema: JSONSchema7): JSONSchema7 {\n\t// oneOf / anyOf with a single element → unwrap\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = schema[key];\n\t\tif (arr && arr.length === 1) {\n\t\t\tconst first = arr[0];\n\t\t\tif (first !== undefined && typeof first !== \"boolean\")\n\t\t\t\treturn simplifySchema(first);\n\t\t}\n\t}\n\n\t// allOf with a single element → unwrap\n\tif (schema.allOf && schema.allOf.length === 1) {\n\t\tconst first = schema.allOf[0];\n\t\tif (first !== undefined && typeof first !== \"boolean\")\n\t\t\treturn simplifySchema(first);\n\t}\n\n\t// Deduplicate identical entries in oneOf/anyOf\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = schema[key];\n\t\tif (arr && arr.length > 1) {\n\t\t\tconst unique: JSONSchema7[] = [];\n\t\t\tfor (const entry of arr) {\n\t\t\t\tif (typeof entry === \"boolean\") continue;\n\t\t\t\t// Use deepEqual instead of JSON.stringify for structural\n\t\t\t\t// comparison — more robust (key order independent) and\n\t\t\t\t// more performant (no string allocations).\n\t\t\t\tconst isDuplicate = unique.some((existing) =>\n\t\t\t\t\tdeepEqual(existing, entry),\n\t\t\t\t);\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tunique.push(simplifySchema(entry));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (unique.length === 1) return unique[0] as JSONSchema7;\n\t\t\treturn { ...schema, [key]: unique };\n\t\t}\n\t}\n\n\treturn schema;\n}\n"],"names":["UnsupportedSchemaError","deepEqual","assertNoConditionalSchema","schema","path","visited","Set","has","add","if","undefined","then","else","properties","key","prop","Object","entries","additionalProperties","items","Array","isArray","i","length","item","keyword","branches","branch","not","defsKey","defs","name","def","resolveRef","root","$ref","ref","match","Error","definitions","$defs","resolveSegment","segment","resolved","schemaType","type","includes","combinatorResult","resolveInCombinators","allOf","matches","filter","b","map","s","resolveSchemaPath","current","next","resolveArrayItems","schemas","oneOf","simplifySchema","arr","first","unique","entry","isDuplicate","some","existing","push"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/schema-resolver.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport { UnsupportedSchemaError } from \"./errors.ts\";\nimport { deepEqual } from \"./utils.ts\";\n\n// ─── JSON Schema Resolver ────────────────────────────────────────────────────\n// Utility for navigating a JSON Schema Draft v7 by following a property path\n// (e.g. [\"user\", \"address\", \"city\"]).\n//\n// Handles:\n// - `$ref` resolution (internal references #/definitions/...)\n// - Navigation through `properties`\n// - Navigation through `items` (array elements)\n// - Combinators `allOf`, `anyOf`, `oneOf` (searches each branch)\n// - `additionalProperties` when the property is not explicitly declared\n//\n// Rejects:\n// - Conditional schemas (`if/then/else`) — non-resolvable without runtime data\n\n// ─── Conditional Schema Detection ────────────────────────────────────────────\n// JSON Schema Draft v7 introduced `if/then/else` conditional schemas.\n// These are fundamentally non-resolvable during static analysis because\n// they depend on runtime data values. Rather than silently ignoring them\n// (which would produce incorrect results — missing properties, wrong types),\n// we fail fast with a clear error pointing to the exact location in the schema.\n\n/**\n * Recursively validates that a JSON Schema does not contain `if/then/else`\n * conditional keywords. Throws an `UnsupportedSchemaError` if any are found.\n *\n * This check traverses the entire schema tree, including:\n * - `properties` values\n * - `additionalProperties` (when it's a schema)\n * - `items` (single schema or tuple)\n * - `allOf`, `anyOf`, `oneOf` branches\n * - `not`\n * - `definitions` / `$defs` values\n *\n * A `Set<object>` is used to track visited schemas and prevent infinite loops\n * from circular structures.\n *\n * @param schema - The JSON Schema to validate\n * @param path - The current JSON pointer path (for error reporting)\n * @param visited - Set of already-visited schema objects (cycle protection)\n *\n * @throws {UnsupportedSchemaError} if `if`, `then`, or `else` is found\n *\n * @example\n * ```\n * // Throws UnsupportedSchemaError:\n * assertNoConditionalSchema({\n * type: \"object\",\n * if: { properties: { kind: { const: \"a\" } } },\n * then: { properties: { a: { type: \"string\" } } },\n * });\n *\n * // OK — no conditional keywords:\n * assertNoConditionalSchema({\n * type: \"object\",\n * properties: { name: { type: \"string\" } },\n * });\n * ```\n */\nexport function assertNoConditionalSchema(\n\tschema: JSONSchema7,\n\tpath = \"\",\n\tvisited: Set<object> = new Set(),\n): void {\n\t// Cycle protection — avoid infinite loops on circular schema structures\n\tif (visited.has(schema)) return;\n\tvisited.add(schema);\n\n\t// ── Detect if/then/else at the current level ─────────────────────────\n\tif (schema.if !== undefined) {\n\t\tthrow new UnsupportedSchemaError(\"if/then/else\", path || \"/\");\n\t}\n\t// `then` or `else` without `if` is unusual but still unsupported\n\tif (schema.then !== undefined) {\n\t\tthrow new UnsupportedSchemaError(\"if/then/else\", path || \"/\");\n\t}\n\tif (schema.else !== undefined) {\n\t\tthrow new UnsupportedSchemaError(\"if/then/else\", path || \"/\");\n\t}\n\n\t// ── Recurse into properties ──────────────────────────────────────────\n\tif (schema.properties) {\n\t\tfor (const [key, prop] of Object.entries(schema.properties)) {\n\t\t\tif (prop && typeof prop !== \"boolean\") {\n\t\t\t\tassertNoConditionalSchema(prop, `${path}/properties/${key}`, visited);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into additionalProperties ────────────────────────────────\n\tif (\n\t\tschema.additionalProperties &&\n\t\ttypeof schema.additionalProperties === \"object\"\n\t) {\n\t\tassertNoConditionalSchema(\n\t\t\tschema.additionalProperties,\n\t\t\t`${path}/additionalProperties`,\n\t\t\tvisited,\n\t\t);\n\t}\n\n\t// ── Recurse into items ───────────────────────────────────────────────\n\tif (schema.items) {\n\t\tif (Array.isArray(schema.items)) {\n\t\t\tfor (let i = 0; i < schema.items.length; i++) {\n\t\t\t\tconst item = schema.items[i];\n\t\t\t\tif (item && typeof item !== \"boolean\") {\n\t\t\t\t\tassertNoConditionalSchema(item, `${path}/items/${i}`, visited);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof schema.items !== \"boolean\") {\n\t\t\tassertNoConditionalSchema(schema.items, `${path}/items`, visited);\n\t\t}\n\t}\n\n\t// ── Recurse into combinators ─────────────────────────────────────────\n\tfor (const keyword of [\"allOf\", \"anyOf\", \"oneOf\"] as const) {\n\t\tconst branches = schema[keyword];\n\t\tif (branches) {\n\t\t\tfor (let i = 0; i < branches.length; i++) {\n\t\t\t\tconst branch = branches[i];\n\t\t\t\tif (branch && typeof branch !== \"boolean\") {\n\t\t\t\t\tassertNoConditionalSchema(branch, `${path}/${keyword}/${i}`, visited);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into not ─────────────────────────────────────────────────\n\tif (schema.not && typeof schema.not !== \"boolean\") {\n\t\tassertNoConditionalSchema(schema.not, `${path}/not`, visited);\n\t}\n\n\t// ── Recurse into definitions / $defs ─────────────────────────────────\n\tfor (const defsKey of [\"definitions\", \"$defs\"] as const) {\n\t\tconst defs = schema[defsKey];\n\t\tif (defs) {\n\t\t\tfor (const [name, def] of Object.entries(defs)) {\n\t\t\t\tif (def && typeof def !== \"boolean\") {\n\t\t\t\t\tassertNoConditionalSchema(def, `${path}/${defsKey}/${name}`, visited);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ─── $ref Resolution ─────────────────────────────────────────────────────────\n// Only supports internal references in the format `#/definitions/Foo`\n// or `#/$defs/Foo` (JSON Schema Draft 2019+). Remote $refs (URLs) are\n// not supported — that is outside the scope of a template engine.\n\n/**\n * Recursively resolves `$ref` in a schema using the root schema as the\n * source of definitions.\n */\nexport function resolveRef(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 {\n\tif (!schema.$ref) return schema;\n\n\tconst ref = schema.$ref;\n\n\t// Expected format: #/definitions/Name or #/$defs/Name\n\tconst match = ref.match(/^#\\/(definitions|\\$defs)\\/(.+)$/);\n\tif (!match) {\n\t\tthrow new Error(\n\t\t\t`Unsupported $ref format: \"${ref}\". Only internal #/definitions/ references are supported.`,\n\t\t);\n\t}\n\n\tconst defsKey = match[1] as \"definitions\" | \"$defs\";\n\tconst name = match[2] ?? \"\";\n\n\tconst defs = defsKey === \"definitions\" ? root.definitions : root.$defs;\n\n\tif (!defs || !(name in defs)) {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve $ref \"${ref}\": definition \"${name}\" not found.`,\n\t\t);\n\t}\n\n\t// Recursive resolution in case the definition itself contains a $ref\n\tconst def = defs[name];\n\tif (!def || typeof def === \"boolean\") {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve $ref \"${ref}\": definition \"${name}\" not found.`,\n\t\t);\n\t}\n\treturn resolveRef(def, root);\n}\n\n// ─── Single-Segment Path Navigation ─────────────────────────────────────────\n\n/**\n * Resolves a single path segment (a property name) within a schema.\n * Returns the corresponding sub-schema, or `undefined` if the path is invalid.\n *\n * @param schema - The current schema (already resolved, no $ref)\n * @param segment - The property name to resolve\n * @param root - The root schema (for resolving any internal $refs)\n */\nfunction resolveSegment(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// 1. Explicit properties\n\tif (resolved.properties && segment in resolved.properties) {\n\t\tconst prop = resolved.properties[segment];\n\t\tif (prop && typeof prop !== \"boolean\") return resolveRef(prop, root);\n\t\tif (prop === true) return {};\n\t}\n\n\t// 2. additionalProperties (when the property is not declared)\n\tif (\n\t\tresolved.additionalProperties !== undefined &&\n\t\tresolved.additionalProperties !== false\n\t) {\n\t\tif (resolved.additionalProperties === true) {\n\t\t\t// additionalProperties: true → type is unknown\n\t\t\treturn {};\n\t\t}\n\t\treturn resolveRef(resolved.additionalProperties, root);\n\t}\n\n\t// 3. Intrinsic array properties (e.g. `.length`)\n\tconst schemaType = resolved.type;\n\tconst isArray =\n\t\tschemaType === \"array\" ||\n\t\t(Array.isArray(schemaType) && schemaType.includes(\"array\"));\n\n\tif (isArray && segment === \"length\") {\n\t\treturn { type: \"integer\" };\n\t}\n\n\t// 3b. Numeric index access on arrays (e.g. `users.[0]` → items schema)\n\tif (isArray && /^\\d+$/.test(segment)) {\n\t\tif (resolved.items === undefined) {\n\t\t\t// array without items → element type is unknown\n\t\t\treturn {};\n\t\t}\n\t\tif (typeof resolved.items === \"boolean\") {\n\t\t\treturn {};\n\t\t}\n\t\t// Tuple: items is an array of schemas — resolve by index if possible\n\t\tif (Array.isArray(resolved.items)) {\n\t\t\tconst idx = Number.parseInt(segment, 10);\n\t\t\tconst item = resolved.items[idx];\n\t\t\tif (item !== undefined && typeof item !== \"boolean\") {\n\t\t\t\treturn resolveRef(item, root);\n\t\t\t}\n\t\t\tif (item !== undefined && typeof item === \"boolean\") {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\t// Index out of bounds for tuple → check additionalItems (Draft 7)\n\t\t\t// additionalItems: false → no additional elements allowed\n\t\t\tif (resolved.additionalItems === false) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// additionalItems: schema → additional elements have this type\n\t\t\tif (\n\t\t\t\tresolved.additionalItems !== undefined &&\n\t\t\t\tresolved.additionalItems !== true &&\n\t\t\t\ttypeof resolved.additionalItems === \"object\"\n\t\t\t) {\n\t\t\t\treturn resolveRef(resolved.additionalItems, root);\n\t\t\t}\n\t\t\t// additionalItems absent or true → type is unknown\n\t\t\treturn {};\n\t\t}\n\t\t// Single items schema — all elements share the same type\n\t\treturn resolveRef(resolved.items, root);\n\t}\n\n\t// 4. Combinators — search within each branch\n\tconst combinatorResult = resolveInCombinators(resolved, segment, root);\n\tif (combinatorResult) return combinatorResult;\n\n\treturn undefined;\n}\n\n/**\n * Searches for a segment within `allOf`, `anyOf`, `oneOf` branches.\n * Returns the first matching sub-schema, or `undefined`.\n * For `allOf`, found results are merged into a single `allOf`.\n */\nfunction resolveInCombinators(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\t// allOf: the property can be defined in any branch, and all constraints\n\t// apply simultaneously.\n\tif (schema.allOf) {\n\t\tconst matches = schema.allOf\n\t\t\t.filter((b): b is JSONSchema7 => typeof b !== \"boolean\")\n\t\t\t.map((branch) => resolveSegment(branch, segment, root))\n\t\t\t.filter((s): s is JSONSchema7 => s !== undefined);\n\n\t\tif (matches.length === 1) return matches[0] as JSONSchema7;\n\t\tif (matches.length > 1) return { allOf: matches };\n\t}\n\n\t// anyOf / oneOf: the property can come from any branch.\n\tfor (const key of [\"anyOf\", \"oneOf\"] as const) {\n\t\tif (!schema[key]) continue;\n\t\tconst matches = schema[key]\n\t\t\t.filter((b): b is JSONSchema7 => typeof b !== \"boolean\")\n\t\t\t.map((branch) => resolveSegment(branch, segment, root))\n\t\t\t.filter((s): s is JSONSchema7 => s !== undefined);\n\n\t\tif (matches.length === 1) return matches[0] as JSONSchema7;\n\t\tif (matches.length > 1) return { [key]: matches };\n\t}\n\n\treturn undefined;\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Resolves a full path (e.g. [\"user\", \"address\", \"city\"]) within a JSON\n * Schema and returns the corresponding sub-schema.\n *\n * @param schema - The root schema describing the template context\n * @param path - Array of segments (property names)\n * @returns The sub-schema at the end of the path, or `undefined` if the path\n * cannot be resolved.\n *\n * @example\n * ```\n * const schema = {\n * type: \"object\",\n * properties: {\n * user: {\n * type: \"object\",\n * properties: {\n * name: { type: \"string\" }\n * }\n * }\n * }\n * };\n * resolveSchemaPath(schema, [\"user\", \"name\"]);\n * // → { type: \"string\" }\n * ```\n */\nexport function resolveSchemaPath(\n\tschema: JSONSchema7,\n\tpath: string[],\n): JSONSchema7 | undefined {\n\tif (path.length === 0) return resolveRef(schema, schema);\n\n\tlet current: JSONSchema7 = resolveRef(schema, schema);\n\tconst root = schema;\n\n\tfor (const segment of path) {\n\t\tconst next = resolveSegment(current, segment, root);\n\t\tif (next === undefined) return undefined;\n\t\tcurrent = next;\n\t}\n\n\treturn current;\n}\n\n/**\n * Resolves the item schema of an array.\n * If the schema is not of type `array` or has no `items`, returns `undefined`.\n *\n * @param schema - The array schema\n * @param root - The root schema (for resolving $refs)\n */\nexport function resolveArrayItems(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// Verify that it's actually an array\n\tconst schemaType = resolved.type;\n\tconst isArray =\n\t\tschemaType === \"array\" ||\n\t\t(Array.isArray(schemaType) && schemaType.includes(\"array\"));\n\n\tif (!isArray && resolved.items === undefined) {\n\t\treturn undefined;\n\t}\n\n\tif (resolved.items === undefined) {\n\t\t// array without items → element type is unknown\n\t\treturn {};\n\t}\n\n\t// items can be a boolean (true = anything, false = nothing)\n\tif (typeof resolved.items === \"boolean\") {\n\t\treturn {};\n\t}\n\n\t// items can be a single schema or a tuple (array of schemas).\n\t// For template loops, we handle the single-schema case.\n\tif (Array.isArray(resolved.items)) {\n\t\t// Tuple: create a oneOf of all possible types\n\t\tconst schemas = resolved.items\n\t\t\t.filter((item): item is JSONSchema7 => typeof item !== \"boolean\")\n\t\t\t.map((item) => resolveRef(item, root));\n\t\tif (schemas.length === 0) return {};\n\t\treturn { oneOf: schemas };\n\t}\n\n\treturn resolveRef(resolved.items, root);\n}\n\n/**\n * Simplifies an output schema to avoid unnecessarily complex constructs\n * (e.g. `oneOf` with a single element, duplicates, etc.).\n *\n * Uses `deepEqual` for deduplication — more robust and performant than\n * `JSON.stringify` (independent of key order, no intermediate string\n * allocations).\n */\nexport function simplifySchema(schema: JSONSchema7): JSONSchema7 {\n\t// oneOf / anyOf with a single element → unwrap\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = schema[key];\n\t\tif (arr && arr.length === 1) {\n\t\t\tconst first = arr[0];\n\t\t\tif (first !== undefined && typeof first !== \"boolean\")\n\t\t\t\treturn simplifySchema(first);\n\t\t}\n\t}\n\n\t// allOf with a single element → unwrap\n\tif (schema.allOf && schema.allOf.length === 1) {\n\t\tconst first = schema.allOf[0];\n\t\tif (first !== undefined && typeof first !== \"boolean\")\n\t\t\treturn simplifySchema(first);\n\t}\n\n\t// Deduplicate identical entries in oneOf/anyOf\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = schema[key];\n\t\tif (arr && arr.length > 1) {\n\t\t\tconst unique: JSONSchema7[] = [];\n\t\t\tfor (const entry of arr) {\n\t\t\t\tif (typeof entry === \"boolean\") continue;\n\t\t\t\t// Use deepEqual instead of JSON.stringify for structural\n\t\t\t\t// comparison — more robust (key order independent) and\n\t\t\t\t// more performant (no string allocations).\n\t\t\t\tconst isDuplicate = unique.some((existing) =>\n\t\t\t\t\tdeepEqual(existing, entry),\n\t\t\t\t);\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tunique.push(simplifySchema(entry));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (unique.length === 1) return unique[0] as JSONSchema7;\n\t\t\treturn { ...schema, [key]: unique };\n\t\t}\n\t}\n\n\treturn schema;\n}\n"],"names":["UnsupportedSchemaError","deepEqual","assertNoConditionalSchema","schema","path","visited","Set","has","add","if","undefined","then","else","properties","key","prop","Object","entries","additionalProperties","items","Array","isArray","i","length","item","keyword","branches","branch","not","defsKey","defs","name","def","resolveRef","root","$ref","ref","match","Error","definitions","$defs","resolveSegment","segment","resolved","schemaType","type","includes","test","idx","Number","parseInt","additionalItems","combinatorResult","resolveInCombinators","allOf","matches","filter","b","map","s","resolveSchemaPath","current","next","resolveArrayItems","schemas","oneOf","simplifySchema","arr","first","unique","entry","isDuplicate","some","existing","push"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import Handlebars from"handlebars";import{analyzeFromAst}from"./analyzer.js";import{CompiledTemplate}from"./compiled-template.js";import{dispatchAnalyze,dispatchAnalyzeAndExecute,dispatchExecute}from"./dispatch.js";import{TemplateAnalysisError}from"./errors.js";import{executeFromAst}from"./executor.js";import{LogicalHelpers,MathHelpers}from"./helpers/index.js";import{parse}from"./parser.js";import{isArrayInput,isLiteralInput,isObjectInput}from"./types.js";import{LRUCache}from"./utils.js";export class Typebars{compile(template){if(isArrayInput(template)){const children=[];for(const element of template){children.push(this.compile(element))}return CompiledTemplate.fromArray(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if(isObjectInput(template)){const children={};for(const[key,value]of Object.entries(template)){children[key]=this.compile(value)}return CompiledTemplate.fromObject(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if(isLiteralInput(template)){return CompiledTemplate.fromLiteral(template,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}const ast=this.getCachedAst(template);const options={helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache};return CompiledTemplate.fromTemplate(ast,template,options)}analyze(template,inputSchema={},options){return dispatchAnalyze(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);return analyzeFromAst(ast,tpl,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers,coerceSchema})},(child,childOptions)=>this.analyze(child,inputSchema,childOptions))}validate(template,inputSchema={},options){const analysis=this.analyze(template,inputSchema,options);return{valid:analysis.valid,diagnostics:analysis.diagnostics}}isValidSyntax(template){if(isArrayInput(template)){return template.every(v=>this.isValidSyntax(v))}if(isObjectInput(template)){return Object.values(template).every(v=>this.isValidSyntax(v))}if(isLiteralInput(template))return true;try{this.getCachedAst(template);return true}catch{return false}}execute(template,data,options){return dispatchExecute(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);if(options?.schema){const analysis=analyzeFromAst(ast,tpl,options.schema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers});if(!analysis.valid){throw new TemplateAnalysisError(analysis.diagnostics)}}return executeFromAst(ast,tpl,data,{identifierData:options?.identifierData,hbs:this.hbs,compilationCache:this.compilationCache,coerceSchema})},(child,childOptions)=>this.execute(child,data,{...options,...childOptions}))}analyzeAndExecute(template,inputSchema={},data,options){return dispatchAnalyzeAndExecute(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);const analysis=analyzeFromAst(ast,tpl,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers,coerceSchema});if(!analysis.valid){return{analysis,value:undefined}}const value=executeFromAst(ast,tpl,data,{identifierData:options?.identifierData,hbs:this.hbs,compilationCache:this.compilationCache,coerceSchema});return{analysis,value}},(child,childOptions)=>this.analyzeAndExecute(child,inputSchema,data,childOptions))}registerHelper(name,definition){this.helpers.set(name,definition);this.hbs.registerHelper(name,definition.fn);this.compilationCache.clear();return this}unregisterHelper(name){this.helpers.delete(name);this.hbs.unregisterHelper(name);this.compilationCache.clear();return this}hasHelper(name){return this.helpers.has(name)}clearCaches(){this.astCache.clear();this.compilationCache.clear()}getCachedAst(template){let ast=this.astCache.get(template);if(!ast){ast=parse(template);this.astCache.set(template,ast)}return ast}constructor(options={}){_define_property(this,"hbs",void 0);_define_property(this,"astCache",void 0);_define_property(this,"compilationCache",void 0);_define_property(this,"helpers",new Map);this.hbs=Handlebars.create();this.astCache=new LRUCache(options.astCacheSize??256);this.compilationCache=new LRUCache(options.compilationCacheSize??256);new MathHelpers().register(this);new LogicalHelpers().register(this);if(options.helpers){for(const helper of options.helpers){const{name,...definition}=helper;this.registerHelper(name,definition)}}}}
1
+ function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import Handlebars from"handlebars";import{analyzeFromAst}from"./analyzer.js";import{CompiledTemplate}from"./compiled-template.js";import{dispatchAnalyze,dispatchAnalyzeAndExecute,dispatchExecute}from"./dispatch.js";import{TemplateAnalysisError}from"./errors.js";import{executeFromAst}from"./executor.js";import{CollectionHelpers,LogicalHelpers,MathHelpers}from"./helpers/index.js";import{parse}from"./parser.js";import{isArrayInput,isLiteralInput,isObjectInput}from"./types.js";import{LRUCache}from"./utils.js";const DIRECT_EXECUTION_HELPER_NAMES=new Set([CollectionHelpers.COLLECT_HELPER_NAME]);function stringifyForTemplate(value){if(value===null||value===undefined)return"";if(Array.isArray(value)){return value.map(item=>{if(item===null||item===undefined)return"";if(typeof item==="object")return JSON.stringify(item);return String(item)}).join(", ")}return String(value)}export class Typebars{compile(template){if(isArrayInput(template)){const children=[];for(const element of template){children.push(this.compile(element))}return CompiledTemplate.fromArray(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if(isObjectInput(template)){const children={};for(const[key,value]of Object.entries(template)){children[key]=this.compile(value)}return CompiledTemplate.fromObject(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if(isLiteralInput(template)){return CompiledTemplate.fromLiteral(template,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}const ast=this.getCachedAst(template);const options={helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache};return CompiledTemplate.fromTemplate(ast,template,options)}analyze(template,inputSchema={},options){return dispatchAnalyze(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);return analyzeFromAst(ast,tpl,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers,coerceSchema})},(child,childOptions)=>this.analyze(child,inputSchema,childOptions))}validate(template,inputSchema={},options){const analysis=this.analyze(template,inputSchema,options);return{valid:analysis.valid,diagnostics:analysis.diagnostics}}isValidSyntax(template){if(isArrayInput(template)){return template.every(v=>this.isValidSyntax(v))}if(isObjectInput(template)){return Object.values(template).every(v=>this.isValidSyntax(v))}if(isLiteralInput(template))return true;try{this.getCachedAst(template);return true}catch{return false}}execute(template,data,options){return dispatchExecute(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);if(options?.schema){const analysis=analyzeFromAst(ast,tpl,options.schema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers});if(!analysis.valid){throw new TemplateAnalysisError(analysis.diagnostics)}}return executeFromAst(ast,tpl,data,{identifierData:options?.identifierData,hbs:this.hbs,compilationCache:this.compilationCache,coerceSchema,helpers:this.helpers})},(child,childOptions)=>this.execute(child,data,{...options,...childOptions}))}analyzeAndExecute(template,inputSchema={},data,options){return dispatchAnalyzeAndExecute(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);const analysis=analyzeFromAst(ast,tpl,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers,coerceSchema});if(!analysis.valid){return{analysis,value:undefined}}const value=executeFromAst(ast,tpl,data,{identifierData:options?.identifierData,hbs:this.hbs,compilationCache:this.compilationCache,coerceSchema,helpers:this.helpers});return{analysis,value}},(child,childOptions)=>this.analyzeAndExecute(child,inputSchema,data,childOptions))}registerHelper(name,definition){this.helpers.set(name,definition);if(DIRECT_EXECUTION_HELPER_NAMES.has(name)){this.hbs.registerHelper(name,(...args)=>{const hbsArgs=args.slice(0,-1);const raw=definition.fn(...hbsArgs);return stringifyForTemplate(raw)})}else{this.hbs.registerHelper(name,definition.fn)}this.compilationCache.clear();return this}unregisterHelper(name){this.helpers.delete(name);this.hbs.unregisterHelper(name);this.compilationCache.clear();return this}hasHelper(name){return this.helpers.has(name)}clearCaches(){this.astCache.clear();this.compilationCache.clear()}getCachedAst(template){let ast=this.astCache.get(template);if(!ast){ast=parse(template);this.astCache.set(template,ast)}return ast}constructor(options={}){_define_property(this,"hbs",void 0);_define_property(this,"astCache",void 0);_define_property(this,"compilationCache",void 0);_define_property(this,"helpers",new Map);this.hbs=Handlebars.create();this.astCache=new LRUCache(options.astCacheSize??256);this.compilationCache=new LRUCache(options.compilationCacheSize??256);new MathHelpers().register(this);new LogicalHelpers().register(this);new CollectionHelpers().register(this);if(options.helpers){for(const helper of options.helpers){const{name,...definition}=helper;this.registerHelper(name,definition)}}}}
2
2
  //# sourceMappingURL=typebars.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/typebars.ts"],"sourcesContent":["import Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { AnalyzeOptions } from \"./analyzer.ts\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport {\n\tCompiledTemplate,\n\ttype CompiledTemplateOptions,\n} from \"./compiled-template.ts\";\nimport {\n\tdispatchAnalyze,\n\tdispatchAnalyzeAndExecute,\n\tdispatchExecute,\n} from \"./dispatch.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { executeFromAst } from \"./executor.ts\";\nimport { LogicalHelpers, MathHelpers } from \"./helpers/index.ts\";\nimport { parse } from \"./parser.ts\";\nimport type {\n\tAnalysisResult,\n\tAnalyzeAndExecuteOptions,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateData,\n\tTemplateEngineOptions,\n\tTemplateInput,\n\tValidationResult,\n} from \"./types.ts\";\nimport { isArrayInput, isLiteralInput, isObjectInput } from \"./types.ts\";\nimport { LRUCache } from \"./utils\";\n\n// ─── Typebars ────────────────────────────────────────────────────────────────\n// Public entry point of the template engine. Orchestrates three phases:\n//\n// 1. **Parsing** — transforms the template string into an AST (via Handlebars)\n// 2. **Analysis** — static validation + return type inference\n// 3. **Execution** — renders the template with real data\n//\n// ─── Architecture v2 ─────────────────────────────────────────────────────────\n// - **LRU cache** for parsed ASTs and compiled Handlebars templates\n// - **Isolated Handlebars environment** per instance (custom helpers)\n// - **`compile()` pattern**: parse-once / execute-many\n// - **`validate()` method**: API shortcut without `outputSchema`\n// - **`registerHelper()`**: custom helpers with static typing\n// - **`ExecuteOptions`**: options object for `execute()`\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// The `{{key:N}}` syntax allows referencing variables from specific data\n// sources, identified by an integer N.\n//\n// - `identifierSchemas`: mapping `{ [id]: JSONSchema7 }` for static analysis\n// - `identifierData`: mapping `{ [id]: Record<string, unknown> }` for execution\n//\n// Usage:\n// engine.execute(\"{{meetingId:1}}\", data, { identifierData: { 1: node1Data } });\n// engine.analyze(\"{{meetingId:1}}\", schema, { identifierSchemas: { 1: node1Schema } });\n\n// ─── Main Class ──────────────────────────────────────────────────────────────\n\nexport class Typebars {\n\t/** Isolated Handlebars environment — each engine has its own helpers */\n\tprivate readonly hbs: typeof Handlebars;\n\n\t/** LRU cache of parsed ASTs (avoids re-parsing) */\n\tprivate readonly astCache: LRUCache<string, hbs.AST.Program>;\n\n\t/** LRU cache of compiled Handlebars templates (avoids recompilation) */\n\tprivate readonly compilationCache: LRUCache<\n\t\tstring,\n\t\tHandlebarsTemplateDelegate\n\t>;\n\n\t/** Custom helpers registered on this instance */\n\tprivate readonly helpers = new Map<string, HelperDefinition>();\n\n\tconstructor(options: TemplateEngineOptions = {}) {\n\t\tthis.hbs = Handlebars.create();\n\t\tthis.astCache = new LRUCache(options.astCacheSize ?? 256);\n\t\tthis.compilationCache = new LRUCache(options.compilationCacheSize ?? 256);\n\n\t\t// ── Built-in helpers ─────────────────────────────────────────────\n\t\tnew MathHelpers().register(this);\n\t\tnew LogicalHelpers().register(this);\n\n\t\t// ── Custom helpers via options ───────────────────────────────────\n\t\tif (options.helpers) {\n\t\t\tfor (const helper of options.helpers) {\n\t\t\t\tconst { name, ...definition } = helper;\n\t\t\t\tthis.registerHelper(name, definition);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Compilation ───────────────────────────────────────────────────────\n\n\t/**\n\t * Compiles a template and returns a `CompiledTemplate` ready to be\n\t * executed or analyzed without re-parsing.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is compiled recursively.\n\t *\n\t * @param template - The template to compile\n\t * @returns A reusable `CompiledTemplate`\n\t */\n\tcompile(template: TemplateInput): CompiledTemplate {\n\t\tif (isArrayInput(template)) {\n\t\t\tconst children: CompiledTemplate[] = [];\n\t\t\tfor (const element of template) {\n\t\t\t\tchildren.push(this.compile(element));\n\t\t\t}\n\t\t\treturn CompiledTemplate.fromArray(children, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tif (isObjectInput(template)) {\n\t\t\tconst children: Record<string, CompiledTemplate> = {};\n\t\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\t\tchildren[key] = this.compile(value);\n\t\t\t}\n\t\t\treturn CompiledTemplate.fromObject(children, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn CompiledTemplate.fromLiteral(template, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tconst ast = this.getCachedAst(template);\n\t\tconst options: CompiledTemplateOptions = {\n\t\t\thelpers: this.helpers,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t};\n\t\treturn CompiledTemplate.fromTemplate(ast, template, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes a template against a JSON Schema v7 describing\n\t * the available context.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is analyzed recursively and the\n\t * `outputSchema` reflects the object structure with resolved types.\n\t *\n\t * @param template - The template to analyze\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tanalyze(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): AnalysisResult {\n\t\treturn dispatchAnalyze(\n\t\t\ttemplate,\n\t\t\toptions,\n\t\t\t// String handler — parse with cache and analyze the AST\n\t\t\t(tpl, coerceSchema) => {\n\t\t\t\tconst ast = this.getCachedAst(tpl);\n\t\t\t\treturn analyzeFromAst(ast, tpl, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t});\n\t\t\t},\n\t\t\t// Recursive handler — re-enter analyze() for child elements\n\t\t\t(child, childOptions) => this.analyze(child, inputSchema, childOptions),\n\t\t);\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────────\n\n\t/**\n\t * Validates a template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param template - The template to validate\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param identifierSchemas - (optional) Schemas by identifier\n\t */\n\tvalidate(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(template, inputSchema, options);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Syntax Validation ───────────────────────────────────────────────────\n\n\t/**\n\t * Checks only that the template syntax is valid (parsing).\n\t * Does not require a schema — useful for quick feedback in an editor.\n\t *\n\t * For objects, recursively checks each property.\n\t *\n\t * @param template - The template to validate\n\t * @returns `true` if the template is syntactically correct\n\t */\n\tisValidSyntax(template: TemplateInput): boolean {\n\t\tif (isArrayInput(template)) {\n\t\t\treturn template.every((v) => this.isValidSyntax(v));\n\t\t}\n\t\tif (isObjectInput(template)) {\n\t\t\treturn Object.values(template).every((v) => this.isValidSyntax(v));\n\t\t}\n\t\tif (isLiteralInput(template)) return true;\n\t\ttry {\n\t\t\tthis.getCachedAst(template);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// ─── Execution ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Executes a template with the provided data.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is executed recursively and an object with\n\t * resolved values is returned.\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param template - The template to execute\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, identifierSchemas)\n\t * @returns The execution result\n\t */\n\texecute(\n\t\ttemplate: TemplateInput,\n\t\tdata?: TemplateData,\n\t\toptions?: ExecuteOptions,\n\t): unknown {\n\t\treturn dispatchExecute(\n\t\t\ttemplate,\n\t\t\toptions,\n\t\t\t// String handler — parse, optionally validate, then execute\n\t\t\t(tpl, coerceSchema) => {\n\t\t\t\tconst ast = this.getCachedAst(tpl);\n\n\t\t\t\t// Pre-execution static validation if a schema is provided\n\t\t\t\tif (options?.schema) {\n\t\t\t\t\tconst analysis = analyzeFromAst(ast, tpl, options.schema, {\n\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t\t});\n\t\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn executeFromAst(ast, tpl, data, {\n\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\thbs: this.hbs,\n\t\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t});\n\t\t\t},\n\t\t\t// Recursive handler — re-enter execute() for child elements\n\t\t\t(child, childOptions) =>\n\t\t\t\tthis.execute(child, data, { ...options, ...childOptions }),\n\t\t);\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────────\n\n\t/**\n\t * Analyzes a template and, if valid, executes it with the provided data.\n\t * Returns both the analysis result and the executed value.\n\t *\n\t * For objects, each property is analyzed and executed recursively.\n\t * The entire object is considered invalid if at least one property is.\n\t *\n\t * @param template - The template\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - (optional) Options for template identifiers\n\t * @returns An object `{ analysis, value }` where `value` is `undefined`\n\t * if analysis failed.\n\t */\n\tanalyzeAndExecute(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7 = {},\n\t\tdata: TemplateData,\n\t\toptions?: AnalyzeAndExecuteOptions & { coerceSchema?: JSONSchema7 },\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\treturn dispatchAnalyzeAndExecute(\n\t\t\ttemplate,\n\t\t\toptions,\n\t\t\t// String handler — analyze then execute if valid\n\t\t\t(tpl, coerceSchema) => {\n\t\t\t\tconst ast = this.getCachedAst(tpl);\n\t\t\t\tconst analysis = analyzeFromAst(ast, tpl, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t});\n\n\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\treturn { analysis, value: undefined };\n\t\t\t\t}\n\n\t\t\t\tconst value = executeFromAst(ast, tpl, data, {\n\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\thbs: this.hbs,\n\t\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t});\n\t\t\t\treturn { analysis, value };\n\t\t\t},\n\t\t\t// Recursive handler — re-enter analyzeAndExecute() for child elements\n\t\t\t(child, childOptions) =>\n\t\t\t\tthis.analyzeAndExecute(child, inputSchema, data, childOptions),\n\t\t);\n\t}\n\n\t// ─── Custom Helper Management ──────────────────────────────────────────\n\n\t/**\n\t * Registers a custom helper on this engine instance.\n\t *\n\t * The helper is available for both execution (via Handlebars) and\n\t * static analysis (via its declared `returnType`).\n\t *\n\t * @param name - Helper name (e.g. `\"uppercase\"`)\n\t * @param definition - Helper definition (implementation + return type)\n\t * @returns `this` to allow chaining\n\t */\n\tregisterHelper(name: string, definition: HelperDefinition): this {\n\t\tthis.helpers.set(name, definition);\n\t\tthis.hbs.registerHelper(name, definition.fn);\n\n\t\t// Invalidate the compilation cache because helpers have changed\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a custom helper from this engine instance.\n\t *\n\t * @param name - Name of the helper to remove\n\t * @returns `this` to allow chaining\n\t */\n\tunregisterHelper(name: string): this {\n\t\tthis.helpers.delete(name);\n\t\tthis.hbs.unregisterHelper(name);\n\n\t\t// Invalidate the compilation cache\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Checks whether a helper is registered on this instance.\n\t *\n\t * @param name - Helper name\n\t * @returns `true` if the helper is registered\n\t */\n\thasHelper(name: string): boolean {\n\t\treturn this.helpers.has(name);\n\t}\n\n\t// ─── Cache Management ──────────────────────────────────────────────────\n\n\t/**\n\t * Clears all internal caches (AST + compilation).\n\t *\n\t * Useful after a configuration change or to free memory.\n\t */\n\tclearCaches(): void {\n\t\tthis.astCache.clear();\n\t\tthis.compilationCache.clear();\n\t}\n\n\t// ─── Internals ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Retrieves the AST of a template from the cache, or parses and caches it.\n\t */\n\tprivate getCachedAst(template: string): hbs.AST.Program {\n\t\tlet ast = this.astCache.get(template);\n\t\tif (!ast) {\n\t\t\tast = parse(template);\n\t\t\tthis.astCache.set(template, ast);\n\t\t}\n\t\treturn ast;\n\t}\n}\n"],"names":["Handlebars","analyzeFromAst","CompiledTemplate","dispatchAnalyze","dispatchAnalyzeAndExecute","dispatchExecute","TemplateAnalysisError","executeFromAst","LogicalHelpers","MathHelpers","parse","isArrayInput","isLiteralInput","isObjectInput","LRUCache","Typebars","compile","template","children","element","push","fromArray","helpers","hbs","compilationCache","key","value","Object","entries","fromObject","fromLiteral","ast","getCachedAst","options","fromTemplate","analyze","inputSchema","tpl","coerceSchema","identifierSchemas","child","childOptions","validate","analysis","valid","diagnostics","isValidSyntax","every","v","values","execute","data","schema","identifierData","analyzeAndExecute","undefined","registerHelper","name","definition","set","fn","clear","unregisterHelper","delete","hasHelper","has","clearCaches","astCache","get","Map","create","astCacheSize","compilationCacheSize","register","helper"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/typebars.ts"],"sourcesContent":["import Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { AnalyzeOptions } from \"./analyzer.ts\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport {\n\tCompiledTemplate,\n\ttype CompiledTemplateOptions,\n} from \"./compiled-template.ts\";\nimport {\n\tdispatchAnalyze,\n\tdispatchAnalyzeAndExecute,\n\tdispatchExecute,\n} from \"./dispatch.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { executeFromAst } from \"./executor.ts\";\nimport {\n\tCollectionHelpers,\n\tLogicalHelpers,\n\tMathHelpers,\n} from \"./helpers/index.ts\";\nimport { parse } from \"./parser.ts\";\nimport type {\n\tAnalysisResult,\n\tAnalyzeAndExecuteOptions,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateData,\n\tTemplateEngineOptions,\n\tTemplateInput,\n\tValidationResult,\n} from \"./types.ts\";\nimport { isArrayInput, isLiteralInput, isObjectInput } from \"./types.ts\";\nimport { LRUCache } from \"./utils\";\n\n// ─── Typebars ────────────────────────────────────────────────────────────────\n// Public entry point of the template engine. Orchestrates three phases:\n//\n// 1. **Parsing** — transforms the template string into an AST (via Handlebars)\n// 2. **Analysis** — static validation + return type inference\n// 3. **Execution** — renders the template with real data\n//\n// ─── Architecture v2 ─────────────────────────────────────────────────────────\n// - **LRU cache** for parsed ASTs and compiled Handlebars templates\n// - **Isolated Handlebars environment** per instance (custom helpers)\n// - **`compile()` pattern**: parse-once / execute-many\n// - **`validate()` method**: API shortcut without `outputSchema`\n// - **`registerHelper()`**: custom helpers with static typing\n// - **`ExecuteOptions`**: options object for `execute()`\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// The `{{key:N}}` syntax allows referencing variables from specific data\n// sources, identified by an integer N.\n//\n// - `identifierSchemas`: mapping `{ [id]: JSONSchema7 }` for static analysis\n// - `identifierData`: mapping `{ [id]: Record<string, unknown> }` for execution\n//\n// Usage:\n// engine.execute(\"{{meetingId:1}}\", data, { identifierData: { 1: node1Data } });\n// engine.analyze(\"{{meetingId:1}}\", schema, { identifierSchemas: { 1: node1Schema } });\n\n// ─── Direct Execution Helper Names ───────────────────────────────────────────\n// Helpers whose return values are non-primitive (arrays, objects) and must be\n// wrapped when registered with Handlebars so that mixed/block templates get a\n// human-readable string (e.g. `\", \"` joined) instead of JS default toString().\n// In single-expression mode the executor bypasses Handlebars entirely, so the\n// raw value is preserved.\nconst DIRECT_EXECUTION_HELPER_NAMES = new Set<string>([\n\tCollectionHelpers.COLLECT_HELPER_NAME,\n]);\n\n/**\n * Converts a value to a string suitable for embedding in a Handlebars template.\n *\n * - Arrays of primitives are joined with `\", \"`\n * - Arrays of objects are JSON-stringified per element, then joined\n * - Primitives use `String(value)`\n * - null/undefined become `\"\"`\n */\nfunction stringifyForTemplate(value: unknown): string {\n\tif (value === null || value === undefined) return \"\";\n\tif (Array.isArray(value)) {\n\t\treturn value\n\t\t\t.map((item) => {\n\t\t\t\tif (item === null || item === undefined) return \"\";\n\t\t\t\tif (typeof item === \"object\") return JSON.stringify(item);\n\t\t\t\treturn String(item);\n\t\t\t})\n\t\t\t.join(\", \");\n\t}\n\treturn String(value);\n}\n\n// ─── Main Class ──────────────────────────────────────────────────────────────\n\nexport class Typebars {\n\t/** Isolated Handlebars environment — each engine has its own helpers */\n\tprivate readonly hbs: typeof Handlebars;\n\n\t/** LRU cache of parsed ASTs (avoids re-parsing) */\n\tprivate readonly astCache: LRUCache<string, hbs.AST.Program>;\n\n\t/** LRU cache of compiled Handlebars templates (avoids recompilation) */\n\tprivate readonly compilationCache: LRUCache<\n\t\tstring,\n\t\tHandlebarsTemplateDelegate\n\t>;\n\n\t/** Custom helpers registered on this instance */\n\tprivate readonly helpers = new Map<string, HelperDefinition>();\n\n\tconstructor(options: TemplateEngineOptions = {}) {\n\t\tthis.hbs = Handlebars.create();\n\t\tthis.astCache = new LRUCache(options.astCacheSize ?? 256);\n\t\tthis.compilationCache = new LRUCache(options.compilationCacheSize ?? 256);\n\n\t\t// ── Built-in helpers ─────────────────────────────────────────────\n\t\tnew MathHelpers().register(this);\n\t\tnew LogicalHelpers().register(this);\n\t\tnew CollectionHelpers().register(this);\n\n\t\t// ── Custom helpers via options ───────────────────────────────────\n\t\tif (options.helpers) {\n\t\t\tfor (const helper of options.helpers) {\n\t\t\t\tconst { name, ...definition } = helper;\n\t\t\t\tthis.registerHelper(name, definition);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Compilation ───────────────────────────────────────────────────────\n\n\t/**\n\t * Compiles a template and returns a `CompiledTemplate` ready to be\n\t * executed or analyzed without re-parsing.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is compiled recursively.\n\t *\n\t * @param template - The template to compile\n\t * @returns A reusable `CompiledTemplate`\n\t */\n\tcompile(template: TemplateInput): CompiledTemplate {\n\t\tif (isArrayInput(template)) {\n\t\t\tconst children: CompiledTemplate[] = [];\n\t\t\tfor (const element of template) {\n\t\t\t\tchildren.push(this.compile(element));\n\t\t\t}\n\t\t\treturn CompiledTemplate.fromArray(children, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tif (isObjectInput(template)) {\n\t\t\tconst children: Record<string, CompiledTemplate> = {};\n\t\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\t\tchildren[key] = this.compile(value);\n\t\t\t}\n\t\t\treturn CompiledTemplate.fromObject(children, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn CompiledTemplate.fromLiteral(template, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tconst ast = this.getCachedAst(template);\n\t\tconst options: CompiledTemplateOptions = {\n\t\t\thelpers: this.helpers,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t};\n\t\treturn CompiledTemplate.fromTemplate(ast, template, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes a template against a JSON Schema v7 describing\n\t * the available context.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is analyzed recursively and the\n\t * `outputSchema` reflects the object structure with resolved types.\n\t *\n\t * @param template - The template to analyze\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tanalyze(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): AnalysisResult {\n\t\treturn dispatchAnalyze(\n\t\t\ttemplate,\n\t\t\toptions,\n\t\t\t// String handler — parse with cache and analyze the AST\n\t\t\t(tpl, coerceSchema) => {\n\t\t\t\tconst ast = this.getCachedAst(tpl);\n\t\t\t\treturn analyzeFromAst(ast, tpl, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t});\n\t\t\t},\n\t\t\t// Recursive handler — re-enter analyze() for child elements\n\t\t\t(child, childOptions) => this.analyze(child, inputSchema, childOptions),\n\t\t);\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────────\n\n\t/**\n\t * Validates a template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param template - The template to validate\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param identifierSchemas - (optional) Schemas by identifier\n\t */\n\tvalidate(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(template, inputSchema, options);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Syntax Validation ───────────────────────────────────────────────────\n\n\t/**\n\t * Checks only that the template syntax is valid (parsing).\n\t * Does not require a schema — useful for quick feedback in an editor.\n\t *\n\t * For objects, recursively checks each property.\n\t *\n\t * @param template - The template to validate\n\t * @returns `true` if the template is syntactically correct\n\t */\n\tisValidSyntax(template: TemplateInput): boolean {\n\t\tif (isArrayInput(template)) {\n\t\t\treturn template.every((v) => this.isValidSyntax(v));\n\t\t}\n\t\tif (isObjectInput(template)) {\n\t\t\treturn Object.values(template).every((v) => this.isValidSyntax(v));\n\t\t}\n\t\tif (isLiteralInput(template)) return true;\n\t\ttry {\n\t\t\tthis.getCachedAst(template);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// ─── Execution ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Executes a template with the provided data.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is executed recursively and an object with\n\t * resolved values is returned.\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param template - The template to execute\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, identifierSchemas)\n\t * @returns The execution result\n\t */\n\texecute(\n\t\ttemplate: TemplateInput,\n\t\tdata?: TemplateData,\n\t\toptions?: ExecuteOptions,\n\t): unknown {\n\t\treturn dispatchExecute(\n\t\t\ttemplate,\n\t\t\toptions,\n\t\t\t// String handler — parse, optionally validate, then execute\n\t\t\t(tpl, coerceSchema) => {\n\t\t\t\tconst ast = this.getCachedAst(tpl);\n\n\t\t\t\t// Pre-execution static validation if a schema is provided\n\t\t\t\tif (options?.schema) {\n\t\t\t\t\tconst analysis = analyzeFromAst(ast, tpl, options.schema, {\n\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t\t});\n\t\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn executeFromAst(ast, tpl, data, {\n\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\thbs: this.hbs,\n\t\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t});\n\t\t\t},\n\t\t\t// Recursive handler — re-enter execute() for child elements\n\t\t\t(child, childOptions) =>\n\t\t\t\tthis.execute(child, data, { ...options, ...childOptions }),\n\t\t);\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────────\n\n\t/**\n\t * Analyzes a template and, if valid, executes it with the provided data.\n\t * Returns both the analysis result and the executed value.\n\t *\n\t * For objects, each property is analyzed and executed recursively.\n\t * The entire object is considered invalid if at least one property is.\n\t *\n\t * @param template - The template\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - (optional) Options for template identifiers\n\t * @returns An object `{ analysis, value }` where `value` is `undefined`\n\t * if analysis failed.\n\t */\n\tanalyzeAndExecute(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7 = {},\n\t\tdata: TemplateData,\n\t\toptions?: AnalyzeAndExecuteOptions & { coerceSchema?: JSONSchema7 },\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\treturn dispatchAnalyzeAndExecute(\n\t\t\ttemplate,\n\t\t\toptions,\n\t\t\t// String handler — analyze then execute if valid\n\t\t\t(tpl, coerceSchema) => {\n\t\t\t\tconst ast = this.getCachedAst(tpl);\n\t\t\t\tconst analysis = analyzeFromAst(ast, tpl, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t});\n\n\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\treturn { analysis, value: undefined };\n\t\t\t\t}\n\n\t\t\t\tconst value = executeFromAst(ast, tpl, data, {\n\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\thbs: this.hbs,\n\t\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t\t\tcoerceSchema,\n\t\t\t\t\thelpers: this.helpers,\n\t\t\t\t});\n\t\t\t\treturn { analysis, value };\n\t\t\t},\n\t\t\t// Recursive handler — re-enter analyzeAndExecute() for child elements\n\t\t\t(child, childOptions) =>\n\t\t\t\tthis.analyzeAndExecute(child, inputSchema, data, childOptions),\n\t\t);\n\t}\n\n\t// ─── Custom Helper Management ──────────────────────────────────────────\n\n\t/**\n\t * Registers a custom helper on this engine instance.\n\t *\n\t * The helper is available for both execution (via Handlebars) and\n\t * static analysis (via its declared `returnType`).\n\t *\n\t * @param name - Helper name (e.g. `\"uppercase\"`)\n\t * @param definition - Helper definition (implementation + return type)\n\t * @returns `this` to allow chaining\n\t */\n\tregisterHelper(name: string, definition: HelperDefinition): this {\n\t\tthis.helpers.set(name, definition);\n\n\t\t// For helpers that return non-primitive values (arrays, objects),\n\t\t// register a Handlebars-friendly wrapper that converts the result\n\t\t// to a string. In single-expression mode the executor bypasses\n\t\t// Handlebars entirely (via tryDirectHelperExecution) and returns\n\t\t// the raw value, so this wrapper only affects mixed/block templates\n\t\t// where Handlebars renders the result into a larger string.\n\t\tif (DIRECT_EXECUTION_HELPER_NAMES.has(name)) {\n\t\t\tthis.hbs.registerHelper(name, (...args: unknown[]) => {\n\t\t\t\t// Handlebars appends an `options` object as the last argument.\n\t\t\t\t// Strip it before calling the real fn.\n\t\t\t\tconst hbsArgs = args.slice(0, -1);\n\t\t\t\tconst raw = definition.fn(...hbsArgs);\n\t\t\t\treturn stringifyForTemplate(raw);\n\t\t\t});\n\t\t} else {\n\t\t\tthis.hbs.registerHelper(name, definition.fn);\n\t\t}\n\n\t\t// Invalidate the compilation cache because helpers have changed\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a custom helper from this engine instance.\n\t *\n\t * @param name - Name of the helper to remove\n\t * @returns `this` to allow chaining\n\t */\n\tunregisterHelper(name: string): this {\n\t\tthis.helpers.delete(name);\n\t\tthis.hbs.unregisterHelper(name);\n\n\t\t// Invalidate the compilation cache\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Checks whether a helper is registered on this instance.\n\t *\n\t * @param name - Helper name\n\t * @returns `true` if the helper is registered\n\t */\n\thasHelper(name: string): boolean {\n\t\treturn this.helpers.has(name);\n\t}\n\n\t// ─── Cache Management ──────────────────────────────────────────────────\n\n\t/**\n\t * Clears all internal caches (AST + compilation).\n\t *\n\t * Useful after a configuration change or to free memory.\n\t */\n\tclearCaches(): void {\n\t\tthis.astCache.clear();\n\t\tthis.compilationCache.clear();\n\t}\n\n\t// ─── Internals ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Retrieves the AST of a template from the cache, or parses and caches it.\n\t */\n\tprivate getCachedAst(template: string): hbs.AST.Program {\n\t\tlet ast = this.astCache.get(template);\n\t\tif (!ast) {\n\t\t\tast = parse(template);\n\t\t\tthis.astCache.set(template, ast);\n\t\t}\n\t\treturn ast;\n\t}\n}\n"],"names":["Handlebars","analyzeFromAst","CompiledTemplate","dispatchAnalyze","dispatchAnalyzeAndExecute","dispatchExecute","TemplateAnalysisError","executeFromAst","CollectionHelpers","LogicalHelpers","MathHelpers","parse","isArrayInput","isLiteralInput","isObjectInput","LRUCache","DIRECT_EXECUTION_HELPER_NAMES","Set","COLLECT_HELPER_NAME","stringifyForTemplate","value","undefined","Array","isArray","map","item","JSON","stringify","String","join","Typebars","compile","template","children","element","push","fromArray","helpers","hbs","compilationCache","key","Object","entries","fromObject","fromLiteral","ast","getCachedAst","options","fromTemplate","analyze","inputSchema","tpl","coerceSchema","identifierSchemas","child","childOptions","validate","analysis","valid","diagnostics","isValidSyntax","every","v","values","execute","data","schema","identifierData","analyzeAndExecute","registerHelper","name","definition","set","has","args","hbsArgs","slice","raw","fn","clear","unregisterHelper","delete","hasHelper","clearCaches","astCache","get","Map","create","astCacheSize","compilationCacheSize","register","helper"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typebars",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "license": "MIT",
5
5
  "description": "Typebars is a type-safe handlebars based template engine for generating object or content with static type checking",
6
6
  "author": {