typebars 1.0.14 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/compiled-template.js +1 -1
- package/dist/cjs/compiled-template.js.map +1 -1
- package/dist/cjs/dispatch.d.ts +4 -0
- package/dist/cjs/dispatch.js +1 -1
- package/dist/cjs/dispatch.js.map +1 -1
- package/dist/cjs/types.d.ts +18 -0
- package/dist/cjs/types.js.map +1 -1
- package/dist/esm/compiled-template.js +1 -1
- package/dist/esm/compiled-template.js.map +1 -1
- package/dist/esm/dispatch.d.ts +4 -0
- package/dist/esm/dispatch.js +1 -1
- package/dist/esm/dispatch.js.map +1 -1
- package/dist/esm/types.d.ts +18 -0
- package/dist/esm/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"CompiledTemplate",{enumerable:true,get:function(){return CompiledTemplate}});const _analyzerts=require("./analyzer.js");const _dispatchts=require("./dispatch.js");const _errorsts=require("./errors.js");const _executorts=require("./executor.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}class CompiledTemplate{get ast(){return this.state.kind==="template"?this.state.ast:null}get template(){return this.state.kind==="template"?this.state.source:""}static fromTemplate(ast,source,options){return new CompiledTemplate({kind:"template",ast,source},options)}static fromLiteral(value,options){return new CompiledTemplate({kind:"literal",value},options)}static fromObject(children,options){return new CompiledTemplate({kind:"object",children},options)}static fromArray(elements,options){return new CompiledTemplate({kind:"array",elements},options)}analyze(inputSchema={},options){const exclude=options?.excludeTemplateExpression===true;switch(this.state.kind){case"array":{const{elements}=this.state;if(exclude){const kept=elements.filter(el=>!isCompiledTemplateWithExpression(el));return(0,_utils.aggregateArrayAnalysis)(kept.length,index=>{const element=kept[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}return(0,_utils.aggregateArrayAnalysis)(elements.length,index=>{const element=elements[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(children).filter(key=>{const child=children[key];return!child||!isCompiledTemplateWithExpression(child)}):Object.keys(children);return(0,_utils.aggregateObjectAnalysis)(keys,key=>{const child=children[key];if(!child)throw new Error(`unreachable: missing child "${key}"`);const childCoerceSchema=(0,_dispatchts.resolveChildCoerceSchema)(coerceSchema,key);return child.analyze(inputSchema,{identifierSchemas:options?.identifierSchemas,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}case"literal":return{valid:true,diagnostics:[],outputSchema:(0,_typests.inferPrimitiveSchema)(this.state.value)};case"template":return(0,_analyzerts.analyzeFromAst)(this.state.ast,this.state.source,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.options.helpers,coerceSchema:options?.coerceSchema})}}validate(inputSchema={},options){const analysis=this.analyze(inputSchema,options);return{valid:analysis.valid,diagnostics:analysis.diagnostics}}execute(data,options){switch(this.state.kind){case"array":{const{elements}=this.state;const result=[];for(const element of
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"CompiledTemplate",{enumerable:true,get:function(){return CompiledTemplate}});const _analyzerts=require("./analyzer.js");const _dispatchts=require("./dispatch.js");const _errorsts=require("./errors.js");const _executorts=require("./executor.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}class CompiledTemplate{get ast(){return this.state.kind==="template"?this.state.ast:null}get template(){return this.state.kind==="template"?this.state.source:""}static fromTemplate(ast,source,options){return new CompiledTemplate({kind:"template",ast,source},options)}static fromLiteral(value,options){return new CompiledTemplate({kind:"literal",value},options)}static fromObject(children,options){return new CompiledTemplate({kind:"object",children},options)}static fromArray(elements,options){return new CompiledTemplate({kind:"array",elements},options)}analyze(inputSchema={},options){const exclude=options?.excludeTemplateExpression===true;switch(this.state.kind){case"array":{const{elements}=this.state;if(exclude){const kept=elements.filter(el=>!isCompiledTemplateWithExpression(el));return(0,_utils.aggregateArrayAnalysis)(kept.length,index=>{const element=kept[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}return(0,_utils.aggregateArrayAnalysis)(elements.length,index=>{const element=elements[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(children).filter(key=>{const child=children[key];return!child||!isCompiledTemplateWithExpression(child)}):Object.keys(children);return(0,_utils.aggregateObjectAnalysis)(keys,key=>{const child=children[key];if(!child)throw new Error(`unreachable: missing child "${key}"`);const childCoerceSchema=(0,_dispatchts.resolveChildCoerceSchema)(coerceSchema,key);return child.analyze(inputSchema,{identifierSchemas:options?.identifierSchemas,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}case"literal":return{valid:true,diagnostics:[],outputSchema:(0,_typests.inferPrimitiveSchema)(this.state.value)};case"template":return(0,_analyzerts.analyzeFromAst)(this.state.ast,this.state.source,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.options.helpers,coerceSchema:options?.coerceSchema})}}validate(inputSchema={},options){const analysis=this.analyze(inputSchema,options);return{valid:analysis.valid,diagnostics:analysis.diagnostics}}execute(data,options){const exclude=options?.excludeTemplateExpression===true;switch(this.state.kind){case"array":{const{elements}=this.state;const effective=exclude?elements.filter(el=>!isCompiledTemplateWithExpression(el)):elements;const result=[];for(const element of effective){result.push(element.execute(data,options))}return result}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(children).filter(key=>{const child=children[key];return!child||!isCompiledTemplateWithExpression(child)}):Object.keys(children);const result={};for(const key of keys){const child=children[key];if(!child)continue;const childCoerceSchema=(0,_dispatchts.resolveChildCoerceSchema)(coerceSchema,key);result[key]=child.execute(data,{...options,coerceSchema:childCoerceSchema})}return result}case"literal":return this.state.value;case"template":{if(exclude&&isCompiledTemplateWithExpression(this)){return null}if(options?.schema){const analysis=this.analyze(options.schema,{identifierSchemas:options.identifierSchemas,coerceSchema:options.coerceSchema});if(!analysis.valid){throw new _errorsts.TemplateAnalysisError(analysis.diagnostics)}}return(0,_executorts.executeFromAst)(this.state.ast,this.state.source,data,this.buildExecutorContext(options))}}}analyzeAndExecute(inputSchema={},data,options){switch(this.state.kind){case"array":{const{elements}=this.state;return(0,_utils.aggregateArrayAnalysisAndExecution)(elements.length,index=>{const element=elements[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyzeAndExecute(inputSchema,data,options)})}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;return(0,_utils.aggregateObjectAnalysisAndExecution)(Object.keys(children),key=>{const child=children[key];if(!child)throw new Error(`unreachable: missing child "${key}"`);const childCoerceSchema=(0,_dispatchts.resolveChildCoerceSchema)(coerceSchema,key);return child.analyzeAndExecute(inputSchema,data,{identifierSchemas:options?.identifierSchemas,identifierData:options?.identifierData,coerceSchema:childCoerceSchema})})}case"literal":return{analysis:{valid:true,diagnostics:[],outputSchema:(0,_typests.inferPrimitiveSchema)(this.state.value)},value:this.state.value};case"template":{const analysis=this.analyze(inputSchema,{identifierSchemas:options?.identifierSchemas,coerceSchema:options?.coerceSchema});if(!analysis.valid){return{analysis,value:undefined}}const value=(0,_executorts.executeFromAst)(this.state.ast,this.state.source,data,this.buildExecutorContext({identifierData:options?.identifierData,coerceSchema:options?.coerceSchema}));return{analysis,value}}}}buildExecutorContext(options){return{identifierData:options?.identifierData,compiledTemplate:this.getOrCompileHbs(),hbs:this.options.hbs,compilationCache:this.options.compilationCache,coerceSchema:options?.coerceSchema,helpers:this.options.helpers}}getOrCompileHbs(){if(!this.hbsCompiled){this.hbsCompiled=this.options.hbs.compile(this.template,{noEscape:true,strict:false})}return this.hbsCompiled}constructor(state,options){_define_property(this,"state",void 0);_define_property(this,"options",void 0);_define_property(this,"hbsCompiled",null);this.state=state;this.options=options}}function isCompiledTemplateWithExpression(ct){return ct.template!==""&&(0,_dispatchts.shouldExcludeEntry)(ct.template)}
|
|
2
2
|
//# sourceMappingURL=compiled-template.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/compiled-template.ts"],"sourcesContent":["import type Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { AnalyzeOptions } from \"./analyzer.ts\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport { resolveChildCoerceSchema, shouldExcludeEntry } from \"./dispatch.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { type ExecutorContext, executeFromAst } from \"./executor.ts\";\nimport type {\n\tAnalysisResult,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateData,\n\tValidationResult,\n} from \"./types.ts\";\nimport { inferPrimitiveSchema } from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n\ttype LRUCache,\n} from \"./utils\";\n\n// ─── CompiledTemplate ────────────────────────────────────────────────────────\n// Pre-parsed template ready to be executed or analyzed without re-parsing.\n//\n// The compile-once / execute-many pattern avoids the cost of Handlebars\n// parsing on every call. The AST is parsed once at compile time, and the\n// Handlebars template is lazily compiled on the first `execute()`.\n//\n// Usage:\n// const tpl = engine.compile(\"Hello {{name}}\");\n// tpl.execute({ name: \"Alice\" }); // no re-parsing\n// tpl.execute({ name: \"Bob\" }); // no re-parsing or recompilation\n// tpl.analyze(schema); // no re-parsing\n//\n// ─── Internal State (TemplateState) ──────────────────────────────────────────\n// CompiledTemplate operates in 4 exclusive modes, modeled by a discriminated\n// union `TemplateState`:\n//\n// - `\"template\"` — parsed Handlebars template (AST + source string)\n// - `\"literal\"` — primitive passthrough value (number, boolean, null)\n// - `\"object\"` — object where each property is a child CompiledTemplate\n// - `\"array\"` — array where each element is a child CompiledTemplate\n//\n// This design eliminates optional fields and `!` assertions in favor of\n// natural TypeScript narrowing via `switch (this.state.kind)`.\n//\n// ─── Advantages Over the Direct API ──────────────────────────────────────────\n// - **Performance**: parsing and compilation happen only once\n// - **Simplified API**: no need to re-pass the template string on each call\n// - **Consistency**: the same AST is used for both analysis and execution\n\n// ─── Internal Types ──────────────────────────────────────────────────────────\n\n/** Internal options passed by Typebars during compilation */\nexport interface CompiledTemplateOptions {\n\t/** Custom helpers registered on the engine */\n\thelpers: Map<string, HelperDefinition>;\n\t/** Isolated Handlebars environment (with registered helpers) */\n\thbs: typeof Handlebars;\n\t/** Compilation cache shared by the engine */\n\tcompilationCache: LRUCache<string, HandlebarsTemplateDelegate>;\n}\n\n/** Discriminated internal state of the CompiledTemplate */\ntype TemplateState =\n\t| {\n\t\t\treadonly kind: \"template\";\n\t\t\treadonly ast: hbs.AST.Program;\n\t\t\treadonly source: string;\n\t }\n\t| { readonly kind: \"literal\"; readonly value: number | boolean | null }\n\t| {\n\t\t\treadonly kind: \"object\";\n\t\t\treadonly children: Record<string, CompiledTemplate>;\n\t }\n\t| {\n\t\t\treadonly kind: \"array\";\n\t\t\treadonly elements: CompiledTemplate[];\n\t };\n\n// ─── Public Class ────────────────────────────────────────────────────────────\n\nexport class CompiledTemplate {\n\t/** Discriminated internal state */\n\tprivate readonly state: TemplateState;\n\n\t/** Options inherited from the parent Typebars instance */\n\tprivate readonly options: CompiledTemplateOptions;\n\n\t/** Compiled Handlebars template (lazy — created on the first `execute()` that needs it) */\n\tprivate hbsCompiled: HandlebarsTemplateDelegate | null = null;\n\n\t// ─── Public Accessors (backward-compatible) ──────────────────────────\n\n\t/** The pre-parsed Handlebars AST — `null` in literal, object, or array mode */\n\tget ast(): hbs.AST.Program | null {\n\t\treturn this.state.kind === \"template\" ? this.state.ast : null;\n\t}\n\n\t/** The original template source — empty string in literal, object, or array mode */\n\tget template(): string {\n\t\treturn this.state.kind === \"template\" ? this.state.source : \"\";\n\t}\n\n\t// ─── Construction ────────────────────────────────────────────────────\n\n\tprivate constructor(state: TemplateState, options: CompiledTemplateOptions) {\n\t\tthis.state = state;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate for a parsed Handlebars template.\n\t *\n\t * @param ast - The pre-parsed Handlebars AST\n\t * @param source - The original template source\n\t * @param options - Options inherited from Typebars\n\t */\n\tstatic fromTemplate(\n\t\tast: hbs.AST.Program,\n\t\tsource: string,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"template\", ast, source }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in passthrough mode for a literal value\n\t * (number, boolean, null). No parsing or compilation is performed.\n\t *\n\t * @param value - The primitive value\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that always returns `value`\n\t */\n\tstatic fromLiteral(\n\t\tvalue: number | boolean | null,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"literal\", value }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in object mode, where each property is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the children.\n\t *\n\t * @param children - The compiled child templates `{ [key]: CompiledTemplate }`\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to children\n\t */\n\tstatic fromObject(\n\t\tchildren: Record<string, CompiledTemplate>,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"object\", children }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in array mode, where each element is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the elements.\n\t *\n\t * @param elements - The compiled child templates (ordered array)\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to elements\n\t */\n\tstatic fromArray(\n\t\telements: CompiledTemplate[],\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"array\", elements }, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes this template against a JSON Schema v7.\n\t *\n\t * Returns an `AnalysisResult` containing:\n\t * - `valid` — `true` if no errors\n\t * - `diagnostics` — list of diagnostics (errors + warnings)\n\t * - `outputSchema` — JSON Schema describing the return type\n\t *\n\t * Since the AST is pre-parsed, this method never re-parses the template.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tanalyze(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): AnalysisResult {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\n\t\t\t\tif (exclude) {\n\t\t\t\t\t// When excludeTemplateExpression is enabled, filter out elements\n\t\t\t\t\t// that are string templates containing Handlebars expressions.\n\t\t\t\t\tconst kept = elements.filter(\n\t\t\t\t\t\t(el) => !isCompiledTemplateWithExpression(el),\n\t\t\t\t\t);\n\t\t\t\t\treturn aggregateArrayAnalysis(kept.length, (index) => {\n\t\t\t\t\t\tconst element = kept[index];\n\t\t\t\t\t\tif (!element)\n\t\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn aggregateArrayAnalysis(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\n\t\t\t\t// When excludeTemplateExpression is enabled, filter out keys whose\n\t\t\t\t// compiled children are string templates with Handlebars expressions.\n\t\t\t\tconst keys = exclude\n\t\t\t\t\t? Object.keys(children).filter((key) => {\n\t\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\t\treturn !child || !isCompiledTemplateWithExpression(child);\n\t\t\t\t\t\t})\n\t\t\t\t\t: Object.keys(children);\n\n\t\t\t\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\t\t\t\tconst child = children[key];\n\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\treturn child.analyze(inputSchema, {\n\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tvalid: true,\n\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t};\n\n\t\t\tcase \"template\":\n\t\t\t\treturn analyzeFromAst(this.state.ast, this.state.source, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.options.helpers,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\t\t}\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────\n\n\t/**\n\t * Validates the template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tvalidate(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(inputSchema, options);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Execution ───────────────────────────────────────────────────────\n\n\t/**\n\t * Executes this template with the provided data.\n\t *\n\t * The return type depends on the template structure:\n\t * - Single expression `{{expr}}` → raw value (number, boolean, object…)\n\t * - Mixed template or with blocks → `string`\n\t * - Primitive literal → the value as-is\n\t * - Object template → object with resolved values\n\t * - Array template → array with resolved values\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, coerceSchema, etc.)\n\t * @returns The execution result\n\t */\n\texecute(data: TemplateData, options?: ExecuteOptions): unknown {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\tconst result: unknown[] = [];\n\t\t\t\tfor (const element of elements) {\n\t\t\t\t\tresult.push(element.execute(data, options));\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\tconst result: Record<string, unknown> = {};\n\t\t\t\tfor (const [key, child] of Object.entries(children)) {\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\tresult[key] = child.execute(data, {\n\t\t\t\t\t\t...options,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn this.state.value;\n\n\t\t\tcase \"template\": {\n\t\t\t\t// Pre-execution static validation if a schema is provided\n\t\t\t\tif (options?.schema) {\n\t\t\t\t\tconst analysis = this.analyze(options.schema, {\n\t\t\t\t\t\tidentifierSchemas: options.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: options.coerceSchema,\n\t\t\t\t\t});\n\t\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext(options),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────\n\n\t/**\n\t * Analyzes and executes the template in a single call.\n\t *\n\t * Returns both the analysis result and the executed value.\n\t * If analysis fails, `value` is `undefined`.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - Additional options (identifierSchemas, identifierData, coerceSchema)\n\t * @returns `{ analysis, value }`\n\t */\n\tanalyzeAndExecute(\n\t\tinputSchema: JSONSchema7 = {},\n\t\tdata: TemplateData,\n\t\toptions?: {\n\t\t\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t\t\tidentifierData?: Record<number, Record<string, unknown>>;\n\t\t\tcoerceSchema?: JSONSchema7;\n\t\t},\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\treturn aggregateArrayAnalysisAndExecution(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyzeAndExecute(inputSchema, data, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\treturn aggregateObjectAnalysisAndExecution(\n\t\t\t\t\tObject.keys(children),\n\t\t\t\t\t(key) => {\n\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(\n\t\t\t\t\t\t\tcoerceSchema,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn child.analyzeAndExecute(inputSchema, data, {\n\t\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tanalysis: {\n\t\t\t\t\t\tvalid: true,\n\t\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t\t},\n\t\t\t\t\tvalue: this.state.value,\n\t\t\t\t};\n\n\t\t\tcase \"template\": {\n\t\t\t\tconst analysis = this.analyze(inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\n\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\treturn { analysis, value: undefined };\n\t\t\t\t}\n\n\t\t\t\tconst value = executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext({\n\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn { analysis, value };\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Internals ───────────────────────────────────────────────────────\n\n\t/**\n\t * Builds the execution context for `executeFromAst`.\n\t *\n\t * Uses lazy Handlebars compilation: the template is only compiled\n\t * on the first call that needs it (not for single expressions).\n\t */\n\tprivate buildExecutorContext(options?: ExecuteOptions): ExecutorContext {\n\t\treturn {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\tcompiledTemplate: this.getOrCompileHbs(),\n\t\t\thbs: this.options.hbs,\n\t\t\tcompilationCache: this.options.compilationCache,\n\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\thelpers: this.options.helpers,\n\t\t};\n\t}\n\n\t/**\n\t * Lazily compiles the Handlebars template and caches it.\n\t *\n\t * Compilation happens only once — subsequent calls return the\n\t * in-memory compiled template.\n\t *\n\t * Precondition: this method is only called from \"template\" mode.\n\t */\n\tprivate getOrCompileHbs(): HandlebarsTemplateDelegate {\n\t\tif (!this.hbsCompiled) {\n\t\t\t// In \"template\" mode, `this.template` returns the source string\n\t\t\tthis.hbsCompiled = this.options.hbs.compile(this.template, {\n\t\t\t\tnoEscape: true,\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t}\n\t\treturn this.hbsCompiled;\n\t}\n}\n\n// ─── Internal Helpers ────────────────────────────────────────────────────────\n\n/**\n * Determines whether a `CompiledTemplate` represents a string template\n * containing Handlebars expressions (`{{…}}`).\n *\n * Used by `excludeTemplateExpression` filtering to skip dynamic entries\n * in object and array modes.\n */\nfunction isCompiledTemplateWithExpression(ct: CompiledTemplate): boolean {\n\t// Only \"template\" kind can contain expressions. Literals, objects,\n\t// and arrays are never excluded at the entry level — objects and\n\t// arrays are recursively filtered by the analysis method itself.\n\treturn ct.template !== \"\" && shouldExcludeEntry(ct.template);\n}\n"],"names":["CompiledTemplate","ast","state","kind","template","source","fromTemplate","options","fromLiteral","value","fromObject","children","fromArray","elements","analyze","inputSchema","exclude","excludeTemplateExpression","kept","filter","el","isCompiledTemplateWithExpression","aggregateArrayAnalysis","length","index","element","Error","coerceSchema","keys","Object","key","child","aggregateObjectAnalysis","childCoerceSchema","resolveChildCoerceSchema","identifierSchemas","valid","diagnostics","outputSchema","inferPrimitiveSchema","analyzeFromAst","helpers","validate","analysis","execute","data","result","push","entries","schema","TemplateAnalysisError","executeFromAst","buildExecutorContext","analyzeAndExecute","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysisAndExecution","identifierData","undefined","compiledTemplate","getOrCompileHbs","hbs","compilationCache","hbsCompiled","compile","noEscape","strict","ct","shouldExcludeEntry"],"mappings":"oGAoFaA,0DAAAA,8CAjFkB,2CAC8B,yCACvB,yCACe,wCAQhB,mCAO9B,+LA+DA,MAAMA,iBAaZ,IAAIC,KAA8B,CACjC,OAAO,IAAI,CAACC,KAAK,CAACC,IAAI,GAAK,WAAa,IAAI,CAACD,KAAK,CAACD,GAAG,CAAG,IAC1D,CAGA,IAAIG,UAAmB,CACtB,OAAO,IAAI,CAACF,KAAK,CAACC,IAAI,GAAK,WAAa,IAAI,CAACD,KAAK,CAACG,MAAM,CAAG,EAC7D,CAgBA,OAAOC,aACNL,GAAoB,CACpBI,MAAc,CACdE,OAAgC,CACb,CACnB,OAAO,IAAIP,iBAAiB,CAAEG,KAAM,WAAYF,IAAKI,MAAO,EAAGE,QAChE,CAUA,OAAOC,YACNC,KAA8B,CAC9BF,OAAgC,CACb,CACnB,OAAO,IAAIP,iBAAiB,CAAEG,KAAM,UAAWM,KAAM,EAAGF,QACzD,CAWA,OAAOG,WACNC,QAA0C,CAC1CJ,OAAgC,CACb,CACnB,OAAO,IAAIP,iBAAiB,CAAEG,KAAM,SAAUQ,QAAS,EAAGJ,QAC3D,CAWA,OAAOK,UACNC,QAA4B,CAC5BN,OAAgC,CACb,CACnB,OAAO,IAAIP,iBAAiB,CAAEG,KAAM,QAASU,QAAS,EAAGN,QAC1D,CAiBAO,QACCC,YAA2B,CAAC,CAAC,CAC7BR,OAAwB,CACP,CACjB,MAAMS,QAAUT,SAASU,4BAA8B,KAEvD,OAAQ,IAAI,CAACf,KAAK,CAACC,IAAI,EACtB,IAAK,QAAS,CACb,KAAM,CAAEU,QAAQ,CAAE,CAAG,IAAI,CAACX,KAAK,CAE/B,GAAIc,QAAS,CAGZ,MAAME,KAAOL,SAASM,MAAM,CAC3B,AAACC,IAAO,CAACC,iCAAiCD,KAE3C,MAAOE,GAAAA,6BAAsB,EAACJ,KAAKK,MAAM,CAAE,AAACC,QAC3C,MAAMC,QAAUP,IAAI,CAACM,MAAM,CAC3B,GAAI,CAACC,QACJ,MAAM,IAAIC,MAAM,CAAC,sCAAsC,EAAEF,MAAM,CAAC,EACjE,OAAOC,QAAQX,OAAO,CAACC,YAAaR,QACrC,EACD,CAEA,MAAOe,GAAAA,6BAAsB,EAACT,SAASU,MAAM,CAAE,AAACC,QAC/C,MAAMC,QAAUZ,QAAQ,CAACW,MAAM,CAC/B,GAAI,CAACC,QACJ,MAAM,IAAIC,MAAM,CAAC,sCAAsC,EAAEF,MAAM,CAAC,EACjE,OAAOC,QAAQX,OAAO,CAACC,YAAaR,QACrC,EACD,CAEA,IAAK,SAAU,CACd,KAAM,CAAEI,QAAQ,CAAE,CAAG,IAAI,CAACT,KAAK,CAC/B,MAAMyB,aAAepB,SAASoB,aAI9B,MAAMC,KAAOZ,QACVa,OAAOD,IAAI,CAACjB,UAAUQ,MAAM,CAAC,AAACW,MAC9B,MAAMC,MAAQpB,QAAQ,CAACmB,IAAI,CAC3B,MAAO,CAACC,OAAS,CAACV,iCAAiCU,MACpD,GACCF,OAAOD,IAAI,CAACjB,UAEf,MAAOqB,GAAAA,8BAAuB,EAACJ,KAAM,AAACE,MACrC,MAAMC,MAAQpB,QAAQ,CAACmB,IAAI,CAC3B,GAAI,CAACC,MAAO,MAAM,IAAIL,MAAM,CAAC,4BAA4B,EAAEI,IAAI,CAAC,CAAC,EACjE,MAAMG,kBAAoBC,GAAAA,oCAAwB,EAACP,aAAcG,KACjE,OAAOC,MAAMjB,OAAO,CAACC,YAAa,CACjCoB,kBAAmB5B,SAAS4B,kBAC5BR,aAAcM,kBACdhB,0BAA2BV,SAASU,yBACrC,EACD,EACD,CAEA,IAAK,UACJ,MAAO,CACNmB,MAAO,KACPC,YAAa,EAAE,CACfC,aAAcC,GAAAA,6BAAoB,EAAC,IAAI,CAACrC,KAAK,CAACO,KAAK,CACpD,CAED,KAAK,WACJ,MAAO+B,GAAAA,0BAAc,EAAC,IAAI,CAACtC,KAAK,CAACD,GAAG,CAAE,IAAI,CAACC,KAAK,CAACG,MAAM,CAAEU,YAAa,CACrEoB,kBAAmB5B,SAAS4B,kBAC5BM,QAAS,IAAI,CAAClC,OAAO,CAACkC,OAAO,CAC7Bd,aAAcpB,SAASoB,YACxB,EACF,CACD,CAeAe,SACC3B,YAA2B,CAAC,CAAC,CAC7BR,OAAwB,CACL,CACnB,MAAMoC,SAAW,IAAI,CAAC7B,OAAO,CAACC,YAAaR,SAC3C,MAAO,CACN6B,MAAOO,SAASP,KAAK,CACrBC,YAAaM,SAASN,WAAW,AAClC,CACD,CAqBAO,QAAQC,IAAkB,CAAEtC,OAAwB,CAAW,CAC9D,OAAQ,IAAI,CAACL,KAAK,CAACC,IAAI,EACtB,IAAK,QAAS,CACb,KAAM,CAAEU,QAAQ,CAAE,CAAG,IAAI,CAACX,KAAK,CAC/B,MAAM4C,OAAoB,EAAE,CAC5B,IAAK,MAAMrB,WAAWZ,SAAU,CAC/BiC,OAAOC,IAAI,CAACtB,QAAQmB,OAAO,CAACC,KAAMtC,SACnC,CACA,OAAOuC,MACR,CAEA,IAAK,SAAU,CACd,KAAM,CAAEnC,QAAQ,CAAE,CAAG,IAAI,CAACT,KAAK,CAC/B,MAAMyB,aAAepB,SAASoB,aAC9B,MAAMmB,OAAkC,CAAC,EACzC,IAAK,KAAM,CAAChB,IAAKC,MAAM,GAAIF,OAAOmB,OAAO,CAACrC,UAAW,CACpD,MAAMsB,kBAAoBC,GAAAA,oCAAwB,EAACP,aAAcG,IACjEgB,CAAAA,MAAM,CAAChB,IAAI,CAAGC,MAAMa,OAAO,CAACC,KAAM,CACjC,GAAGtC,OAAO,CACVoB,aAAcM,iBACf,EACD,CACA,OAAOa,MACR,CAEA,IAAK,UACJ,OAAO,IAAI,CAAC5C,KAAK,CAACO,KAAK,AAExB,KAAK,WAAY,CAEhB,GAAIF,SAAS0C,OAAQ,CACpB,MAAMN,SAAW,IAAI,CAAC7B,OAAO,CAACP,QAAQ0C,MAAM,CAAE,CAC7Cd,kBAAmB5B,QAAQ4B,iBAAiB,CAC5CR,aAAcpB,QAAQoB,YAAY,AACnC,GACA,GAAI,CAACgB,SAASP,KAAK,CAAE,CACpB,MAAM,IAAIc,+BAAqB,CAACP,SAASN,WAAW,CACrD,CACD,CAEA,MAAOc,GAAAA,0BAAc,EACpB,IAAI,CAACjD,KAAK,CAACD,GAAG,CACd,IAAI,CAACC,KAAK,CAACG,MAAM,CACjBwC,KACA,IAAI,CAACO,oBAAoB,CAAC7C,SAE5B,CACD,CACD,CAeA8C,kBACCtC,YAA2B,CAAC,CAAC,CAC7B8B,IAAkB,CAClBtC,OAIC,CAC8C,CAC/C,OAAQ,IAAI,CAACL,KAAK,CAACC,IAAI,EACtB,IAAK,QAAS,CACb,KAAM,CAAEU,QAAQ,CAAE,CAAG,IAAI,CAACX,KAAK,CAC/B,MAAOoD,GAAAA,yCAAkC,EAACzC,SAASU,MAAM,CAAE,AAACC,QAC3D,MAAMC,QAAUZ,QAAQ,CAACW,MAAM,CAC/B,GAAI,CAACC,QACJ,MAAM,IAAIC,MAAM,CAAC,sCAAsC,EAAEF,MAAM,CAAC,EACjE,OAAOC,QAAQ4B,iBAAiB,CAACtC,YAAa8B,KAAMtC,QACrD,EACD,CAEA,IAAK,SAAU,CACd,KAAM,CAAEI,QAAQ,CAAE,CAAG,IAAI,CAACT,KAAK,CAC/B,MAAMyB,aAAepB,SAASoB,aAC9B,MAAO4B,GAAAA,0CAAmC,EACzC1B,OAAOD,IAAI,CAACjB,UACZ,AAACmB,MACA,MAAMC,MAAQpB,QAAQ,CAACmB,IAAI,CAC3B,GAAI,CAACC,MAAO,MAAM,IAAIL,MAAM,CAAC,4BAA4B,EAAEI,IAAI,CAAC,CAAC,EACjE,MAAMG,kBAAoBC,GAAAA,oCAAwB,EACjDP,aACAG,KAED,OAAOC,MAAMsB,iBAAiB,CAACtC,YAAa8B,KAAM,CACjDV,kBAAmB5B,SAAS4B,kBAC5BqB,eAAgBjD,SAASiD,eACzB7B,aAAcM,iBACf,EACD,EAEF,CAEA,IAAK,UACJ,MAAO,CACNU,SAAU,CACTP,MAAO,KACPC,YAAa,EAAE,CACfC,aAAcC,GAAAA,6BAAoB,EAAC,IAAI,CAACrC,KAAK,CAACO,KAAK,CACpD,EACAA,MAAO,IAAI,CAACP,KAAK,CAACO,KAAK,AACxB,CAED,KAAK,WAAY,CAChB,MAAMkC,SAAW,IAAI,CAAC7B,OAAO,CAACC,YAAa,CAC1CoB,kBAAmB5B,SAAS4B,kBAC5BR,aAAcpB,SAASoB,YACxB,GAEA,GAAI,CAACgB,SAASP,KAAK,CAAE,CACpB,MAAO,CAAEO,SAAUlC,MAAOgD,SAAU,CACrC,CAEA,MAAMhD,MAAQ0C,GAAAA,0BAAc,EAC3B,IAAI,CAACjD,KAAK,CAACD,GAAG,CACd,IAAI,CAACC,KAAK,CAACG,MAAM,CACjBwC,KACA,IAAI,CAACO,oBAAoB,CAAC,CACzBI,eAAgBjD,SAASiD,eACzB7B,aAAcpB,SAASoB,YACxB,IAGD,MAAO,CAAEgB,SAAUlC,KAAM,CAC1B,CACD,CACD,CAUA,AAAQ2C,qBAAqB7C,OAAwB,CAAmB,CACvE,MAAO,CACNiD,eAAgBjD,SAASiD,eACzBE,iBAAkB,IAAI,CAACC,eAAe,GACtCC,IAAK,IAAI,CAACrD,OAAO,CAACqD,GAAG,CACrBC,iBAAkB,IAAI,CAACtD,OAAO,CAACsD,gBAAgB,CAC/ClC,aAAcpB,SAASoB,aACvBc,QAAS,IAAI,CAAClC,OAAO,CAACkC,OAAO,AAC9B,CACD,CAUA,AAAQkB,iBAA8C,CACrD,GAAI,CAAC,IAAI,CAACG,WAAW,CAAE,CAEtB,IAAI,CAACA,WAAW,CAAG,IAAI,CAACvD,OAAO,CAACqD,GAAG,CAACG,OAAO,CAAC,IAAI,CAAC3D,QAAQ,CAAE,CAC1D4D,SAAU,KACVC,OAAQ,KACT,EACD,CACA,OAAO,IAAI,CAACH,WAAW,AACxB,CArXA,YAAoB5D,KAAoB,CAAEK,OAAgC,CAAE,CAtB5E,sBAAiBL,QAAjB,KAAA,GAGA,sBAAiBK,UAAjB,KAAA,GAGA,sBAAQuD,cAAiD,KAiBxD,CAAA,IAAI,CAAC5D,KAAK,CAAGA,KACb,CAAA,IAAI,CAACK,OAAO,CAAGA,OAChB,CAmXD,CAWA,SAASc,iCAAiC6C,EAAoB,EAI7D,OAAOA,GAAG9D,QAAQ,GAAK,IAAM+D,GAAAA,8BAAkB,EAACD,GAAG9D,QAAQ,CAC5D"}
|
|
1
|
+
{"version":3,"sources":["../../src/compiled-template.ts"],"sourcesContent":["import type Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { AnalyzeOptions } from \"./analyzer.ts\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport { resolveChildCoerceSchema, shouldExcludeEntry } from \"./dispatch.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { type ExecutorContext, executeFromAst } from \"./executor.ts\";\nimport type {\n\tAnalysisResult,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateData,\n\tValidationResult,\n} from \"./types.ts\";\nimport { inferPrimitiveSchema } from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n\ttype LRUCache,\n} from \"./utils\";\n\n// ─── CompiledTemplate ────────────────────────────────────────────────────────\n// Pre-parsed template ready to be executed or analyzed without re-parsing.\n//\n// The compile-once / execute-many pattern avoids the cost of Handlebars\n// parsing on every call. The AST is parsed once at compile time, and the\n// Handlebars template is lazily compiled on the first `execute()`.\n//\n// Usage:\n// const tpl = engine.compile(\"Hello {{name}}\");\n// tpl.execute({ name: \"Alice\" }); // no re-parsing\n// tpl.execute({ name: \"Bob\" }); // no re-parsing or recompilation\n// tpl.analyze(schema); // no re-parsing\n//\n// ─── Internal State (TemplateState) ──────────────────────────────────────────\n// CompiledTemplate operates in 4 exclusive modes, modeled by a discriminated\n// union `TemplateState`:\n//\n// - `\"template\"` — parsed Handlebars template (AST + source string)\n// - `\"literal\"` — primitive passthrough value (number, boolean, null)\n// - `\"object\"` — object where each property is a child CompiledTemplate\n// - `\"array\"` — array where each element is a child CompiledTemplate\n//\n// This design eliminates optional fields and `!` assertions in favor of\n// natural TypeScript narrowing via `switch (this.state.kind)`.\n//\n// ─── Advantages Over the Direct API ──────────────────────────────────────────\n// - **Performance**: parsing and compilation happen only once\n// - **Simplified API**: no need to re-pass the template string on each call\n// - **Consistency**: the same AST is used for both analysis and execution\n\n// ─── Internal Types ──────────────────────────────────────────────────────────\n\n/** Internal options passed by Typebars during compilation */\nexport interface CompiledTemplateOptions {\n\t/** Custom helpers registered on the engine */\n\thelpers: Map<string, HelperDefinition>;\n\t/** Isolated Handlebars environment (with registered helpers) */\n\thbs: typeof Handlebars;\n\t/** Compilation cache shared by the engine */\n\tcompilationCache: LRUCache<string, HandlebarsTemplateDelegate>;\n}\n\n/** Discriminated internal state of the CompiledTemplate */\ntype TemplateState =\n\t| {\n\t\t\treadonly kind: \"template\";\n\t\t\treadonly ast: hbs.AST.Program;\n\t\t\treadonly source: string;\n\t }\n\t| { readonly kind: \"literal\"; readonly value: number | boolean | null }\n\t| {\n\t\t\treadonly kind: \"object\";\n\t\t\treadonly children: Record<string, CompiledTemplate>;\n\t }\n\t| {\n\t\t\treadonly kind: \"array\";\n\t\t\treadonly elements: CompiledTemplate[];\n\t };\n\n// ─── Public Class ────────────────────────────────────────────────────────────\n\nexport class CompiledTemplate {\n\t/** Discriminated internal state */\n\tprivate readonly state: TemplateState;\n\n\t/** Options inherited from the parent Typebars instance */\n\tprivate readonly options: CompiledTemplateOptions;\n\n\t/** Compiled Handlebars template (lazy — created on the first `execute()` that needs it) */\n\tprivate hbsCompiled: HandlebarsTemplateDelegate | null = null;\n\n\t// ─── Public Accessors (backward-compatible) ──────────────────────────\n\n\t/** The pre-parsed Handlebars AST — `null` in literal, object, or array mode */\n\tget ast(): hbs.AST.Program | null {\n\t\treturn this.state.kind === \"template\" ? this.state.ast : null;\n\t}\n\n\t/** The original template source — empty string in literal, object, or array mode */\n\tget template(): string {\n\t\treturn this.state.kind === \"template\" ? this.state.source : \"\";\n\t}\n\n\t// ─── Construction ────────────────────────────────────────────────────\n\n\tprivate constructor(state: TemplateState, options: CompiledTemplateOptions) {\n\t\tthis.state = state;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate for a parsed Handlebars template.\n\t *\n\t * @param ast - The pre-parsed Handlebars AST\n\t * @param source - The original template source\n\t * @param options - Options inherited from Typebars\n\t */\n\tstatic fromTemplate(\n\t\tast: hbs.AST.Program,\n\t\tsource: string,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"template\", ast, source }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in passthrough mode for a literal value\n\t * (number, boolean, null). No parsing or compilation is performed.\n\t *\n\t * @param value - The primitive value\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that always returns `value`\n\t */\n\tstatic fromLiteral(\n\t\tvalue: number | boolean | null,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"literal\", value }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in object mode, where each property is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the children.\n\t *\n\t * @param children - The compiled child templates `{ [key]: CompiledTemplate }`\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to children\n\t */\n\tstatic fromObject(\n\t\tchildren: Record<string, CompiledTemplate>,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"object\", children }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in array mode, where each element is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the elements.\n\t *\n\t * @param elements - The compiled child templates (ordered array)\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to elements\n\t */\n\tstatic fromArray(\n\t\telements: CompiledTemplate[],\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"array\", elements }, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes this template against a JSON Schema v7.\n\t *\n\t * Returns an `AnalysisResult` containing:\n\t * - `valid` — `true` if no errors\n\t * - `diagnostics` — list of diagnostics (errors + warnings)\n\t * - `outputSchema` — JSON Schema describing the return type\n\t *\n\t * Since the AST is pre-parsed, this method never re-parses the template.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tanalyze(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): AnalysisResult {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\n\t\t\t\tif (exclude) {\n\t\t\t\t\t// When excludeTemplateExpression is enabled, filter out elements\n\t\t\t\t\t// that are string templates containing Handlebars expressions.\n\t\t\t\t\tconst kept = elements.filter(\n\t\t\t\t\t\t(el) => !isCompiledTemplateWithExpression(el),\n\t\t\t\t\t);\n\t\t\t\t\treturn aggregateArrayAnalysis(kept.length, (index) => {\n\t\t\t\t\t\tconst element = kept[index];\n\t\t\t\t\t\tif (!element)\n\t\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn aggregateArrayAnalysis(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\n\t\t\t\t// When excludeTemplateExpression is enabled, filter out keys whose\n\t\t\t\t// compiled children are string templates with Handlebars expressions.\n\t\t\t\tconst keys = exclude\n\t\t\t\t\t? Object.keys(children).filter((key) => {\n\t\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\t\treturn !child || !isCompiledTemplateWithExpression(child);\n\t\t\t\t\t\t})\n\t\t\t\t\t: Object.keys(children);\n\n\t\t\t\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\t\t\t\tconst child = children[key];\n\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\treturn child.analyze(inputSchema, {\n\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tvalid: true,\n\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t};\n\n\t\t\tcase \"template\":\n\t\t\t\treturn analyzeFromAst(this.state.ast, this.state.source, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.options.helpers,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\t\t}\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────\n\n\t/**\n\t * Validates the template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tvalidate(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(inputSchema, options);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Execution ───────────────────────────────────────────────────────\n\n\t/**\n\t * Executes this template with the provided data.\n\t *\n\t * The return type depends on the template structure:\n\t * - Single expression `{{expr}}` → raw value (number, boolean, object…)\n\t * - Mixed template or with blocks → `string`\n\t * - Primitive literal → the value as-is\n\t * - Object template → object with resolved values\n\t * - Array template → array with resolved values\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, coerceSchema, etc.)\n\t * @returns The execution result\n\t */\n\texecute(data: TemplateData, options?: ExecuteOptions): unknown {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\tconst effective = exclude\n\t\t\t\t\t? elements.filter((el) => !isCompiledTemplateWithExpression(el))\n\t\t\t\t\t: elements;\n\t\t\t\tconst result: unknown[] = [];\n\t\t\t\tfor (const element of effective) {\n\t\t\t\t\tresult.push(element.execute(data, options));\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\tconst keys = exclude\n\t\t\t\t\t? Object.keys(children).filter((key) => {\n\t\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\t\treturn !child || !isCompiledTemplateWithExpression(child);\n\t\t\t\t\t\t})\n\t\t\t\t\t: Object.keys(children);\n\t\t\t\tconst result: Record<string, unknown> = {};\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tconst child = children[key];\n\t\t\t\t\tif (!child) continue;\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\tresult[key] = child.execute(data, {\n\t\t\t\t\t\t...options,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn this.state.value;\n\n\t\t\tcase \"template\": {\n\t\t\t\t// When excludeTemplateExpression is enabled at root level,\n\t\t\t\t// return null if the template contains Handlebars expressions\n\t\t\t\t// (there is no parent to remove it from).\n\t\t\t\tif (exclude && isCompiledTemplateWithExpression(this)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// Pre-execution static validation if a schema is provided\n\t\t\t\tif (options?.schema) {\n\t\t\t\t\tconst analysis = this.analyze(options.schema, {\n\t\t\t\t\t\tidentifierSchemas: options.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: options.coerceSchema,\n\t\t\t\t\t});\n\t\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext(options),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────\n\n\t/**\n\t * Analyzes and executes the template in a single call.\n\t *\n\t * Returns both the analysis result and the executed value.\n\t * If analysis fails, `value` is `undefined`.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - Additional options (identifierSchemas, identifierData, coerceSchema)\n\t * @returns `{ analysis, value }`\n\t */\n\tanalyzeAndExecute(\n\t\tinputSchema: JSONSchema7 = {},\n\t\tdata: TemplateData,\n\t\toptions?: {\n\t\t\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t\t\tidentifierData?: Record<number, Record<string, unknown>>;\n\t\t\tcoerceSchema?: JSONSchema7;\n\t\t},\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\treturn aggregateArrayAnalysisAndExecution(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyzeAndExecute(inputSchema, data, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\treturn aggregateObjectAnalysisAndExecution(\n\t\t\t\t\tObject.keys(children),\n\t\t\t\t\t(key) => {\n\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(\n\t\t\t\t\t\t\tcoerceSchema,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn child.analyzeAndExecute(inputSchema, data, {\n\t\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tanalysis: {\n\t\t\t\t\t\tvalid: true,\n\t\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t\t},\n\t\t\t\t\tvalue: this.state.value,\n\t\t\t\t};\n\n\t\t\tcase \"template\": {\n\t\t\t\tconst analysis = this.analyze(inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\n\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\treturn { analysis, value: undefined };\n\t\t\t\t}\n\n\t\t\t\tconst value = executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext({\n\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn { analysis, value };\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Internals ───────────────────────────────────────────────────────\n\n\t/**\n\t * Builds the execution context for `executeFromAst`.\n\t *\n\t * Uses lazy Handlebars compilation: the template is only compiled\n\t * on the first call that needs it (not for single expressions).\n\t */\n\tprivate buildExecutorContext(options?: ExecuteOptions): ExecutorContext {\n\t\treturn {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\tcompiledTemplate: this.getOrCompileHbs(),\n\t\t\thbs: this.options.hbs,\n\t\t\tcompilationCache: this.options.compilationCache,\n\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\thelpers: this.options.helpers,\n\t\t};\n\t}\n\n\t/**\n\t * Lazily compiles the Handlebars template and caches it.\n\t *\n\t * Compilation happens only once — subsequent calls return the\n\t * in-memory compiled template.\n\t *\n\t * Precondition: this method is only called from \"template\" mode.\n\t */\n\tprivate getOrCompileHbs(): HandlebarsTemplateDelegate {\n\t\tif (!this.hbsCompiled) {\n\t\t\t// In \"template\" mode, `this.template` returns the source string\n\t\t\tthis.hbsCompiled = this.options.hbs.compile(this.template, {\n\t\t\t\tnoEscape: true,\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t}\n\t\treturn this.hbsCompiled;\n\t}\n}\n\n// ─── Internal Helpers ────────────────────────────────────────────────────────\n\n/**\n * Determines whether a `CompiledTemplate` represents a string template\n * containing Handlebars expressions (`{{…}}`).\n *\n * Used by `excludeTemplateExpression` filtering to skip dynamic entries\n * in object and array modes.\n */\nfunction isCompiledTemplateWithExpression(ct: CompiledTemplate): boolean {\n\t// Only \"template\" kind can contain expressions. Literals, objects,\n\t// and arrays are never excluded at the entry level — objects and\n\t// arrays are recursively filtered by the analysis method itself.\n\treturn ct.template !== \"\" && shouldExcludeEntry(ct.template);\n}\n"],"names":["CompiledTemplate","ast","state","kind","template","source","fromTemplate","options","fromLiteral","value","fromObject","children","fromArray","elements","analyze","inputSchema","exclude","excludeTemplateExpression","kept","filter","el","isCompiledTemplateWithExpression","aggregateArrayAnalysis","length","index","element","Error","coerceSchema","keys","Object","key","child","aggregateObjectAnalysis","childCoerceSchema","resolveChildCoerceSchema","identifierSchemas","valid","diagnostics","outputSchema","inferPrimitiveSchema","analyzeFromAst","helpers","validate","analysis","execute","data","effective","result","push","schema","TemplateAnalysisError","executeFromAst","buildExecutorContext","analyzeAndExecute","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysisAndExecution","identifierData","undefined","compiledTemplate","getOrCompileHbs","hbs","compilationCache","hbsCompiled","compile","noEscape","strict","ct","shouldExcludeEntry"],"mappings":"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"}
|
package/dist/cjs/dispatch.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface DispatchAnalyzeOptions {
|
|
|
13
13
|
export interface DispatchExecuteOptions {
|
|
14
14
|
/** Explicit coercion schema for output type coercion */
|
|
15
15
|
coerceSchema?: JSONSchema7;
|
|
16
|
+
/** When true, exclude entries containing Handlebars expressions */
|
|
17
|
+
excludeTemplateExpression?: boolean;
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* Dispatches a `TemplateInput` for analysis, handling the array/object/literal
|
|
@@ -47,6 +49,8 @@ export interface DispatchAnalyzeAndExecuteOptions {
|
|
|
47
49
|
identifierSchemas?: Record<number, JSONSchema7>;
|
|
48
50
|
identifierData?: Record<number, Record<string, unknown>>;
|
|
49
51
|
coerceSchema?: JSONSchema7;
|
|
52
|
+
/** When true, exclude entries containing Handlebars expressions */
|
|
53
|
+
excludeTemplateExpression?: boolean;
|
|
50
54
|
}
|
|
51
55
|
/**
|
|
52
56
|
* Dispatches a `TemplateInput` for combined analysis and execution,
|
package/dist/cjs/dispatch.js
CHANGED
|
@@ -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 dispatchAnalyze(){return dispatchAnalyze},get dispatchAnalyzeAndExecute(){return dispatchAnalyzeAndExecute},get dispatchExecute(){return dispatchExecute},get resolveChildCoerceSchema(){return resolveChildCoerceSchema},get shouldExcludeEntry(){return shouldExcludeEntry}});const _parserts=require("./parser.js");const _schemaresolverts=require("./schema-resolver.js");const _typests=require("./types.js");const _utilsts=require("./utils.js");function dispatchAnalyze(template,options,analyzeString,recurse){if((0,_typests.isArrayInput)(template)){const exclude=options?.excludeTemplateExpression===true;if(exclude){const kept=template.filter(item=>!shouldExcludeEntry(item));return(0,_utilsts.aggregateArrayAnalysis)(kept.length,index=>recurse(kept[index],
|
|
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 dispatchAnalyze(){return dispatchAnalyze},get dispatchAnalyzeAndExecute(){return dispatchAnalyzeAndExecute},get dispatchExecute(){return dispatchExecute},get resolveChildCoerceSchema(){return resolveChildCoerceSchema},get shouldExcludeEntry(){return shouldExcludeEntry}});const _parserts=require("./parser.js");const _schemaresolverts=require("./schema-resolver.js");const _typests=require("./types.js");const _utilsts=require("./utils.js");function dispatchAnalyze(template,options,analyzeString,recurse){if((0,_typests.isArrayInput)(template)){const exclude=options?.excludeTemplateExpression===true;const childOptions=resolveArrayChildOptions(options);if(exclude){const kept=template.filter(item=>!shouldExcludeEntry(item));return(0,_utilsts.aggregateArrayAnalysis)(kept.length,index=>recurse(kept[index],childOptions))}return(0,_utilsts.aggregateArrayAnalysis)(template.length,index=>recurse(template[index],childOptions))}if((0,_typests.isObjectInput)(template)){return dispatchObjectAnalysis(template,options,recurse)}if((0,_typests.isLiteralInput)(template)){return{valid:true,diagnostics:[],outputSchema:(0,_typests.inferPrimitiveSchema)(template)}}return analyzeString(template,options?.coerceSchema)}function dispatchObjectAnalysis(template,options,recurse){const coerceSchema=options?.coerceSchema;const exclude=options?.excludeTemplateExpression===true;const keys=exclude?Object.keys(template).filter(key=>!shouldExcludeEntry(template[key])):Object.keys(template);return(0,_utilsts.aggregateObjectAnalysis)(keys,key=>{const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);return recurse(template[key],{identifierSchemas:options?.identifierSchemas,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}function dispatchExecute(template,options,executeString,recurse){const exclude=options?.excludeTemplateExpression===true;if((0,_typests.isArrayInput)(template)){const childOptions=resolveArrayChildOptions(options);const elements=exclude?template.filter(item=>!shouldExcludeEntry(item)):template;const result=[];for(const element of elements){result.push(recurse(element,childOptions))}return result}if((0,_typests.isObjectInput)(template)){const coerceSchema=options?.coerceSchema;const result={};const keys=exclude?Object.keys(template).filter(key=>!shouldExcludeEntry(template[key])):Object.keys(template);for(const key of keys){const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);result[key]=recurse(template[key],{...options,coerceSchema:childCoerceSchema})}return result}if((0,_typests.isLiteralInput)(template))return template;if(exclude&&shouldExcludeEntry(template)){return null}return executeString(template,options?.coerceSchema)}function dispatchAnalyzeAndExecute(template,options,processString,recurse){const exclude=options?.excludeTemplateExpression===true;if((0,_typests.isArrayInput)(template)){const childOptions=resolveArrayChildOptions(options);const elements=exclude?template.filter(item=>!shouldExcludeEntry(item)):template;return(0,_utilsts.aggregateArrayAnalysisAndExecution)(elements.length,index=>recurse(elements[index],childOptions))}if((0,_typests.isObjectInput)(template)){const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(template).filter(key=>!shouldExcludeEntry(template[key])):Object.keys(template);return(0,_utilsts.aggregateObjectAnalysisAndExecution)(keys,key=>{const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);return recurse(template[key],{identifierSchemas:options?.identifierSchemas,identifierData:options?.identifierData,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}if((0,_typests.isLiteralInput)(template)){return{analysis:{valid:true,diagnostics:[],outputSchema:(0,_typests.inferPrimitiveSchema)(template)},value:template}}if(exclude&&shouldExcludeEntry(template)){return{analysis:{valid:true,diagnostics:[],outputSchema:{type:"null"}},value:null}}return processString(template,options?.coerceSchema)}function resolveArrayChildOptions(options){if(!options?.coerceSchema)return options;const itemsSchema=resolveItemsCoerceSchema(options.coerceSchema);if(itemsSchema===options.coerceSchema)return options;return{...options,coerceSchema:itemsSchema}}function resolveItemsCoerceSchema(coerceSchema){if(typeof coerceSchema==="boolean")return undefined;const items=coerceSchema.items;if(items!=null&&typeof items==="object"&&!Array.isArray(items)){return items}return undefined}function resolveChildCoerceSchema(coerceSchema,key){return coerceSchema?(0,_schemaresolverts.resolveSchemaPath)(coerceSchema,[key]):undefined}function shouldExcludeEntry(input){return typeof input==="string"&&(0,_parserts.hasHandlebarsExpression)(input)}
|
|
2
2
|
//# sourceMappingURL=dispatch.js.map
|
package/dist/cjs/dispatch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dispatch.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport { hasHandlebarsExpression } from \"./parser.ts\";\nimport { resolveSchemaPath } from \"./schema-resolver.ts\";\nimport type { AnalysisResult, TemplateInput } from \"./types.ts\";\nimport {\n\tinferPrimitiveSchema,\n\tisArrayInput,\n\tisLiteralInput,\n\tisObjectInput,\n} from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n} from \"./utils.ts\";\n\n// ─── Template Input Dispatching ──────────────────────────────────────────────\n// Factorized dispatching for recursive processing of `TemplateInput` values.\n//\n// Every method in the engine (`analyze`, `execute`, `analyzeAndExecute`,\n// `compile`) follows the same recursive pattern:\n//\n// 1. If the input is an **array** → process each element recursively\n// 2. If the input is an **object** → process each property recursively\n// 3. If the input is a **literal** (number, boolean, null) → passthrough\n// 4. If the input is a **string** → delegate to a template-specific handler\n//\n// This module extracts the common dispatching logic into generic functions\n// that accept a callback for the string (template) case. This eliminates\n// the duplication across `Typebars`, `CompiledTemplate`, and `analyzer.ts`.\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Options controlling recursive dispatching behavior */\nexport interface DispatchAnalyzeOptions {\n\t/** Schemas by template identifier */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Explicit coercion schema for static literal output type */\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n/** Options controlling recursive execution dispatching */\nexport interface DispatchExecuteOptions {\n\t/** Explicit coercion schema for output type coercion */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Analysis Dispatching ────────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for analysis, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to analyze\n * @param options - Dispatching options (coerceSchema, excludeTemplateExpression)\n * @param analyzeString - Callback for analyzing a string template.\n * Receives `(template, coerceSchema?)` and must return an `AnalysisResult`.\n * @param recurse - Callback for recursively analyzing a child `TemplateInput`.\n * Receives `(child, options?)` and must return an `AnalysisResult`.\n * This allows callers (like `Typebars`) to rebind `this` or inject\n * additional context on each recursive call.\n * @returns An `AnalysisResult`\n */\nexport function dispatchAnalyze(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeOptions | undefined,\n\tanalyzeString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => AnalysisResult,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\t\tif (exclude) {\n\t\t\tconst kept = template.filter(\n\t\t\t\t(item) => !shouldExcludeEntry(item as TemplateInput),\n\t\t\t);\n\t\t\treturn aggregateArrayAnalysis(kept.length, (index) =>\n\t\t\t\trecurse(kept[index] as TemplateInput, options),\n\t\t\t);\n\t\t}\n\t\treturn aggregateArrayAnalysis(template.length, (index) =>\n\t\t\trecurse(template[index] as TemplateInput, options),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\treturn dispatchObjectAnalysis(template, options, recurse);\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tvalid: true,\n\t\t\tdiagnostics: [],\n\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn analyzeString(template, options?.coerceSchema);\n}\n\n/**\n * Dispatches object analysis with `coerceSchema` propagation and\n * `excludeTemplateExpression` filtering.\n *\n * Extracted as a separate function because the object case is the most\n * complex (key filtering + per-key coerceSchema resolution).\n */\nfunction dispatchObjectAnalysis(\n\ttemplate: Record<string, TemplateInput>,\n\toptions: DispatchAnalyzeOptions | undefined,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\tconst coerceSchema = options?.coerceSchema;\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\tconst keys = exclude\n\t\t? Object.keys(template).filter(\n\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t)\n\t\t: Object.keys(template);\n\n\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t});\n\t});\n}\n\n// ─── Execution Dispatching ───────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for execution, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to execute\n * @param options - Dispatching options (coerceSchema)\n * @param executeString - Callback for executing a string template.\n * Receives `(template, coerceSchema?)` and must return the result.\n * @param recurse - Callback for recursively executing a child `TemplateInput`.\n * Receives `(child, options?)` and must return the result.\n * @returns The execution result\n */\nexport function dispatchExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchExecuteOptions | undefined,\n\texecuteString: (template: string, coerceSchema?: JSONSchema7) => unknown,\n\trecurse: (child: TemplateInput, options?: DispatchExecuteOptions) => unknown,\n): unknown {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst result: unknown[] = [];\n\t\tfor (const element of template) {\n\t\t\tresult.push(recurse(element, options));\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\tresult[key] = recurse(value, {\n\t\t\t\t...options,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) return template;\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn executeString(template, options?.coerceSchema);\n}\n\n// ─── Analyze-and-Execute Dispatching ─────────────────────────────────────────\n\n/** Options for combined analyze-and-execute dispatching */\nexport interface DispatchAnalyzeAndExecuteOptions {\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\tcoerceSchema?: JSONSchema7;\n}\n\n/**\n * Dispatches a `TemplateInput` for combined analysis and execution,\n * handling array/object/literal cases generically and delegating\n * the string case to a callback.\n *\n * @param template - The input to process\n * @param options - Options (identifierSchemas, identifierData, coerceSchema)\n * @param processString - Callback for analyzing and executing a string template.\n * Receives `(template, coerceSchema?)` and must return\n * `{ analysis, value }`.\n * @param recurse - Callback for recursively processing a child `TemplateInput`.\n * @returns `{ analysis, value }` where `value` is `undefined` if analysis fails\n */\nexport function dispatchAnalyzeAndExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeAndExecuteOptions | undefined,\n\tprocessString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => { analysis: AnalysisResult; value: unknown },\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeAndExecuteOptions,\n\t) => { analysis: AnalysisResult; value: unknown },\n): { analysis: AnalysisResult; value: unknown } {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\treturn aggregateArrayAnalysisAndExecution(template.length, (index) =>\n\t\t\trecurse(template[index] as TemplateInput, options),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\treturn aggregateObjectAnalysisAndExecution(Object.keys(template), (key) => {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t});\n\t\t});\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tanalysis: {\n\t\t\t\tvalid: true,\n\t\t\t\tdiagnostics: [],\n\t\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t\t},\n\t\t\tvalue: template,\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn processString(template, options?.coerceSchema);\n}\n\n// ─── Internal Utilities ──────────────────────────────────────────────────────\n\n/**\n * Resolves the child `coerceSchema` for a given object key.\n *\n * When a `coerceSchema` is provided, navigates into its `properties`\n * to find the schema for the given key. This allows deeply nested\n * objects to propagate coercion at every level.\n *\n * @param coerceSchema - The parent coercion schema (may be `undefined`)\n * @param key - The object property key\n * @returns The child coercion schema, or `undefined`\n */\nexport function resolveChildCoerceSchema(\n\tcoerceSchema: JSONSchema7 | undefined,\n\tkey: string,\n): JSONSchema7 | undefined {\n\treturn coerceSchema ? resolveSchemaPath(coerceSchema, [key]) : undefined;\n}\n\n/**\n * Determines whether a `TemplateInput` value should be excluded when\n * `excludeTemplateExpression` is enabled.\n *\n * A value is excluded if it is a string containing at least one Handlebars\n * expression (`{{…}}`). Literals (number, boolean, null), plain strings\n * without expressions, objects, and arrays are never excluded at the\n * entry level — objects and arrays are recursively filtered by the\n * dispatching functions themselves.\n *\n * @param input - The template input to check\n * @returns `true` if the input should be excluded\n */\nexport function shouldExcludeEntry(input: TemplateInput): boolean {\n\treturn typeof input === \"string\" && hasHandlebarsExpression(input);\n}\n"],"names":["dispatchAnalyze","dispatchAnalyzeAndExecute","dispatchExecute","resolveChildCoerceSchema","shouldExcludeEntry","template","options","analyzeString","recurse","isArrayInput","exclude","excludeTemplateExpression","kept","filter","item","aggregateArrayAnalysis","length","index","isObjectInput","dispatchObjectAnalysis","isLiteralInput","valid","diagnostics","outputSchema","inferPrimitiveSchema","coerceSchema","keys","Object","key","aggregateObjectAnalysis","childCoerceSchema","identifierSchemas","executeString","result","element","push","value","entries","processString","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysisAndExecution","identifierData","analysis","resolveSchemaPath","undefined","input","hasHandlebarsExpression"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/dispatch.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport { hasHandlebarsExpression } from \"./parser.ts\";\nimport { resolveSchemaPath } from \"./schema-resolver.ts\";\nimport type { AnalysisResult, TemplateInput } from \"./types.ts\";\nimport {\n\tinferPrimitiveSchema,\n\tisArrayInput,\n\tisLiteralInput,\n\tisObjectInput,\n} from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n} from \"./utils.ts\";\n\n// ─── Template Input Dispatching ──────────────────────────────────────────────\n// Factorized dispatching for recursive processing of `TemplateInput` values.\n//\n// Every method in the engine (`analyze`, `execute`, `analyzeAndExecute`,\n// `compile`) follows the same recursive pattern:\n//\n// 1. If the input is an **array** → process each element recursively\n// 2. If the input is an **object** → process each property recursively\n// 3. If the input is a **literal** (number, boolean, null) → passthrough\n// 4. If the input is a **string** → delegate to a template-specific handler\n//\n// This module extracts the common dispatching logic into generic functions\n// that accept a callback for the string (template) case. This eliminates\n// the duplication across `Typebars`, `CompiledTemplate`, and `analyzer.ts`.\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Options controlling recursive dispatching behavior */\nexport interface DispatchAnalyzeOptions {\n\t/** Schemas by template identifier */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Explicit coercion schema for static literal output type */\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n/** Options controlling recursive execution dispatching */\nexport interface DispatchExecuteOptions {\n\t/** Explicit coercion schema for output type coercion */\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n// ─── Analysis Dispatching ────────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for analysis, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to analyze\n * @param options - Dispatching options (coerceSchema, excludeTemplateExpression)\n * @param analyzeString - Callback for analyzing a string template.\n * Receives `(template, coerceSchema?)` and must return an `AnalysisResult`.\n * @param recurse - Callback for recursively analyzing a child `TemplateInput`.\n * Receives `(child, options?)` and must return an `AnalysisResult`.\n * This allows callers (like `Typebars`) to rebind `this` or inject\n * additional context on each recursive call.\n * @returns An `AnalysisResult`\n */\nexport function dispatchAnalyze(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeOptions | undefined,\n\tanalyzeString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => AnalysisResult,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\t\tconst childOptions = resolveArrayChildOptions(options);\n\t\tif (exclude) {\n\t\t\tconst kept = template.filter(\n\t\t\t\t(item) => !shouldExcludeEntry(item as TemplateInput),\n\t\t\t);\n\t\t\treturn aggregateArrayAnalysis(kept.length, (index) =>\n\t\t\t\trecurse(kept[index] as TemplateInput, childOptions),\n\t\t\t);\n\t\t}\n\t\treturn aggregateArrayAnalysis(template.length, (index) =>\n\t\t\trecurse(template[index] as TemplateInput, childOptions),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\treturn dispatchObjectAnalysis(template, options, recurse);\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tvalid: true,\n\t\t\tdiagnostics: [],\n\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn analyzeString(template, options?.coerceSchema);\n}\n\n/**\n * Dispatches object analysis with `coerceSchema` propagation and\n * `excludeTemplateExpression` filtering.\n *\n * Extracted as a separate function because the object case is the most\n * complex (key filtering + per-key coerceSchema resolution).\n */\nfunction dispatchObjectAnalysis(\n\ttemplate: Record<string, TemplateInput>,\n\toptions: DispatchAnalyzeOptions | undefined,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\tconst coerceSchema = options?.coerceSchema;\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\tconst keys = exclude\n\t\t? Object.keys(template).filter(\n\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t)\n\t\t: Object.keys(template);\n\n\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t});\n\t});\n}\n\n// ─── Execution Dispatching ───────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for execution, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to execute\n * @param options - Dispatching options (coerceSchema)\n * @param executeString - Callback for executing a string template.\n * Receives `(template, coerceSchema?)` and must return the result.\n * @param recurse - Callback for recursively executing a child `TemplateInput`.\n * Receives `(child, options?)` and must return the result.\n * @returns The execution result\n */\nexport function dispatchExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchExecuteOptions | undefined,\n\texecuteString: (template: string, coerceSchema?: JSONSchema7) => unknown,\n\trecurse: (child: TemplateInput, options?: DispatchExecuteOptions) => unknown,\n): unknown {\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst childOptions = resolveArrayChildOptions(options);\n\t\tconst elements = exclude\n\t\t\t? template.filter((item) => !shouldExcludeEntry(item as TemplateInput))\n\t\t\t: template;\n\t\tconst result: unknown[] = [];\n\t\tfor (const element of elements) {\n\t\t\tresult.push(recurse(element as TemplateInput, childOptions));\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\tconst result: Record<string, unknown> = {};\n\t\tconst keys = exclude\n\t\t\t? Object.keys(template).filter(\n\t\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t\t)\n\t\t\t: Object.keys(template);\n\t\tfor (const key of keys) {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\tresult[key] = recurse(template[key] as TemplateInput, {\n\t\t\t\t...options,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) return template;\n\n\t// ── String template ──────────────────────────────────────────────────\n\t// At root level, if the string contains expressions and exclude is on,\n\t// return null (there is no parent to remove it from).\n\tif (exclude && shouldExcludeEntry(template)) {\n\t\treturn null;\n\t}\n\n\treturn executeString(template, options?.coerceSchema);\n}\n\n// ─── Analyze-and-Execute Dispatching ─────────────────────────────────────────\n\n/** Options for combined analyze-and-execute dispatching */\nexport interface DispatchAnalyzeAndExecuteOptions {\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n/**\n * Dispatches a `TemplateInput` for combined analysis and execution,\n * handling array/object/literal cases generically and delegating\n * the string case to a callback.\n *\n * @param template - The input to process\n * @param options - Options (identifierSchemas, identifierData, coerceSchema)\n * @param processString - Callback for analyzing and executing a string template.\n * Receives `(template, coerceSchema?)` and must return\n * `{ analysis, value }`.\n * @param recurse - Callback for recursively processing a child `TemplateInput`.\n * @returns `{ analysis, value }` where `value` is `undefined` if analysis fails\n */\nexport function dispatchAnalyzeAndExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeAndExecuteOptions | undefined,\n\tprocessString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => { analysis: AnalysisResult; value: unknown },\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeAndExecuteOptions,\n\t) => { analysis: AnalysisResult; value: unknown },\n): { analysis: AnalysisResult; value: unknown } {\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst childOptions = resolveArrayChildOptions(options);\n\t\tconst elements = exclude\n\t\t\t? template.filter((item) => !shouldExcludeEntry(item as TemplateInput))\n\t\t\t: template;\n\t\treturn aggregateArrayAnalysisAndExecution(elements.length, (index) =>\n\t\t\trecurse(elements[index] as TemplateInput, childOptions),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\tconst keys = exclude\n\t\t\t? Object.keys(template).filter(\n\t\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t\t)\n\t\t\t: Object.keys(template);\n\t\treturn aggregateObjectAnalysisAndExecution(keys, (key) => {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t\t});\n\t\t});\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tanalysis: {\n\t\t\t\tvalid: true,\n\t\t\t\tdiagnostics: [],\n\t\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t\t},\n\t\t\tvalue: template,\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\t// At root level, if the string contains expressions and exclude is on,\n\t// return null with a valid analysis (no parent to remove from).\n\tif (exclude && shouldExcludeEntry(template)) {\n\t\treturn {\n\t\t\tanalysis: {\n\t\t\t\tvalid: true,\n\t\t\t\tdiagnostics: [],\n\t\t\t\toutputSchema: { type: \"null\" },\n\t\t\t},\n\t\t\tvalue: null,\n\t\t};\n\t}\n\n\treturn processString(template, options?.coerceSchema);\n}\n\n// ─── Internal Utilities ──────────────────────────────────────────────────────\n\n/**\n * Resolves the child options for array element recursion.\n *\n * When a `coerceSchema` with `items` is provided, the child options\n * will use `coerceSchema.items` as the element-level coercion schema.\n * All other options are passed through unchanged.\n *\n * @param options - The parent dispatching options (may be `undefined`)\n * @returns New options with `coerceSchema` resolved to the items schema, or\n * the original options if no items schema is available.\n */\nfunction resolveArrayChildOptions<\n\tT extends { coerceSchema?: JSONSchema7 } | undefined,\n>(options: T): T {\n\tif (!options?.coerceSchema) return options;\n\n\tconst itemsSchema = resolveItemsCoerceSchema(options.coerceSchema);\n\tif (itemsSchema === options.coerceSchema) return options;\n\n\treturn { ...options, coerceSchema: itemsSchema };\n}\n\n/**\n * Extracts the `items` schema from an array-typed `coerceSchema`.\n *\n * If the schema declares `items` as a single schema (not a tuple),\n * returns that schema. Otherwise returns `undefined`.\n *\n * @param coerceSchema - The parent coercion schema\n * @returns The items coercion schema, or `undefined`\n */\nfunction resolveItemsCoerceSchema(\n\tcoerceSchema: JSONSchema7,\n): JSONSchema7 | undefined {\n\tif (typeof coerceSchema === \"boolean\") return undefined;\n\n\tconst items = coerceSchema.items;\n\tif (items != null && typeof items === \"object\" && !Array.isArray(items)) {\n\t\treturn items as JSONSchema7;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Resolves the child `coerceSchema` for a given object key.\n *\n * When a `coerceSchema` is provided, navigates into its `properties`\n * to find the schema for the given key. This allows deeply nested\n * objects to propagate coercion at every level.\n *\n * @param coerceSchema - The parent coercion schema (may be `undefined`)\n * @param key - The object property key\n * @returns The child coercion schema, or `undefined`\n */\nexport function resolveChildCoerceSchema(\n\tcoerceSchema: JSONSchema7 | undefined,\n\tkey: string,\n): JSONSchema7 | undefined {\n\treturn coerceSchema ? resolveSchemaPath(coerceSchema, [key]) : undefined;\n}\n\n/**\n * Determines whether a `TemplateInput` value should be excluded when\n * `excludeTemplateExpression` is enabled.\n *\n * A value is excluded if it is a string containing at least one Handlebars\n * expression (`{{…}}`). Literals (number, boolean, null), plain strings\n * without expressions, objects, and arrays are never excluded at the\n * entry level — objects and arrays are recursively filtered by the\n * dispatching functions themselves.\n *\n * @param input - The template input to check\n * @returns `true` if the input should be excluded\n */\nexport function shouldExcludeEntry(input: TemplateInput): boolean {\n\treturn typeof input === \"string\" && hasHandlebarsExpression(input);\n}\n"],"names":["dispatchAnalyze","dispatchAnalyzeAndExecute","dispatchExecute","resolveChildCoerceSchema","shouldExcludeEntry","template","options","analyzeString","recurse","isArrayInput","exclude","excludeTemplateExpression","childOptions","resolveArrayChildOptions","kept","filter","item","aggregateArrayAnalysis","length","index","isObjectInput","dispatchObjectAnalysis","isLiteralInput","valid","diagnostics","outputSchema","inferPrimitiveSchema","coerceSchema","keys","Object","key","aggregateObjectAnalysis","childCoerceSchema","identifierSchemas","executeString","elements","result","element","push","processString","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysisAndExecution","identifierData","analysis","value","type","itemsSchema","resolveItemsCoerceSchema","undefined","items","Array","isArray","resolveSchemaPath","input","hasHandlebarsExpression"],"mappings":"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"}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -207,6 +207,24 @@ export interface ExecuteOptions {
|
|
|
207
207
|
* coerced to match the declared type instead of using auto-detection.
|
|
208
208
|
*/
|
|
209
209
|
coerceSchema?: JSONSchema7;
|
|
210
|
+
/**
|
|
211
|
+
* When `true`, properties whose values contain Handlebars expressions
|
|
212
|
+
* (i.e. any `{{…}}` syntax) are excluded from the execution result.
|
|
213
|
+
*
|
|
214
|
+
* - **Object**: properties with template expressions are omitted from
|
|
215
|
+
* the resulting object.
|
|
216
|
+
* - **Array**: elements with template expressions are omitted from
|
|
217
|
+
* the resulting array.
|
|
218
|
+
* - **Root string** with expressions: returns `null` (there is no
|
|
219
|
+
* parent to exclude from).
|
|
220
|
+
* - **Literals** (number, boolean, null): unaffected.
|
|
221
|
+
*
|
|
222
|
+
* This mirrors the analysis-side `excludeTemplateExpression` option
|
|
223
|
+
* but applied at runtime.
|
|
224
|
+
*
|
|
225
|
+
* @default false
|
|
226
|
+
*/
|
|
227
|
+
excludeTemplateExpression?: boolean;
|
|
210
228
|
}
|
|
211
229
|
export interface AnalyzeAndExecuteOptions {
|
|
212
230
|
/** Schemas by identifier `{ [id]: JSONSchema7 }` for static analysis */
|
package/dist/cjs/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport type { FromSchema, JSONSchema } from \"json-schema-to-ts\";\n\n// ─── Template Input ──────────────────────────────────────────────────────────\n// The engine accepts primitive values in addition to template strings.\n// When a non-string value is passed, it is treated as a literal passthrough:\n// analysis returns the inferred type, and execution returns the value as-is.\n\n/**\n * Object where each property is a `TemplateInput` (recursive).\n *\n * Allows passing an entire structure as a template:\n * ```\n * engine.analyze({\n * userName: \"{{name}}\",\n * userAge: \"{{age}}\",\n * nested: { x: \"{{foo}}\" },\n * }, inputSchema);\n * ```\n */\nexport interface TemplateInputObject {\n\t[key: string]: TemplateInput;\n}\n\n/**\n * Array where each element is a `TemplateInput` (recursive).\n *\n * Allows passing an array as a template:\n * ```\n * engine.analyze([\"{{name}}\", \"{{age}}\"], inputSchema);\n * engine.execute([\"{{name}}\", 42], data);\n * ```\n */\nexport type TemplateInputArray = TemplateInput[];\n\n/**\n * Input type accepted by the template engine.\n *\n * - `string` → standard Handlebars template (parsed and executed)\n * - `number` → numeric literal (passthrough)\n * - `boolean` → boolean literal (passthrough)\n * - `null` → null literal (passthrough)\n * - `TemplateInputArray` → array where each element is a `TemplateInput`\n * - `TemplateInputObject` → object where each property is a `TemplateInput`\n */\nexport type TemplateInput =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| TemplateInputArray\n\t| TemplateInputObject;\n\n// ─── Template Data ───────────────────────────────────────────────────────────\n// The data parameter accepted by `execute()` and `analyzeAndExecute()`.\n// In most cases this is a `Record<string, unknown>` (object context), but\n// primitives are also allowed — for example when using `{{$root}}` to\n// reference the entire data value directly.\n\n/**\n * Data type accepted by the template engine's execution methods.\n *\n * - `Record<string, unknown>` → standard object context (most common)\n * - `string` → primitive value (e.g. for `{{$root}}`)\n * - `number` → primitive value\n * - `boolean` → primitive value\n * - `null` → null value\n * - `unknown[]` → array value\n */\nexport type TemplateData =\n\t| Record<string, unknown>\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| unknown[];\n\n/**\n * Checks whether a value is a non-string primitive literal (number, boolean, null).\n * These values are treated as passthrough by the engine.\n *\n * Note: objects (`TemplateInputObject`) and arrays (`TemplateInputArray`) are NOT literals.\n */\nexport function isLiteralInput(\n\tinput: TemplateInput,\n): input is number | boolean | null {\n\treturn (\n\t\tinput === null || (typeof input !== \"string\" && typeof input !== \"object\")\n\t);\n}\n\n/**\n * Checks whether a value is a template array (`TemplateInputArray`).\n * Template arrays are processed recursively by the engine:\n * each element is analyzed/executed individually and the result is an array.\n */\nexport function isArrayInput(\n\tinput: TemplateInput,\n): input is TemplateInputArray {\n\treturn Array.isArray(input);\n}\n\n/**\n * Checks whether a value is a template object (`TemplateInputObject`).\n * Template objects are processed recursively by the engine:\n * each property is analyzed/executed individually.\n *\n * Note: arrays are excluded — use `isArrayInput()` first.\n */\nexport function isObjectInput(\n\tinput: TemplateInput,\n): input is TemplateInputObject {\n\treturn input !== null && typeof input === \"object\" && !Array.isArray(input);\n}\n\n/**\n * Infers the JSON Schema of a non-string primitive value.\n *\n * @param value - The primitive value (number, boolean, null)\n * @returns The corresponding JSON Schema\n *\n * @example\n * ```\n * inferPrimitiveSchema(42) // → { type: \"number\" }\n * inferPrimitiveSchema(true) // → { type: \"boolean\" }\n * inferPrimitiveSchema(null) // → { type: \"null\" }\n * ```\n */\nexport function inferPrimitiveSchema(\n\tvalue: number | boolean | null,\n): JSONSchema7 {\n\tif (value === null) return { type: \"null\" };\n\tif (typeof value === \"boolean\") return { type: \"boolean\" };\n\tif (typeof value === \"number\") {\n\t\treturn Number.isInteger(value) ? { type: \"integer\" } : { type: \"number\" };\n\t}\n\t// Exhaustiveness check — all branches are covered above.\n\t// If the type of `value` changes, TypeScript will raise an error here.\n\tvalue satisfies never;\n\treturn { type: \"null\" };\n}\n\n// ─── Diagnostic Codes ────────────────────────────────────────────────────────\n// Machine-readable codes for each error/warning type, enabling the frontend\n// to react programmatically without parsing the human-readable message.\n\nexport type DiagnosticCode =\n\t/** The referenced property does not exist in the context schema */\n\t| \"UNKNOWN_PROPERTY\"\n\t/** Type mismatch (e.g. #each on a non-array) */\n\t| \"TYPE_MISMATCH\"\n\t/** A block helper is used without a required argument */\n\t| \"MISSING_ARGUMENT\"\n\t/** Unknown block helper (neither built-in nor registered) */\n\t| \"UNKNOWN_HELPER\"\n\t/** The expression cannot be statically analyzed */\n\t| \"UNANALYZABLE\"\n\t/** The {{key:N}} syntax is used but no identifierSchemas were provided */\n\t| \"MISSING_IDENTIFIER_SCHEMAS\"\n\t/** The identifier N does not exist in the provided identifierSchemas */\n\t| \"UNKNOWN_IDENTIFIER\"\n\t/** The property does not exist in the identifier's schema */\n\t| \"IDENTIFIER_PROPERTY_NOT_FOUND\"\n\t/** Syntax error in the template */\n\t| \"PARSE_ERROR\"\n\t/** The $root token is used with path traversal (e.g. $root.name) */\n\t| \"ROOT_PATH_TRAVERSAL\";\n\n// ─── Diagnostic Details ──────────────────────────────────────────────────────\n// Supplementary information to understand the exact cause of the error.\n// Designed to be easily JSON-serializable and consumable by a frontend.\n\nexport interface DiagnosticDetails {\n\t/** Path of the expression that caused the error (e.g. `\"user.name.foo\"`) */\n\tpath?: string;\n\t/** Name of the helper involved (for helper-related errors) */\n\thelperName?: string;\n\t/** What was expected (e.g. `\"array\"`, `\"property to exist\"`) */\n\texpected?: string;\n\t/** What was found (e.g. `\"string\"`, `\"undefined\"`) */\n\tactual?: string;\n\t/** Available properties in the current schema (for suggestions) */\n\tavailableProperties?: string[];\n\t/** Template identifier number (for `{{key:N}}` errors) */\n\tidentifier?: number;\n}\n\n// ─── Static Analysis Result ──────────────────────────────────────────────────\n\n/** Diagnostic produced by the static analyzer */\nexport interface TemplateDiagnostic {\n\t/** \"error\" blocks execution, \"warning\" is informational */\n\tseverity: \"error\" | \"warning\";\n\n\t/** Machine-readable code identifying the error type */\n\tcode: DiagnosticCode;\n\n\t/** Human-readable message describing the problem */\n\tmessage: string;\n\n\t/** Position in the template source (if available from the AST) */\n\tloc?: {\n\t\tstart: { line: number; column: number };\n\t\tend: { line: number; column: number };\n\t};\n\n\t/** Fragment of the template source around the error */\n\tsource?: string;\n\n\t/** Structured information for debugging and frontend display */\n\tdetails?: DiagnosticDetails;\n}\n\n/** Complete result of the static analysis */\nexport interface AnalysisResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n\t/** JSON Schema describing the template's return type */\n\toutputSchema: JSONSchema7;\n}\n\n/** Lightweight validation result (without output type inference) */\nexport interface ValidationResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n}\n\n// ─── Public Engine Options ───────────────────────────────────────────────────\n\nexport interface TemplateEngineOptions {\n\t/**\n\t * Capacity of the parsed AST cache. Each parsed template is cached\n\t * to avoid costly re-parsing on repeated calls.\n\t * @default 256\n\t */\n\tastCacheSize?: number;\n\n\t/**\n\t * Capacity of the compiled Handlebars template cache.\n\t * @default 256\n\t */\n\tcompilationCacheSize?: number;\n\n\t/**\n\t * Custom helpers to register during engine construction.\n\t *\n\t * Each entry describes a helper with its name, implementation,\n\t * expected parameters, and return type.\n\t *\n\t * @example\n\t * ```\n\t * const engine = new Typebars({\n\t * helpers: [\n\t * {\n\t * name: \"uppercase\",\n\t * description: \"Converts a string to uppercase\",\n\t * fn: (value: string) => String(value).toUpperCase(),\n\t * params: [\n\t * { name: \"value\", type: { type: \"string\" }, description: \"The string to convert\" },\n\t * ],\n\t * returnType: { type: \"string\" },\n\t * },\n\t * ],\n\t * });\n\t * ```\n\t */\n\thelpers?: HelperConfig[];\n}\n\n// ─── Execution Options ───────────────────────────────────────────────────────\n// Optional options object for `execute()`, replacing multiple positional\n// parameters for better ergonomics.\n\nexport interface ExecuteOptions {\n\t/** JSON Schema for pre-execution static validation */\n\tschema?: JSONSchema7;\n\t/** Data by identifier `{ [id]: { key: value } }` */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/** Schemas by identifier (for static validation with identifiers) */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Combined Analyze-and-Execute Options ────────────────────────────────────\n// Optional options object for `analyzeAndExecute()`, grouping parameters\n// related to template identifiers.\n\nexport interface AnalyzeAndExecuteOptions {\n\t/** Schemas by identifier `{ [id]: JSONSchema7 }` for static analysis */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Data by identifier `{ [id]: { key: value } }` for execution */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Custom Helpers ──────────────────────────────────────────────────────────\n// Allows registering custom helpers with their type signature for static\n// analysis support.\n\n/** Describes a parameter expected by a helper */\nexport interface HelperParam {\n\t/** Parameter name (for documentation / introspection) */\n\tname: string;\n\n\t/**\n\t * JSON Schema describing the expected type for this parameter.\n\t * Used for documentation and static validation.\n\t */\n\ttype?: JSONSchema7;\n\n\t/** Human-readable description of the parameter */\n\tdescription?: string;\n\n\t/**\n\t * Whether the parameter is optional.\n\t * @default false\n\t */\n\toptional?: boolean;\n}\n\n/**\n * Definition of a helper registerable via `registerHelper()`.\n *\n * Contains the runtime implementation and typing metadata\n * for static analysis.\n */\nexport interface HelperDefinition {\n\t/**\n\t * Runtime implementation of the helper — will be registered with Handlebars.\n\t *\n\t * For an inline helper `{{uppercase name}}`:\n\t * `(value: string) => string`\n\t *\n\t * For a block helper `{{#repeat count}}...{{/repeat}}`:\n\t * `function(this: any, count: number, options: Handlebars.HelperOptions) { ... }`\n\t */\n\t// biome-ignore lint/suspicious/noExplicitAny: Handlebars helper signatures are inherently dynamic\n\tfn: (...args: any[]) => unknown;\n\n\t/**\n\t * Parameters expected by the helper (for documentation and analysis).\n\t *\n\t * @example\n\t * ```\n\t * params: [\n\t * { name: \"value\", type: { type: \"number\" }, description: \"The value to round\" },\n\t * { name: \"precision\", type: { type: \"number\" }, description: \"Decimal places\", optional: true },\n\t * ]\n\t * ```\n\t */\n\tparams?: HelperParam[];\n\n\t/**\n\t * JSON Schema describing the helper's return type for static analysis.\n\t * @default { type: \"string\" }\n\t */\n\treturnType?: JSONSchema7;\n\n\t/** Human-readable description of the helper */\n\tdescription?: string;\n}\n\n/**\n * Full helper configuration for registration via the `Typebars({ helpers: [...] })`\n * constructor options.\n *\n * Extends `HelperDefinition` with a required `name`.\n *\n * @example\n * ```\n * const config: HelperConfig = {\n * name: \"round\",\n * description: \"Rounds a number to a given precision\",\n * fn: (value: number, precision?: number) => { ... },\n * params: [\n * { name: \"value\", type: { type: \"number\" } },\n * { name: \"precision\", type: { type: \"number\" }, optional: true },\n * ],\n * returnType: { type: \"number\" },\n * };\n * ```\n */\nexport interface HelperConfig extends HelperDefinition {\n\t/** Name of the helper as used in templates (e.g. `\"uppercase\"`) */\n\tname: string;\n}\n\n// ─── Automatic Type Inference via json-schema-to-ts ──────────────────────────\n// Allows `defineHelper()` to infer TypeScript types for `fn` arguments\n// from the JSON Schemas declared in `params`.\n\n/**\n * Param definition used for type inference.\n * Accepts `JSONSchema` from `json-schema-to-ts` to allow `FromSchema`\n * to resolve literal types.\n */\ntype TypedHelperParam = {\n\treadonly name: string;\n\treadonly type?: JSONSchema;\n\treadonly description?: string;\n\treadonly optional?: boolean;\n};\n\n/**\n * Infers the TypeScript type of a single parameter from its JSON Schema.\n * - If `optional: true`, the resolved type is unioned with `undefined`.\n * - If `type` is not provided, the type is `unknown`.\n */\ntype InferParamType<P> = P extends {\n\treadonly type: infer S extends JSONSchema;\n\treadonly optional: true;\n}\n\t? FromSchema<S> | undefined\n\t: P extends { readonly type: infer S extends JSONSchema }\n\t\t? FromSchema<S>\n\t\t: unknown;\n\n/**\n * Maps a tuple of `TypedHelperParam` to a tuple of inferred TypeScript types,\n * usable as the `fn` signature.\n *\n * @example\n * ```\n * type Args = InferArgs<readonly [\n * { name: \"a\"; type: { type: \"string\" } },\n * { name: \"b\"; type: { type: \"number\" }; optional: true },\n * ]>;\n * // => [string, number | undefined]\n * ```\n */\ntype InferArgs<P extends readonly TypedHelperParam[]> = {\n\t[K in keyof P]: InferParamType<P[K]>;\n};\n\n/**\n * Helper configuration with generic parameter inference.\n * Used exclusively by `defineHelper()`.\n */\ninterface TypedHelperConfig<P extends readonly TypedHelperParam[]> {\n\tname: string;\n\tdescription?: string;\n\tparams: P;\n\tfn: (...args: InferArgs<P>) => unknown;\n\treturnType?: JSONSchema;\n}\n\n/**\n * Creates a `HelperConfig` with automatic type inference for `fn` arguments\n * based on the JSON Schemas declared in `params`.\n *\n * The generic parameter `const P` preserves schema literal types\n * (equivalent of `as const`), enabling `FromSchema` to resolve the\n * corresponding TypeScript types.\n *\n * @example\n * ```\n * const helper = defineHelper({\n * name: \"concat\",\n * description: \"Concatenates two strings\",\n * params: [\n * { name: \"a\", type: { type: \"string\" }, description: \"First string\" },\n * { name: \"b\", type: { type: \"string\" }, description: \"Second string\" },\n * { name: \"sep\", type: { type: \"string\" }, description: \"Separator\", optional: true },\n * ],\n * fn: (a, b, sep) => {\n * // a: string, b: string, sep: string | undefined\n * const separator = sep ?? \"\";\n * return `${a}${separator}${b}`;\n * },\n * returnType: { type: \"string\" },\n * });\n * ```\n */\nexport function defineHelper<const P extends readonly TypedHelperParam[]>(\n\tconfig: TypedHelperConfig<P>,\n): HelperConfig {\n\treturn config as unknown as HelperConfig;\n}\n"],"names":["defineHelper","inferPrimitiveSchema","isArrayInput","isLiteralInput","isObjectInput","input","Array","isArray","value","type","Number","isInteger","config"],"mappings":"mPAuegBA,sBAAAA,kBAvWAC,8BAAAA,0BAhCAC,sBAAAA,kBAbAC,wBAAAA,oBA0BAC,uBAAAA,iBA1BT,SAASD,eACfE,KAAoB,EAEpB,OACCA,QAAU,MAAS,OAAOA,QAAU,UAAY,OAAOA,QAAU,QAEnE,CAOO,SAASH,aACfG,KAAoB,EAEpB,OAAOC,MAAMC,OAAO,CAACF,MACtB,CASO,SAASD,cACfC,KAAoB,EAEpB,OAAOA,QAAU,MAAQ,OAAOA,QAAU,UAAY,CAACC,MAAMC,OAAO,CAACF,MACtE,CAeO,SAASJ,qBACfO,KAA8B,EAE9B,GAAIA,QAAU,KAAM,MAAO,CAAEC,KAAM,MAAO,EAC1C,GAAI,OAAOD,QAAU,UAAW,MAAO,CAAEC,KAAM,SAAU,EACzD,GAAI,OAAOD,QAAU,SAAU,CAC9B,OAAOE,OAAOC,SAAS,CAACH,OAAS,CAAEC,KAAM,SAAU,EAAI,CAAEA,KAAM,QAAS,CACzE,CAGAD,MACA,MAAO,CAAEC,KAAM,MAAO,CACvB,CA2VO,SAAST,aACfY,MAA4B,EAE5B,OAAOA,MACR"}
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport type { FromSchema, JSONSchema } from \"json-schema-to-ts\";\n\n// ─── Template Input ──────────────────────────────────────────────────────────\n// The engine accepts primitive values in addition to template strings.\n// When a non-string value is passed, it is treated as a literal passthrough:\n// analysis returns the inferred type, and execution returns the value as-is.\n\n/**\n * Object where each property is a `TemplateInput` (recursive).\n *\n * Allows passing an entire structure as a template:\n * ```\n * engine.analyze({\n * userName: \"{{name}}\",\n * userAge: \"{{age}}\",\n * nested: { x: \"{{foo}}\" },\n * }, inputSchema);\n * ```\n */\nexport interface TemplateInputObject {\n\t[key: string]: TemplateInput;\n}\n\n/**\n * Array where each element is a `TemplateInput` (recursive).\n *\n * Allows passing an array as a template:\n * ```\n * engine.analyze([\"{{name}}\", \"{{age}}\"], inputSchema);\n * engine.execute([\"{{name}}\", 42], data);\n * ```\n */\nexport type TemplateInputArray = TemplateInput[];\n\n/**\n * Input type accepted by the template engine.\n *\n * - `string` → standard Handlebars template (parsed and executed)\n * - `number` → numeric literal (passthrough)\n * - `boolean` → boolean literal (passthrough)\n * - `null` → null literal (passthrough)\n * - `TemplateInputArray` → array where each element is a `TemplateInput`\n * - `TemplateInputObject` → object where each property is a `TemplateInput`\n */\nexport type TemplateInput =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| TemplateInputArray\n\t| TemplateInputObject;\n\n// ─── Template Data ───────────────────────────────────────────────────────────\n// The data parameter accepted by `execute()` and `analyzeAndExecute()`.\n// In most cases this is a `Record<string, unknown>` (object context), but\n// primitives are also allowed — for example when using `{{$root}}` to\n// reference the entire data value directly.\n\n/**\n * Data type accepted by the template engine's execution methods.\n *\n * - `Record<string, unknown>` → standard object context (most common)\n * - `string` → primitive value (e.g. for `{{$root}}`)\n * - `number` → primitive value\n * - `boolean` → primitive value\n * - `null` → null value\n * - `unknown[]` → array value\n */\nexport type TemplateData =\n\t| Record<string, unknown>\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| unknown[];\n\n/**\n * Checks whether a value is a non-string primitive literal (number, boolean, null).\n * These values are treated as passthrough by the engine.\n *\n * Note: objects (`TemplateInputObject`) and arrays (`TemplateInputArray`) are NOT literals.\n */\nexport function isLiteralInput(\n\tinput: TemplateInput,\n): input is number | boolean | null {\n\treturn (\n\t\tinput === null || (typeof input !== \"string\" && typeof input !== \"object\")\n\t);\n}\n\n/**\n * Checks whether a value is a template array (`TemplateInputArray`).\n * Template arrays are processed recursively by the engine:\n * each element is analyzed/executed individually and the result is an array.\n */\nexport function isArrayInput(\n\tinput: TemplateInput,\n): input is TemplateInputArray {\n\treturn Array.isArray(input);\n}\n\n/**\n * Checks whether a value is a template object (`TemplateInputObject`).\n * Template objects are processed recursively by the engine:\n * each property is analyzed/executed individually.\n *\n * Note: arrays are excluded — use `isArrayInput()` first.\n */\nexport function isObjectInput(\n\tinput: TemplateInput,\n): input is TemplateInputObject {\n\treturn input !== null && typeof input === \"object\" && !Array.isArray(input);\n}\n\n/**\n * Infers the JSON Schema of a non-string primitive value.\n *\n * @param value - The primitive value (number, boolean, null)\n * @returns The corresponding JSON Schema\n *\n * @example\n * ```\n * inferPrimitiveSchema(42) // → { type: \"number\" }\n * inferPrimitiveSchema(true) // → { type: \"boolean\" }\n * inferPrimitiveSchema(null) // → { type: \"null\" }\n * ```\n */\nexport function inferPrimitiveSchema(\n\tvalue: number | boolean | null,\n): JSONSchema7 {\n\tif (value === null) return { type: \"null\" };\n\tif (typeof value === \"boolean\") return { type: \"boolean\" };\n\tif (typeof value === \"number\") {\n\t\treturn Number.isInteger(value) ? { type: \"integer\" } : { type: \"number\" };\n\t}\n\t// Exhaustiveness check — all branches are covered above.\n\t// If the type of `value` changes, TypeScript will raise an error here.\n\tvalue satisfies never;\n\treturn { type: \"null\" };\n}\n\n// ─── Diagnostic Codes ────────────────────────────────────────────────────────\n// Machine-readable codes for each error/warning type, enabling the frontend\n// to react programmatically without parsing the human-readable message.\n\nexport type DiagnosticCode =\n\t/** The referenced property does not exist in the context schema */\n\t| \"UNKNOWN_PROPERTY\"\n\t/** Type mismatch (e.g. #each on a non-array) */\n\t| \"TYPE_MISMATCH\"\n\t/** A block helper is used without a required argument */\n\t| \"MISSING_ARGUMENT\"\n\t/** Unknown block helper (neither built-in nor registered) */\n\t| \"UNKNOWN_HELPER\"\n\t/** The expression cannot be statically analyzed */\n\t| \"UNANALYZABLE\"\n\t/** The {{key:N}} syntax is used but no identifierSchemas were provided */\n\t| \"MISSING_IDENTIFIER_SCHEMAS\"\n\t/** The identifier N does not exist in the provided identifierSchemas */\n\t| \"UNKNOWN_IDENTIFIER\"\n\t/** The property does not exist in the identifier's schema */\n\t| \"IDENTIFIER_PROPERTY_NOT_FOUND\"\n\t/** Syntax error in the template */\n\t| \"PARSE_ERROR\"\n\t/** The $root token is used with path traversal (e.g. $root.name) */\n\t| \"ROOT_PATH_TRAVERSAL\";\n\n// ─── Diagnostic Details ──────────────────────────────────────────────────────\n// Supplementary information to understand the exact cause of the error.\n// Designed to be easily JSON-serializable and consumable by a frontend.\n\nexport interface DiagnosticDetails {\n\t/** Path of the expression that caused the error (e.g. `\"user.name.foo\"`) */\n\tpath?: string;\n\t/** Name of the helper involved (for helper-related errors) */\n\thelperName?: string;\n\t/** What was expected (e.g. `\"array\"`, `\"property to exist\"`) */\n\texpected?: string;\n\t/** What was found (e.g. `\"string\"`, `\"undefined\"`) */\n\tactual?: string;\n\t/** Available properties in the current schema (for suggestions) */\n\tavailableProperties?: string[];\n\t/** Template identifier number (for `{{key:N}}` errors) */\n\tidentifier?: number;\n}\n\n// ─── Static Analysis Result ──────────────────────────────────────────────────\n\n/** Diagnostic produced by the static analyzer */\nexport interface TemplateDiagnostic {\n\t/** \"error\" blocks execution, \"warning\" is informational */\n\tseverity: \"error\" | \"warning\";\n\n\t/** Machine-readable code identifying the error type */\n\tcode: DiagnosticCode;\n\n\t/** Human-readable message describing the problem */\n\tmessage: string;\n\n\t/** Position in the template source (if available from the AST) */\n\tloc?: {\n\t\tstart: { line: number; column: number };\n\t\tend: { line: number; column: number };\n\t};\n\n\t/** Fragment of the template source around the error */\n\tsource?: string;\n\n\t/** Structured information for debugging and frontend display */\n\tdetails?: DiagnosticDetails;\n}\n\n/** Complete result of the static analysis */\nexport interface AnalysisResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n\t/** JSON Schema describing the template's return type */\n\toutputSchema: JSONSchema7;\n}\n\n/** Lightweight validation result (without output type inference) */\nexport interface ValidationResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n}\n\n// ─── Public Engine Options ───────────────────────────────────────────────────\n\nexport interface TemplateEngineOptions {\n\t/**\n\t * Capacity of the parsed AST cache. Each parsed template is cached\n\t * to avoid costly re-parsing on repeated calls.\n\t * @default 256\n\t */\n\tastCacheSize?: number;\n\n\t/**\n\t * Capacity of the compiled Handlebars template cache.\n\t * @default 256\n\t */\n\tcompilationCacheSize?: number;\n\n\t/**\n\t * Custom helpers to register during engine construction.\n\t *\n\t * Each entry describes a helper with its name, implementation,\n\t * expected parameters, and return type.\n\t *\n\t * @example\n\t * ```\n\t * const engine = new Typebars({\n\t * helpers: [\n\t * {\n\t * name: \"uppercase\",\n\t * description: \"Converts a string to uppercase\",\n\t * fn: (value: string) => String(value).toUpperCase(),\n\t * params: [\n\t * { name: \"value\", type: { type: \"string\" }, description: \"The string to convert\" },\n\t * ],\n\t * returnType: { type: \"string\" },\n\t * },\n\t * ],\n\t * });\n\t * ```\n\t */\n\thelpers?: HelperConfig[];\n}\n\n// ─── Execution Options ───────────────────────────────────────────────────────\n// Optional options object for `execute()`, replacing multiple positional\n// parameters for better ergonomics.\n\nexport interface ExecuteOptions {\n\t/** JSON Schema for pre-execution static validation */\n\tschema?: JSONSchema7;\n\t/** Data by identifier `{ [id]: { key: value } }` */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/** Schemas by identifier (for static validation with identifiers) */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n\t/**\n\t * When `true`, properties whose values contain Handlebars expressions\n\t * (i.e. any `{{…}}` syntax) are excluded from the execution result.\n\t *\n\t * - **Object**: properties with template expressions are omitted from\n\t * the resulting object.\n\t * - **Array**: elements with template expressions are omitted from\n\t * the resulting array.\n\t * - **Root string** with expressions: returns `null` (there is no\n\t * parent to exclude from).\n\t * - **Literals** (number, boolean, null): unaffected.\n\t *\n\t * This mirrors the analysis-side `excludeTemplateExpression` option\n\t * but applied at runtime.\n\t *\n\t * @default false\n\t */\n\texcludeTemplateExpression?: boolean;\n}\n\n// ─── Combined Analyze-and-Execute Options ────────────────────────────────────\n// Optional options object for `analyzeAndExecute()`, grouping parameters\n// related to template identifiers.\n\nexport interface AnalyzeAndExecuteOptions {\n\t/** Schemas by identifier `{ [id]: JSONSchema7 }` for static analysis */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Data by identifier `{ [id]: { key: value } }` for execution */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Custom Helpers ──────────────────────────────────────────────────────────\n// Allows registering custom helpers with their type signature for static\n// analysis support.\n\n/** Describes a parameter expected by a helper */\nexport interface HelperParam {\n\t/** Parameter name (for documentation / introspection) */\n\tname: string;\n\n\t/**\n\t * JSON Schema describing the expected type for this parameter.\n\t * Used for documentation and static validation.\n\t */\n\ttype?: JSONSchema7;\n\n\t/** Human-readable description of the parameter */\n\tdescription?: string;\n\n\t/**\n\t * Whether the parameter is optional.\n\t * @default false\n\t */\n\toptional?: boolean;\n}\n\n/**\n * Definition of a helper registerable via `registerHelper()`.\n *\n * Contains the runtime implementation and typing metadata\n * for static analysis.\n */\nexport interface HelperDefinition {\n\t/**\n\t * Runtime implementation of the helper — will be registered with Handlebars.\n\t *\n\t * For an inline helper `{{uppercase name}}`:\n\t * `(value: string) => string`\n\t *\n\t * For a block helper `{{#repeat count}}...{{/repeat}}`:\n\t * `function(this: any, count: number, options: Handlebars.HelperOptions) { ... }`\n\t */\n\t// biome-ignore lint/suspicious/noExplicitAny: Handlebars helper signatures are inherently dynamic\n\tfn: (...args: any[]) => unknown;\n\n\t/**\n\t * Parameters expected by the helper (for documentation and analysis).\n\t *\n\t * @example\n\t * ```\n\t * params: [\n\t * { name: \"value\", type: { type: \"number\" }, description: \"The value to round\" },\n\t * { name: \"precision\", type: { type: \"number\" }, description: \"Decimal places\", optional: true },\n\t * ]\n\t * ```\n\t */\n\tparams?: HelperParam[];\n\n\t/**\n\t * JSON Schema describing the helper's return type for static analysis.\n\t * @default { type: \"string\" }\n\t */\n\treturnType?: JSONSchema7;\n\n\t/** Human-readable description of the helper */\n\tdescription?: string;\n}\n\n/**\n * Full helper configuration for registration via the `Typebars({ helpers: [...] })`\n * constructor options.\n *\n * Extends `HelperDefinition` with a required `name`.\n *\n * @example\n * ```\n * const config: HelperConfig = {\n * name: \"round\",\n * description: \"Rounds a number to a given precision\",\n * fn: (value: number, precision?: number) => { ... },\n * params: [\n * { name: \"value\", type: { type: \"number\" } },\n * { name: \"precision\", type: { type: \"number\" }, optional: true },\n * ],\n * returnType: { type: \"number\" },\n * };\n * ```\n */\nexport interface HelperConfig extends HelperDefinition {\n\t/** Name of the helper as used in templates (e.g. `\"uppercase\"`) */\n\tname: string;\n}\n\n// ─── Automatic Type Inference via json-schema-to-ts ──────────────────────────\n// Allows `defineHelper()` to infer TypeScript types for `fn` arguments\n// from the JSON Schemas declared in `params`.\n\n/**\n * Param definition used for type inference.\n * Accepts `JSONSchema` from `json-schema-to-ts` to allow `FromSchema`\n * to resolve literal types.\n */\ntype TypedHelperParam = {\n\treadonly name: string;\n\treadonly type?: JSONSchema;\n\treadonly description?: string;\n\treadonly optional?: boolean;\n};\n\n/**\n * Infers the TypeScript type of a single parameter from its JSON Schema.\n * - If `optional: true`, the resolved type is unioned with `undefined`.\n * - If `type` is not provided, the type is `unknown`.\n */\ntype InferParamType<P> = P extends {\n\treadonly type: infer S extends JSONSchema;\n\treadonly optional: true;\n}\n\t? FromSchema<S> | undefined\n\t: P extends { readonly type: infer S extends JSONSchema }\n\t\t? FromSchema<S>\n\t\t: unknown;\n\n/**\n * Maps a tuple of `TypedHelperParam` to a tuple of inferred TypeScript types,\n * usable as the `fn` signature.\n *\n * @example\n * ```\n * type Args = InferArgs<readonly [\n * { name: \"a\"; type: { type: \"string\" } },\n * { name: \"b\"; type: { type: \"number\" }; optional: true },\n * ]>;\n * // => [string, number | undefined]\n * ```\n */\ntype InferArgs<P extends readonly TypedHelperParam[]> = {\n\t[K in keyof P]: InferParamType<P[K]>;\n};\n\n/**\n * Helper configuration with generic parameter inference.\n * Used exclusively by `defineHelper()`.\n */\ninterface TypedHelperConfig<P extends readonly TypedHelperParam[]> {\n\tname: string;\n\tdescription?: string;\n\tparams: P;\n\tfn: (...args: InferArgs<P>) => unknown;\n\treturnType?: JSONSchema;\n}\n\n/**\n * Creates a `HelperConfig` with automatic type inference for `fn` arguments\n * based on the JSON Schemas declared in `params`.\n *\n * The generic parameter `const P` preserves schema literal types\n * (equivalent of `as const`), enabling `FromSchema` to resolve the\n * corresponding TypeScript types.\n *\n * @example\n * ```\n * const helper = defineHelper({\n * name: \"concat\",\n * description: \"Concatenates two strings\",\n * params: [\n * { name: \"a\", type: { type: \"string\" }, description: \"First string\" },\n * { name: \"b\", type: { type: \"string\" }, description: \"Second string\" },\n * { name: \"sep\", type: { type: \"string\" }, description: \"Separator\", optional: true },\n * ],\n * fn: (a, b, sep) => {\n * // a: string, b: string, sep: string | undefined\n * const separator = sep ?? \"\";\n * return `${a}${separator}${b}`;\n * },\n * returnType: { type: \"string\" },\n * });\n * ```\n */\nexport function defineHelper<const P extends readonly TypedHelperParam[]>(\n\tconfig: TypedHelperConfig<P>,\n): HelperConfig {\n\treturn config as unknown as HelperConfig;\n}\n"],"names":["defineHelper","inferPrimitiveSchema","isArrayInput","isLiteralInput","isObjectInput","input","Array","isArray","value","type","Number","isInteger","config"],"mappings":"mPAyfgBA,sBAAAA,kBAzXAC,8BAAAA,0BAhCAC,sBAAAA,kBAbAC,wBAAAA,oBA0BAC,uBAAAA,iBA1BT,SAASD,eACfE,KAAoB,EAEpB,OACCA,QAAU,MAAS,OAAOA,QAAU,UAAY,OAAOA,QAAU,QAEnE,CAOO,SAASH,aACfG,KAAoB,EAEpB,OAAOC,MAAMC,OAAO,CAACF,MACtB,CASO,SAASD,cACfC,KAAoB,EAEpB,OAAOA,QAAU,MAAQ,OAAOA,QAAU,UAAY,CAACC,MAAMC,OAAO,CAACF,MACtE,CAeO,SAASJ,qBACfO,KAA8B,EAE9B,GAAIA,QAAU,KAAM,MAAO,CAAEC,KAAM,MAAO,EAC1C,GAAI,OAAOD,QAAU,UAAW,MAAO,CAAEC,KAAM,SAAU,EACzD,GAAI,OAAOD,QAAU,SAAU,CAC9B,OAAOE,OAAOC,SAAS,CAACH,OAAS,CAAEC,KAAM,SAAU,EAAI,CAAEA,KAAM,QAAS,CACzE,CAGAD,MACA,MAAO,CAAEC,KAAM,MAAO,CACvB,CA6WO,SAAST,aACfY,MAA4B,EAE5B,OAAOA,MACR"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import{analyzeFromAst}from"./analyzer.js";import{resolveChildCoerceSchema,shouldExcludeEntry}from"./dispatch.js";import{TemplateAnalysisError}from"./errors.js";import{executeFromAst}from"./executor.js";import{inferPrimitiveSchema}from"./types.js";import{aggregateArrayAnalysis,aggregateArrayAnalysisAndExecution,aggregateObjectAnalysis,aggregateObjectAnalysisAndExecution}from"./utils.js";export class CompiledTemplate{get ast(){return this.state.kind==="template"?this.state.ast:null}get template(){return this.state.kind==="template"?this.state.source:""}static fromTemplate(ast,source,options){return new CompiledTemplate({kind:"template",ast,source},options)}static fromLiteral(value,options){return new CompiledTemplate({kind:"literal",value},options)}static fromObject(children,options){return new CompiledTemplate({kind:"object",children},options)}static fromArray(elements,options){return new CompiledTemplate({kind:"array",elements},options)}analyze(inputSchema={},options){const exclude=options?.excludeTemplateExpression===true;switch(this.state.kind){case"array":{const{elements}=this.state;if(exclude){const kept=elements.filter(el=>!isCompiledTemplateWithExpression(el));return aggregateArrayAnalysis(kept.length,index=>{const element=kept[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}return aggregateArrayAnalysis(elements.length,index=>{const element=elements[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(children).filter(key=>{const child=children[key];return!child||!isCompiledTemplateWithExpression(child)}):Object.keys(children);return aggregateObjectAnalysis(keys,key=>{const child=children[key];if(!child)throw new Error(`unreachable: missing child "${key}"`);const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);return child.analyze(inputSchema,{identifierSchemas:options?.identifierSchemas,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}case"literal":return{valid:true,diagnostics:[],outputSchema:inferPrimitiveSchema(this.state.value)};case"template":return analyzeFromAst(this.state.ast,this.state.source,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.options.helpers,coerceSchema:options?.coerceSchema})}}validate(inputSchema={},options){const analysis=this.analyze(inputSchema,options);return{valid:analysis.valid,diagnostics:analysis.diagnostics}}execute(data,options){switch(this.state.kind){case"array":{const{elements}=this.state;const result=[];for(const element of
|
|
1
|
+
function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import{analyzeFromAst}from"./analyzer.js";import{resolveChildCoerceSchema,shouldExcludeEntry}from"./dispatch.js";import{TemplateAnalysisError}from"./errors.js";import{executeFromAst}from"./executor.js";import{inferPrimitiveSchema}from"./types.js";import{aggregateArrayAnalysis,aggregateArrayAnalysisAndExecution,aggregateObjectAnalysis,aggregateObjectAnalysisAndExecution}from"./utils.js";export class CompiledTemplate{get ast(){return this.state.kind==="template"?this.state.ast:null}get template(){return this.state.kind==="template"?this.state.source:""}static fromTemplate(ast,source,options){return new CompiledTemplate({kind:"template",ast,source},options)}static fromLiteral(value,options){return new CompiledTemplate({kind:"literal",value},options)}static fromObject(children,options){return new CompiledTemplate({kind:"object",children},options)}static fromArray(elements,options){return new CompiledTemplate({kind:"array",elements},options)}analyze(inputSchema={},options){const exclude=options?.excludeTemplateExpression===true;switch(this.state.kind){case"array":{const{elements}=this.state;if(exclude){const kept=elements.filter(el=>!isCompiledTemplateWithExpression(el));return aggregateArrayAnalysis(kept.length,index=>{const element=kept[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}return aggregateArrayAnalysis(elements.length,index=>{const element=elements[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyze(inputSchema,options)})}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(children).filter(key=>{const child=children[key];return!child||!isCompiledTemplateWithExpression(child)}):Object.keys(children);return aggregateObjectAnalysis(keys,key=>{const child=children[key];if(!child)throw new Error(`unreachable: missing child "${key}"`);const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);return child.analyze(inputSchema,{identifierSchemas:options?.identifierSchemas,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}case"literal":return{valid:true,diagnostics:[],outputSchema:inferPrimitiveSchema(this.state.value)};case"template":return analyzeFromAst(this.state.ast,this.state.source,inputSchema,{identifierSchemas:options?.identifierSchemas,helpers:this.options.helpers,coerceSchema:options?.coerceSchema})}}validate(inputSchema={},options){const analysis=this.analyze(inputSchema,options);return{valid:analysis.valid,diagnostics:analysis.diagnostics}}execute(data,options){const exclude=options?.excludeTemplateExpression===true;switch(this.state.kind){case"array":{const{elements}=this.state;const effective=exclude?elements.filter(el=>!isCompiledTemplateWithExpression(el)):elements;const result=[];for(const element of effective){result.push(element.execute(data,options))}return result}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(children).filter(key=>{const child=children[key];return!child||!isCompiledTemplateWithExpression(child)}):Object.keys(children);const result={};for(const key of keys){const child=children[key];if(!child)continue;const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);result[key]=child.execute(data,{...options,coerceSchema:childCoerceSchema})}return result}case"literal":return this.state.value;case"template":{if(exclude&&isCompiledTemplateWithExpression(this)){return null}if(options?.schema){const analysis=this.analyze(options.schema,{identifierSchemas:options.identifierSchemas,coerceSchema:options.coerceSchema});if(!analysis.valid){throw new TemplateAnalysisError(analysis.diagnostics)}}return executeFromAst(this.state.ast,this.state.source,data,this.buildExecutorContext(options))}}}analyzeAndExecute(inputSchema={},data,options){switch(this.state.kind){case"array":{const{elements}=this.state;return aggregateArrayAnalysisAndExecution(elements.length,index=>{const element=elements[index];if(!element)throw new Error(`unreachable: missing element at index ${index}`);return element.analyzeAndExecute(inputSchema,data,options)})}case"object":{const{children}=this.state;const coerceSchema=options?.coerceSchema;return aggregateObjectAnalysisAndExecution(Object.keys(children),key=>{const child=children[key];if(!child)throw new Error(`unreachable: missing child "${key}"`);const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);return child.analyzeAndExecute(inputSchema,data,{identifierSchemas:options?.identifierSchemas,identifierData:options?.identifierData,coerceSchema:childCoerceSchema})})}case"literal":return{analysis:{valid:true,diagnostics:[],outputSchema:inferPrimitiveSchema(this.state.value)},value:this.state.value};case"template":{const analysis=this.analyze(inputSchema,{identifierSchemas:options?.identifierSchemas,coerceSchema:options?.coerceSchema});if(!analysis.valid){return{analysis,value:undefined}}const value=executeFromAst(this.state.ast,this.state.source,data,this.buildExecutorContext({identifierData:options?.identifierData,coerceSchema:options?.coerceSchema}));return{analysis,value}}}}buildExecutorContext(options){return{identifierData:options?.identifierData,compiledTemplate:this.getOrCompileHbs(),hbs:this.options.hbs,compilationCache:this.options.compilationCache,coerceSchema:options?.coerceSchema,helpers:this.options.helpers}}getOrCompileHbs(){if(!this.hbsCompiled){this.hbsCompiled=this.options.hbs.compile(this.template,{noEscape:true,strict:false})}return this.hbsCompiled}constructor(state,options){_define_property(this,"state",void 0);_define_property(this,"options",void 0);_define_property(this,"hbsCompiled",null);this.state=state;this.options=options}}function isCompiledTemplateWithExpression(ct){return ct.template!==""&&shouldExcludeEntry(ct.template)}
|
|
2
2
|
//# sourceMappingURL=compiled-template.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/compiled-template.ts"],"sourcesContent":["import type Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { AnalyzeOptions } from \"./analyzer.ts\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport { resolveChildCoerceSchema, shouldExcludeEntry } from \"./dispatch.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { type ExecutorContext, executeFromAst } from \"./executor.ts\";\nimport type {\n\tAnalysisResult,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateData,\n\tValidationResult,\n} from \"./types.ts\";\nimport { inferPrimitiveSchema } from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n\ttype LRUCache,\n} from \"./utils\";\n\n// ─── CompiledTemplate ────────────────────────────────────────────────────────\n// Pre-parsed template ready to be executed or analyzed without re-parsing.\n//\n// The compile-once / execute-many pattern avoids the cost of Handlebars\n// parsing on every call. The AST is parsed once at compile time, and the\n// Handlebars template is lazily compiled on the first `execute()`.\n//\n// Usage:\n// const tpl = engine.compile(\"Hello {{name}}\");\n// tpl.execute({ name: \"Alice\" }); // no re-parsing\n// tpl.execute({ name: \"Bob\" }); // no re-parsing or recompilation\n// tpl.analyze(schema); // no re-parsing\n//\n// ─── Internal State (TemplateState) ──────────────────────────────────────────\n// CompiledTemplate operates in 4 exclusive modes, modeled by a discriminated\n// union `TemplateState`:\n//\n// - `\"template\"` — parsed Handlebars template (AST + source string)\n// - `\"literal\"` — primitive passthrough value (number, boolean, null)\n// - `\"object\"` — object where each property is a child CompiledTemplate\n// - `\"array\"` — array where each element is a child CompiledTemplate\n//\n// This design eliminates optional fields and `!` assertions in favor of\n// natural TypeScript narrowing via `switch (this.state.kind)`.\n//\n// ─── Advantages Over the Direct API ──────────────────────────────────────────\n// - **Performance**: parsing and compilation happen only once\n// - **Simplified API**: no need to re-pass the template string on each call\n// - **Consistency**: the same AST is used for both analysis and execution\n\n// ─── Internal Types ──────────────────────────────────────────────────────────\n\n/** Internal options passed by Typebars during compilation */\nexport interface CompiledTemplateOptions {\n\t/** Custom helpers registered on the engine */\n\thelpers: Map<string, HelperDefinition>;\n\t/** Isolated Handlebars environment (with registered helpers) */\n\thbs: typeof Handlebars;\n\t/** Compilation cache shared by the engine */\n\tcompilationCache: LRUCache<string, HandlebarsTemplateDelegate>;\n}\n\n/** Discriminated internal state of the CompiledTemplate */\ntype TemplateState =\n\t| {\n\t\t\treadonly kind: \"template\";\n\t\t\treadonly ast: hbs.AST.Program;\n\t\t\treadonly source: string;\n\t }\n\t| { readonly kind: \"literal\"; readonly value: number | boolean | null }\n\t| {\n\t\t\treadonly kind: \"object\";\n\t\t\treadonly children: Record<string, CompiledTemplate>;\n\t }\n\t| {\n\t\t\treadonly kind: \"array\";\n\t\t\treadonly elements: CompiledTemplate[];\n\t };\n\n// ─── Public Class ────────────────────────────────────────────────────────────\n\nexport class CompiledTemplate {\n\t/** Discriminated internal state */\n\tprivate readonly state: TemplateState;\n\n\t/** Options inherited from the parent Typebars instance */\n\tprivate readonly options: CompiledTemplateOptions;\n\n\t/** Compiled Handlebars template (lazy — created on the first `execute()` that needs it) */\n\tprivate hbsCompiled: HandlebarsTemplateDelegate | null = null;\n\n\t// ─── Public Accessors (backward-compatible) ──────────────────────────\n\n\t/** The pre-parsed Handlebars AST — `null` in literal, object, or array mode */\n\tget ast(): hbs.AST.Program | null {\n\t\treturn this.state.kind === \"template\" ? this.state.ast : null;\n\t}\n\n\t/** The original template source — empty string in literal, object, or array mode */\n\tget template(): string {\n\t\treturn this.state.kind === \"template\" ? this.state.source : \"\";\n\t}\n\n\t// ─── Construction ────────────────────────────────────────────────────\n\n\tprivate constructor(state: TemplateState, options: CompiledTemplateOptions) {\n\t\tthis.state = state;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate for a parsed Handlebars template.\n\t *\n\t * @param ast - The pre-parsed Handlebars AST\n\t * @param source - The original template source\n\t * @param options - Options inherited from Typebars\n\t */\n\tstatic fromTemplate(\n\t\tast: hbs.AST.Program,\n\t\tsource: string,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"template\", ast, source }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in passthrough mode for a literal value\n\t * (number, boolean, null). No parsing or compilation is performed.\n\t *\n\t * @param value - The primitive value\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that always returns `value`\n\t */\n\tstatic fromLiteral(\n\t\tvalue: number | boolean | null,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"literal\", value }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in object mode, where each property is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the children.\n\t *\n\t * @param children - The compiled child templates `{ [key]: CompiledTemplate }`\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to children\n\t */\n\tstatic fromObject(\n\t\tchildren: Record<string, CompiledTemplate>,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"object\", children }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in array mode, where each element is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the elements.\n\t *\n\t * @param elements - The compiled child templates (ordered array)\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to elements\n\t */\n\tstatic fromArray(\n\t\telements: CompiledTemplate[],\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"array\", elements }, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes this template against a JSON Schema v7.\n\t *\n\t * Returns an `AnalysisResult` containing:\n\t * - `valid` — `true` if no errors\n\t * - `diagnostics` — list of diagnostics (errors + warnings)\n\t * - `outputSchema` — JSON Schema describing the return type\n\t *\n\t * Since the AST is pre-parsed, this method never re-parses the template.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tanalyze(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): AnalysisResult {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\n\t\t\t\tif (exclude) {\n\t\t\t\t\t// When excludeTemplateExpression is enabled, filter out elements\n\t\t\t\t\t// that are string templates containing Handlebars expressions.\n\t\t\t\t\tconst kept = elements.filter(\n\t\t\t\t\t\t(el) => !isCompiledTemplateWithExpression(el),\n\t\t\t\t\t);\n\t\t\t\t\treturn aggregateArrayAnalysis(kept.length, (index) => {\n\t\t\t\t\t\tconst element = kept[index];\n\t\t\t\t\t\tif (!element)\n\t\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn aggregateArrayAnalysis(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\n\t\t\t\t// When excludeTemplateExpression is enabled, filter out keys whose\n\t\t\t\t// compiled children are string templates with Handlebars expressions.\n\t\t\t\tconst keys = exclude\n\t\t\t\t\t? Object.keys(children).filter((key) => {\n\t\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\t\treturn !child || !isCompiledTemplateWithExpression(child);\n\t\t\t\t\t\t})\n\t\t\t\t\t: Object.keys(children);\n\n\t\t\t\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\t\t\t\tconst child = children[key];\n\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\treturn child.analyze(inputSchema, {\n\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tvalid: true,\n\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t};\n\n\t\t\tcase \"template\":\n\t\t\t\treturn analyzeFromAst(this.state.ast, this.state.source, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.options.helpers,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\t\t}\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────\n\n\t/**\n\t * Validates the template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tvalidate(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(inputSchema, options);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Execution ───────────────────────────────────────────────────────\n\n\t/**\n\t * Executes this template with the provided data.\n\t *\n\t * The return type depends on the template structure:\n\t * - Single expression `{{expr}}` → raw value (number, boolean, object…)\n\t * - Mixed template or with blocks → `string`\n\t * - Primitive literal → the value as-is\n\t * - Object template → object with resolved values\n\t * - Array template → array with resolved values\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, coerceSchema, etc.)\n\t * @returns The execution result\n\t */\n\texecute(data: TemplateData, options?: ExecuteOptions): unknown {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\tconst result: unknown[] = [];\n\t\t\t\tfor (const element of elements) {\n\t\t\t\t\tresult.push(element.execute(data, options));\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\tconst result: Record<string, unknown> = {};\n\t\t\t\tfor (const [key, child] of Object.entries(children)) {\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\tresult[key] = child.execute(data, {\n\t\t\t\t\t\t...options,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn this.state.value;\n\n\t\t\tcase \"template\": {\n\t\t\t\t// Pre-execution static validation if a schema is provided\n\t\t\t\tif (options?.schema) {\n\t\t\t\t\tconst analysis = this.analyze(options.schema, {\n\t\t\t\t\t\tidentifierSchemas: options.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: options.coerceSchema,\n\t\t\t\t\t});\n\t\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext(options),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────\n\n\t/**\n\t * Analyzes and executes the template in a single call.\n\t *\n\t * Returns both the analysis result and the executed value.\n\t * If analysis fails, `value` is `undefined`.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - Additional options (identifierSchemas, identifierData, coerceSchema)\n\t * @returns `{ analysis, value }`\n\t */\n\tanalyzeAndExecute(\n\t\tinputSchema: JSONSchema7 = {},\n\t\tdata: TemplateData,\n\t\toptions?: {\n\t\t\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t\t\tidentifierData?: Record<number, Record<string, unknown>>;\n\t\t\tcoerceSchema?: JSONSchema7;\n\t\t},\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\treturn aggregateArrayAnalysisAndExecution(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyzeAndExecute(inputSchema, data, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\treturn aggregateObjectAnalysisAndExecution(\n\t\t\t\t\tObject.keys(children),\n\t\t\t\t\t(key) => {\n\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(\n\t\t\t\t\t\t\tcoerceSchema,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn child.analyzeAndExecute(inputSchema, data, {\n\t\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tanalysis: {\n\t\t\t\t\t\tvalid: true,\n\t\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t\t},\n\t\t\t\t\tvalue: this.state.value,\n\t\t\t\t};\n\n\t\t\tcase \"template\": {\n\t\t\t\tconst analysis = this.analyze(inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\n\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\treturn { analysis, value: undefined };\n\t\t\t\t}\n\n\t\t\t\tconst value = executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext({\n\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn { analysis, value };\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Internals ───────────────────────────────────────────────────────\n\n\t/**\n\t * Builds the execution context for `executeFromAst`.\n\t *\n\t * Uses lazy Handlebars compilation: the template is only compiled\n\t * on the first call that needs it (not for single expressions).\n\t */\n\tprivate buildExecutorContext(options?: ExecuteOptions): ExecutorContext {\n\t\treturn {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\tcompiledTemplate: this.getOrCompileHbs(),\n\t\t\thbs: this.options.hbs,\n\t\t\tcompilationCache: this.options.compilationCache,\n\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\thelpers: this.options.helpers,\n\t\t};\n\t}\n\n\t/**\n\t * Lazily compiles the Handlebars template and caches it.\n\t *\n\t * Compilation happens only once — subsequent calls return the\n\t * in-memory compiled template.\n\t *\n\t * Precondition: this method is only called from \"template\" mode.\n\t */\n\tprivate getOrCompileHbs(): HandlebarsTemplateDelegate {\n\t\tif (!this.hbsCompiled) {\n\t\t\t// In \"template\" mode, `this.template` returns the source string\n\t\t\tthis.hbsCompiled = this.options.hbs.compile(this.template, {\n\t\t\t\tnoEscape: true,\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t}\n\t\treturn this.hbsCompiled;\n\t}\n}\n\n// ─── Internal Helpers ────────────────────────────────────────────────────────\n\n/**\n * Determines whether a `CompiledTemplate` represents a string template\n * containing Handlebars expressions (`{{…}}`).\n *\n * Used by `excludeTemplateExpression` filtering to skip dynamic entries\n * in object and array modes.\n */\nfunction isCompiledTemplateWithExpression(ct: CompiledTemplate): boolean {\n\t// Only \"template\" kind can contain expressions. Literals, objects,\n\t// and arrays are never excluded at the entry level — objects and\n\t// arrays are recursively filtered by the analysis method itself.\n\treturn ct.template !== \"\" && shouldExcludeEntry(ct.template);\n}\n"],"names":["analyzeFromAst","resolveChildCoerceSchema","shouldExcludeEntry","TemplateAnalysisError","executeFromAst","inferPrimitiveSchema","aggregateArrayAnalysis","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysis","aggregateObjectAnalysisAndExecution","CompiledTemplate","ast","state","kind","template","source","fromTemplate","options","fromLiteral","value","fromObject","children","fromArray","elements","analyze","inputSchema","exclude","excludeTemplateExpression","kept","filter","el","isCompiledTemplateWithExpression","length","index","element","Error","coerceSchema","keys","Object","key","child","childCoerceSchema","identifierSchemas","valid","diagnostics","outputSchema","helpers","validate","analysis","execute","data","result","push","entries","schema","buildExecutorContext","analyzeAndExecute","identifierData","undefined","compiledTemplate","getOrCompileHbs","hbs","compilationCache","hbsCompiled","compile","noEscape","strict","ct"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/compiled-template.ts"],"sourcesContent":["import type Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport type { AnalyzeOptions } from \"./analyzer.ts\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport { resolveChildCoerceSchema, shouldExcludeEntry } from \"./dispatch.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { type ExecutorContext, executeFromAst } from \"./executor.ts\";\nimport type {\n\tAnalysisResult,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateData,\n\tValidationResult,\n} from \"./types.ts\";\nimport { inferPrimitiveSchema } from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n\ttype LRUCache,\n} from \"./utils\";\n\n// ─── CompiledTemplate ────────────────────────────────────────────────────────\n// Pre-parsed template ready to be executed or analyzed without re-parsing.\n//\n// The compile-once / execute-many pattern avoids the cost of Handlebars\n// parsing on every call. The AST is parsed once at compile time, and the\n// Handlebars template is lazily compiled on the first `execute()`.\n//\n// Usage:\n// const tpl = engine.compile(\"Hello {{name}}\");\n// tpl.execute({ name: \"Alice\" }); // no re-parsing\n// tpl.execute({ name: \"Bob\" }); // no re-parsing or recompilation\n// tpl.analyze(schema); // no re-parsing\n//\n// ─── Internal State (TemplateState) ──────────────────────────────────────────\n// CompiledTemplate operates in 4 exclusive modes, modeled by a discriminated\n// union `TemplateState`:\n//\n// - `\"template\"` — parsed Handlebars template (AST + source string)\n// - `\"literal\"` — primitive passthrough value (number, boolean, null)\n// - `\"object\"` — object where each property is a child CompiledTemplate\n// - `\"array\"` — array where each element is a child CompiledTemplate\n//\n// This design eliminates optional fields and `!` assertions in favor of\n// natural TypeScript narrowing via `switch (this.state.kind)`.\n//\n// ─── Advantages Over the Direct API ──────────────────────────────────────────\n// - **Performance**: parsing and compilation happen only once\n// - **Simplified API**: no need to re-pass the template string on each call\n// - **Consistency**: the same AST is used for both analysis and execution\n\n// ─── Internal Types ──────────────────────────────────────────────────────────\n\n/** Internal options passed by Typebars during compilation */\nexport interface CompiledTemplateOptions {\n\t/** Custom helpers registered on the engine */\n\thelpers: Map<string, HelperDefinition>;\n\t/** Isolated Handlebars environment (with registered helpers) */\n\thbs: typeof Handlebars;\n\t/** Compilation cache shared by the engine */\n\tcompilationCache: LRUCache<string, HandlebarsTemplateDelegate>;\n}\n\n/** Discriminated internal state of the CompiledTemplate */\ntype TemplateState =\n\t| {\n\t\t\treadonly kind: \"template\";\n\t\t\treadonly ast: hbs.AST.Program;\n\t\t\treadonly source: string;\n\t }\n\t| { readonly kind: \"literal\"; readonly value: number | boolean | null }\n\t| {\n\t\t\treadonly kind: \"object\";\n\t\t\treadonly children: Record<string, CompiledTemplate>;\n\t }\n\t| {\n\t\t\treadonly kind: \"array\";\n\t\t\treadonly elements: CompiledTemplate[];\n\t };\n\n// ─── Public Class ────────────────────────────────────────────────────────────\n\nexport class CompiledTemplate {\n\t/** Discriminated internal state */\n\tprivate readonly state: TemplateState;\n\n\t/** Options inherited from the parent Typebars instance */\n\tprivate readonly options: CompiledTemplateOptions;\n\n\t/** Compiled Handlebars template (lazy — created on the first `execute()` that needs it) */\n\tprivate hbsCompiled: HandlebarsTemplateDelegate | null = null;\n\n\t// ─── Public Accessors (backward-compatible) ──────────────────────────\n\n\t/** The pre-parsed Handlebars AST — `null` in literal, object, or array mode */\n\tget ast(): hbs.AST.Program | null {\n\t\treturn this.state.kind === \"template\" ? this.state.ast : null;\n\t}\n\n\t/** The original template source — empty string in literal, object, or array mode */\n\tget template(): string {\n\t\treturn this.state.kind === \"template\" ? this.state.source : \"\";\n\t}\n\n\t// ─── Construction ────────────────────────────────────────────────────\n\n\tprivate constructor(state: TemplateState, options: CompiledTemplateOptions) {\n\t\tthis.state = state;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate for a parsed Handlebars template.\n\t *\n\t * @param ast - The pre-parsed Handlebars AST\n\t * @param source - The original template source\n\t * @param options - Options inherited from Typebars\n\t */\n\tstatic fromTemplate(\n\t\tast: hbs.AST.Program,\n\t\tsource: string,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"template\", ast, source }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in passthrough mode for a literal value\n\t * (number, boolean, null). No parsing or compilation is performed.\n\t *\n\t * @param value - The primitive value\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that always returns `value`\n\t */\n\tstatic fromLiteral(\n\t\tvalue: number | boolean | null,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"literal\", value }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in object mode, where each property is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the children.\n\t *\n\t * @param children - The compiled child templates `{ [key]: CompiledTemplate }`\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to children\n\t */\n\tstatic fromObject(\n\t\tchildren: Record<string, CompiledTemplate>,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"object\", children }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in array mode, where each element is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the elements.\n\t *\n\t * @param elements - The compiled child templates (ordered array)\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to elements\n\t */\n\tstatic fromArray(\n\t\telements: CompiledTemplate[],\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"array\", elements }, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes this template against a JSON Schema v7.\n\t *\n\t * Returns an `AnalysisResult` containing:\n\t * - `valid` — `true` if no errors\n\t * - `diagnostics` — list of diagnostics (errors + warnings)\n\t * - `outputSchema` — JSON Schema describing the return type\n\t *\n\t * Since the AST is pre-parsed, this method never re-parses the template.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tanalyze(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): AnalysisResult {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\n\t\t\t\tif (exclude) {\n\t\t\t\t\t// When excludeTemplateExpression is enabled, filter out elements\n\t\t\t\t\t// that are string templates containing Handlebars expressions.\n\t\t\t\t\tconst kept = elements.filter(\n\t\t\t\t\t\t(el) => !isCompiledTemplateWithExpression(el),\n\t\t\t\t\t);\n\t\t\t\t\treturn aggregateArrayAnalysis(kept.length, (index) => {\n\t\t\t\t\t\tconst element = kept[index];\n\t\t\t\t\t\tif (!element)\n\t\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn aggregateArrayAnalysis(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyze(inputSchema, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\n\t\t\t\t// When excludeTemplateExpression is enabled, filter out keys whose\n\t\t\t\t// compiled children are string templates with Handlebars expressions.\n\t\t\t\tconst keys = exclude\n\t\t\t\t\t? Object.keys(children).filter((key) => {\n\t\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\t\treturn !child || !isCompiledTemplateWithExpression(child);\n\t\t\t\t\t\t})\n\t\t\t\t\t: Object.keys(children);\n\n\t\t\t\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\t\t\t\tconst child = children[key];\n\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\treturn child.analyze(inputSchema, {\n\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tvalid: true,\n\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t};\n\n\t\t\tcase \"template\":\n\t\t\t\treturn analyzeFromAst(this.state.ast, this.state.source, inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\thelpers: this.options.helpers,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\t\t}\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────\n\n\t/**\n\t * Validates the template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param options - (optional) Analysis options (identifierSchemas, coerceSchema)\n\t */\n\tvalidate(\n\t\tinputSchema: JSONSchema7 = {},\n\t\toptions?: AnalyzeOptions,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(inputSchema, options);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Execution ───────────────────────────────────────────────────────\n\n\t/**\n\t * Executes this template with the provided data.\n\t *\n\t * The return type depends on the template structure:\n\t * - Single expression `{{expr}}` → raw value (number, boolean, object…)\n\t * - Mixed template or with blocks → `string`\n\t * - Primitive literal → the value as-is\n\t * - Object template → object with resolved values\n\t * - Array template → array with resolved values\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, coerceSchema, etc.)\n\t * @returns The execution result\n\t */\n\texecute(data: TemplateData, options?: ExecuteOptions): unknown {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\tconst effective = exclude\n\t\t\t\t\t? elements.filter((el) => !isCompiledTemplateWithExpression(el))\n\t\t\t\t\t: elements;\n\t\t\t\tconst result: unknown[] = [];\n\t\t\t\tfor (const element of effective) {\n\t\t\t\t\tresult.push(element.execute(data, options));\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\tconst keys = exclude\n\t\t\t\t\t? Object.keys(children).filter((key) => {\n\t\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\t\treturn !child || !isCompiledTemplateWithExpression(child);\n\t\t\t\t\t\t})\n\t\t\t\t\t: Object.keys(children);\n\t\t\t\tconst result: Record<string, unknown> = {};\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tconst child = children[key];\n\t\t\t\t\tif (!child) continue;\n\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\t\t\tresult[key] = child.execute(data, {\n\t\t\t\t\t\t...options,\n\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn this.state.value;\n\n\t\t\tcase \"template\": {\n\t\t\t\t// When excludeTemplateExpression is enabled at root level,\n\t\t\t\t// return null if the template contains Handlebars expressions\n\t\t\t\t// (there is no parent to remove it from).\n\t\t\t\tif (exclude && isCompiledTemplateWithExpression(this)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// Pre-execution static validation if a schema is provided\n\t\t\t\tif (options?.schema) {\n\t\t\t\t\tconst analysis = this.analyze(options.schema, {\n\t\t\t\t\t\tidentifierSchemas: options.identifierSchemas,\n\t\t\t\t\t\tcoerceSchema: options.coerceSchema,\n\t\t\t\t\t});\n\t\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext(options),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────\n\n\t/**\n\t * Analyzes and executes the template in a single call.\n\t *\n\t * Returns both the analysis result and the executed value.\n\t * If analysis fails, `value` is `undefined`.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - Additional options (identifierSchemas, identifierData, coerceSchema)\n\t * @returns `{ analysis, value }`\n\t */\n\tanalyzeAndExecute(\n\t\tinputSchema: JSONSchema7 = {},\n\t\tdata: TemplateData,\n\t\toptions?: {\n\t\t\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t\t\tidentifierData?: Record<number, Record<string, unknown>>;\n\t\t\tcoerceSchema?: JSONSchema7;\n\t\t},\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"array\": {\n\t\t\t\tconst { elements } = this.state;\n\t\t\t\treturn aggregateArrayAnalysisAndExecution(elements.length, (index) => {\n\t\t\t\t\tconst element = elements[index];\n\t\t\t\t\tif (!element)\n\t\t\t\t\t\tthrow new Error(`unreachable: missing element at index ${index}`);\n\t\t\t\t\treturn element.analyzeAndExecute(inputSchema, data, options);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst coerceSchema = options?.coerceSchema;\n\t\t\t\treturn aggregateObjectAnalysisAndExecution(\n\t\t\t\t\tObject.keys(children),\n\t\t\t\t\t(key) => {\n\t\t\t\t\t\tconst child = children[key];\n\t\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(\n\t\t\t\t\t\t\tcoerceSchema,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn child.analyzeAndExecute(inputSchema, data, {\n\t\t\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tanalysis: {\n\t\t\t\t\t\tvalid: true,\n\t\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t\t},\n\t\t\t\t\tvalue: this.state.value,\n\t\t\t\t};\n\n\t\t\tcase \"template\": {\n\t\t\t\tconst analysis = this.analyze(inputSchema, {\n\t\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t});\n\n\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\treturn { analysis, value: undefined };\n\t\t\t\t}\n\n\t\t\t\tconst value = executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext({\n\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn { analysis, value };\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Internals ───────────────────────────────────────────────────────\n\n\t/**\n\t * Builds the execution context for `executeFromAst`.\n\t *\n\t * Uses lazy Handlebars compilation: the template is only compiled\n\t * on the first call that needs it (not for single expressions).\n\t */\n\tprivate buildExecutorContext(options?: ExecuteOptions): ExecutorContext {\n\t\treturn {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\tcompiledTemplate: this.getOrCompileHbs(),\n\t\t\thbs: this.options.hbs,\n\t\t\tcompilationCache: this.options.compilationCache,\n\t\t\tcoerceSchema: options?.coerceSchema,\n\t\t\thelpers: this.options.helpers,\n\t\t};\n\t}\n\n\t/**\n\t * Lazily compiles the Handlebars template and caches it.\n\t *\n\t * Compilation happens only once — subsequent calls return the\n\t * in-memory compiled template.\n\t *\n\t * Precondition: this method is only called from \"template\" mode.\n\t */\n\tprivate getOrCompileHbs(): HandlebarsTemplateDelegate {\n\t\tif (!this.hbsCompiled) {\n\t\t\t// In \"template\" mode, `this.template` returns the source string\n\t\t\tthis.hbsCompiled = this.options.hbs.compile(this.template, {\n\t\t\t\tnoEscape: true,\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t}\n\t\treturn this.hbsCompiled;\n\t}\n}\n\n// ─── Internal Helpers ────────────────────────────────────────────────────────\n\n/**\n * Determines whether a `CompiledTemplate` represents a string template\n * containing Handlebars expressions (`{{…}}`).\n *\n * Used by `excludeTemplateExpression` filtering to skip dynamic entries\n * in object and array modes.\n */\nfunction isCompiledTemplateWithExpression(ct: CompiledTemplate): boolean {\n\t// Only \"template\" kind can contain expressions. Literals, objects,\n\t// and arrays are never excluded at the entry level — objects and\n\t// arrays are recursively filtered by the analysis method itself.\n\treturn ct.template !== \"\" && shouldExcludeEntry(ct.template);\n}\n"],"names":["analyzeFromAst","resolveChildCoerceSchema","shouldExcludeEntry","TemplateAnalysisError","executeFromAst","inferPrimitiveSchema","aggregateArrayAnalysis","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysis","aggregateObjectAnalysisAndExecution","CompiledTemplate","ast","state","kind","template","source","fromTemplate","options","fromLiteral","value","fromObject","children","fromArray","elements","analyze","inputSchema","exclude","excludeTemplateExpression","kept","filter","el","isCompiledTemplateWithExpression","length","index","element","Error","coerceSchema","keys","Object","key","child","childCoerceSchema","identifierSchemas","valid","diagnostics","outputSchema","helpers","validate","analysis","execute","data","effective","result","push","schema","buildExecutorContext","analyzeAndExecute","identifierData","undefined","compiledTemplate","getOrCompileHbs","hbs","compilationCache","hbsCompiled","compile","noEscape","strict","ct"],"mappings":"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"}
|
package/dist/esm/dispatch.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface DispatchAnalyzeOptions {
|
|
|
13
13
|
export interface DispatchExecuteOptions {
|
|
14
14
|
/** Explicit coercion schema for output type coercion */
|
|
15
15
|
coerceSchema?: JSONSchema7;
|
|
16
|
+
/** When true, exclude entries containing Handlebars expressions */
|
|
17
|
+
excludeTemplateExpression?: boolean;
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* Dispatches a `TemplateInput` for analysis, handling the array/object/literal
|
|
@@ -47,6 +49,8 @@ export interface DispatchAnalyzeAndExecuteOptions {
|
|
|
47
49
|
identifierSchemas?: Record<number, JSONSchema7>;
|
|
48
50
|
identifierData?: Record<number, Record<string, unknown>>;
|
|
49
51
|
coerceSchema?: JSONSchema7;
|
|
52
|
+
/** When true, exclude entries containing Handlebars expressions */
|
|
53
|
+
excludeTemplateExpression?: boolean;
|
|
50
54
|
}
|
|
51
55
|
/**
|
|
52
56
|
* Dispatches a `TemplateInput` for combined analysis and execution,
|
package/dist/esm/dispatch.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{hasHandlebarsExpression}from"./parser.js";import{resolveSchemaPath}from"./schema-resolver.js";import{inferPrimitiveSchema,isArrayInput,isLiteralInput,isObjectInput}from"./types.js";import{aggregateArrayAnalysis,aggregateArrayAnalysisAndExecution,aggregateObjectAnalysis,aggregateObjectAnalysisAndExecution}from"./utils.js";export function dispatchAnalyze(template,options,analyzeString,recurse){if(isArrayInput(template)){const exclude=options?.excludeTemplateExpression===true;if(exclude){const kept=template.filter(item=>!shouldExcludeEntry(item));return aggregateArrayAnalysis(kept.length,index=>recurse(kept[index],
|
|
1
|
+
import{hasHandlebarsExpression}from"./parser.js";import{resolveSchemaPath}from"./schema-resolver.js";import{inferPrimitiveSchema,isArrayInput,isLiteralInput,isObjectInput}from"./types.js";import{aggregateArrayAnalysis,aggregateArrayAnalysisAndExecution,aggregateObjectAnalysis,aggregateObjectAnalysisAndExecution}from"./utils.js";export function dispatchAnalyze(template,options,analyzeString,recurse){if(isArrayInput(template)){const exclude=options?.excludeTemplateExpression===true;const childOptions=resolveArrayChildOptions(options);if(exclude){const kept=template.filter(item=>!shouldExcludeEntry(item));return aggregateArrayAnalysis(kept.length,index=>recurse(kept[index],childOptions))}return aggregateArrayAnalysis(template.length,index=>recurse(template[index],childOptions))}if(isObjectInput(template)){return dispatchObjectAnalysis(template,options,recurse)}if(isLiteralInput(template)){return{valid:true,diagnostics:[],outputSchema:inferPrimitiveSchema(template)}}return analyzeString(template,options?.coerceSchema)}function dispatchObjectAnalysis(template,options,recurse){const coerceSchema=options?.coerceSchema;const exclude=options?.excludeTemplateExpression===true;const keys=exclude?Object.keys(template).filter(key=>!shouldExcludeEntry(template[key])):Object.keys(template);return aggregateObjectAnalysis(keys,key=>{const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);return recurse(template[key],{identifierSchemas:options?.identifierSchemas,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}export function dispatchExecute(template,options,executeString,recurse){const exclude=options?.excludeTemplateExpression===true;if(isArrayInput(template)){const childOptions=resolveArrayChildOptions(options);const elements=exclude?template.filter(item=>!shouldExcludeEntry(item)):template;const result=[];for(const element of elements){result.push(recurse(element,childOptions))}return result}if(isObjectInput(template)){const coerceSchema=options?.coerceSchema;const result={};const keys=exclude?Object.keys(template).filter(key=>!shouldExcludeEntry(template[key])):Object.keys(template);for(const key of keys){const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);result[key]=recurse(template[key],{...options,coerceSchema:childCoerceSchema})}return result}if(isLiteralInput(template))return template;if(exclude&&shouldExcludeEntry(template)){return null}return executeString(template,options?.coerceSchema)}export function dispatchAnalyzeAndExecute(template,options,processString,recurse){const exclude=options?.excludeTemplateExpression===true;if(isArrayInput(template)){const childOptions=resolveArrayChildOptions(options);const elements=exclude?template.filter(item=>!shouldExcludeEntry(item)):template;return aggregateArrayAnalysisAndExecution(elements.length,index=>recurse(elements[index],childOptions))}if(isObjectInput(template)){const coerceSchema=options?.coerceSchema;const keys=exclude?Object.keys(template).filter(key=>!shouldExcludeEntry(template[key])):Object.keys(template);return aggregateObjectAnalysisAndExecution(keys,key=>{const childCoerceSchema=resolveChildCoerceSchema(coerceSchema,key);return recurse(template[key],{identifierSchemas:options?.identifierSchemas,identifierData:options?.identifierData,coerceSchema:childCoerceSchema,excludeTemplateExpression:options?.excludeTemplateExpression})})}if(isLiteralInput(template)){return{analysis:{valid:true,diagnostics:[],outputSchema:inferPrimitiveSchema(template)},value:template}}if(exclude&&shouldExcludeEntry(template)){return{analysis:{valid:true,diagnostics:[],outputSchema:{type:"null"}},value:null}}return processString(template,options?.coerceSchema)}function resolveArrayChildOptions(options){if(!options?.coerceSchema)return options;const itemsSchema=resolveItemsCoerceSchema(options.coerceSchema);if(itemsSchema===options.coerceSchema)return options;return{...options,coerceSchema:itemsSchema}}function resolveItemsCoerceSchema(coerceSchema){if(typeof coerceSchema==="boolean")return undefined;const items=coerceSchema.items;if(items!=null&&typeof items==="object"&&!Array.isArray(items)){return items}return undefined}export function resolveChildCoerceSchema(coerceSchema,key){return coerceSchema?resolveSchemaPath(coerceSchema,[key]):undefined}export function shouldExcludeEntry(input){return typeof input==="string"&&hasHandlebarsExpression(input)}
|
|
2
2
|
//# sourceMappingURL=dispatch.js.map
|
package/dist/esm/dispatch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dispatch.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport { hasHandlebarsExpression } from \"./parser.ts\";\nimport { resolveSchemaPath } from \"./schema-resolver.ts\";\nimport type { AnalysisResult, TemplateInput } from \"./types.ts\";\nimport {\n\tinferPrimitiveSchema,\n\tisArrayInput,\n\tisLiteralInput,\n\tisObjectInput,\n} from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n} from \"./utils.ts\";\n\n// ─── Template Input Dispatching ──────────────────────────────────────────────\n// Factorized dispatching for recursive processing of `TemplateInput` values.\n//\n// Every method in the engine (`analyze`, `execute`, `analyzeAndExecute`,\n// `compile`) follows the same recursive pattern:\n//\n// 1. If the input is an **array** → process each element recursively\n// 2. If the input is an **object** → process each property recursively\n// 3. If the input is a **literal** (number, boolean, null) → passthrough\n// 4. If the input is a **string** → delegate to a template-specific handler\n//\n// This module extracts the common dispatching logic into generic functions\n// that accept a callback for the string (template) case. This eliminates\n// the duplication across `Typebars`, `CompiledTemplate`, and `analyzer.ts`.\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Options controlling recursive dispatching behavior */\nexport interface DispatchAnalyzeOptions {\n\t/** Schemas by template identifier */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Explicit coercion schema for static literal output type */\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n/** Options controlling recursive execution dispatching */\nexport interface DispatchExecuteOptions {\n\t/** Explicit coercion schema for output type coercion */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Analysis Dispatching ────────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for analysis, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to analyze\n * @param options - Dispatching options (coerceSchema, excludeTemplateExpression)\n * @param analyzeString - Callback for analyzing a string template.\n * Receives `(template, coerceSchema?)` and must return an `AnalysisResult`.\n * @param recurse - Callback for recursively analyzing a child `TemplateInput`.\n * Receives `(child, options?)` and must return an `AnalysisResult`.\n * This allows callers (like `Typebars`) to rebind `this` or inject\n * additional context on each recursive call.\n * @returns An `AnalysisResult`\n */\nexport function dispatchAnalyze(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeOptions | undefined,\n\tanalyzeString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => AnalysisResult,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\t\tif (exclude) {\n\t\t\tconst kept = template.filter(\n\t\t\t\t(item) => !shouldExcludeEntry(item as TemplateInput),\n\t\t\t);\n\t\t\treturn aggregateArrayAnalysis(kept.length, (index) =>\n\t\t\t\trecurse(kept[index] as TemplateInput, options),\n\t\t\t);\n\t\t}\n\t\treturn aggregateArrayAnalysis(template.length, (index) =>\n\t\t\trecurse(template[index] as TemplateInput, options),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\treturn dispatchObjectAnalysis(template, options, recurse);\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tvalid: true,\n\t\t\tdiagnostics: [],\n\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn analyzeString(template, options?.coerceSchema);\n}\n\n/**\n * Dispatches object analysis with `coerceSchema` propagation and\n * `excludeTemplateExpression` filtering.\n *\n * Extracted as a separate function because the object case is the most\n * complex (key filtering + per-key coerceSchema resolution).\n */\nfunction dispatchObjectAnalysis(\n\ttemplate: Record<string, TemplateInput>,\n\toptions: DispatchAnalyzeOptions | undefined,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\tconst coerceSchema = options?.coerceSchema;\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\tconst keys = exclude\n\t\t? Object.keys(template).filter(\n\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t)\n\t\t: Object.keys(template);\n\n\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t});\n\t});\n}\n\n// ─── Execution Dispatching ───────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for execution, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to execute\n * @param options - Dispatching options (coerceSchema)\n * @param executeString - Callback for executing a string template.\n * Receives `(template, coerceSchema?)` and must return the result.\n * @param recurse - Callback for recursively executing a child `TemplateInput`.\n * Receives `(child, options?)` and must return the result.\n * @returns The execution result\n */\nexport function dispatchExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchExecuteOptions | undefined,\n\texecuteString: (template: string, coerceSchema?: JSONSchema7) => unknown,\n\trecurse: (child: TemplateInput, options?: DispatchExecuteOptions) => unknown,\n): unknown {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst result: unknown[] = [];\n\t\tfor (const element of template) {\n\t\t\tresult.push(recurse(element, options));\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\tresult[key] = recurse(value, {\n\t\t\t\t...options,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) return template;\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn executeString(template, options?.coerceSchema);\n}\n\n// ─── Analyze-and-Execute Dispatching ─────────────────────────────────────────\n\n/** Options for combined analyze-and-execute dispatching */\nexport interface DispatchAnalyzeAndExecuteOptions {\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\tcoerceSchema?: JSONSchema7;\n}\n\n/**\n * Dispatches a `TemplateInput` for combined analysis and execution,\n * handling array/object/literal cases generically and delegating\n * the string case to a callback.\n *\n * @param template - The input to process\n * @param options - Options (identifierSchemas, identifierData, coerceSchema)\n * @param processString - Callback for analyzing and executing a string template.\n * Receives `(template, coerceSchema?)` and must return\n * `{ analysis, value }`.\n * @param recurse - Callback for recursively processing a child `TemplateInput`.\n * @returns `{ analysis, value }` where `value` is `undefined` if analysis fails\n */\nexport function dispatchAnalyzeAndExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeAndExecuteOptions | undefined,\n\tprocessString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => { analysis: AnalysisResult; value: unknown },\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeAndExecuteOptions,\n\t) => { analysis: AnalysisResult; value: unknown },\n): { analysis: AnalysisResult; value: unknown } {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\treturn aggregateArrayAnalysisAndExecution(template.length, (index) =>\n\t\t\trecurse(template[index] as TemplateInput, options),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\treturn aggregateObjectAnalysisAndExecution(Object.keys(template), (key) => {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t});\n\t\t});\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tanalysis: {\n\t\t\t\tvalid: true,\n\t\t\t\tdiagnostics: [],\n\t\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t\t},\n\t\t\tvalue: template,\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn processString(template, options?.coerceSchema);\n}\n\n// ─── Internal Utilities ──────────────────────────────────────────────────────\n\n/**\n * Resolves the child `coerceSchema` for a given object key.\n *\n * When a `coerceSchema` is provided, navigates into its `properties`\n * to find the schema for the given key. This allows deeply nested\n * objects to propagate coercion at every level.\n *\n * @param coerceSchema - The parent coercion schema (may be `undefined`)\n * @param key - The object property key\n * @returns The child coercion schema, or `undefined`\n */\nexport function resolveChildCoerceSchema(\n\tcoerceSchema: JSONSchema7 | undefined,\n\tkey: string,\n): JSONSchema7 | undefined {\n\treturn coerceSchema ? resolveSchemaPath(coerceSchema, [key]) : undefined;\n}\n\n/**\n * Determines whether a `TemplateInput` value should be excluded when\n * `excludeTemplateExpression` is enabled.\n *\n * A value is excluded if it is a string containing at least one Handlebars\n * expression (`{{…}}`). Literals (number, boolean, null), plain strings\n * without expressions, objects, and arrays are never excluded at the\n * entry level — objects and arrays are recursively filtered by the\n * dispatching functions themselves.\n *\n * @param input - The template input to check\n * @returns `true` if the input should be excluded\n */\nexport function shouldExcludeEntry(input: TemplateInput): boolean {\n\treturn typeof input === \"string\" && hasHandlebarsExpression(input);\n}\n"],"names":["hasHandlebarsExpression","resolveSchemaPath","inferPrimitiveSchema","isArrayInput","isLiteralInput","isObjectInput","aggregateArrayAnalysis","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysis","aggregateObjectAnalysisAndExecution","dispatchAnalyze","template","options","analyzeString","recurse","exclude","excludeTemplateExpression","kept","filter","item","shouldExcludeEntry","length","index","dispatchObjectAnalysis","valid","diagnostics","outputSchema","coerceSchema","keys","Object","key","childCoerceSchema","resolveChildCoerceSchema","identifierSchemas","dispatchExecute","executeString","result","element","push","value","entries","dispatchAnalyzeAndExecute","processString","identifierData","analysis","undefined","input"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/dispatch.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport { hasHandlebarsExpression } from \"./parser.ts\";\nimport { resolveSchemaPath } from \"./schema-resolver.ts\";\nimport type { AnalysisResult, TemplateInput } from \"./types.ts\";\nimport {\n\tinferPrimitiveSchema,\n\tisArrayInput,\n\tisLiteralInput,\n\tisObjectInput,\n} from \"./types.ts\";\nimport {\n\taggregateArrayAnalysis,\n\taggregateArrayAnalysisAndExecution,\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n} from \"./utils.ts\";\n\n// ─── Template Input Dispatching ──────────────────────────────────────────────\n// Factorized dispatching for recursive processing of `TemplateInput` values.\n//\n// Every method in the engine (`analyze`, `execute`, `analyzeAndExecute`,\n// `compile`) follows the same recursive pattern:\n//\n// 1. If the input is an **array** → process each element recursively\n// 2. If the input is an **object** → process each property recursively\n// 3. If the input is a **literal** (number, boolean, null) → passthrough\n// 4. If the input is a **string** → delegate to a template-specific handler\n//\n// This module extracts the common dispatching logic into generic functions\n// that accept a callback for the string (template) case. This eliminates\n// the duplication across `Typebars`, `CompiledTemplate`, and `analyzer.ts`.\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Options controlling recursive dispatching behavior */\nexport interface DispatchAnalyzeOptions {\n\t/** Schemas by template identifier */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Explicit coercion schema for static literal output type */\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n/** Options controlling recursive execution dispatching */\nexport interface DispatchExecuteOptions {\n\t/** Explicit coercion schema for output type coercion */\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n// ─── Analysis Dispatching ────────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for analysis, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to analyze\n * @param options - Dispatching options (coerceSchema, excludeTemplateExpression)\n * @param analyzeString - Callback for analyzing a string template.\n * Receives `(template, coerceSchema?)` and must return an `AnalysisResult`.\n * @param recurse - Callback for recursively analyzing a child `TemplateInput`.\n * Receives `(child, options?)` and must return an `AnalysisResult`.\n * This allows callers (like `Typebars`) to rebind `this` or inject\n * additional context on each recursive call.\n * @returns An `AnalysisResult`\n */\nexport function dispatchAnalyze(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeOptions | undefined,\n\tanalyzeString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => AnalysisResult,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst exclude = options?.excludeTemplateExpression === true;\n\t\tconst childOptions = resolveArrayChildOptions(options);\n\t\tif (exclude) {\n\t\t\tconst kept = template.filter(\n\t\t\t\t(item) => !shouldExcludeEntry(item as TemplateInput),\n\t\t\t);\n\t\t\treturn aggregateArrayAnalysis(kept.length, (index) =>\n\t\t\t\trecurse(kept[index] as TemplateInput, childOptions),\n\t\t\t);\n\t\t}\n\t\treturn aggregateArrayAnalysis(template.length, (index) =>\n\t\t\trecurse(template[index] as TemplateInput, childOptions),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\treturn dispatchObjectAnalysis(template, options, recurse);\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tvalid: true,\n\t\t\tdiagnostics: [],\n\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\treturn analyzeString(template, options?.coerceSchema);\n}\n\n/**\n * Dispatches object analysis with `coerceSchema` propagation and\n * `excludeTemplateExpression` filtering.\n *\n * Extracted as a separate function because the object case is the most\n * complex (key filtering + per-key coerceSchema resolution).\n */\nfunction dispatchObjectAnalysis(\n\ttemplate: Record<string, TemplateInput>,\n\toptions: DispatchAnalyzeOptions | undefined,\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeOptions,\n\t) => AnalysisResult,\n): AnalysisResult {\n\tconst coerceSchema = options?.coerceSchema;\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\tconst keys = exclude\n\t\t? Object.keys(template).filter(\n\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t)\n\t\t: Object.keys(template);\n\n\treturn aggregateObjectAnalysis(keys, (key) => {\n\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t});\n\t});\n}\n\n// ─── Execution Dispatching ───────────────────────────────────────────────────\n\n/**\n * Dispatches a `TemplateInput` for execution, handling the array/object/literal\n * cases generically and delegating the string (template) case to a callback.\n *\n * @param template - The input to execute\n * @param options - Dispatching options (coerceSchema)\n * @param executeString - Callback for executing a string template.\n * Receives `(template, coerceSchema?)` and must return the result.\n * @param recurse - Callback for recursively executing a child `TemplateInput`.\n * Receives `(child, options?)` and must return the result.\n * @returns The execution result\n */\nexport function dispatchExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchExecuteOptions | undefined,\n\texecuteString: (template: string, coerceSchema?: JSONSchema7) => unknown,\n\trecurse: (child: TemplateInput, options?: DispatchExecuteOptions) => unknown,\n): unknown {\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst childOptions = resolveArrayChildOptions(options);\n\t\tconst elements = exclude\n\t\t\t? template.filter((item) => !shouldExcludeEntry(item as TemplateInput))\n\t\t\t: template;\n\t\tconst result: unknown[] = [];\n\t\tfor (const element of elements) {\n\t\t\tresult.push(recurse(element as TemplateInput, childOptions));\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\tconst result: Record<string, unknown> = {};\n\t\tconst keys = exclude\n\t\t\t? Object.keys(template).filter(\n\t\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t\t)\n\t\t\t: Object.keys(template);\n\t\tfor (const key of keys) {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\tresult[key] = recurse(template[key] as TemplateInput, {\n\t\t\t\t...options,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) return template;\n\n\t// ── String template ──────────────────────────────────────────────────\n\t// At root level, if the string contains expressions and exclude is on,\n\t// return null (there is no parent to remove it from).\n\tif (exclude && shouldExcludeEntry(template)) {\n\t\treturn null;\n\t}\n\n\treturn executeString(template, options?.coerceSchema);\n}\n\n// ─── Analyze-and-Execute Dispatching ─────────────────────────────────────────\n\n/** Options for combined analyze-and-execute dispatching */\nexport interface DispatchAnalyzeAndExecuteOptions {\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\tcoerceSchema?: JSONSchema7;\n\t/** When true, exclude entries containing Handlebars expressions */\n\texcludeTemplateExpression?: boolean;\n}\n\n/**\n * Dispatches a `TemplateInput` for combined analysis and execution,\n * handling array/object/literal cases generically and delegating\n * the string case to a callback.\n *\n * @param template - The input to process\n * @param options - Options (identifierSchemas, identifierData, coerceSchema)\n * @param processString - Callback for analyzing and executing a string template.\n * Receives `(template, coerceSchema?)` and must return\n * `{ analysis, value }`.\n * @param recurse - Callback for recursively processing a child `TemplateInput`.\n * @returns `{ analysis, value }` where `value` is `undefined` if analysis fails\n */\nexport function dispatchAnalyzeAndExecute(\n\ttemplate: TemplateInput,\n\toptions: DispatchAnalyzeAndExecuteOptions | undefined,\n\tprocessString: (\n\t\ttemplate: string,\n\t\tcoerceSchema?: JSONSchema7,\n\t) => { analysis: AnalysisResult; value: unknown },\n\trecurse: (\n\t\tchild: TemplateInput,\n\t\toptions?: DispatchAnalyzeAndExecuteOptions,\n\t) => { analysis: AnalysisResult; value: unknown },\n): { analysis: AnalysisResult; value: unknown } {\n\tconst exclude = options?.excludeTemplateExpression === true;\n\n\t// ── Array ─────────────────────────────────────────────────────────────\n\tif (isArrayInput(template)) {\n\t\tconst childOptions = resolveArrayChildOptions(options);\n\t\tconst elements = exclude\n\t\t\t? template.filter((item) => !shouldExcludeEntry(item as TemplateInput))\n\t\t\t: template;\n\t\treturn aggregateArrayAnalysisAndExecution(elements.length, (index) =>\n\t\t\trecurse(elements[index] as TemplateInput, childOptions),\n\t\t);\n\t}\n\n\t// ── Object ────────────────────────────────────────────────────────────\n\tif (isObjectInput(template)) {\n\t\tconst coerceSchema = options?.coerceSchema;\n\t\tconst keys = exclude\n\t\t\t? Object.keys(template).filter(\n\t\t\t\t\t(key) => !shouldExcludeEntry(template[key] as TemplateInput),\n\t\t\t\t)\n\t\t\t: Object.keys(template);\n\t\treturn aggregateObjectAnalysisAndExecution(keys, (key) => {\n\t\t\tconst childCoerceSchema = resolveChildCoerceSchema(coerceSchema, key);\n\t\t\treturn recurse(template[key] as TemplateInput, {\n\t\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\tcoerceSchema: childCoerceSchema,\n\t\t\t\texcludeTemplateExpression: options?.excludeTemplateExpression,\n\t\t\t});\n\t\t});\n\t}\n\n\t// ── Literal (number, boolean, null) ───────────────────────────────────\n\tif (isLiteralInput(template)) {\n\t\treturn {\n\t\t\tanalysis: {\n\t\t\t\tvalid: true,\n\t\t\t\tdiagnostics: [],\n\t\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t\t},\n\t\t\tvalue: template,\n\t\t};\n\t}\n\n\t// ── String template ──────────────────────────────────────────────────\n\t// At root level, if the string contains expressions and exclude is on,\n\t// return null with a valid analysis (no parent to remove from).\n\tif (exclude && shouldExcludeEntry(template)) {\n\t\treturn {\n\t\t\tanalysis: {\n\t\t\t\tvalid: true,\n\t\t\t\tdiagnostics: [],\n\t\t\t\toutputSchema: { type: \"null\" },\n\t\t\t},\n\t\t\tvalue: null,\n\t\t};\n\t}\n\n\treturn processString(template, options?.coerceSchema);\n}\n\n// ─── Internal Utilities ──────────────────────────────────────────────────────\n\n/**\n * Resolves the child options for array element recursion.\n *\n * When a `coerceSchema` with `items` is provided, the child options\n * will use `coerceSchema.items` as the element-level coercion schema.\n * All other options are passed through unchanged.\n *\n * @param options - The parent dispatching options (may be `undefined`)\n * @returns New options with `coerceSchema` resolved to the items schema, or\n * the original options if no items schema is available.\n */\nfunction resolveArrayChildOptions<\n\tT extends { coerceSchema?: JSONSchema7 } | undefined,\n>(options: T): T {\n\tif (!options?.coerceSchema) return options;\n\n\tconst itemsSchema = resolveItemsCoerceSchema(options.coerceSchema);\n\tif (itemsSchema === options.coerceSchema) return options;\n\n\treturn { ...options, coerceSchema: itemsSchema };\n}\n\n/**\n * Extracts the `items` schema from an array-typed `coerceSchema`.\n *\n * If the schema declares `items` as a single schema (not a tuple),\n * returns that schema. Otherwise returns `undefined`.\n *\n * @param coerceSchema - The parent coercion schema\n * @returns The items coercion schema, or `undefined`\n */\nfunction resolveItemsCoerceSchema(\n\tcoerceSchema: JSONSchema7,\n): JSONSchema7 | undefined {\n\tif (typeof coerceSchema === \"boolean\") return undefined;\n\n\tconst items = coerceSchema.items;\n\tif (items != null && typeof items === \"object\" && !Array.isArray(items)) {\n\t\treturn items as JSONSchema7;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Resolves the child `coerceSchema` for a given object key.\n *\n * When a `coerceSchema` is provided, navigates into its `properties`\n * to find the schema for the given key. This allows deeply nested\n * objects to propagate coercion at every level.\n *\n * @param coerceSchema - The parent coercion schema (may be `undefined`)\n * @param key - The object property key\n * @returns The child coercion schema, or `undefined`\n */\nexport function resolveChildCoerceSchema(\n\tcoerceSchema: JSONSchema7 | undefined,\n\tkey: string,\n): JSONSchema7 | undefined {\n\treturn coerceSchema ? resolveSchemaPath(coerceSchema, [key]) : undefined;\n}\n\n/**\n * Determines whether a `TemplateInput` value should be excluded when\n * `excludeTemplateExpression` is enabled.\n *\n * A value is excluded if it is a string containing at least one Handlebars\n * expression (`{{…}}`). Literals (number, boolean, null), plain strings\n * without expressions, objects, and arrays are never excluded at the\n * entry level — objects and arrays are recursively filtered by the\n * dispatching functions themselves.\n *\n * @param input - The template input to check\n * @returns `true` if the input should be excluded\n */\nexport function shouldExcludeEntry(input: TemplateInput): boolean {\n\treturn typeof input === \"string\" && hasHandlebarsExpression(input);\n}\n"],"names":["hasHandlebarsExpression","resolveSchemaPath","inferPrimitiveSchema","isArrayInput","isLiteralInput","isObjectInput","aggregateArrayAnalysis","aggregateArrayAnalysisAndExecution","aggregateObjectAnalysis","aggregateObjectAnalysisAndExecution","dispatchAnalyze","template","options","analyzeString","recurse","exclude","excludeTemplateExpression","childOptions","resolveArrayChildOptions","kept","filter","item","shouldExcludeEntry","length","index","dispatchObjectAnalysis","valid","diagnostics","outputSchema","coerceSchema","keys","Object","key","childCoerceSchema","resolveChildCoerceSchema","identifierSchemas","dispatchExecute","executeString","elements","result","element","push","dispatchAnalyzeAndExecute","processString","identifierData","analysis","value","type","itemsSchema","resolveItemsCoerceSchema","undefined","items","Array","isArray","input"],"mappings":"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"}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -207,6 +207,24 @@ export interface ExecuteOptions {
|
|
|
207
207
|
* coerced to match the declared type instead of using auto-detection.
|
|
208
208
|
*/
|
|
209
209
|
coerceSchema?: JSONSchema7;
|
|
210
|
+
/**
|
|
211
|
+
* When `true`, properties whose values contain Handlebars expressions
|
|
212
|
+
* (i.e. any `{{…}}` syntax) are excluded from the execution result.
|
|
213
|
+
*
|
|
214
|
+
* - **Object**: properties with template expressions are omitted from
|
|
215
|
+
* the resulting object.
|
|
216
|
+
* - **Array**: elements with template expressions are omitted from
|
|
217
|
+
* the resulting array.
|
|
218
|
+
* - **Root string** with expressions: returns `null` (there is no
|
|
219
|
+
* parent to exclude from).
|
|
220
|
+
* - **Literals** (number, boolean, null): unaffected.
|
|
221
|
+
*
|
|
222
|
+
* This mirrors the analysis-side `excludeTemplateExpression` option
|
|
223
|
+
* but applied at runtime.
|
|
224
|
+
*
|
|
225
|
+
* @default false
|
|
226
|
+
*/
|
|
227
|
+
excludeTemplateExpression?: boolean;
|
|
210
228
|
}
|
|
211
229
|
export interface AnalyzeAndExecuteOptions {
|
|
212
230
|
/** Schemas by identifier `{ [id]: JSONSchema7 }` for static analysis */
|
package/dist/esm/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport type { FromSchema, JSONSchema } from \"json-schema-to-ts\";\n\n// ─── Template Input ──────────────────────────────────────────────────────────\n// The engine accepts primitive values in addition to template strings.\n// When a non-string value is passed, it is treated as a literal passthrough:\n// analysis returns the inferred type, and execution returns the value as-is.\n\n/**\n * Object where each property is a `TemplateInput` (recursive).\n *\n * Allows passing an entire structure as a template:\n * ```\n * engine.analyze({\n * userName: \"{{name}}\",\n * userAge: \"{{age}}\",\n * nested: { x: \"{{foo}}\" },\n * }, inputSchema);\n * ```\n */\nexport interface TemplateInputObject {\n\t[key: string]: TemplateInput;\n}\n\n/**\n * Array where each element is a `TemplateInput` (recursive).\n *\n * Allows passing an array as a template:\n * ```\n * engine.analyze([\"{{name}}\", \"{{age}}\"], inputSchema);\n * engine.execute([\"{{name}}\", 42], data);\n * ```\n */\nexport type TemplateInputArray = TemplateInput[];\n\n/**\n * Input type accepted by the template engine.\n *\n * - `string` → standard Handlebars template (parsed and executed)\n * - `number` → numeric literal (passthrough)\n * - `boolean` → boolean literal (passthrough)\n * - `null` → null literal (passthrough)\n * - `TemplateInputArray` → array where each element is a `TemplateInput`\n * - `TemplateInputObject` → object where each property is a `TemplateInput`\n */\nexport type TemplateInput =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| TemplateInputArray\n\t| TemplateInputObject;\n\n// ─── Template Data ───────────────────────────────────────────────────────────\n// The data parameter accepted by `execute()` and `analyzeAndExecute()`.\n// In most cases this is a `Record<string, unknown>` (object context), but\n// primitives are also allowed — for example when using `{{$root}}` to\n// reference the entire data value directly.\n\n/**\n * Data type accepted by the template engine's execution methods.\n *\n * - `Record<string, unknown>` → standard object context (most common)\n * - `string` → primitive value (e.g. for `{{$root}}`)\n * - `number` → primitive value\n * - `boolean` → primitive value\n * - `null` → null value\n * - `unknown[]` → array value\n */\nexport type TemplateData =\n\t| Record<string, unknown>\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| unknown[];\n\n/**\n * Checks whether a value is a non-string primitive literal (number, boolean, null).\n * These values are treated as passthrough by the engine.\n *\n * Note: objects (`TemplateInputObject`) and arrays (`TemplateInputArray`) are NOT literals.\n */\nexport function isLiteralInput(\n\tinput: TemplateInput,\n): input is number | boolean | null {\n\treturn (\n\t\tinput === null || (typeof input !== \"string\" && typeof input !== \"object\")\n\t);\n}\n\n/**\n * Checks whether a value is a template array (`TemplateInputArray`).\n * Template arrays are processed recursively by the engine:\n * each element is analyzed/executed individually and the result is an array.\n */\nexport function isArrayInput(\n\tinput: TemplateInput,\n): input is TemplateInputArray {\n\treturn Array.isArray(input);\n}\n\n/**\n * Checks whether a value is a template object (`TemplateInputObject`).\n * Template objects are processed recursively by the engine:\n * each property is analyzed/executed individually.\n *\n * Note: arrays are excluded — use `isArrayInput()` first.\n */\nexport function isObjectInput(\n\tinput: TemplateInput,\n): input is TemplateInputObject {\n\treturn input !== null && typeof input === \"object\" && !Array.isArray(input);\n}\n\n/**\n * Infers the JSON Schema of a non-string primitive value.\n *\n * @param value - The primitive value (number, boolean, null)\n * @returns The corresponding JSON Schema\n *\n * @example\n * ```\n * inferPrimitiveSchema(42) // → { type: \"number\" }\n * inferPrimitiveSchema(true) // → { type: \"boolean\" }\n * inferPrimitiveSchema(null) // → { type: \"null\" }\n * ```\n */\nexport function inferPrimitiveSchema(\n\tvalue: number | boolean | null,\n): JSONSchema7 {\n\tif (value === null) return { type: \"null\" };\n\tif (typeof value === \"boolean\") return { type: \"boolean\" };\n\tif (typeof value === \"number\") {\n\t\treturn Number.isInteger(value) ? { type: \"integer\" } : { type: \"number\" };\n\t}\n\t// Exhaustiveness check — all branches are covered above.\n\t// If the type of `value` changes, TypeScript will raise an error here.\n\tvalue satisfies never;\n\treturn { type: \"null\" };\n}\n\n// ─── Diagnostic Codes ────────────────────────────────────────────────────────\n// Machine-readable codes for each error/warning type, enabling the frontend\n// to react programmatically without parsing the human-readable message.\n\nexport type DiagnosticCode =\n\t/** The referenced property does not exist in the context schema */\n\t| \"UNKNOWN_PROPERTY\"\n\t/** Type mismatch (e.g. #each on a non-array) */\n\t| \"TYPE_MISMATCH\"\n\t/** A block helper is used without a required argument */\n\t| \"MISSING_ARGUMENT\"\n\t/** Unknown block helper (neither built-in nor registered) */\n\t| \"UNKNOWN_HELPER\"\n\t/** The expression cannot be statically analyzed */\n\t| \"UNANALYZABLE\"\n\t/** The {{key:N}} syntax is used but no identifierSchemas were provided */\n\t| \"MISSING_IDENTIFIER_SCHEMAS\"\n\t/** The identifier N does not exist in the provided identifierSchemas */\n\t| \"UNKNOWN_IDENTIFIER\"\n\t/** The property does not exist in the identifier's schema */\n\t| \"IDENTIFIER_PROPERTY_NOT_FOUND\"\n\t/** Syntax error in the template */\n\t| \"PARSE_ERROR\"\n\t/** The $root token is used with path traversal (e.g. $root.name) */\n\t| \"ROOT_PATH_TRAVERSAL\";\n\n// ─── Diagnostic Details ──────────────────────────────────────────────────────\n// Supplementary information to understand the exact cause of the error.\n// Designed to be easily JSON-serializable and consumable by a frontend.\n\nexport interface DiagnosticDetails {\n\t/** Path of the expression that caused the error (e.g. `\"user.name.foo\"`) */\n\tpath?: string;\n\t/** Name of the helper involved (for helper-related errors) */\n\thelperName?: string;\n\t/** What was expected (e.g. `\"array\"`, `\"property to exist\"`) */\n\texpected?: string;\n\t/** What was found (e.g. `\"string\"`, `\"undefined\"`) */\n\tactual?: string;\n\t/** Available properties in the current schema (for suggestions) */\n\tavailableProperties?: string[];\n\t/** Template identifier number (for `{{key:N}}` errors) */\n\tidentifier?: number;\n}\n\n// ─── Static Analysis Result ──────────────────────────────────────────────────\n\n/** Diagnostic produced by the static analyzer */\nexport interface TemplateDiagnostic {\n\t/** \"error\" blocks execution, \"warning\" is informational */\n\tseverity: \"error\" | \"warning\";\n\n\t/** Machine-readable code identifying the error type */\n\tcode: DiagnosticCode;\n\n\t/** Human-readable message describing the problem */\n\tmessage: string;\n\n\t/** Position in the template source (if available from the AST) */\n\tloc?: {\n\t\tstart: { line: number; column: number };\n\t\tend: { line: number; column: number };\n\t};\n\n\t/** Fragment of the template source around the error */\n\tsource?: string;\n\n\t/** Structured information for debugging and frontend display */\n\tdetails?: DiagnosticDetails;\n}\n\n/** Complete result of the static analysis */\nexport interface AnalysisResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n\t/** JSON Schema describing the template's return type */\n\toutputSchema: JSONSchema7;\n}\n\n/** Lightweight validation result (without output type inference) */\nexport interface ValidationResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n}\n\n// ─── Public Engine Options ───────────────────────────────────────────────────\n\nexport interface TemplateEngineOptions {\n\t/**\n\t * Capacity of the parsed AST cache. Each parsed template is cached\n\t * to avoid costly re-parsing on repeated calls.\n\t * @default 256\n\t */\n\tastCacheSize?: number;\n\n\t/**\n\t * Capacity of the compiled Handlebars template cache.\n\t * @default 256\n\t */\n\tcompilationCacheSize?: number;\n\n\t/**\n\t * Custom helpers to register during engine construction.\n\t *\n\t * Each entry describes a helper with its name, implementation,\n\t * expected parameters, and return type.\n\t *\n\t * @example\n\t * ```\n\t * const engine = new Typebars({\n\t * helpers: [\n\t * {\n\t * name: \"uppercase\",\n\t * description: \"Converts a string to uppercase\",\n\t * fn: (value: string) => String(value).toUpperCase(),\n\t * params: [\n\t * { name: \"value\", type: { type: \"string\" }, description: \"The string to convert\" },\n\t * ],\n\t * returnType: { type: \"string\" },\n\t * },\n\t * ],\n\t * });\n\t * ```\n\t */\n\thelpers?: HelperConfig[];\n}\n\n// ─── Execution Options ───────────────────────────────────────────────────────\n// Optional options object for `execute()`, replacing multiple positional\n// parameters for better ergonomics.\n\nexport interface ExecuteOptions {\n\t/** JSON Schema for pre-execution static validation */\n\tschema?: JSONSchema7;\n\t/** Data by identifier `{ [id]: { key: value } }` */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/** Schemas by identifier (for static validation with identifiers) */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Combined Analyze-and-Execute Options ────────────────────────────────────\n// Optional options object for `analyzeAndExecute()`, grouping parameters\n// related to template identifiers.\n\nexport interface AnalyzeAndExecuteOptions {\n\t/** Schemas by identifier `{ [id]: JSONSchema7 }` for static analysis */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Data by identifier `{ [id]: { key: value } }` for execution */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Custom Helpers ──────────────────────────────────────────────────────────\n// Allows registering custom helpers with their type signature for static\n// analysis support.\n\n/** Describes a parameter expected by a helper */\nexport interface HelperParam {\n\t/** Parameter name (for documentation / introspection) */\n\tname: string;\n\n\t/**\n\t * JSON Schema describing the expected type for this parameter.\n\t * Used for documentation and static validation.\n\t */\n\ttype?: JSONSchema7;\n\n\t/** Human-readable description of the parameter */\n\tdescription?: string;\n\n\t/**\n\t * Whether the parameter is optional.\n\t * @default false\n\t */\n\toptional?: boolean;\n}\n\n/**\n * Definition of a helper registerable via `registerHelper()`.\n *\n * Contains the runtime implementation and typing metadata\n * for static analysis.\n */\nexport interface HelperDefinition {\n\t/**\n\t * Runtime implementation of the helper — will be registered with Handlebars.\n\t *\n\t * For an inline helper `{{uppercase name}}`:\n\t * `(value: string) => string`\n\t *\n\t * For a block helper `{{#repeat count}}...{{/repeat}}`:\n\t * `function(this: any, count: number, options: Handlebars.HelperOptions) { ... }`\n\t */\n\t// biome-ignore lint/suspicious/noExplicitAny: Handlebars helper signatures are inherently dynamic\n\tfn: (...args: any[]) => unknown;\n\n\t/**\n\t * Parameters expected by the helper (for documentation and analysis).\n\t *\n\t * @example\n\t * ```\n\t * params: [\n\t * { name: \"value\", type: { type: \"number\" }, description: \"The value to round\" },\n\t * { name: \"precision\", type: { type: \"number\" }, description: \"Decimal places\", optional: true },\n\t * ]\n\t * ```\n\t */\n\tparams?: HelperParam[];\n\n\t/**\n\t * JSON Schema describing the helper's return type for static analysis.\n\t * @default { type: \"string\" }\n\t */\n\treturnType?: JSONSchema7;\n\n\t/** Human-readable description of the helper */\n\tdescription?: string;\n}\n\n/**\n * Full helper configuration for registration via the `Typebars({ helpers: [...] })`\n * constructor options.\n *\n * Extends `HelperDefinition` with a required `name`.\n *\n * @example\n * ```\n * const config: HelperConfig = {\n * name: \"round\",\n * description: \"Rounds a number to a given precision\",\n * fn: (value: number, precision?: number) => { ... },\n * params: [\n * { name: \"value\", type: { type: \"number\" } },\n * { name: \"precision\", type: { type: \"number\" }, optional: true },\n * ],\n * returnType: { type: \"number\" },\n * };\n * ```\n */\nexport interface HelperConfig extends HelperDefinition {\n\t/** Name of the helper as used in templates (e.g. `\"uppercase\"`) */\n\tname: string;\n}\n\n// ─── Automatic Type Inference via json-schema-to-ts ──────────────────────────\n// Allows `defineHelper()` to infer TypeScript types for `fn` arguments\n// from the JSON Schemas declared in `params`.\n\n/**\n * Param definition used for type inference.\n * Accepts `JSONSchema` from `json-schema-to-ts` to allow `FromSchema`\n * to resolve literal types.\n */\ntype TypedHelperParam = {\n\treadonly name: string;\n\treadonly type?: JSONSchema;\n\treadonly description?: string;\n\treadonly optional?: boolean;\n};\n\n/**\n * Infers the TypeScript type of a single parameter from its JSON Schema.\n * - If `optional: true`, the resolved type is unioned with `undefined`.\n * - If `type` is not provided, the type is `unknown`.\n */\ntype InferParamType<P> = P extends {\n\treadonly type: infer S extends JSONSchema;\n\treadonly optional: true;\n}\n\t? FromSchema<S> | undefined\n\t: P extends { readonly type: infer S extends JSONSchema }\n\t\t? FromSchema<S>\n\t\t: unknown;\n\n/**\n * Maps a tuple of `TypedHelperParam` to a tuple of inferred TypeScript types,\n * usable as the `fn` signature.\n *\n * @example\n * ```\n * type Args = InferArgs<readonly [\n * { name: \"a\"; type: { type: \"string\" } },\n * { name: \"b\"; type: { type: \"number\" }; optional: true },\n * ]>;\n * // => [string, number | undefined]\n * ```\n */\ntype InferArgs<P extends readonly TypedHelperParam[]> = {\n\t[K in keyof P]: InferParamType<P[K]>;\n};\n\n/**\n * Helper configuration with generic parameter inference.\n * Used exclusively by `defineHelper()`.\n */\ninterface TypedHelperConfig<P extends readonly TypedHelperParam[]> {\n\tname: string;\n\tdescription?: string;\n\tparams: P;\n\tfn: (...args: InferArgs<P>) => unknown;\n\treturnType?: JSONSchema;\n}\n\n/**\n * Creates a `HelperConfig` with automatic type inference for `fn` arguments\n * based on the JSON Schemas declared in `params`.\n *\n * The generic parameter `const P` preserves schema literal types\n * (equivalent of `as const`), enabling `FromSchema` to resolve the\n * corresponding TypeScript types.\n *\n * @example\n * ```\n * const helper = defineHelper({\n * name: \"concat\",\n * description: \"Concatenates two strings\",\n * params: [\n * { name: \"a\", type: { type: \"string\" }, description: \"First string\" },\n * { name: \"b\", type: { type: \"string\" }, description: \"Second string\" },\n * { name: \"sep\", type: { type: \"string\" }, description: \"Separator\", optional: true },\n * ],\n * fn: (a, b, sep) => {\n * // a: string, b: string, sep: string | undefined\n * const separator = sep ?? \"\";\n * return `${a}${separator}${b}`;\n * },\n * returnType: { type: \"string\" },\n * });\n * ```\n */\nexport function defineHelper<const P extends readonly TypedHelperParam[]>(\n\tconfig: TypedHelperConfig<P>,\n): HelperConfig {\n\treturn config as unknown as HelperConfig;\n}\n"],"names":["isLiteralInput","input","isArrayInput","Array","isArray","isObjectInput","inferPrimitiveSchema","value","type","Number","isInteger","defineHelper","config"],"mappings":"AAmFA,OAAO,SAASA,eACfC,KAAoB,EAEpB,OACCA,QAAU,MAAS,OAAOA,QAAU,UAAY,OAAOA,QAAU,QAEnE,CAOA,OAAO,SAASC,aACfD,KAAoB,EAEpB,OAAOE,MAAMC,OAAO,CAACH,MACtB,CASA,OAAO,SAASI,cACfJ,KAAoB,EAEpB,OAAOA,QAAU,MAAQ,OAAOA,QAAU,UAAY,CAACE,MAAMC,OAAO,CAACH,MACtE,CAeA,OAAO,SAASK,qBACfC,KAA8B,EAE9B,GAAIA,QAAU,KAAM,MAAO,CAAEC,KAAM,MAAO,EAC1C,GAAI,OAAOD,QAAU,UAAW,MAAO,CAAEC,KAAM,SAAU,EACzD,GAAI,OAAOD,QAAU,SAAU,CAC9B,OAAOE,OAAOC,SAAS,CAACH,OAAS,CAAEC,KAAM,SAAU,EAAI,CAAEA,KAAM,QAAS,CACzE,CAGAD,MACA,MAAO,CAAEC,KAAM,MAAO,CACvB,CA2VA,OAAO,SAASG,aACfC,MAA4B,EAE5B,OAAOA,MACR"}
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts"],"sourcesContent":["import type { JSONSchema7 } from \"json-schema\";\nimport type { FromSchema, JSONSchema } from \"json-schema-to-ts\";\n\n// ─── Template Input ──────────────────────────────────────────────────────────\n// The engine accepts primitive values in addition to template strings.\n// When a non-string value is passed, it is treated as a literal passthrough:\n// analysis returns the inferred type, and execution returns the value as-is.\n\n/**\n * Object where each property is a `TemplateInput` (recursive).\n *\n * Allows passing an entire structure as a template:\n * ```\n * engine.analyze({\n * userName: \"{{name}}\",\n * userAge: \"{{age}}\",\n * nested: { x: \"{{foo}}\" },\n * }, inputSchema);\n * ```\n */\nexport interface TemplateInputObject {\n\t[key: string]: TemplateInput;\n}\n\n/**\n * Array where each element is a `TemplateInput` (recursive).\n *\n * Allows passing an array as a template:\n * ```\n * engine.analyze([\"{{name}}\", \"{{age}}\"], inputSchema);\n * engine.execute([\"{{name}}\", 42], data);\n * ```\n */\nexport type TemplateInputArray = TemplateInput[];\n\n/**\n * Input type accepted by the template engine.\n *\n * - `string` → standard Handlebars template (parsed and executed)\n * - `number` → numeric literal (passthrough)\n * - `boolean` → boolean literal (passthrough)\n * - `null` → null literal (passthrough)\n * - `TemplateInputArray` → array where each element is a `TemplateInput`\n * - `TemplateInputObject` → object where each property is a `TemplateInput`\n */\nexport type TemplateInput =\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| TemplateInputArray\n\t| TemplateInputObject;\n\n// ─── Template Data ───────────────────────────────────────────────────────────\n// The data parameter accepted by `execute()` and `analyzeAndExecute()`.\n// In most cases this is a `Record<string, unknown>` (object context), but\n// primitives are also allowed — for example when using `{{$root}}` to\n// reference the entire data value directly.\n\n/**\n * Data type accepted by the template engine's execution methods.\n *\n * - `Record<string, unknown>` → standard object context (most common)\n * - `string` → primitive value (e.g. for `{{$root}}`)\n * - `number` → primitive value\n * - `boolean` → primitive value\n * - `null` → null value\n * - `unknown[]` → array value\n */\nexport type TemplateData =\n\t| Record<string, unknown>\n\t| string\n\t| number\n\t| boolean\n\t| null\n\t| unknown[];\n\n/**\n * Checks whether a value is a non-string primitive literal (number, boolean, null).\n * These values are treated as passthrough by the engine.\n *\n * Note: objects (`TemplateInputObject`) and arrays (`TemplateInputArray`) are NOT literals.\n */\nexport function isLiteralInput(\n\tinput: TemplateInput,\n): input is number | boolean | null {\n\treturn (\n\t\tinput === null || (typeof input !== \"string\" && typeof input !== \"object\")\n\t);\n}\n\n/**\n * Checks whether a value is a template array (`TemplateInputArray`).\n * Template arrays are processed recursively by the engine:\n * each element is analyzed/executed individually and the result is an array.\n */\nexport function isArrayInput(\n\tinput: TemplateInput,\n): input is TemplateInputArray {\n\treturn Array.isArray(input);\n}\n\n/**\n * Checks whether a value is a template object (`TemplateInputObject`).\n * Template objects are processed recursively by the engine:\n * each property is analyzed/executed individually.\n *\n * Note: arrays are excluded — use `isArrayInput()` first.\n */\nexport function isObjectInput(\n\tinput: TemplateInput,\n): input is TemplateInputObject {\n\treturn input !== null && typeof input === \"object\" && !Array.isArray(input);\n}\n\n/**\n * Infers the JSON Schema of a non-string primitive value.\n *\n * @param value - The primitive value (number, boolean, null)\n * @returns The corresponding JSON Schema\n *\n * @example\n * ```\n * inferPrimitiveSchema(42) // → { type: \"number\" }\n * inferPrimitiveSchema(true) // → { type: \"boolean\" }\n * inferPrimitiveSchema(null) // → { type: \"null\" }\n * ```\n */\nexport function inferPrimitiveSchema(\n\tvalue: number | boolean | null,\n): JSONSchema7 {\n\tif (value === null) return { type: \"null\" };\n\tif (typeof value === \"boolean\") return { type: \"boolean\" };\n\tif (typeof value === \"number\") {\n\t\treturn Number.isInteger(value) ? { type: \"integer\" } : { type: \"number\" };\n\t}\n\t// Exhaustiveness check — all branches are covered above.\n\t// If the type of `value` changes, TypeScript will raise an error here.\n\tvalue satisfies never;\n\treturn { type: \"null\" };\n}\n\n// ─── Diagnostic Codes ────────────────────────────────────────────────────────\n// Machine-readable codes for each error/warning type, enabling the frontend\n// to react programmatically without parsing the human-readable message.\n\nexport type DiagnosticCode =\n\t/** The referenced property does not exist in the context schema */\n\t| \"UNKNOWN_PROPERTY\"\n\t/** Type mismatch (e.g. #each on a non-array) */\n\t| \"TYPE_MISMATCH\"\n\t/** A block helper is used without a required argument */\n\t| \"MISSING_ARGUMENT\"\n\t/** Unknown block helper (neither built-in nor registered) */\n\t| \"UNKNOWN_HELPER\"\n\t/** The expression cannot be statically analyzed */\n\t| \"UNANALYZABLE\"\n\t/** The {{key:N}} syntax is used but no identifierSchemas were provided */\n\t| \"MISSING_IDENTIFIER_SCHEMAS\"\n\t/** The identifier N does not exist in the provided identifierSchemas */\n\t| \"UNKNOWN_IDENTIFIER\"\n\t/** The property does not exist in the identifier's schema */\n\t| \"IDENTIFIER_PROPERTY_NOT_FOUND\"\n\t/** Syntax error in the template */\n\t| \"PARSE_ERROR\"\n\t/** The $root token is used with path traversal (e.g. $root.name) */\n\t| \"ROOT_PATH_TRAVERSAL\";\n\n// ─── Diagnostic Details ──────────────────────────────────────────────────────\n// Supplementary information to understand the exact cause of the error.\n// Designed to be easily JSON-serializable and consumable by a frontend.\n\nexport interface DiagnosticDetails {\n\t/** Path of the expression that caused the error (e.g. `\"user.name.foo\"`) */\n\tpath?: string;\n\t/** Name of the helper involved (for helper-related errors) */\n\thelperName?: string;\n\t/** What was expected (e.g. `\"array\"`, `\"property to exist\"`) */\n\texpected?: string;\n\t/** What was found (e.g. `\"string\"`, `\"undefined\"`) */\n\tactual?: string;\n\t/** Available properties in the current schema (for suggestions) */\n\tavailableProperties?: string[];\n\t/** Template identifier number (for `{{key:N}}` errors) */\n\tidentifier?: number;\n}\n\n// ─── Static Analysis Result ──────────────────────────────────────────────────\n\n/** Diagnostic produced by the static analyzer */\nexport interface TemplateDiagnostic {\n\t/** \"error\" blocks execution, \"warning\" is informational */\n\tseverity: \"error\" | \"warning\";\n\n\t/** Machine-readable code identifying the error type */\n\tcode: DiagnosticCode;\n\n\t/** Human-readable message describing the problem */\n\tmessage: string;\n\n\t/** Position in the template source (if available from the AST) */\n\tloc?: {\n\t\tstart: { line: number; column: number };\n\t\tend: { line: number; column: number };\n\t};\n\n\t/** Fragment of the template source around the error */\n\tsource?: string;\n\n\t/** Structured information for debugging and frontend display */\n\tdetails?: DiagnosticDetails;\n}\n\n/** Complete result of the static analysis */\nexport interface AnalysisResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n\t/** JSON Schema describing the template's return type */\n\toutputSchema: JSONSchema7;\n}\n\n/** Lightweight validation result (without output type inference) */\nexport interface ValidationResult {\n\t/** true if no errors (warnings are tolerated) */\n\tvalid: boolean;\n\t/** List of diagnostics (errors + warnings) */\n\tdiagnostics: TemplateDiagnostic[];\n}\n\n// ─── Public Engine Options ───────────────────────────────────────────────────\n\nexport interface TemplateEngineOptions {\n\t/**\n\t * Capacity of the parsed AST cache. Each parsed template is cached\n\t * to avoid costly re-parsing on repeated calls.\n\t * @default 256\n\t */\n\tastCacheSize?: number;\n\n\t/**\n\t * Capacity of the compiled Handlebars template cache.\n\t * @default 256\n\t */\n\tcompilationCacheSize?: number;\n\n\t/**\n\t * Custom helpers to register during engine construction.\n\t *\n\t * Each entry describes a helper with its name, implementation,\n\t * expected parameters, and return type.\n\t *\n\t * @example\n\t * ```\n\t * const engine = new Typebars({\n\t * helpers: [\n\t * {\n\t * name: \"uppercase\",\n\t * description: \"Converts a string to uppercase\",\n\t * fn: (value: string) => String(value).toUpperCase(),\n\t * params: [\n\t * { name: \"value\", type: { type: \"string\" }, description: \"The string to convert\" },\n\t * ],\n\t * returnType: { type: \"string\" },\n\t * },\n\t * ],\n\t * });\n\t * ```\n\t */\n\thelpers?: HelperConfig[];\n}\n\n// ─── Execution Options ───────────────────────────────────────────────────────\n// Optional options object for `execute()`, replacing multiple positional\n// parameters for better ergonomics.\n\nexport interface ExecuteOptions {\n\t/** JSON Schema for pre-execution static validation */\n\tschema?: JSONSchema7;\n\t/** Data by identifier `{ [id]: { key: value } }` */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/** Schemas by identifier (for static validation with identifiers) */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n\t/**\n\t * When `true`, properties whose values contain Handlebars expressions\n\t * (i.e. any `{{…}}` syntax) are excluded from the execution result.\n\t *\n\t * - **Object**: properties with template expressions are omitted from\n\t * the resulting object.\n\t * - **Array**: elements with template expressions are omitted from\n\t * the resulting array.\n\t * - **Root string** with expressions: returns `null` (there is no\n\t * parent to exclude from).\n\t * - **Literals** (number, boolean, null): unaffected.\n\t *\n\t * This mirrors the analysis-side `excludeTemplateExpression` option\n\t * but applied at runtime.\n\t *\n\t * @default false\n\t */\n\texcludeTemplateExpression?: boolean;\n}\n\n// ─── Combined Analyze-and-Execute Options ────────────────────────────────────\n// Optional options object for `analyzeAndExecute()`, grouping parameters\n// related to template identifiers.\n\nexport interface AnalyzeAndExecuteOptions {\n\t/** Schemas by identifier `{ [id]: JSONSchema7 }` for static analysis */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Data by identifier `{ [id]: { key: value } }` for execution */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/**\n\t * Explicit coercion schema for the output value.\n\t * When provided with a primitive type, the execution result will be\n\t * coerced to match the declared type instead of using auto-detection.\n\t */\n\tcoerceSchema?: JSONSchema7;\n}\n\n// ─── Custom Helpers ──────────────────────────────────────────────────────────\n// Allows registering custom helpers with their type signature for static\n// analysis support.\n\n/** Describes a parameter expected by a helper */\nexport interface HelperParam {\n\t/** Parameter name (for documentation / introspection) */\n\tname: string;\n\n\t/**\n\t * JSON Schema describing the expected type for this parameter.\n\t * Used for documentation and static validation.\n\t */\n\ttype?: JSONSchema7;\n\n\t/** Human-readable description of the parameter */\n\tdescription?: string;\n\n\t/**\n\t * Whether the parameter is optional.\n\t * @default false\n\t */\n\toptional?: boolean;\n}\n\n/**\n * Definition of a helper registerable via `registerHelper()`.\n *\n * Contains the runtime implementation and typing metadata\n * for static analysis.\n */\nexport interface HelperDefinition {\n\t/**\n\t * Runtime implementation of the helper — will be registered with Handlebars.\n\t *\n\t * For an inline helper `{{uppercase name}}`:\n\t * `(value: string) => string`\n\t *\n\t * For a block helper `{{#repeat count}}...{{/repeat}}`:\n\t * `function(this: any, count: number, options: Handlebars.HelperOptions) { ... }`\n\t */\n\t// biome-ignore lint/suspicious/noExplicitAny: Handlebars helper signatures are inherently dynamic\n\tfn: (...args: any[]) => unknown;\n\n\t/**\n\t * Parameters expected by the helper (for documentation and analysis).\n\t *\n\t * @example\n\t * ```\n\t * params: [\n\t * { name: \"value\", type: { type: \"number\" }, description: \"The value to round\" },\n\t * { name: \"precision\", type: { type: \"number\" }, description: \"Decimal places\", optional: true },\n\t * ]\n\t * ```\n\t */\n\tparams?: HelperParam[];\n\n\t/**\n\t * JSON Schema describing the helper's return type for static analysis.\n\t * @default { type: \"string\" }\n\t */\n\treturnType?: JSONSchema7;\n\n\t/** Human-readable description of the helper */\n\tdescription?: string;\n}\n\n/**\n * Full helper configuration for registration via the `Typebars({ helpers: [...] })`\n * constructor options.\n *\n * Extends `HelperDefinition` with a required `name`.\n *\n * @example\n * ```\n * const config: HelperConfig = {\n * name: \"round\",\n * description: \"Rounds a number to a given precision\",\n * fn: (value: number, precision?: number) => { ... },\n * params: [\n * { name: \"value\", type: { type: \"number\" } },\n * { name: \"precision\", type: { type: \"number\" }, optional: true },\n * ],\n * returnType: { type: \"number\" },\n * };\n * ```\n */\nexport interface HelperConfig extends HelperDefinition {\n\t/** Name of the helper as used in templates (e.g. `\"uppercase\"`) */\n\tname: string;\n}\n\n// ─── Automatic Type Inference via json-schema-to-ts ──────────────────────────\n// Allows `defineHelper()` to infer TypeScript types for `fn` arguments\n// from the JSON Schemas declared in `params`.\n\n/**\n * Param definition used for type inference.\n * Accepts `JSONSchema` from `json-schema-to-ts` to allow `FromSchema`\n * to resolve literal types.\n */\ntype TypedHelperParam = {\n\treadonly name: string;\n\treadonly type?: JSONSchema;\n\treadonly description?: string;\n\treadonly optional?: boolean;\n};\n\n/**\n * Infers the TypeScript type of a single parameter from its JSON Schema.\n * - If `optional: true`, the resolved type is unioned with `undefined`.\n * - If `type` is not provided, the type is `unknown`.\n */\ntype InferParamType<P> = P extends {\n\treadonly type: infer S extends JSONSchema;\n\treadonly optional: true;\n}\n\t? FromSchema<S> | undefined\n\t: P extends { readonly type: infer S extends JSONSchema }\n\t\t? FromSchema<S>\n\t\t: unknown;\n\n/**\n * Maps a tuple of `TypedHelperParam` to a tuple of inferred TypeScript types,\n * usable as the `fn` signature.\n *\n * @example\n * ```\n * type Args = InferArgs<readonly [\n * { name: \"a\"; type: { type: \"string\" } },\n * { name: \"b\"; type: { type: \"number\" }; optional: true },\n * ]>;\n * // => [string, number | undefined]\n * ```\n */\ntype InferArgs<P extends readonly TypedHelperParam[]> = {\n\t[K in keyof P]: InferParamType<P[K]>;\n};\n\n/**\n * Helper configuration with generic parameter inference.\n * Used exclusively by `defineHelper()`.\n */\ninterface TypedHelperConfig<P extends readonly TypedHelperParam[]> {\n\tname: string;\n\tdescription?: string;\n\tparams: P;\n\tfn: (...args: InferArgs<P>) => unknown;\n\treturnType?: JSONSchema;\n}\n\n/**\n * Creates a `HelperConfig` with automatic type inference for `fn` arguments\n * based on the JSON Schemas declared in `params`.\n *\n * The generic parameter `const P` preserves schema literal types\n * (equivalent of `as const`), enabling `FromSchema` to resolve the\n * corresponding TypeScript types.\n *\n * @example\n * ```\n * const helper = defineHelper({\n * name: \"concat\",\n * description: \"Concatenates two strings\",\n * params: [\n * { name: \"a\", type: { type: \"string\" }, description: \"First string\" },\n * { name: \"b\", type: { type: \"string\" }, description: \"Second string\" },\n * { name: \"sep\", type: { type: \"string\" }, description: \"Separator\", optional: true },\n * ],\n * fn: (a, b, sep) => {\n * // a: string, b: string, sep: string | undefined\n * const separator = sep ?? \"\";\n * return `${a}${separator}${b}`;\n * },\n * returnType: { type: \"string\" },\n * });\n * ```\n */\nexport function defineHelper<const P extends readonly TypedHelperParam[]>(\n\tconfig: TypedHelperConfig<P>,\n): HelperConfig {\n\treturn config as unknown as HelperConfig;\n}\n"],"names":["isLiteralInput","input","isArrayInput","Array","isArray","isObjectInput","inferPrimitiveSchema","value","type","Number","isInteger","defineHelper","config"],"mappings":"AAmFA,OAAO,SAASA,eACfC,KAAoB,EAEpB,OACCA,QAAU,MAAS,OAAOA,QAAU,UAAY,OAAOA,QAAU,QAEnE,CAOA,OAAO,SAASC,aACfD,KAAoB,EAEpB,OAAOE,MAAMC,OAAO,CAACH,MACtB,CASA,OAAO,SAASI,cACfJ,KAAoB,EAEpB,OAAOA,QAAU,MAAQ,OAAOA,QAAU,UAAY,CAACE,MAAMC,OAAO,CAACH,MACtE,CAeA,OAAO,SAASK,qBACfC,KAA8B,EAE9B,GAAIA,QAAU,KAAM,MAAO,CAAEC,KAAM,MAAO,EAC1C,GAAI,OAAOD,QAAU,UAAW,MAAO,CAAEC,KAAM,SAAU,EACzD,GAAI,OAAOD,QAAU,SAAU,CAC9B,OAAOE,OAAOC,SAAS,CAACH,OAAS,CAAEC,KAAM,SAAU,EAAI,CAAEA,KAAM,QAAS,CACzE,CAGAD,MACA,MAAO,CAAEC,KAAM,MAAO,CACvB,CA6WA,OAAO,SAASG,aACfC,MAA4B,EAE5B,OAAOA,MACR"}
|
package/package.json
CHANGED