typebars 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +1582 -0
  2. package/dist/analyzer.d.ts +59 -0
  3. package/dist/analyzer.js +4 -0
  4. package/dist/analyzer.js.map +9 -0
  5. package/dist/chunk-1gm6cf0e.js +5 -0
  6. package/dist/chunk-1gm6cf0e.js.map +10 -0
  7. package/dist/chunk-1qwj7pjc.js +4 -0
  8. package/dist/chunk-1qwj7pjc.js.map +10 -0
  9. package/dist/chunk-4zv02svp.js +7 -0
  10. package/dist/chunk-4zv02svp.js.map +10 -0
  11. package/dist/chunk-60gk3q7z.js +5 -0
  12. package/dist/chunk-60gk3q7z.js.map +10 -0
  13. package/dist/chunk-6955jpr7.js +5 -0
  14. package/dist/chunk-6955jpr7.js.map +10 -0
  15. package/dist/chunk-6c0pw73w.js +7 -0
  16. package/dist/chunk-6c0pw73w.js.map +10 -0
  17. package/dist/chunk-7j6q1e3z.js +5 -0
  18. package/dist/chunk-7j6q1e3z.js.map +14 -0
  19. package/dist/chunk-8g0d6h85.js +5 -0
  20. package/dist/chunk-8g0d6h85.js.map +10 -0
  21. package/dist/chunk-9mg6qfrs.js +5 -0
  22. package/dist/chunk-9mg6qfrs.js.map +10 -0
  23. package/dist/chunk-a37yzqra.js +5 -0
  24. package/dist/chunk-a37yzqra.js.map +11 -0
  25. package/dist/chunk-awgj10qg.js +4 -0
  26. package/dist/chunk-awgj10qg.js.map +10 -0
  27. package/dist/chunk-fhvf5y4x.js +7 -0
  28. package/dist/chunk-fhvf5y4x.js.map +10 -0
  29. package/dist/chunk-ggdfaqhe.js +5 -0
  30. package/dist/chunk-ggdfaqhe.js.map +10 -0
  31. package/dist/chunk-hc1jnqaw.js +5 -0
  32. package/dist/chunk-hc1jnqaw.js.map +10 -0
  33. package/dist/chunk-kznb0bev.js +5 -0
  34. package/dist/chunk-kznb0bev.js.map +10 -0
  35. package/dist/chunk-mx8neh7q.js +5 -0
  36. package/dist/chunk-mx8neh7q.js.map +10 -0
  37. package/dist/chunk-p3xzf1ew.js +5 -0
  38. package/dist/chunk-p3xzf1ew.js.map +10 -0
  39. package/dist/chunk-qh2r1pa1.js +5 -0
  40. package/dist/chunk-qh2r1pa1.js.map +10 -0
  41. package/dist/chunk-qpzzr2rd.js +5 -0
  42. package/dist/chunk-qpzzr2rd.js.map +10 -0
  43. package/dist/chunk-vka4e61h.js +7 -0
  44. package/dist/chunk-vka4e61h.js.map +10 -0
  45. package/dist/chunk-xbvk4ygq.js +5 -0
  46. package/dist/chunk-xbvk4ygq.js.map +11 -0
  47. package/dist/chunk-ybh51hbe.js +7 -0
  48. package/dist/chunk-ybh51hbe.js.map +10 -0
  49. package/dist/chunk-yczpjh73.js +4 -0
  50. package/dist/chunk-yczpjh73.js.map +10 -0
  51. package/dist/chunk-yraqh2tz.js +5 -0
  52. package/dist/chunk-yraqh2tz.js.map +10 -0
  53. package/dist/chunk-z6yh5qvc.js +5 -0
  54. package/dist/chunk-z6yh5qvc.js.map +10 -0
  55. package/dist/compiled-template.d.ts +130 -0
  56. package/dist/compiled-template.js +4 -0
  57. package/dist/compiled-template.js.map +9 -0
  58. package/dist/errors.d.ts +93 -0
  59. package/dist/errors.js +4 -0
  60. package/dist/errors.js.map +9 -0
  61. package/dist/executor.d.ts +55 -0
  62. package/dist/executor.js +4 -0
  63. package/dist/executor.js.map +9 -0
  64. package/dist/helpers/helper-factory.d.ts +56 -0
  65. package/dist/helpers/index.d.ts +4 -0
  66. package/dist/helpers/logical-helpers.d.ts +15 -0
  67. package/dist/helpers/math-helpers.d.ts +13 -0
  68. package/dist/helpers/utils.d.ts +19 -0
  69. package/dist/index.d.ts +2 -0
  70. package/dist/index.js +4 -0
  71. package/dist/index.js.map +9 -0
  72. package/dist/parser.d.ts +146 -0
  73. package/dist/parser.js +4 -0
  74. package/dist/parser.js.map +9 -0
  75. package/dist/schema-resolver.d.ts +50 -0
  76. package/dist/schema-resolver.js +4 -0
  77. package/dist/schema-resolver.js.map +9 -0
  78. package/dist/typebars.d.ts +130 -0
  79. package/dist/typebars.js +4 -0
  80. package/dist/typebars.js.map +9 -0
  81. package/dist/types.d.ts +334 -0
  82. package/dist/types.js +4 -0
  83. package/dist/types.js.map +9 -0
  84. package/dist/utils.d.ts +113 -0
  85. package/dist/utils.js +4 -0
  86. package/dist/utils.js.map +9 -0
  87. package/package.json +42 -0
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/typebars.ts", "../src/helpers/helper-factory.ts", "../src/helpers/utils.ts", "../src/helpers/logical-helpers.ts", "../src/helpers/math-helpers.ts"],
4
+ "sourcesContent": [
5
+ "import Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport {\n\tCompiledTemplate,\n\ttype CompiledTemplateOptions,\n} from \"./compiled-template.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { executeFromAst } from \"./executor.ts\";\nimport { LogicalHelpers, MathHelpers } from \"./helpers/index.ts\";\nimport { parse } from \"./parser.ts\";\nimport type {\n\tAnalysisResult,\n\tAnalyzeAndExecuteOptions,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateEngineOptions,\n\tTemplateInput,\n\tValidationResult,\n} from \"./types.ts\";\nimport {\n\tinferPrimitiveSchema,\n\tisLiteralInput,\n\tisObjectInput,\n} from \"./types.ts\";\nimport {\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n\tLRUCache,\n} from \"./utils.ts\";\n\n// ─── Typebars ────────────────────────────────────────────────────────────────\n// Public entry point of the template engine. Orchestrates three phases:\n//\n// 1. **Parsing** — transforms the template string into an AST (via Handlebars)\n// 2. **Analysis** — static validation + return type inference\n// 3. **Execution** — renders the template with real data\n//\n// ─── Architecture v2 ─────────────────────────────────────────────────────────\n// - **LRU cache** for parsed ASTs and compiled Handlebars templates\n// - **Isolated Handlebars environment** per instance (custom helpers)\n// - **`compile()` pattern**: parse-once / execute-many\n// - **`validate()` method**: API shortcut without `outputSchema`\n// - **`registerHelper()`**: custom helpers with static typing\n// - **`ExecuteOptions`**: options object for `execute()`\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// The `{{key:N}}` syntax allows referencing variables from specific data\n// sources, identified by an integer N.\n//\n// - `identifierSchemas`: mapping `{ [id]: JSONSchema7 }` for static analysis\n// - `identifierData`: mapping `{ [id]: Record<string, unknown> }` for execution\n//\n// Usage:\n// engine.execute(\"{{meetingId:1}}\", data, { identifierData: { 1: node1Data } });\n// engine.analyze(\"{{meetingId:1}}\", schema, { 1: node1Schema });\n\n// ─── Main Class ──────────────────────────────────────────────────────────────\n\nexport class Typebars {\n\t/** Isolated Handlebars environment — each engine has its own helpers */\n\tprivate readonly hbs: typeof Handlebars;\n\n\t/** LRU cache of parsed ASTs (avoids re-parsing) */\n\tprivate readonly astCache: LRUCache<string, hbs.AST.Program>;\n\n\t/** LRU cache of compiled Handlebars templates (avoids recompilation) */\n\tprivate readonly compilationCache: LRUCache<\n\t\tstring,\n\t\tHandlebarsTemplateDelegate\n\t>;\n\n\t/** Custom helpers registered on this instance */\n\tprivate readonly helpers = new Map<string, HelperDefinition>();\n\n\tconstructor(options: TemplateEngineOptions = {}) {\n\t\tthis.hbs = Handlebars.create();\n\t\tthis.astCache = new LRUCache(options.astCacheSize ?? 256);\n\t\tthis.compilationCache = new LRUCache(options.compilationCacheSize ?? 256);\n\n\t\t// ── Built-in helpers ─────────────────────────────────────────────\n\t\tnew MathHelpers().register(this);\n\t\tnew LogicalHelpers().register(this);\n\n\t\t// ── Custom helpers via options ───────────────────────────────────\n\t\tif (options.helpers) {\n\t\t\tfor (const helper of options.helpers) {\n\t\t\t\tconst { name, ...definition } = helper;\n\t\t\t\tthis.registerHelper(name, definition);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Compilation ───────────────────────────────────────────────────────\n\n\t/**\n\t * Compiles a template and returns a `CompiledTemplate` ready to be\n\t * executed or analyzed without re-parsing.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is compiled recursively.\n\t *\n\t * @param template - The template to compile\n\t * @returns A reusable `CompiledTemplate`\n\t */\n\tcompile(template: TemplateInput): CompiledTemplate {\n\t\tif (isObjectInput(template)) {\n\t\t\tconst children: Record<string, CompiledTemplate> = {};\n\t\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\t\tchildren[key] = this.compile(value);\n\t\t\t}\n\t\t\treturn CompiledTemplate.fromObject(children, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn CompiledTemplate.fromLiteral(template, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tconst ast = this.getCachedAst(template);\n\t\tconst options: CompiledTemplateOptions = {\n\t\t\thelpers: this.helpers,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t};\n\t\treturn CompiledTemplate.fromTemplate(ast, template, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes a template against a JSON Schema v7 describing\n\t * the available context.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is analyzed recursively and the\n\t * `outputSchema` reflects the object structure with resolved types.\n\t *\n\t * @param template - The template to analyze\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param identifierSchemas - (optional) Schemas by identifier `{ [id]: JSONSchema7 }`\n\t */\n\tanalyze(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7,\n\t\tidentifierSchemas?: Record<number, JSONSchema7>,\n\t): AnalysisResult {\n\t\tif (isObjectInput(template)) {\n\t\t\treturn aggregateObjectAnalysis(Object.keys(template), (key) =>\n\t\t\t\tthis.analyze(\n\t\t\t\t\ttemplate[key] as TemplateInput,\n\t\t\t\t\tinputSchema,\n\t\t\t\t\tidentifierSchemas,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn {\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}\n\t\tconst ast = this.getCachedAst(template);\n\t\treturn analyzeFromAst(ast, template, inputSchema, {\n\t\t\tidentifierSchemas,\n\t\t\thelpers: this.helpers,\n\t\t});\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────────\n\n\t/**\n\t * Validates a template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param template - The template to validate\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param identifierSchemas - (optional) Schemas by identifier\n\t */\n\tvalidate(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7,\n\t\tidentifierSchemas?: Record<number, JSONSchema7>,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(template, inputSchema, identifierSchemas);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Syntax Validation ───────────────────────────────────────────────────\n\n\t/**\n\t * Checks only that the template syntax is valid (parsing).\n\t * Does not require a schema — useful for quick feedback in an editor.\n\t *\n\t * For objects, recursively checks each property.\n\t *\n\t * @param template - The template to validate\n\t * @returns `true` if the template is syntactically correct\n\t */\n\tisValidSyntax(template: TemplateInput): boolean {\n\t\tif (isObjectInput(template)) {\n\t\t\treturn Object.values(template).every((v) => this.isValidSyntax(v));\n\t\t}\n\t\tif (isLiteralInput(template)) return true;\n\t\ttry {\n\t\t\tthis.getCachedAst(template);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// ─── Execution ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Executes a template with the provided data.\n\t *\n\t * Accepts a `TemplateInput`: string, number, boolean, null, or object.\n\t * For objects, each property is executed recursively and an object with\n\t * resolved values is returned.\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param template - The template to execute\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, identifierSchemas)\n\t * @returns The execution result\n\t */\n\texecute(\n\t\ttemplate: TemplateInput,\n\t\tdata: Record<string, unknown>,\n\t\toptions?: ExecuteOptions,\n\t): unknown {\n\t\t// ── Object template → recursive execution ────────────────────────────\n\t\tif (isObjectInput(template)) {\n\t\t\tconst result: Record<string, unknown> = {};\n\t\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\t\tresult[key] = this.execute(value, data, options);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\t// ── Passthrough for literal values ────────────────────────────────────\n\t\tif (isLiteralInput(template)) return template;\n\n\t\t// ── Parse once ───────────────────────────────────────────────────────\n\t\tconst ast = this.getCachedAst(template);\n\n\t\t// ── Pre-execution static validation ──────────────────────────────────\n\t\tif (options?.schema) {\n\t\t\tconst analysis = analyzeFromAst(ast, template, options.schema, {\n\t\t\t\tidentifierSchemas: options.identifierSchemas,\n\t\t\t\thelpers: this.helpers,\n\t\t\t});\n\t\t\tif (!analysis.valid) {\n\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t}\n\t\t}\n\n\t\t// ── Execution ────────────────────────────────────────────────────────\n\t\treturn executeFromAst(ast, template, data, {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t});\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────────\n\n\t/**\n\t * Analyzes a template and, if valid, executes it with the provided data.\n\t * Returns both the analysis result and the executed value.\n\t *\n\t * For objects, each property is analyzed and executed recursively.\n\t * The entire object is considered invalid if at least one property is.\n\t *\n\t * @param template - The template\n\t * @param inputSchema - JSON Schema v7 describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - (optional) Options for template identifiers\n\t * @returns An object `{ analysis, value }` where `value` is `undefined`\n\t * if analysis failed.\n\t */\n\tanalyzeAndExecute(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7,\n\t\tdata: Record<string, unknown>,\n\t\toptions?: AnalyzeAndExecuteOptions,\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\tif (isObjectInput(template)) {\n\t\t\treturn aggregateObjectAnalysisAndExecution(Object.keys(template), (key) =>\n\t\t\t\tthis.analyzeAndExecute(\n\t\t\t\t\ttemplate[key] as TemplateInput,\n\t\t\t\t\tinputSchema,\n\t\t\t\t\tdata,\n\t\t\t\t\toptions,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn {\n\t\t\t\tanalysis: {\n\t\t\t\t\tvalid: true,\n\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t\t\t},\n\t\t\t\tvalue: template,\n\t\t\t};\n\t\t}\n\n\t\tconst ast = this.getCachedAst(template);\n\t\tconst analysis = analyzeFromAst(ast, template, inputSchema, {\n\t\t\tidentifierSchemas: options?.identifierSchemas,\n\t\t\thelpers: this.helpers,\n\t\t});\n\n\t\tif (!analysis.valid) {\n\t\t\treturn { analysis, value: undefined };\n\t\t}\n\n\t\tconst value = executeFromAst(ast, template, data, {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t});\n\t\treturn { analysis, value };\n\t}\n\n\t// ─── Custom Helper Management ──────────────────────────────────────────\n\n\t/**\n\t * Registers a custom helper on this engine instance.\n\t *\n\t * The helper is available for both execution (via Handlebars) and\n\t * static analysis (via its declared `returnType`).\n\t *\n\t * @param name - Helper name (e.g. `\"uppercase\"`)\n\t * @param definition - Helper definition (implementation + return type)\n\t * @returns `this` to allow chaining\n\t */\n\tregisterHelper(name: string, definition: HelperDefinition): this {\n\t\tthis.helpers.set(name, definition);\n\t\tthis.hbs.registerHelper(name, definition.fn);\n\n\t\t// Invalidate the compilation cache because helpers have changed\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Removes a custom helper from this engine instance.\n\t *\n\t * @param name - Name of the helper to remove\n\t * @returns `this` to allow chaining\n\t */\n\tunregisterHelper(name: string): this {\n\t\tthis.helpers.delete(name);\n\t\tthis.hbs.unregisterHelper(name);\n\n\t\t// Invalidate the compilation cache\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Checks whether a helper is registered on this instance.\n\t *\n\t * @param name - Helper name\n\t * @returns `true` if the helper is registered\n\t */\n\thasHelper(name: string): boolean {\n\t\treturn this.helpers.has(name);\n\t}\n\n\t// ─── Cache Management ──────────────────────────────────────────────────\n\n\t/**\n\t * Clears all internal caches (AST + compilation).\n\t *\n\t * Useful after a configuration change or to free memory.\n\t */\n\tclearCaches(): void {\n\t\tthis.astCache.clear();\n\t\tthis.compilationCache.clear();\n\t}\n\n\t// ─── Internals ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Retrieves the AST of a template from the cache, or parses and caches it.\n\t */\n\tprivate getCachedAst(template: string): hbs.AST.Program {\n\t\tlet ast = this.astCache.get(template);\n\t\tif (!ast) {\n\t\t\tast = parse(template);\n\t\t\tthis.astCache.set(template, ast);\n\t\t}\n\t\treturn ast;\n\t}\n}\n",
6
+ "import type { HelperDefinition } from \"../types.ts\";\n\n// ─── HelperFactory ───────────────────────────────────────────────────────────\n// Abstract base class that enforces a consistent pattern for creating,\n// registering, and managing groups of related helpers.\n//\n// Every helper factory (MathHelpers, LogicalHelpers, …) must extend this class\n// and implement the `buildDefinitions()` method to populate its helpers.\n//\n// The base class provides:\n// - Lazy-cached definitions, helper names, and name set\n// - `register()` / `unregister()` for any `HelperRegistry`\n// - `getHelperNames()` / `isHelper()` for introspection\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Minimal registration interface — avoids tight coupling with Typebars */\nexport interface HelperRegistry {\n\tregisterHelper(name: string, definition: HelperDefinition): unknown;\n\tunregisterHelper(name: string): unknown;\n}\n\n// ─── Abstract Base Class ─────────────────────────────────────────────────────\n\nexport abstract class HelperFactory {\n\t// ── Lazy caches (populated on first access) ──────────────────────────\n\tprivate _definitions: Map<string, HelperDefinition> | null = null;\n\tprivate _helperNames: readonly string[] | null = null;\n\tprivate _helperNamesSet: ReadonlySet<string> | null = null;\n\n\t// ── Abstract method — must be implemented by each factory ────────────\n\n\t/**\n\t * Populates the `defs` map with all helper definitions.\n\t *\n\t * Subclasses implement this method to register their helpers:\n\t * ```\n\t * protected buildDefinitions(defs: Map<string, HelperDefinition>): void {\n\t * defs.set(\"myHelper\", {\n\t * fn: (a: unknown) => String(a).toUpperCase(),\n\t * params: [{ name: \"a\", type: { type: \"string\" } }],\n\t * returnType: { type: \"string\" },\n\t * description: \"Converts to uppercase\",\n\t * });\n\t * }\n\t * ```\n\t *\n\t * @param defs - The map to populate with `[name, HelperDefinition]` entries\n\t */\n\tprotected abstract buildDefinitions(\n\t\tdefs: Map<string, HelperDefinition>,\n\t): void;\n\n\t// ── Public API ───────────────────────────────────────────────────────\n\n\t/**\n\t * Returns all definitions as a `Map<name, HelperDefinition>`.\n\t * The map is lazily built and cached on first access.\n\t */\n\tgetDefinitions(): Map<string, HelperDefinition> {\n\t\tif (!this._definitions) {\n\t\t\tthis._definitions = new Map();\n\t\t\tthis.buildDefinitions(this._definitions);\n\t\t}\n\t\treturn this._definitions;\n\t}\n\n\t/**\n\t * Returns the list of all helper names provided by this factory.\n\t */\n\tgetHelperNames(): readonly string[] {\n\t\tif (!this._helperNames) {\n\t\t\tthis._helperNames = [...this.getDefinitions().keys()];\n\t\t}\n\t\treturn this._helperNames;\n\t}\n\n\t/**\n\t * Checks whether a helper name belongs to this factory.\n\t *\n\t * @param name - The helper name to check\n\t */\n\tisHelper(name: string): boolean {\n\t\tif (!this._helperNamesSet) {\n\t\t\tthis._helperNamesSet = new Set(this.getHelperNames());\n\t\t}\n\t\treturn this._helperNamesSet.has(name);\n\t}\n\n\t/**\n\t * Registers all helpers from this factory on the given registry.\n\t *\n\t * @param registry - The engine or target registry\n\t */\n\tregister(registry: HelperRegistry): void {\n\t\tfor (const [name, def] of this.getDefinitions()) {\n\t\t\tregistry.registerHelper(name, def);\n\t\t}\n\t}\n\n\t/**\n\t * Removes all helpers from this factory from the given registry.\n\t *\n\t * @param registry - The engine or target registry\n\t */\n\tunregister(registry: HelperRegistry): void {\n\t\tfor (const name of this.getHelperNames()) {\n\t\t\tregistry.unregisterHelper(name);\n\t\t}\n\t}\n}\n",
7
+ "// ─── Shared Helper Utilities ─────────────────────────────────────────────────\n// Common utilities used across helper packs (MathHelpers, LogicalHelpers, …).\n\n/**\n * Converts an unknown value to a number.\n *\n * Conversion rules:\n * - `number` → returned as-is\n * - `string` → parsed via `Number()`; returns `fallback` if result is `NaN`\n * - `boolean` → `true` → `1`, `false` → `0`\n * - anything else → `fallback`\n *\n * The `fallback` parameter lets each consumer choose the right semantics:\n * - **Math helpers** pass `0` so that invalid inputs silently become zero\n * (e.g. `add(\"abc\", 5)` → `5`).\n * - **Logical helpers** pass `NaN` (the default) so that invalid comparisons\n * evaluate to `false` (e.g. `lt(\"abc\", 5)` → `false`).\n *\n * @param value - The value to convert\n * @param fallback - Value returned when conversion fails (default: `NaN`)\n */\nexport function toNumber(value: unknown, fallback: number = NaN): number {\n\tif (typeof value === \"number\") return value;\n\tif (typeof value === \"string\") {\n\t\tconst n = Number(value);\n\t\treturn Number.isNaN(n) ? fallback : n;\n\t}\n\tif (typeof value === \"boolean\") return value ? 1 : 0;\n\treturn fallback;\n}\n",
8
+ "import type { HelperDefinition } from \"../types.ts\";\nimport { HelperFactory } from \"./helper-factory.ts\";\nimport { toNumber } from \"./utils.ts\";\n\n// ─── LogicalHelpers ──────────────────────────────────────────────────────────\n// Aggregates all logical / comparison helpers for the template engine.\n//\n// Provides two kinds of helpers:\n//\n// 1. **Named helpers** — one helper per operation (`eq`, `lt`, `not`, …)\n// Usage: `{{#if (eq status \"active\")}}`, `{{#if (lt price 100)}}`\n//\n// 2. **Generic `compare` helper** — single helper with the operator as a param\n// Usage: `{{#if (compare a \"<\" b)}}`, `{{#if (compare name \"==\" \"Alice\")}}`\n//\n// ─── Registration ────────────────────────────────────────────────────────────\n// LogicalHelpers are automatically pre-registered by the `Typebars` constructor.\n// They can also be registered manually on any object implementing\n// `HelperRegistry`:\n//\n// const factory = new LogicalHelpers();\n// factory.register(engine); // registers all helpers\n// factory.unregister(engine); // removes all helpers\n//\n// ─── Supported operators (generic `compare` helper) ──────────────────────────\n// == Loose equality\n// === Strict equality\n// != Loose inequality\n// !== Strict inequality\n// < Less than\n// <= Less than or equal\n// > Greater than\n// >= Greater than or equal\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Operators supported by the generic `compare` helper */\ntype CompareOperator = \"==\" | \"===\" | \"!=\" | \"!==\" | \"<\" | \"<=\" | \">\" | \">=\";\n\nconst SUPPORTED_OPERATORS = new Set<string>([\n\t\"==\",\n\t\"===\",\n\t\"!=\",\n\t\"!==\",\n\t\"<\",\n\t\"<=\",\n\t\">\",\n\t\">=\",\n]);\n\n// ─── Internal utilities ─────────────────────────────────────────────────────\n\n/**\n * Applies a comparison operator to two operands.\n */\nfunction applyOperator(a: unknown, op: CompareOperator, b: unknown): boolean {\n\tswitch (op) {\n\t\tcase \"==\":\n\t\t\t// biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality\n\t\t\treturn a == b;\n\t\tcase \"===\":\n\t\t\treturn a === b;\n\t\tcase \"!=\":\n\t\t\t// biome-ignore lint/suspicious/noDoubleEquals: intentional loose inequality\n\t\t\treturn a != b;\n\t\tcase \"!==\":\n\t\t\treturn a !== b;\n\t\tcase \"<\":\n\t\t\treturn toNumber(a) < toNumber(b);\n\t\tcase \"<=\":\n\t\t\treturn toNumber(a) <= toNumber(b);\n\t\tcase \">\":\n\t\t\treturn toNumber(a) > toNumber(b);\n\t\tcase \">=\":\n\t\t\treturn toNumber(a) >= toNumber(b);\n\t}\n}\n\n/**\n * Checks whether a value is a Handlebars options object.\n * Handlebars always passes an options object as the last argument to helpers.\n */\nfunction isHandlebarsOptions(value: unknown): boolean {\n\treturn (\n\t\tvalue !== null &&\n\t\ttypeof value === \"object\" &&\n\t\t\"hash\" in (value as Record<string, unknown>) &&\n\t\t\"name\" in (value as Record<string, unknown>)\n\t);\n}\n\n// ─── Main class ─────────────────────────────────────────────────────────────\n\nexport class LogicalHelpers extends HelperFactory {\n\t// ─── buildDefinitions (required by HelperFactory) ──────────────────\n\n\tprotected buildDefinitions(defs: Map<string, HelperDefinition>): void {\n\t\tthis.registerEquality(defs);\n\t\tthis.registerComparison(defs);\n\t\tthis.registerLogicalOperators(defs);\n\t\tthis.registerCollectionHelpers(defs);\n\t\tthis.registerGenericCompare(defs);\n\t}\n\n\t// ── Equality helpers ─────────────────────────────────────────────\n\n\t/** Registers eq, ne / neq */\n\tprivate registerEquality(defs: Map<string, HelperDefinition>): void {\n\t\t// eq — Strict equality: {{#if (eq a b)}}\n\t\tdefs.set(\"eq\", {\n\t\t\tfn: (a: unknown, b: unknown) => a === b,\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", description: \"Left value\" },\n\t\t\t\t{ name: \"b\", description: \"Right value\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription: \"Returns true if a is strictly equal to b: {{#if (eq a b)}}\",\n\t\t});\n\n\t\t// ne / neq — Strict inequality: {{#if (ne a b)}}\n\t\tconst neDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => a !== b,\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", description: \"Left value\" },\n\t\t\t\t{ name: \"b\", description: \"Right value\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription:\n\t\t\t\t\"Returns true if a is not strictly equal to b: {{#if (ne a b)}}\",\n\t\t};\n\t\tdefs.set(\"ne\", neDef);\n\t\tdefs.set(\"neq\", neDef);\n\t}\n\n\t// ── Comparison helpers ───────────────────────────────────────────\n\n\t/** Registers lt, lte / le, gt, gte / ge */\n\tprivate registerComparison(defs: Map<string, HelperDefinition>): void {\n\t\t// lt — Less than: {{#if (lt a b)}}\n\t\tdefs.set(\"lt\", {\n\t\t\tfn: (a: unknown, b: unknown) => toNumber(a) < toNumber(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Left operand\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Right operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription: \"Returns true if a < b: {{#if (lt a b)}}\",\n\t\t});\n\n\t\t// lte / le — Less than or equal: {{#if (lte a b)}}\n\t\tconst lteDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => toNumber(a) <= toNumber(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Left operand\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Right operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription: \"Returns true if a <= b: {{#if (lte a b)}}\",\n\t\t};\n\t\tdefs.set(\"lte\", lteDef);\n\t\tdefs.set(\"le\", lteDef);\n\n\t\t// gt — Greater than: {{#if (gt a b)}}\n\t\tdefs.set(\"gt\", {\n\t\t\tfn: (a: unknown, b: unknown) => toNumber(a) > toNumber(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Left operand\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Right operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription: \"Returns true if a > b: {{#if (gt a b)}}\",\n\t\t});\n\n\t\t// gte / ge — Greater than or equal: {{#if (gte a b)}}\n\t\tconst gteDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => toNumber(a) >= toNumber(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Left operand\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Right operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription: \"Returns true if a >= b: {{#if (gte a b)}}\",\n\t\t};\n\t\tdefs.set(\"gte\", gteDef);\n\t\tdefs.set(\"ge\", gteDef);\n\t}\n\n\t// ── Logical operators ────────────────────────────────────────────\n\n\t/** Registers not, and, or */\n\tprivate registerLogicalOperators(defs: Map<string, HelperDefinition>): void {\n\t\t// not — Logical negation: {{#if (not active)}}\n\t\tdefs.set(\"not\", {\n\t\t\tfn: (value: unknown) => !value,\n\t\t\tparams: [{ name: \"value\", description: \"Value to negate\" }],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription: \"Returns true if the value is falsy: {{#if (not active)}}\",\n\t\t});\n\n\t\t// and — Logical AND: {{#if (and a b)}}\n\t\tdefs.set(\"and\", {\n\t\t\tfn: (a: unknown, b: unknown) => !!a && !!b,\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", description: \"First condition\" },\n\t\t\t\t{ name: \"b\", description: \"Second condition\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription: \"Returns true if both values are truthy: {{#if (and a b)}}\",\n\t\t});\n\n\t\t// or — Logical OR: {{#if (or a b)}}\n\t\tdefs.set(\"or\", {\n\t\t\tfn: (a: unknown, b: unknown) => !!a || !!b,\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", description: \"First condition\" },\n\t\t\t\t{ name: \"b\", description: \"Second condition\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription:\n\t\t\t\t\"Returns true if at least one value is truthy: {{#if (or a b)}}\",\n\t\t});\n\t}\n\n\t// ── Collection / String helpers ──────────────────────────────────\n\n\t/** Registers contains, in */\n\tprivate registerCollectionHelpers(defs: Map<string, HelperDefinition>): void {\n\t\t// contains — Checks if a string contains a substring or an array contains an element\n\t\t// Usage: {{#if (contains name \"ali\")}} or {{#if (contains tags \"admin\")}}\n\t\tdefs.set(\"contains\", {\n\t\t\tfn: (haystack: unknown, needle: unknown) => {\n\t\t\t\tif (typeof haystack === \"string\") {\n\t\t\t\t\treturn haystack.includes(String(needle));\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(haystack)) {\n\t\t\t\t\treturn haystack.includes(needle);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"haystack\",\n\t\t\t\t\tdescription: \"String or array to search in\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"needle\",\n\t\t\t\t\tdescription: \"Value to search for\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription:\n\t\t\t\t'Checks if a string contains a substring or an array contains an element: {{#if (contains name \"ali\")}}',\n\t\t});\n\n\t\t// in — Checks if a value is one of the provided options (variadic)\n\t\t// Usage: {{#if (in status \"active\" \"pending\" \"draft\")}}\n\t\tdefs.set(\"in\", {\n\t\t\tfn: (...args: unknown[]) => {\n\t\t\t\t// Handlebars always passes an options object as the last argument.\n\t\t\t\t// We need to exclude it from the candidate list.\n\t\t\t\tif (args.length < 2) return false;\n\n\t\t\t\tconst value = args[0];\n\t\t\t\t// Filter out the trailing Handlebars options object\n\t\t\t\tconst candidates = args.slice(1).filter((a) => !isHandlebarsOptions(a));\n\n\t\t\t\treturn candidates.some((c) => c === value);\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\tdescription: \"Value to look for\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"candidates\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'One or more candidate values (variadic): {{#if (in status \"active\" \"pending\")}}',\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription:\n\t\t\t\t'Checks if a value is one of the provided options: {{#if (in status \"active\" \"pending\" \"draft\")}}',\n\t\t});\n\t}\n\n\t// ── Generic helper ───────────────────────────────────────────────\n\n\t/** Registers the generic `compare` helper with operator as a parameter */\n\tprivate registerGenericCompare(defs: Map<string, HelperDefinition>): void {\n\t\t// Usage: {{#if (compare a \"<\" b)}}, {{#if (compare name \"===\" \"Alice\")}}\n\t\tdefs.set(\"compare\", {\n\t\t\tfn: (a: unknown, operator: unknown, b: unknown) => {\n\t\t\t\tconst op = String(operator);\n\t\t\t\tif (!SUPPORTED_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`[compare helper] Unknown operator \"${op}\". ` +\n\t\t\t\t\t\t\t`Supported: ${[...SUPPORTED_OPERATORS].join(\", \")} `,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn applyOperator(a, op as CompareOperator, b);\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", description: \"Left operand\" },\n\t\t\t\t{\n\t\t\t\t\tname: \"operator\",\n\t\t\t\t\ttype: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\tenum: [\"==\", \"===\", \"!=\", \"!==\", \"<\", \"<=\", \">\", \">=\"],\n\t\t\t\t\t},\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'Comparison operator: \"==\", \"===\", \"!=\", \"!==\", \"<\", \"<=\", \">\", \">=\"',\n\t\t\t\t},\n\t\t\t\t{ name: \"b\", description: \"Right operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"boolean\" },\n\t\t\tdescription:\n\t\t\t\t'Generic comparison helper with operator as parameter: {{#if (compare a \"<\" b)}}. ' +\n\t\t\t\t\"Supported operators: ==, ===, !=, !==, <, <=, >, >=\",\n\t\t});\n\t}\n}\n",
9
+ "import type { HelperDefinition } from \"../types.ts\";\nimport { HelperFactory } from \"./helper-factory.ts\";\nimport { toNumber } from \"./utils.ts\";\n\n// ─── MathHelpers ─────────────────────────────────────────────────────────────\n// Aggregates all math-related helpers for the template engine.\n//\n// Provides two kinds of helpers:\n//\n// 1. **Named helpers** — one helper per operation (`add`, `subtract`, `divide`, …)\n// Usage: `{{ add a b }}`, `{{ abs value }}`, `{{ round value 2 }}`\n//\n// 2. **Generic `math` helper** — single helper with the operator as a parameter\n// Usage: `{{ math a \"+\" b }}`, `{{ math a \"/\" b }}`, `{{ math a \"**\" b }}`\n//\n// ─── Registration ────────────────────────────────────────────────────────────\n// MathHelpers are automatically pre-registered by the `Typebars` constructor.\n// They can also be registered manually on any object implementing\n// `HelperRegistry`:\n//\n// const factory = new MathHelpers();\n// factory.register(engine); // registers all helpers\n// factory.unregister(engine); // removes all helpers\n//\n// ─── Supported operators (generic `math` helper) ─────────────────────────────\n// + Addition\n// - Subtraction\n// * Multiplication\n// / Division\n// % Modulo\n// ** Exponentiation\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Operators supported by the generic `math` helper */\ntype MathOperator = \"+\" | \"-\" | \"*\" | \"/\" | \"%\" | \"**\";\n\nconst SUPPORTED_OPERATORS = new Set<string>([\"+\", \"-\", \"*\", \"/\", \"%\", \"**\"]);\n\n// ─── Internal utilities ─────────────────────────────────────────────────────\n\n/** Converts a value to a number with a fallback of `0` for math operations. */\nconst num = (value: unknown): number => toNumber(value, 0);\n\n/**\n * Applies a binary operator to two operands.\n */\nfunction applyOperator(a: number, op: MathOperator, b: number): number {\n\tswitch (op) {\n\t\tcase \"+\":\n\t\t\treturn a + b;\n\t\tcase \"-\":\n\t\t\treturn a - b;\n\t\tcase \"*\":\n\t\t\treturn a * b;\n\t\tcase \"/\":\n\t\t\treturn b === 0 ? Infinity : a / b;\n\t\tcase \"%\":\n\t\t\treturn b === 0 ? NaN : a % b;\n\t\tcase \"**\":\n\t\t\treturn a ** b;\n\t}\n}\n\n// ─── Main class ─────────────────────────────────────────────────────────────\n\nexport class MathHelpers extends HelperFactory {\n\t// ─── buildDefinitions (required by HelperFactory) ──────────────────\n\n\tprotected buildDefinitions(defs: Map<string, HelperDefinition>): void {\n\t\tthis.registerBinaryOperators(defs);\n\t\tthis.registerUnaryFunctions(defs);\n\t\tthis.registerMinMax(defs);\n\t\tthis.registerGenericMath(defs);\n\t}\n\n\t// ── Binary operators ─────────────────────────────────────────────\n\n\t/** Registers add, subtract/sub, multiply/mul, divide/div, modulo/mod, pow */\n\tprivate registerBinaryOperators(defs: Map<string, HelperDefinition>): void {\n\t\t// add — Addition : {{ add a b }}\n\t\tconst addDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => num(a) + num(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First operand\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Adds two numbers: {{ add a b }}\",\n\t\t};\n\t\tdefs.set(\"add\", addDef);\n\n\t\t// subtract / sub — Subtraction: {{ subtract a b }} or {{ sub a b }}\n\t\tconst subtractDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => num(a) - num(b),\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"a\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"Value to subtract from\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"b\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"Value to subtract\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Subtracts b from a: {{ subtract a b }}\",\n\t\t};\n\t\tdefs.set(\"subtract\", subtractDef);\n\t\tdefs.set(\"sub\", subtractDef);\n\n\t\t// multiply / mul — Multiplication: {{ multiply a b }} or {{ mul a b }}\n\t\tconst multiplyDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => num(a) * num(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First factor\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second factor\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Multiplies two numbers: {{ multiply a b }}\",\n\t\t};\n\t\tdefs.set(\"multiply\", multiplyDef);\n\t\tdefs.set(\"mul\", multiplyDef);\n\n\t\t// divide / div — Division: {{ divide a b }} or {{ div a b }}\n\t\tconst divideDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => {\n\t\t\t\tconst divisor = num(b);\n\t\t\t\treturn divisor === 0 ? Infinity : num(a) / divisor;\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Dividend\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Divisor\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t\"Divides a by b: {{ divide a b }}. Returns Infinity if b is 0.\",\n\t\t};\n\t\tdefs.set(\"divide\", divideDef);\n\t\tdefs.set(\"div\", divideDef);\n\n\t\t// modulo / mod — Modulo: {{ modulo a b }} or {{ mod a b }}\n\t\tconst moduloDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => {\n\t\t\t\tconst divisor = num(b);\n\t\t\t\treturn divisor === 0 ? NaN : num(a) % divisor;\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Dividend\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Divisor\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the remainder of a divided by b: {{ modulo a b }}\",\n\t\t};\n\t\tdefs.set(\"modulo\", moduloDef);\n\t\tdefs.set(\"mod\", moduloDef);\n\n\t\t// pow — Exponentiation : {{ pow base exponent }}\n\t\tdefs.set(\"pow\", {\n\t\t\tfn: (base: unknown, exponent: unknown) => num(base) ** num(exponent),\n\t\t\tparams: [\n\t\t\t\t{ name: \"base\", type: { type: \"number\" }, description: \"The base\" },\n\t\t\t\t{\n\t\t\t\t\tname: \"exponent\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The exponent\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t\"Raises base to the power of exponent: {{ pow base exponent }}\",\n\t\t});\n\t}\n\n\t// ── Unary functions ──────────────────────────────────────────────\n\n\t/** Registers abs, ceil, floor, round, sqrt */\n\tprivate registerUnaryFunctions(defs: Map<string, HelperDefinition>): void {\n\t\t// abs — Absolute value: {{ abs value }}\n\t\tdefs.set(\"abs\", {\n\t\t\tfn: (value: unknown) => Math.abs(num(value)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"value\", type: { type: \"number\" }, description: \"The number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the absolute value: {{ abs value }}\",\n\t\t});\n\n\t\t// ceil — Round up: {{ ceil value }}\n\t\tdefs.set(\"ceil\", {\n\t\t\tfn: (value: unknown) => Math.ceil(num(value)),\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The number to round up\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Rounds up to the nearest integer: {{ ceil value }}\",\n\t\t});\n\n\t\t// floor — Round down: {{ floor value }}\n\t\tdefs.set(\"floor\", {\n\t\t\tfn: (value: unknown) => Math.floor(num(value)),\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The number to round down\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Rounds down to the nearest integer: {{ floor value }}\",\n\t\t});\n\n\t\t// round — Rounding: {{ round value }} or {{ round value precision }}\n\t\t// With precision: {{ round 3.14159 2 }} → 3.14\n\t\tdefs.set(\"round\", {\n\t\t\tfn: (value: unknown, precision: unknown) => {\n\t\t\t\tconst n = num(value);\n\t\t\t\t// If precision is a Handlebars options object (not a number),\n\t\t\t\t// it means the second parameter was not provided.\n\t\t\t\tif (\n\t\t\t\t\tprecision === undefined ||\n\t\t\t\t\tprecision === null ||\n\t\t\t\t\ttypeof precision === \"object\"\n\t\t\t\t) {\n\t\t\t\t\treturn Math.round(n);\n\t\t\t\t}\n\t\t\t\tconst p = num(precision);\n\t\t\t\tconst factor = 10 ** p;\n\t\t\t\treturn Math.round(n * factor) / factor;\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The number to round\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"precision\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"Number of decimal places (default: 0)\",\n\t\t\t\t\toptional: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t\"Rounds to the nearest integer or to a given precision: {{ round value }} or {{ round value 2 }}\",\n\t\t});\n\n\t\t// sqrt — Square root: {{ sqrt value }}\n\t\tdefs.set(\"sqrt\", {\n\t\t\tfn: (value: unknown) => Math.sqrt(num(value)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"value\", type: { type: \"number\" }, description: \"The number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the square root: {{ sqrt value }}\",\n\t\t});\n\t}\n\n\t// ── Min / Max ────────────────────────────────────────────────────\n\n\t/** Registers min and max */\n\tprivate registerMinMax(defs: Map<string, HelperDefinition>): void {\n\t\t// min — Minimum : {{ min a b }}\n\t\tdefs.set(\"min\", {\n\t\t\tfn: (a: unknown, b: unknown) => Math.min(num(a), num(b)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First number\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the smaller of two numbers: {{ min a b }}\",\n\t\t});\n\n\t\t// max — Maximum : {{ max a b }}\n\t\tdefs.set(\"max\", {\n\t\t\tfn: (a: unknown, b: unknown) => Math.max(num(a), num(b)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First number\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the larger of two numbers: {{ max a b }}\",\n\t\t});\n\t}\n\n\t// ── Generic helper ───────────────────────────────────────────────\n\n\t/** Registers the generic `math` helper with operator as a parameter */\n\tprivate registerGenericMath(defs: Map<string, HelperDefinition>): void {\n\t\t// Usage : {{ math a \"+\" b }}, {{ math a \"/\" b }}, {{ math a \"**\" b }}\n\t\tdefs.set(\"math\", {\n\t\t\tfn: (a: unknown, operator: unknown, b: unknown) => {\n\t\t\t\tconst op = String(operator);\n\t\t\t\tif (!SUPPORTED_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`[math helper] Unknown operator \"${op}\". ` +\n\t\t\t\t\t\t\t`Supported: ${[...SUPPORTED_OPERATORS].join(\", \")} `,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn applyOperator(num(a), op as MathOperator, num(b));\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Left operand\" },\n\t\t\t\t{\n\t\t\t\t\tname: \"operator\",\n\t\t\t\t\ttype: { type: \"string\", enum: [\"+\", \"-\", \"*\", \"/\", \"%\", \"**\"] },\n\t\t\t\t\tdescription: 'Arithmetic operator: \"+\", \"-\", \"*\", \"/\", \"%\", \"**\"',\n\t\t\t\t},\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Right operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t'Generic math helper with operator as parameter: {{ math a \"+\" b }}, {{ math a \"/\" b }}. ' +\n\t\t\t\t\"Supported operators: +, -, *, /, %, **\",\n\t\t});\n\t}\n}\n"
10
+ ],
11
+ "mappings": "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",
12
+ "debugId": "D5BDDDBE699F089564756E2164756E21",
13
+ "names": []
14
+ }
@@ -0,0 +1,5 @@
1
+ import{M}from"./chunk-4zv02svp.js";function G(A,z){if(!A.$ref)return A;let w=A.$ref,j=w.match(/^#\/(definitions|\$defs)\/(.+)$/);if(!j)throw Error(`Unsupported $ref format: "${w}". Only internal #/definitions/ references are supported.`);let B=j[1],D=j[2]??"",F=B==="definitions"?z.definitions:z.$defs;if(!F||!(D in F))throw Error(`Cannot resolve $ref "${w}": definition "${D}" not found.`);let H=F[D];if(!H||typeof H==="boolean")throw Error(`Cannot resolve $ref "${w}": definition "${D}" not found.`);return G(H,z)}function L(A,z,w){let j=G(A,w);if(j.properties&&z in j.properties){let H=j.properties[z];if(H&&typeof H!=="boolean")return G(H,w);if(H===!0)return{}}if(j.additionalProperties!==void 0&&j.additionalProperties!==!1){if(j.additionalProperties===!0)return{};return G(j.additionalProperties,w)}let B=j.type;if((B==="array"||Array.isArray(B)&&B.includes("array"))&&z==="length")return{type:"integer"};let F=N(j,z,w);if(F)return F;return}function N(A,z,w){if(A.allOf){let j=A.allOf.filter((B)=>typeof B!=="boolean").map((B)=>L(B,z,w)).filter((B)=>B!==void 0);if(j.length===1)return j[0];if(j.length>1)return{allOf:j}}for(let j of["anyOf","oneOf"]){if(!A[j])continue;let B=A[j].filter((D)=>typeof D!=="boolean").map((D)=>L(D,z,w)).filter((D)=>D!==void 0);if(B.length===1)return B[0];if(B.length>1)return{[j]:B}}return}function P(A,z){if(z.length===0)return G(A,A);let w=G(A,A),j=A;for(let B of z){let D=L(w,B,j);if(D===void 0)return;w=D}return w}function Q(A,z){let w=G(A,z),j=w.type;if(!(j==="array"||Array.isArray(j)&&j.includes("array"))&&w.items===void 0)return;if(w.items===void 0)return{};if(typeof w.items==="boolean")return{};if(Array.isArray(w.items)){let D=w.items.filter((F)=>typeof F!=="boolean").map((F)=>G(F,z));if(D.length===0)return{};return{oneOf:D}}return G(w.items,z)}function J(A){for(let z of["oneOf","anyOf"]){let w=A[z];if(w&&w.length===1){let j=w[0];if(j!==void 0&&typeof j!=="boolean")return J(j)}}if(A.allOf&&A.allOf.length===1){let z=A.allOf[0];if(z!==void 0&&typeof z!=="boolean")return J(z)}for(let z of["oneOf","anyOf"]){let w=A[z];if(w&&w.length>1){let j=[];for(let B of w){if(typeof B==="boolean")continue;if(!j.some((F)=>M(F,B)))j.push(J(B))}if(j.length===1)return j[0];return{...A,[z]:j}}}return A}
2
+ export{G as I,P as J,Q as K,J as L};
3
+
4
+ //# debugId=3010A16AF72C22DE64756E2164756E21
5
+ //# sourceMappingURL=chunk-8g0d6h85.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/schema-resolver.ts"],
4
+ "sourcesContent": [
5
+ "import type { JSONSchema7 } from \"json-schema\";\nimport { deepEqual } from \"./utils.ts\";\n\n// ─── JSON Schema Resolver ────────────────────────────────────────────────────\n// Utility for navigating a JSON Schema Draft v7 by following a property path\n// (e.g. [\"user\", \"address\", \"city\"]).\n//\n// Handles:\n// - `$ref` resolution (internal references #/definitions/...)\n// - Navigation through `properties`\n// - Navigation through `items` (array elements)\n// - Combinators `allOf`, `anyOf`, `oneOf` (searches each branch)\n// - `additionalProperties` when the property is not explicitly declared\n\n// ─── $ref Resolution ─────────────────────────────────────────────────────────\n// Only supports internal references in the format `#/definitions/Foo`\n// or `#/$defs/Foo` (JSON Schema Draft 2019+). Remote $refs (URLs) are\n// not supported — that is outside the scope of a template engine.\n\n/**\n * Recursively resolves `$ref` in a schema using the root schema as the\n * source of definitions.\n */\nexport function resolveRef(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 {\n\tif (!schema.$ref) return schema;\n\n\tconst ref = schema.$ref;\n\n\t// Expected format: #/definitions/Name or #/$defs/Name\n\tconst match = ref.match(/^#\\/(definitions|\\$defs)\\/(.+)$/);\n\tif (!match) {\n\t\tthrow new Error(\n\t\t\t`Unsupported $ref format: \"${ref}\". Only internal #/definitions/ references are supported.`,\n\t\t);\n\t}\n\n\tconst defsKey = match[1] as \"definitions\" | \"$defs\";\n\tconst name = match[2] ?? \"\";\n\n\tconst defs = defsKey === \"definitions\" ? root.definitions : root.$defs;\n\n\tif (!defs || !(name in defs)) {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve $ref \"${ref}\": definition \"${name}\" not found.`,\n\t\t);\n\t}\n\n\t// Recursive resolution in case the definition itself contains a $ref\n\tconst def = defs[name];\n\tif (!def || typeof def === \"boolean\") {\n\t\tthrow new Error(\n\t\t\t`Cannot resolve $ref \"${ref}\": definition \"${name}\" not found.`,\n\t\t);\n\t}\n\treturn resolveRef(def, root);\n}\n\n// ─── Single-Segment Path Navigation ─────────────────────────────────────────\n\n/**\n * Resolves a single path segment (a property name) within a schema.\n * Returns the corresponding sub-schema, or `undefined` if the path is invalid.\n *\n * @param schema - The current schema (already resolved, no $ref)\n * @param segment - The property name to resolve\n * @param root - The root schema (for resolving any internal $refs)\n */\nfunction resolveSegment(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// 1. Explicit properties\n\tif (resolved.properties && segment in resolved.properties) {\n\t\tconst prop = resolved.properties[segment];\n\t\tif (prop && typeof prop !== \"boolean\") return resolveRef(prop, root);\n\t\tif (prop === true) return {};\n\t}\n\n\t// 2. additionalProperties (when the property is not declared)\n\tif (\n\t\tresolved.additionalProperties !== undefined &&\n\t\tresolved.additionalProperties !== false\n\t) {\n\t\tif (resolved.additionalProperties === true) {\n\t\t\t// additionalProperties: true → type is unknown\n\t\t\treturn {};\n\t\t}\n\t\treturn resolveRef(resolved.additionalProperties, root);\n\t}\n\n\t// 3. Intrinsic array properties (e.g. `.length`)\n\tconst schemaType = resolved.type;\n\tconst isArray =\n\t\tschemaType === \"array\" ||\n\t\t(Array.isArray(schemaType) && schemaType.includes(\"array\"));\n\n\tif (isArray && segment === \"length\") {\n\t\treturn { type: \"integer\" };\n\t}\n\n\t// 4. Combinators — search within each branch\n\tconst combinatorResult = resolveInCombinators(resolved, segment, root);\n\tif (combinatorResult) return combinatorResult;\n\n\treturn undefined;\n}\n\n/**\n * Searches for a segment within `allOf`, `anyOf`, `oneOf` branches.\n * Returns the first matching sub-schema, or `undefined`.\n * For `allOf`, found results are merged into a single `allOf`.\n */\nfunction resolveInCombinators(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\t// allOf: the property can be defined in any branch, and all constraints\n\t// apply simultaneously.\n\tif (schema.allOf) {\n\t\tconst matches = schema.allOf\n\t\t\t.filter((b): b is JSONSchema7 => typeof b !== \"boolean\")\n\t\t\t.map((branch) => resolveSegment(branch, segment, root))\n\t\t\t.filter((s): s is JSONSchema7 => s !== undefined);\n\n\t\tif (matches.length === 1) return matches[0] as JSONSchema7;\n\t\tif (matches.length > 1) return { allOf: matches };\n\t}\n\n\t// anyOf / oneOf: the property can come from any branch.\n\tfor (const key of [\"anyOf\", \"oneOf\"] as const) {\n\t\tif (!schema[key]) continue;\n\t\tconst matches = schema[key]\n\t\t\t.filter((b): b is JSONSchema7 => typeof b !== \"boolean\")\n\t\t\t.map((branch) => resolveSegment(branch, segment, root))\n\t\t\t.filter((s): s is JSONSchema7 => s !== undefined);\n\n\t\tif (matches.length === 1) return matches[0] as JSONSchema7;\n\t\tif (matches.length > 1) return { [key]: matches };\n\t}\n\n\treturn undefined;\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Resolves a full path (e.g. [\"user\", \"address\", \"city\"]) within a JSON\n * Schema and returns the corresponding sub-schema.\n *\n * @param schema - The root schema describing the template context\n * @param path - Array of segments (property names)\n * @returns The sub-schema at the end of the path, or `undefined` if the path\n * cannot be resolved.\n *\n * @example\n * ```\n * const schema = {\n * type: \"object\",\n * properties: {\n * user: {\n * type: \"object\",\n * properties: {\n * name: { type: \"string\" }\n * }\n * }\n * }\n * };\n * resolveSchemaPath(schema, [\"user\", \"name\"]);\n * // → { type: \"string\" }\n * ```\n */\nexport function resolveSchemaPath(\n\tschema: JSONSchema7,\n\tpath: string[],\n): JSONSchema7 | undefined {\n\tif (path.length === 0) return resolveRef(schema, schema);\n\n\tlet current: JSONSchema7 = resolveRef(schema, schema);\n\tconst root = schema;\n\n\tfor (const segment of path) {\n\t\tconst next = resolveSegment(current, segment, root);\n\t\tif (next === undefined) return undefined;\n\t\tcurrent = next;\n\t}\n\n\treturn current;\n}\n\n/**\n * Resolves the item schema of an array.\n * If the schema is not of type `array` or has no `items`, returns `undefined`.\n *\n * @param schema - The array schema\n * @param root - The root schema (for resolving $refs)\n */\nexport function resolveArrayItems(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// Verify that it's actually an array\n\tconst schemaType = resolved.type;\n\tconst isArray =\n\t\tschemaType === \"array\" ||\n\t\t(Array.isArray(schemaType) && schemaType.includes(\"array\"));\n\n\tif (!isArray && resolved.items === undefined) {\n\t\treturn undefined;\n\t}\n\n\tif (resolved.items === undefined) {\n\t\t// array without items → element type is unknown\n\t\treturn {};\n\t}\n\n\t// items can be a boolean (true = anything, false = nothing)\n\tif (typeof resolved.items === \"boolean\") {\n\t\treturn {};\n\t}\n\n\t// items can be a single schema or a tuple (array of schemas).\n\t// For template loops, we handle the single-schema case.\n\tif (Array.isArray(resolved.items)) {\n\t\t// Tuple: create a oneOf of all possible types\n\t\tconst schemas = resolved.items\n\t\t\t.filter((item): item is JSONSchema7 => typeof item !== \"boolean\")\n\t\t\t.map((item) => resolveRef(item, root));\n\t\tif (schemas.length === 0) return {};\n\t\treturn { oneOf: schemas };\n\t}\n\n\treturn resolveRef(resolved.items, root);\n}\n\n/**\n * Simplifies an output schema to avoid unnecessarily complex constructs\n * (e.g. `oneOf` with a single element, duplicates, etc.).\n *\n * Uses `deepEqual` for deduplication — more robust and performant than\n * `JSON.stringify` (independent of key order, no intermediate string\n * allocations).\n */\nexport function simplifySchema(schema: JSONSchema7): JSONSchema7 {\n\t// oneOf / anyOf with a single element → unwrap\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = schema[key];\n\t\tif (arr && arr.length === 1) {\n\t\t\tconst first = arr[0];\n\t\t\tif (first !== undefined && typeof first !== \"boolean\")\n\t\t\t\treturn simplifySchema(first);\n\t\t}\n\t}\n\n\t// allOf with a single element → unwrap\n\tif (schema.allOf && schema.allOf.length === 1) {\n\t\tconst first = schema.allOf[0];\n\t\tif (first !== undefined && typeof first !== \"boolean\")\n\t\t\treturn simplifySchema(first);\n\t}\n\n\t// Deduplicate identical entries in oneOf/anyOf\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tconst arr = schema[key];\n\t\tif (arr && arr.length > 1) {\n\t\t\tconst unique: JSONSchema7[] = [];\n\t\t\tfor (const entry of arr) {\n\t\t\t\tif (typeof entry === \"boolean\") continue;\n\t\t\t\t// Use deepEqual instead of JSON.stringify for structural\n\t\t\t\t// comparison — more robust (key order independent) and\n\t\t\t\t// more performant (no string allocations).\n\t\t\t\tconst isDuplicate = unique.some((existing) =>\n\t\t\t\t\tdeepEqual(existing, entry),\n\t\t\t\t);\n\t\t\t\tif (!isDuplicate) {\n\t\t\t\t\tunique.push(simplifySchema(entry));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (unique.length === 1) return unique[0] as JSONSchema7;\n\t\t\treturn { ...schema, [key]: unique };\n\t\t}\n\t}\n\n\treturn schema;\n}\n"
6
+ ],
7
+ "mappings": "mCAuBO,SAAS,CAAU,CACzB,EACA,EACc,CACd,GAAI,CAAC,EAAO,KAAM,OAAO,EAEzB,IAAM,EAAM,EAAO,KAGb,EAAQ,EAAI,MAAM,iCAAiC,EACzD,GAAI,CAAC,EACJ,MAAU,MACT,6BAA6B,4DAC9B,EAGD,IAAM,EAAU,EAAM,GAChB,EAAO,EAAM,IAAM,GAEnB,EAAO,IAAY,cAAgB,EAAK,YAAc,EAAK,MAEjE,GAAI,CAAC,GAAQ,EAAE,KAAQ,GACtB,MAAU,MACT,wBAAwB,mBAAqB,eAC9C,EAID,IAAM,EAAM,EAAK,GACjB,GAAI,CAAC,GAAO,OAAO,IAAQ,UAC1B,MAAU,MACT,wBAAwB,mBAAqB,eAC9C,EAED,OAAO,EAAW,EAAK,CAAI,EAa5B,SAAS,CAAc,CACtB,EACA,EACA,EAC0B,CAC1B,IAAM,EAAW,EAAW,EAAQ,CAAI,EAGxC,GAAI,EAAS,YAAc,KAAW,EAAS,WAAY,CAC1D,IAAM,EAAO,EAAS,WAAW,GACjC,GAAI,GAAQ,OAAO,IAAS,UAAW,OAAO,EAAW,EAAM,CAAI,EACnE,GAAI,IAAS,GAAM,MAAO,CAAC,EAI5B,GACC,EAAS,uBAAyB,QAClC,EAAS,uBAAyB,GACjC,CACD,GAAI,EAAS,uBAAyB,GAErC,MAAO,CAAC,EAET,OAAO,EAAW,EAAS,qBAAsB,CAAI,EAItD,IAAM,EAAa,EAAS,KAK5B,IAHC,IAAe,SACd,MAAM,QAAQ,CAAU,GAAK,EAAW,SAAS,OAAO,IAE3C,IAAY,SAC1B,MAAO,CAAE,KAAM,SAAU,EAI1B,IAAM,EAAmB,EAAqB,EAAU,EAAS,CAAI,EACrE,GAAI,EAAkB,OAAO,EAE7B,OAQD,SAAS,CAAoB,CAC5B,EACA,EACA,EAC0B,CAG1B,GAAI,EAAO,MAAO,CACjB,IAAM,EAAU,EAAO,MACrB,OAAO,CAAC,IAAwB,OAAO,IAAM,SAAS,EACtD,IAAI,CAAC,IAAW,EAAe,EAAQ,EAAS,CAAI,CAAC,EACrD,OAAO,CAAC,IAAwB,IAAM,MAAS,EAEjD,GAAI,EAAQ,SAAW,EAAG,OAAO,EAAQ,GACzC,GAAI,EAAQ,OAAS,EAAG,MAAO,CAAE,MAAO,CAAQ,EAIjD,QAAW,IAAO,CAAC,QAAS,OAAO,EAAY,CAC9C,GAAI,CAAC,EAAO,GAAM,SAClB,IAAM,EAAU,EAAO,GACrB,OAAO,CAAC,IAAwB,OAAO,IAAM,SAAS,EACtD,IAAI,CAAC,IAAW,EAAe,EAAQ,EAAS,CAAI,CAAC,EACrD,OAAO,CAAC,IAAwB,IAAM,MAAS,EAEjD,GAAI,EAAQ,SAAW,EAAG,OAAO,EAAQ,GACzC,GAAI,EAAQ,OAAS,EAAG,MAAO,EAAG,GAAM,CAAQ,EAGjD,OA+BM,SAAS,CAAiB,CAChC,EACA,EAC0B,CAC1B,GAAI,EAAK,SAAW,EAAG,OAAO,EAAW,EAAQ,CAAM,EAEvD,IAAI,EAAuB,EAAW,EAAQ,CAAM,EAC9C,EAAO,EAEb,QAAW,KAAW,EAAM,CAC3B,IAAM,EAAO,EAAe,EAAS,EAAS,CAAI,EAClD,GAAI,IAAS,OAAW,OACxB,EAAU,EAGX,OAAO,EAUD,SAAS,CAAiB,CAChC,EACA,EAC0B,CAC1B,IAAM,EAAW,EAAW,EAAQ,CAAI,EAGlC,EAAa,EAAS,KAK5B,GAAI,EAHH,IAAe,SACd,MAAM,QAAQ,CAAU,GAAK,EAAW,SAAS,OAAO,IAE1C,EAAS,QAAU,OAClC,OAGD,GAAI,EAAS,QAAU,OAEtB,MAAO,CAAC,EAIT,GAAI,OAAO,EAAS,QAAU,UAC7B,MAAO,CAAC,EAKT,GAAI,MAAM,QAAQ,EAAS,KAAK,EAAG,CAElC,IAAM,EAAU,EAAS,MACvB,OAAO,CAAC,IAA8B,OAAO,IAAS,SAAS,EAC/D,IAAI,CAAC,IAAS,EAAW,EAAM,CAAI,CAAC,EACtC,GAAI,EAAQ,SAAW,EAAG,MAAO,CAAC,EAClC,MAAO,CAAE,MAAO,CAAQ,EAGzB,OAAO,EAAW,EAAS,MAAO,CAAI,EAWhC,SAAS,CAAc,CAAC,EAAkC,CAEhE,QAAW,IAAO,CAAC,QAAS,OAAO,EAAY,CAC9C,IAAM,EAAM,EAAO,GACnB,GAAI,GAAO,EAAI,SAAW,EAAG,CAC5B,IAAM,EAAQ,EAAI,GAClB,GAAI,IAAU,QAAa,OAAO,IAAU,UAC3C,OAAO,EAAe,CAAK,GAK9B,GAAI,EAAO,OAAS,EAAO,MAAM,SAAW,EAAG,CAC9C,IAAM,EAAQ,EAAO,MAAM,GAC3B,GAAI,IAAU,QAAa,OAAO,IAAU,UAC3C,OAAO,EAAe,CAAK,EAI7B,QAAW,IAAO,CAAC,QAAS,OAAO,EAAY,CAC9C,IAAM,EAAM,EAAO,GACnB,GAAI,GAAO,EAAI,OAAS,EAAG,CAC1B,IAAM,EAAwB,CAAC,EAC/B,QAAW,KAAS,EAAK,CACxB,GAAI,OAAO,IAAU,UAAW,SAOhC,GAAI,CAHgB,EAAO,KAAK,CAAC,IAChC,EAAU,EAAU,CAAK,CAC1B,EAEC,EAAO,KAAK,EAAe,CAAK,CAAC,EAGnC,GAAI,EAAO,SAAW,EAAG,OAAO,EAAO,GACvC,MAAO,IAAK,GAAS,GAAM,CAAO,GAIpC,OAAO",
8
+ "debugId": "3010A16AF72C22DE64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ import{q as J}from"./chunk-6c0pw73w.js";import Q from"handlebars";var V=/^(.+):(\d+)$/,W=/^-?\d+(\.\d+)?$/;function A(k){try{return Q.parse(k)}catch(q){let z=q instanceof Error?q.message:String(q),G=z.match(/line\s+(\d+).*?column\s+(\d+)/i),O=G?{line:parseInt(G[1]??"0",10),column:parseInt(G[2]??"0",10)}:void 0;throw new J(z,O)}}function C(k){let{body:q}=k;return q.length===1&&q[0]?.type==="MustacheStatement"}function D(k){if(k.type==="PathExpression")return k.parts;return[]}function F(k){if(k.type!=="PathExpression")return!1;let q=k;return q.original==="this"||q.original==="."}function K(k){return k.body.filter((q)=>!(q.type==="ContentStatement"&&q.value.trim()===""))}function P(k){let q=K(k);if(q.length===1&&q[0]?.type==="BlockStatement")return q[0];return null}function j(k){let q=K(k);if(q.length===1&&q[0]?.type==="MustacheStatement")return q[0];return null}function X(k){if(W.test(k))return"number";if(k==="true"||k==="false")return"boolean";if(k==="null")return"null";return null}function B(k){let q=k.trim(),z=X(q);if(z==="number")return Number(q);if(z==="boolean")return q==="true";if(z==="null")return null;return k}function Y(k){let q=k.match(V);if(q)return{key:q[1]??k,identifier:parseInt(q[2]??"0",10)};return{key:k,identifier:null}}function H(k){if(k.length===0)return{cleanSegments:[],identifier:null};let q=k[k.length-1],z=Y(q);if(z.identifier!==null)return{cleanSegments:[...k.slice(0,-1),z.key],identifier:z.identifier};return{cleanSegments:k,identifier:null}}
2
+ export{A as e,C as f,D as g,F as h,K as i,P as j,j as k,X as l,B as m,Y as n,H as o};
3
+
4
+ //# debugId=3EF6290B476C2E2064756E2164756E21
5
+ //# sourceMappingURL=chunk-9mg6qfrs.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/parser.ts"],
4
+ "sourcesContent": [
5
+ "import Handlebars from \"handlebars\";\nimport { TemplateParseError } from \"./errors.ts\";\n\n// ─── Regex pour détecter un identifiant de template (ex: \"meetingId:1\") ──────\n// L'identifiant est toujours un entier positif ou zéro, séparé du nom de la\n// variable par un `:`. Le `:` et le nombre sont sur le **dernier** segment\n// du chemin (Handlebars split sur les `.`).\nconst IDENTIFIER_RE = /^(.+):(\\d+)$/;\n\n// ─── Template Parser ─────────────────────────────────────────────────────────\n// Wrapper mince autour du parser Handlebars. On centralise ici l'appel au\n// parser pour :\n// 1. Encapsuler les erreurs dans notre hiérarchie (`TemplateParseError`)\n// 2. Exposer des helpers d'introspection sur l'AST (ex: `isSingleExpression`)\n// 3. Isoler la dépendance directe à Handlebars du reste du code\n\n// ─── Regex pour détecter un littéral numérique (entier ou décimal, signé) ────\n// Conservateur volontairement : pas de notation scientifique (1e5), pas de\n// hex (0xFF), pas de séparateurs (1_000). On veut reconnaître uniquement ce\n// qu'un humain écrirait comme valeur numérique dans un template.\nconst NUMERIC_LITERAL_RE = /^-?\\d+(\\.\\d+)?$/;\n\n/**\n * Parse un template string et retourne l'AST Handlebars.\n *\n * @param template - La chaîne de template à parser (ex: `\"Hello {{name}}\"`)\n * @returns L'AST racine (`hbs.AST.Program`)\n * @throws {TemplateParseError} si la syntaxe du template est invalide\n */\nexport function parse(template: string): hbs.AST.Program {\n\ttry {\n\t\treturn Handlebars.parse(template);\n\t} catch (error: unknown) {\n\t\t// Handlebars lève une Error classique avec un message descriptif.\n\t\t// On la transforme en TemplateParseError pour un traitement uniforme.\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\n\t\t// Handlebars inclut parfois la position dans le message, on tente\n\t\t// de l'extraire pour enrichir notre erreur.\n\t\tconst locMatch = message.match(/line\\s+(\\d+).*?column\\s+(\\d+)/i);\n\t\tconst loc = locMatch\n\t\t\t? {\n\t\t\t\t\tline: parseInt(locMatch[1] ?? \"0\", 10),\n\t\t\t\t\tcolumn: parseInt(locMatch[2] ?? \"0\", 10),\n\t\t\t\t}\n\t\t\t: undefined;\n\n\t\tthrow new TemplateParseError(message, loc);\n\t}\n}\n\n/**\n * Détermine si l'AST représente un template constitué d'une seule expression\n * `{{expression}}` sans aucun contenu textuel autour.\n *\n * C'est important pour l'inférence de type de retour :\n * - Template `{{value}}` → retourne le type brut de `value` (number, object…)\n * - Template `Hello {{name}}` → retourne toujours `string` (concaténation)\n *\n * @param ast - L'AST parsé du template\n * @returns `true` si le template est une expression unique\n */\nexport function isSingleExpression(ast: hbs.AST.Program): boolean {\n\tconst { body } = ast;\n\n\t// Exactement un nœud, et c'est un MustacheStatement (pas un block, pas du texte)\n\treturn body.length === 1 && body[0]?.type === \"MustacheStatement\";\n}\n\n/**\n * Extrait les segments de chemin d'un `PathExpression` Handlebars.\n *\n * Handlebars décompose `user.address.city` en `{ parts: [\"user\", \"address\", \"city\"] }`.\n * Cette fonction extrait ces segments de manière sûre.\n *\n * @param expr - L'expression dont on veut le chemin\n * @returns Les segments du chemin, ou un tableau vide si l'expression n'est\n * pas un `PathExpression`\n */\nexport function extractPathSegments(expr: hbs.AST.Expression): string[] {\n\tif (expr.type === \"PathExpression\") {\n\t\treturn (expr as hbs.AST.PathExpression).parts;\n\t}\n\treturn [];\n}\n\n/**\n * Vérifie si une expression AST est un `PathExpression` pointant vers `this`\n * (utilisé à l'intérieur des blocs `{{#each}}`).\n */\nexport function isThisExpression(expr: hbs.AST.Expression): boolean {\n\tif (expr.type !== \"PathExpression\") return false;\n\tconst path = expr as hbs.AST.PathExpression;\n\treturn path.original === \"this\" || path.original === \".\";\n}\n\n// ─── Filtrage des nœuds significatifs ────────────────────────────────────────\n// Dans un AST Handlebars, le formatage (retours à la ligne, indentation)\n// produit des `ContentStatement` dont la valeur est purement du whitespace.\n// Ces nœuds n'ont aucun impact sémantique et doivent être ignorés lors de\n// l'inférence de type pour détecter les cas \"effectivement un seul bloc\" ou\n// \"effectivement une seule expression\".\n\n/**\n * Retourne les statements significatifs d'un Program en éliminant les\n * `ContentStatement` constitués uniquement de whitespace.\n */\nexport function getEffectiveBody(\n\tprogram: hbs.AST.Program,\n): hbs.AST.Statement[] {\n\treturn program.body.filter(\n\t\t(s) =>\n\t\t\t!(\n\t\t\t\ts.type === \"ContentStatement\" &&\n\t\t\t\t(s as hbs.AST.ContentStatement).value.trim() === \"\"\n\t\t\t),\n\t);\n}\n\n/**\n * Détermine si un Program est effectivement constitué d'un seul\n * `BlockStatement` (en ignorant le whitespace autour).\n *\n * Exemples reconnus :\n * ```\n * {{#if x}}...{{/if}}\n *\n * {{#each items}}...{{/each}}\n * ```\n *\n * @returns Le `BlockStatement` unique ou `null` si le programme contient\n * d'autres nœuds significatifs.\n */\nexport function getEffectivelySingleBlock(\n\tprogram: hbs.AST.Program,\n): hbs.AST.BlockStatement | null {\n\tconst effective = getEffectiveBody(program);\n\tif (effective.length === 1 && effective[0]?.type === \"BlockStatement\") {\n\t\treturn effective[0] as hbs.AST.BlockStatement;\n\t}\n\treturn null;\n}\n\n/**\n * Détermine si un Program est effectivement constitué d'une seule\n * `MustacheStatement` (en ignorant le whitespace autour).\n *\n * Exemple : ` {{age}} ` → true\n */\nexport function getEffectivelySingleExpression(\n\tprogram: hbs.AST.Program,\n): hbs.AST.MustacheStatement | null {\n\tconst effective = getEffectiveBody(program);\n\tif (effective.length === 1 && effective[0]?.type === \"MustacheStatement\") {\n\t\treturn effective[0] as hbs.AST.MustacheStatement;\n\t}\n\treturn null;\n}\n\n// ─── Détection de littéraux dans le contenu textuel ──────────────────────────\n// Quand un programme ne contient que des ContentStatements (pas d'expressions),\n// on essaie de détecter si le texte concaténé et trimé est un littéral typé\n// (nombre, booléen, null). Cela permet d'inférer correctement le type de\n// branches comme `{{#if x}} 42 {{/if}}`.\n\n/**\n * Tente de détecter le type d'un littéral textuel brut.\n *\n * @param text - Le texte trimé d'un ContentStatement ou d'un groupe de ContentStatements\n * @returns Le type JSON Schema détecté, ou `null` si c'est du texte libre (string).\n */\nexport function detectLiteralType(\n\ttext: string,\n): \"number\" | \"boolean\" | \"null\" | null {\n\tif (NUMERIC_LITERAL_RE.test(text)) return \"number\";\n\tif (text === \"true\" || text === \"false\") return \"boolean\";\n\tif (text === \"null\") return \"null\";\n\treturn null;\n}\n\n/**\n * Coerce une string brute issue du rendu Handlebars vers son type réel\n * si elle représente un littéral (number, boolean, null).\n * Retourne la string trimée sinon.\n */\nexport function coerceLiteral(raw: string): unknown {\n\tconst trimmed = raw.trim();\n\tconst type = detectLiteralType(trimmed);\n\tif (type === \"number\") return Number(trimmed);\n\tif (type === \"boolean\") return trimmed === \"true\";\n\tif (type === \"null\") return null;\n\t// Pas un littéral typé → on retourne la string brute sans la trimer,\n\t// car le whitespace peut être significatif (ex: résultat d'un #each).\n\treturn raw;\n}\n\n// ─── Template Identifier Parsing ─────────────────────────────────────────────\n// Syntaxe `{{key:N}}` où N est un entier positif ou zéro.\n// L'identifiant permet de résoudre une variable depuis une source de données\n// spécifique (ex: un nœud de workflow identifié par son numéro).\n\n/** Résultat du parsing d'un segment de chemin avec identifiant potentiel */\nexport interface ParsedIdentifier {\n\t/** Le nom de la variable, sans le suffixe `:N` */\n\tkey: string;\n\t/** L'identifiant numérique, ou `null` si absent */\n\tidentifier: number | null;\n}\n\n/**\n * Parse un segment de chemin individuel pour en extraire la clé et\n * l'identifiant optionnel.\n *\n * @param segment - Un segment de chemin brut (ex: `\"meetingId:1\"` ou `\"meetingId\"`)\n * @returns Un objet `{ key, identifier }`\n *\n * @example\n * ```\n * parseIdentifier(\"meetingId:1\") // → { key: \"meetingId\", identifier: 1 }\n * parseIdentifier(\"meetingId\") // → { key: \"meetingId\", identifier: null }\n * parseIdentifier(\"meetingId:0\") // → { key: \"meetingId\", identifier: 0 }\n * ```\n */\nexport function parseIdentifier(segment: string): ParsedIdentifier {\n\tconst match = segment.match(IDENTIFIER_RE);\n\tif (match) {\n\t\treturn {\n\t\t\tkey: match[1] ?? segment,\n\t\t\tidentifier: parseInt(match[2] ?? \"0\", 10),\n\t\t};\n\t}\n\treturn { key: segment, identifier: null };\n}\n\n/** Résultat de l'extraction de l'identifiant sur une expression complète */\nexport interface ExpressionIdentifier {\n\t/** Segments de chemin nettoyés (sans le suffixe `:N` sur le dernier) */\n\tcleanSegments: string[];\n\t/** L'identifiant numérique extrait du dernier segment, ou `null` */\n\tidentifier: number | null;\n}\n\n/**\n * Extrait l'identifiant d'une expression complète (tableau de segments).\n *\n * L'identifiant est toujours sur le **dernier** segment du chemin, car\n * Handlebars split sur les `.` avant le `:`.\n *\n * @param segments - Les segments bruts du chemin (ex: `[\"user\", \"name:1\"]`)\n * @returns Un objet `{ cleanSegments, identifier }`\n *\n * @example\n * ```\n * extractExpressionIdentifier([\"meetingId:1\"])\n * // → { cleanSegments: [\"meetingId\"], identifier: 1 }\n *\n * extractExpressionIdentifier([\"user\", \"name:1\"])\n * // → { cleanSegments: [\"user\", \"name\"], identifier: 1 }\n *\n * extractExpressionIdentifier([\"meetingId\"])\n * // → { cleanSegments: [\"meetingId\"], identifier: null }\n * ```\n */\nexport function extractExpressionIdentifier(\n\tsegments: string[],\n): ExpressionIdentifier {\n\tif (segments.length === 0) {\n\t\treturn { cleanSegments: [], identifier: null };\n\t}\n\n\tconst lastSegment = segments[segments.length - 1] as string;\n\tconst parsed = parseIdentifier(lastSegment);\n\n\tif (parsed.identifier !== null) {\n\t\tconst cleanSegments = [...segments.slice(0, -1), parsed.key];\n\t\treturn { cleanSegments, identifier: parsed.identifier };\n\t}\n\n\treturn { cleanSegments: segments, identifier: null };\n}\n"
6
+ ],
7
+ "mappings": "wCAAA,0BAOA,IAAM,EAAgB,eAahB,EAAqB,kBASpB,SAAS,CAAK,CAAC,EAAmC,CACxD,GAAI,CACH,OAAO,EAAW,MAAM,CAAQ,EAC/B,MAAO,EAAgB,CAGxB,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAI/D,EAAW,EAAQ,MAAM,gCAAgC,EACzD,EAAM,EACT,CACA,KAAM,SAAS,EAAS,IAAM,IAAK,EAAE,EACrC,OAAQ,SAAS,EAAS,IAAM,IAAK,EAAE,CACxC,EACC,OAEH,MAAM,IAAI,EAAmB,EAAS,CAAG,GAepC,SAAS,CAAkB,CAAC,EAA+B,CACjE,IAAQ,QAAS,EAGjB,OAAO,EAAK,SAAW,GAAK,EAAK,IAAI,OAAS,oBAaxC,SAAS,CAAmB,CAAC,EAAoC,CACvE,GAAI,EAAK,OAAS,iBACjB,OAAQ,EAAgC,MAEzC,MAAO,CAAC,EAOF,SAAS,CAAgB,CAAC,EAAmC,CACnE,GAAI,EAAK,OAAS,iBAAkB,MAAO,GAC3C,IAAM,EAAO,EACb,OAAO,EAAK,WAAa,QAAU,EAAK,WAAa,IAc/C,SAAS,CAAgB,CAC/B,EACsB,CACtB,OAAO,EAAQ,KAAK,OACnB,CAAC,IACA,EACC,EAAE,OAAS,oBACV,EAA+B,MAAM,KAAK,IAAM,GAEpD,EAiBM,SAAS,CAAyB,CACxC,EACgC,CAChC,IAAM,EAAY,EAAiB,CAAO,EAC1C,GAAI,EAAU,SAAW,GAAK,EAAU,IAAI,OAAS,iBACpD,OAAO,EAAU,GAElB,OAAO,KASD,SAAS,CAA8B,CAC7C,EACmC,CACnC,IAAM,EAAY,EAAiB,CAAO,EAC1C,GAAI,EAAU,SAAW,GAAK,EAAU,IAAI,OAAS,oBACpD,OAAO,EAAU,GAElB,OAAO,KAeD,SAAS,CAAiB,CAChC,EACuC,CACvC,GAAI,EAAmB,KAAK,CAAI,EAAG,MAAO,SAC1C,GAAI,IAAS,QAAU,IAAS,QAAS,MAAO,UAChD,GAAI,IAAS,OAAQ,MAAO,OAC5B,OAAO,KAQD,SAAS,CAAa,CAAC,EAAsB,CACnD,IAAM,EAAU,EAAI,KAAK,EACnB,EAAO,EAAkB,CAAO,EACtC,GAAI,IAAS,SAAU,OAAO,OAAO,CAAO,EAC5C,GAAI,IAAS,UAAW,OAAO,IAAY,OAC3C,GAAI,IAAS,OAAQ,OAAO,KAG5B,OAAO,EA8BD,SAAS,CAAe,CAAC,EAAmC,CAClE,IAAM,EAAQ,EAAQ,MAAM,CAAa,EACzC,GAAI,EACH,MAAO,CACN,IAAK,EAAM,IAAM,EACjB,WAAY,SAAS,EAAM,IAAM,IAAK,EAAE,CACzC,EAED,MAAO,CAAE,IAAK,EAAS,WAAY,IAAK,EAgClC,SAAS,CAA2B,CAC1C,EACuB,CACvB,GAAI,EAAS,SAAW,EACvB,MAAO,CAAE,cAAe,CAAC,EAAG,WAAY,IAAK,EAG9C,IAAM,EAAc,EAAS,EAAS,OAAS,GACzC,EAAS,EAAgB,CAAW,EAE1C,GAAI,EAAO,aAAe,KAEzB,MAAO,CAAE,cADa,CAAC,GAAG,EAAS,MAAM,EAAG,EAAE,EAAG,EAAO,GAAG,EACnC,WAAY,EAAO,UAAW,EAGvD,MAAO,CAAE,cAAe,EAAU,WAAY,IAAK",
8
+ "debugId": "3EF6290B476C2E2064756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ import{b as z}from"./chunk-yraqh2tz.js";import{d as _}from"./chunk-yczpjh73.js";import{g as F}from"./chunk-p3xzf1ew.js";import{j as q,k as V,l as C}from"./chunk-6955jpr7.js";import{n as U}from"./chunk-ggdfaqhe.js";import{D as E}from"./chunk-vka4e61h.js";import{Q as x,T as g,U as k}from"./chunk-fhvf5y4x.js";import P from"handlebars";var j=new Set(["+","-","*","/","%","**"]);function K(w){if(typeof w==="number")return w;if(typeof w==="string"){let B=Number(w);return Number.isNaN(B)?0:B}return 0}function L(w,B,G){switch(B){case"+":return w+G;case"-":return w-G;case"*":return w*G;case"/":return G===0?1/0:w/G;case"%":return G===0?NaN:w%G;case"**":return w**G}}class Z{static HELPER_NAMES=["add","subtract","sub","multiply","mul","divide","div","modulo","mod","pow","abs","ceil","floor","round","sqrt","min","max","math"];static HELPER_NAMES_SET=new Set(Z.HELPER_NAMES);static getDefinitions(){let w=new Map;return Z.registerBinaryOperators(w),Z.registerUnaryFunctions(w),Z.registerMinMax(w),Z.registerGenericMath(w),w}static registerBinaryOperators(w){let B={fn:(W,Y)=>K(W)+K(Y),params:[{name:"a",type:{type:"number"},description:"First operand"},{name:"b",type:{type:"number"},description:"Second operand"}],returnType:{type:"number"},description:"Adds two numbers: {{ add a b }}"};w.set("add",B);let G={fn:(W,Y)=>K(W)-K(Y),params:[{name:"a",type:{type:"number"},description:"Value to subtract from"},{name:"b",type:{type:"number"},description:"Value to subtract"}],returnType:{type:"number"},description:"Subtracts b from a: {{ subtract a b }}"};w.set("subtract",G),w.set("sub",G);let J={fn:(W,Y)=>K(W)*K(Y),params:[{name:"a",type:{type:"number"},description:"First factor"},{name:"b",type:{type:"number"},description:"Second factor"}],returnType:{type:"number"},description:"Multiplies two numbers: {{ multiply a b }}"};w.set("multiply",J),w.set("mul",J);let Q={fn:(W,Y)=>{let $=K(Y);return $===0?1/0:K(W)/$},params:[{name:"a",type:{type:"number"},description:"Dividend"},{name:"b",type:{type:"number"},description:"Divisor"}],returnType:{type:"number"},description:"Divides a by b: {{ divide a b }}. Returns Infinity if b is 0."};w.set("divide",Q),w.set("div",Q);let X={fn:(W,Y)=>{let $=K(Y);return $===0?NaN:K(W)%$},params:[{name:"a",type:{type:"number"},description:"Dividend"},{name:"b",type:{type:"number"},description:"Divisor"}],returnType:{type:"number"},description:"Returns the remainder of a divided by b: {{ modulo a b }}"};w.set("modulo",X),w.set("mod",X),w.set("pow",{fn:(W,Y)=>K(W)**K(Y),params:[{name:"base",type:{type:"number"},description:"The base"},{name:"exponent",type:{type:"number"},description:"The exponent"}],returnType:{type:"number"},description:"Raises base to the power of exponent: {{ pow base exponent }}"})}static registerUnaryFunctions(w){w.set("abs",{fn:(B)=>Math.abs(K(B)),params:[{name:"value",type:{type:"number"},description:"The number"}],returnType:{type:"number"},description:"Returns the absolute value: {{ abs value }}"}),w.set("ceil",{fn:(B)=>Math.ceil(K(B)),params:[{name:"value",type:{type:"number"},description:"The number to round up"}],returnType:{type:"number"},description:"Rounds up to the nearest integer: {{ ceil value }}"}),w.set("floor",{fn:(B)=>Math.floor(K(B)),params:[{name:"value",type:{type:"number"},description:"The number to round down"}],returnType:{type:"number"},description:"Rounds down to the nearest integer: {{ floor value }}"}),w.set("round",{fn:(B,G)=>{let J=K(B);if(G===void 0||G===null||typeof G==="object")return Math.round(J);let X=10**K(G);return Math.round(J*X)/X},params:[{name:"value",type:{type:"number"},description:"The number to round"},{name:"precision",type:{type:"number"},description:"Number of decimal places (default: 0)",optional:!0}],returnType:{type:"number"},description:"Rounds to the nearest integer or to a given precision: {{ round value }} or {{ round value 2 }}"}),w.set("sqrt",{fn:(B)=>Math.sqrt(K(B)),params:[{name:"value",type:{type:"number"},description:"The number"}],returnType:{type:"number"},description:"Returns the square root: {{ sqrt value }}"})}static registerMinMax(w){w.set("min",{fn:(B,G)=>Math.min(K(B),K(G)),params:[{name:"a",type:{type:"number"},description:"First number"},{name:"b",type:{type:"number"},description:"Second number"}],returnType:{type:"number"},description:"Returns the smaller of two numbers: {{ min a b }}"}),w.set("max",{fn:(B,G)=>Math.max(K(B),K(G)),params:[{name:"a",type:{type:"number"},description:"First number"},{name:"b",type:{type:"number"},description:"Second number"}],returnType:{type:"number"},description:"Returns the larger of two numbers: {{ max a b }}"})}static registerGenericMath(w){w.set("math",{fn:(B,G,J)=>{let Q=String(G);if(!j.has(Q))throw Error(`[math helper] Unknown operator "${Q}". Supported: ${[...j].join(", ")} `);return L(K(B),Q,K(J))},params:[{name:"a",type:{type:"number"},description:"Left operand"},{name:"operator",type:{type:"string",enum:["+","-","*","/","%","**"]},description:'Arithmetic operator: "+", "-", "*", "/", "%", "**"'},{name:"b",type:{type:"number"},description:"Right operand"}],returnType:{type:"number"},description:'Generic math helper with operator as parameter: {{ math a "+" b }}, {{ math a "/" b }}. Supported operators: +, -, *, /, %, **'})}static register(w){let B=Z.getDefinitions();for(let[G,J]of B)w.registerHelper(G,J)}static unregister(w){for(let B of Z.HELPER_NAMES)w.unregisterHelper(B)}static getHelperNames(){return Z.HELPER_NAMES}static isMathHelper(w){return Z.HELPER_NAMES_SET.has(w)}}class R{hbs;astCache;compilationCache;helpers=new Map;constructor(w={}){if(this.hbs=P.create(),this.astCache=new x(w.astCacheSize??256),this.compilationCache=new x(w.compilationCacheSize??256),Z.register(this),w.helpers)for(let B of w.helpers){let{name:G,...J}=B;this.registerHelper(G,J)}}compile(w){if(V(w)){let J={};for(let[Q,X]of Object.entries(w))J[Q]=this.compile(X);return z.fromObject(J,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if(q(w))return z.fromLiteral(w,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache});let B=this.getCachedAst(w),G={helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache};return z.fromTemplate(B,w,G)}analyze(w,B,G){if(V(w))return g(Object.keys(w),(Q)=>this.analyze(w[Q],B,G));if(q(w))return{valid:!0,diagnostics:[],outputSchema:C(w)};let J=this.getCachedAst(w);return _(J,w,B,{identifierSchemas:G,helpers:this.helpers})}validate(w,B,G){let J=this.analyze(w,B,G);return{valid:J.valid,diagnostics:J.diagnostics}}isValidSyntax(w){if(V(w))return Object.values(w).every((B)=>this.isValidSyntax(B));if(q(w))return!0;try{return U(w),!0}catch{return!1}}execute(w,B,G){if(V(w)){let Q={};for(let[X,W]of Object.entries(w))Q[X]=this.execute(W,B,G);return Q}if(q(w))return w;if(G?.schema){let Q=this.getCachedAst(w),X=_(Q,w,G.schema,{identifierSchemas:G.identifierSchemas,helpers:this.helpers});if(!X.valid)throw new E(X.diagnostics)}let J=this.getCachedAst(w);return F(J,w,B,{identifierData:G?.identifierData,hbs:this.hbs,compilationCache:this.compilationCache})}analyzeAndExecute(w,B,G,J,Q){if(V(w))return k(Object.keys(w),($)=>this.analyzeAndExecute(w[$],B,G,J,Q));if(q(w))return{analysis:{valid:!0,diagnostics:[],outputSchema:C(w)},value:w};let X=this.getCachedAst(w),W=_(X,w,B,{identifierSchemas:J,helpers:this.helpers});if(!W.valid)return{analysis:W,value:void 0};let Y=F(X,w,G,{identifierData:Q,hbs:this.hbs,compilationCache:this.compilationCache});return{analysis:W,value:Y}}registerHelper(w,B){return this.helpers.set(w,B),this.hbs.registerHelper(w,B.fn),this.compilationCache.clear(),this}unregisterHelper(w){return this.helpers.delete(w),this.hbs.unregisterHelper(w),this.compilationCache.clear(),this}hasHelper(w){return this.helpers.has(w)}clearCaches(){this.astCache.clear(),this.compilationCache.clear()}getCachedAst(w){let B=this.astCache.get(w);if(!B)B=U(w),this.astCache.set(w,B);return B}}
2
+ export{R as a};
3
+
4
+ //# debugId=ACEF99364BF4CF0764756E2164756E21
5
+ //# sourceMappingURL=chunk-a37yzqra.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/typebars.ts", "../src/helpers/math-helpers.ts"],
4
+ "sourcesContent": [
5
+ "import Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport {\n\tCompiledTemplate,\n\ttype CompiledTemplateOptions,\n} from \"./compiled-template.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { executeFromAst } from \"./executor.ts\";\nimport { MathHelpers } from \"./helpers/index.ts\";\nimport { parse } from \"./parser.ts\";\nimport type {\n\tAnalysisResult,\n\tExecuteOptions,\n\tHelperDefinition,\n\tTemplateEngineOptions,\n\tTemplateInput,\n\tValidationResult,\n} from \"./types.ts\";\nimport {\n\tinferPrimitiveSchema,\n\tisLiteralInput,\n\tisObjectInput,\n} from \"./types.ts\";\nimport {\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n\tLRUCache,\n} from \"./utils.ts\";\n\n// ─── Typebars ────────────────────────────────────────────────────────────────\n// Point d'entrée public du moteur de template. Orchestre les trois phases :\n//\n// 1. **Parsing** — transformation du template string en AST (via Handlebars)\n// 2. **Analyse** — validation statique + inférence du type de retour\n// 3. **Exécution** — rendu du template avec des données réelles\n//\n// ─── Architecture v2 ─────────────────────────────────────────────────────────\n// - **Cache LRU** pour les AST parsés et les templates Handlebars compilés\n// - **Environnement Handlebars isolé** par instance (custom helpers)\n// - **Pattern `compile()`** : parse-once / execute-many\n// - **Méthode `validate()`** : raccourci d'API sans `outputSchema`\n// - **`registerHelper()`** : helpers custom avec typage statique\n// - **`ExecuteOptions`** : options object pour `execute()`\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// La syntaxe `{{key:N}}` permet de référencer des variables provenant de\n// sources de données spécifiques, identifiées par un entier N.\n//\n// - `identifierSchemas` : mapping `{ [id]: JSONSchema7 }` pour l'analyse statique\n// - `identifierData` : mapping `{ [id]: Record<string, unknown> }` pour l'exécution\n//\n// Usage :\n// engine.execute(\"{{meetingId:1}}\", data, { identifierData: { 1: node1Data } });\n// engine.analyze(\"{{meetingId:1}}\", schema, { 1: node1Schema });\n\n// ─── Classe principale ──────────────────────────────────────────────────────\n\nexport class Typebars {\n\t/** Environnement Handlebars isolé — chaque engine a ses propres helpers */\n\tprivate readonly hbs: typeof Handlebars;\n\n\t/** Cache LRU des AST parsés (évite le re-parsing) */\n\tprivate readonly astCache: LRUCache<string, hbs.AST.Program>;\n\n\t/** Cache LRU des templates Handlebars compilés (évite la recompilation) */\n\tprivate readonly compilationCache: LRUCache<\n\t\tstring,\n\t\tHandlebarsTemplateDelegate\n\t>;\n\n\t/** Helpers custom enregistrés sur cette instance */\n\tprivate readonly helpers = new Map<string, HelperDefinition>();\n\n\tconstructor(options: TemplateEngineOptions = {}) {\n\t\tthis.hbs = Handlebars.create();\n\t\tthis.astCache = new LRUCache(options.astCacheSize ?? 256);\n\t\tthis.compilationCache = new LRUCache(options.compilationCacheSize ?? 256);\n\n\t\t// ── Built-in helpers (math) ──────────────────────────────────────────\n\t\tMathHelpers.register(this);\n\n\t\t// ── Helpers custom via options ───────────────────────────────────────\n\t\tif (options.helpers) {\n\t\t\tfor (const helper of options.helpers) {\n\t\t\t\tconst { name, ...definition } = helper;\n\t\t\t\tthis.registerHelper(name, definition);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Compilation ───────────────────────────────────────────────────────\n\n\t/**\n\t * Compile un template et retourne un `CompiledTemplate` prêt à être\n\t * exécuté ou analysé sans re-parsing.\n\t *\n\t * Accepte un `TemplateInput` : string, number, boolean, null ou objet.\n\t * Pour les objets, chaque propriété est compilée récursivement.\n\t *\n\t * @param template - Le template à compiler\n\t * @returns Un `CompiledTemplate` réutilisable\n\t */\n\tcompile(template: TemplateInput): CompiledTemplate {\n\t\tif (isObjectInput(template)) {\n\t\t\tconst children: Record<string, CompiledTemplate> = {};\n\t\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\t\tchildren[key] = this.compile(value);\n\t\t\t}\n\t\t\treturn CompiledTemplate.fromObject(children, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn CompiledTemplate.fromLiteral(template, {\n\t\t\t\thelpers: this.helpers,\n\t\t\t\thbs: this.hbs,\n\t\t\t\tcompilationCache: this.compilationCache,\n\t\t\t});\n\t\t}\n\t\tconst ast = this.getCachedAst(template);\n\t\tconst options: CompiledTemplateOptions = {\n\t\t\thelpers: this.helpers,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t};\n\t\treturn CompiledTemplate.fromTemplate(ast, template, options);\n\t}\n\n\t// ─── Analyse statique ────────────────────────────────────────────────────\n\n\t/**\n\t * Analyse statiquement un template par rapport à un JSON Schema v7\n\t * décrivant le contexte disponible.\n\t *\n\t * Accepte un `TemplateInput` : string, number, boolean, null ou objet.\n\t * Pour les objets, chaque propriété est analysée récursivement et le\n\t * `outputSchema` reflète la structure de l'objet avec les types résolus.\n\t *\n\t * @param template - Le template à analyser\n\t * @param inputSchema - JSON Schema v7 décrivant les variables disponibles\n\t * @param identifierSchemas - (optionnel) Schemas par identifiant `{ [id]: JSONSchema7 }`\n\t */\n\tanalyze(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7,\n\t\tidentifierSchemas?: Record<number, JSONSchema7>,\n\t): AnalysisResult {\n\t\tif (isObjectInput(template)) {\n\t\t\treturn aggregateObjectAnalysis(Object.keys(template), (key) =>\n\t\t\t\tthis.analyze(\n\t\t\t\t\ttemplate[key] as TemplateInput,\n\t\t\t\t\tinputSchema,\n\t\t\t\t\tidentifierSchemas,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn {\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}\n\t\tconst ast = this.getCachedAst(template);\n\t\treturn analyzeFromAst(ast, template, inputSchema, {\n\t\t\tidentifierSchemas,\n\t\t\thelpers: this.helpers,\n\t\t});\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────────\n\n\t/**\n\t * Valide un template contre un schema sans retourner le type de sortie.\n\t *\n\t * C'est un raccourci d'API pour `analyze()` qui ne retourne que `valid`\n\t * et `diagnostics`, sans `outputSchema`. L'analyse complète (y compris\n\t * l'inférence de type) est exécutée en interne — cette méthode ne\n\t * fournit pas de gain de performance, uniquement une API simplifiée.\n\t *\n\t * @param template - Le template à valider\n\t * @param inputSchema - JSON Schema v7 décrivant les variables disponibles\n\t * @param identifierSchemas - (optionnel) Schemas par identifiant\n\t */\n\tvalidate(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7,\n\t\tidentifierSchemas?: Record<number, JSONSchema7>,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(template, inputSchema, identifierSchemas);\n\t\treturn {\n\t\t\tvalid: analysis.valid,\n\t\t\tdiagnostics: analysis.diagnostics,\n\t\t};\n\t}\n\n\t// ─── Validation syntaxique ───────────────────────────────────────────────\n\n\t/**\n\t * Vérifie uniquement que la syntaxe du template est valide (parsing).\n\t * Ne nécessite pas de schema — utile pour un feedback rapide dans un éditeur.\n\t *\n\t * Pour les objets, vérifie récursivement chaque propriété.\n\t *\n\t * @param template - Le template à valider\n\t * @returns `true` si le template est syntaxiquement correct\n\t */\n\tisValidSyntax(template: TemplateInput): boolean {\n\t\tif (isObjectInput(template)) {\n\t\t\treturn Object.values(template).every((v) => this.isValidSyntax(v));\n\t\t}\n\t\tif (isLiteralInput(template)) return true;\n\t\ttry {\n\t\t\tparse(template);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// ─── Exécution ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Exécute un template avec les données fournies.\n\t *\n\t * Accepte un `TemplateInput` : string, number, boolean, null ou objet.\n\t * Pour les objets, chaque propriété est exécutée récursivement et un\n\t * objet avec les valeurs résolues est retourné.\n\t *\n\t * Si un `schema` est fourni dans les options, l'analyse statique est\n\t * lancée avant l'exécution. Une `TemplateAnalysisError` est levée en\n\t * cas d'erreur.\n\t *\n\t * @param template - Le template à exécuter\n\t * @param data - Les données de contexte pour le rendu\n\t * @param options - Options d'exécution (schema, identifierData, identifierSchemas)\n\t * @returns Le résultat de l'exécution\n\t */\n\texecute(\n\t\ttemplate: TemplateInput,\n\t\tdata: Record<string, unknown>,\n\t\toptions?: ExecuteOptions,\n\t): unknown {\n\t\t// ── Objet template → exécution récursive ─────────────────────────────\n\t\tif (isObjectInput(template)) {\n\t\t\tconst result: Record<string, unknown> = {};\n\t\t\tfor (const [key, value] of Object.entries(template)) {\n\t\t\t\tresult[key] = this.execute(value, data, options);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\t// ── Passthrough pour les valeurs littérales ───────────────────────────\n\t\tif (isLiteralInput(template)) return template;\n\n\t\t// ── Validation statique préalable ────────────────────────────────────\n\t\tif (options?.schema) {\n\t\t\tconst ast = this.getCachedAst(template);\n\t\t\tconst analysis = analyzeFromAst(ast, template, options.schema, {\n\t\t\t\tidentifierSchemas: options.identifierSchemas,\n\t\t\t\thelpers: this.helpers,\n\t\t\t});\n\t\t\tif (!analysis.valid) {\n\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t}\n\t\t}\n\n\t\t// ── Exécution ────────────────────────────────────────────────────────\n\t\tconst ast = this.getCachedAst(template);\n\t\treturn executeFromAst(ast, template, data, {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t});\n\t}\n\n\t// ─── Raccourcis combinés ─────────────────────────────────────────────────\n\n\t/**\n\t * Analyse un template et, si valide, l'exécute avec les données fournies.\n\t * Retourne à la fois le résultat d'analyse et la valeur exécutée.\n\t *\n\t * Pour les objets, chaque propriété est analysée et exécutée récursivement.\n\t * L'objet entier est considéré invalide si au moins une propriété l'est.\n\t *\n\t * @param template - Le template\n\t * @param inputSchema - JSON Schema v7 décrivant les variables disponibles\n\t * @param data - Les données de contexte pour le rendu\n\t * @param identifierSchemas - (optionnel) Schemas par identifiant\n\t * @param identifierData - (optionnel) Données par identifiant\n\t * @returns Un objet `{ analysis, value }` où `value` est `undefined` si\n\t * l'analyse a échoué.\n\t */\n\tanalyzeAndExecute(\n\t\ttemplate: TemplateInput,\n\t\tinputSchema: JSONSchema7,\n\t\tdata: Record<string, unknown>,\n\t\tidentifierSchemas?: Record<number, JSONSchema7>,\n\t\tidentifierData?: Record<number, Record<string, unknown>>,\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\tif (isObjectInput(template)) {\n\t\t\treturn aggregateObjectAnalysisAndExecution(Object.keys(template), (key) =>\n\t\t\t\tthis.analyzeAndExecute(\n\t\t\t\t\ttemplate[key] as TemplateInput,\n\t\t\t\t\tinputSchema,\n\t\t\t\t\tdata,\n\t\t\t\t\tidentifierSchemas,\n\t\t\t\t\tidentifierData,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tif (isLiteralInput(template)) {\n\t\t\treturn {\n\t\t\t\tanalysis: {\n\t\t\t\t\tvalid: true,\n\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\toutputSchema: inferPrimitiveSchema(template),\n\t\t\t\t},\n\t\t\t\tvalue: template,\n\t\t\t};\n\t\t}\n\n\t\tconst ast = this.getCachedAst(template);\n\t\tconst analysis = analyzeFromAst(ast, template, inputSchema, {\n\t\t\tidentifierSchemas,\n\t\t\thelpers: this.helpers,\n\t\t});\n\n\t\tif (!analysis.valid) {\n\t\t\treturn { analysis, value: undefined };\n\t\t}\n\n\t\tconst value = executeFromAst(ast, template, data, {\n\t\t\tidentifierData,\n\t\t\thbs: this.hbs,\n\t\t\tcompilationCache: this.compilationCache,\n\t\t});\n\t\treturn { analysis, value };\n\t}\n\n\t// ─── Gestion des helpers custom ────────────────────────────────────────\n\n\t/**\n\t * Enregistre un helper custom sur cette instance du moteur.\n\t *\n\t * Le helper est disponible à la fois pour l'exécution (via Handlebars)\n\t * et pour l'analyse statique (via son `returnType` déclaré).\n\t *\n\t * @param name - Nom du helper (ex: `\"uppercase\"`)\n\t * @param definition - Définition du helper (implémentation + type de retour)\n\t * @returns `this` pour permettre le chaînage\n\t */\n\tregisterHelper(name: string, definition: HelperDefinition): this {\n\t\tthis.helpers.set(name, definition);\n\t\tthis.hbs.registerHelper(name, definition.fn);\n\n\t\t// Invalider le cache de compilation car les helpers ont changé\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Supprime un helper custom de cette instance du moteur.\n\t *\n\t * @param name - Nom du helper à supprimer\n\t * @returns `this` pour permettre le chaînage\n\t */\n\tunregisterHelper(name: string): this {\n\t\tthis.helpers.delete(name);\n\t\tthis.hbs.unregisterHelper(name);\n\n\t\t// Invalider le cache de compilation\n\t\tthis.compilationCache.clear();\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Vérifie si un helper est enregistré sur cette instance.\n\t *\n\t * @param name - Nom du helper\n\t * @returns `true` si le helper est enregistré\n\t */\n\thasHelper(name: string): boolean {\n\t\treturn this.helpers.has(name);\n\t}\n\n\t// ─── Gestion du cache ──────────────────────────────────────────────────\n\n\t/**\n\t * Vide tous les caches internes (AST + compilation).\n\t *\n\t * Utile après un changement de configuration ou pour libérer la mémoire.\n\t */\n\tclearCaches(): void {\n\t\tthis.astCache.clear();\n\t\tthis.compilationCache.clear();\n\t}\n\n\t// ─── Internals ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Récupère l'AST d'un template depuis le cache, ou le parse et le cache.\n\t */\n\tprivate getCachedAst(template: string): hbs.AST.Program {\n\t\tlet ast = this.astCache.get(template);\n\t\tif (!ast) {\n\t\t\tast = parse(template);\n\t\t\tthis.astCache.set(template, ast);\n\t\t}\n\t\treturn ast;\n\t}\n}\n",
6
+ "import type { HelperDefinition } from \"../types.ts\";\n\n// ─── MathHelpers ─────────────────────────────────────────────────────────────\n// Classe regroupant tous les helpers mathématiques pour le moteur de template.\n//\n// Fournit deux types de helpers :\n//\n// 1. **Helpers nommés** — un helper par opération (`add`, `subtract`, `divide`, …)\n// Usage : `{ { add a b } } `, `{ { abs value } } `, `{ { round value 2 } } `\n//\n// 2. **Helper générique `math`** — un seul helper avec l'opérateur en paramètre\n// Usage : `{ { math a \"+\" b } } `, `{ { math a \"/\" b } } `, `{ { math a \"**\" b } } `\n//\n// ─── Enregistrement ──────────────────────────────────────────────────────────\n// Les MathHelpers sont pré-enregistrés automatiquement par le constructeur\n// de `Typebars`. Il est aussi possible de les enregistrer manuellement\n// sur n'importe quel objet implémentant `HelperRegistry` :\n//\n// MathHelpers.register(engine); // enregistre tous les helpers\n// MathHelpers.unregister(engine); // les supprime tous\n//\n// ─── Opérateurs supportés (helper `math`) ────────────────────────────────────\n// + Addition\n// - Subtraction\n// * Multiplication\n// / Division\n// % Modulo\n// ** Exponentiation\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Interface minimale pour l'enregistrement — évite le couplage avec Typebars */\ninterface HelperRegistry {\n\tregisterHelper(name: string, definition: HelperDefinition): unknown;\n\tunregisterHelper(name: string): unknown;\n}\n\n/** Opérateurs supportés par le helper générique `math` */\ntype MathOperator = \"+\" | \"-\" | \"*\" | \"/\" | \"%\" | \"**\";\n\nconst SUPPORTED_OPERATORS = new Set<string>([\"+\", \"-\", \"*\", \"/\", \"%\", \"**\"]);\n\n// ─── Utilitaires internes ────────────────────────────────────────────────────\n\n/**\n * Convertit une valeur inconnue en nombre. Retourne `0` si la conversion\n * échoue (string non numérique, objet, etc.).\n */\nfunction toNumber(value: unknown): number {\n\tif (typeof value === \"number\") return value;\n\tif (typeof value === \"string\") {\n\t\tconst n = Number(value);\n\t\treturn Number.isNaN(n) ? 0 : n;\n\t}\n\treturn 0;\n}\n\n/**\n * Applique un opérateur binaire sur deux opérandes.\n */\nfunction applyOperator(a: number, op: MathOperator, b: number): number {\n\tswitch (op) {\n\t\tcase \"+\":\n\t\t\treturn a + b;\n\t\tcase \"-\":\n\t\t\treturn a - b;\n\t\tcase \"*\":\n\t\t\treturn a * b;\n\t\tcase \"/\":\n\t\t\treturn b === 0 ? Infinity : a / b;\n\t\tcase \"%\":\n\t\t\treturn b === 0 ? NaN : a % b;\n\t\tcase \"**\":\n\t\t\treturn a ** b;\n\t}\n}\n\n// ─── Classe principale ──────────────────────────────────────────────────────\n\nexport class MathHelpers {\n\t// ─── Noms de tous les helpers enregistrés ─────────────────────────────\n\t// Utilisé par `register()` et `unregister()` pour itérer.\n\tprivate static readonly HELPER_NAMES: readonly string[] = [\n\t\t// Opérateurs binaires\n\t\t\"add\",\n\t\t\"subtract\",\n\t\t\"sub\",\n\t\t\"multiply\",\n\t\t\"mul\",\n\t\t\"divide\",\n\t\t\"div\",\n\t\t\"modulo\",\n\t\t\"mod\",\n\t\t\"pow\",\n\n\t\t// Fonctions unaires\n\t\t\"abs\",\n\t\t\"ceil\",\n\t\t\"floor\",\n\t\t\"round\",\n\t\t\"sqrt\",\n\n\t\t// Min / Max (binaires)\n\t\t\"min\",\n\t\t\"max\",\n\n\t\t// Helper générique\n\t\t\"math\",\n\t];\n\n\t/** Set dérivé de `HELPER_NAMES` pour un lookup O(1) dans `isMathHelper()` */\n\tprivate static readonly HELPER_NAMES_SET: ReadonlySet<string> = new Set(\n\t\tMathHelpers.HELPER_NAMES,\n\t);\n\n\t// ─── Définitions des helpers ─────────────────────────────────────────\n\n\t/** Retourne toutes les définitions sous forme de `Map<name, HelperDefinition>` */\n\tstatic getDefinitions(): Map<string, HelperDefinition> {\n\t\tconst defs = new Map<string, HelperDefinition>();\n\n\t\tMathHelpers.registerBinaryOperators(defs);\n\t\tMathHelpers.registerUnaryFunctions(defs);\n\t\tMathHelpers.registerMinMax(defs);\n\t\tMathHelpers.registerGenericMath(defs);\n\n\t\treturn defs;\n\t}\n\n\t// ── Opérateurs binaires ──────────────────────────────────────────\n\n\t/** Enregistre add, subtract/sub, multiply/mul, divide/div, modulo/mod, pow */\n\tprivate static registerBinaryOperators(\n\t\tdefs: Map<string, HelperDefinition>,\n\t): void {\n\t\t// add — Addition : {{ add a b }}\n\t\tconst addDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => toNumber(a) + toNumber(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First operand\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Adds two numbers: {{ add a b }}\",\n\t\t};\n\t\tdefs.set(\"add\", addDef);\n\n\t\t// subtract / sub — Soustraction : {{ subtract a b }} ou {{ sub a b }}\n\t\tconst subtractDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => toNumber(a) - toNumber(b),\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"a\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"Value to subtract from\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"b\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"Value to subtract\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Subtracts b from a: {{ subtract a b }}\",\n\t\t};\n\t\tdefs.set(\"subtract\", subtractDef);\n\t\tdefs.set(\"sub\", subtractDef);\n\n\t\t// multiply / mul — Multiplication : {{ multiply a b }} ou {{ mul a b }}\n\t\tconst multiplyDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => toNumber(a) * toNumber(b),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First factor\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second factor\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Multiplies two numbers: {{ multiply a b }}\",\n\t\t};\n\t\tdefs.set(\"multiply\", multiplyDef);\n\t\tdefs.set(\"mul\", multiplyDef);\n\n\t\t// divide / div — Division : {{ divide a b }} ou {{ div a b }}\n\t\tconst divideDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => {\n\t\t\t\tconst divisor = toNumber(b);\n\t\t\t\treturn divisor === 0 ? Infinity : toNumber(a) / divisor;\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Dividend\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Divisor\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t\"Divides a by b: {{ divide a b }}. Returns Infinity if b is 0.\",\n\t\t};\n\t\tdefs.set(\"divide\", divideDef);\n\t\tdefs.set(\"div\", divideDef);\n\n\t\t// modulo / mod — Modulo : {{ modulo a b }} ou {{ mod a b }}\n\t\tconst moduloDef: HelperDefinition = {\n\t\t\tfn: (a: unknown, b: unknown) => {\n\t\t\t\tconst divisor = toNumber(b);\n\t\t\t\treturn divisor === 0 ? NaN : toNumber(a) % divisor;\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Dividend\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Divisor\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the remainder of a divided by b: {{ modulo a b }}\",\n\t\t};\n\t\tdefs.set(\"modulo\", moduloDef);\n\t\tdefs.set(\"mod\", moduloDef);\n\n\t\t// pow — Exponentiation : {{ pow base exponent }}\n\t\tdefs.set(\"pow\", {\n\t\t\tfn: (base: unknown, exponent: unknown) =>\n\t\t\t\ttoNumber(base) ** toNumber(exponent),\n\t\t\tparams: [\n\t\t\t\t{ name: \"base\", type: { type: \"number\" }, description: \"The base\" },\n\t\t\t\t{\n\t\t\t\t\tname: \"exponent\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The exponent\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t\"Raises base to the power of exponent: {{ pow base exponent }}\",\n\t\t});\n\t}\n\n\t// ── Fonctions unaires ────────────────────────────────────────────\n\n\t/** Enregistre abs, ceil, floor, round, sqrt */\n\tprivate static registerUnaryFunctions(\n\t\tdefs: Map<string, HelperDefinition>,\n\t): void {\n\t\t// abs — Valeur absolue : {{ abs value }}\n\t\tdefs.set(\"abs\", {\n\t\t\tfn: (value: unknown) => Math.abs(toNumber(value)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"value\", type: { type: \"number\" }, description: \"The number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the absolute value: {{ abs value }}\",\n\t\t});\n\n\t\t// ceil — Arrondi supérieur : {{ ceil value }}\n\t\tdefs.set(\"ceil\", {\n\t\t\tfn: (value: unknown) => Math.ceil(toNumber(value)),\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The number to round up\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Rounds up to the nearest integer: {{ ceil value }}\",\n\t\t});\n\n\t\t// floor — Arrondi inférieur : {{ floor value }}\n\t\tdefs.set(\"floor\", {\n\t\t\tfn: (value: unknown) => Math.floor(toNumber(value)),\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The number to round down\",\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Rounds down to the nearest integer: {{ floor value }}\",\n\t\t});\n\n\t\t// round — Arrondi : {{ round value }} ou {{ round value precision }}\n\t\t// Avec précision : {{ round 3.14159 2 }} → 3.14\n\t\tdefs.set(\"round\", {\n\t\t\tfn: (value: unknown, precision: unknown) => {\n\t\t\t\tconst n = toNumber(value);\n\t\t\t\t// Si precision est un objet Handlebars options (pas un nombre),\n\t\t\t\t// c'est que le second paramètre n'a pas été fourni.\n\t\t\t\tif (\n\t\t\t\t\tprecision === undefined ||\n\t\t\t\t\tprecision === null ||\n\t\t\t\t\ttypeof precision === \"object\"\n\t\t\t\t) {\n\t\t\t\t\treturn Math.round(n);\n\t\t\t\t}\n\t\t\t\tconst p = toNumber(precision);\n\t\t\t\tconst factor = 10 ** p;\n\t\t\t\treturn Math.round(n * factor) / factor;\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"The number to round\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"precision\",\n\t\t\t\t\ttype: { type: \"number\" },\n\t\t\t\t\tdescription: \"Number of decimal places (default: 0)\",\n\t\t\t\t\toptional: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t\"Rounds to the nearest integer or to a given precision: {{ round value }} or {{ round value 2 }}\",\n\t\t});\n\n\t\t// sqrt — Racine carrée : {{ sqrt value }}\n\t\tdefs.set(\"sqrt\", {\n\t\t\tfn: (value: unknown) => Math.sqrt(toNumber(value)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"value\", type: { type: \"number\" }, description: \"The number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the square root: {{ sqrt value }}\",\n\t\t});\n\t}\n\n\t// ── Min / Max ────────────────────────────────────────────────────\n\n\t/** Enregistre min et max */\n\tprivate static registerMinMax(defs: Map<string, HelperDefinition>): void {\n\t\t// min — Minimum : {{ min a b }}\n\t\tdefs.set(\"min\", {\n\t\t\tfn: (a: unknown, b: unknown) => Math.min(toNumber(a), toNumber(b)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First number\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the smaller of two numbers: {{ min a b }}\",\n\t\t});\n\n\t\t// max — Maximum : {{ max a b }}\n\t\tdefs.set(\"max\", {\n\t\t\tfn: (a: unknown, b: unknown) => Math.max(toNumber(a), toNumber(b)),\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"First number\" },\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Second number\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription: \"Returns the larger of two numbers: {{ max a b }}\",\n\t\t});\n\t}\n\n\t// ── Helper générique ─────────────────────────────────────────────\n\n\t/** Enregistre le helper générique `math` avec opérateur en paramètre */\n\tprivate static registerGenericMath(\n\t\tdefs: Map<string, HelperDefinition>,\n\t): void {\n\t\t// Usage : {{ math a \"+\" b }}, {{ math a \"/\" b }}, {{ math a \"**\" b }}\n\t\tdefs.set(\"math\", {\n\t\t\tfn: (a: unknown, operator: unknown, b: unknown) => {\n\t\t\t\tconst op = String(operator);\n\t\t\t\tif (!SUPPORTED_OPERATORS.has(op)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`[math helper] Unknown operator \"${op}\". ` +\n\t\t\t\t\t\t\t`Supported: ${[...SUPPORTED_OPERATORS].join(\", \")} `,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn applyOperator(toNumber(a), op as MathOperator, toNumber(b));\n\t\t\t},\n\t\t\tparams: [\n\t\t\t\t{ name: \"a\", type: { type: \"number\" }, description: \"Left operand\" },\n\t\t\t\t{\n\t\t\t\t\tname: \"operator\",\n\t\t\t\t\ttype: { type: \"string\", enum: [\"+\", \"-\", \"*\", \"/\", \"%\", \"**\"] },\n\t\t\t\t\tdescription: 'Arithmetic operator: \"+\", \"-\", \"*\", \"/\", \"%\", \"**\"',\n\t\t\t\t},\n\t\t\t\t{ name: \"b\", type: { type: \"number\" }, description: \"Right operand\" },\n\t\t\t],\n\t\t\treturnType: { type: \"number\" },\n\t\t\tdescription:\n\t\t\t\t'Generic math helper with operator as parameter: {{ math a \"+\" b }}, {{ math a \"/\" b }}. ' +\n\t\t\t\t\"Supported operators: +, -, *, /, %, **\",\n\t\t});\n\t}\n\n\t// ─── Enregistrement / Désenregistrement ──────────────────────────────\n\n\t/**\n\t * Enregistre tous les helpers mathématiques sur un `Typebars`\n\t * (ou tout objet implémentant `HelperRegistry`).\n\t *\n\t * **Note :** les MathHelpers sont pré-enregistrés automatiquement par\n\t * le constructeur de `Typebars`. Cette méthode n'est utile que\n\t * si vous avez appelé `unregister()` et souhaitez les ré-activer,\n\t * ou si vous enregistrez sur un registre custom.\n\t *\n\t * @param registry - L'engine ou le registre cible\n\t *\n\t * @example\n\t * ```\n\t * const engine = new Typebars();\n\t * // Les math helpers sont déjà disponibles !\n\t * engine.analyzeAndExecute(\"{{ divide total count }}\", schema, data);\n\t * engine.analyzeAndExecute(\"{{ math price '*' quantity }}\", schema, data);\n\t * ```\n\t */\n\tstatic register(registry: HelperRegistry): void {\n\t\tconst defs = MathHelpers.getDefinitions();\n\t\tfor (const [name, def] of defs) {\n\t\t\tregistry.registerHelper(name, def);\n\t\t}\n\t}\n\n\t/**\n\t * Supprime tous les helpers mathématiques du registre.\n\t *\n\t * @param registry - L'engine ou le registre cible\n\t */\n\tstatic unregister(registry: HelperRegistry): void {\n\t\tfor (const name of MathHelpers.HELPER_NAMES) {\n\t\t\tregistry.unregisterHelper(name);\n\t\t}\n\t}\n\n\t/**\n\t * Retourne la liste des noms de tous les helpers mathématiques.\n\t * Utile pour vérifier si un helper donné fait partie du pack math.\n\t */\n\tstatic getHelperNames(): readonly string[] {\n\t\treturn MathHelpers.HELPER_NAMES;\n\t}\n\n\t/**\n\t * Vérifie si un nom de helper fait partie du pack mathématique.\n\t *\n\t * @param name - Le nom du helper à vérifier\n\t */\n\tstatic isMathHelper(name: string): boolean {\n\t\treturn MathHelpers.HELPER_NAMES_SET.has(name);\n\t}\n}\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "ACEF99364BF4CF0764756E2164756E21",
10
+ "names": []
11
+ }
@@ -0,0 +1,4 @@
1
+ import{j as u,k as v,l as S}from"./chunk-6955jpr7.js";import{n as M,p as b,q,r as C,s as k,t as D,v as W,y as E}from"./chunk-1gm6cf0e.js";import{D as Z,E as _,F as R,G as $,H as B}from"./chunk-ybh51hbe.js";import{J as X,K as N,L as Y}from"./chunk-8g0d6h85.js";import{M as T,O as P,P as V,Q as y}from"./chunk-4zv02svp.js";function o(j,w,A){if(v(j))return d(j,w,A);if(u(j))return{valid:!0,diagnostics:[],outputSchema:S(j)};let F=M(j);return n(F,j,w,{identifierSchemas:A})}function d(j,w,A){return y(Object.keys(j),(F)=>o(j[F],w,A))}function n(j,w,A,F){let z={root:A,current:A,diagnostics:[],template:w,identifierSchemas:F?.identifierSchemas,helpers:F?.helpers},G=J(j,z);return{valid:!z.diagnostics.some((I)=>I.severity==="error"),diagnostics:z.diagnostics,outputSchema:Y(G)}}function l(j,w){switch(j.type){case"ContentStatement":case"CommentStatement":return;case"MustacheStatement":return g(j,w);case"BlockStatement":return f(j,w);default:K(w,"UNANALYZABLE","warning",`Unsupported AST node type: "${j.type}"`,j);return}}function g(j,w){if(j.path.type==="SubExpression")return K(w,"UNANALYZABLE","warning","Sub-expressions are not statically analyzable",j),{};if(j.params.length>0||j.hash){let A=i(j.path),F=w.helpers?.get(A);if(F){let z=F.params;if(z){let G=z.filter((H)=>!H.optional).length;if(j.params.length<G)K(w,"MISSING_ARGUMENT","error",`Helper "${A}" expects at least ${G} argument(s), but got ${j.params.length}`,j,{helperName:A,expected:`${G} argument(s)`,actual:`${j.params.length} argument(s)`})}for(let G=0;G<j.params.length;G++){let H=O(j.params[G],w,j),I=z?.[G];if(H&&I?.type){let L=I.type;if(!p(H,L)){let h=I.name;K(w,"TYPE_MISMATCH","error",`Helper "${A}" parameter "${h}" expects ${Q(L)}, but got ${Q(H)}`,j,{helperName:A,expected:Q(L),actual:Q(H)})}}}return F.returnType??{type:"string"}}return K(w,"UNKNOWN_HELPER","warning",`Unknown inline helper "${A}" — cannot analyze statically`,j,{helperName:A}),{type:"string"}}return O(j.path,w,j)??{}}function p(j,w){if(!w.type||!j.type)return!0;let A=Array.isArray(w.type)?w.type:[w.type];return(Array.isArray(j.type)?j.type:[j.type]).some((z)=>A.some((G)=>z===G||G==="number"&&z==="integer"||G==="integer"&&z==="number"))}function J(j,w){let A=C(j);if(A.length===0)return{type:"string"};let F=D(j);if(F)return g(F,w);let z=k(j);if(z)return f(z,w);if(A.every((H)=>H.type==="ContentStatement")){let H=A.map((L)=>L.value).join("").trim();if(H==="")return{type:"string"};let I=W(H);if(I)return{type:I}}for(let H of j.body)l(H,w);return{type:"string"}}function f(j,w){let A=r(j);switch(A){case"if":case"unless":{let F=U(j);if(F)O(F,w,j);else K(w,"MISSING_ARGUMENT","error",R(A),j,{helperName:A});let z=J(j.program,w);if(j.inverse){let G=J(j.inverse,w);if(T(z,G))return z;return Y({oneOf:[z,G]})}return z}case"each":{let F=U(j);if(!F){K(w,"MISSING_ARGUMENT","error",R("each"),j,{helperName:"each"});let I=w.current;if(w.current={},J(j.program,w),w.current=I,j.inverse)J(j.inverse,w);return{type:"string"}}let z=O(F,w,j);if(!z){let I=w.current;if(w.current={},J(j.program,w),w.current=I,j.inverse)J(j.inverse,w);return{type:"string"}}let G=N(z,w.root);if(!G){K(w,"TYPE_MISMATCH","error",_("each","an array",Q(z)),j,{helperName:"each",expected:"array",actual:Q(z)});let I=w.current;if(w.current={},J(j.program,w),w.current=I,j.inverse)J(j.inverse,w);return{type:"string"}}let H=w.current;if(w.current=G,J(j.program,w),w.current=H,j.inverse)J(j.inverse,w);return{type:"string"}}case"with":{let F=U(j);if(!F){K(w,"MISSING_ARGUMENT","error",R("with"),j,{helperName:"with"});let I=w.current;w.current={};let L=J(j.program,w);if(w.current=I,j.inverse)J(j.inverse,w);return L}let z=O(F,w,j),G=w.current;w.current=z??{};let H=J(j.program,w);if(w.current=G,j.inverse)J(j.inverse,w);return H}default:{let F=w.helpers?.get(A);if(F){for(let z of j.params)O(z,w,j);if(J(j.program,w),j.inverse)J(j.inverse,w);return F.returnType??{type:"string"}}if(K(w,"UNKNOWN_HELPER","warning",$(A),j,{helperName:A}),J(j.program,w),j.inverse)J(j.inverse,w);return{type:"string"}}}}function O(j,w,A){if(q(j))return w.current;let F=b(j);if(F.length===0){if(j.type==="StringLiteral")return{type:"string"};if(j.type==="NumberLiteral")return{type:"number"};if(j.type==="BooleanLiteral")return{type:"boolean"};if(j.type==="NullLiteral")return{type:"null"};if(j.type==="UndefinedLiteral")return{};K(w,"UNANALYZABLE","warning",B(j.type),A??j);return}let{cleanSegments:z,identifier:G}=E(F);if(G!==null)return a(z,G,w,A??j);let H=X(w.current,z);if(H===void 0){let I=z.join("."),L=V(w.current);K(w,"UNKNOWN_PROPERTY","error",Z(I,L),A??j,{path:I,availableProperties:L});return}return H}function a(j,w,A,F){let z=j.join(".");if(!A.identifierSchemas){K(A,"MISSING_IDENTIFIER_SCHEMAS","error",`Property "${z}:${w}" uses an identifier but no identifier schemas were provided`,F,{path:`${z}:${w}`,identifier:w});return}let G=A.identifierSchemas[w];if(!G){K(A,"UNKNOWN_IDENTIFIER","error",`Property "${z}:${w}" references identifier ${w} but no schema exists for this identifier`,F,{path:`${z}:${w}`,identifier:w});return}let H=X(G,j);if(H===void 0){let I=V(G);K(A,"IDENTIFIER_PROPERTY_NOT_FOUND","error",`Property "${z}" does not exist in the schema for identifier ${w}`,F,{path:z,identifier:w,availableProperties:I});return}return H}function U(j){return j.params[0]}function r(j){if(j.path.type==="PathExpression")return j.path.original;return""}function i(j){if(j.type==="PathExpression")return j.original;return""}function K(j,w,A,F,z,G){let H={severity:A,code:w,message:F};if(z&&"loc"in z&&z.loc)H.loc={start:{line:z.loc.start.line,column:z.loc.start.column},end:{line:z.loc.end.line,column:z.loc.end.column}},H.source=P(j.template,H.loc);if(G)H.details=G;j.diagnostics.push(H)}function Q(j){if(j.type)return Array.isArray(j.type)?j.type.join(" | "):j.type;if(j.oneOf)return"oneOf(...)";if(j.anyOf)return"anyOf(...)";if(j.allOf)return"allOf(...)";if(j.enum)return"enum";return"unknown"}export{o as c,n as d,f as e};
2
+
3
+ //# debugId=5BE61AD08B9B8A9B64756E2164756E21
4
+ //# sourceMappingURL=chunk-awgj10qg.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/analyzer.ts"],
4
+ "sourcesContent": [
5
+ "import type { JSONSchema7 } from \"json-schema\";\nimport {\n\tcreateMissingArgumentMessage,\n\tcreatePropertyNotFoundMessage,\n\tcreateTypeMismatchMessage,\n\tcreateUnanalyzableMessage,\n\tcreateUnknownHelperMessage,\n} from \"./errors.ts\";\nimport {\n\tdetectLiteralType,\n\textractExpressionIdentifier,\n\textractPathSegments,\n\tgetEffectiveBody,\n\tgetEffectivelySingleBlock,\n\tgetEffectivelySingleExpression,\n\tisThisExpression,\n\tparse,\n} from \"./parser.ts\";\nimport {\n\tresolveArrayItems,\n\tresolveSchemaPath,\n\tsimplifySchema,\n} from \"./schema-resolver.ts\";\nimport type {\n\tAnalysisResult,\n\tDiagnosticCode,\n\tDiagnosticDetails,\n\tHelperDefinition,\n\tTemplateDiagnostic,\n\tTemplateInput,\n\tTemplateInputObject,\n} from \"./types.ts\";\nimport {\n\tinferPrimitiveSchema,\n\tisLiteralInput,\n\tisObjectInput,\n} from \"./types.ts\";\nimport {\n\taggregateObjectAnalysis,\n\tdeepEqual,\n\textractSourceSnippet,\n\tgetSchemaPropertyNames,\n} from \"./utils.ts\";\n\n// ─── Static Analyzer ─────────────────────────────────────────────────────────\n// Static analysis of a Handlebars template against a JSON Schema v7\n// describing the available context.\n//\n// Merged architecture (v2):\n// A single AST traversal performs both **validation** and **return type\n// inference** simultaneously. This eliminates duplication between the former\n// `validate*` and `infer*` functions and improves performance by avoiding\n// a double traversal.\n//\n// Context:\n// The analysis context uses a **save/restore** pattern instead of creating\n// new objects on each recursion (`{ ...ctx, current: X }`). This reduces\n// GC pressure for deeply nested templates.\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// The `{{key:N}}` syntax allows referencing a variable from a specific\n// schema, identified by an integer N. The optional `identifierSchemas`\n// parameter provides a mapping `{ [id]: JSONSchema7 }`.\n//\n// Resolution rules:\n// - `{{meetingId}}` → validated against `inputSchema` (standard behavior)\n// - `{{meetingId:1}}` → validated against `identifierSchemas[1]`\n// - `{{meetingId:1}}` without `identifierSchemas[1]` → error\n\n// ─── Internal Types ──────────────────────────────────────────────────────────\n\n/** Context passed recursively during AST traversal */\ninterface AnalysisContext {\n\t/** Root schema (for resolving $refs) */\n\troot: JSONSchema7;\n\t/** Current context schema (changes with #each, #with) — mutated via save/restore */\n\tcurrent: JSONSchema7;\n\t/** Diagnostics accumulator */\n\tdiagnostics: TemplateDiagnostic[];\n\t/** Full template source (for extracting error snippets) */\n\ttemplate: string;\n\t/** Schemas by template identifier (for the {{key:N}} syntax) */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t/** Registered custom helpers (for static analysis) */\n\thelpers?: Map<string, HelperDefinition>;\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Statically analyzes a template against a JSON Schema v7 describing the\n * available context.\n *\n * Backward-compatible version — parses the template internally.\n *\n * @param template - The template string (e.g. `\"Hello {{user.name}}\"`)\n * @param inputSchema - JSON Schema v7 describing the available variables\n * @param identifierSchemas - (optional) Schemas by identifier `{ [id]: JSONSchema7 }`\n * @returns An `AnalysisResult` containing validity, diagnostics, and the\n * inferred output schema.\n */\nexport function analyze(\n\ttemplate: TemplateInput,\n\tinputSchema: JSONSchema7,\n\tidentifierSchemas?: Record<number, JSONSchema7>,\n): AnalysisResult {\n\tif (isObjectInput(template)) {\n\t\treturn analyzeObjectTemplate(template, inputSchema, identifierSchemas);\n\t}\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\tconst ast = parse(template);\n\treturn analyzeFromAst(ast, template, inputSchema, { identifierSchemas });\n}\n\n/**\n * Analyzes an object template recursively (standalone version).\n * Each property is analyzed individually, diagnostics are merged,\n * and the `outputSchema` reflects the object structure.\n */\nfunction analyzeObjectTemplate(\n\ttemplate: TemplateInputObject,\n\tinputSchema: JSONSchema7,\n\tidentifierSchemas?: Record<number, JSONSchema7>,\n): AnalysisResult {\n\treturn aggregateObjectAnalysis(Object.keys(template), (key) =>\n\t\tanalyze(template[key] as TemplateInput, inputSchema, identifierSchemas),\n\t);\n}\n\n/**\n * Statically analyzes a template from an already-parsed AST.\n *\n * This is the internal function used by `Typebars.compile()` and\n * `CompiledTemplate.analyze()` to avoid costly re-parsing.\n *\n * @param ast - The already-parsed Handlebars AST\n * @param template - The template source (for error snippets)\n * @param inputSchema - JSON Schema v7 describing the available variables\n * @param options - Additional options\n * @returns An `AnalysisResult`\n */\nexport function analyzeFromAst(\n\tast: hbs.AST.Program,\n\ttemplate: string,\n\tinputSchema: JSONSchema7,\n\toptions?: {\n\t\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t\thelpers?: Map<string, HelperDefinition>;\n\t},\n): AnalysisResult {\n\tconst ctx: AnalysisContext = {\n\t\troot: inputSchema,\n\t\tcurrent: inputSchema,\n\t\tdiagnostics: [],\n\t\ttemplate,\n\t\tidentifierSchemas: options?.identifierSchemas,\n\t\thelpers: options?.helpers,\n\t};\n\n\t// Single pass: type inference + validation in one traversal.\n\tconst outputSchema = inferProgramType(ast, ctx);\n\n\tconst hasErrors = ctx.diagnostics.some((d) => d.severity === \"error\");\n\n\treturn {\n\t\tvalid: !hasErrors,\n\t\tdiagnostics: ctx.diagnostics,\n\t\toutputSchema: simplifySchema(outputSchema),\n\t};\n}\n\n// ─── Unified AST Traversal ───────────────────────────────────────────────────\n// A single set of functions handles both validation (emitting diagnostics)\n// and type inference (returning a JSONSchema7).\n//\n// Main functions:\n// - `inferProgramType` — entry point for a Program (template body or block)\n// - `processStatement` — dispatches a statement (validation side-effects)\n// - `processMustache` — handles a MustacheStatement (expression or inline helper)\n// - `inferBlockType` — handles a BlockStatement (if, each, with, custom…)\n\n/**\n * Dispatches the processing of an individual statement.\n *\n * Called by `inferProgramType` in the \"mixed template\" case to validate\n * each statement while ignoring the returned type (the result is always\n * `string` for a mixed template).\n *\n * @returns The inferred schema for this statement, or `undefined` for\n * statements with no semantics (ContentStatement, CommentStatement).\n */\nfunction processStatement(\n\tstmt: hbs.AST.Statement,\n\tctx: AnalysisContext,\n): JSONSchema7 | undefined {\n\tswitch (stmt.type) {\n\t\tcase \"ContentStatement\":\n\t\tcase \"CommentStatement\":\n\t\t\t// Static text or comment — nothing to validate, no type to infer\n\t\t\treturn undefined;\n\n\t\tcase \"MustacheStatement\":\n\t\t\treturn processMustache(stmt as hbs.AST.MustacheStatement, ctx);\n\n\t\tcase \"BlockStatement\":\n\t\t\treturn inferBlockType(stmt as hbs.AST.BlockStatement, ctx);\n\n\t\tdefault:\n\t\t\t// Unrecognized AST node — emit a warning rather than an error\n\t\t\t// to avoid blocking on future Handlebars extensions.\n\t\t\taddDiagnostic(\n\t\t\t\tctx,\n\t\t\t\t\"UNANALYZABLE\",\n\t\t\t\t\"warning\",\n\t\t\t\t`Unsupported AST node type: \"${stmt.type}\"`,\n\t\t\t\tstmt,\n\t\t\t);\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Processes a MustacheStatement `{{expression}}` or `{{helper arg}}`.\n *\n * Distinguishes two cases:\n * 1. **Simple expression** (`{{name}}`, `{{user.age}}`) — resolution in the schema\n * 2. **Inline helper** (`{{uppercase name}}`) — params > 0 or hash present\n *\n * @returns The inferred schema for this expression\n */\nfunction processMustache(\n\tstmt: hbs.AST.MustacheStatement,\n\tctx: AnalysisContext,\n): JSONSchema7 {\n\t// Sub-expressions (nested helpers) are not supported for static\n\t// analysis — emit a warning.\n\tif (stmt.path.type === \"SubExpression\") {\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"UNANALYZABLE\",\n\t\t\t\"warning\",\n\t\t\t\"Sub-expressions are not statically analyzable\",\n\t\t\tstmt,\n\t\t);\n\t\treturn {};\n\t}\n\n\t// ── Inline helper detection ──────────────────────────────────────────────\n\t// If the MustacheStatement has parameters or a hash, it's a helper call\n\t// (e.g. `{{uppercase name}}`), not a simple expression.\n\tif (stmt.params.length > 0 || stmt.hash) {\n\t\tconst helperName = getExpressionName(stmt.path);\n\n\t\t// Check if the helper is registered\n\t\tconst helper = ctx.helpers?.get(helperName);\n\t\tif (helper) {\n\t\t\tconst helperParams = helper.params;\n\n\t\t\t// ── Check the number of required parameters ──────────────\n\t\t\tif (helperParams) {\n\t\t\t\tconst requiredCount = helperParams.filter((p) => !p.optional).length;\n\t\t\t\tif (stmt.params.length < requiredCount) {\n\t\t\t\t\taddDiagnostic(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\"MISSING_ARGUMENT\",\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t`Helper \"${helperName}\" expects at least ${requiredCount} argument(s), but got ${stmt.params.length}`,\n\t\t\t\t\t\tstmt,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thelperName,\n\t\t\t\t\t\t\texpected: `${requiredCount} argument(s)`,\n\t\t\t\t\t\t\tactual: `${stmt.params.length} argument(s)`,\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\t// ── Validate each parameter (existence + type) ───────────────\n\t\t\tfor (let i = 0; i < stmt.params.length; i++) {\n\t\t\t\tconst resolvedSchema = resolveExpressionWithDiagnostics(\n\t\t\t\t\tstmt.params[i] as hbs.AST.Expression,\n\t\t\t\t\tctx,\n\t\t\t\t\tstmt,\n\t\t\t\t);\n\n\t\t\t\t// Check type compatibility if the helper declares the\n\t\t\t\t// expected type for this parameter\n\t\t\t\tconst helperParam = helperParams?.[i];\n\t\t\t\tif (resolvedSchema && helperParam?.type) {\n\t\t\t\t\tconst expectedType = helperParam.type;\n\t\t\t\t\tif (!isParamTypeCompatible(resolvedSchema, expectedType)) {\n\t\t\t\t\t\tconst paramName = helperParam.name;\n\t\t\t\t\t\taddDiagnostic(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\t`Helper \"${helperName}\" parameter \"${paramName}\" expects ${schemaTypeLabel(expectedType)}, but got ${schemaTypeLabel(resolvedSchema)}`,\n\t\t\t\t\t\t\tstmt,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thelperName,\n\t\t\t\t\t\t\t\texpected: schemaTypeLabel(expectedType),\n\t\t\t\t\t\t\t\tactual: schemaTypeLabel(resolvedSchema),\n\t\t\t\t\t\t\t},\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\treturn helper.returnType ?? { type: \"string\" };\n\t\t}\n\n\t\t// Unknown inline helper — warning\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"UNKNOWN_HELPER\",\n\t\t\t\"warning\",\n\t\t\t`Unknown inline helper \"${helperName}\" — cannot analyze statically`,\n\t\t\tstmt,\n\t\t\t{ helperName },\n\t\t);\n\t\treturn { type: \"string\" };\n\t}\n\n\t// ── Simple expression ────────────────────────────────────────────────────\n\treturn resolveExpressionWithDiagnostics(stmt.path, ctx, stmt) ?? {};\n}\n\n/**\n * Checks whether a resolved type is compatible with the type expected\n * by a helper parameter.\n *\n * Compatibility rules:\n * - If either schema has no `type`, validation is not possible → compatible\n * - `integer` is compatible with `number` (integer ⊂ number)\n * - For multiple types (e.g. `[\"string\", \"number\"]`), at least one resolved\n * type must match one expected type\n */\nfunction isParamTypeCompatible(\n\tresolved: JSONSchema7,\n\texpected: JSONSchema7,\n): boolean {\n\t// If either has no type info, we cannot validate\n\tif (!expected.type || !resolved.type) return true;\n\n\tconst expectedTypes = Array.isArray(expected.type)\n\t\t? expected.type\n\t\t: [expected.type];\n\tconst resolvedTypes = Array.isArray(resolved.type)\n\t\t? resolved.type\n\t\t: [resolved.type];\n\n\t// At least one resolved type must be compatible with one expected type\n\treturn resolvedTypes.some((rt) =>\n\t\texpectedTypes.some(\n\t\t\t(et) =>\n\t\t\t\trt === et ||\n\t\t\t\t// integer is a subtype of number\n\t\t\t\t(et === \"number\" && rt === \"integer\") ||\n\t\t\t\t(et === \"integer\" && rt === \"number\"),\n\t\t),\n\t);\n}\n\n/**\n * Infers the output type of a `Program` (template body or block body).\n *\n * Handles 4 cases, from most specific to most general:\n *\n * 1. **Single expression** `{{expr}}` → type of the expression\n * 2. **Single block** `{{#if}}…{{/if}}` → type of the block\n * 3. **Pure text content** → literal detection (number, boolean, null)\n * 4. **Mixed template** → always `string` (concatenation)\n *\n * Validation is performed alongside inference: each expression and block\n * is validated during processing.\n */\nfunction inferProgramType(\n\tprogram: hbs.AST.Program,\n\tctx: AnalysisContext,\n): JSONSchema7 {\n\tconst effective = getEffectiveBody(program);\n\n\t// No significant statements → empty string\n\tif (effective.length === 0) {\n\t\treturn { type: \"string\" };\n\t}\n\n\t// ── Case 1: single expression {{expr}} ─────────────────────────────────\n\tconst singleExpr = getEffectivelySingleExpression(program);\n\tif (singleExpr) {\n\t\treturn processMustache(singleExpr, ctx);\n\t}\n\n\t// ── Case 2: single block {{#if}}, {{#each}}, {{#with}}, … ──────────────\n\tconst singleBlock = getEffectivelySingleBlock(program);\n\tif (singleBlock) {\n\t\treturn inferBlockType(singleBlock, ctx);\n\t}\n\n\t// ── Case 3: only ContentStatements (no expressions) ────────────────────\n\t// If the concatenated (trimmed) text is a typed literal (number, boolean,\n\t// null), we infer the corresponding type.\n\tconst allContent = effective.every((s) => s.type === \"ContentStatement\");\n\tif (allContent) {\n\t\tconst text = effective\n\t\t\t.map((s) => (s as hbs.AST.ContentStatement).value)\n\t\t\t.join(\"\")\n\t\t\t.trim();\n\n\t\tif (text === \"\") return { type: \"string\" };\n\n\t\tconst literalType = detectLiteralType(text);\n\t\tif (literalType) return { type: literalType };\n\t}\n\n\t// ── Case 4: mixed template (text + expressions, multiple blocks…) ──────\n\t// Traverse all statements for validation (side-effects: diagnostics).\n\t// The result is always string (concatenation).\n\tfor (const stmt of program.body) {\n\t\tprocessStatement(stmt, ctx);\n\t}\n\treturn { type: \"string\" };\n}\n\n/**\n * Infers the output type of a BlockStatement and validates its content.\n *\n * Supports built-in helpers (`if`, `unless`, `each`, `with`) and custom\n * helpers registered via `Typebars.registerHelper()`.\n *\n * Uses the **save/restore** pattern for context: instead of creating a new\n * object `{ ...ctx, current: X }` on each recursion, we save `ctx.current`,\n * mutate it, process the body, then restore. This reduces GC pressure for\n * deeply nested templates.\n */\nfunction inferBlockType(\n\tstmt: hbs.AST.BlockStatement,\n\tctx: AnalysisContext,\n): JSONSchema7 {\n\tconst helperName = getBlockHelperName(stmt);\n\n\tswitch (helperName) {\n\t\t// ── if / unless ──────────────────────────────────────────────────────\n\t\t// Validate the condition argument, then infer types from both branches.\n\t\tcase \"if\":\n\t\tcase \"unless\": {\n\t\t\tconst arg = getBlockArgument(stmt);\n\t\t\tif (arg) {\n\t\t\t\tresolveExpressionWithDiagnostics(arg, ctx, stmt);\n\t\t\t} else {\n\t\t\t\taddDiagnostic(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"MISSING_ARGUMENT\",\n\t\t\t\t\t\"error\",\n\t\t\t\t\tcreateMissingArgumentMessage(helperName),\n\t\t\t\t\tstmt,\n\t\t\t\t\t{ helperName },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Infer the type of the \"then\" branch\n\t\t\tconst thenType = inferProgramType(stmt.program, ctx);\n\n\t\t\tif (stmt.inverse) {\n\t\t\t\tconst elseType = inferProgramType(stmt.inverse, ctx);\n\t\t\t\t// If both branches have the same type → single type\n\t\t\t\tif (deepEqual(thenType, elseType)) return thenType;\n\t\t\t\t// Otherwise → union of both types\n\t\t\t\treturn simplifySchema({ oneOf: [thenType, elseType] });\n\t\t\t}\n\n\t\t\t// No else branch → the result is the type of the then branch\n\t\t\t// (conceptually optional, but Handlebars returns \"\" for falsy)\n\t\t\treturn thenType;\n\t\t}\n\n\t\t// ── each ─────────────────────────────────────────────────────────────\n\t\t// Resolve the collection schema, then validate the body with the item\n\t\t// schema as the new context.\n\t\tcase \"each\": {\n\t\t\tconst arg = getBlockArgument(stmt);\n\t\t\tif (!arg) {\n\t\t\t\taddDiagnostic(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"MISSING_ARGUMENT\",\n\t\t\t\t\t\"error\",\n\t\t\t\t\tcreateMissingArgumentMessage(\"each\"),\n\t\t\t\t\tstmt,\n\t\t\t\t\t{ helperName: \"each\" },\n\t\t\t\t);\n\t\t\t\t// Validate the body with an empty context (best-effort)\n\t\t\t\tconst saved = ctx.current;\n\t\t\t\tctx.current = {};\n\t\t\t\tinferProgramType(stmt.program, ctx);\n\t\t\t\tctx.current = saved;\n\t\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\t\t\t\treturn { type: \"string\" };\n\t\t\t}\n\n\t\t\tconst collectionSchema = resolveExpressionWithDiagnostics(arg, ctx, stmt);\n\t\t\tif (!collectionSchema) {\n\t\t\t\t// The path could not be resolved — diagnostic already emitted.\n\t\t\t\tconst saved = ctx.current;\n\t\t\t\tctx.current = {};\n\t\t\t\tinferProgramType(stmt.program, ctx);\n\t\t\t\tctx.current = saved;\n\t\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\t\t\t\treturn { type: \"string\" };\n\t\t\t}\n\n\t\t\t// Resolve the schema of the array elements\n\t\t\tconst itemSchema = resolveArrayItems(collectionSchema, ctx.root);\n\t\t\tif (!itemSchema) {\n\t\t\t\taddDiagnostic(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"TYPE_MISMATCH\",\n\t\t\t\t\t\"error\",\n\t\t\t\t\tcreateTypeMismatchMessage(\n\t\t\t\t\t\t\"each\",\n\t\t\t\t\t\t\"an array\",\n\t\t\t\t\t\tschemaTypeLabel(collectionSchema),\n\t\t\t\t\t),\n\t\t\t\t\tstmt,\n\t\t\t\t\t{\n\t\t\t\t\t\thelperName: \"each\",\n\t\t\t\t\t\texpected: \"array\",\n\t\t\t\t\t\tactual: schemaTypeLabel(collectionSchema),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\t// Validate the body with an empty context (best-effort)\n\t\t\t\tconst saved = ctx.current;\n\t\t\t\tctx.current = {};\n\t\t\t\tinferProgramType(stmt.program, ctx);\n\t\t\t\tctx.current = saved;\n\t\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\t\t\t\treturn { type: \"string\" };\n\t\t\t}\n\n\t\t\t// Validate the body with the item schema as the new context\n\t\t\tconst saved = ctx.current;\n\t\t\tctx.current = itemSchema;\n\t\t\tinferProgramType(stmt.program, ctx);\n\t\t\tctx.current = saved;\n\n\t\t\t// The inverse branch ({{else}}) keeps the parent context\n\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\n\t\t\t// An each concatenates renders → always string\n\t\t\treturn { type: \"string\" };\n\t\t}\n\n\t\t// ── with ─────────────────────────────────────────────────────────────\n\t\t// Resolve the inner schema, then validate the body with it as the\n\t\t// new context.\n\t\tcase \"with\": {\n\t\t\tconst arg = getBlockArgument(stmt);\n\t\t\tif (!arg) {\n\t\t\t\taddDiagnostic(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"MISSING_ARGUMENT\",\n\t\t\t\t\t\"error\",\n\t\t\t\t\tcreateMissingArgumentMessage(\"with\"),\n\t\t\t\t\tstmt,\n\t\t\t\t\t{ helperName: \"with\" },\n\t\t\t\t);\n\t\t\t\t// Validate the body with an empty context\n\t\t\t\tconst saved = ctx.current;\n\t\t\t\tctx.current = {};\n\t\t\t\tconst result = inferProgramType(stmt.program, ctx);\n\t\t\t\tctx.current = saved;\n\t\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tconst innerSchema = resolveExpressionWithDiagnostics(arg, ctx, stmt);\n\n\t\t\tconst saved = ctx.current;\n\t\t\tctx.current = innerSchema ?? {};\n\t\t\tconst result = inferProgramType(stmt.program, ctx);\n\t\t\tctx.current = saved;\n\n\t\t\t// The inverse branch keeps the parent context\n\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\n\t\t\treturn result;\n\t\t}\n\n\t\t// ── Custom or unknown helper ─────────────────────────────────────────\n\t\tdefault: {\n\t\t\tconst helper = ctx.helpers?.get(helperName);\n\t\t\tif (helper) {\n\t\t\t\t// Registered custom helper — validate parameters\n\t\t\t\tfor (const param of stmt.params) {\n\t\t\t\t\tresolveExpressionWithDiagnostics(\n\t\t\t\t\t\tparam as hbs.AST.Expression,\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\tstmt,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Validate the body with the current context\n\t\t\t\tinferProgramType(stmt.program, ctx);\n\t\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\t\t\t\treturn helper.returnType ?? { type: \"string\" };\n\t\t\t}\n\n\t\t\t// Unknown helper — warning\n\t\t\taddDiagnostic(\n\t\t\t\tctx,\n\t\t\t\t\"UNKNOWN_HELPER\",\n\t\t\t\t\"warning\",\n\t\t\t\tcreateUnknownHelperMessage(helperName),\n\t\t\t\tstmt,\n\t\t\t\t{ helperName },\n\t\t\t);\n\t\t\t// Still validate the body with the current context (best-effort)\n\t\t\tinferProgramType(stmt.program, ctx);\n\t\t\tif (stmt.inverse) inferProgramType(stmt.inverse, ctx);\n\t\t\treturn { type: \"string\" };\n\t\t}\n\t}\n}\n\n// ─── Expression Resolution ───────────────────────────────────────────────────\n\n/**\n * Resolves an AST expression to a sub-schema, emitting a diagnostic\n * if the path cannot be resolved.\n *\n * Handles the `{{key:N}}` syntax:\n * - If the expression has an identifier N → resolution in `identifierSchemas[N]`\n * - If identifier N has no associated schema → error\n * - If no identifier → resolution in `ctx.current` (standard behavior)\n *\n * @returns The resolved sub-schema, or `undefined` if the path is invalid.\n */\nfunction resolveExpressionWithDiagnostics(\n\texpr: hbs.AST.Expression,\n\tctx: AnalysisContext,\n\t/** Parent AST node (for diagnostic location) */\n\tparentNode?: hbs.AST.Node,\n): JSONSchema7 | undefined {\n\t// Handle `this` / `.` → return the current context\n\tif (isThisExpression(expr)) {\n\t\treturn ctx.current;\n\t}\n\n\tconst segments = extractPathSegments(expr);\n\tif (segments.length === 0) {\n\t\t// Expression that is not a PathExpression (e.g. literal, SubExpression)\n\t\tif (expr.type === \"StringLiteral\") return { type: \"string\" };\n\t\tif (expr.type === \"NumberLiteral\") return { type: \"number\" };\n\t\tif (expr.type === \"BooleanLiteral\") return { type: \"boolean\" };\n\t\tif (expr.type === \"NullLiteral\") return { type: \"null\" };\n\t\tif (expr.type === \"UndefinedLiteral\") return {};\n\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"UNANALYZABLE\",\n\t\t\t\"warning\",\n\t\t\tcreateUnanalyzableMessage(expr.type),\n\t\t\tparentNode ?? expr,\n\t\t);\n\t\treturn undefined;\n\t}\n\n\t// ── Identifier extraction ──────────────────────────────────────────────\n\tconst { cleanSegments, identifier } = extractExpressionIdentifier(segments);\n\n\tif (identifier !== null) {\n\t\t// The expression uses the {{key:N}} syntax — resolve from\n\t\t// the schema of identifier N.\n\t\treturn resolveWithIdentifier(\n\t\t\tcleanSegments,\n\t\t\tidentifier,\n\t\t\tctx,\n\t\t\tparentNode ?? expr,\n\t\t);\n\t}\n\n\t// ── Standard resolution (no identifier) ────────────────────────────────\n\tconst resolved = resolveSchemaPath(ctx.current, cleanSegments);\n\tif (resolved === undefined) {\n\t\tconst fullPath = cleanSegments.join(\".\");\n\t\tconst availableProperties = getSchemaPropertyNames(ctx.current);\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"UNKNOWN_PROPERTY\",\n\t\t\t\"error\",\n\t\t\tcreatePropertyNotFoundMessage(fullPath, availableProperties),\n\t\t\tparentNode ?? expr,\n\t\t\t{ path: fullPath, availableProperties },\n\t\t);\n\t\treturn undefined;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Resolves an expression with identifier `{{key:N}}` by looking up the\n * schema associated with identifier N.\n *\n * Emits an error diagnostic if:\n * - No `identifierSchemas` were provided\n * - Identifier N has no associated schema\n * - The property does not exist in the identifier's schema\n */\nfunction resolveWithIdentifier(\n\tcleanSegments: string[],\n\tidentifier: number,\n\tctx: AnalysisContext,\n\tnode: hbs.AST.Node,\n): JSONSchema7 | undefined {\n\tconst fullPath = cleanSegments.join(\".\");\n\n\t// No identifierSchemas provided at all\n\tif (!ctx.identifierSchemas) {\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"MISSING_IDENTIFIER_SCHEMAS\",\n\t\t\t\"error\",\n\t\t\t`Property \"${fullPath}:${identifier}\" uses an identifier but no identifier schemas were provided`,\n\t\t\tnode,\n\t\t\t{ path: `${fullPath}:${identifier}`, identifier },\n\t\t);\n\t\treturn undefined;\n\t}\n\n\t// The identifier does not exist in the provided schemas\n\tconst idSchema = ctx.identifierSchemas[identifier];\n\tif (!idSchema) {\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"UNKNOWN_IDENTIFIER\",\n\t\t\t\"error\",\n\t\t\t`Property \"${fullPath}:${identifier}\" references identifier ${identifier} but no schema exists for this identifier`,\n\t\t\tnode,\n\t\t\t{ path: `${fullPath}:${identifier}`, identifier },\n\t\t);\n\t\treturn undefined;\n\t}\n\n\t// Resolve the path within the identifier's schema\n\tconst resolved = resolveSchemaPath(idSchema, cleanSegments);\n\tif (resolved === undefined) {\n\t\tconst availableProperties = getSchemaPropertyNames(idSchema);\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"IDENTIFIER_PROPERTY_NOT_FOUND\",\n\t\t\t\"error\",\n\t\t\t`Property \"${fullPath}\" does not exist in the schema for identifier ${identifier}`,\n\t\t\tnode,\n\t\t\t{\n\t\t\t\tpath: fullPath,\n\t\t\t\tidentifier,\n\t\t\t\tavailableProperties,\n\t\t\t},\n\t\t);\n\t\treturn undefined;\n\t}\n\n\treturn resolved;\n}\n\n// ─── Utilities ───────────────────────────────────────────────────────────────\n\n/**\n * Extracts the first argument of a BlockStatement.\n *\n * In the Handlebars AST, for `{{#if active}}`:\n * - `stmt.path` → PathExpression(\"if\") ← the helper name\n * - `stmt.params[0]` → PathExpression(\"active\") ← the actual argument\n *\n * @returns The argument expression, or `undefined` if the block has no argument.\n */\nfunction getBlockArgument(\n\tstmt: hbs.AST.BlockStatement,\n): hbs.AST.Expression | undefined {\n\treturn stmt.params[0] as hbs.AST.Expression | undefined;\n}\n\n/**\n * Retrieves the helper name from a BlockStatement (e.g. \"if\", \"each\", \"with\").\n */\nfunction getBlockHelperName(stmt: hbs.AST.BlockStatement): string {\n\tif (stmt.path.type === \"PathExpression\") {\n\t\treturn (stmt.path as hbs.AST.PathExpression).original;\n\t}\n\treturn \"\";\n}\n\n/**\n * Retrieves the name of an expression (first segment of the PathExpression).\n * Used to identify inline helpers.\n */\nfunction getExpressionName(expr: hbs.AST.Expression): string {\n\tif (expr.type === \"PathExpression\") {\n\t\treturn (expr as hbs.AST.PathExpression).original;\n\t}\n\treturn \"\";\n}\n\n/**\n * Adds an enriched diagnostic to the analysis context.\n *\n * Each diagnostic includes:\n * - A machine-readable `code` for the frontend\n * - A human-readable `message` describing the problem\n * - A `source` snippet from the template (if the position is available)\n * - Structured `details` for debugging\n */\nfunction addDiagnostic(\n\tctx: AnalysisContext,\n\tcode: DiagnosticCode,\n\tseverity: \"error\" | \"warning\",\n\tmessage: string,\n\tnode?: hbs.AST.Node,\n\tdetails?: DiagnosticDetails,\n): void {\n\tconst diagnostic: TemplateDiagnostic = { severity, code, message };\n\n\t// Extract the position and source snippet if available\n\tif (node && \"loc\" in node && node.loc) {\n\t\tdiagnostic.loc = {\n\t\t\tstart: { line: node.loc.start.line, column: node.loc.start.column },\n\t\t\tend: { line: node.loc.end.line, column: node.loc.end.column },\n\t\t};\n\t\t// Extract the template fragment around the error\n\t\tdiagnostic.source = extractSourceSnippet(ctx.template, diagnostic.loc);\n\t}\n\n\tif (details) {\n\t\tdiagnostic.details = details;\n\t}\n\n\tctx.diagnostics.push(diagnostic);\n}\n\n/**\n * Returns a human-readable label for a schema's type (for error messages).\n */\nfunction schemaTypeLabel(schema: JSONSchema7): string {\n\tif (schema.type) {\n\t\treturn Array.isArray(schema.type) ? schema.type.join(\" | \") : schema.type;\n\t}\n\tif (schema.oneOf) return \"oneOf(...)\";\n\tif (schema.anyOf) return \"anyOf(...)\";\n\tif (schema.allOf) return \"allOf(...)\";\n\tif (schema.enum) return \"enum\";\n\treturn \"unknown\";\n}\n\n// ─── Export for Internal Use ─────────────────────────────────────────────────\n// `inferBlockType` is exported to allow targeted unit tests\n// on block type inference.\nexport { inferBlockType };\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "5BE61AD08B9B8A9B64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,7 @@
1
+ function P(w,G){if(w===G)return!0;if(w===null||G===null)return!1;if(typeof w!==typeof G)return!1;if(Array.isArray(w)){if(!Array.isArray(G))return!1;if(w.length!==G.length)return!1;for(let F=0;F<w.length;F++)if(!P(w[F],G[F]))return!1;return!0}if(typeof w==="object"){let F=w,H=G,I=Object.keys(F),J=Object.keys(H);if(I.length!==J.length)return!1;for(let M of I)if(!(M in H)||!P(F[M],H[M]))return!1;return!0}return!1}class Q{capacity;cache=new Map;constructor(w){this.capacity=w;if(w<1)throw Error("LRUCache capacity must be at least 1")}get(w){if(!this.cache.has(w))return;let G=this.cache.get(w);return this.cache.delete(w),this.cache.set(w,G),G}set(w,G){if(this.cache.has(w))this.cache.delete(w);else if(this.cache.size>=this.capacity){let F=this.cache.keys().next().value;if(F!==void 0)this.cache.delete(F)}this.cache.set(w,G)}has(w){return this.cache.has(w)}delete(w){return this.cache.delete(w)}clear(){this.cache.clear()}get size(){return this.cache.size}}function S(w,G){let F=w.split(`
2
+ `),H=G.start.line-1,I=G.end.line-1;if(H<0||H>=F.length)return"";if(H===I)return(F[H]??"").trim();let J=Math.min(I,F.length-1);return F.slice(H,J+1).map((M)=>M.trimEnd()).join(`
3
+ `).trim()}function T(w){let G=new Set;if(w.properties)for(let F of Object.keys(w.properties))G.add(F);for(let F of["allOf","anyOf","oneOf"]){let H=w[F];if(H)for(let I of H){if(typeof I==="boolean")continue;if(I.properties)for(let J of Object.keys(I.properties))G.add(J)}}return Array.from(G).sort()}function U(w,G){let F=[],H={},I=!0;for(let J of w){let M=G(J);if(!M.valid)I=!1;F.push(...M.diagnostics),H[J]=M.outputSchema}return{valid:I,diagnostics:F,outputSchema:{type:"object",properties:H,required:w}}}function W(w,G){let F=[],H={},I={},J=!0;for(let O of w){let N=G(O);if(!N.analysis.valid)J=!1;F.push(...N.analysis.diagnostics),H[O]=N.analysis.outputSchema,I[O]=N.value}return{analysis:{valid:J,diagnostics:F,outputSchema:{type:"object",properties:H,required:w}},value:J?I:void 0}}
4
+ export{P,Q,S as R,T as S,U as T,W as U};
5
+
6
+ //# debugId=7D2B6D65A23A9D4664756E2164756E21
7
+ //# sourceMappingURL=chunk-fhvf5y4x.js.map