typebars 1.0.24 → 1.0.25

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.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get clearCompilationCache(){return clearCompilationCache},get execute(){return execute},get executeFromAst(){return executeFromAst},get resolveDataPath(){return resolveDataPath}});const _handlebars=/*#__PURE__*/_interop_require_default(require("handlebars"));const _dispatchts=require("./dispatch.js");const _errorsts=require("./errors.js");const _maphelpersts=require("./helpers/map-helpers.js");const _parserts=require("./parser.js");const _utilsts=require("./utils.js");function _interop_require_default(obj){return obj&&obj.__esModule?obj:{default:obj}}const globalCompilationCache=new _utilsts.LRUCache(128);function execute(template,data,identifierData){return(0,_dispatchts.dispatchExecute)(template,undefined,tpl=>{const ast=(0,_parserts.parse)(tpl);return executeFromAst(ast,tpl,data,{identifierData})},child=>execute(child,data,identifierData))}function executeFromAst(ast,template,data,ctx){const identifierData=ctx?.identifierData;if((0,_parserts.isSingleExpression)(ast)){const stmt=ast.body[0];if(stmt.params.length===0&&!stmt.hash){return resolveExpression(stmt.path,data,identifierData,ctx?.helpers)}}const singleExpr=(0,_parserts.getEffectivelySingleExpression)(ast);if(singleExpr&&singleExpr.params.length===0&&!singleExpr.hash){return resolveExpression(singleExpr.path,data,identifierData,ctx?.helpers)}if(singleExpr&&(singleExpr.params.length>0||singleExpr.hash)){const directResult=tryDirectHelperExecution(singleExpr,data,ctx);if(directResult!==undefined){return directResult.value}const merged=mergeDataWithIdentifiers(data,identifierData);const raw=renderWithHandlebars(template,merged,ctx);return coerceValue(raw,ctx?.coerceSchema)}if((0,_parserts.canUseFastPath)(ast)&&ast.body.length>1){return executeFastPath(ast,data,identifierData)}const singleBlock=(0,_parserts.getEffectivelySingleBlock)(ast);if(singleBlock){const directResult=tryDirectBlockExecution(singleBlock,data,ctx);if(directResult!==undefined){return directResult.value}const merged=mergeDataWithIdentifiers(data,identifierData);const raw=renderWithHandlebars(template,merged,ctx);return coerceValue(raw,ctx?.coerceSchema)}const merged=mergeDataWithIdentifiers(data,identifierData);const raw=renderWithHandlebars(template,merged,ctx);const effective=(0,_parserts.getEffectiveBody)(ast);const allContent=effective.every(s=>s.type==="ContentStatement");if(allContent){return coerceValue(raw,ctx?.coerceSchema)}return raw}function coerceValue(raw,coerceSchema){if(coerceSchema){const targetType=coerceSchema.type;if(typeof targetType==="string"){if(targetType==="string")return raw;if(targetType==="number"||targetType==="integer"){const trimmed=raw.trim();if(trimmed==="")return undefined;const num=Number(trimmed);if(Number.isNaN(num))return undefined;if(targetType==="integer"&&!Number.isInteger(num))return undefined;return num}if(targetType==="boolean"){const lower=raw.trim().toLowerCase();if(lower==="true")return true;if(lower==="false")return false;return undefined}if(targetType==="null")return null}}return(0,_parserts.coerceLiteral)(raw)}function executeFastPath(ast,data,identifierData){let result="";for(const stmt of ast.body){if(stmt.type==="ContentStatement"){result+=stmt.value}else if(stmt.type==="MustacheStatement"){const value=resolveExpression(stmt.path,data,identifierData);if(value!=null){result+=String(value)}}}return result}function resolveExpression(expr,data,identifierData,helpers){if((0,_parserts.isThisExpression)(expr)){return data}if(expr.type==="StringLiteral")return expr.value;if(expr.type==="NumberLiteral")return expr.value;if(expr.type==="BooleanLiteral")return expr.value;if(expr.type==="NullLiteral")return null;if(expr.type==="UndefinedLiteral")return undefined;if(expr.type==="SubExpression"){const subExpr=expr;if(subExpr.path.type==="PathExpression"){const helperName=subExpr.path.original;const helper=helpers?.get(helperName);if(helper){const isMap=helperName===_maphelpersts.MapHelpers.MAP_HELPER_NAME;const resolvedArgs=[];for(let i=0;i<subExpr.params.length;i++){const param=subExpr.params[i];if(isMap&&i===1&&param.type==="StringLiteral"){resolvedArgs.push(param.value)}else{resolvedArgs.push(resolveExpression(param,data,identifierData,helpers))}}return helper.fn(...resolvedArgs)}}return undefined}const segments=(0,_parserts.extractPathSegments)(expr);if(segments.length===0){throw new _errorsts.TemplateRuntimeError(`Cannot resolve expression of type "${expr.type}"`)}const{cleanSegments,identifier}=(0,_parserts.extractExpressionIdentifier)(segments);if((0,_parserts.isRootPathTraversal)(cleanSegments)){return undefined}if((0,_parserts.isRootSegments)(cleanSegments)){if(identifier!==null&&identifierData){const source=identifierData[identifier];return source??undefined}if(identifier!==null){return undefined}return data}if(identifier!==null&&identifierData){const source=identifierData[identifier];if(source){if(Array.isArray(source)){return source.map(item=>resolveDataPath(item,cleanSegments)).filter(v=>v!==undefined)}return resolveDataPath(source,cleanSegments)}return undefined}if(identifier!==null&&!identifierData){return undefined}return resolveDataPath(data,cleanSegments)}function resolveDataPath(data,segments){let current=data;for(const segment of segments){if(current===null||current===undefined){return undefined}if(typeof current!=="object"){return undefined}current=current[segment]}return current}function mergeDataWithIdentifiers(data,identifierData){const base=data!==null&&typeof data==="object"&&!Array.isArray(data)?data:{};const merged={...base,[_parserts.ROOT_TOKEN]:data};if(!identifierData)return merged;for(const[id,idData]of Object.entries(identifierData)){merged[`${_parserts.ROOT_TOKEN}:${id}`]=idData;if(Array.isArray(idData)){continue}for(const[key,value]of Object.entries(idData)){merged[`${key}:${id}`]=value}}return merged}function renderWithHandlebars(template,data,ctx){try{if(ctx?.compiledTemplate){return ctx.compiledTemplate(data)}const cache=ctx?.compilationCache??globalCompilationCache;const hbs=ctx?.hbs??_handlebars.default;let compiled=cache.get(template);if(!compiled){compiled=hbs.compile(template,{noEscape:true,strict:false});cache.set(template,compiled)}return compiled(data)}catch(error){const message=error instanceof Error?error.message:String(error);throw new _errorsts.TemplateRuntimeError(message)}}function clearCompilationCache(){globalCompilationCache.clear()}function tryDirectBlockExecution(block,data,ctx){if(block.path.type!=="PathExpression")return undefined;const helperName=block.path.original;if(helperName!=="if"&&helperName!=="unless")return undefined;if(block.params.length!==1)return undefined;const condition=resolveExpression(block.params[0],data,ctx?.identifierData,ctx?.helpers);let isTruthy;if(Array.isArray(condition)){isTruthy=condition.length>0}else{isTruthy=!!condition}if(helperName==="unless")isTruthy=!isTruthy;const branch=isTruthy?block.program:block.inverse;if(!branch){return{value:""}}const singleExpr=(0,_parserts.getEffectivelySingleExpression)(branch);if(singleExpr){if(singleExpr.params.length===0&&!singleExpr.hash){return{value:resolveExpression(singleExpr.path,data,ctx?.identifierData,ctx?.helpers)}}if(singleExpr.params.length>0||singleExpr.hash){const directResult=tryDirectHelperExecution(singleExpr,data,ctx);if(directResult!==undefined)return directResult}}const nestedBlock=(0,_parserts.getEffectivelySingleBlock)(branch);if(nestedBlock){return tryDirectBlockExecution(nestedBlock,data,ctx)}return undefined}const DIRECT_EXECUTION_HELPERS=new Set([_maphelpersts.MapHelpers.MAP_HELPER_NAME]);function tryDirectHelperExecution(stmt,data,ctx){if(stmt.path.type!=="PathExpression")return undefined;const helperName=stmt.path.original;if(!DIRECT_EXECUTION_HELPERS.has(helperName))return undefined;const helper=ctx?.helpers?.get(helperName);if(!helper)return undefined;const isMap=helperName===_maphelpersts.MapHelpers.MAP_HELPER_NAME;const resolvedArgs=[];for(let i=0;i<stmt.params.length;i++){const param=stmt.params[i];if(isMap&&i===1){if(param.type==="StringLiteral"){resolvedArgs.push(param.value)}else{resolvedArgs.push(resolveExpression(param,data,ctx?.identifierData,ctx?.helpers))}}else{resolvedArgs.push(resolveExpression(param,data,ctx?.identifierData,ctx?.helpers))}}const value=helper.fn(...resolvedArgs);return{value}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get clearCompilationCache(){return clearCompilationCache},get execute(){return execute},get executeFromAst(){return executeFromAst},get resolveDataPath(){return resolveDataPath}});const _handlebars=/*#__PURE__*/_interop_require_default(require("handlebars"));const _dispatchts=require("./dispatch.js");const _errorsts=require("./errors.js");const _defaulthelpersts=require("./helpers/default-helpers.js");const _maphelpersts=require("./helpers/map-helpers.js");const _parserts=require("./parser.js");const _utilsts=require("./utils.js");function _interop_require_default(obj){return obj&&obj.__esModule?obj:{default:obj}}const globalCompilationCache=new _utilsts.LRUCache(128);function execute(template,data,identifierData){return(0,_dispatchts.dispatchExecute)(template,undefined,tpl=>{const ast=(0,_parserts.parse)(tpl);return executeFromAst(ast,tpl,data,{identifierData})},child=>execute(child,data,identifierData))}function executeFromAst(ast,template,data,ctx){const identifierData=ctx?.identifierData;if((0,_parserts.isSingleExpression)(ast)){const stmt=ast.body[0];if(stmt.params.length===0&&!stmt.hash){return resolveExpression(stmt.path,data,identifierData,ctx?.helpers)}}const singleExpr=(0,_parserts.getEffectivelySingleExpression)(ast);if(singleExpr&&singleExpr.params.length===0&&!singleExpr.hash){return resolveExpression(singleExpr.path,data,identifierData,ctx?.helpers)}if(singleExpr&&(singleExpr.params.length>0||singleExpr.hash)){const directResult=tryDirectHelperExecution(singleExpr,data,ctx);if(directResult!==undefined){return directResult.value}const merged=mergeDataWithIdentifiers(data,identifierData);const raw=renderWithHandlebars(template,merged,ctx);return coerceValue(raw,ctx?.coerceSchema)}if((0,_parserts.canUseFastPath)(ast)&&ast.body.length>1){return executeFastPath(ast,data,identifierData)}const singleBlock=(0,_parserts.getEffectivelySingleBlock)(ast);if(singleBlock){const directResult=tryDirectBlockExecution(singleBlock,data,ctx);if(directResult!==undefined){return directResult.value}const merged=mergeDataWithIdentifiers(data,identifierData);const raw=renderWithHandlebars(template,merged,ctx);return coerceValue(raw,ctx?.coerceSchema)}const merged=mergeDataWithIdentifiers(data,identifierData);const raw=renderWithHandlebars(template,merged,ctx);const effective=(0,_parserts.getEffectiveBody)(ast);const allContent=effective.every(s=>s.type==="ContentStatement");if(allContent){return coerceValue(raw,ctx?.coerceSchema)}return raw}function coerceValue(raw,coerceSchema){if(coerceSchema){const targetType=coerceSchema.type;if(typeof targetType==="string"){if(targetType==="string")return raw;if(targetType==="number"||targetType==="integer"){const trimmed=raw.trim();if(trimmed==="")return undefined;const num=Number(trimmed);if(Number.isNaN(num))return undefined;if(targetType==="integer"&&!Number.isInteger(num))return undefined;return num}if(targetType==="boolean"){const lower=raw.trim().toLowerCase();if(lower==="true")return true;if(lower==="false")return false;return undefined}if(targetType==="null")return null}}return(0,_parserts.coerceLiteral)(raw)}function executeFastPath(ast,data,identifierData){let result="";for(const stmt of ast.body){if(stmt.type==="ContentStatement"){result+=stmt.value}else if(stmt.type==="MustacheStatement"){const value=resolveExpression(stmt.path,data,identifierData);if(value!=null){result+=String(value)}}}return result}function resolveExpression(expr,data,identifierData,helpers){if((0,_parserts.isThisExpression)(expr)){return data}if(expr.type==="StringLiteral")return expr.value;if(expr.type==="NumberLiteral")return expr.value;if(expr.type==="BooleanLiteral")return expr.value;if(expr.type==="NullLiteral")return null;if(expr.type==="UndefinedLiteral")return undefined;if(expr.type==="SubExpression"){const subExpr=expr;if(subExpr.path.type==="PathExpression"){const helperName=subExpr.path.original;const helper=helpers?.get(helperName);if(helper){const isMap=helperName===_maphelpersts.MapHelpers.MAP_HELPER_NAME;const resolvedArgs=[];for(let i=0;i<subExpr.params.length;i++){const param=subExpr.params[i];if(isMap&&i===1&&param.type==="StringLiteral"){resolvedArgs.push(param.value)}else{resolvedArgs.push(resolveExpression(param,data,identifierData,helpers))}}return helper.fn(...resolvedArgs)}}return undefined}const segments=(0,_parserts.extractPathSegments)(expr);if(segments.length===0){throw new _errorsts.TemplateRuntimeError(`Cannot resolve expression of type "${expr.type}"`)}const{cleanSegments,identifier}=(0,_parserts.extractExpressionIdentifier)(segments);if((0,_parserts.isRootPathTraversal)(cleanSegments)){return undefined}if((0,_parserts.isRootSegments)(cleanSegments)){if(identifier!==null&&identifierData){const source=identifierData[identifier];return source??undefined}if(identifier!==null){return undefined}return data}if(identifier!==null&&identifierData){const source=identifierData[identifier];if(source){if(Array.isArray(source)){return source.map(item=>resolveDataPath(item,cleanSegments)).filter(v=>v!==undefined)}return resolveDataPath(source,cleanSegments)}return undefined}if(identifier!==null&&!identifierData){return undefined}return resolveDataPath(data,cleanSegments)}function resolveDataPath(data,segments){let current=data;for(const segment of segments){if(current===null||current===undefined){return undefined}if(typeof current!=="object"){return undefined}current=current[segment]}return current}function mergeDataWithIdentifiers(data,identifierData){const base=data!==null&&typeof data==="object"&&!Array.isArray(data)?data:{};const merged={...base,[_parserts.ROOT_TOKEN]:data};if(!identifierData)return merged;for(const[id,idData]of Object.entries(identifierData)){merged[`${_parserts.ROOT_TOKEN}:${id}`]=idData;if(Array.isArray(idData)){continue}for(const[key,value]of Object.entries(idData)){merged[`${key}:${id}`]=value}}return merged}function renderWithHandlebars(template,data,ctx){try{if(ctx?.compiledTemplate){return ctx.compiledTemplate(data)}const cache=ctx?.compilationCache??globalCompilationCache;const hbs=ctx?.hbs??_handlebars.default;let compiled=cache.get(template);if(!compiled){compiled=hbs.compile(template,{noEscape:true,strict:false});cache.set(template,compiled)}return compiled(data)}catch(error){const message=error instanceof Error?error.message:String(error);throw new _errorsts.TemplateRuntimeError(message)}}function clearCompilationCache(){globalCompilationCache.clear()}function tryDirectBlockExecution(block,data,ctx){if(block.path.type!=="PathExpression")return undefined;const helperName=block.path.original;if(helperName!=="if"&&helperName!=="unless")return undefined;if(block.params.length!==1)return undefined;const condition=resolveExpression(block.params[0],data,ctx?.identifierData,ctx?.helpers);let isTruthy;if(Array.isArray(condition)){isTruthy=condition.length>0}else{isTruthy=!!condition}if(helperName==="unless")isTruthy=!isTruthy;const branch=isTruthy?block.program:block.inverse;if(!branch){return{value:""}}const singleExpr=(0,_parserts.getEffectivelySingleExpression)(branch);if(singleExpr){if(singleExpr.params.length===0&&!singleExpr.hash){return{value:resolveExpression(singleExpr.path,data,ctx?.identifierData,ctx?.helpers)}}if(singleExpr.params.length>0||singleExpr.hash){const directResult=tryDirectHelperExecution(singleExpr,data,ctx);if(directResult!==undefined)return directResult}}const nestedBlock=(0,_parserts.getEffectivelySingleBlock)(branch);if(nestedBlock){return tryDirectBlockExecution(nestedBlock,data,ctx)}return undefined}const DIRECT_EXECUTION_HELPERS=new Set([_defaulthelpersts.DefaultHelpers.DEFAULT_HELPER_NAME,_maphelpersts.MapHelpers.MAP_HELPER_NAME]);function tryDirectHelperExecution(stmt,data,ctx){if(stmt.path.type!=="PathExpression")return undefined;const helperName=stmt.path.original;if(!DIRECT_EXECUTION_HELPERS.has(helperName))return undefined;const helper=ctx?.helpers?.get(helperName);if(!helper)return undefined;const isMap=helperName===_maphelpersts.MapHelpers.MAP_HELPER_NAME;const resolvedArgs=[];for(let i=0;i<stmt.params.length;i++){const param=stmt.params[i];if(isMap&&i===1){if(param.type==="StringLiteral"){resolvedArgs.push(param.value)}else{resolvedArgs.push(resolveExpression(param,data,ctx?.identifierData,ctx?.helpers))}}else{resolvedArgs.push(resolveExpression(param,data,ctx?.identifierData,ctx?.helpers))}}const value=helper.fn(...resolvedArgs);return{value}}
2
2
  //# sourceMappingURL=executor.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/executor.ts"],"sourcesContent":["import Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport { dispatchExecute } from \"./dispatch.ts\";\nimport { TemplateRuntimeError } from \"./errors.ts\";\nimport { MapHelpers } from \"./helpers/map-helpers.ts\";\nimport {\n\tcanUseFastPath,\n\tcoerceLiteral,\n\textractExpressionIdentifier,\n\textractPathSegments,\n\tgetEffectiveBody,\n\tgetEffectivelySingleBlock,\n\tgetEffectivelySingleExpression,\n\tisRootPathTraversal,\n\tisRootSegments,\n\tisSingleExpression,\n\tisThisExpression,\n\tparse,\n\tROOT_TOKEN,\n} from \"./parser.ts\";\nimport type {\n\tHelperDefinition,\n\tIdentifierData,\n\tTemplateInput,\n} from \"./types.ts\";\nimport { LRUCache } from \"./utils.ts\";\n\n// ─── Template Executor ───────────────────────────────────────────────────────\n// Executes a Handlebars template with real data.\n//\n// Four execution modes (from fastest to most general):\n//\n// 1. **Single expression** (`{{value}}` or ` {{value}} `) → returns the raw\n// value without converting to string. This preserves the original type\n// (number, boolean, object, array, null).\n//\n// 2. **Fast-path** (text + simple expressions, no blocks or helpers) →\n// direct concatenation without going through Handlebars.compile(). Up to\n// 10-100x faster for simple templates like `Hello {{name}}`.\n//\n// 3. **Single block** (`{{#if x}}10{{else}}20{{/if}}` possibly surrounded\n// by whitespace) → rendered via Handlebars then intelligently coerced\n// (detecting number, boolean, null literals).\n//\n// 4. **Mixed template** (text + multiple blocks, helpers, …) →\n// delegates to Handlebars which always produces a string.\n//\n// ─── Caching ─────────────────────────────────────────────────────────────────\n// Handlebars-compiled templates are cached in an LRU cache to avoid costly\n// recompilation on repeated calls.\n//\n// Two cache levels:\n// - **Global cache** (module-level) for standalone `execute()` calls\n// - **Instance cache** for `Typebars` (passed via `ExecutorContext`)\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// The `{{key:N}}` syntax allows resolving a variable from a specific data\n// source, identified by an integer N. The optional `identifierData` parameter\n// provides a mapping `{ [id]: { key: value, ... } }`.\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Optional context for execution (used by Typebars/CompiledTemplate) */\nexport interface ExecutorContext {\n\t/**\n\t * Data by identifier `{ [id]: { key: value } }`.\n\t *\n\t * Each identifier can map to a single object (standard) or an array\n\t * of objects (aggregated multi-version data). When the value is an\n\t * array, `{{key:N}}` extracts the property from each element.\n\t */\n\tidentifierData?: IdentifierData;\n\t/** Pre-compiled Handlebars template (for CompiledTemplate) */\n\tcompiledTemplate?: HandlebarsTemplateDelegate;\n\t/** Isolated Handlebars environment (for custom helpers) */\n\thbs?: typeof Handlebars;\n\t/** Compilation cache shared by the engine */\n\tcompilationCache?: LRUCache<string, HandlebarsTemplateDelegate>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When set with a primitive type, the execution result will be coerced\n\t * to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n\t/** Registered helpers (for direct execution of special helpers like `map`) */\n\thelpers?: Map<string, HelperDefinition>;\n}\n\n// ─── Global Compilation Cache ────────────────────────────────────────────────\n// Used by the standalone `execute()` function and `renderWithHandlebars()`.\n// `Typebars` instances use their own cache.\nconst globalCompilationCache = new LRUCache<string, HandlebarsTemplateDelegate>(\n\t128,\n);\n\n// ─── Public API (backward-compatible) ────────────────────────────────────────\n\n/**\n * Executes a template with the provided data and returns the result.\n *\n * The return type depends on the template structure:\n * - Single expression `{{expr}}` → raw value (any)\n * - Single block → coerced value (number, boolean, null, or string)\n * - Mixed template → `string`\n *\n * @param template - The template string\n * @param data - The main context data\n * @param identifierData - (optional) Data by identifier `{ [id]: { key: value } }`\n */\nexport function execute(\n\ttemplate: TemplateInput,\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n): unknown {\n\treturn dispatchExecute(\n\t\ttemplate,\n\t\tundefined,\n\t\t// String handler — parse and execute the AST\n\t\t(tpl) => {\n\t\t\tconst ast = parse(tpl);\n\t\t\treturn executeFromAst(ast, tpl, data, { identifierData });\n\t\t},\n\t\t// Recursive handler — re-enter execute() for child elements\n\t\t(child) => execute(child, data, identifierData),\n\t);\n}\n\n// ─── Internal API (for Typebars / CompiledTemplate) ──────────────────────\n\n/**\n * Executes a template from an already-parsed AST.\n *\n * This function is the core of execution. It is used by:\n * - `execute()` (backward-compatible wrapper)\n * - `CompiledTemplate.execute()` (with pre-parsed AST and cache)\n * - `Typebars.execute()` (with cache and helpers)\n *\n * @param ast - The already-parsed Handlebars AST\n * @param template - The template source (for Handlebars compilation if needed)\n * @param data - The main context data\n * @param ctx - Optional execution context\n */\nexport function executeFromAst(\n\tast: hbs.AST.Program,\n\ttemplate: string,\n\tdata: unknown,\n\tctx?: ExecutorContext,\n): unknown {\n\tconst identifierData = ctx?.identifierData;\n\n\t// ── Case 1: strict single expression `{{expr}}` ──────────────────────\n\t// Exclude helper calls (params > 0 or hash) because they must go\n\t// through Handlebars for correct execution.\n\tif (isSingleExpression(ast)) {\n\t\tconst stmt = ast.body[0] as hbs.AST.MustacheStatement;\n\t\tif (stmt.params.length === 0 && !stmt.hash) {\n\t\t\treturn resolveExpression(stmt.path, data, identifierData, ctx?.helpers);\n\t\t}\n\t}\n\n\t// ── Case 1b: single expression with surrounding whitespace ` {{expr}} `\n\tconst singleExpr = getEffectivelySingleExpression(ast);\n\tif (singleExpr && singleExpr.params.length === 0 && !singleExpr.hash) {\n\t\treturn resolveExpression(\n\t\t\tsingleExpr.path,\n\t\t\tdata,\n\t\t\tidentifierData,\n\t\t\tctx?.helpers,\n\t\t);\n\t}\n\n\t// ── Case 1c: single expression with helper (params > 0) ──────────────\n\t// E.g. `{{ divide accountIds.length 10 }}` or `{{ math a \"+\" b }}`\n\t// The helper returns a typed value but Handlebars converts it to a\n\t// string. We render via Handlebars then coerce the result to recover\n\t// the original type (number, boolean, null).\n\tif (singleExpr && (singleExpr.params.length > 0 || singleExpr.hash)) {\n\t\t// ── Special case: helpers that return non-primitive values ────────\n\t\t// Some helpers (e.g. `map`) return arrays or objects. Handlebars\n\t\t// would stringify these, so we resolve their arguments directly and\n\t\t// call the helper's fn to preserve the raw return value.\n\t\tconst directResult = tryDirectHelperExecution(singleExpr, data, ctx);\n\t\tif (directResult !== undefined) {\n\t\t\treturn directResult.value;\n\t\t}\n\n\t\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\t\tconst raw = renderWithHandlebars(template, merged, ctx);\n\t\treturn coerceValue(raw, ctx?.coerceSchema);\n\t}\n\n\t// ── Case 2: fast-path for simple templates (text + expressions) ──────\n\t// If the template only contains text and simple expressions (no blocks,\n\t// no helpers with parameters), we can do direct concatenation without\n\t// going through Handlebars.compile().\n\tif (canUseFastPath(ast) && ast.body.length > 1) {\n\t\treturn executeFastPath(ast, data, identifierData);\n\t}\n\n\t// ── Case 3: single block (possibly surrounded by whitespace) ─────────\n\t// For conditional blocks (#if/#unless), try to evaluate the condition\n\t// and execute the selected branch directly to preserve non-string types\n\t// (e.g. arrays from `map`). Falls back to Handlebars rendering.\n\tconst singleBlock = getEffectivelySingleBlock(ast);\n\tif (singleBlock) {\n\t\tconst directResult = tryDirectBlockExecution(singleBlock, data, ctx);\n\t\tif (directResult !== undefined) {\n\t\t\treturn directResult.value;\n\t\t}\n\n\t\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\t\tconst raw = renderWithHandlebars(template, merged, ctx);\n\t\treturn coerceValue(raw, ctx?.coerceSchema);\n\t}\n\n\t// ── Case 4: mixed template ───────────────────────────────────────────\n\t// For purely static templates (only ContentStatements), coerce the\n\t// result to match the coerceSchema type or auto-detect the literal type.\n\t// For truly mixed templates (text + blocks + expressions), return string.\n\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\tconst raw = renderWithHandlebars(template, merged, ctx);\n\n\tconst effective = getEffectiveBody(ast);\n\tconst allContent = effective.every((s) => s.type === \"ContentStatement\");\n\tif (allContent) {\n\t\treturn coerceValue(raw, ctx?.coerceSchema);\n\t}\n\n\treturn raw;\n}\n\n// ─── Value Coercion ──────────────────────────────────────────────────────────\n// Coerces a raw string from Handlebars rendering based on an optional\n// coerceSchema. When no schema is provided, falls back to auto-detection\n// via `coerceLiteral`.\n\n/**\n * Coerces a raw string value based on an optional coercion schema.\n *\n * - If `coerceSchema` declares a primitive type (`string`, `number`,\n * `integer`, `boolean`, `null`), the value is cast to that type.\n * - Otherwise, falls back to `coerceLiteral` (auto-detection).\n *\n * @param raw - The raw string from Handlebars rendering\n * @param coerceSchema - Optional schema declaring the desired output type\n * @returns The coerced value\n */\nfunction coerceValue(raw: string, coerceSchema?: JSONSchema7): unknown {\n\tif (coerceSchema) {\n\t\tconst targetType = coerceSchema.type;\n\t\tif (typeof targetType === \"string\") {\n\t\t\tif (targetType === \"string\") return raw;\n\t\t\tif (targetType === \"number\" || targetType === \"integer\") {\n\t\t\t\tconst trimmed = raw.trim();\n\t\t\t\tif (trimmed === \"\") return undefined;\n\t\t\t\tconst num = Number(trimmed);\n\t\t\t\tif (Number.isNaN(num)) return undefined;\n\t\t\t\tif (targetType === \"integer\" && !Number.isInteger(num))\n\t\t\t\t\treturn undefined;\n\t\t\t\treturn num;\n\t\t\t}\n\t\t\tif (targetType === \"boolean\") {\n\t\t\t\tconst lower = raw.trim().toLowerCase();\n\t\t\t\tif (lower === \"true\") return true;\n\t\t\t\tif (lower === \"false\") return false;\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (targetType === \"null\") return null;\n\t\t}\n\t}\n\t// No coerceSchema or non-primitive type → auto-detect\n\treturn coerceLiteral(raw);\n}\n\n// ─── Fast-Path Execution ─────────────────────────────────────────────────────\n// For templates consisting only of text and simple expressions (no blocks,\n// no helpers), we bypass Handlebars and do direct concatenation.\n// This is significantly faster.\n\n/**\n * Executes a template via the fast-path (direct concatenation).\n *\n * Precondition: `canUseFastPath(ast)` must return `true`.\n *\n * @param ast - The template AST (only ContentStatement and simple MustacheStatement)\n * @param data - The context data\n * @param identifierData - Data by identifier (optional)\n * @returns The resulting string\n */\nfunction executeFastPath(\n\tast: hbs.AST.Program,\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n): string {\n\tlet result = \"\";\n\n\tfor (const stmt of ast.body) {\n\t\tif (stmt.type === \"ContentStatement\") {\n\t\t\tresult += (stmt as hbs.AST.ContentStatement).value;\n\t\t} else if (stmt.type === \"MustacheStatement\") {\n\t\t\tconst value = resolveExpression(\n\t\t\t\t(stmt as hbs.AST.MustacheStatement).path,\n\t\t\t\tdata,\n\t\t\t\tidentifierData,\n\t\t\t);\n\t\t\t// Handlebars converts values to strings for rendering.\n\t\t\t// We replicate this behavior: null/undefined → \"\", otherwise String(value).\n\t\t\tif (value != null) {\n\t\t\t\tresult += String(value);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// ─── Direct Expression Resolution ────────────────────────────────────────────\n// Used for single-expression templates and the fast-path, to return the raw\n// value without going through the Handlebars engine.\n\n/**\n * Resolves an AST expression by following the path through the data.\n *\n * If the expression contains an identifier (e.g. `meetingId:1`), resolution\n * is performed in `identifierData[1]` instead of `data`.\n *\n * @param expr - The AST expression to resolve\n * @param data - The main data context\n * @param identifierData - Data by identifier (optional)\n * @returns The raw value pointed to by the expression\n */\nfunction resolveExpression(\n\texpr: hbs.AST.Expression,\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n\thelpers?: Map<string, HelperDefinition>,\n): unknown {\n\t// this / . → return the entire context\n\tif (isThisExpression(expr)) {\n\t\treturn data;\n\t}\n\n\t// Literals\n\tif (expr.type === \"StringLiteral\")\n\t\treturn (expr as hbs.AST.StringLiteral).value;\n\tif (expr.type === \"NumberLiteral\")\n\t\treturn (expr as hbs.AST.NumberLiteral).value;\n\tif (expr.type === \"BooleanLiteral\")\n\t\treturn (expr as hbs.AST.BooleanLiteral).value;\n\tif (expr.type === \"NullLiteral\") return null;\n\tif (expr.type === \"UndefinedLiteral\") return undefined;\n\n\t// ── SubExpression (nested helper call) ────────────────────────────────\n\t// E.g. `(map users 'cartItems')` used as an argument to another helper.\n\t// Resolve all arguments recursively and call the helper's fn directly.\n\tif (expr.type === \"SubExpression\") {\n\t\tconst subExpr = expr as hbs.AST.SubExpression;\n\t\tif (subExpr.path.type === \"PathExpression\") {\n\t\t\tconst helperName = (subExpr.path as hbs.AST.PathExpression).original;\n\t\t\tconst helper = helpers?.get(helperName);\n\t\t\tif (helper) {\n\t\t\t\tconst isMap = helperName === MapHelpers.MAP_HELPER_NAME;\n\t\t\t\tconst resolvedArgs: unknown[] = [];\n\t\t\t\tfor (let i = 0; i < subExpr.params.length; i++) {\n\t\t\t\t\tconst param = subExpr.params[i] as hbs.AST.Expression;\n\t\t\t\t\t// For `map`, the second argument is a property name literal\n\t\t\t\t\tif (isMap && i === 1 && param.type === \"StringLiteral\") {\n\t\t\t\t\t\tresolvedArgs.push((param as hbs.AST.StringLiteral).value);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresolvedArgs.push(\n\t\t\t\t\t\t\tresolveExpression(param, data, identifierData, helpers),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn helper.fn(...resolvedArgs);\n\t\t\t}\n\t\t}\n\t\t// Unknown sub-expression helper — return undefined\n\t\treturn undefined;\n\t}\n\n\t// PathExpression — navigate through segments in the data object\n\tconst segments = extractPathSegments(expr);\n\tif (segments.length === 0) {\n\t\tthrow new TemplateRuntimeError(\n\t\t\t`Cannot resolve expression of type \"${expr.type}\"`,\n\t\t);\n\t}\n\n\t// Extract the potential identifier from the last segment BEFORE\n\t// checking for $root, so that both {{$root}} and {{$root:N}} are\n\t// handled uniformly.\n\tconst { cleanSegments, identifier } = extractExpressionIdentifier(segments);\n\n\t// $root path traversal ($root.name) — not supported, return undefined\n\t// (the analyzer already rejects it with a diagnostic).\n\tif (isRootPathTraversal(cleanSegments)) {\n\t\treturn undefined;\n\t}\n\n\t// $root → return the entire data context (or identifier data)\n\tif (isRootSegments(cleanSegments)) {\n\t\tif (identifier !== null && identifierData) {\n\t\t\tconst source = identifierData[identifier];\n\t\t\treturn source ?? undefined;\n\t\t}\n\t\tif (identifier !== null) {\n\t\t\t// Template uses an identifier but no identifierData was provided\n\t\t\treturn undefined;\n\t\t}\n\t\treturn data;\n\t}\n\n\tif (identifier !== null && identifierData) {\n\t\tconst source = identifierData[identifier];\n\t\tif (source) {\n\t\t\t// ── Aggregated identifier (array of objects) ──────────────────\n\t\t\t// When the identifier maps to an array of objects (multi-version\n\t\t\t// data), extract the property from each element to produce a\n\t\t\t// result array. E.g. {{accountId:4}} on [{accountId:\"A\"},{accountId:\"B\"}]\n\t\t\t// → [\"A\", \"B\"]\n\t\t\tif (Array.isArray(source)) {\n\t\t\t\treturn source\n\t\t\t\t\t.map((item) => resolveDataPath(item, cleanSegments))\n\t\t\t\t\t.filter((v) => v !== undefined);\n\t\t\t}\n\t\t\treturn resolveDataPath(source, cleanSegments);\n\t\t}\n\t\t// Source does not exist → undefined (like a missing key)\n\t\treturn undefined;\n\t}\n\n\tif (identifier !== null && !identifierData) {\n\t\t// Template uses an identifier but no identifierData was provided\n\t\treturn undefined;\n\t}\n\n\treturn resolveDataPath(data, cleanSegments);\n}\n\n/**\n * Navigates through a data object by following a path of segments.\n *\n * @param data - The data object\n * @param segments - The path segments (e.g. `[\"user\", \"address\", \"city\"]`)\n * @returns The value at the end of the path, or `undefined` if an\n * intermediate segment is null/undefined\n */\nexport function resolveDataPath(data: unknown, segments: string[]): unknown {\n\tlet current: unknown = data;\n\n\tfor (const segment of segments) {\n\t\tif (current === null || current === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (typeof current !== \"object\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcurrent = (current as Record<string, unknown>)[segment];\n\t}\n\n\treturn current;\n}\n\n// ─── Data Merging ────────────────────────────────────────────────────────────\n// For Handlebars rendering (mixed templates / blocks), we cannot intercept\n// resolution on a per-expression basis. Instead, we merge identifier data\n// into the main object using the format `\"key:N\"`.\n//\n// Handlebars parses `{{meetingId:1}}` as a PathExpression with a single\n// segment `\"meetingId:1\"`, so it looks up the key `\"meetingId:1\"` in the\n// data object — which matches our flattened format exactly.\n\n/**\n * Merges the main data with identifier data.\n *\n * @param data - Main data\n * @param identifierData - Data by identifier\n * @returns A merged object where identifier data appears as `\"key:N\"` keys\n *\n * @example\n * ```\n * mergeDataWithIdentifiers(\n * { name: \"Alice\" },\n * { 1: { meetingId: \"val1\" }, 2: { meetingId: \"val2\" } }\n * )\n * // → { name: \"Alice\", \"meetingId:1\": \"val1\", \"meetingId:2\": \"val2\" }\n * ```\n */\nfunction mergeDataWithIdentifiers(\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n): Record<string, unknown> {\n\t// Always include $root so that Handlebars can resolve {{$root}} in\n\t// mixed templates and block helpers (where we delegate to Handlebars\n\t// instead of resolving expressions ourselves).\n\t// When data is a primitive (e.g. number passed with {{$root}}), we\n\t// wrap it into an object so Handlebars can still function.\n\tconst base: Record<string, unknown> =\n\t\tdata !== null && typeof data === \"object\" && !Array.isArray(data)\n\t\t\t? (data as Record<string, unknown>)\n\t\t\t: {};\n\tconst merged: Record<string, unknown> = { ...base, [ROOT_TOKEN]: data };\n\n\tif (!identifierData) return merged;\n\n\tfor (const [id, idData] of Object.entries(identifierData)) {\n\t\t// Add `$root:N` so Handlebars can resolve {{$root:N}} in mixed/block\n\t\t// templates (where we delegate to Handlebars instead of resolving\n\t\t// expressions ourselves). The value is the entire identifier data\n\t\t// object (or array for aggregated identifiers).\n\t\tmerged[`${ROOT_TOKEN}:${id}`] = idData;\n\n\t\t// ── Aggregated identifier (array of objects) ─────────────────\n\t\t// When the identifier data is an array (multi-version), we cannot\n\t\t// flatten individual properties into `\"key:N\"` keys because there\n\t\t// are multiple values per key. The array is only accessible via\n\t\t// `$root:N` (already set above). Handlebars helpers like `map`\n\t\t// can then consume it: `{{ map ($root:4) \"accountId\" }}`.\n\t\tif (Array.isArray(idData)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(idData)) {\n\t\t\tmerged[`${key}:${id}`] = value;\n\t\t}\n\t}\n\n\treturn merged;\n}\n\n// ─── Handlebars Rendering ────────────────────────────────────────────────────\n// For complex templates (blocks, helpers), we delegate to Handlebars.\n// Compilation is cached to avoid costly recompilations.\n\n/**\n * Compiles and executes a template via Handlebars.\n *\n * Uses a compilation cache (LRU) to avoid recompiling the same template\n * on repeated calls. The cache is either:\n * - The global cache (for the standalone `execute()` function)\n * - The instance cache provided via `ExecutorContext` (for `Typebars`)\n *\n * @param template - The template string\n * @param data - The context data\n * @param ctx - Optional execution context (cache, Handlebars env)\n * @returns Always a string\n */\nfunction renderWithHandlebars(\n\ttemplate: string,\n\tdata: Record<string, unknown>,\n\tctx?: ExecutorContext,\n): string {\n\ttry {\n\t\t// 1. Use the pre-compiled template if available (CompiledTemplate)\n\t\tif (ctx?.compiledTemplate) {\n\t\t\treturn ctx.compiledTemplate(data);\n\t\t}\n\n\t\t// 2. Look up in the cache (instance or global)\n\t\tconst cache = ctx?.compilationCache ?? globalCompilationCache;\n\t\tconst hbs = ctx?.hbs ?? Handlebars;\n\n\t\tlet compiled = cache.get(template);\n\t\tif (!compiled) {\n\t\t\tcompiled = hbs.compile(template, {\n\t\t\t\t// Disable HTML-escaping by default — this engine is not\n\t\t\t\t// HTML-specific, we want raw values.\n\t\t\t\tnoEscape: true,\n\t\t\t\t// Strict mode: throws if a path does not exist in the data.\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t\tcache.set(template, compiled);\n\t\t}\n\n\t\treturn compiled(data);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new TemplateRuntimeError(message);\n\t}\n}\n\n/**\n * Clears the global Handlebars compilation cache.\n * Useful for tests or to free memory.\n */\nexport function clearCompilationCache(): void {\n\tglobalCompilationCache.clear();\n}\n\n// ─── Direct Block Execution ──────────────────────────────────────────────────\n// For conditional blocks (#if/#unless), we can evaluate the condition directly\n// and execute the selected branch through the type-preserving execution paths.\n// This avoids Handlebars stringification when the branch contains helpers that\n// return non-primitive values (e.g. `map` returning arrays).\n\n/**\n * Attempts to execute a conditional block directly by evaluating its condition\n * and executing the selected branch through type-preserving paths.\n *\n * Only handles `#if` and `#unless` blocks. Returns `{ value }` if the branch\n * was executed directly, or `undefined` to fall back to Handlebars rendering.\n */\nfunction tryDirectBlockExecution(\n\tblock: hbs.AST.BlockStatement,\n\tdata: unknown,\n\tctx?: ExecutorContext,\n): { value: unknown } | undefined {\n\tif (block.path.type !== \"PathExpression\") return undefined;\n\tconst helperName = (block.path as hbs.AST.PathExpression).original;\n\n\t// Only handle built-in conditional blocks\n\tif (helperName !== \"if\" && helperName !== \"unless\") return undefined;\n\tif (block.params.length !== 1) return undefined;\n\n\t// Evaluate the condition\n\tconst condition = resolveExpression(\n\t\tblock.params[0] as hbs.AST.Expression,\n\t\tdata,\n\t\tctx?.identifierData,\n\t\tctx?.helpers,\n\t);\n\n\t// Handlebars truthiness: empty arrays are falsy\n\tlet isTruthy: boolean;\n\tif (Array.isArray(condition)) {\n\t\tisTruthy = condition.length > 0;\n\t} else {\n\t\tisTruthy = !!condition;\n\t}\n\tif (helperName === \"unless\") isTruthy = !isTruthy;\n\n\tconst branch = isTruthy ? block.program : block.inverse;\n\tif (!branch) {\n\t\t// No matching branch (e.g. falsy #if with no {{else}}) → empty string\n\t\treturn { value: \"\" };\n\t}\n\n\t// Try to execute the branch as a single expression (preserves types)\n\tconst singleExpr = getEffectivelySingleExpression(branch);\n\tif (singleExpr) {\n\t\tif (singleExpr.params.length === 0 && !singleExpr.hash) {\n\t\t\treturn {\n\t\t\t\tvalue: resolveExpression(\n\t\t\t\t\tsingleExpr.path,\n\t\t\t\t\tdata,\n\t\t\t\t\tctx?.identifierData,\n\t\t\t\t\tctx?.helpers,\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t\t// Single expression with helper (e.g. {{map users \"name\"}})\n\t\tif (singleExpr.params.length > 0 || singleExpr.hash) {\n\t\t\tconst directResult = tryDirectHelperExecution(singleExpr, data, ctx);\n\t\t\tif (directResult !== undefined) return directResult;\n\t\t}\n\t}\n\n\t// Try to execute the branch as a nested conditional block (recursive)\n\tconst nestedBlock = getEffectivelySingleBlock(branch);\n\tif (nestedBlock) {\n\t\treturn tryDirectBlockExecution(nestedBlock, data, ctx);\n\t}\n\n\t// Branch is too complex for direct execution → fall back\n\treturn undefined;\n}\n\n// ─── Direct Helper Execution ─────────────────────────────────────────────────\n// Some helpers (e.g. `map`) return non-primitive values (arrays, objects)\n// that Handlebars would stringify. For these helpers, we resolve their\n// arguments directly and call the helper's `fn` to preserve the raw value.\n\n/** Set of helper names that must be executed directly (bypass Handlebars) */\nconst DIRECT_EXECUTION_HELPERS = new Set<string>([MapHelpers.MAP_HELPER_NAME]);\n\n/**\n * Attempts to execute a helper directly (without Handlebars rendering).\n *\n * Returns `{ value }` if the helper was executed directly, or `undefined`\n * if the helper should go through the normal Handlebars rendering path.\n *\n * @param stmt - The MustacheStatement containing the helper call\n * @param data - The context data\n * @param ctx - Optional execution context (with helpers and identifierData)\n */\nfunction tryDirectHelperExecution(\n\tstmt: hbs.AST.MustacheStatement,\n\tdata: unknown,\n\tctx?: ExecutorContext,\n): { value: unknown } | undefined {\n\t// Get the helper name from the path\n\tif (stmt.path.type !== \"PathExpression\") return undefined;\n\tconst helperName = (stmt.path as hbs.AST.PathExpression).original;\n\n\t// Only intercept known direct-execution helpers\n\tif (!DIRECT_EXECUTION_HELPERS.has(helperName)) return undefined;\n\n\t// Look up the helper definition\n\tconst helper = ctx?.helpers?.get(helperName);\n\tif (!helper) return undefined;\n\n\t// Resolve each argument from the data context.\n\t// For the `map` helper, the resolution strategy is:\n\t// - Arg 0 (array): resolve as a data path (e.g. `users` → array)\n\t// - Arg 1 (property): must be a StringLiteral (e.g. `\"name\"`)\n\t// The analyzer enforces this — bare identifiers like `name` are\n\t// rejected at analysis time because Handlebars would resolve them\n\t// as a data path instead of a literal property name.\n\tconst isMap = helperName === MapHelpers.MAP_HELPER_NAME;\n\n\tconst resolvedArgs: unknown[] = [];\n\tfor (let i = 0; i < stmt.params.length; i++) {\n\t\tconst param = stmt.params[i] as hbs.AST.Expression;\n\n\t\t// For `map`, the second argument (index 1) is a property name —\n\t\t// it must be a StringLiteral (enforced by the analyzer).\n\t\tif (isMap && i === 1) {\n\t\t\tif (param.type === \"StringLiteral\") {\n\t\t\t\tresolvedArgs.push((param as hbs.AST.StringLiteral).value);\n\t\t\t} else {\n\t\t\t\t// Fallback: resolve normally (will likely be undefined at runtime)\n\t\t\t\tresolvedArgs.push(\n\t\t\t\t\tresolveExpression(param, data, ctx?.identifierData, ctx?.helpers),\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tresolvedArgs.push(\n\t\t\t\tresolveExpression(param, data, ctx?.identifierData, ctx?.helpers),\n\t\t\t);\n\t\t}\n\t}\n\n\t// Call the helper's fn directly with the resolved arguments\n\tconst value = helper.fn(...resolvedArgs);\n\treturn { value };\n}\n"],"names":["clearCompilationCache","execute","executeFromAst","resolveDataPath","globalCompilationCache","LRUCache","template","data","identifierData","dispatchExecute","undefined","tpl","ast","parse","child","ctx","isSingleExpression","stmt","body","params","length","hash","resolveExpression","path","helpers","singleExpr","getEffectivelySingleExpression","directResult","tryDirectHelperExecution","value","merged","mergeDataWithIdentifiers","raw","renderWithHandlebars","coerceValue","coerceSchema","canUseFastPath","executeFastPath","singleBlock","getEffectivelySingleBlock","tryDirectBlockExecution","effective","getEffectiveBody","allContent","every","s","type","targetType","trimmed","trim","num","Number","isNaN","isInteger","lower","toLowerCase","coerceLiteral","result","String","expr","isThisExpression","subExpr","helperName","original","helper","get","isMap","MapHelpers","MAP_HELPER_NAME","resolvedArgs","i","param","push","fn","segments","extractPathSegments","TemplateRuntimeError","cleanSegments","identifier","extractExpressionIdentifier","isRootPathTraversal","isRootSegments","source","Array","isArray","map","item","filter","v","current","segment","base","ROOT_TOKEN","id","idData","Object","entries","key","compiledTemplate","cache","compilationCache","hbs","Handlebars","compiled","compile","noEscape","strict","set","error","message","Error","clear","block","condition","isTruthy","branch","program","inverse","nestedBlock","DIRECT_EXECUTION_HELPERS","Set","has"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/executor.ts"],"sourcesContent":["import Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport { dispatchExecute } from \"./dispatch.ts\";\nimport { TemplateRuntimeError } from \"./errors.ts\";\nimport { DefaultHelpers } from \"./helpers/default-helpers.ts\";\nimport { MapHelpers } from \"./helpers/map-helpers.ts\";\nimport {\n\tcanUseFastPath,\n\tcoerceLiteral,\n\textractExpressionIdentifier,\n\textractPathSegments,\n\tgetEffectiveBody,\n\tgetEffectivelySingleBlock,\n\tgetEffectivelySingleExpression,\n\tisRootPathTraversal,\n\tisRootSegments,\n\tisSingleExpression,\n\tisThisExpression,\n\tparse,\n\tROOT_TOKEN,\n} from \"./parser.ts\";\nimport type {\n\tHelperDefinition,\n\tIdentifierData,\n\tTemplateInput,\n} from \"./types.ts\";\nimport { LRUCache } from \"./utils.ts\";\n\n// ─── Template Executor ───────────────────────────────────────────────────────\n// Executes a Handlebars template with real data.\n//\n// Four execution modes (from fastest to most general):\n//\n// 1. **Single expression** (`{{value}}` or ` {{value}} `) → returns the raw\n// value without converting to string. This preserves the original type\n// (number, boolean, object, array, null).\n//\n// 2. **Fast-path** (text + simple expressions, no blocks or helpers) →\n// direct concatenation without going through Handlebars.compile(). Up to\n// 10-100x faster for simple templates like `Hello {{name}}`.\n//\n// 3. **Single block** (`{{#if x}}10{{else}}20{{/if}}` possibly surrounded\n// by whitespace) → rendered via Handlebars then intelligently coerced\n// (detecting number, boolean, null literals).\n//\n// 4. **Mixed template** (text + multiple blocks, helpers, …) →\n// delegates to Handlebars which always produces a string.\n//\n// ─── Caching ─────────────────────────────────────────────────────────────────\n// Handlebars-compiled templates are cached in an LRU cache to avoid costly\n// recompilation on repeated calls.\n//\n// Two cache levels:\n// - **Global cache** (module-level) for standalone `execute()` calls\n// - **Instance cache** for `Typebars` (passed via `ExecutorContext`)\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// The `{{key:N}}` syntax allows resolving a variable from a specific data\n// source, identified by an integer N. The optional `identifierData` parameter\n// provides a mapping `{ [id]: { key: value, ... } }`.\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Optional context for execution (used by Typebars/CompiledTemplate) */\nexport interface ExecutorContext {\n\t/**\n\t * Data by identifier `{ [id]: { key: value } }`.\n\t *\n\t * Each identifier can map to a single object (standard) or an array\n\t * of objects (aggregated multi-version data). When the value is an\n\t * array, `{{key:N}}` extracts the property from each element.\n\t */\n\tidentifierData?: IdentifierData;\n\t/** Pre-compiled Handlebars template (for CompiledTemplate) */\n\tcompiledTemplate?: HandlebarsTemplateDelegate;\n\t/** Isolated Handlebars environment (for custom helpers) */\n\thbs?: typeof Handlebars;\n\t/** Compilation cache shared by the engine */\n\tcompilationCache?: LRUCache<string, HandlebarsTemplateDelegate>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When set with a primitive type, the execution result will be coerced\n\t * to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n\t/** Registered helpers (for direct execution of special helpers like `map`) */\n\thelpers?: Map<string, HelperDefinition>;\n}\n\n// ─── Global Compilation Cache ────────────────────────────────────────────────\n// Used by the standalone `execute()` function and `renderWithHandlebars()`.\n// `Typebars` instances use their own cache.\nconst globalCompilationCache = new LRUCache<string, HandlebarsTemplateDelegate>(\n\t128,\n);\n\n// ─── Public API (backward-compatible) ────────────────────────────────────────\n\n/**\n * Executes a template with the provided data and returns the result.\n *\n * The return type depends on the template structure:\n * - Single expression `{{expr}}` → raw value (any)\n * - Single block → coerced value (number, boolean, null, or string)\n * - Mixed template → `string`\n *\n * @param template - The template string\n * @param data - The main context data\n * @param identifierData - (optional) Data by identifier `{ [id]: { key: value } }`\n */\nexport function execute(\n\ttemplate: TemplateInput,\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n): unknown {\n\treturn dispatchExecute(\n\t\ttemplate,\n\t\tundefined,\n\t\t// String handler — parse and execute the AST\n\t\t(tpl) => {\n\t\t\tconst ast = parse(tpl);\n\t\t\treturn executeFromAst(ast, tpl, data, { identifierData });\n\t\t},\n\t\t// Recursive handler — re-enter execute() for child elements\n\t\t(child) => execute(child, data, identifierData),\n\t);\n}\n\n// ─── Internal API (for Typebars / CompiledTemplate) ──────────────────────\n\n/**\n * Executes a template from an already-parsed AST.\n *\n * This function is the core of execution. It is used by:\n * - `execute()` (backward-compatible wrapper)\n * - `CompiledTemplate.execute()` (with pre-parsed AST and cache)\n * - `Typebars.execute()` (with cache and helpers)\n *\n * @param ast - The already-parsed Handlebars AST\n * @param template - The template source (for Handlebars compilation if needed)\n * @param data - The main context data\n * @param ctx - Optional execution context\n */\nexport function executeFromAst(\n\tast: hbs.AST.Program,\n\ttemplate: string,\n\tdata: unknown,\n\tctx?: ExecutorContext,\n): unknown {\n\tconst identifierData = ctx?.identifierData;\n\n\t// ── Case 1: strict single expression `{{expr}}` ──────────────────────\n\t// Exclude helper calls (params > 0 or hash) because they must go\n\t// through Handlebars for correct execution.\n\tif (isSingleExpression(ast)) {\n\t\tconst stmt = ast.body[0] as hbs.AST.MustacheStatement;\n\t\tif (stmt.params.length === 0 && !stmt.hash) {\n\t\t\treturn resolveExpression(stmt.path, data, identifierData, ctx?.helpers);\n\t\t}\n\t}\n\n\t// ── Case 1b: single expression with surrounding whitespace ` {{expr}} `\n\tconst singleExpr = getEffectivelySingleExpression(ast);\n\tif (singleExpr && singleExpr.params.length === 0 && !singleExpr.hash) {\n\t\treturn resolveExpression(\n\t\t\tsingleExpr.path,\n\t\t\tdata,\n\t\t\tidentifierData,\n\t\t\tctx?.helpers,\n\t\t);\n\t}\n\n\t// ── Case 1c: single expression with helper (params > 0) ──────────────\n\t// E.g. `{{ divide accountIds.length 10 }}` or `{{ math a \"+\" b }}`\n\t// The helper returns a typed value but Handlebars converts it to a\n\t// string. We render via Handlebars then coerce the result to recover\n\t// the original type (number, boolean, null).\n\tif (singleExpr && (singleExpr.params.length > 0 || singleExpr.hash)) {\n\t\t// ── Special case: helpers that return non-primitive values ────────\n\t\t// Some helpers (e.g. `map`) return arrays or objects. Handlebars\n\t\t// would stringify these, so we resolve their arguments directly and\n\t\t// call the helper's fn to preserve the raw return value.\n\t\tconst directResult = tryDirectHelperExecution(singleExpr, data, ctx);\n\t\tif (directResult !== undefined) {\n\t\t\treturn directResult.value;\n\t\t}\n\n\t\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\t\tconst raw = renderWithHandlebars(template, merged, ctx);\n\t\treturn coerceValue(raw, ctx?.coerceSchema);\n\t}\n\n\t// ── Case 2: fast-path for simple templates (text + expressions) ──────\n\t// If the template only contains text and simple expressions (no blocks,\n\t// no helpers with parameters), we can do direct concatenation without\n\t// going through Handlebars.compile().\n\tif (canUseFastPath(ast) && ast.body.length > 1) {\n\t\treturn executeFastPath(ast, data, identifierData);\n\t}\n\n\t// ── Case 3: single block (possibly surrounded by whitespace) ─────────\n\t// For conditional blocks (#if/#unless), try to evaluate the condition\n\t// and execute the selected branch directly to preserve non-string types\n\t// (e.g. arrays from `map`). Falls back to Handlebars rendering.\n\tconst singleBlock = getEffectivelySingleBlock(ast);\n\tif (singleBlock) {\n\t\tconst directResult = tryDirectBlockExecution(singleBlock, data, ctx);\n\t\tif (directResult !== undefined) {\n\t\t\treturn directResult.value;\n\t\t}\n\n\t\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\t\tconst raw = renderWithHandlebars(template, merged, ctx);\n\t\treturn coerceValue(raw, ctx?.coerceSchema);\n\t}\n\n\t// ── Case 4: mixed template ───────────────────────────────────────────\n\t// For purely static templates (only ContentStatements), coerce the\n\t// result to match the coerceSchema type or auto-detect the literal type.\n\t// For truly mixed templates (text + blocks + expressions), return string.\n\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\tconst raw = renderWithHandlebars(template, merged, ctx);\n\n\tconst effective = getEffectiveBody(ast);\n\tconst allContent = effective.every((s) => s.type === \"ContentStatement\");\n\tif (allContent) {\n\t\treturn coerceValue(raw, ctx?.coerceSchema);\n\t}\n\n\treturn raw;\n}\n\n// ─── Value Coercion ──────────────────────────────────────────────────────────\n// Coerces a raw string from Handlebars rendering based on an optional\n// coerceSchema. When no schema is provided, falls back to auto-detection\n// via `coerceLiteral`.\n\n/**\n * Coerces a raw string value based on an optional coercion schema.\n *\n * - If `coerceSchema` declares a primitive type (`string`, `number`,\n * `integer`, `boolean`, `null`), the value is cast to that type.\n * - Otherwise, falls back to `coerceLiteral` (auto-detection).\n *\n * @param raw - The raw string from Handlebars rendering\n * @param coerceSchema - Optional schema declaring the desired output type\n * @returns The coerced value\n */\nfunction coerceValue(raw: string, coerceSchema?: JSONSchema7): unknown {\n\tif (coerceSchema) {\n\t\tconst targetType = coerceSchema.type;\n\t\tif (typeof targetType === \"string\") {\n\t\t\tif (targetType === \"string\") return raw;\n\t\t\tif (targetType === \"number\" || targetType === \"integer\") {\n\t\t\t\tconst trimmed = raw.trim();\n\t\t\t\tif (trimmed === \"\") return undefined;\n\t\t\t\tconst num = Number(trimmed);\n\t\t\t\tif (Number.isNaN(num)) return undefined;\n\t\t\t\tif (targetType === \"integer\" && !Number.isInteger(num))\n\t\t\t\t\treturn undefined;\n\t\t\t\treturn num;\n\t\t\t}\n\t\t\tif (targetType === \"boolean\") {\n\t\t\t\tconst lower = raw.trim().toLowerCase();\n\t\t\t\tif (lower === \"true\") return true;\n\t\t\t\tif (lower === \"false\") return false;\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (targetType === \"null\") return null;\n\t\t}\n\t}\n\t// No coerceSchema or non-primitive type → auto-detect\n\treturn coerceLiteral(raw);\n}\n\n// ─── Fast-Path Execution ─────────────────────────────────────────────────────\n// For templates consisting only of text and simple expressions (no blocks,\n// no helpers), we bypass Handlebars and do direct concatenation.\n// This is significantly faster.\n\n/**\n * Executes a template via the fast-path (direct concatenation).\n *\n * Precondition: `canUseFastPath(ast)` must return `true`.\n *\n * @param ast - The template AST (only ContentStatement and simple MustacheStatement)\n * @param data - The context data\n * @param identifierData - Data by identifier (optional)\n * @returns The resulting string\n */\nfunction executeFastPath(\n\tast: hbs.AST.Program,\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n): string {\n\tlet result = \"\";\n\n\tfor (const stmt of ast.body) {\n\t\tif (stmt.type === \"ContentStatement\") {\n\t\t\tresult += (stmt as hbs.AST.ContentStatement).value;\n\t\t} else if (stmt.type === \"MustacheStatement\") {\n\t\t\tconst value = resolveExpression(\n\t\t\t\t(stmt as hbs.AST.MustacheStatement).path,\n\t\t\t\tdata,\n\t\t\t\tidentifierData,\n\t\t\t);\n\t\t\t// Handlebars converts values to strings for rendering.\n\t\t\t// We replicate this behavior: null/undefined → \"\", otherwise String(value).\n\t\t\tif (value != null) {\n\t\t\t\tresult += String(value);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// ─── Direct Expression Resolution ────────────────────────────────────────────\n// Used for single-expression templates and the fast-path, to return the raw\n// value without going through the Handlebars engine.\n\n/**\n * Resolves an AST expression by following the path through the data.\n *\n * If the expression contains an identifier (e.g. `meetingId:1`), resolution\n * is performed in `identifierData[1]` instead of `data`.\n *\n * @param expr - The AST expression to resolve\n * @param data - The main data context\n * @param identifierData - Data by identifier (optional)\n * @returns The raw value pointed to by the expression\n */\nfunction resolveExpression(\n\texpr: hbs.AST.Expression,\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n\thelpers?: Map<string, HelperDefinition>,\n): unknown {\n\t// this / . → return the entire context\n\tif (isThisExpression(expr)) {\n\t\treturn data;\n\t}\n\n\t// Literals\n\tif (expr.type === \"StringLiteral\")\n\t\treturn (expr as hbs.AST.StringLiteral).value;\n\tif (expr.type === \"NumberLiteral\")\n\t\treturn (expr as hbs.AST.NumberLiteral).value;\n\tif (expr.type === \"BooleanLiteral\")\n\t\treturn (expr as hbs.AST.BooleanLiteral).value;\n\tif (expr.type === \"NullLiteral\") return null;\n\tif (expr.type === \"UndefinedLiteral\") return undefined;\n\n\t// ── SubExpression (nested helper call) ────────────────────────────────\n\t// E.g. `(map users 'cartItems')` used as an argument to another helper.\n\t// Resolve all arguments recursively and call the helper's fn directly.\n\tif (expr.type === \"SubExpression\") {\n\t\tconst subExpr = expr as hbs.AST.SubExpression;\n\t\tif (subExpr.path.type === \"PathExpression\") {\n\t\t\tconst helperName = (subExpr.path as hbs.AST.PathExpression).original;\n\t\t\tconst helper = helpers?.get(helperName);\n\t\t\tif (helper) {\n\t\t\t\tconst isMap = helperName === MapHelpers.MAP_HELPER_NAME;\n\t\t\t\tconst resolvedArgs: unknown[] = [];\n\t\t\t\tfor (let i = 0; i < subExpr.params.length; i++) {\n\t\t\t\t\tconst param = subExpr.params[i] as hbs.AST.Expression;\n\t\t\t\t\t// For `map`, the second argument is a property name literal\n\t\t\t\t\tif (isMap && i === 1 && param.type === \"StringLiteral\") {\n\t\t\t\t\t\tresolvedArgs.push((param as hbs.AST.StringLiteral).value);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresolvedArgs.push(\n\t\t\t\t\t\t\tresolveExpression(param, data, identifierData, helpers),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn helper.fn(...resolvedArgs);\n\t\t\t}\n\t\t}\n\t\t// Unknown sub-expression helper — return undefined\n\t\treturn undefined;\n\t}\n\n\t// PathExpression — navigate through segments in the data object\n\tconst segments = extractPathSegments(expr);\n\tif (segments.length === 0) {\n\t\tthrow new TemplateRuntimeError(\n\t\t\t`Cannot resolve expression of type \"${expr.type}\"`,\n\t\t);\n\t}\n\n\t// Extract the potential identifier from the last segment BEFORE\n\t// checking for $root, so that both {{$root}} and {{$root:N}} are\n\t// handled uniformly.\n\tconst { cleanSegments, identifier } = extractExpressionIdentifier(segments);\n\n\t// $root path traversal ($root.name) — not supported, return undefined\n\t// (the analyzer already rejects it with a diagnostic).\n\tif (isRootPathTraversal(cleanSegments)) {\n\t\treturn undefined;\n\t}\n\n\t// $root → return the entire data context (or identifier data)\n\tif (isRootSegments(cleanSegments)) {\n\t\tif (identifier !== null && identifierData) {\n\t\t\tconst source = identifierData[identifier];\n\t\t\treturn source ?? undefined;\n\t\t}\n\t\tif (identifier !== null) {\n\t\t\t// Template uses an identifier but no identifierData was provided\n\t\t\treturn undefined;\n\t\t}\n\t\treturn data;\n\t}\n\n\tif (identifier !== null && identifierData) {\n\t\tconst source = identifierData[identifier];\n\t\tif (source) {\n\t\t\t// ── Aggregated identifier (array of objects) ──────────────────\n\t\t\t// When the identifier maps to an array of objects (multi-version\n\t\t\t// data), extract the property from each element to produce a\n\t\t\t// result array. E.g. {{accountId:4}} on [{accountId:\"A\"},{accountId:\"B\"}]\n\t\t\t// → [\"A\", \"B\"]\n\t\t\tif (Array.isArray(source)) {\n\t\t\t\treturn source\n\t\t\t\t\t.map((item) => resolveDataPath(item, cleanSegments))\n\t\t\t\t\t.filter((v) => v !== undefined);\n\t\t\t}\n\t\t\treturn resolveDataPath(source, cleanSegments);\n\t\t}\n\t\t// Source does not exist → undefined (like a missing key)\n\t\treturn undefined;\n\t}\n\n\tif (identifier !== null && !identifierData) {\n\t\t// Template uses an identifier but no identifierData was provided\n\t\treturn undefined;\n\t}\n\n\treturn resolveDataPath(data, cleanSegments);\n}\n\n/**\n * Navigates through a data object by following a path of segments.\n *\n * @param data - The data object\n * @param segments - The path segments (e.g. `[\"user\", \"address\", \"city\"]`)\n * @returns The value at the end of the path, or `undefined` if an\n * intermediate segment is null/undefined\n */\nexport function resolveDataPath(data: unknown, segments: string[]): unknown {\n\tlet current: unknown = data;\n\n\tfor (const segment of segments) {\n\t\tif (current === null || current === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (typeof current !== \"object\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcurrent = (current as Record<string, unknown>)[segment];\n\t}\n\n\treturn current;\n}\n\n// ─── Data Merging ────────────────────────────────────────────────────────────\n// For Handlebars rendering (mixed templates / blocks), we cannot intercept\n// resolution on a per-expression basis. Instead, we merge identifier data\n// into the main object using the format `\"key:N\"`.\n//\n// Handlebars parses `{{meetingId:1}}` as a PathExpression with a single\n// segment `\"meetingId:1\"`, so it looks up the key `\"meetingId:1\"` in the\n// data object — which matches our flattened format exactly.\n\n/**\n * Merges the main data with identifier data.\n *\n * @param data - Main data\n * @param identifierData - Data by identifier\n * @returns A merged object where identifier data appears as `\"key:N\"` keys\n *\n * @example\n * ```\n * mergeDataWithIdentifiers(\n * { name: \"Alice\" },\n * { 1: { meetingId: \"val1\" }, 2: { meetingId: \"val2\" } }\n * )\n * // → { name: \"Alice\", \"meetingId:1\": \"val1\", \"meetingId:2\": \"val2\" }\n * ```\n */\nfunction mergeDataWithIdentifiers(\n\tdata: unknown,\n\tidentifierData?: IdentifierData,\n): Record<string, unknown> {\n\t// Always include $root so that Handlebars can resolve {{$root}} in\n\t// mixed templates and block helpers (where we delegate to Handlebars\n\t// instead of resolving expressions ourselves).\n\t// When data is a primitive (e.g. number passed with {{$root}}), we\n\t// wrap it into an object so Handlebars can still function.\n\tconst base: Record<string, unknown> =\n\t\tdata !== null && typeof data === \"object\" && !Array.isArray(data)\n\t\t\t? (data as Record<string, unknown>)\n\t\t\t: {};\n\tconst merged: Record<string, unknown> = { ...base, [ROOT_TOKEN]: data };\n\n\tif (!identifierData) return merged;\n\n\tfor (const [id, idData] of Object.entries(identifierData)) {\n\t\t// Add `$root:N` so Handlebars can resolve {{$root:N}} in mixed/block\n\t\t// templates (where we delegate to Handlebars instead of resolving\n\t\t// expressions ourselves). The value is the entire identifier data\n\t\t// object (or array for aggregated identifiers).\n\t\tmerged[`${ROOT_TOKEN}:${id}`] = idData;\n\n\t\t// ── Aggregated identifier (array of objects) ─────────────────\n\t\t// When the identifier data is an array (multi-version), we cannot\n\t\t// flatten individual properties into `\"key:N\"` keys because there\n\t\t// are multiple values per key. The array is only accessible via\n\t\t// `$root:N` (already set above). Handlebars helpers like `map`\n\t\t// can then consume it: `{{ map ($root:4) \"accountId\" }}`.\n\t\tif (Array.isArray(idData)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const [key, value] of Object.entries(idData)) {\n\t\t\tmerged[`${key}:${id}`] = value;\n\t\t}\n\t}\n\n\treturn merged;\n}\n\n// ─── Handlebars Rendering ────────────────────────────────────────────────────\n// For complex templates (blocks, helpers), we delegate to Handlebars.\n// Compilation is cached to avoid costly recompilations.\n\n/**\n * Compiles and executes a template via Handlebars.\n *\n * Uses a compilation cache (LRU) to avoid recompiling the same template\n * on repeated calls. The cache is either:\n * - The global cache (for the standalone `execute()` function)\n * - The instance cache provided via `ExecutorContext` (for `Typebars`)\n *\n * @param template - The template string\n * @param data - The context data\n * @param ctx - Optional execution context (cache, Handlebars env)\n * @returns Always a string\n */\nfunction renderWithHandlebars(\n\ttemplate: string,\n\tdata: Record<string, unknown>,\n\tctx?: ExecutorContext,\n): string {\n\ttry {\n\t\t// 1. Use the pre-compiled template if available (CompiledTemplate)\n\t\tif (ctx?.compiledTemplate) {\n\t\t\treturn ctx.compiledTemplate(data);\n\t\t}\n\n\t\t// 2. Look up in the cache (instance or global)\n\t\tconst cache = ctx?.compilationCache ?? globalCompilationCache;\n\t\tconst hbs = ctx?.hbs ?? Handlebars;\n\n\t\tlet compiled = cache.get(template);\n\t\tif (!compiled) {\n\t\t\tcompiled = hbs.compile(template, {\n\t\t\t\t// Disable HTML-escaping by default — this engine is not\n\t\t\t\t// HTML-specific, we want raw values.\n\t\t\t\tnoEscape: true,\n\t\t\t\t// Strict mode: throws if a path does not exist in the data.\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t\tcache.set(template, compiled);\n\t\t}\n\n\t\treturn compiled(data);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new TemplateRuntimeError(message);\n\t}\n}\n\n/**\n * Clears the global Handlebars compilation cache.\n * Useful for tests or to free memory.\n */\nexport function clearCompilationCache(): void {\n\tglobalCompilationCache.clear();\n}\n\n// ─── Direct Block Execution ──────────────────────────────────────────────────\n// For conditional blocks (#if/#unless), we can evaluate the condition directly\n// and execute the selected branch through the type-preserving execution paths.\n// This avoids Handlebars stringification when the branch contains helpers that\n// return non-primitive values (e.g. `map` returning arrays).\n\n/**\n * Attempts to execute a conditional block directly by evaluating its condition\n * and executing the selected branch through type-preserving paths.\n *\n * Only handles `#if` and `#unless` blocks. Returns `{ value }` if the branch\n * was executed directly, or `undefined` to fall back to Handlebars rendering.\n */\nfunction tryDirectBlockExecution(\n\tblock: hbs.AST.BlockStatement,\n\tdata: unknown,\n\tctx?: ExecutorContext,\n): { value: unknown } | undefined {\n\tif (block.path.type !== \"PathExpression\") return undefined;\n\tconst helperName = (block.path as hbs.AST.PathExpression).original;\n\n\t// Only handle built-in conditional blocks\n\tif (helperName !== \"if\" && helperName !== \"unless\") return undefined;\n\tif (block.params.length !== 1) return undefined;\n\n\t// Evaluate the condition\n\tconst condition = resolveExpression(\n\t\tblock.params[0] as hbs.AST.Expression,\n\t\tdata,\n\t\tctx?.identifierData,\n\t\tctx?.helpers,\n\t);\n\n\t// Handlebars truthiness: empty arrays are falsy\n\tlet isTruthy: boolean;\n\tif (Array.isArray(condition)) {\n\t\tisTruthy = condition.length > 0;\n\t} else {\n\t\tisTruthy = !!condition;\n\t}\n\tif (helperName === \"unless\") isTruthy = !isTruthy;\n\n\tconst branch = isTruthy ? block.program : block.inverse;\n\tif (!branch) {\n\t\t// No matching branch (e.g. falsy #if with no {{else}}) → empty string\n\t\treturn { value: \"\" };\n\t}\n\n\t// Try to execute the branch as a single expression (preserves types)\n\tconst singleExpr = getEffectivelySingleExpression(branch);\n\tif (singleExpr) {\n\t\tif (singleExpr.params.length === 0 && !singleExpr.hash) {\n\t\t\treturn {\n\t\t\t\tvalue: resolveExpression(\n\t\t\t\t\tsingleExpr.path,\n\t\t\t\t\tdata,\n\t\t\t\t\tctx?.identifierData,\n\t\t\t\t\tctx?.helpers,\n\t\t\t\t),\n\t\t\t};\n\t\t}\n\t\t// Single expression with helper (e.g. {{map users \"name\"}})\n\t\tif (singleExpr.params.length > 0 || singleExpr.hash) {\n\t\t\tconst directResult = tryDirectHelperExecution(singleExpr, data, ctx);\n\t\t\tif (directResult !== undefined) return directResult;\n\t\t}\n\t}\n\n\t// Try to execute the branch as a nested conditional block (recursive)\n\tconst nestedBlock = getEffectivelySingleBlock(branch);\n\tif (nestedBlock) {\n\t\treturn tryDirectBlockExecution(nestedBlock, data, ctx);\n\t}\n\n\t// Branch is too complex for direct execution → fall back\n\treturn undefined;\n}\n\n// ─── Direct Helper Execution ─────────────────────────────────────────────────\n// Some helpers (e.g. `map`) return non-primitive values (arrays, objects)\n// that Handlebars would stringify. For these helpers, we resolve their\n// arguments directly and call the helper's `fn` to preserve the raw value.\n\n/** Set of helper names that must be executed directly (bypass Handlebars) */\nconst DIRECT_EXECUTION_HELPERS = new Set<string>([\n\tDefaultHelpers.DEFAULT_HELPER_NAME,\n\tMapHelpers.MAP_HELPER_NAME,\n]);\n\n/**\n * Attempts to execute a helper directly (without Handlebars rendering).\n *\n * Returns `{ value }` if the helper was executed directly, or `undefined`\n * if the helper should go through the normal Handlebars rendering path.\n *\n * @param stmt - The MustacheStatement containing the helper call\n * @param data - The context data\n * @param ctx - Optional execution context (with helpers and identifierData)\n */\nfunction tryDirectHelperExecution(\n\tstmt: hbs.AST.MustacheStatement,\n\tdata: unknown,\n\tctx?: ExecutorContext,\n): { value: unknown } | undefined {\n\t// Get the helper name from the path\n\tif (stmt.path.type !== \"PathExpression\") return undefined;\n\tconst helperName = (stmt.path as hbs.AST.PathExpression).original;\n\n\t// Only intercept known direct-execution helpers\n\tif (!DIRECT_EXECUTION_HELPERS.has(helperName)) return undefined;\n\n\t// Look up the helper definition\n\tconst helper = ctx?.helpers?.get(helperName);\n\tif (!helper) return undefined;\n\n\t// Resolve each argument from the data context.\n\t// For the `map` helper, the resolution strategy is:\n\t// - Arg 0 (array): resolve as a data path (e.g. `users` → array)\n\t// - Arg 1 (property): must be a StringLiteral (e.g. `\"name\"`)\n\t// The analyzer enforces this — bare identifiers like `name` are\n\t// rejected at analysis time because Handlebars would resolve them\n\t// as a data path instead of a literal property name.\n\tconst isMap = helperName === MapHelpers.MAP_HELPER_NAME;\n\n\tconst resolvedArgs: unknown[] = [];\n\tfor (let i = 0; i < stmt.params.length; i++) {\n\t\tconst param = stmt.params[i] as hbs.AST.Expression;\n\n\t\t// For `map`, the second argument (index 1) is a property name —\n\t\t// it must be a StringLiteral (enforced by the analyzer).\n\t\tif (isMap && i === 1) {\n\t\t\tif (param.type === \"StringLiteral\") {\n\t\t\t\tresolvedArgs.push((param as hbs.AST.StringLiteral).value);\n\t\t\t} else {\n\t\t\t\t// Fallback: resolve normally (will likely be undefined at runtime)\n\t\t\t\tresolvedArgs.push(\n\t\t\t\t\tresolveExpression(param, data, ctx?.identifierData, ctx?.helpers),\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tresolvedArgs.push(\n\t\t\t\tresolveExpression(param, data, ctx?.identifierData, ctx?.helpers),\n\t\t\t);\n\t\t}\n\t}\n\n\t// Call the helper's fn directly with the resolved arguments\n\tconst value = helper.fn(...resolvedArgs);\n\treturn { value };\n}\n"],"names":["clearCompilationCache","execute","executeFromAst","resolveDataPath","globalCompilationCache","LRUCache","template","data","identifierData","dispatchExecute","undefined","tpl","ast","parse","child","ctx","isSingleExpression","stmt","body","params","length","hash","resolveExpression","path","helpers","singleExpr","getEffectivelySingleExpression","directResult","tryDirectHelperExecution","value","merged","mergeDataWithIdentifiers","raw","renderWithHandlebars","coerceValue","coerceSchema","canUseFastPath","executeFastPath","singleBlock","getEffectivelySingleBlock","tryDirectBlockExecution","effective","getEffectiveBody","allContent","every","s","type","targetType","trimmed","trim","num","Number","isNaN","isInteger","lower","toLowerCase","coerceLiteral","result","String","expr","isThisExpression","subExpr","helperName","original","helper","get","isMap","MapHelpers","MAP_HELPER_NAME","resolvedArgs","i","param","push","fn","segments","extractPathSegments","TemplateRuntimeError","cleanSegments","identifier","extractExpressionIdentifier","isRootPathTraversal","isRootSegments","source","Array","isArray","map","item","filter","v","current","segment","base","ROOT_TOKEN","id","idData","Object","entries","key","compiledTemplate","cache","compilationCache","hbs","Handlebars","compiled","compile","noEscape","strict","set","error","message","Error","clear","block","condition","isTruthy","branch","program","inverse","nestedBlock","DIRECT_EXECUTION_HELPERS","Set","DefaultHelpers","DEFAULT_HELPER_NAME","has"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { HelperDefinition } from "../types.js";
2
+ import { HelperFactory } from "./helper-factory.js";
3
+ export declare class DefaultHelpers extends HelperFactory {
4
+ /** The name used for special-case detection in the analyzer/executor */
5
+ static readonly DEFAULT_HELPER_NAME = "default";
6
+ protected buildDefinitions(defs: Map<string, HelperDefinition>): void;
7
+ /** Registers the `default` helper */
8
+ private registerDefault;
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"DefaultHelpers",{enumerable:true,get:function(){return DefaultHelpers}});const _helperfactoryts=require("./helper-factory.js");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}function isHandlebarsOptions(value){return value!==null&&typeof value==="object"&&"hash"in value&&"name"in value}function defaultValue(...args){const candidates=args.filter(a=>!isHandlebarsOptions(a));for(const candidate of candidates){if(candidate!==null&&candidate!==undefined){return candidate}}return null}class DefaultHelpers extends _helperfactoryts.HelperFactory{buildDefinitions(defs){this.registerDefault(defs)}registerDefault(defs){defs.set(DefaultHelpers.DEFAULT_HELPER_NAME,{fn:defaultValue,params:[{name:"primary",description:"The primary value to use (may be nullish)"},{name:"fallback",description:"One or more fallback values (variadic). The chain must end with a guaranteed value."}],description:'Returns the first non-nullish value from a list of arguments: {{ default userId "anonymous" }}'})}}_define_property(DefaultHelpers,"DEFAULT_HELPER_NAME","default");
2
+ //# sourceMappingURL=default-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/helpers/default-helpers.ts"],"sourcesContent":["import type { HelperDefinition } from \"../types.ts\";\nimport { HelperFactory } from \"./helper-factory.ts\";\n\n// ─── DefaultHelpers ──────────────────────────────────────────────────────────\n// Provides a variadic fallback helper that returns the first non-nullish\n// argument, similar to the `??` (nullish coalescing) chain in JavaScript.\n//\n// - **`default`** — Returns the first non-nullish value from a list of\n// arguments (variables or literals).\n// Usage: `{{ default userId \"anonymous\" }}`\n// `{{ default a b c }}`\n// `{{ default departmentId accountId \"fallback-id\" }}`\n//\n// ─── Registration ────────────────────────────────────────────────────────────\n// DefaultHelpers are automatically pre-registered by the `Typebars`\n// constructor. They can also be registered manually on any object\n// implementing `HelperRegistry`:\n//\n// const factory = new DefaultHelpers();\n// factory.register(engine); // registers all helpers\n// factory.unregister(engine); // removes all helpers\n//\n// ─── Static Analysis ─────────────────────────────────────────────────────────\n// The `default` helper has special static analysis handling in the analyzer:\n// - At least 2 arguments are required\n// - All arguments must have compatible types\n// - The argument chain must terminate with a guaranteed value (a literal,\n// a non-optional property, or a sub-expression). If no argument is\n// guaranteed, a `DEFAULT_NO_GUARANTEED_VALUE` diagnostic error is emitted.\n// - The inferred return type is the union of all argument types (simplified)\n\n// ─── Internal utilities ─────────────────────────────────────────────────────\n\n/**\n * Checks whether a value is a Handlebars options object.\n * Handlebars always passes an options object as the last argument to helpers.\n */\nfunction isHandlebarsOptions(value: unknown): boolean {\n\treturn (\n\t\tvalue !== null &&\n\t\ttypeof value === \"object\" &&\n\t\t\"hash\" in (value as Record<string, unknown>) &&\n\t\t\"name\" in (value as Record<string, unknown>)\n\t);\n}\n\n/**\n * Returns the first non-nullish argument from a variadic argument list.\n * The trailing Handlebars options object is automatically excluded.\n */\nfunction defaultValue(...args: unknown[]): unknown {\n\t// Filter out the trailing Handlebars options object\n\tconst candidates = args.filter((a) => !isHandlebarsOptions(a));\n\n\tfor (const candidate of candidates) {\n\t\tif (candidate !== null && candidate !== undefined) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// ─── Main class ─────────────────────────────────────────────────────────────\n\nexport class DefaultHelpers extends HelperFactory {\n\t/** The name used for special-case detection in the analyzer/executor */\n\tstatic readonly DEFAULT_HELPER_NAME = \"default\";\n\n\t// ─── buildDefinitions (required by HelperFactory) ──────────────────\n\n\tprotected buildDefinitions(defs: Map<string, HelperDefinition>): void {\n\t\tthis.registerDefault(defs);\n\t}\n\n\t// ── default ──────────────────────────────────────────────────────────\n\n\t/** Registers the `default` helper */\n\tprivate registerDefault(defs: Map<string, HelperDefinition>): void {\n\t\tdefs.set(DefaultHelpers.DEFAULT_HELPER_NAME, {\n\t\t\tfn: defaultValue,\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"primary\",\n\t\t\t\t\tdescription: \"The primary value to use (may be nullish)\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"fallback\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"One or more fallback values (variadic). The chain must end with a guaranteed value.\",\n\t\t\t\t},\n\t\t\t],\n\t\t\t// No static returnType — the analyzer infers it from the arguments\n\t\t\tdescription:\n\t\t\t\t'Returns the first non-nullish value from a list of arguments: {{ default userId \"anonymous\" }}',\n\t\t});\n\t}\n}\n"],"names":["DefaultHelpers","isHandlebarsOptions","value","defaultValue","args","candidates","filter","a","candidate","undefined","HelperFactory","buildDefinitions","defs","registerDefault","set","DEFAULT_HELPER_NAME","fn","params","name","description"],"mappings":"oGAiEaA,wDAAAA,iDAhEiB,2MAoC9B,SAASC,oBAAoBC,KAAc,EAC1C,OACCA,QAAU,MACV,OAAOA,QAAU,UACjB,SAAWA,OACX,SAAWA,KAEb,CAMA,SAASC,aAAa,GAAGC,IAAe,EAEvC,MAAMC,WAAaD,KAAKE,MAAM,CAAC,AAACC,GAAM,CAACN,oBAAoBM,IAE3D,IAAK,MAAMC,aAAaH,WAAY,CACnC,GAAIG,YAAc,MAAQA,YAAcC,UAAW,CAClD,OAAOD,SACR,CACD,CAEA,OAAO,IACR,CAIO,MAAMR,uBAAuBU,8BAAa,CAMhD,AAAUC,iBAAiBC,IAAmC,CAAQ,CACrE,IAAI,CAACC,eAAe,CAACD,KACtB,CAKA,AAAQC,gBAAgBD,IAAmC,CAAQ,CAClEA,KAAKE,GAAG,CAACd,eAAee,mBAAmB,CAAE,CAC5CC,GAAIb,aACJc,OAAQ,CACP,CACCC,KAAM,UACNC,YAAa,2CACd,EACA,CACCD,KAAM,WACNC,YACC,qFACF,EACA,CAEDA,YACC,gGACF,EACD,CACD,CA9BC,iBAFYnB,eAEIe,sBAAsB"}
@@ -1,3 +1,4 @@
1
+ export { DefaultHelpers } from "./default-helpers.js";
1
2
  export { HelperFactory, type HelperRegistry } from "./helper-factory.js";
2
3
  export { LogicalHelpers } from "./logical-helpers.js";
3
4
  export { MapHelpers } from "./map-helpers.js";
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get HelperFactory(){return _helperfactory.HelperFactory},get LogicalHelpers(){return _logicalhelpers.LogicalHelpers},get MapHelpers(){return _maphelpers.MapHelpers},get MathHelpers(){return _mathhelpers.MathHelpers},get toNumber(){return _utils.toNumber}});const _helperfactory=require("./helper-factory.js");const _logicalhelpers=require("./logical-helpers.js");const _maphelpers=require("./map-helpers.js");const _mathhelpers=require("./math-helpers.js");const _utils=require("./utils.js");
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get DefaultHelpers(){return _defaulthelpers.DefaultHelpers},get HelperFactory(){return _helperfactory.HelperFactory},get LogicalHelpers(){return _logicalhelpers.LogicalHelpers},get MapHelpers(){return _maphelpers.MapHelpers},get MathHelpers(){return _mathhelpers.MathHelpers},get toNumber(){return _utils.toNumber}});const _defaulthelpers=require("./default-helpers.js");const _helperfactory=require("./helper-factory.js");const _logicalhelpers=require("./logical-helpers.js");const _maphelpers=require("./map-helpers.js");const _mathhelpers=require("./math-helpers.js");const _utils=require("./utils.js");
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/helpers/index.ts"],"sourcesContent":["export { HelperFactory, type HelperRegistry } from \"./helper-factory\";\nexport { LogicalHelpers } from \"./logical-helpers\";\nexport { MapHelpers } from \"./map-helpers\";\nexport { MathHelpers } from \"./math-helpers\";\nexport { toNumber } from \"./utils\";\n"],"names":["HelperFactory","LogicalHelpers","MapHelpers","MathHelpers","toNumber"],"mappings":"mPAASA,uBAAAA,4BAAa,MACbC,wBAAAA,8BAAc,MACdC,oBAAAA,sBAAU,MACVC,qBAAAA,wBAAW,MACXC,kBAAAA,eAAQ,iCAJkC,kDACpB,+CACJ,4CACC,uCACH"}
1
+ {"version":3,"sources":["../../../src/helpers/index.ts"],"sourcesContent":["export { DefaultHelpers } from \"./default-helpers\";\nexport { HelperFactory, type HelperRegistry } from \"./helper-factory\";\nexport { LogicalHelpers } from \"./logical-helpers\";\nexport { MapHelpers } from \"./map-helpers\";\nexport { MathHelpers } from \"./math-helpers\";\nexport { toNumber } from \"./utils\";\n"],"names":["DefaultHelpers","HelperFactory","LogicalHelpers","MapHelpers","MathHelpers","toNumber"],"mappings":"mPAASA,wBAAAA,8BAAc,MACdC,uBAAAA,4BAAa,MACbC,wBAAAA,8BAAc,MACdC,oBAAAA,sBAAU,MACVC,qBAAAA,wBAAW,MACXC,kBAAAA,eAAQ,kCALc,kDACoB,kDACpB,+CACJ,4CACC,uCACH"}
@@ -110,6 +110,23 @@ export declare function resolveSchemaPath(schema: JSONSchema7, path: string[]):
110
110
  * @param root - The root schema (for resolving $refs)
111
111
  */
112
112
  export declare function resolveArrayItems(schema: JSONSchema7, root: JSONSchema7): JSONSchema7 | undefined;
113
+ /**
114
+ * Checks whether a property at the given path is **required** in its parent
115
+ * object schema. This navigates the schema segment by segment and checks
116
+ * the `required` array of the parent object for the last segment.
117
+ *
118
+ * For multi-segment paths (e.g. `["user", "name"]`), each intermediate
119
+ * segment is navigated and the check applies only to the final segment
120
+ * within its immediate parent.
121
+ *
122
+ * Returns `true` if the property is explicitly listed in the parent's
123
+ * `required` array. Returns `false` otherwise (including when the path
124
+ * cannot be resolved).
125
+ *
126
+ * @param schema - The root schema describing the template context
127
+ * @param path - Array of segments (property names) leading to the property
128
+ */
129
+ export declare function isPropertyRequired(schema: JSONSchema7, path: string[]): boolean;
113
130
  /**
114
131
  * Simplifies an output schema to avoid unnecessarily complex constructs
115
132
  * (e.g. `oneOf` with a single element, duplicates, etc.).
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get assertNoConditionalSchema(){return assertNoConditionalSchema},get findConditionalSchemaLocations(){return findConditionalSchemaLocations},get resolveArrayItems(){return resolveArrayItems},get resolveRef(){return resolveRef},get resolveSchemaPath(){return resolveSchemaPath},get simplifySchema(){return simplifySchema}});const _errorsts=require("./errors.js");const _utilsts=require("./utils.js");function findConditionalSchemaLocations(schema,path="",visited=new Set){const locations=[];if(visited.has(schema))return locations;visited.add(schema);for(const kw of["if","then","else"]){if(schema[kw]!==undefined){locations.push({keyword:"if/then/else",schemaPath:path||"/"});break}}if(schema.properties){for(const[key,prop]of Object.entries(schema.properties)){if(prop&&typeof prop!=="boolean"){locations.push(...findConditionalSchemaLocations(prop,`${path}/properties/${key}`,visited))}}}if(schema.additionalProperties&&typeof schema.additionalProperties==="object"){locations.push(...findConditionalSchemaLocations(schema.additionalProperties,`${path}/additionalProperties`,visited))}if(schema.items){if(Array.isArray(schema.items)){for(let i=0;i<schema.items.length;i++){const item=schema.items[i];if(item&&typeof item!=="boolean"){locations.push(...findConditionalSchemaLocations(item,`${path}/items/${i}`,visited))}}}else if(typeof schema.items!=="boolean"){locations.push(...findConditionalSchemaLocations(schema.items,`${path}/items`,visited))}}for(const keyword of["allOf","anyOf","oneOf"]){const branches=schema[keyword];if(branches){for(let i=0;i<branches.length;i++){const branch=branches[i];if(branch&&typeof branch!=="boolean"){locations.push(...findConditionalSchemaLocations(branch,`${path}/${keyword}/${i}`,visited))}}}}if(schema.not&&typeof schema.not!=="boolean"){locations.push(...findConditionalSchemaLocations(schema.not,`${path}/not`,visited))}for(const defsKey of["definitions","$defs"]){const defs=schema[defsKey];if(defs){for(const[name,def]of Object.entries(defs)){if(def&&typeof def!=="boolean"){locations.push(...findConditionalSchemaLocations(def,`${path}/${defsKey}/${name}`,visited))}}}}return locations}function assertNoConditionalSchema(schema,path="",visited=new Set){const locations=findConditionalSchemaLocations(schema,path,visited);if(locations.length>0){const first=locations[0];throw new _errorsts.UnsupportedSchemaError(first.keyword,first.schemaPath)}}function resolveRef(schema,root){if(!schema.$ref)return schema;const ref=schema.$ref;const match=ref.match(/^#\/(definitions|\$defs)\/(.+)$/);if(!match){throw new Error(`Unsupported $ref format: "${ref}". Only internal #/definitions/ references are supported.`)}const defsKey=match[1];const name=match[2]??"";const defs=defsKey==="definitions"?root.definitions:root.$defs;if(!defs||!(name in defs)){throw new Error(`Cannot resolve $ref "${ref}": definition "${name}" not found.`)}const def=defs[name];if(!def||typeof def==="boolean"){throw new Error(`Cannot resolve $ref "${ref}": definition "${name}" not found.`)}return resolveRef(def,root)}function resolveSegment(schema,segment,root){const resolved=resolveRef(schema,root);if(resolved.properties&&segment in resolved.properties){const prop=resolved.properties[segment];if(prop&&typeof prop!=="boolean")return resolveRef(prop,root);if(prop===true)return{}}if(resolved.additionalProperties!==undefined&&resolved.additionalProperties!==false){if(resolved.additionalProperties===true){return{}}return resolveRef(resolved.additionalProperties,root)}const schemaType=resolved.type;const isArray=schemaType==="array"||Array.isArray(schemaType)&&schemaType.includes("array");if(isArray&&segment==="length"){return{type:"integer"}}if(isArray&&/^\d+$/.test(segment)){if(resolved.items===undefined){return{}}if(typeof resolved.items==="boolean"){return{}}if(Array.isArray(resolved.items)){const idx=Number.parseInt(segment,10);const item=resolved.items[idx];if(item!==undefined&&typeof item!=="boolean"){return resolveRef(item,root)}if(item!==undefined&&typeof item==="boolean"){return{}}if(resolved.additionalItems===false){return undefined}if(resolved.additionalItems!==undefined&&resolved.additionalItems!==true&&typeof resolved.additionalItems==="object"){return resolveRef(resolved.additionalItems,root)}return{}}return resolveRef(resolved.items,root)}const combinatorResult=resolveInCombinators(resolved,segment,root);if(combinatorResult)return combinatorResult;return undefined}function resolveInCombinators(schema,segment,root){if(schema.allOf){const matches=schema.allOf.filter(b=>typeof b!=="boolean").map(branch=>resolveSegment(branch,segment,root)).filter(s=>s!==undefined);if(matches.length===1)return matches[0];if(matches.length>1)return{allOf:matches}}for(const key of["anyOf","oneOf"]){if(!schema[key])continue;const matches=schema[key].filter(b=>typeof b!=="boolean").map(branch=>resolveSegment(branch,segment,root)).filter(s=>s!==undefined);if(matches.length===1)return matches[0];if(matches.length>1)return{[key]:matches}}return undefined}function resolveSchemaPath(schema,path){if(path.length===0)return resolveRef(schema,schema);let current=resolveRef(schema,schema);const root=schema;for(const segment of path){const next=resolveSegment(current,segment,root);if(next===undefined)return undefined;current=next}return current}function resolveArrayItems(schema,root){const resolved=resolveRef(schema,root);const schemaType=resolved.type;const isArray=schemaType==="array"||Array.isArray(schemaType)&&schemaType.includes("array");if(!isArray&&resolved.items===undefined){return undefined}if(resolved.items===undefined){return{}}if(typeof resolved.items==="boolean"){return{}}if(Array.isArray(resolved.items)){const schemas=resolved.items.filter(item=>typeof item!=="boolean").map(item=>resolveRef(item,root));if(schemas.length===0)return{};return{oneOf:schemas}}return resolveRef(resolved.items,root)}function simplifySchema(schema){for(const key of["oneOf","anyOf"]){const arr=schema[key];if(arr&&arr.length===1){const first=arr[0];if(first!==undefined&&typeof first!=="boolean")return simplifySchema(first)}}if(schema.allOf&&schema.allOf.length===1){const first=schema.allOf[0];if(first!==undefined&&typeof first!=="boolean")return simplifySchema(first)}let result=schema;for(const key of["oneOf","anyOf"]){const arr=result[key];if(arr&&arr.length>1){const unique=[];for(const entry of arr){if(typeof entry==="boolean")continue;const simplified=simplifySchema(entry);const isDuplicate=unique.some(existing=>(0,_utilsts.deepEqual)(existing,simplified));if(!isDuplicate){unique.push(simplified)}}if(unique.length===1)return unique[0];result={...result,[key]:unique}}}if(result.allOf&&result.allOf.length>1){const simplifiedBranches=result.allOf.map(branch=>{if(typeof branch==="boolean"||branch===undefined)return branch;return simplifySchema(branch)});result={...result,allOf:simplifiedBranches}}if(result.properties){const simplifiedProps={};let changed=false;for(const[key,prop]of Object.entries(result.properties)){if(prop&&typeof prop!=="boolean"){const simplified=simplifySchema(prop);simplifiedProps[key]=simplified;if(simplified!==prop)changed=true}else{simplifiedProps[key]=prop}}if(changed){result={...result,properties:simplifiedProps}}}if(result.items){if(Array.isArray(result.items)){let itemsChanged=false;const simplifiedItems=result.items.map(item=>{if(item&&typeof item!=="boolean"){const simplified=simplifySchema(item);if(simplified!==item)itemsChanged=true;return simplified}return item});if(itemsChanged){result={...result,items:simplifiedItems}}}else if(typeof result.items!=="boolean"){const simplified=simplifySchema(result.items);if(simplified!==result.items){result={...result,items:simplified}}}}if(result.additionalProperties&&typeof result.additionalProperties==="object"){const simplified=simplifySchema(result.additionalProperties);if(simplified!==result.additionalProperties){result={...result,additionalProperties:simplified}}}return result}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get assertNoConditionalSchema(){return assertNoConditionalSchema},get findConditionalSchemaLocations(){return findConditionalSchemaLocations},get isPropertyRequired(){return isPropertyRequired},get resolveArrayItems(){return resolveArrayItems},get resolveRef(){return resolveRef},get resolveSchemaPath(){return resolveSchemaPath},get simplifySchema(){return simplifySchema}});const _errorsts=require("./errors.js");const _utilsts=require("./utils.js");function findConditionalSchemaLocations(schema,path="",visited=new Set){const locations=[];if(visited.has(schema))return locations;visited.add(schema);for(const kw of["if","then","else"]){if(schema[kw]!==undefined){locations.push({keyword:"if/then/else",schemaPath:path||"/"});break}}if(schema.properties){for(const[key,prop]of Object.entries(schema.properties)){if(prop&&typeof prop!=="boolean"){locations.push(...findConditionalSchemaLocations(prop,`${path}/properties/${key}`,visited))}}}if(schema.additionalProperties&&typeof schema.additionalProperties==="object"){locations.push(...findConditionalSchemaLocations(schema.additionalProperties,`${path}/additionalProperties`,visited))}if(schema.items){if(Array.isArray(schema.items)){for(let i=0;i<schema.items.length;i++){const item=schema.items[i];if(item&&typeof item!=="boolean"){locations.push(...findConditionalSchemaLocations(item,`${path}/items/${i}`,visited))}}}else if(typeof schema.items!=="boolean"){locations.push(...findConditionalSchemaLocations(schema.items,`${path}/items`,visited))}}for(const keyword of["allOf","anyOf","oneOf"]){const branches=schema[keyword];if(branches){for(let i=0;i<branches.length;i++){const branch=branches[i];if(branch&&typeof branch!=="boolean"){locations.push(...findConditionalSchemaLocations(branch,`${path}/${keyword}/${i}`,visited))}}}}if(schema.not&&typeof schema.not!=="boolean"){locations.push(...findConditionalSchemaLocations(schema.not,`${path}/not`,visited))}for(const defsKey of["definitions","$defs"]){const defs=schema[defsKey];if(defs){for(const[name,def]of Object.entries(defs)){if(def&&typeof def!=="boolean"){locations.push(...findConditionalSchemaLocations(def,`${path}/${defsKey}/${name}`,visited))}}}}return locations}function assertNoConditionalSchema(schema,path="",visited=new Set){const locations=findConditionalSchemaLocations(schema,path,visited);if(locations.length>0){const first=locations[0];throw new _errorsts.UnsupportedSchemaError(first.keyword,first.schemaPath)}}function resolveRef(schema,root){if(!schema.$ref)return schema;const ref=schema.$ref;const match=ref.match(/^#\/(definitions|\$defs)\/(.+)$/);if(!match){throw new Error(`Unsupported $ref format: "${ref}". Only internal #/definitions/ references are supported.`)}const defsKey=match[1];const name=match[2]??"";const defs=defsKey==="definitions"?root.definitions:root.$defs;if(!defs||!(name in defs)){throw new Error(`Cannot resolve $ref "${ref}": definition "${name}" not found.`)}const def=defs[name];if(!def||typeof def==="boolean"){throw new Error(`Cannot resolve $ref "${ref}": definition "${name}" not found.`)}return resolveRef(def,root)}function resolveSegment(schema,segment,root){const resolved=resolveRef(schema,root);if(resolved.properties&&segment in resolved.properties){const prop=resolved.properties[segment];if(prop&&typeof prop!=="boolean")return resolveRef(prop,root);if(prop===true)return{}}if(resolved.additionalProperties!==undefined&&resolved.additionalProperties!==false){if(resolved.additionalProperties===true){return{}}return resolveRef(resolved.additionalProperties,root)}const schemaType=resolved.type;const isArray=schemaType==="array"||Array.isArray(schemaType)&&schemaType.includes("array");if(isArray&&segment==="length"){return{type:"integer"}}if(isArray&&/^\d+$/.test(segment)){if(resolved.items===undefined){return{}}if(typeof resolved.items==="boolean"){return{}}if(Array.isArray(resolved.items)){const idx=Number.parseInt(segment,10);const item=resolved.items[idx];if(item!==undefined&&typeof item!=="boolean"){return resolveRef(item,root)}if(item!==undefined&&typeof item==="boolean"){return{}}if(resolved.additionalItems===false){return undefined}if(resolved.additionalItems!==undefined&&resolved.additionalItems!==true&&typeof resolved.additionalItems==="object"){return resolveRef(resolved.additionalItems,root)}return{}}return resolveRef(resolved.items,root)}const combinatorResult=resolveInCombinators(resolved,segment,root);if(combinatorResult)return combinatorResult;return undefined}function resolveInCombinators(schema,segment,root){if(schema.allOf){const matches=schema.allOf.filter(b=>typeof b!=="boolean").map(branch=>resolveSegment(branch,segment,root)).filter(s=>s!==undefined);if(matches.length===1)return matches[0];if(matches.length>1)return{allOf:matches}}for(const key of["anyOf","oneOf"]){if(!schema[key])continue;const matches=schema[key].filter(b=>typeof b!=="boolean").map(branch=>resolveSegment(branch,segment,root)).filter(s=>s!==undefined);if(matches.length===1)return matches[0];if(matches.length>1)return{[key]:matches}}return undefined}function resolveSchemaPath(schema,path){if(path.length===0)return resolveRef(schema,schema);let current=resolveRef(schema,schema);const root=schema;for(const segment of path){const next=resolveSegment(current,segment,root);if(next===undefined)return undefined;current=next}return current}function resolveArrayItems(schema,root){const resolved=resolveRef(schema,root);const schemaType=resolved.type;const isArray=schemaType==="array"||Array.isArray(schemaType)&&schemaType.includes("array");if(!isArray&&resolved.items===undefined){return undefined}if(resolved.items===undefined){return{}}if(typeof resolved.items==="boolean"){return{}}if(Array.isArray(resolved.items)){const schemas=resolved.items.filter(item=>typeof item!=="boolean").map(item=>resolveRef(item,root));if(schemas.length===0)return{};return{oneOf:schemas}}return resolveRef(resolved.items,root)}function isPropertyRequired(schema,path){if(path.length===0)return true;const root=schema;let parent=resolveRef(schema,root);for(let i=0;i<path.length-1;i++){const segment=path[i];const next=resolveSegment(parent,segment,root);if(next===undefined)return false;parent=next}const lastSegment=path[path.length-1];if(isRequiredInSchema(parent,lastSegment))return true;return isRequiredInCombinators(parent,lastSegment)}function isRequiredInSchema(schema,property){const resolved=schema.$ref?resolveRef(schema,schema):schema;return Array.isArray(resolved.required)&&resolved.required.includes(property)}function isRequiredInCombinators(schema,property){if(schema.allOf){for(const branch of schema.allOf){if(typeof branch==="boolean")continue;if(isRequiredInSchema(branch,property))return true}}for(const key of["anyOf","oneOf"]){const arr=schema[key];if(!arr||arr.length===0)continue;const nonBoolBranches=arr.filter(b=>typeof b!=="boolean");if(nonBoolBranches.length>0&&nonBoolBranches.every(branch=>isRequiredInSchema(branch,property))){return true}}return false}function simplifySchema(schema){for(const key of["oneOf","anyOf"]){const arr=schema[key];if(arr&&arr.length===1){const first=arr[0];if(first!==undefined&&typeof first!=="boolean")return simplifySchema(first)}}if(schema.allOf&&schema.allOf.length===1){const first=schema.allOf[0];if(first!==undefined&&typeof first!=="boolean")return simplifySchema(first)}let result=schema;for(const key of["oneOf","anyOf"]){const arr=result[key];if(arr&&arr.length>1){const unique=[];for(const entry of arr){if(typeof entry==="boolean")continue;const simplified=simplifySchema(entry);const isDuplicate=unique.some(existing=>(0,_utilsts.deepEqual)(existing,simplified));if(!isDuplicate){unique.push(simplified)}}if(unique.length===1)return unique[0];result={...result,[key]:unique}}}if(result.allOf&&result.allOf.length>1){const simplifiedBranches=result.allOf.map(branch=>{if(typeof branch==="boolean"||branch===undefined)return branch;return simplifySchema(branch)});result={...result,allOf:simplifiedBranches}}if(result.properties){const simplifiedProps={};let changed=false;for(const[key,prop]of Object.entries(result.properties)){if(prop&&typeof prop!=="boolean"){const simplified=simplifySchema(prop);simplifiedProps[key]=simplified;if(simplified!==prop)changed=true}else{simplifiedProps[key]=prop}}if(changed){result={...result,properties:simplifiedProps}}}if(result.items){if(Array.isArray(result.items)){let itemsChanged=false;const simplifiedItems=result.items.map(item=>{if(item&&typeof item!=="boolean"){const simplified=simplifySchema(item);if(simplified!==item)itemsChanged=true;return simplified}return item});if(itemsChanged){result={...result,items:simplifiedItems}}}else if(typeof result.items!=="boolean"){const simplified=simplifySchema(result.items);if(simplified!==result.items){result={...result,items:simplified}}}}if(result.additionalProperties&&typeof result.additionalProperties==="object"){const simplified=simplifySchema(result.additionalProperties);if(simplified!==result.additionalProperties){result={...result,additionalProperties:simplified}}}return result}
2
2
  //# sourceMappingURL=schema-resolver.js.map
@@ -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 scans a JSON Schema tree for `if/then/else` conditional keywords\n * and returns their locations as an array of `{ keyword, schemaPath }` objects.\n *\n * This is the non-throwing counterpart of `assertNoConditionalSchema`.\n * It 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 scan\n * @param path - The current JSON pointer path (for location reporting)\n * @param visited - Set of already-visited schema objects (cycle protection)\n * @returns Array of locations where `if/then/else` keywords were found\n *\n * @example\n * ```\n * // Returns [{ keyword: \"if/then/else\", schemaPath: \"/\" }]:\n * findConditionalSchemaLocations({\n * type: \"object\",\n * if: { properties: { kind: { const: \"a\" } } },\n * then: { properties: { a: { type: \"string\" } } },\n * });\n *\n * // Returns []:\n * findConditionalSchemaLocations({\n * type: \"object\",\n * properties: { name: { type: \"string\" } },\n * });\n * ```\n */\nexport function findConditionalSchemaLocations(\n\tschema: JSONSchema7,\n\tpath = \"\",\n\tvisited: Set<object> = new Set(),\n): Array<{ keyword: string; schemaPath: string }> {\n\tconst locations: Array<{ keyword: string; schemaPath: string }> = [];\n\n\t// Cycle protection — avoid infinite loops on circular schema structures\n\tif (visited.has(schema)) return locations;\n\tvisited.add(schema);\n\n\t// ── Detect if/then/else at the current level ─────────────────────────\n\t// One diagnostic per schema node is enough — no need to report `then`\n\t// and `else` separately if `if` is already present.\n\tfor (const kw of [\"if\", \"then\", \"else\"] as const) {\n\t\tif (schema[kw] !== undefined) {\n\t\t\tlocations.push({ keyword: \"if/then/else\", schemaPath: path || \"/\" });\n\t\t\tbreak;\n\t\t}\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\tlocations.push(\n\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\tprop,\n\t\t\t\t\t\t`${path}/properties/${key}`,\n\t\t\t\t\t\tvisited,\n\t\t\t\t\t),\n\t\t\t\t);\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\tlocations.push(\n\t\t\t...findConditionalSchemaLocations(\n\t\t\t\tschema.additionalProperties,\n\t\t\t\t`${path}/additionalProperties`,\n\t\t\t\tvisited,\n\t\t\t),\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\tlocations.push(\n\t\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t`${path}/items/${i}`,\n\t\t\t\t\t\t\tvisited,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof schema.items !== \"boolean\") {\n\t\t\tlocations.push(\n\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\tschema.items,\n\t\t\t\t\t`${path}/items`,\n\t\t\t\t\tvisited,\n\t\t\t\t),\n\t\t\t);\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\tlocations.push(\n\t\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\t\tbranch,\n\t\t\t\t\t\t\t`${path}/${keyword}/${i}`,\n\t\t\t\t\t\t\tvisited,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\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\tlocations.push(\n\t\t\t...findConditionalSchemaLocations(schema.not, `${path}/not`, visited),\n\t\t);\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\tlocations.push(\n\t\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\t\tdef,\n\t\t\t\t\t\t\t`${path}/${defsKey}/${name}`,\n\t\t\t\t\t\t\tvisited,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn locations;\n}\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 * @deprecated Use `findConditionalSchemaLocations` for diagnostic-based reporting.\n * This function is preserved for backward compatibility.\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\tconst locations = findConditionalSchemaLocations(schema, path, visited);\n\tif (locations.length > 0) {\n\t\t// biome-ignore lint: length check guarantees defined\n\t\tconst first = locations[0]!;\n\t\tthrow new UnsupportedSchemaError(first.keyword, first.schemaPath);\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// ── Phase 1 : Unwrap single-branch combinators ──────────────────────\n\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\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// ── Phase 2 : Deduplicate multi-branch oneOf/anyOf ──────────────────\n\n\tlet result: JSONSchema7 = schema;\n\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = result[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 simplified = simplifySchema(entry);\n\t\t\t\tconst isDuplicate = unique.some((existing) =>\n\t\t\t\t\tdeepEqual(existing, simplified),\n\t\t\t\t);\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tunique.push(simplified);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (unique.length === 1) return unique[0] as JSONSchema7;\n\t\t\tresult = { ...result, [key]: unique };\n\t\t}\n\t}\n\n\t// ── Phase 3 : Recurse into allOf branches (multi-branch) ────────────\n\n\tif (result.allOf && result.allOf.length > 1) {\n\t\tconst simplifiedBranches = result.allOf.map((branch) => {\n\t\t\tif (typeof branch === \"boolean\" || branch === undefined) return branch;\n\t\t\treturn simplifySchema(branch);\n\t\t});\n\t\tresult = { ...result, allOf: simplifiedBranches };\n\t}\n\n\t// ── Phase 4 : Recurse into properties ───────────────────────────────\n\n\tif (result.properties) {\n\t\tconst simplifiedProps: Record<string, JSONSchema7> = {};\n\t\tlet changed = false;\n\t\tfor (const [key, prop] of Object.entries(result.properties)) {\n\t\t\tif (prop && typeof prop !== \"boolean\") {\n\t\t\t\tconst simplified = simplifySchema(prop);\n\t\t\t\tsimplifiedProps[key] = simplified;\n\t\t\t\tif (simplified !== prop) changed = true;\n\t\t\t} else {\n\t\t\t\tsimplifiedProps[key] = prop as unknown as JSONSchema7;\n\t\t\t}\n\t\t}\n\t\tif (changed) {\n\t\t\tresult = { ...result, properties: simplifiedProps };\n\t\t}\n\t}\n\n\t// ── Phase 5 : Recurse into items ────────────────────────────────────\n\n\tif (result.items) {\n\t\tif (Array.isArray(result.items)) {\n\t\t\t// Tuple items\n\t\t\tlet itemsChanged = false;\n\t\t\tconst simplifiedItems = result.items.map((item) => {\n\t\t\t\tif (item && typeof item !== \"boolean\") {\n\t\t\t\t\tconst simplified = simplifySchema(item);\n\t\t\t\t\tif (simplified !== item) itemsChanged = true;\n\t\t\t\t\treturn simplified;\n\t\t\t\t}\n\t\t\t\treturn item;\n\t\t\t});\n\t\t\tif (itemsChanged) {\n\t\t\t\tresult = { ...result, items: simplifiedItems };\n\t\t\t}\n\t\t} else if (typeof result.items !== \"boolean\") {\n\t\t\t// Single items schema\n\t\t\tconst simplified = simplifySchema(result.items);\n\t\t\tif (simplified !== result.items) {\n\t\t\t\tresult = { ...result, items: simplified };\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Phase 6 : Recurse into additionalProperties ─────────────────────\n\n\tif (\n\t\tresult.additionalProperties &&\n\t\ttypeof result.additionalProperties === \"object\"\n\t) {\n\t\tconst simplified = simplifySchema(result.additionalProperties);\n\t\tif (simplified !== result.additionalProperties) {\n\t\t\tresult = { ...result, additionalProperties: simplified };\n\t\t}\n\t}\n\n\treturn result;\n}\n"],"names":["assertNoConditionalSchema","findConditionalSchemaLocations","resolveArrayItems","resolveRef","resolveSchemaPath","simplifySchema","schema","path","visited","Set","locations","has","add","kw","undefined","push","keyword","schemaPath","properties","key","prop","Object","entries","additionalProperties","items","Array","isArray","i","length","item","branches","branch","not","defsKey","defs","name","def","first","UnsupportedSchemaError","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","current","next","schemas","oneOf","arr","result","unique","entry","simplified","isDuplicate","some","existing","deepEqual","simplifiedBranches","simplifiedProps","changed","itemsChanged","simplifiedItems"],"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 scans a JSON Schema tree for `if/then/else` conditional keywords\n * and returns their locations as an array of `{ keyword, schemaPath }` objects.\n *\n * This is the non-throwing counterpart of `assertNoConditionalSchema`.\n * It 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 scan\n * @param path - The current JSON pointer path (for location reporting)\n * @param visited - Set of already-visited schema objects (cycle protection)\n * @returns Array of locations where `if/then/else` keywords were found\n *\n * @example\n * ```\n * // Returns [{ keyword: \"if/then/else\", schemaPath: \"/\" }]:\n * findConditionalSchemaLocations({\n * type: \"object\",\n * if: { properties: { kind: { const: \"a\" } } },\n * then: { properties: { a: { type: \"string\" } } },\n * });\n *\n * // Returns []:\n * findConditionalSchemaLocations({\n * type: \"object\",\n * properties: { name: { type: \"string\" } },\n * });\n * ```\n */\nexport function findConditionalSchemaLocations(\n\tschema: JSONSchema7,\n\tpath = \"\",\n\tvisited: Set<object> = new Set(),\n): Array<{ keyword: string; schemaPath: string }> {\n\tconst locations: Array<{ keyword: string; schemaPath: string }> = [];\n\n\t// Cycle protection — avoid infinite loops on circular schema structures\n\tif (visited.has(schema)) return locations;\n\tvisited.add(schema);\n\n\t// ── Detect if/then/else at the current level ─────────────────────────\n\t// One diagnostic per schema node is enough — no need to report `then`\n\t// and `else` separately if `if` is already present.\n\tfor (const kw of [\"if\", \"then\", \"else\"] as const) {\n\t\tif (schema[kw] !== undefined) {\n\t\t\tlocations.push({ keyword: \"if/then/else\", schemaPath: path || \"/\" });\n\t\t\tbreak;\n\t\t}\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\tlocations.push(\n\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\tprop,\n\t\t\t\t\t\t`${path}/properties/${key}`,\n\t\t\t\t\t\tvisited,\n\t\t\t\t\t),\n\t\t\t\t);\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\tlocations.push(\n\t\t\t...findConditionalSchemaLocations(\n\t\t\t\tschema.additionalProperties,\n\t\t\t\t`${path}/additionalProperties`,\n\t\t\t\tvisited,\n\t\t\t),\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\tlocations.push(\n\t\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t`${path}/items/${i}`,\n\t\t\t\t\t\t\tvisited,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (typeof schema.items !== \"boolean\") {\n\t\t\tlocations.push(\n\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\tschema.items,\n\t\t\t\t\t`${path}/items`,\n\t\t\t\t\tvisited,\n\t\t\t\t),\n\t\t\t);\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\tlocations.push(\n\t\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\t\tbranch,\n\t\t\t\t\t\t\t`${path}/${keyword}/${i}`,\n\t\t\t\t\t\t\tvisited,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\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\tlocations.push(\n\t\t\t...findConditionalSchemaLocations(schema.not, `${path}/not`, visited),\n\t\t);\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\tlocations.push(\n\t\t\t\t\t\t...findConditionalSchemaLocations(\n\t\t\t\t\t\t\tdef,\n\t\t\t\t\t\t\t`${path}/${defsKey}/${name}`,\n\t\t\t\t\t\t\tvisited,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn locations;\n}\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 * @deprecated Use `findConditionalSchemaLocations` for diagnostic-based reporting.\n * This function is preserved for backward compatibility.\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\tconst locations = findConditionalSchemaLocations(schema, path, visited);\n\tif (locations.length > 0) {\n\t\t// biome-ignore lint: length check guarantees defined\n\t\tconst first = locations[0]!;\n\t\tthrow new UnsupportedSchemaError(first.keyword, first.schemaPath);\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 * Checks whether a property at the given path is **required** in its parent\n * object schema. This navigates the schema segment by segment and checks\n * the `required` array of the parent object for the last segment.\n *\n * For multi-segment paths (e.g. `[\"user\", \"name\"]`), each intermediate\n * segment is navigated and the check applies only to the final segment\n * within its immediate parent.\n *\n * Returns `true` if the property is explicitly listed in the parent's\n * `required` array. Returns `false` otherwise (including when the path\n * cannot be resolved).\n *\n * @param schema - The root schema describing the template context\n * @param path - Array of segments (property names) leading to the property\n */\nexport function isPropertyRequired(\n\tschema: JSONSchema7,\n\tpath: string[],\n): boolean {\n\tif (path.length === 0) return true;\n\n\tconst root = schema;\n\tlet parent: JSONSchema7 = resolveRef(schema, root);\n\n\t// Navigate to the parent of the target property\n\tfor (let i = 0; i < path.length - 1; i++) {\n\t\tconst segment = path[i] as string;\n\t\tconst next = resolveSegment(parent, segment, root);\n\t\tif (next === undefined) return false;\n\t\tparent = next;\n\t}\n\n\tconst lastSegment = path[path.length - 1] as string;\n\n\t// Check direct properties + required array\n\tif (isRequiredInSchema(parent, lastSegment)) return true;\n\n\t// Check combinators: for allOf, the property is required if ANY branch\n\t// requires it. For anyOf/oneOf, the property is required only if ALL\n\t// branches require it.\n\treturn isRequiredInCombinators(parent, lastSegment);\n}\n\n/**\n * Checks if a property is in the `required` array of a schema.\n */\nfunction isRequiredInSchema(schema: JSONSchema7, property: string): boolean {\n\tconst resolved = schema.$ref ? resolveRef(schema, schema) : schema;\n\treturn (\n\t\tArray.isArray(resolved.required) && resolved.required.includes(property)\n\t);\n}\n\n/**\n * Checks if a property is required through combinator schemas.\n */\nfunction isRequiredInCombinators(\n\tschema: JSONSchema7,\n\tproperty: string,\n): boolean {\n\t// allOf: required if ANY branch lists it as required\n\tif (schema.allOf) {\n\t\tfor (const branch of schema.allOf) {\n\t\t\tif (typeof branch === \"boolean\") continue;\n\t\t\tif (isRequiredInSchema(branch, property)) return true;\n\t\t}\n\t}\n\n\t// anyOf / oneOf: required only if ALL branches list it as required\n\tfor (const key of [\"anyOf\", \"oneOf\"] as const) {\n\t\tconst arr = schema[key];\n\t\tif (!arr || arr.length === 0) continue;\n\t\tconst nonBoolBranches = arr.filter(\n\t\t\t(b): b is JSONSchema7 => typeof b !== \"boolean\",\n\t\t);\n\t\tif (\n\t\t\tnonBoolBranches.length > 0 &&\n\t\t\tnonBoolBranches.every((branch) => isRequiredInSchema(branch, property))\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\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// ── Phase 1 : Unwrap single-branch combinators ──────────────────────\n\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\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// ── Phase 2 : Deduplicate multi-branch oneOf/anyOf ──────────────────\n\n\tlet result: JSONSchema7 = schema;\n\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = result[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 simplified = simplifySchema(entry);\n\t\t\t\tconst isDuplicate = unique.some((existing) =>\n\t\t\t\t\tdeepEqual(existing, simplified),\n\t\t\t\t);\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tunique.push(simplified);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (unique.length === 1) return unique[0] as JSONSchema7;\n\t\t\tresult = { ...result, [key]: unique };\n\t\t}\n\t}\n\n\t// ── Phase 3 : Recurse into allOf branches (multi-branch) ────────────\n\n\tif (result.allOf && result.allOf.length > 1) {\n\t\tconst simplifiedBranches = result.allOf.map((branch) => {\n\t\t\tif (typeof branch === \"boolean\" || branch === undefined) return branch;\n\t\t\treturn simplifySchema(branch);\n\t\t});\n\t\tresult = { ...result, allOf: simplifiedBranches };\n\t}\n\n\t// ── Phase 4 : Recurse into properties ───────────────────────────────\n\n\tif (result.properties) {\n\t\tconst simplifiedProps: Record<string, JSONSchema7> = {};\n\t\tlet changed = false;\n\t\tfor (const [key, prop] of Object.entries(result.properties)) {\n\t\t\tif (prop && typeof prop !== \"boolean\") {\n\t\t\t\tconst simplified = simplifySchema(prop);\n\t\t\t\tsimplifiedProps[key] = simplified;\n\t\t\t\tif (simplified !== prop) changed = true;\n\t\t\t} else {\n\t\t\t\tsimplifiedProps[key] = prop as unknown as JSONSchema7;\n\t\t\t}\n\t\t}\n\t\tif (changed) {\n\t\t\tresult = { ...result, properties: simplifiedProps };\n\t\t}\n\t}\n\n\t// ── Phase 5 : Recurse into items ────────────────────────────────────\n\n\tif (result.items) {\n\t\tif (Array.isArray(result.items)) {\n\t\t\t// Tuple items\n\t\t\tlet itemsChanged = false;\n\t\t\tconst simplifiedItems = result.items.map((item) => {\n\t\t\t\tif (item && typeof item !== \"boolean\") {\n\t\t\t\t\tconst simplified = simplifySchema(item);\n\t\t\t\t\tif (simplified !== item) itemsChanged = true;\n\t\t\t\t\treturn simplified;\n\t\t\t\t}\n\t\t\t\treturn item;\n\t\t\t});\n\t\t\tif (itemsChanged) {\n\t\t\t\tresult = { ...result, items: simplifiedItems };\n\t\t\t}\n\t\t} else if (typeof result.items !== \"boolean\") {\n\t\t\t// Single items schema\n\t\t\tconst simplified = simplifySchema(result.items);\n\t\t\tif (simplified !== result.items) {\n\t\t\t\tresult = { ...result, items: simplified };\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Phase 6 : Recurse into additionalProperties ─────────────────────\n\n\tif (\n\t\tresult.additionalProperties &&\n\t\ttypeof result.additionalProperties === \"object\"\n\t) {\n\t\tconst simplified = simplifySchema(result.additionalProperties);\n\t\tif (simplified !== result.additionalProperties) {\n\t\t\tresult = { ...result, additionalProperties: simplified };\n\t\t}\n\t}\n\n\treturn result;\n}\n"],"names":["assertNoConditionalSchema","findConditionalSchemaLocations","isPropertyRequired","resolveArrayItems","resolveRef","resolveSchemaPath","simplifySchema","schema","path","visited","Set","locations","has","add","kw","undefined","push","keyword","schemaPath","properties","key","prop","Object","entries","additionalProperties","items","Array","isArray","i","length","item","branches","branch","not","defsKey","defs","name","def","first","UnsupportedSchemaError","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","current","next","schemas","oneOf","parent","lastSegment","isRequiredInSchema","isRequiredInCombinators","property","required","arr","nonBoolBranches","every","result","unique","entry","simplified","isDuplicate","some","existing","deepEqual","simplifiedBranches","simplifiedProps","changed","itemsChanged","simplifiedItems"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"Typebars",{enumerable:true,get:function(){return Typebars}});const _handlebars=/*#__PURE__*/_interop_require_default(require("handlebars"));const _analyzerts=require("./analyzer.js");const _compiledtemplatets=require("./compiled-template.js");const _dispatchts=require("./dispatch.js");const _errorsts=require("./errors.js");const _executorts=require("./executor.js");const _indexts=require("./helpers/index.js");const _parserts=require("./parser.js");const _typests=require("./types.js");const _utils=require("./utils.js");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}function _interop_require_default(obj){return obj&&obj.__esModule?obj:{default:obj}}const DIRECT_EXECUTION_HELPER_NAMES=new Set([_indexts.MapHelpers.MAP_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)}class Typebars{compile(template){if((0,_typests.isArrayInput)(template)){const children=[];for(const element of template){children.push(this.compile(element))}return _compiledtemplatets.CompiledTemplate.fromArray(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if((0,_typests.isObjectInput)(template)){const children={};for(const[key,value]of Object.entries(template)){children[key]=this.compile(value)}return _compiledtemplatets.CompiledTemplate.fromObject(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if((0,_typests.isLiteralInput)(template)){return _compiledtemplatets.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 _compiledtemplatets.CompiledTemplate.fromTemplate(ast,template,options)}analyze(template,inputSchema={},options){return(0,_dispatchts.dispatchAnalyze)(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);return(0,_analyzerts.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((0,_typests.isArrayInput)(template)){return template.every(v=>this.isValidSyntax(v))}if((0,_typests.isObjectInput)(template)){return Object.values(template).every(v=>this.isValidSyntax(v))}if((0,_typests.isLiteralInput)(template))return true;try{this.getCachedAst(template);return true}catch{return false}}execute(template,data,options){return(0,_dispatchts.dispatchExecute)(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);if(options?.schema){const analysis=(0,_analyzerts.analyzeFromAst)(ast,tpl,options.schema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers});if(!analysis.valid){throw new _errorsts.TemplateAnalysisError(analysis.diagnostics)}}return(0,_executorts.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(0,_dispatchts.dispatchAnalyzeAndExecute)(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);const analysis=(0,_analyzerts.analyzeFromAst)(ast,tpl,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers,coerceSchema});if(!analysis.valid){return{analysis,value:undefined}}const value=(0,_executorts.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=(0,_parserts.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.default.create();this.astCache=new _utils.LRUCache(options.astCacheSize??256);this.compilationCache=new _utils.LRUCache(options.compilationCacheSize??256);new _indexts.MathHelpers().register(this);new _indexts.LogicalHelpers().register(this);new _indexts.MapHelpers().register(this);if(options.helpers){for(const helper of options.helpers){const{name,...definition}=helper;this.registerHelper(name,definition)}}}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"Typebars",{enumerable:true,get:function(){return Typebars}});const _handlebars=/*#__PURE__*/_interop_require_default(require("handlebars"));const _analyzerts=require("./analyzer.js");const _compiledtemplatets=require("./compiled-template.js");const _dispatchts=require("./dispatch.js");const _errorsts=require("./errors.js");const _executorts=require("./executor.js");const _indexts=require("./helpers/index.js");const _parserts=require("./parser.js");const _typests=require("./types.js");const _utils=require("./utils.js");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}function _interop_require_default(obj){return obj&&obj.__esModule?obj:{default:obj}}const DIRECT_EXECUTION_HELPER_NAMES=new Set([_indexts.MapHelpers.MAP_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)}class Typebars{compile(template){if((0,_typests.isArrayInput)(template)){const children=[];for(const element of template){children.push(this.compile(element))}return _compiledtemplatets.CompiledTemplate.fromArray(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if((0,_typests.isObjectInput)(template)){const children={};for(const[key,value]of Object.entries(template)){children[key]=this.compile(value)}return _compiledtemplatets.CompiledTemplate.fromObject(children,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if((0,_typests.isLiteralInput)(template)){return _compiledtemplatets.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 _compiledtemplatets.CompiledTemplate.fromTemplate(ast,template,options)}analyze(template,inputSchema={},options){return(0,_dispatchts.dispatchAnalyze)(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);return(0,_analyzerts.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((0,_typests.isArrayInput)(template)){return template.every(v=>this.isValidSyntax(v))}if((0,_typests.isObjectInput)(template)){return Object.values(template).every(v=>this.isValidSyntax(v))}if((0,_typests.isLiteralInput)(template))return true;try{this.getCachedAst(template);return true}catch{return false}}execute(template,data,options){return(0,_dispatchts.dispatchExecute)(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);if(options?.schema){const analysis=(0,_analyzerts.analyzeFromAst)(ast,tpl,options.schema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers});if(!analysis.valid){throw new _errorsts.TemplateAnalysisError(analysis.diagnostics)}}return(0,_executorts.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(0,_dispatchts.dispatchAnalyzeAndExecute)(template,options,(tpl,coerceSchema)=>{const ast=this.getCachedAst(tpl);const analysis=(0,_analyzerts.analyzeFromAst)(ast,tpl,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.helpers,coerceSchema});if(!analysis.valid){return{analysis,value:undefined}}const value=(0,_executorts.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=(0,_parserts.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.default.create();this.astCache=new _utils.LRUCache(options.astCacheSize??256);this.compilationCache=new _utils.LRUCache(options.compilationCacheSize??256);new _indexts.MathHelpers().register(this);new _indexts.LogicalHelpers().register(this);new _indexts.MapHelpers().register(this);new _indexts.DefaultHelpers().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