typebars 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyzer.js +1 -1
- package/dist/{chunk-kznb0bev.js → chunk-ecs3yth2.js} +3 -3
- package/dist/{chunk-z6yh5qvc.js.map → chunk-ecs3yth2.js.map} +1 -1
- package/dist/{chunk-qpzzr2rd.js → chunk-efqd0598.js} +3 -3
- package/dist/{chunk-qpzzr2rd.js.map → chunk-efqd0598.js.map} +1 -1
- package/dist/chunk-jms1ndxn.js +5 -0
- package/dist/chunk-jms1ndxn.js.map +10 -0
- package/dist/{chunk-4zv02svp.js → chunk-p5efqsxw.js} +3 -3
- package/dist/{chunk-4zv02svp.js.map → chunk-p5efqsxw.js.map} +1 -1
- package/dist/{chunk-1gm6cf0e.js → chunk-rkrp4ysw.js} +3 -3
- package/dist/{chunk-1gm6cf0e.js.map → chunk-rkrp4ysw.js.map} +1 -1
- package/dist/chunk-t6n956qz.js +4 -0
- package/dist/chunk-t6n956qz.js.map +10 -0
- package/dist/chunk-xd2vmd03.js +5 -0
- package/dist/{chunk-7j6q1e3z.js.map → chunk-xd2vmd03.js.map} +2 -2
- package/dist/chunk-zh1e0yhd.js +7 -0
- package/dist/chunk-zh1e0yhd.js.map +10 -0
- package/dist/compiled-template.js +1 -1
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/executor.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/parser.js +1 -1
- package/dist/schema-resolver.d.ts +38 -0
- package/dist/schema-resolver.js +2 -2
- package/dist/schema-resolver.js.map +1 -1
- package/dist/typebars.js +1 -1
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/package.json +40 -40
- package/dist/chunk-1qwj7pjc.js +0 -4
- package/dist/chunk-1qwj7pjc.js.map +0 -10
- package/dist/chunk-60gk3q7z.js +0 -5
- package/dist/chunk-60gk3q7z.js.map +0 -10
- package/dist/chunk-6c0pw73w.js +0 -7
- package/dist/chunk-6c0pw73w.js.map +0 -10
- package/dist/chunk-7j6q1e3z.js +0 -5
- package/dist/chunk-8g0d6h85.js +0 -5
- package/dist/chunk-8g0d6h85.js.map +0 -10
- package/dist/chunk-9mg6qfrs.js +0 -5
- package/dist/chunk-9mg6qfrs.js.map +0 -10
- package/dist/chunk-a37yzqra.js +0 -5
- package/dist/chunk-a37yzqra.js.map +0 -11
- package/dist/chunk-awgj10qg.js +0 -4
- package/dist/chunk-awgj10qg.js.map +0 -10
- package/dist/chunk-fhvf5y4x.js +0 -7
- package/dist/chunk-fhvf5y4x.js.map +0 -10
- package/dist/chunk-ggdfaqhe.js +0 -5
- package/dist/chunk-ggdfaqhe.js.map +0 -10
- package/dist/chunk-hc1jnqaw.js +0 -5
- package/dist/chunk-hc1jnqaw.js.map +0 -10
- package/dist/chunk-kznb0bev.js.map +0 -10
- package/dist/chunk-mx8neh7q.js +0 -5
- package/dist/chunk-mx8neh7q.js.map +0 -10
- package/dist/chunk-p3xzf1ew.js +0 -5
- package/dist/chunk-p3xzf1ew.js.map +0 -10
- package/dist/chunk-qh2r1pa1.js +0 -5
- package/dist/chunk-qh2r1pa1.js.map +0 -10
- package/dist/chunk-vka4e61h.js +0 -7
- package/dist/chunk-vka4e61h.js.map +0 -10
- package/dist/chunk-xbvk4ygq.js +0 -5
- package/dist/chunk-xbvk4ygq.js.map +0 -11
- package/dist/chunk-ybh51hbe.js +0 -7
- package/dist/chunk-ybh51hbe.js.map +0 -10
- package/dist/chunk-yczpjh73.js +0 -4
- package/dist/chunk-yczpjh73.js.map +0 -10
- package/dist/chunk-yraqh2tz.js +0 -5
- package/dist/chunk-yraqh2tz.js.map +0 -10
- package/dist/chunk-z6yh5qvc.js +0 -5
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/parser.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import Handlebars from \"handlebars\";\nimport { TemplateParseError } from \"./errors.ts\";\nimport { LRUCache } from \"./utils.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// 4. Cacher les ASTs parsés via un LRU cache pour éviter les re-parsings\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// ─── Cache global d'AST ──────────────────────────────────────────────────────\n// Le parsing Handlebars est coûteux. Ce cache module-level évite de re-parser\n// le même template string lors d'appels répétés à `parse()`.\n// Taille par défaut : 128 entrées (suffisant pour la majorité des usages).\nconst globalAstCache = new LRUCache<string, hbs.AST.Program>(128);\n\n/**\n * Parse un template string et retourne l'AST Handlebars.\n *\n * Les résultats sont cachés automatiquement : appeler `parse()` deux fois\n * avec le même template ne re-parse pas.\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\t// Vérifier le cache en premier\n\tconst cached = globalAstCache.get(template);\n\tif (cached) return cached;\n\n\ttry {\n\t\tconst ast = Handlebars.parse(template);\n\t\tglobalAstCache.set(template, ast);\n\t\treturn ast;\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 * Parse un template sans utiliser le cache. Utile pour les benchmarks\n * ou quand on veut un AST frais garanti.\n *\n * @param template - La chaîne de template à parser\n * @returns L'AST racine (`hbs.AST.Program`)\n * @throws {TemplateParseError} si la syntaxe du template est invalide\n */\nexport function parseUncached(template: string): hbs.AST.Program {\n\ttry {\n\t\treturn Handlebars.parse(template);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\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\t\tthrow new TemplateParseError(message, loc);\n\t}\n}\n\n/**\n * Vide le cache global d'AST. Utile pour les tests ou pour libérer\n * la mémoire si beaucoup de templates uniques ont été parsés.\n */\nexport function clearParseCache(): void {\n\tglobalAstCache.clear();\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 du fast-path ──────────────────────────────────────────────────\n// Pour les templates constitués uniquement de texte et d'expressions simples\n// (pas de blocs, pas de helpers avec paramètres), on peut court-circuiter\n// Handlebars et faire un simple remplacement de variables.\n\n/**\n * Détermine si un AST peut être exécuté via le fast-path (concaténation\n * directe sans passer par `Handlebars.compile()`).\n *\n * Le fast-path est possible quand le template ne contient que :\n * - Des `ContentStatement` (texte statique)\n * - Des `MustacheStatement` simples (sans params, sans hash)\n *\n * Cela exclut :\n * - Les blocs (`{{#if}}`, `{{#each}}`, etc.)\n * - Les helpers inline (`{{uppercase name}}`)\n * - Les sub-expressions\n *\n * @param ast - L'AST parsé du template\n * @returns `true` si le template peut utiliser le fast-path\n */\nexport function canUseFastPath(ast: hbs.AST.Program): boolean {\n\treturn ast.body.every(\n\t\t(s) =>\n\t\t\ts.type === \"ContentStatement\" ||\n\t\t\t(s.type === \"MustacheStatement\" &&\n\t\t\t\t(s as hbs.AST.MustacheStatement).params.length === 0 &&\n\t\t\t\t!(s as hbs.AST.MustacheStatement).hash),\n\t);\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": "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",
|
|
8
|
-
"debugId": "3C85E965B62779F664756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-hc1jnqaw.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{e as X,g as Y,h as Z,i as _,j as $,k,l as A,o as B}from"./chunk-9mg6qfrs.js";import{u as Q,v as R,w as U}from"./chunk-qh2r1pa1.js";function g(b,j,w){let q=X(b),z={root:j,current:j,diagnostics:[],identifierSchemas:w},F=O(q,z);return{valid:!z.diagnostics.some((K)=>K.severity==="error"),diagnostics:z.diagnostics,outputSchema:U(F)}}function C(b,j){for(let w of b.body)P(w,j)}function P(b,j){switch(b.type){case"ContentStatement":break;case"MustacheStatement":D(b,j);break;case"BlockStatement":N(b,j);break;case"CommentStatement":break;default:H(j,"warning",`Unsupported AST node type: "${b.type}"`,b)}}function D(b,j){if(b.path.type==="SubExpression"){H(j,"warning","Sub-expressions are not statically analyzable",b);return}L(b.path,j,b)}function M(b){return b.params[0]}function N(b,j){let w=V(b);switch(w){case"if":case"unless":W(b,j);break;case"each":T(b,j);break;case"with":u(b,j);break;default:if(H(j,"warning",`Unknown block helper "{{#${w}}}" — cannot analyze statically`,b),C(b.program,j),b.inverse)C(b.inverse,j)}}function W(b,j){let w=M(b);if(w)L(w,j,b);else H(j,"error",`"{{#${V(b)}}}" requires an argument`,b);if(C(b.program,j),b.inverse)C(b.inverse,j)}function T(b,j){let w=M(b);if(!w){if(H(j,"error",'"{{#each}}" requires an argument',b),C(b.program,{...j,current:{}}),b.inverse)C(b.inverse,j);return}let q=L(w,j,b);if(!q){if(C(b.program,{...j,current:{}}),b.inverse)C(b.inverse,j);return}let z=R(q,j.root);if(!z){if(H(j,"error",`"{{#each}}" expects an array, but resolved schema has type "${I(q)}"`,b),C(b.program,{...j,current:{}}),b.inverse)C(b.inverse,j);return}if(C(b.program,{...j,current:z}),b.inverse)C(b.inverse,j)}function u(b,j){let w=M(b);if(!w){if(H(j,"error",'"{{#with}}" requires an argument',b),C(b.program,{...j,current:{}}),b.inverse)C(b.inverse,j);return}let q=L(w,j,b);if(!q){if(C(b.program,{...j,current:{}}),b.inverse)C(b.inverse,j);return}if(C(b.program,{...j,current:q}),b.inverse)C(b.inverse,j)}function E(b,j){return L(b,j)??{}}function O(b,j){let w=_(b);if(w.length===0)return{type:"string"};let q=k(b);if(q)return E(q.path,j);let z=$(b);if(z)return y(z,j);if(w.every((G)=>G.type==="ContentStatement")){let G=w.map((J)=>J.value).join("").trim();if(G==="")return{type:"string"};let K=A(G);if(K)return{type:K}}return C(b,j),{type:"string"}}function y(b,j){switch(V(b)){case"if":case"unless":{let q=M(b);if(q)L(q,j,b);let z=O(b.program,j);if(b.inverse){let F=O(b.inverse,j),G=JSON.stringify(z),K=JSON.stringify(F);if(G===K)return z;return U({oneOf:[z,F]})}return z}case"each":{let q=M(b);if(q){let z=L(q,j,b);if(z){let F=R(z,j.root);if(F)C(b.program,{...j,current:F});else H(j,"error",`"{{#each}}" expects an array, but resolved schema has type "${I(z)}"`,b)}}return{type:"string"}}case"with":{let q=M(b);if(q){let z=L(q,j,b);if(z)return O(b.program,{...j,current:z})}return O(b.program,{...j,current:{}})}default:{if(C(b.program,j),b.inverse)C(b.inverse,j);return{type:"string"}}}}function L(b,j,w){if(Z(b))return j.current;let q=Y(b);if(q.length===0){if(b.type==="StringLiteral")return{type:"string"};if(b.type==="NumberLiteral")return{type:"number"};if(b.type==="BooleanLiteral")return{type:"boolean"};if(b.type==="NullLiteral")return{type:"null"};if(b.type==="UndefinedLiteral")return{};H(j,"warning",`Expression of type "${b.type}" cannot be statically analyzed`,w??b);return}let{cleanSegments:z,identifier:F}=B(q);if(F!==null)return v(z,F,j,w??b);let G=Q(j.current,z);if(G===void 0){let K=z.join(".");H(j,"error",`Property "${K}" does not exist in the context schema`,w??b);return}return G}function v(b,j,w,q){let z=b.join(".");if(!w.identifierSchemas){H(w,"error",`Property "${z}:${j}" uses an identifier but no identifier schemas were provided`,q);return}let F=w.identifierSchemas[j];if(!F){H(w,"error",`Property "${z}:${j}" references identifier ${j} but no schema exists for this identifier`,q);return}let G=Q(F,b);if(G===void 0){H(w,"error",`Property "${z}" does not exist in the schema for identifier ${j}`,q);return}return G}function V(b){if(b.path.type==="PathExpression")return b.path.original;return""}function H(b,j,w,q){let z={severity:j,message:w};if(q&&"loc"in q&&q.loc)z.loc={start:{line:q.loc.start.line,column:q.loc.start.column},end:{line:q.loc.end.line,column:q.loc.end.column}};b.diagnostics.push(z)}function I(b){if(b.type)return Array.isArray(b.type)?b.type.join(" | "):b.type;if(b.oneOf)return"oneOf(...)";if(b.anyOf)return"anyOf(...)";if(b.allOf)return"allOf(...)";if(b.enum)return"enum";return"unknown"}
|
|
2
|
-
export{g as a,y as b};
|
|
3
|
-
|
|
4
|
-
//# debugId=BE231BA8C982D31264756E2164756E21
|
|
5
|
-
//# sourceMappingURL=chunk-hc1jnqaw.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/analyzer.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import {\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\tJSONSchema7,\n\tTemplateDiagnostic,\n} from \"./types.ts\";\n\n// ─── Static Analyzer ─────────────────────────────────────────────────────────\n// Analyse statique d'un template Handlebars par rapport à un JSON Schema v7\n// décrivant le contexte disponible.\n//\n// Deux responsabilités :\n// 1. **Validation** — vérifier que chaque référence du template existe dans le\n// schema et que les constructions (if, each, with) sont utilisées sur des\n// types compatibles.\n// 2. **Inférence du type de retour** — produire un JSON Schema décrivant le\n// type de la valeur retournée par l'exécution du template.\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// La syntaxe `{{key:N}}` permet de référencer une variable depuis un schema\n// spécifique, identifié par un entier N. Le paramètre optionnel\n// `identifierSchemas` fournit un mapping `{ [id]: JSONSchema7 }`.\n//\n// Règles de résolution :\n// - `{{meetingId}}` → validé contre `inputSchema` (comportement standard)\n// - `{{meetingId:1}}` → validé contre `identifierSchemas[1]`\n// - `{{meetingId:1}}` sans `identifierSchemas[1]` → erreur\n\n// ─── Types internes ──────────────────────────────────────────────────────────\n\n/** Contexte transmis récursivement pendant le parcours de l'AST */\ninterface AnalysisContext {\n\t/** Schema racine (pour résoudre les $ref) */\n\troot: JSONSchema7;\n\t/** Schema du contexte courant (change avec #each, #with) */\n\tcurrent: JSONSchema7;\n\t/** Accumulateur de diagnostics */\n\tdiagnostics: TemplateDiagnostic[];\n\t/** Schemas par identifiant de template (pour la syntaxe {{key:N}}) */\n\tidentifierSchemas?: Record<number, JSONSchema7>;\n}\n\n// ─── API publique ────────────────────────────────────────────────────────────\n\n/**\n * Analyse statiquement un template par rapport à un JSON Schema v7 décrivant\n * le contexte disponible.\n *\n * @param template - La chaîne de template (ex: `\"Hello {{user.name}}\"`)\n * @param inputSchema - JSON Schema v7 décrivant les variables disponibles\n * @param identifierSchemas - (optionnel) Schemas par identifiant `{ [id]: JSONSchema7 }`\n * @returns Un `AnalysisResult` contenant la validité, les diagnostics et le\n * schema de sortie inféré.\n */\nexport function analyze(\n\ttemplate: string,\n\tinputSchema: JSONSchema7,\n\tidentifierSchemas?: Record<number, JSONSchema7>,\n): AnalysisResult {\n\tconst ast = parse(template);\n\n\tconst ctx: AnalysisContext = {\n\t\troot: inputSchema,\n\t\tcurrent: inputSchema,\n\t\tdiagnostics: [],\n\t\tidentifierSchemas,\n\t};\n\n\t// Inférer le type de sortie en parcourant l'AST.\n\t// On distingue 3 cas (du plus spécifique au plus général) :\n\t//\n\t// 1. Expression unique `{{expr}}`\n\t// → le type de retour est celui de l'expression (number, object, …)\n\t//\n\t// 2. Bloc unique `{{#if …}}…{{/if}}` (éventuellement entouré de whitespace)\n\t// → on délègue à `inferBlockType` qui analyse les branches\n\t//\n\t// 3. Template mixte (texte + expressions, blocs multiples, …)\n\t// → le résultat est toujours une string (concaténation)\n\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// ─── Parcours de l'AST (validation) ──────────────────────────────────────────\n// Ces fonctions parcourent l'AST pour valider les références et collecter\n// les diagnostics. Elles ne retournent pas de type — c'est le rôle des\n// fonctions `infer*`.\n\n/**\n * Valide un `Program` (corps d'un template ou d'un bloc).\n * Parcourt séquentiellement chaque statement.\n */\nfunction validateProgram(program: hbs.AST.Program, ctx: AnalysisContext): void {\n\tfor (const stmt of program.body) {\n\t\tvalidateStatement(stmt, ctx);\n\t}\n}\n\n/**\n * Dispatche la validation d'un statement selon son type AST.\n */\nfunction validateStatement(\n\tstmt: hbs.AST.Statement,\n\tctx: AnalysisContext,\n): void {\n\tswitch (stmt.type) {\n\t\tcase \"ContentStatement\":\n\t\t\t// Texte statique — rien à valider\n\t\t\tbreak;\n\n\t\tcase \"MustacheStatement\":\n\t\t\tvalidateMustache(stmt as hbs.AST.MustacheStatement, ctx);\n\t\t\tbreak;\n\n\t\tcase \"BlockStatement\":\n\t\t\tvalidateBlock(stmt as hbs.AST.BlockStatement, ctx);\n\t\t\tbreak;\n\n\t\tcase \"CommentStatement\":\n\t\t\t// Commentaire Handlebars {{!-- ... --}} — ignoré\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\t// Nœud AST non reconnu — on émet un warning plutôt qu'une erreur\n\t\t\t// pour ne pas bloquer sur des extensions futures de Handlebars.\n\t\t\taddDiagnostic(\n\t\t\t\tctx,\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}\n}\n\n/**\n * Valide une expression moustache `{{expression}}`.\n * Vérifie que le chemin référencé existe dans le schema courant.\n */\nfunction validateMustache(\n\tstmt: hbs.AST.MustacheStatement,\n\tctx: AnalysisContext,\n): void {\n\t// Les SubExpressions (helpers imbriqués) ne sont pas supportées pour\n\t// l'analyse statique — on émet un warning.\n\tif (stmt.path.type === \"SubExpression\") {\n\t\taddDiagnostic(\n\t\t\tctx,\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\tresolveExpressionWithDiagnostics(stmt.path, ctx, stmt);\n}\n\n/**\n * Extrait le premier argument d'un BlockStatement.\n *\n * Dans l'AST Handlebars, pour `{{#if active}}` :\n * - `stmt.path` → PathExpression(\"if\") ← le nom du helper\n * - `stmt.params[0]` → PathExpression(\"active\") ← l'argument réel\n *\n * @returns L'expression argument, ou `undefined` si le bloc n'a pas d'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 * Valide un bloc `{{#helper}}...{{/helper}}`.\n * Supporte : `if`, `unless`, `each`, `with`.\n */\nfunction validateBlock(\n\tstmt: hbs.AST.BlockStatement,\n\tctx: AnalysisContext,\n): void {\n\tconst helperName = getBlockHelperName(stmt);\n\n\tswitch (helperName) {\n\t\tcase \"if\":\n\t\tcase \"unless\":\n\t\t\tvalidateIfBlock(stmt, ctx);\n\t\t\tbreak;\n\n\t\tcase \"each\":\n\t\t\tvalidateEachBlock(stmt, ctx);\n\t\t\tbreak;\n\n\t\tcase \"with\":\n\t\t\tvalidateWithBlock(stmt, ctx);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\taddDiagnostic(\n\t\t\t\tctx,\n\t\t\t\t\"warning\",\n\t\t\t\t`Unknown block helper \"{{#${helperName}}}\" — cannot analyze statically`,\n\t\t\t\tstmt,\n\t\t\t);\n\t\t\t// On valide quand même le corps avec le contexte courant (best-effort)\n\t\t\tvalidateProgram(stmt.program, ctx);\n\t\t\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n\t}\n}\n\n/**\n * Valide un bloc `{{#if condition}}...{{else}}...{{/if}}`.\n * La condition doit référencer un chemin valide dans le schema.\n */\nfunction validateIfBlock(\n\tstmt: hbs.AST.BlockStatement,\n\tctx: AnalysisContext,\n): void {\n\tconst arg = getBlockArgument(stmt);\n\tif (arg) {\n\t\t// Valider que la condition référence un chemin existant\n\t\tresolveExpressionWithDiagnostics(arg, ctx, stmt);\n\t} else {\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"error\",\n\t\t\t`\"{{#${getBlockHelperName(stmt)}}}\" requires an argument`,\n\t\t\tstmt,\n\t\t);\n\t}\n\n\t// Le contexte ne change pas dans un if/unless — on valide les deux branches\n\tvalidateProgram(stmt.program, ctx);\n\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n}\n\n/**\n * Valide un bloc `{{#each items}}...{{/each}}`.\n * `items` doit référencer un tableau dans le schema.\n * Le corps du bloc est validé avec le schema des éléments du tableau.\n */\nfunction validateEachBlock(\n\tstmt: hbs.AST.BlockStatement,\n\tctx: AnalysisContext,\n): void {\n\tconst arg = getBlockArgument(stmt);\n\tif (!arg) {\n\t\taddDiagnostic(ctx, \"error\", `\"{{#each}}\" requires an argument`, stmt);\n\t\tvalidateProgram(stmt.program, { ...ctx, current: {} });\n\t\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n\t\treturn;\n\t}\n\n\tconst schema = resolveExpressionWithDiagnostics(arg, ctx, stmt);\n\tif (!schema) {\n\t\t// Le chemin n'a pas pu être résolu — on a déjà émis un diagnostic.\n\t\t// On valide le corps avec un schema vide (best-effort).\n\t\tvalidateProgram(stmt.program, { ...ctx, current: {} });\n\t\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n\t\treturn;\n\t}\n\n\t// Résoudre le schema des éléments du tableau\n\tconst itemSchema = resolveArrayItems(schema, ctx.root);\n\tif (!itemSchema) {\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"error\",\n\t\t\t`\"{{#each}}\" expects an array, but resolved schema has type \"${schemaTypeLabel(schema)}\"`,\n\t\t\tstmt,\n\t\t);\n\t\tvalidateProgram(stmt.program, { ...ctx, current: {} });\n\t\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n\t\treturn;\n\t}\n\n\t// Valider le corps avec le schema des éléments comme contexte\n\tvalidateProgram(stmt.program, { ...ctx, current: itemSchema });\n\n\t// La branche inverse ({{else}}) garde le contexte parent\n\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n}\n\n/**\n * Valide un bloc `{{#with object}}...{{/with}}`.\n * `object` doit référencer un objet dans le schema.\n * Le corps du bloc est validé avec ce sous-schema comme contexte.\n */\nfunction validateWithBlock(\n\tstmt: hbs.AST.BlockStatement,\n\tctx: AnalysisContext,\n): void {\n\tconst arg = getBlockArgument(stmt);\n\tif (!arg) {\n\t\taddDiagnostic(ctx, \"error\", `\"{{#with}}\" requires an argument`, stmt);\n\t\tvalidateProgram(stmt.program, { ...ctx, current: {} });\n\t\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n\t\treturn;\n\t}\n\n\tconst schema = resolveExpressionWithDiagnostics(arg, ctx, stmt);\n\tif (!schema) {\n\t\tvalidateProgram(stmt.program, { ...ctx, current: {} });\n\t\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n\t\treturn;\n\t}\n\n\t// Valider le corps avec le sous-schema comme nouveau contexte\n\tvalidateProgram(stmt.program, { ...ctx, current: schema });\n\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n}\n\n// ─── Inférence de type ───────────────────────────────────────────────────────\n// Ces fonctions déterminent le JSON Schema de sortie du template.\n\nfunction inferExpressionType(\n\texpr: hbs.AST.Expression,\n\tctx: AnalysisContext,\n): JSONSchema7 {\n\tconst schema = resolveExpressionWithDiagnostics(expr, ctx);\n\t// Si le chemin n'a pas pu être résolu, on retourne un schema vide (unknown).\n\t// Le diagnostic a déjà été émis par resolveExpressionWithDiagnostics.\n\treturn schema ?? {};\n}\n\n/**\n * Infère le type de sortie d'un `Program` (corps d'un template ou d'un bloc).\n *\n * - Si le programme est vide → `{ type: \"string\" }` (string vide)\n * - Si le programme contient un seul MustacheStatement → type de l'expression\n * - Sinon → `{ type: \"string\" }` (concaténation)\n */\nfunction inferProgramType(\n\tprogram: hbs.AST.Program,\n\tctx: AnalysisContext,\n): JSONSchema7 {\n\tconst effective = getEffectiveBody(program);\n\n\t// Aucun statement significatif → string vide\n\tif (effective.length === 0) {\n\t\treturn { type: \"string\" };\n\t}\n\n\t// ── Cas 1 : une seule expression {{expr}} ──────────────────────────────\n\tconst singleExpr = getEffectivelySingleExpression(program);\n\tif (singleExpr) {\n\t\treturn inferExpressionType(singleExpr.path, ctx);\n\t}\n\n\t// ── Cas 2 : un seul bloc {{#if}}, {{#each}}, {{#with}}, … ─────────────\n\tconst singleBlock = getEffectivelySingleBlock(program);\n\tif (singleBlock) {\n\t\treturn inferBlockType(singleBlock, ctx);\n\t}\n\n\t// ── Cas 3 : uniquement des ContentStatements (pas d'expressions) ───────\n\t// Si le texte concaténé (trimé) est un littéral typé (nombre, booléen,\n\t// null), on infère le type correspondant.\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// ── Cas 4 : template mixte (texte + expressions, blocs multiples…) ────\n\t// On valide pour collecter les diagnostics, le résultat est toujours string.\n\tvalidateProgram(program, ctx);\n\treturn { type: \"string\" };\n}\n\n/**\n * Infère le type de sortie d'un bloc `{{#if}}...{{else}}...{{/if}}`.\n * Le résultat est l'union des types des deux branches.\n */\nexport function inferBlockType(\n\tstmt: hbs.AST.BlockStatement,\n\tctx: AnalysisContext,\n): JSONSchema7 {\n\tconst helperName = getBlockHelperName(stmt);\n\n\tswitch (helperName) {\n\t\tcase \"if\":\n\t\tcase \"unless\": {\n\t\t\t// Valider la condition (argument du bloc, pas le nom du helper)\n\t\t\tconst arg = getBlockArgument(stmt);\n\t\t\tif (arg) {\n\t\t\t\tresolveExpressionWithDiagnostics(arg, ctx, stmt);\n\t\t\t}\n\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// Union des deux branches\n\t\t\t\tconst thenJson = JSON.stringify(thenType);\n\t\t\t\tconst elseJson = JSON.stringify(elseType);\n\t\t\t\tif (thenJson === elseJson) return thenType;\n\t\t\t\treturn simplifySchema({ oneOf: [thenType, elseType] });\n\t\t\t}\n\n\t\t\t// Pas de branche else → le résultat peut être undefined (string vide\n\t\t\t// en Handlebars, mais conceptuellement c'est optionnel).\n\t\t\treturn thenType;\n\t\t}\n\n\t\tcase \"each\": {\n\t\t\t// Valider et résoudre le schema de la collection (argument du bloc)\n\t\t\tconst arg = getBlockArgument(stmt);\n\t\t\tif (arg) {\n\t\t\t\tconst collectionSchema = resolveExpressionWithDiagnostics(\n\t\t\t\t\targ,\n\t\t\t\t\tctx,\n\t\t\t\t\tstmt,\n\t\t\t\t);\n\t\t\t\tif (collectionSchema) {\n\t\t\t\t\tconst itemSchema = resolveArrayItems(collectionSchema, ctx.root);\n\t\t\t\t\tif (itemSchema) {\n\t\t\t\t\t\t// Valider le corps avec le contexte des éléments\n\t\t\t\t\t\tvalidateProgram(stmt.program, { ...ctx, current: itemSchema });\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// La cible n'est pas un tableau — même diagnostic que validateEachBlock\n\t\t\t\t\t\taddDiagnostic(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\t\t`\"{{#each}}\" expects an array, but resolved schema has type \"${schemaTypeLabel(collectionSchema)}\"`,\n\t\t\t\t\t\t\tstmt,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Un each concatène les rendus → toujours string\n\t\t\treturn { type: \"string\" };\n\t\t}\n\n\t\tcase \"with\": {\n\t\t\tconst arg = getBlockArgument(stmt);\n\t\t\tif (arg) {\n\t\t\t\tconst innerSchema = resolveExpressionWithDiagnostics(arg, ctx, stmt);\n\t\t\t\tif (innerSchema) {\n\t\t\t\t\treturn inferProgramType(stmt.program, {\n\t\t\t\t\t\t...ctx,\n\t\t\t\t\t\tcurrent: innerSchema,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn inferProgramType(stmt.program, { ...ctx, current: {} });\n\t\t}\n\n\t\tdefault: {\n\t\t\t// Helper inconnu — on ne peut rien inférer\n\t\t\tvalidateProgram(stmt.program, ctx);\n\t\t\tif (stmt.inverse) validateProgram(stmt.inverse, ctx);\n\t\t\treturn { type: \"string\" };\n\t\t}\n\t}\n}\n\n// ─── Résolution d'expressions ────────────────────────────────────────────────\n\n/**\n * Résout une expression AST en un sous-schema, en émettant un diagnostic\n * si le chemin n'est pas résolvable.\n *\n * Gère la syntaxe `{{key:N}}` :\n * - Si l'expression a un identifiant N → résolution dans `identifierSchemas[N]`\n * - Si l'identifiant N n'a pas de schema associé → erreur\n * - Si pas d'identifiant → résolution dans `ctx.current` (comportement standard)\n *\n * @returns Le sous-schema résolu, ou `undefined` si le chemin est invalide.\n */\nfunction resolveExpressionWithDiagnostics(\n\texpr: hbs.AST.Expression,\n\tctx: AnalysisContext,\n\t/** Nœud AST parent (pour la localisation du diagnostic) */\n\tparentNode?: hbs.AST.Node,\n): JSONSchema7 | undefined {\n\t// Gestion de `this` / `.` → retourne le contexte courant\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 qui n'est pas un PathExpression (ex: 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\"warning\",\n\t\t\t`Expression of type \"${expr.type}\" cannot be statically analyzed`,\n\t\t\tparentNode ?? expr,\n\t\t);\n\t\treturn undefined;\n\t}\n\n\t// ── Extraction de l'identifiant ────────────────────────────────────────\n\tconst { cleanSegments, identifier } = extractExpressionIdentifier(segments);\n\n\tif (identifier !== null) {\n\t\t// L'expression utilise la syntaxe {{key:N}} — résoudre depuis\n\t\t// le schema de l'identifiant 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// ── Résolution standard (pas d'identifiant) ────────────────────────────\n\tconst resolved = resolveSchemaPath(ctx.current, cleanSegments);\n\tif (resolved === undefined) {\n\t\tconst fullPath = cleanSegments.join(\".\");\n\t\taddDiagnostic(\n\t\t\tctx,\n\t\t\t\"error\",\n\t\t\t`Property \"${fullPath}\" does not exist in the context schema`,\n\t\t\tparentNode ?? expr,\n\t\t);\n\t\treturn undefined;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Résout une expression avec identifiant `{{key:N}}` en cherchant dans\n * le schema associé à l'identifiant N.\n *\n * Émet un diagnostic d'erreur si :\n * - Aucun `identifierSchemas` n'a été fourni\n * - L'identifiant N n'a pas de schema associé\n * - La propriété n'existe pas dans le schema de l'identifiant\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// Pas d'identifierSchemas fourni du tout\n\tif (!ctx.identifierSchemas) {\n\t\taddDiagnostic(\n\t\t\tctx,\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);\n\t\treturn undefined;\n\t}\n\n\t// L'identifiant n'existe pas dans les schemas fournis\n\tconst idSchema = ctx.identifierSchemas[identifier];\n\tif (!idSchema) {\n\t\taddDiagnostic(\n\t\t\tctx,\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);\n\t\treturn undefined;\n\t}\n\n\t// Résoudre le chemin dans le schema de l'identifiant\n\tconst resolved = resolveSchemaPath(idSchema, cleanSegments);\n\tif (resolved === undefined) {\n\t\taddDiagnostic(\n\t\t\tctx,\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);\n\t\treturn undefined;\n\t}\n\n\treturn resolved;\n}\n\n// ─── Utilitaires ─────────────────────────────────────────────────────────────\n\n/**\n * Récupère le nom du helper d'un BlockStatement (ex: \"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 * Ajoute un diagnostic au contexte d'analyse.\n */\nfunction addDiagnostic(\n\tctx: AnalysisContext,\n\tseverity: \"error\" | \"warning\",\n\tmessage: string,\n\tnode?: hbs.AST.Node,\n): void {\n\tconst diagnostic: TemplateDiagnostic = { severity, message };\n\n\t// Extraire la position si disponible dans le nœud AST\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}\n\n\tctx.diagnostics.push(diagnostic);\n}\n\n/**\n * Retourne un label lisible du type d'un schema (pour les messages d'erreur).\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"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "gJAoEO,GAAS,CAAO,CACtB,EACA,EACA,EACiB,CACjB,IAAM,EAAM,EAAM,CAAQ,EAEpB,EAAuB,CAC5B,KAAM,EACN,QAAS,EACT,YAAa,CAAC,EACd,mBACD,EAcM,EAAe,EAAiB,EAAK,CAAG,EAI9C,MAAO,CACN,MAAO,CAHU,EAAI,YAAY,KAAK,CAAC,IAAM,EAAE,WAAa,OAAO,EAInE,YAAa,EAAI,YACjB,aAAc,EAAe,CAAY,CAC1C,EAYD,SAAS,CAAe,CAAC,EAA0B,EAA4B,CAC9E,QAAW,KAAQ,EAAQ,KAC1B,EAAkB,EAAM,CAAG,EAO7B,SAAS,CAAiB,CACzB,EACA,EACO,CACP,OAAQ,EAAK,UACP,mBAEJ,UAEI,oBACJ,EAAiB,EAAmC,CAAG,EACvD,UAEI,iBACJ,EAAc,EAAgC,CAAG,EACjD,UAEI,mBAEJ,cAKA,EACC,EACA,UACA,+BAA+B,EAAK,QACpC,CACD,GAQH,SAAS,CAAgB,CACxB,EACA,EACO,CAGP,GAAI,EAAK,KAAK,OAAS,gBAAiB,CACvC,EACC,EACA,UACA,gDACA,CACD,EACA,OAGD,EAAiC,EAAK,KAAM,EAAK,CAAI,EAYtD,SAAS,CAAgB,CACxB,EACiC,CACjC,OAAO,EAAK,OAAO,GAOpB,SAAS,CAAa,CACrB,EACA,EACO,CACP,IAAM,EAAa,EAAmB,CAAI,EAE1C,OAAQ,OACF,SACA,SACJ,EAAgB,EAAM,CAAG,EACzB,UAEI,OACJ,EAAkB,EAAM,CAAG,EAC3B,UAEI,OACJ,EAAkB,EAAM,CAAG,EAC3B,cAWA,GARA,EACC,EACA,UACA,4BAA4B,mCAC5B,CACD,EAEA,EAAgB,EAAK,QAAS,CAAG,EAC7B,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,GAQtD,SAAS,CAAe,CACvB,EACA,EACO,CACP,IAAM,EAAM,EAAiB,CAAI,EACjC,GAAI,EAEH,EAAiC,EAAK,EAAK,CAAI,EAE/C,OACC,EACA,QACA,OAAO,EAAmB,CAAI,4BAC9B,CACD,EAKD,GADA,EAAgB,EAAK,QAAS,CAAG,EAC7B,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EAQpD,SAAS,CAAiB,CACzB,EACA,EACO,CACP,IAAM,EAAM,EAAiB,CAAI,EACjC,GAAI,CAAC,EAAK,CAGT,GAFA,EAAc,EAAK,QAAS,mCAAoC,CAAI,EACpE,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAC,CAAE,CAAC,EACjD,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EACnD,OAGD,IAAM,EAAS,EAAiC,EAAK,EAAK,CAAI,EAC9D,GAAI,CAAC,EAAQ,CAIZ,GADA,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAC,CAAE,CAAC,EACjD,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EACnD,OAID,IAAM,EAAa,EAAkB,EAAQ,EAAI,IAAI,EACrD,GAAI,CAAC,EAAY,CAQhB,GAPA,EACC,EACA,QACA,+DAA+D,EAAgB,CAAM,KACrF,CACD,EACA,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAC,CAAE,CAAC,EACjD,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EACnD,OAOD,GAHA,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAW,CAAC,EAGzD,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EAQpD,SAAS,CAAiB,CACzB,EACA,EACO,CACP,IAAM,EAAM,EAAiB,CAAI,EACjC,GAAI,CAAC,EAAK,CAGT,GAFA,EAAc,EAAK,QAAS,mCAAoC,CAAI,EACpE,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAC,CAAE,CAAC,EACjD,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EACnD,OAGD,IAAM,EAAS,EAAiC,EAAK,EAAK,CAAI,EAC9D,GAAI,CAAC,EAAQ,CAEZ,GADA,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAC,CAAE,CAAC,EACjD,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EACnD,OAKD,GADA,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAO,CAAC,EACrD,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EAMpD,SAAS,CAAmB,CAC3B,EACA,EACc,CAId,OAHe,EAAiC,EAAM,CAAG,GAGxC,CAAC,EAUnB,SAAS,CAAgB,CACxB,EACA,EACc,CACd,IAAM,EAAY,EAAiB,CAAO,EAG1C,GAAI,EAAU,SAAW,EACxB,MAAO,CAAE,KAAM,QAAS,EAIzB,IAAM,EAAa,EAA+B,CAAO,EACzD,GAAI,EACH,OAAO,EAAoB,EAAW,KAAM,CAAG,EAIhD,IAAM,EAAc,EAA0B,CAAO,EACrD,GAAI,EACH,OAAO,EAAe,EAAa,CAAG,EAOvC,GADmB,EAAU,MAAM,CAAC,IAAM,EAAE,OAAS,kBAAkB,EACvD,CACf,IAAM,EAAO,EACX,IAAI,CAAC,IAAO,EAA+B,KAAK,EAChD,KAAK,EAAE,EACP,KAAK,EAEP,GAAI,IAAS,GAAI,MAAO,CAAE,KAAM,QAAS,EAEzC,IAAM,EAAc,EAAkB,CAAI,EAC1C,GAAI,EAAa,MAAO,CAAE,KAAM,CAAY,EAM7C,OADA,EAAgB,EAAS,CAAG,EACrB,CAAE,KAAM,QAAS,EAOlB,SAAS,CAAc,CAC7B,EACA,EACc,CAGd,OAFmB,EAAmB,CAAI,OAGpC,SACA,SAAU,CAEd,IAAM,EAAM,EAAiB,CAAI,EACjC,GAAI,EACH,EAAiC,EAAK,EAAK,CAAI,EAGhD,IAAM,EAAW,EAAiB,EAAK,QAAS,CAAG,EAEnD,GAAI,EAAK,QAAS,CACjB,IAAM,EAAW,EAAiB,EAAK,QAAS,CAAG,EAE7C,EAAW,KAAK,UAAU,CAAQ,EAClC,EAAW,KAAK,UAAU,CAAQ,EACxC,GAAI,IAAa,EAAU,OAAO,EAClC,OAAO,EAAe,CAAE,MAAO,CAAC,EAAU,CAAQ,CAAE,CAAC,EAKtD,OAAO,CACR,KAEK,OAAQ,CAEZ,IAAM,EAAM,EAAiB,CAAI,EACjC,GAAI,EAAK,CACR,IAAM,EAAmB,EACxB,EACA,EACA,CACD,EACA,GAAI,EAAkB,CACrB,IAAM,EAAa,EAAkB,EAAkB,EAAI,IAAI,EAC/D,GAAI,EAEH,EAAgB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAW,CAAC,EAG7D,OACC,EACA,QACA,+DAA+D,EAAgB,CAAgB,KAC/F,CACD,GAKH,MAAO,CAAE,KAAM,QAAS,CACzB,KAEK,OAAQ,CACZ,IAAM,EAAM,EAAiB,CAAI,EACjC,GAAI,EAAK,CACR,IAAM,EAAc,EAAiC,EAAK,EAAK,CAAI,EACnE,GAAI,EACH,OAAO,EAAiB,EAAK,QAAS,IAClC,EACH,QAAS,CACV,CAAC,EAGH,OAAO,EAAiB,EAAK,QAAS,IAAK,EAAK,QAAS,CAAC,CAAE,CAAC,CAC9D,SAES,CAGR,GADA,EAAgB,EAAK,QAAS,CAAG,EAC7B,EAAK,QAAS,EAAgB,EAAK,QAAS,CAAG,EACnD,MAAO,CAAE,KAAM,QAAS,CACzB,GAiBF,SAAS,CAAgC,CACxC,EACA,EAEA,EAC0B,CAE1B,GAAI,EAAiB,CAAI,EACxB,OAAO,EAAI,QAGZ,IAAM,EAAW,EAAoB,CAAI,EACzC,GAAI,EAAS,SAAW,EAAG,CAE1B,GAAI,EAAK,OAAS,gBAAiB,MAAO,CAAE,KAAM,QAAS,EAC3D,GAAI,EAAK,OAAS,gBAAiB,MAAO,CAAE,KAAM,QAAS,EAC3D,GAAI,EAAK,OAAS,iBAAkB,MAAO,CAAE,KAAM,SAAU,EAC7D,GAAI,EAAK,OAAS,cAAe,MAAO,CAAE,KAAM,MAAO,EACvD,GAAI,EAAK,OAAS,mBAAoB,MAAO,CAAC,EAE9C,EACC,EACA,UACA,uBAAuB,EAAK,sCAC5B,GAAc,CACf,EACA,OAID,IAAQ,gBAAe,cAAe,EAA4B,CAAQ,EAE1E,GAAI,IAAe,KAGlB,OAAO,EACN,EACA,EACA,EACA,GAAc,CACf,EAID,IAAM,EAAW,EAAkB,EAAI,QAAS,CAAa,EAC7D,GAAI,IAAa,OAAW,CAC3B,IAAM,EAAW,EAAc,KAAK,GAAG,EACvC,EACC,EACA,QACA,aAAa,0CACb,GAAc,CACf,EACA,OAGD,OAAO,EAYR,SAAS,CAAqB,CAC7B,EACA,EACA,EACA,EAC0B,CAC1B,IAAM,EAAW,EAAc,KAAK,GAAG,EAGvC,GAAI,CAAC,EAAI,kBAAmB,CAC3B,EACC,EACA,QACA,aAAa,KAAY,gEACzB,CACD,EACA,OAID,IAAM,EAAW,EAAI,kBAAkB,GACvC,GAAI,CAAC,EAAU,CACd,EACC,EACA,QACA,aAAa,KAAY,4BAAqC,6CAC9D,CACD,EACA,OAID,IAAM,EAAW,EAAkB,EAAU,CAAa,EAC1D,GAAI,IAAa,OAAW,CAC3B,EACC,EACA,QACA,aAAa,kDAAyD,IACtE,CACD,EACA,OAGD,OAAO,EAQR,SAAS,CAAkB,CAAC,EAAsC,CACjE,GAAI,EAAK,KAAK,OAAS,iBACtB,OAAQ,EAAK,KAAgC,SAE9C,MAAO,GAMR,SAAS,CAAa,CACrB,EACA,EACA,EACA,EACO,CACP,IAAM,EAAiC,CAAE,WAAU,SAAQ,EAG3D,GAAI,GAAQ,QAAS,GAAQ,EAAK,IACjC,EAAW,IAAM,CAChB,MAAO,CAAE,KAAM,EAAK,IAAI,MAAM,KAAM,OAAQ,EAAK,IAAI,MAAM,MAAO,EAClE,IAAK,CAAE,KAAM,EAAK,IAAI,IAAI,KAAM,OAAQ,EAAK,IAAI,IAAI,MAAO,CAC7D,EAGD,EAAI,YAAY,KAAK,CAAU,EAMhC,SAAS,CAAe,CAAC,EAA6B,CACrD,GAAI,EAAO,KACV,OAAO,MAAM,QAAQ,EAAO,IAAI,EAAI,EAAO,KAAK,KAAK,KAAK,EAAI,EAAO,KAEtE,GAAI,EAAO,MAAO,MAAO,aACzB,GAAI,EAAO,MAAO,MAAO,aACzB,GAAI,EAAO,MAAO,MAAO,aACzB,GAAI,EAAO,KAAM,MAAO,OACxB,MAAO",
|
|
8
|
-
"debugId": "BE231BA8C982D31264756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/compiled-template.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import type Handlebars from \"handlebars\";\nimport type { JSONSchema7 } from \"json-schema\";\nimport { analyzeFromAst } from \"./analyzer.ts\";\nimport { TemplateAnalysisError } from \"./errors.ts\";\nimport { type ExecutorContext, executeFromAst } from \"./executor.ts\";\nimport type {\n\tAnalysisResult,\n\tExecuteOptions,\n\tHelperDefinition,\n\tValidationResult,\n} from \"./types.ts\";\nimport { inferPrimitiveSchema } from \"./types.ts\";\nimport {\n\taggregateObjectAnalysis,\n\taggregateObjectAnalysisAndExecution,\n\ttype LRUCache,\n} from \"./utils.ts\";\n\n// ─── CompiledTemplate ────────────────────────────────────────────────────────\n// Pre-parsed template ready to be executed or analyzed without re-parsing.\n//\n// The compile-once / execute-many pattern avoids the cost of Handlebars\n// parsing on every call. The AST is parsed once at compile time, and the\n// Handlebars template is lazily compiled on the first `execute()`.\n//\n// Usage:\n// const tpl = engine.compile(\"Hello {{name}}\");\n// tpl.execute({ name: \"Alice\" }); // no re-parsing\n// tpl.execute({ name: \"Bob\" }); // no re-parsing or recompilation\n// tpl.analyze(schema); // no re-parsing\n//\n// ─── Internal State (TemplateState) ──────────────────────────────────────────\n// CompiledTemplate operates in 3 exclusive modes, modeled by a discriminated\n// union `TemplateState`:\n//\n// - `\"template\"` — parsed Handlebars template (AST + source string)\n// - `\"literal\"` — primitive passthrough value (number, boolean, null)\n// - `\"object\"` — object where each property is a child CompiledTemplate\n//\n// This design eliminates optional fields and `!` assertions in favor of\n// natural TypeScript narrowing via `switch (this.state.kind)`.\n//\n// ─── Advantages Over the Direct API ──────────────────────────────────────────\n// - **Performance**: parsing and compilation happen only once\n// - **Simplified API**: no need to re-pass the template string on each call\n// - **Consistency**: the same AST is used for both analysis and execution\n\n// ─── Internal Types ──────────────────────────────────────────────────────────\n\n/** Internal options passed by Typebars during compilation */\nexport interface CompiledTemplateOptions {\n\t/** Custom helpers registered on the engine */\n\thelpers: Map<string, HelperDefinition>;\n\t/** Isolated Handlebars environment (with registered helpers) */\n\thbs: typeof Handlebars;\n\t/** Compilation cache shared by the engine */\n\tcompilationCache: LRUCache<string, HandlebarsTemplateDelegate>;\n}\n\n/** Discriminated internal state of the CompiledTemplate */\ntype TemplateState =\n\t| {\n\t\t\treadonly kind: \"template\";\n\t\t\treadonly ast: hbs.AST.Program;\n\t\t\treadonly source: string;\n\t }\n\t| { readonly kind: \"literal\"; readonly value: number | boolean | null }\n\t| {\n\t\t\treadonly kind: \"object\";\n\t\t\treadonly children: Record<string, CompiledTemplate>;\n\t };\n\n// ─── Public Class ────────────────────────────────────────────────────────────\n\nexport class CompiledTemplate {\n\t/** Discriminated internal state */\n\tprivate readonly state: TemplateState;\n\n\t/** Options inherited from the parent Typebars instance */\n\tprivate readonly options: CompiledTemplateOptions;\n\n\t/** Compiled Handlebars template (lazy — created on the first `execute()` that needs it) */\n\tprivate hbsCompiled: HandlebarsTemplateDelegate | null = null;\n\n\t// ─── Public Accessors (backward-compatible) ──────────────────────────\n\n\t/** The pre-parsed Handlebars AST — `null` in literal or object mode */\n\tget ast(): hbs.AST.Program | null {\n\t\treturn this.state.kind === \"template\" ? this.state.ast : null;\n\t}\n\n\t/** The original template source — empty string in literal or object mode */\n\tget template(): string {\n\t\treturn this.state.kind === \"template\" ? this.state.source : \"\";\n\t}\n\n\t// ─── Construction ────────────────────────────────────────────────────\n\n\tprivate constructor(state: TemplateState, options: CompiledTemplateOptions) {\n\t\tthis.state = state;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate for a parsed Handlebars template.\n\t *\n\t * @param ast - The pre-parsed Handlebars AST\n\t * @param source - The original template source\n\t * @param options - Options inherited from Typebars\n\t */\n\tstatic fromTemplate(\n\t\tast: hbs.AST.Program,\n\t\tsource: string,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"template\", ast, source }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in passthrough mode for a literal value\n\t * (number, boolean, null). No parsing or compilation is performed.\n\t *\n\t * @param value - The primitive value\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that always returns `value`\n\t */\n\tstatic fromLiteral(\n\t\tvalue: number | boolean | null,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"literal\", value }, options);\n\t}\n\n\t/**\n\t * Creates a CompiledTemplate in object mode, where each property is a\n\t * child CompiledTemplate. All operations are recursively delegated\n\t * to the children.\n\t *\n\t * @param children - The compiled child templates `{ [key]: CompiledTemplate }`\n\t * @param options - Options inherited from Typebars\n\t * @returns A CompiledTemplate that delegates to children\n\t */\n\tstatic fromObject(\n\t\tchildren: Record<string, CompiledTemplate>,\n\t\toptions: CompiledTemplateOptions,\n\t): CompiledTemplate {\n\t\treturn new CompiledTemplate({ kind: \"object\", children }, options);\n\t}\n\n\t// ─── Static Analysis ─────────────────────────────────────────────────\n\n\t/**\n\t * Statically analyzes this template against a JSON Schema v7.\n\t *\n\t * Returns an `AnalysisResult` containing:\n\t * - `valid` — `true` if no errors\n\t * - `diagnostics` — list of diagnostics (errors + warnings)\n\t * - `outputSchema` — JSON Schema describing the return type\n\t *\n\t * Since the AST is pre-parsed, this method never re-parses the template.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param identifierSchemas - (optional) Schemas by identifier `{ [id]: JSONSchema7 }`\n\t */\n\tanalyze(\n\t\tinputSchema: JSONSchema7,\n\t\tidentifierSchemas?: Record<number, JSONSchema7>,\n\t): AnalysisResult {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\treturn aggregateObjectAnalysis(Object.keys(children), (key) => {\n\t\t\t\t\tconst child = children[key];\n\t\t\t\t\tif (!child) throw new Error(`unreachable: missing child \"${key}\"`);\n\t\t\t\t\treturn child.analyze(inputSchema, identifierSchemas);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tvalid: true,\n\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t};\n\n\t\t\tcase \"template\":\n\t\t\t\treturn analyzeFromAst(this.state.ast, this.state.source, inputSchema, {\n\t\t\t\t\tidentifierSchemas,\n\t\t\t\t\thelpers: this.options.helpers,\n\t\t\t\t});\n\t\t}\n\t}\n\n\t// ─── Validation ──────────────────────────────────────────────────────\n\n\t/**\n\t * Validates the template against a schema without returning the output type.\n\t *\n\t * This is an API shortcut for `analyze()` that only returns `valid` and\n\t * `diagnostics`, without `outputSchema`. The full analysis (including type\n\t * inference) is executed internally — this method provides no performance\n\t * gain, only a simplified API.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param identifierSchemas - (optional) Schemas by identifier\n\t */\n\tvalidate(\n\t\tinputSchema: JSONSchema7,\n\t\tidentifierSchemas?: Record<number, JSONSchema7>,\n\t): ValidationResult {\n\t\tconst analysis = this.analyze(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// ─── Execution ───────────────────────────────────────────────────────\n\n\t/**\n\t * Executes this template with the provided data.\n\t *\n\t * The return type depends on the template structure:\n\t * - Single expression `{{expr}}` → raw value (number, boolean, object…)\n\t * - Mixed template or with blocks → `string`\n\t * - Primitive literal → the value as-is\n\t * - Object template → object with resolved values\n\t *\n\t * If a `schema` is provided in options, static analysis is performed\n\t * before execution. A `TemplateAnalysisError` is thrown on errors.\n\t *\n\t * @param data - The context data for rendering\n\t * @param options - Execution options (schema, identifierData, etc.)\n\t * @returns The execution result\n\t */\n\texecute(data: Record<string, unknown>, options?: ExecuteOptions): unknown {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\tconst result: Record<string, unknown> = {};\n\t\t\t\tfor (const [key, child] of Object.entries(children)) {\n\t\t\t\t\tresult[key] = child.execute(data, options);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn this.state.value;\n\n\t\t\tcase \"template\": {\n\t\t\t\t// Pre-execution static validation if a schema is provided\n\t\t\t\tif (options?.schema) {\n\t\t\t\t\tconst analysis = this.analyze(\n\t\t\t\t\t\toptions.schema,\n\t\t\t\t\t\toptions.identifierSchemas,\n\t\t\t\t\t);\n\t\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\t\tthrow new TemplateAnalysisError(analysis.diagnostics);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext(options),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Combined Shortcuts ──────────────────────────────────────────────\n\n\t/**\n\t * Analyzes and executes the template in a single call.\n\t *\n\t * Returns both the analysis result and the executed value.\n\t * If analysis fails, `value` is `undefined`.\n\t *\n\t * @param inputSchema - JSON Schema describing the available variables\n\t * @param data - The context data for rendering\n\t * @param options - Additional options\n\t * @returns `{ analysis, value }`\n\t */\n\tanalyzeAndExecute(\n\t\tinputSchema: JSONSchema7,\n\t\tdata: Record<string, unknown>,\n\t\toptions?: {\n\t\t\tidentifierSchemas?: Record<number, JSONSchema7>;\n\t\t\tidentifierData?: Record<number, Record<string, unknown>>;\n\t\t},\n\t): { analysis: AnalysisResult; value: unknown } {\n\t\tswitch (this.state.kind) {\n\t\t\tcase \"object\": {\n\t\t\t\tconst { children } = this.state;\n\t\t\t\treturn aggregateObjectAnalysisAndExecution(\n\t\t\t\t\tObject.keys(children),\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: key comes from Object.keys(children), access is guaranteed\n\t\t\t\t\t(key) => children[key]!.analyzeAndExecute(inputSchema, data, options),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcase \"literal\":\n\t\t\t\treturn {\n\t\t\t\t\tanalysis: {\n\t\t\t\t\t\tvalid: true,\n\t\t\t\t\t\tdiagnostics: [],\n\t\t\t\t\t\toutputSchema: inferPrimitiveSchema(this.state.value),\n\t\t\t\t\t},\n\t\t\t\t\tvalue: this.state.value,\n\t\t\t\t};\n\n\t\t\tcase \"template\": {\n\t\t\t\tconst analysis = this.analyze(inputSchema, options?.identifierSchemas);\n\n\t\t\t\tif (!analysis.valid) {\n\t\t\t\t\treturn { analysis, value: undefined };\n\t\t\t\t}\n\n\t\t\t\tconst value = executeFromAst(\n\t\t\t\t\tthis.state.ast,\n\t\t\t\t\tthis.state.source,\n\t\t\t\t\tdata,\n\t\t\t\t\tthis.buildExecutorContext({\n\t\t\t\t\t\tidentifierData: options?.identifierData,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn { analysis, value };\n\t\t\t}\n\t\t}\n\t}\n\n\t// ─── Internals ───────────────────────────────────────────────────────\n\n\t/**\n\t * Builds the execution context for `executeFromAst`.\n\t *\n\t * Uses lazy Handlebars compilation: the template is only compiled\n\t * on the first call that needs it (not for single expressions).\n\t */\n\tprivate buildExecutorContext(options?: ExecuteOptions): ExecutorContext {\n\t\treturn {\n\t\t\tidentifierData: options?.identifierData,\n\t\t\tcompiledTemplate: this.getOrCompileHbs(),\n\t\t\thbs: this.options.hbs,\n\t\t\tcompilationCache: this.options.compilationCache,\n\t\t};\n\t}\n\n\t/**\n\t * Lazily compiles the Handlebars template and caches it.\n\t *\n\t * Compilation happens only once — subsequent calls return the\n\t * in-memory compiled template.\n\t *\n\t * Precondition: this method is only called from \"template\" mode.\n\t */\n\tprivate getOrCompileHbs(): HandlebarsTemplateDelegate {\n\t\tif (!this.hbsCompiled) {\n\t\t\t// In \"template\" mode, `this.template` returns the source string\n\t\t\tthis.hbsCompiled = this.options.hbs.compile(this.template, {\n\t\t\t\tnoEscape: true,\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t}\n\t\treturn this.hbsCompiled;\n\t}\n}\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "7E9B6C0E0074084D64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-mx8neh7q.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{P as M}from"./chunk-fhvf5y4x.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 L,P as M,Q as N,J as O};
|
|
3
|
-
|
|
4
|
-
//# debugId=0F300C79E490F4DC64756E2164756E21
|
|
5
|
-
//# sourceMappingURL=chunk-mx8neh7q.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
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// Utilitaire pour naviguer dans un JSON Schema Draft v7 en suivant un chemin\n// de propriétés (ex: [\"user\", \"address\", \"city\"]).\n//\n// Gère :\n// - La résolution de `$ref` (références internes #/definitions/...)\n// - La navigation dans `properties`\n// - La navigation dans `items` (éléments d'un tableau)\n// - Les combinateurs `allOf`, `anyOf`, `oneOf` (recherche dans chaque branche)\n// - `additionalProperties` quand la propriété n'est pas déclarée\n\n// ─── Résolution de $ref ──────────────────────────────────────────────────────\n// Supporte uniquement les références internes au format `#/definitions/Foo`\n// ou `#/$defs/Foo` (JSON Schema Draft 2019+). Les $ref distantes (URL) ne\n// sont pas prises en charge — ce n'est pas le rôle d'un moteur de template.\n\n/**\n * Résout récursivement les `$ref` d'un schema en utilisant le schema racine\n * comme source de définitions.\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// Format attendu : #/definitions/Name ou #/$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// Résolution récursive au cas où la définition elle-même contient un $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// ─── Navigation par segment de chemin ────────────────────────────────────────\n\n/**\n * Résout un seul segment de chemin (un nom de propriété) dans un schema.\n * Retourne le sous-schema correspondant ou `undefined` si le chemin est invalide.\n *\n * @param schema - Le schema courant (déjà résolu, sans $ref)\n * @param segment - Le nom de la propriété à résoudre\n * @param root - Le schema racine (pour résoudre d'éventuels $ref internes)\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. Propriétés explicites\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 (quand la propriété n'est pas déclarée)\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 → on ne sait rien du type\n\t\t\treturn {};\n\t\t}\n\t\treturn resolveRef(resolved.additionalProperties, root);\n\t}\n\n\t// 3. Propriétés intrinsèques des tableaux (ex: `.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. Combinateurs — on cherche dans chaque branche\n\tconst combinatorResult = resolveInCombinators(resolved, segment, root);\n\tif (combinatorResult) return combinatorResult;\n\n\treturn undefined;\n}\n\n/**\n * Cherche un segment dans les branches `allOf`, `anyOf`, `oneOf`.\n * Retourne le premier sous-schema trouvé ou `undefined`.\n * Pour `allOf`, on fusionne les résultats trouvés en un `allOf`.\n */\nfunction resolveInCombinators(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\t// allOf : la propriété peut être définie dans n'importe quelle branche,\n\t// et toutes les contraintes s'appliquent simultanément.\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 : la propriété peut venir de n'importe quelle branche.\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// ─── API publique ────────────────────────────────────────────────────────────\n\n/**\n * Résout un chemin complet (ex: [\"user\", \"address\", \"city\"]) dans un JSON\n * Schema et retourne le sous-schema correspondant.\n *\n * @param schema - Le schema racine décrivant le contexte du template\n * @param path - Tableau de segments (noms de propriétés)\n * @returns Le sous-schema au bout du chemin, ou `undefined` si le chemin\n * ne peut pas être résolu.\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 * Résout le schema des éléments d'un tableau.\n * Si le schema n'est pas de type `array` ou n'a pas de `items`, retourne `undefined`.\n *\n * @param schema - Le schema d'un tableau\n * @param root - Le schema racine (pour résoudre les $ref)\n */\nexport function resolveArrayItems(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// Vérification que c'est bien un tableau\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 sans items → éléments de type inconnu\n\t\treturn {};\n\t}\n\n\t// items peut être un boolean (true = anything, false = nothing)\n\tif (typeof resolved.items === \"boolean\") {\n\t\treturn {};\n\t}\n\n\t// items peut être un schema unique ou un tuple (tableau de schemas).\n\t// Pour les boucles de template, on traite le cas d'un schema unique.\n\tif (Array.isArray(resolved.items)) {\n\t\t// Tuple : on crée un oneOf de tous les types possibles\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 * Simplifie un schema de sortie pour éviter les constructions inutilement\n * complexes (ex: `oneOf` avec un seul élément, doublons, etc.).\n *\n * Utilise `deepEqual` pour la déduplication — plus robuste et performant\n * que `JSON.stringify` (indépendant de l'ordre des clés, sans allocation\n * de strings intermédiaires).\n */\nexport function simplifySchema(schema: JSONSchema7): JSONSchema7 {\n\t// oneOf / anyOf avec un seul élément → on déplie\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 avec un seul élément → on déplie\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// Déduplique les entrées identiques dans 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// Utilisation de deepEqual au lieu de JSON.stringify pour la\n\t\t\t\t// comparaison structurelle — plus robuste (ordre des clés) et\n\t\t\t\t// plus performant (pas d'allocation de strings).\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": "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",
|
|
8
|
-
"debugId": "0F300C79E490F4DC64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-p3xzf1ew.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{j as T,k as y}from"./chunk-6955jpr7.js";import{A as L,n as j,q as w,r as O,s as k,u as F,v as R,w as U,y as _}from"./chunk-ggdfaqhe.js";import{E as A}from"./chunk-vka4e61h.js";import{Q as V}from"./chunk-fhvf5y4x.js";import P from"handlebars";var C=new V(128);function I(q,M,z){if(y(q))return S(q,M,z);if(T(q))return q;let G=j(q);return W(G,q,M,{identifierData:z})}function S(q,M,z){let G={};for(let[K,J]of Object.entries(q))G[K]=I(J,M,z);return G}function W(q,M,z,G){let K=G?.identifierData;if(w(q)){let N=q.body[0];if(N.params.length===0&&!N.hash)return $(N.path,z,K)}let J=R(q);if(J&&J.params.length===0&&!J.hash)return $(J.path,z,K);if(J&&(J.params.length>0||J.hash)){let N=Y(z,K),X=Z(M,N,G);return _(X)}if(U(q)&&q.body.length>1)return v(q,z,K);if(F(q)){let N=Y(z,K),X=Z(M,N,G);return _(X)}let H=Y(z,K);return Z(M,H,G)}function v(q,M,z){let G="";for(let K of q.body)if(K.type==="ContentStatement")G+=K.value;else if(K.type==="MustacheStatement"){let J=$(K.path,M,z);if(J!=null)G+=String(J)}return G}function $(q,M,z){if(k(q))return M;if(q.type==="StringLiteral")return q.value;if(q.type==="NumberLiteral")return q.value;if(q.type==="BooleanLiteral")return q.value;if(q.type==="NullLiteral")return null;if(q.type==="UndefinedLiteral")return;let G=O(q);if(G.length===0)throw new A(`Cannot resolve expression of type "${q.type}"`);let{cleanSegments:K,identifier:J}=L(G);if(J!==null&&z){let Q=z[J];if(Q)return B(Q,K);return}if(J!==null&&!z)return;return B(M,K)}function B(q,M){let z=q;for(let G of M){if(z===null||z===void 0)return;if(typeof z!=="object")return;z=z[G]}return z}function Y(q,M){if(!M)return q;let z={...q};for(let[G,K]of Object.entries(M))for(let[J,Q]of Object.entries(K))z[`${J}:${G}`]=Q;return z}function Z(q,M,z){try{if(z?.compiledTemplate)return z.compiledTemplate(M);let G=z?.compilationCache??C,K=z?.hbs??P,J=G.get(q);if(!J)J=K.compile(q,{noEscape:!0,strict:!1}),G.set(q,J);return J(M)}catch(G){let K=G instanceof Error?G.message:String(G);throw new A(K)}}function g(){C.clear()}
|
|
2
|
-
export{I as f,W as g,B as h,g as i};
|
|
3
|
-
|
|
4
|
-
//# debugId=22DB3A05EDDFCF4C64756E2164756E21
|
|
5
|
-
//# sourceMappingURL=chunk-p3xzf1ew.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/executor.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import Handlebars from \"handlebars\";\nimport { TemplateRuntimeError } from \"./errors.ts\";\nimport {\n\tcanUseFastPath,\n\tcoerceLiteral,\n\textractExpressionIdentifier,\n\textractPathSegments,\n\tgetEffectivelySingleBlock,\n\tgetEffectivelySingleExpression,\n\tisSingleExpression,\n\tisThisExpression,\n\tparse,\n} from \"./parser.ts\";\nimport type { TemplateInput, TemplateInputObject } from \"./types.ts\";\nimport { isLiteralInput, isObjectInput } from \"./types.ts\";\nimport { LRUCache } from \"./utils.ts\";\n\n// ─── Template Executor ───────────────────────────────────────────────────────\n// Exécute un template Handlebars avec des données réelles.\n//\n// Quatre modes d'exécution (du plus rapide au plus général) :\n//\n// 1. **Expression unique** (`{{value}}` ou ` {{value}} `) → retourne la\n// valeur brute sans conversion en string. Cela permet de préserver le type\n// original (number, boolean, object, array, null).\n//\n// 2. **Fast-path** (texte + expressions simples, pas de blocs ni helpers) →\n// concaténation directe sans passer par Handlebars.compile(). Jusqu'à\n// 10-100x plus rapide pour les templates simples comme `Hello {{name}}`.\n//\n// 3. **Bloc unique** (`{{#if x}}10{{else}}20{{/if}}` éventuellement entouré\n// de whitespace) → rendu via Handlebars puis coercion intelligente du\n// résultat (détection de littéraux number, boolean, null).\n//\n// 4. **Template mixte** (texte + blocs multiples, helpers, …) →\n// délègue à Handlebars qui produit toujours une string.\n//\n// ─── Caching ─────────────────────────────────────────────────────────────────\n// Les templates compilés par Handlebars sont cachés dans un LRU cache pour\n// éviter la recompilation coûteuse lors d'appels répétés.\n//\n// Deux niveaux de cache :\n// - **Cache global** (module-level) pour les fonctions standalone `execute()`\n// - **Cache d'instance** pour `Typebars` (passé via `ExecutorContext`)\n//\n// ─── Template Identifiers ────────────────────────────────────────────────────\n// La syntaxe `{{key:N}}` permet de résoudre une variable depuis une source\n// de données spécifique, identifiée par un entier N. Le paramètre optionnel\n// `identifierData` fournit un mapping `{ [id]: { key: value, ... } }`.\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** Contexte optionnel pour l'exécution (utilisé par Typebars/CompiledTemplate) */\nexport interface ExecutorContext {\n\t/** Données par identifiant `{ [id]: { key: value } }` */\n\tidentifierData?: Record<number, Record<string, unknown>>;\n\t/** Template Handlebars pré-compilé (pour CompiledTemplate) */\n\tcompiledTemplate?: HandlebarsTemplateDelegate;\n\t/** Environnement Handlebars isolé (pour les helpers custom) */\n\thbs?: typeof Handlebars;\n\t/** Cache de compilation partagé par l'engine */\n\tcompilationCache?: LRUCache<string, HandlebarsTemplateDelegate>;\n}\n\n// ─── Cache global de compilation ─────────────────────────────────────────────\n// Utilisé par la fonction standalone `execute()` et `renderWithHandlebars()`.\n// Les instances de `Typebars` utilisent leur propre cache.\nconst globalCompilationCache = new LRUCache<string, HandlebarsTemplateDelegate>(\n\t128,\n);\n\n// ─── API publique (backward-compatible) ──────────────────────────────────────\n\n/**\n * Exécute un template avec les données fournies et retourne le résultat.\n *\n * Le type de retour dépend de la structure du template :\n * - Expression unique `{{expr}}` → valeur brute (any)\n * - Bloc unique → valeur coercée (number, boolean, null ou string)\n * - Template mixte → `string`\n *\n * @param template - La chaîne de template\n * @param data - Les données de contexte principal\n * @param identifierData - (optionnel) Données par identifiant `{ [id]: { key: value } }`\n */\nexport function execute(\n\ttemplate: TemplateInput,\n\tdata: Record<string, unknown>,\n\tidentifierData?: Record<number, Record<string, unknown>>,\n): unknown {\n\tif (isObjectInput(template)) {\n\t\treturn executeObjectTemplate(template, data, identifierData);\n\t}\n\tif (isLiteralInput(template)) return template;\n\tconst ast = parse(template);\n\treturn executeFromAst(ast, template, data, { identifierData });\n}\n\n/**\n * Exécute un objet template récursivement (version standalone).\n * Chaque propriété est exécutée individuellement et le résultat est un objet\n * avec la même structure mais les valeurs résolues.\n */\nfunction executeObjectTemplate(\n\ttemplate: TemplateInputObject,\n\tdata: Record<string, unknown>,\n\tidentifierData?: Record<number, Record<string, unknown>>,\n): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(template)) {\n\t\tresult[key] = execute(value, data, identifierData);\n\t}\n\treturn result;\n}\n\n// ─── API interne (pour Typebars / CompiledTemplate) ────────────────────\n\n/**\n * Exécute un template à partir d'un AST déjà parsé.\n *\n * Cette fonction est le cœur de l'exécution. Elle est utilisée par :\n * - `execute()` (wrapper backward-compatible)\n * - `CompiledTemplate.execute()` (avec AST pré-parsé et cache)\n * - `Typebars.execute()` (avec cache et helpers)\n *\n * @param ast - L'AST Handlebars déjà parsé\n * @param template - Le template source (pour la compilation Handlebars si nécessaire)\n * @param data - Les données de contexte principal\n * @param ctx - Contexte d'exécution optionnel\n */\nexport function executeFromAst(\n\tast: hbs.AST.Program,\n\ttemplate: string,\n\tdata: Record<string, unknown>,\n\tctx?: ExecutorContext,\n): unknown {\n\tconst identifierData = ctx?.identifierData;\n\n\t// ── Cas 1 : expression unique stricte `{{expr}}` ─────────────────────\n\t// On exclut les helper calls (params > 0 ou hash) car ils doivent\n\t// passer par Handlebars pour être exécutés correctement.\n\tif (isSingleExpression(ast)) {\n\t\tconst stmt = ast.body[0] as hbs.AST.MustacheStatement;\n\t\tif (stmt.params.length === 0 && !stmt.hash) {\n\t\t\treturn resolveExpression(stmt.path, data, identifierData);\n\t\t}\n\t}\n\n\t// ── Cas 1b : expression unique avec whitespace autour ` {{expr}} ` ──\n\tconst singleExpr = getEffectivelySingleExpression(ast);\n\tif (singleExpr && singleExpr.params.length === 0 && !singleExpr.hash) {\n\t\treturn resolveExpression(singleExpr.path, data, identifierData);\n\t}\n\n\t// ── Cas 1c : expression unique avec helper (params > 0) ──────────────\n\t// Ex: `{{ divide accountIds.length 10 }}` ou `{{ math a \"+\" b }}`\n\t// Le helper retourne une valeur typée mais Handlebars la convertit en\n\t// string. On rend via Handlebars puis on coerce le résultat pour\n\t// retrouver le type original (number, boolean, null).\n\tif (singleExpr && (singleExpr.params.length > 0 || singleExpr.hash)) {\n\t\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\t\tconst raw = renderWithHandlebars(template, merged, ctx);\n\t\treturn coerceLiteral(raw);\n\t}\n\n\t// ── Cas 2 : fast-path pour templates simples (texte + expressions) ────\n\t// Si le template ne contient que du texte et des expressions simples\n\t// (pas de blocs, pas de helpers avec paramètres), on peut faire une\n\t// concaténation directe sans passer par Handlebars.compile().\n\tif (canUseFastPath(ast) && ast.body.length > 1) {\n\t\treturn executeFastPath(ast, data, identifierData);\n\t}\n\n\t// ── Cas 3 : bloc unique (éventuellement entouré de whitespace) ────────\n\t// On rend via Handlebars puis on tente de coercer le résultat vers le\n\t// type littéral détecté (number, boolean, null).\n\tconst singleBlock = getEffectivelySingleBlock(ast);\n\tif (singleBlock) {\n\t\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\t\tconst raw = renderWithHandlebars(template, merged, ctx);\n\t\treturn coerceLiteral(raw);\n\t}\n\n\t// ── Cas 4 : template mixte → string ───────────────────────────────────\n\tconst merged = mergeDataWithIdentifiers(data, identifierData);\n\treturn renderWithHandlebars(template, merged, ctx);\n}\n\n// ─── Fast-path execution ─────────────────────────────────────────────────────\n// Pour les templates constitués uniquement de texte et d'expressions simples\n// (pas de blocs, pas de helpers), on court-circuite Handlebars et on fait\n// une concaténation directe. C'est significativement plus rapide.\n\n/**\n * Exécute un template via le fast-path (concaténation directe).\n *\n * Pré-condition : `canUseFastPath(ast)` doit retourner `true`.\n *\n * @param ast - L'AST du template (que ContentStatement et MustacheStatement simples)\n * @param data - Les données de contexte\n * @param identifierData - Données par identifiant (optionnel)\n * @returns La string résultante\n */\nfunction executeFastPath(\n\tast: hbs.AST.Program,\n\tdata: Record<string, unknown>,\n\tidentifierData?: Record<number, Record<string, unknown>>,\n): string {\n\tlet result = \"\";\n\n\tfor (const stmt of ast.body) {\n\t\tif (stmt.type === \"ContentStatement\") {\n\t\t\tresult += (stmt as hbs.AST.ContentStatement).value;\n\t\t} else if (stmt.type === \"MustacheStatement\") {\n\t\t\tconst value = resolveExpression(\n\t\t\t\t(stmt as hbs.AST.MustacheStatement).path,\n\t\t\t\tdata,\n\t\t\t\tidentifierData,\n\t\t\t);\n\t\t\t// Handlebars convertit les valeurs en string pour le rendu.\n\t\t\t// On reproduit ce comportement : null/undefined → \"\", sinon String(value).\n\t\t\tif (value != null) {\n\t\t\t\tresult += String(value);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// ─── Résolution directe d'expression ─────────────────────────────────────────\n// Utilisé pour les templates à expression unique et le fast-path, afin de\n// retourner la valeur brute sans passer par le moteur Handlebars.\n\n/**\n * Résout une expression AST en suivant le chemin dans les données.\n *\n * Si l'expression contient un identifiant (ex: `meetingId:1`), la résolution\n * se fait dans `identifierData[1]` au lieu de `data`.\n *\n * @param expr - L'expression AST à résoudre\n * @param data - Le contexte de données principal\n * @param identifierData - Données par identifiant (optionnel)\n * @returns La valeur brute pointée par l'expression\n */\nfunction resolveExpression(\n\texpr: hbs.AST.Expression,\n\tdata: Record<string, unknown>,\n\tidentifierData?: Record<number, Record<string, unknown>>,\n): unknown {\n\t// this / . → retourne le contexte entier\n\tif (isThisExpression(expr)) {\n\t\treturn data;\n\t}\n\n\t// Literals\n\tif (expr.type === \"StringLiteral\")\n\t\treturn (expr as hbs.AST.StringLiteral).value;\n\tif (expr.type === \"NumberLiteral\")\n\t\treturn (expr as hbs.AST.NumberLiteral).value;\n\tif (expr.type === \"BooleanLiteral\")\n\t\treturn (expr as hbs.AST.BooleanLiteral).value;\n\tif (expr.type === \"NullLiteral\") return null;\n\tif (expr.type === \"UndefinedLiteral\") return undefined;\n\n\t// PathExpression — navigation par segments dans l'objet data\n\tconst segments = extractPathSegments(expr);\n\tif (segments.length === 0) {\n\t\tthrow new TemplateRuntimeError(\n\t\t\t`Cannot resolve expression of type \"${expr.type}\"`,\n\t\t);\n\t}\n\n\t// Extraire l'identifiant éventuel du dernier segment\n\tconst { cleanSegments, identifier } = extractExpressionIdentifier(segments);\n\n\tif (identifier !== null && identifierData) {\n\t\tconst source = identifierData[identifier];\n\t\tif (source) {\n\t\t\treturn resolveDataPath(source, cleanSegments);\n\t\t}\n\t\t// La source n'existe pas → undefined (comme une clé manquante)\n\t\treturn undefined;\n\t}\n\n\tif (identifier !== null && !identifierData) {\n\t\t// Template utilise un identifiant mais aucune identifierData fournie\n\t\treturn undefined;\n\t}\n\n\treturn resolveDataPath(data, cleanSegments);\n}\n\n/**\n * Navigue dans un objet de données en suivant un chemin de segments.\n *\n * @param data - L'objet de données\n * @param segments - Les segments du chemin (ex: `[\"user\", \"address\", \"city\"]`)\n * @returns La valeur au bout du chemin, ou `undefined` si un segment\n * intermédiaire est null/undefined\n */\nexport function resolveDataPath(data: unknown, segments: string[]): unknown {\n\tlet current: unknown = data;\n\n\tfor (const segment of segments) {\n\t\tif (current === null || current === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (typeof current !== \"object\") {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcurrent = (current as Record<string, unknown>)[segment];\n\t}\n\n\treturn current;\n}\n\n// ─── Fusion des données ──────────────────────────────────────────────────────\n// Pour le rendu Handlebars (templates mixtes / blocs), on ne peut pas\n// intercepter la résolution expression par expression. On fusionne donc\n// les données identifiées dans l'objet principal sous la forme `\"key:N\"`.\n//\n// Handlebars parse `{{meetingId:1}}` comme un PathExpression avec un seul\n// segment `\"meetingId:1\"`, donc il cherchera la clé `\"meetingId:1\"` dans\n// l'objet de données — ce qui correspond exactement à notre format aplati.\n\n/**\n * Fusionne les données principales avec les données identifiées.\n *\n * @param data - Données principales\n * @param identifierData - Données par identifiant\n * @returns Un objet fusionné où les données identifiées sont sous la forme `\"key:N\"`\n *\n * @example\n * ```\n * mergeDataWithIdentifiers(\n * { name: \"Alice\" },\n * { 1: { meetingId: \"val1\" }, 2: { meetingId: \"val2\" } }\n * )\n * // → { name: \"Alice\", \"meetingId:1\": \"val1\", \"meetingId:2\": \"val2\" }\n * ```\n */\nfunction mergeDataWithIdentifiers(\n\tdata: Record<string, unknown>,\n\tidentifierData?: Record<number, Record<string, unknown>>,\n): Record<string, unknown> {\n\tif (!identifierData) return data;\n\n\tconst merged: Record<string, unknown> = { ...data };\n\n\tfor (const [id, idData] of Object.entries(identifierData)) {\n\t\tfor (const [key, value] of Object.entries(idData)) {\n\t\t\tmerged[`${key}:${id}`] = value;\n\t\t}\n\t}\n\n\treturn merged;\n}\n\n// ─── Rendu Handlebars ────────────────────────────────────────────────────────\n// Pour les templates complexes (blocs, helpers), on délègue à Handlebars.\n// La compilation est cachée pour éviter les recompilations coûteuses.\n\n/**\n * Compile et exécute un template via Handlebars.\n *\n * Utilise un cache de compilation (LRU) pour éviter de recompiler le même\n * template lors d'appels répétés. Le cache est soit :\n * - Le cache global (pour la fonction standalone `execute()`)\n * - Le cache d'instance fourni via `ExecutorContext` (pour `Typebars`)\n *\n * @param template - La chaîne de template\n * @param data - Les données de contexte\n * @param ctx - Contexte d'exécution optionnel (cache, env Handlebars)\n * @returns Toujours une string\n */\nfunction renderWithHandlebars(\n\ttemplate: string,\n\tdata: Record<string, unknown>,\n\tctx?: ExecutorContext,\n): string {\n\ttry {\n\t\t// 1. Utiliser le template pré-compilé si disponible (CompiledTemplate)\n\t\tif (ctx?.compiledTemplate) {\n\t\t\treturn ctx.compiledTemplate(data);\n\t\t}\n\n\t\t// 2. Chercher dans le cache (instance ou global)\n\t\tconst cache = ctx?.compilationCache ?? globalCompilationCache;\n\t\tconst hbs = ctx?.hbs ?? Handlebars;\n\n\t\tlet compiled = cache.get(template);\n\t\tif (!compiled) {\n\t\t\tcompiled = hbs.compile(template, {\n\t\t\t\t// Désactive le HTML-escaping par défaut — ce moteur n'est pas\n\t\t\t\t// spécifique au HTML, on veut les valeurs brutes.\n\t\t\t\tnoEscape: true,\n\t\t\t\t// Mode strict : lève une erreur si un chemin n'existe pas dans les données.\n\t\t\t\tstrict: false,\n\t\t\t});\n\t\t\tcache.set(template, compiled);\n\t\t}\n\n\t\treturn compiled(data);\n\t} catch (error: unknown) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new TemplateRuntimeError(message);\n\t}\n}\n\n/**\n * Vide le cache global de compilation Handlebars.\n * Utile pour les tests ou pour libérer la mémoire.\n */\nexport function clearCompilationCache(): void {\n\tglobalCompilationCache.clear();\n}\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "22DB3A05EDDFCF4C64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-qh2r1pa1.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
function G(w,A){if(!w.$ref)return w;let B=w.$ref,j=B.match(/^#\/(definitions|\$defs)\/(.+)$/);if(!j)throw Error(`Unsupported $ref format: "${B}". Only internal #/definitions/ references are supported.`);let E=j[1],F=j[2]??"",H=E==="definitions"?A.definitions:A.$defs;if(!H||!(F in H))throw Error(`Cannot resolve $ref "${B}": definition "${F}" not found.`);let M=H[F];if(!M)throw Error(`Cannot resolve $ref "${B}": definition "${F}" not found.`);return G(M,A)}function L(w,A,B){let j=G(w,B);if(j.properties&&A in j.properties){let F=j.properties[A];if(F)return G(F,B)}if(j.additionalProperties!==void 0&&j.additionalProperties!==!1){if(j.additionalProperties===!0)return{};return G(j.additionalProperties,B)}let E=N(j,A,B);if(E)return E;return}function N(w,A,B){if(w.allOf){let j=w.allOf.map((E)=>L(E,A,B)).filter((E)=>E!==void 0);if(j.length===1)return j[0];if(j.length>1)return{allOf:j}}for(let j of["anyOf","oneOf"]){if(!w[j])continue;let E=w[j].map((F)=>L(F,A,B)).filter((F)=>F!==void 0);if(E.length===1)return E[0];if(E.length>1)return{[j]:E}}return}function P(w,A){if(A.length===0)return G(w,w);let B=G(w,w),j=w;for(let E of A){let F=L(B,E,j);if(F===void 0)return;B=F}return B}function Q(w,A){let B=G(w,A),j=B.type;if(!(j==="array"||Array.isArray(j)&&j.includes("array"))&&B.items===void 0)return;if(B.items===void 0)return{};if(Array.isArray(B.items))return{oneOf:B.items.map((F)=>G(F,A))};return G(B.items,A)}function J(w){for(let A of["oneOf","anyOf"])if(w[A]&&w[A].length===1)return J(w[A][0]);if(w.allOf&&w.allOf.length===1)return J(w.allOf[0]);for(let A of["oneOf","anyOf"])if(w[A]&&w[A].length>1){let B=new Set,j=[];for(let E of w[A]){let F=JSON.stringify(E);if(!B.has(F))B.add(F),j.push(J(E))}if(j.length===1)return j[0];return{...w,[A]:j}}return w}
|
|
2
|
-
export{G as t,P as u,Q as v,J as w};
|
|
3
|
-
|
|
4
|
-
//# debugId=BE90011647E1C81A64756E2164756E21
|
|
5
|
-
//# sourceMappingURL=chunk-qh2r1pa1.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/schema-resolver.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import type { JSONSchema7 } from \"./types.ts\";\n\n// ─── JSON Schema Resolver ────────────────────────────────────────────────────\n// Utilitaire pour naviguer dans un JSON Schema Draft v7 en suivant un chemin\n// de propriétés (ex: [\"user\", \"address\", \"city\"]).\n//\n// Gère :\n// - La résolution de `$ref` (références internes #/definitions/...)\n// - La navigation dans `properties`\n// - La navigation dans `items` (éléments d'un tableau)\n// - Les combinateurs `allOf`, `anyOf`, `oneOf` (recherche dans chaque branche)\n// - `additionalProperties` quand la propriété n'est pas déclarée\n\n// ─── Résolution de $ref ──────────────────────────────────────────────────────\n// Supporte uniquement les références internes au format `#/definitions/Foo`\n// ou `#/$defs/Foo` (JSON Schema Draft 2019+). Les $ref distantes (URL) ne\n// sont pas prises en charge — ce n'est pas le rôle d'un moteur de template.\n\n/**\n * Résout récursivement les `$ref` d'un schema en utilisant le schema racine\n * comme source de définitions.\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// Format attendu : #/definitions/Name ou #/$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 =\n\t\tdefsKey === \"definitions\"\n\t\t\t? root.definitions\n\t\t\t: ((root as Record<string, unknown>).$defs as\n\t\t\t\t\t| Record<string, JSONSchema7>\n\t\t\t\t\t| undefined);\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// Résolution récursive au cas où la définition elle-même contient un $ref\n\tconst def = defs[name];\n\tif (!def) {\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// ─── Navigation par segment de chemin ────────────────────────────────────────\n\n/**\n * Résout un seul segment de chemin (un nom de propriété) dans un schema.\n * Retourne le sous-schema correspondant ou `undefined` si le chemin est invalide.\n *\n * @param schema - Le schema courant (déjà résolu, sans $ref)\n * @param segment - Le nom de la propriété à résoudre\n * @param root - Le schema racine (pour résoudre d'éventuels $ref internes)\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. Propriétés explicites\n\tif (resolved.properties && segment in resolved.properties) {\n\t\tconst prop = resolved.properties[segment];\n\t\tif (prop) return resolveRef(prop, root);\n\t}\n\n\t// 2. additionalProperties (quand la propriété n'est pas déclarée)\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 → on ne sait rien du type\n\t\t\treturn {};\n\t\t}\n\t\treturn resolveRef(resolved.additionalProperties, root);\n\t}\n\n\t// 3. Combinateurs — on cherche dans chaque branche\n\tconst combinatorResult = resolveInCombinators(resolved, segment, root);\n\tif (combinatorResult) return combinatorResult;\n\n\treturn undefined;\n}\n\n/**\n * Cherche un segment dans les branches `allOf`, `anyOf`, `oneOf`.\n * Retourne le premier sous-schema trouvé ou `undefined`.\n * Pour `allOf`, on fusionne les résultats trouvés en un `allOf`.\n */\nfunction resolveInCombinators(\n\tschema: JSONSchema7,\n\tsegment: string,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\t// allOf : la propriété peut être définie dans n'importe quelle branche,\n\t// et toutes les contraintes s'appliquent simultanément.\n\tif (schema.allOf) {\n\t\tconst matches = schema.allOf\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 : la propriété peut venir de n'importe quelle branche.\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.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// ─── API publique ────────────────────────────────────────────────────────────\n\n/**\n * Résout un chemin complet (ex: [\"user\", \"address\", \"city\"]) dans un JSON\n * Schema et retourne le sous-schema correspondant.\n *\n * @param schema - Le schema racine décrivant le contexte du template\n * @param path - Tableau de segments (noms de propriétés)\n * @returns Le sous-schema au bout du chemin, ou `undefined` si le chemin\n * ne peut pas être résolu.\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 * Résout le schema des éléments d'un tableau.\n * Si le schema n'est pas de type `array` ou n'a pas de `items`, retourne `undefined`.\n *\n * @param schema - Le schema d'un tableau\n * @param root - Le schema racine (pour résoudre les $ref)\n */\nexport function resolveArrayItems(\n\tschema: JSONSchema7,\n\troot: JSONSchema7,\n): JSONSchema7 | undefined {\n\tconst resolved = resolveRef(schema, root);\n\n\t// Vérification que c'est bien un tableau\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 sans items → éléments de type inconnu\n\t\treturn {};\n\t}\n\n\t// items peut être un schema unique ou un tuple (tableau de schemas).\n\t// Pour les boucles de template, on traite le cas d'un schema unique.\n\tif (Array.isArray(resolved.items)) {\n\t\t// Tuple : on crée un oneOf de tous les types possibles\n\t\treturn { oneOf: resolved.items.map((item) => resolveRef(item, root)) };\n\t}\n\n\treturn resolveRef(resolved.items, root);\n}\n\n/**\n * Simplifie un schema de sortie pour éviter les constructions inutilement\n * complexes (ex: `oneOf` avec un seul élément, doublons, etc.).\n */\nexport function simplifySchema(schema: JSONSchema7): JSONSchema7 {\n\t// oneOf / anyOf avec un seul élément → on déplie\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tif (schema[key] && schema[key].length === 1) {\n\t\t\treturn simplifySchema(schema[key][0] as JSONSchema7);\n\t\t}\n\t}\n\n\t// allOf avec un seul élément → on déplie\n\tif (schema.allOf && schema.allOf.length === 1) {\n\t\treturn simplifySchema(schema.allOf[0] as JSONSchema7);\n\t}\n\n\t// Déduplique les entrées identiques dans oneOf/anyOf\n\tfor (const key of [\"oneOf\", \"anyOf\"] as const) {\n\t\tif (schema[key] && schema[key].length > 1) {\n\t\t\tconst seen = new Set<string>();\n\t\t\tconst unique: JSONSchema7[] = [];\n\t\t\tfor (const entry of schema[key]) {\n\t\t\t\tconst serialized = JSON.stringify(entry);\n\t\t\t\tif (!seen.has(serialized)) {\n\t\t\t\t\tseen.add(serialized);\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": "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",
|
|
8
|
-
"debugId": "BE90011647E1C81A64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-vka4e61h.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
class A extends Error{constructor(j){super(j);this.name="TemplateError"}toJSON(){return{name:this.name,message:this.message}}}class F extends A{loc;source;constructor(j,k,q){super(`Parse error: ${j}`);this.loc=k;this.source=q;this.name="TemplateParseError"}toJSON(){return{name:this.name,message:this.message,loc:this.loc,source:this.source}}}class G extends A{diagnostics;errors;warnings;errorCount;warningCount;constructor(j){let k=j.filter((z)=>z.severity==="error"),q=j.filter((z)=>z.severity==="warning"),B=k.map((z)=>I(z)).join(`
|
|
2
|
-
`);super(`Static analysis failed with ${k.length} error(s):
|
|
3
|
-
${B}`);this.name="TemplateAnalysisError",this.diagnostics=j,this.errors=k,this.warnings=q,this.errorCount=k.length,this.warningCount=q.length}toJSON(){return{name:this.name,message:this.message,errorCount:this.errorCount,warningCount:this.warningCount,diagnostics:this.diagnostics}}}class H extends A{constructor(j){super(`Runtime error: ${j}`);this.name="TemplateRuntimeError"}}function I(j){let k=[` • [${j.code}] ${j.message}`];if(j.loc)k.push(`(at ${j.loc.start.line}:${j.loc.start.column})`);return k.join(" ")}function J(j,k){let q=`Property "${j}" does not exist in the context schema`;if(k.length===0)return q;return`${q}. Available properties: ${k.join(", ")}`}function K(j,k,q){return`"{{#${j}}}" expects ${k}, but resolved schema has type "${q}"`}function M(j){return`"{{#${j}}}" requires an argument`}function O(j){return`Unknown block helper "{{#${j}}}" — cannot analyze statically`}function Q(j){return`Expression of type "${j}" cannot be statically analyzed`}function R(j,k){if(!j)return"MISSING_IDENTIFIER_SCHEMAS";if(!k)return"UNKNOWN_IDENTIFIER";return"IDENTIFIER_PROPERTY_NOT_FOUND"}
|
|
4
|
-
export{A as B,F as C,G as D,H as E,J as F,K as G,M as H,O as I,Q as J,R as K};
|
|
5
|
-
|
|
6
|
-
//# debugId=47521E188A2A57ED64756E2164756E21
|
|
7
|
-
//# sourceMappingURL=chunk-vka4e61h.js.map
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/errors.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import type { DiagnosticCode, TemplateDiagnostic } from \"./types.ts\";\n\n// ─── Classe de base ──────────────────────────────────────────────────────────\n// Toutes les erreurs du moteur de template héritent de cette classe pour\n// permettre un `catch` ciblé : `catch (e) { if (e instanceof TemplateError) … }`\n\nexport class TemplateError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"TemplateError\";\n\t}\n\n\t/**\n\t * Sérialise l'erreur en un objet JSON-compatible, adapté à l'envoi\n\t * vers un frontend ou un système de logging structuré.\n\t */\n\ttoJSON(): Record<string, unknown> {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t};\n\t}\n}\n\n// ─── Erreur de parsing ───────────────────────────────────────────────────────\n// Levée quand Handlebars ne parvient pas à parser le template (syntaxe invalide).\n\nexport class TemplateParseError extends TemplateError {\n\tconstructor(\n\t\tmessage: string,\n\t\t/** Position approximative de l'erreur dans le source */\n\t\tpublic readonly loc?: { line: number; column: number },\n\t\t/** Fragment du template source autour de l'erreur */\n\t\tpublic readonly source?: string,\n\t) {\n\t\tsuper(`Parse error: ${message}`);\n\t\tthis.name = \"TemplateParseError\";\n\t}\n\n\toverride toJSON(): Record<string, unknown> {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\tloc: this.loc,\n\t\t\tsource: this.source,\n\t\t};\n\t}\n}\n\n// ─── Erreur d'analyse statique ───────────────────────────────────────────────\n// Levée en mode strict quand l'analyse produit au moins une erreur.\n// Contient la liste complète des diagnostics pour inspection détaillée.\n\nexport class TemplateAnalysisError extends TemplateError {\n\t/** Liste complète des diagnostics (erreurs + warnings) */\n\tpublic readonly diagnostics: TemplateDiagnostic[];\n\n\t/** Uniquement les diagnostics de sévérité \"error\" */\n\tpublic readonly errors: TemplateDiagnostic[];\n\n\t/** Uniquement les diagnostics de sévérité \"warning\" */\n\tpublic readonly warnings: TemplateDiagnostic[];\n\n\t/** Nombre total d'erreurs */\n\tpublic readonly errorCount: number;\n\n\t/** Nombre total de warnings */\n\tpublic readonly warningCount: number;\n\n\tconstructor(diagnostics: TemplateDiagnostic[]) {\n\t\tconst errors = diagnostics.filter((d) => d.severity === \"error\");\n\t\tconst warnings = diagnostics.filter((d) => d.severity === \"warning\");\n\n\t\tconst summary = errors.map((d) => formatDiagnosticLine(d)).join(\"\\n\");\n\t\tsuper(`Static analysis failed with ${errors.length} error(s):\\n${summary}`);\n\n\t\tthis.name = \"TemplateAnalysisError\";\n\t\tthis.diagnostics = diagnostics;\n\t\tthis.errors = errors;\n\t\tthis.warnings = warnings;\n\t\tthis.errorCount = errors.length;\n\t\tthis.warningCount = warnings.length;\n\t}\n\n\t/**\n\t * Sérialise l'erreur d'analyse en un objet JSON-compatible.\n\t *\n\t * Conçu pour être envoyé directement à un frontend :\n\t * ```\n\t * res.status(400).json(error.toJSON());\n\t * ```\n\t *\n\t * Structure retournée :\n\t * ```\n\t * {\n\t * name: \"TemplateAnalysisError\",\n\t * message: \"Static analysis failed with 2 error(s): ...\",\n\t * errorCount: 2,\n\t * warningCount: 0,\n\t * diagnostics: [\n\t * {\n\t * severity: \"error\",\n\t * code: \"UNKNOWN_PROPERTY\",\n\t * message: \"Property \\\"foo\\\" does not exist...\",\n\t * loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 7 } },\n\t * source: \"{{foo}}\",\n\t * details: { path: \"foo\", availableProperties: [\"name\", \"age\"] }\n\t * }\n\t * ]\n\t * }\n\t * ```\n\t */\n\toverride toJSON(): Record<string, unknown> {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\terrorCount: this.errorCount,\n\t\t\twarningCount: this.warningCount,\n\t\t\tdiagnostics: this.diagnostics,\n\t\t};\n\t}\n}\n\n// ─── Erreur d'exécution ──────────────────────────────────────────────────────\n// Levée quand l'exécution du template échoue (accès à une propriété\n// inexistante en mode strict, type inattendu, etc.).\n\nexport class TemplateRuntimeError extends TemplateError {\n\tconstructor(message: string) {\n\t\tsuper(`Runtime error: ${message}`);\n\t\tthis.name = \"TemplateRuntimeError\";\n\t}\n}\n\n// ─── Utilitaires internes ────────────────────────────────────────────────────\n\n/**\n * Formate une ligne de diagnostic pour le message résumé d'une\n * `TemplateAnalysisError`.\n *\n * Produit un format lisible :\n * ` • [UNKNOWN_PROPERTY] Property \"foo\" does not exist (at 1:0)`\n */\nfunction formatDiagnosticLine(diag: TemplateDiagnostic): string {\n\tconst parts: string[] = [` • [${diag.code}] ${diag.message}`];\n\n\tif (diag.loc) {\n\t\tparts.push(`(at ${diag.loc.start.line}:${diag.loc.start.column})`);\n\t}\n\n\treturn parts.join(\" \");\n}\n\n// ─── Factory pour les erreurs courantes ──────────────────────────────────────\n// Ces fonctions simplifient la création d'erreurs typées à travers le code.\n\n/**\n * Crée un diagnostic structuré pour une propriété inexistante.\n * Utilisé par l'analyseur pour produire des messages d'erreur enrichis.\n */\nexport function createPropertyNotFoundMessage(\n\tpath: string,\n\tavailableProperties: string[],\n): string {\n\tconst base = `Property \"${path}\" does not exist in the context schema`;\n\tif (availableProperties.length === 0) return base;\n\treturn `${base}. Available properties: ${availableProperties.join(\", \")}`;\n}\n\n/**\n * Crée un message pour une incompatibilité de type.\n */\nexport function createTypeMismatchMessage(\n\thelperName: string,\n\texpected: string,\n\tactual: string,\n): string {\n\treturn `\"{{#${helperName}}}\" expects ${expected}, but resolved schema has type \"${actual}\"`;\n}\n\n/**\n * Crée un message pour un argument manquant sur un helper de bloc.\n */\nexport function createMissingArgumentMessage(helperName: string): string {\n\treturn `\"{{#${helperName}}}\" requires an argument`;\n}\n\n/**\n * Crée un message pour un helper de bloc inconnu.\n */\nexport function createUnknownHelperMessage(helperName: string): string {\n\treturn `Unknown block helper \"{{#${helperName}}}\" — cannot analyze statically`;\n}\n\n/**\n * Crée un message pour une expression non analysable.\n */\nexport function createUnanalyzableMessage(nodeType: string): string {\n\treturn `Expression of type \"${nodeType}\" cannot be statically analyzed`;\n}\n\n/**\n * Détermine le DiagnosticCode approprié pour une erreur d'identifiant.\n */\nexport function getIdentifierErrorCode(\n\thasSchemas: boolean,\n\thasSpecificSchema: boolean,\n): DiagnosticCode {\n\tif (!hasSchemas) return \"MISSING_IDENTIFIER_SCHEMAS\";\n\tif (!hasSpecificSchema) return \"UNKNOWN_IDENTIFIER\";\n\treturn \"IDENTIFIER_PROPERTY_NOT_FOUND\";\n}\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "AAMO,MAAM,UAAsB,KAAM,CACxC,WAAW,CAAC,EAAiB,CAC5B,MAAM,CAAO,EACb,KAAK,KAAO,gBAOb,MAAM,EAA4B,CACjC,MAAO,CACN,KAAM,KAAK,KACX,QAAS,KAAK,OACf,EAEF,CAKO,MAAM,UAA2B,CAAc,CAIpC,IAEA,OALjB,WAAW,CACV,EAEgB,EAEA,EACf,CACD,MAAM,gBAAgB,GAAS,EAJf,WAEA,cAGhB,KAAK,KAAO,qBAGJ,MAAM,EAA4B,CAC1C,MAAO,CACN,KAAM,KAAK,KACX,QAAS,KAAK,QACd,IAAK,KAAK,IACV,OAAQ,KAAK,MACd,EAEF,CAMO,MAAM,UAA8B,CAAc,CAExC,YAGA,OAGA,SAGA,WAGA,aAEhB,WAAW,CAAC,EAAmC,CAC9C,IAAM,EAAS,EAAY,OAAO,CAAC,IAAM,EAAE,WAAa,OAAO,EACzD,EAAW,EAAY,OAAO,CAAC,IAAM,EAAE,WAAa,SAAS,EAE7D,EAAU,EAAO,IAAI,CAAC,IAAM,EAAqB,CAAC,CAAC,EAAE,KAAK;AAAA,CAAI,EACpE,MAAM,+BAA+B,EAAO;AAAA,EAAqB,GAAS,EAE1E,KAAK,KAAO,wBACZ,KAAK,YAAc,EACnB,KAAK,OAAS,EACd,KAAK,SAAW,EAChB,KAAK,WAAa,EAAO,OACzB,KAAK,aAAe,EAAS,OA+BrB,MAAM,EAA4B,CAC1C,MAAO,CACN,KAAM,KAAK,KACX,QAAS,KAAK,QACd,WAAY,KAAK,WACjB,aAAc,KAAK,aACnB,YAAa,KAAK,WACnB,EAEF,CAMO,MAAM,UAA6B,CAAc,CACvD,WAAW,CAAC,EAAiB,CAC5B,MAAM,kBAAkB,GAAS,EACjC,KAAK,KAAO,uBAEd,CAWA,SAAS,CAAoB,CAAC,EAAkC,CAC/D,IAAM,EAAkB,CAAC,QAAO,EAAK,SAAS,EAAK,SAAS,EAE5D,GAAI,EAAK,IACR,EAAM,KAAK,OAAO,EAAK,IAAI,MAAM,QAAQ,EAAK,IAAI,MAAM,SAAS,EAGlE,OAAO,EAAM,KAAK,GAAG,EAUf,SAAS,CAA6B,CAC5C,EACA,EACS,CACT,IAAM,EAAO,aAAa,0CAC1B,GAAI,EAAoB,SAAW,EAAG,OAAO,EAC7C,MAAO,GAAG,4BAA+B,EAAoB,KAAK,IAAI,IAMhE,SAAS,CAAyB,CACxC,EACA,EACA,EACS,CACT,MAAO,OAAO,gBAAyB,oCAA2C,KAM5E,SAAS,CAA4B,CAAC,EAA4B,CACxE,MAAO,OAAO,4BAMR,SAAS,CAA0B,CAAC,EAA4B,CACtE,MAAO,4BAA4B,mCAM7B,SAAS,CAAyB,CAAC,EAA0B,CACnE,MAAO,uBAAuB,mCAMxB,SAAS,CAAsB,CACrC,EACA,EACiB,CACjB,GAAI,CAAC,EAAY,MAAO,6BACxB,GAAI,CAAC,EAAmB,MAAO,qBAC/B,MAAO",
|
|
8
|
-
"debugId": "47521E188A2A57ED64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-xbvk4ygq.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{b as z}from"./chunk-z6yh5qvc.js";import{d as _}from"./chunk-awgj10qg.js";import{g as F}from"./chunk-qpzzr2rd.js";import{j as Z,k as $,l as U}from"./chunk-6955jpr7.js";import{n as E}from"./chunk-1gm6cf0e.js";import{B as C}from"./chunk-ybh51hbe.js";import{N as x,Q as L,R as g}from"./chunk-4zv02svp.js";import R from"handlebars";var j=new Set(["+","-","*","/","%","**"]);function K(q){if(typeof q==="number")return q;if(typeof q==="string"){let B=Number(q);return Number.isNaN(B)?0:B}return 0}function P(q,B,G){switch(B){case"+":return q+G;case"-":return q-G;case"*":return q*G;case"/":return G===0?1/0:q/G;case"%":return G===0?NaN:q%G;case"**":return q**G}}class Y{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(Y.HELPER_NAMES);static getDefinitions(){let q=new Map;return Y.registerBinaryOperators(q),Y.registerUnaryFunctions(q),Y.registerMinMax(q),Y.registerGenericMath(q),q}static registerBinaryOperators(q){let B={fn:(V,X)=>K(V)+K(X),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 }}"};q.set("add",B);let G={fn:(V,X)=>K(V)-K(X),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 }}"};q.set("subtract",G),q.set("sub",G);let J={fn:(V,X)=>K(V)*K(X),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 }}"};q.set("multiply",J),q.set("mul",J);let Q={fn:(V,X)=>{let w=K(X);return w===0?1/0:K(V)/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."};q.set("divide",Q),q.set("div",Q);let W={fn:(V,X)=>{let w=K(X);return w===0?NaN:K(V)%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 }}"};q.set("modulo",W),q.set("mod",W),q.set("pow",{fn:(V,X)=>K(V)**K(X),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(q){q.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 }}"}),q.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 }}"}),q.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 }}"}),q.set("round",{fn:(B,G)=>{let J=K(B);if(G===void 0||G===null||typeof G==="object")return Math.round(J);let W=10**K(G);return Math.round(J*W)/W},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 }}"}),q.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(q){q.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 }}"}),q.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(q){q.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 P(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(q){let B=Y.getDefinitions();for(let[G,J]of B)q.registerHelper(G,J)}static unregister(q){for(let B of Y.HELPER_NAMES)q.unregisterHelper(B)}static getHelperNames(){return Y.HELPER_NAMES}static isMathHelper(q){return Y.HELPER_NAMES_SET.has(q)}}class k{hbs;astCache;compilationCache;helpers=new Map;constructor(q={}){if(this.hbs=R.create(),this.astCache=new x(q.astCacheSize??256),this.compilationCache=new x(q.compilationCacheSize??256),Y.register(this),q.helpers)for(let B of q.helpers){let{name:G,...J}=B;this.registerHelper(G,J)}}compile(q){if($(q)){let J={};for(let[Q,W]of Object.entries(q))J[Q]=this.compile(W);return z.fromObject(J,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache})}if(Z(q))return z.fromLiteral(q,{helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache});let B=this.getCachedAst(q),G={helpers:this.helpers,hbs:this.hbs,compilationCache:this.compilationCache};return z.fromTemplate(B,q,G)}analyze(q,B,G){if($(q))return L(Object.keys(q),(Q)=>this.analyze(q[Q],B,G));if(Z(q))return{valid:!0,diagnostics:[],outputSchema:U(q)};let J=this.getCachedAst(q);return _(J,q,B,{identifierSchemas:G,helpers:this.helpers})}validate(q,B,G){let J=this.analyze(q,B,G);return{valid:J.valid,diagnostics:J.diagnostics}}isValidSyntax(q){if($(q))return Object.values(q).every((B)=>this.isValidSyntax(B));if(Z(q))return!0;try{return this.getCachedAst(q),!0}catch{return!1}}execute(q,B,G){if($(q)){let Q={};for(let[W,V]of Object.entries(q))Q[W]=this.execute(V,B,G);return Q}if(Z(q))return q;let J=this.getCachedAst(q);if(G?.schema){let Q=_(J,q,G.schema,{identifierSchemas:G.identifierSchemas,helpers:this.helpers});if(!Q.valid)throw new C(Q.diagnostics)}return F(J,q,B,{identifierData:G?.identifierData,hbs:this.hbs,compilationCache:this.compilationCache})}analyzeAndExecute(q,B,G,J){if($(q))return g(Object.keys(q),(X)=>this.analyzeAndExecute(q[X],B,G,J));if(Z(q))return{analysis:{valid:!0,diagnostics:[],outputSchema:U(q)},value:q};let Q=this.getCachedAst(q),W=_(Q,q,B,{identifierSchemas:J?.identifierSchemas,helpers:this.helpers});if(!W.valid)return{analysis:W,value:void 0};let V=F(Q,q,G,{identifierData:J?.identifierData,hbs:this.hbs,compilationCache:this.compilationCache});return{analysis:W,value:V}}registerHelper(q,B){return this.helpers.set(q,B),this.hbs.registerHelper(q,B.fn),this.compilationCache.clear(),this}unregisterHelper(q){return this.helpers.delete(q),this.hbs.unregisterHelper(q),this.compilationCache.clear(),this}hasHelper(q){return this.helpers.has(q)}clearCaches(){this.astCache.clear(),this.compilationCache.clear()}getCachedAst(q){let B=this.astCache.get(q);if(!B)B=E(q),this.astCache.set(q,B);return B}}
|
|
2
|
-
export{k as a};
|
|
3
|
-
|
|
4
|
-
//# debugId=073ABADC78560F0964756E2164756E21
|
|
5
|
-
//# sourceMappingURL=chunk-xbvk4ygq.js.map
|
|
@@ -1,11 +0,0 @@
|
|
|
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\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 (math) ──────────────────────────────────────\n\t\tMathHelpers.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// ─── 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// MathHelpers.register(engine); // registers all helpers\n// MathHelpers.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/** Minimal registration interface — avoids tight coupling with Typebars */\ninterface HelperRegistry {\n\tregisterHelper(name: string, definition: HelperDefinition): unknown;\n\tunregisterHelper(name: string): unknown;\n}\n\n/** Operators supported by the generic `math` helper */\ntype MathOperator = \"+\" | \"-\" | \"*\" | \"/\" | \"%\" | \"**\";\n\nconst SUPPORTED_OPERATORS = new Set<string>([\"+\", \"-\", \"*\", \"/\", \"%\", \"**\"]);\n\n// ─── Internal utilities ─────────────────────────────────────────────────────\n\n/**\n * Converts an unknown value to a number.\n * Returns `0` when conversion fails (non-numeric string, object, 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 * 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 {\n\t// ─── All registered helper names ─────────────────────────────────────\n\t// Used by `register()` and `unregister()` to iterate.\n\tprivate static readonly HELPER_NAMES: readonly string[] = [\n\t\t// Binary operators\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// Unary functions\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 (binary)\n\t\t\"min\",\n\t\t\"max\",\n\n\t\t// Generic helper\n\t\t\"math\",\n\t];\n\n\t/** Set derived from `HELPER_NAMES` for O(1) lookup in `isMathHelper()` */\n\tprivate static readonly HELPER_NAMES_SET: ReadonlySet<string> = new Set(\n\t\tMathHelpers.HELPER_NAMES,\n\t);\n\n\t// ─── Helper definitions ─────────────────────────────────────────────\n\n\t/** Returns all definitions as a `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// ── Binary operators ─────────────────────────────────────────────\n\n\t/** Registers 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 — Subtraction: {{ subtract a b }} or {{ 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 }} or {{ 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 }} or {{ 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 }} or {{ 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// ── Unary functions ──────────────────────────────────────────────\n\n\t/** Registers abs, ceil, floor, round, sqrt */\n\tprivate static registerUnaryFunctions(\n\t\tdefs: Map<string, HelperDefinition>,\n\t): void {\n\t\t// abs — Absolute value: {{ 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 — Round up: {{ 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 — Round down: {{ 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 — 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 = toNumber(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 = 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 — Square root: {{ 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/** Registers min and 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// ── Generic helper ───────────────────────────────────────────────\n\n\t/** Registers the generic `math` helper with operator as a parameter */\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// ─── Registration / Unregistration ───────────────────────────────────\n\n\t/**\n\t * Registers all math helpers on a `Typebars` instance\n\t * (or any object implementing `HelperRegistry`).\n\t *\n\t * **Note:** MathHelpers are automatically pre-registered by the\n\t * `Typebars` constructor. This method is only useful if you have\n\t * called `unregister()` and want to re-enable them, or if you are\n\t * registering on a custom registry.\n\t *\n\t * @param registry - The engine or target registry\n\t *\n\t * @example\n\t * ```\n\t * const engine = new Typebars();\n\t * // Math helpers are already available!\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 * Removes all math helpers from the registry.\n\t *\n\t * @param registry - The engine or target registry\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 * Returns the list of all math helper names.\n\t * Useful for checking whether a given helper belongs to the math pack.\n\t */\n\tstatic getHelperNames(): readonly string[] {\n\t\treturn MathHelpers.HELPER_NAMES;\n\t}\n\n\t/**\n\t * Checks whether a helper name belongs to the math pack.\n\t *\n\t * @param name - The helper name to check\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": "073ABADC78560F0964756E2164756E21",
|
|
10
|
-
"names": []
|
|
11
|
-
}
|
package/dist/chunk-ybh51hbe.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
class B extends Error{constructor(j){super(j);this.name="TemplateError"}toJSON(){return{name:this.name,message:this.message}}}class G extends B{loc;source;constructor(j,k,q){super(`Parse error: ${j}`);this.loc=k;this.source=q;this.name="TemplateParseError"}toJSON(){return{name:this.name,message:this.message,loc:this.loc,source:this.source}}}class H extends B{diagnostics;errors;warnings;errorCount;warningCount;constructor(j){let k=j.filter((A)=>A.severity==="error"),q=j.filter((A)=>A.severity==="warning"),F=k.map((A)=>J(A)).join(`
|
|
2
|
-
`);super(`Static analysis failed with ${k.length} error(s):
|
|
3
|
-
${F}`);this.name="TemplateAnalysisError",this.diagnostics=j,this.errors=k,this.warnings=q,this.errorCount=k.length,this.warningCount=q.length}toJSON(){return{name:this.name,message:this.message,errorCount:this.errorCount,warningCount:this.warningCount,diagnostics:this.diagnostics}}}class I extends B{constructor(j){super(`Runtime error: ${j}`);this.name="TemplateRuntimeError"}}function J(j){let k=[` • [${j.code}] ${j.message}`];if(j.loc)k.push(`(at ${j.loc.start.line}:${j.loc.start.column})`);return k.join(" ")}function K(j,k){let q=`Property "${j}" does not exist in the context schema`;if(k.length===0)return q;return`${q}. Available properties: ${k.join(", ")}`}function M(j,k,q){return`"{{#${j}}}" expects ${k}, but resolved schema has type "${q}"`}function O(j){return`"{{#${j}}}" requires an argument`}function Q(j){return`Unknown block helper "{{#${j}}}" — cannot analyze statically`}function R(j){return`Expression of type "${j}" cannot be statically analyzed`}
|
|
4
|
-
export{B as z,G as A,H as B,I as C,K as D,M as E,O as F,Q as G,R as H};
|
|
5
|
-
|
|
6
|
-
//# debugId=C1C5104B96E761E764756E2164756E21
|
|
7
|
-
//# sourceMappingURL=chunk-ybh51hbe.js.map
|