@twinfinity/printing 5.0.3-ci.28538-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/README.md +208 -0
  2. package/dist/BuildInfo.d.ts +25 -0
  3. package/dist/BuildInfo.d.ts.map +1 -0
  4. package/dist/BuildInfo.js +15 -0
  5. package/dist/BuildInfo.js.map +1 -0
  6. package/dist/index.d.ts +7 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +9 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/layout/analyzeTemplate.d.ts +29 -0
  11. package/dist/layout/analyzeTemplate.d.ts.map +1 -0
  12. package/dist/layout/analyzeTemplate.js +168 -0
  13. package/dist/layout/analyzeTemplate.js.map +1 -0
  14. package/dist/layout/clipUtils.d.ts +18 -0
  15. package/dist/layout/clipUtils.d.ts.map +1 -0
  16. package/dist/layout/clipUtils.js +165 -0
  17. package/dist/layout/clipUtils.js.map +1 -0
  18. package/dist/layout/colorConstants.d.ts +11 -0
  19. package/dist/layout/colorConstants.d.ts.map +1 -0
  20. package/dist/layout/colorConstants.js +14 -0
  21. package/dist/layout/colorConstants.js.map +1 -0
  22. package/dist/layout/elementKinds.d.ts +21 -0
  23. package/dist/layout/elementKinds.d.ts.map +1 -0
  24. package/dist/layout/elementKinds.js +17 -0
  25. package/dist/layout/elementKinds.js.map +1 -0
  26. package/dist/layout/exportDrawing.d.ts +143 -0
  27. package/dist/layout/exportDrawing.d.ts.map +1 -0
  28. package/dist/layout/exportDrawing.js +146 -0
  29. package/dist/layout/exportDrawing.js.map +1 -0
  30. package/dist/layout/filters.d.ts +33 -0
  31. package/dist/layout/filters.d.ts.map +1 -0
  32. package/dist/layout/filters.js +77 -0
  33. package/dist/layout/filters.js.map +1 -0
  34. package/dist/layout/geometryConstants.d.ts +8 -0
  35. package/dist/layout/geometryConstants.d.ts.map +1 -0
  36. package/dist/layout/geometryConstants.js +10 -0
  37. package/dist/layout/geometryConstants.js.map +1 -0
  38. package/dist/layout/index.d.ts +86 -0
  39. package/dist/layout/index.d.ts.map +1 -0
  40. package/dist/layout/index.js +363 -0
  41. package/dist/layout/index.js.map +1 -0
  42. package/dist/layout/itemBuilders.d.ts +29 -0
  43. package/dist/layout/itemBuilders.d.ts.map +1 -0
  44. package/dist/layout/itemBuilders.js +135 -0
  45. package/dist/layout/itemBuilders.js.map +1 -0
  46. package/dist/layout/labelsRender.d.ts +29 -0
  47. package/dist/layout/labelsRender.d.ts.map +1 -0
  48. package/dist/layout/labelsRender.js +109 -0
  49. package/dist/layout/labelsRender.js.map +1 -0
  50. package/dist/layout/legendConstants.d.ts +12 -0
  51. package/dist/layout/legendConstants.d.ts.map +1 -0
  52. package/dist/layout/legendConstants.js +12 -0
  53. package/dist/layout/legendConstants.js.map +1 -0
  54. package/dist/layout/legendRender.d.ts +13 -0
  55. package/dist/layout/legendRender.d.ts.map +1 -0
  56. package/dist/layout/legendRender.js +424 -0
  57. package/dist/layout/legendRender.js.map +1 -0
  58. package/dist/layout/legendRows.d.ts +26 -0
  59. package/dist/layout/legendRows.d.ts.map +1 -0
  60. package/dist/layout/legendRows.js +45 -0
  61. package/dist/layout/legendRows.js.map +1 -0
  62. package/dist/layout/legendUtils.d.ts +21 -0
  63. package/dist/layout/legendUtils.d.ts.map +1 -0
  64. package/dist/layout/legendUtils.js +110 -0
  65. package/dist/layout/legendUtils.js.map +1 -0
  66. package/dist/layout/metadata.d.ts +43 -0
  67. package/dist/layout/metadata.d.ts.map +1 -0
  68. package/dist/layout/metadata.js +191 -0
  69. package/dist/layout/metadata.js.map +1 -0
  70. package/dist/layout/model.d.ts +15 -0
  71. package/dist/layout/model.d.ts.map +1 -0
  72. package/dist/layout/model.js +310 -0
  73. package/dist/layout/model.js.map +1 -0
  74. package/dist/layout/options.d.ts +17 -0
  75. package/dist/layout/options.d.ts.map +1 -0
  76. package/dist/layout/options.js +2 -0
  77. package/dist/layout/options.js.map +1 -0
  78. package/dist/layout/presets.d.ts +23 -0
  79. package/dist/layout/presets.d.ts.map +1 -0
  80. package/dist/layout/presets.js +41 -0
  81. package/dist/layout/presets.js.map +1 -0
  82. package/dist/layout/qrRender.d.ts +13 -0
  83. package/dist/layout/qrRender.d.ts.map +1 -0
  84. package/dist/layout/qrRender.js +97 -0
  85. package/dist/layout/qrRender.js.map +1 -0
  86. package/dist/layout/renderDrawing.d.ts +62 -0
  87. package/dist/layout/renderDrawing.d.ts.map +1 -0
  88. package/dist/layout/renderDrawing.js +555 -0
  89. package/dist/layout/renderDrawing.js.map +1 -0
  90. package/dist/layout/renderUtils.d.ts +36 -0
  91. package/dist/layout/renderUtils.d.ts.map +1 -0
  92. package/dist/layout/renderUtils.js +117 -0
  93. package/dist/layout/renderUtils.js.map +1 -0
  94. package/dist/layout/sectionValidation.d.ts +3 -0
  95. package/dist/layout/sectionValidation.d.ts.map +1 -0
  96. package/dist/layout/sectionValidation.js +2 -0
  97. package/dist/layout/sectionValidation.js.map +1 -0
  98. package/dist/layout/templateVariables.d.ts +137 -0
  99. package/dist/layout/templateVariables.d.ts.map +1 -0
  100. package/dist/layout/templateVariables.js +295 -0
  101. package/dist/layout/templateVariables.js.map +1 -0
  102. package/dist/layout/typeGuards.d.ts +5 -0
  103. package/dist/layout/typeGuards.d.ts.map +1 -0
  104. package/dist/layout/typeGuards.js +9 -0
  105. package/dist/layout/typeGuards.js.map +1 -0
  106. package/dist/layout/types.d.ts +816 -0
  107. package/dist/layout/types.d.ts.map +1 -0
  108. package/dist/layout/types.js +2 -0
  109. package/dist/layout/types.js.map +1 -0
  110. package/dist/layout/utils.d.ts +9 -0
  111. package/dist/layout/utils.d.ts.map +1 -0
  112. package/dist/layout/utils.js +84 -0
  113. package/dist/layout/utils.js.map +1 -0
  114. package/dist/layout/validation.d.ts +7 -0
  115. package/dist/layout/validation.d.ts.map +1 -0
  116. package/dist/layout/validation.js +352 -0
  117. package/dist/layout/validation.js.map +1 -0
  118. package/dist/layout/validationHelpers.d.ts +15 -0
  119. package/dist/layout/validationHelpers.d.ts.map +1 -0
  120. package/dist/layout/validationHelpers.js +43 -0
  121. package/dist/layout/validationHelpers.js.map +1 -0
  122. package/dist/layout/validationUtils.d.ts +5 -0
  123. package/dist/layout/validationUtils.d.ts.map +1 -0
  124. package/dist/layout/validationUtils.js +5 -0
  125. package/dist/layout/validationUtils.js.map +1 -0
  126. package/dist/layout/viewportPrep.d.ts +47 -0
  127. package/dist/layout/viewportPrep.d.ts.map +1 -0
  128. package/dist/layout/viewportPrep.js +275 -0
  129. package/dist/layout/viewportPrep.js.map +1 -0
  130. package/dist/layout/viewportRender.d.ts +42 -0
  131. package/dist/layout/viewportRender.d.ts.map +1 -0
  132. package/dist/layout/viewportRender.js +337 -0
  133. package/dist/layout/viewportRender.js.map +1 -0
  134. package/dist/layout/viewportUtils.d.ts +9 -0
  135. package/dist/layout/viewportUtils.d.ts.map +1 -0
  136. package/dist/layout/viewportUtils.js +40 -0
  137. package/dist/layout/viewportUtils.js.map +1 -0
  138. package/dist/layout/warnings.d.ts +2 -0
  139. package/dist/layout/warnings.d.ts.map +1 -0
  140. package/dist/layout/warnings.js +4 -0
  141. package/dist/layout/warnings.js.map +1 -0
  142. package/dist/printToPdf.d.ts +38 -0
  143. package/dist/printToPdf.d.ts.map +1 -0
  144. package/dist/printToPdf.js +79 -0
  145. package/dist/printToPdf.js.map +1 -0
  146. package/dist/printToSvg.d.ts +11 -0
  147. package/dist/printToSvg.d.ts.map +1 -0
  148. package/dist/printToSvg.js +168 -0
  149. package/dist/printToSvg.js.map +1 -0
  150. package/dist/sections.d.ts +118 -0
  151. package/dist/sections.d.ts.map +1 -0
  152. package/dist/sections.js +839 -0
  153. package/dist/sections.js.map +1 -0
  154. package/dist/templates/default-template.json +137 -0
  155. package/dist/types.d.ts +54 -0
  156. package/dist/types.d.ts.map +1 -0
  157. package/dist/types.js +11 -0
  158. package/dist/types.js.map +1 -0
  159. package/package.json +47 -0
  160. package/src/BuildInfo.ts +41 -0
  161. package/src/index.ts +10 -0
  162. package/src/layout/analyzeTemplate.ts +218 -0
  163. package/src/layout/clipUtils.ts +193 -0
  164. package/src/layout/colorConstants.ts +16 -0
  165. package/src/layout/elementKinds.ts +35 -0
  166. package/src/layout/exportDrawing.ts +206 -0
  167. package/src/layout/filters.ts +80 -0
  168. package/src/layout/geometryConstants.ts +11 -0
  169. package/src/layout/index.ts +671 -0
  170. package/src/layout/itemBuilders.ts +159 -0
  171. package/src/layout/labelsRender.ts +170 -0
  172. package/src/layout/legendConstants.ts +11 -0
  173. package/src/layout/legendRender.ts +543 -0
  174. package/src/layout/legendRows.ts +62 -0
  175. package/src/layout/legendUtils.ts +144 -0
  176. package/src/layout/metadata.ts +210 -0
  177. package/src/layout/model.ts +372 -0
  178. package/src/layout/options.ts +17 -0
  179. package/src/layout/presets.ts +51 -0
  180. package/src/layout/qrRender.ts +126 -0
  181. package/src/layout/qrcode.d.ts +2 -0
  182. package/src/layout/renderDrawing.ts +710 -0
  183. package/src/layout/renderUtils.ts +138 -0
  184. package/src/layout/sectionValidation.ts +2 -0
  185. package/src/layout/templateVariables.ts +317 -0
  186. package/src/layout/typeGuards.ts +9 -0
  187. package/src/layout/types.ts +835 -0
  188. package/src/layout/utils.ts +85 -0
  189. package/src/layout/validation.ts +392 -0
  190. package/src/layout/validationHelpers.ts +59 -0
  191. package/src/layout/validationUtils.ts +6 -0
  192. package/src/layout/viewportPrep.ts +351 -0
  193. package/src/layout/viewportRender.ts +442 -0
  194. package/src/layout/viewportUtils.ts +50 -0
  195. package/src/layout/warnings.ts +3 -0
  196. package/src/printToPdf.ts +108 -0
  197. package/src/printToSvg.ts +188 -0
  198. package/src/sections.ts +1019 -0
  199. package/src/templates/default-template.json +137 -0
  200. package/src/types.ts +49 -0
  201. package/templates/default-a0-landscape.json +209 -0
  202. package/templates/default-a0-portrait.json +195 -0
  203. package/templates/default-a1-landscape.json +167 -0
  204. package/templates/default-a1-portrait.json +153 -0
  205. package/templates/default-a3-landscape.json +111 -0
  206. package/templates/default-a3-portrait.json +125 -0
  207. package/templates/default-a4-landscape.json +97 -0
  208. package/templates/default-a4-portrait.json +97 -0
  209. package/templates/template-schema.json +1395 -0
@@ -0,0 +1,295 @@
1
+ /**
2
+ * Template variable extraction, validation, and resolution.
3
+ *
4
+ * This module provides utilities for working with parameterized templates:
5
+ * - Extract variable definitions for UI generation
6
+ * - Get default values (fail-safe fallback)
7
+ * - Resolve user-provided values with validation
8
+ * - Apply variables to template (substitute {{vars.*}} references)
9
+ *
10
+ * @module templateVariables
11
+ */
12
+ /**
13
+ * Extract all variable definitions from a template.
14
+ *
15
+ * Returns an array of variable info objects suitable for UI generation.
16
+ * Returns empty array if template has no variables.
17
+ *
18
+ * @param template - Layout template (may or may not have variables)
19
+ * @returns Array of variable definitions with metadata
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const vars = getTemplateVariables(template);
24
+ * // [
25
+ * // { name: 'hyresobjektsnummer', type: 'string', default: '2022-F2008', label: 'Hyresobjekt', ... },
26
+ * // { name: 'showLegend', type: 'boolean', default: true, label: 'Show Legend', ... }
27
+ * // ]
28
+ *
29
+ * // Use for UI generation
30
+ * vars.forEach(v => {
31
+ * if (v.type === 'string') {
32
+ * renderTextField(v.label, v.default);
33
+ * } else if (v.type === 'boolean') {
34
+ * renderCheckbox(v.label, v.default);
35
+ * }
36
+ * });
37
+ * ```
38
+ */
39
+ export function getTemplateVariables(template) {
40
+ if (!template.variables)
41
+ return [];
42
+ return Object.entries(template.variables).map(([name, def]) => ({
43
+ name,
44
+ type: def.type,
45
+ default: def.default,
46
+ label: def.label ?? name,
47
+ description: def.description,
48
+ format: def.format,
49
+ min: def.min,
50
+ max: def.max,
51
+ step: def.step,
52
+ minLength: def.minLength,
53
+ maxLength: def.maxLength,
54
+ pattern: def.pattern,
55
+ enum: def.enum,
56
+ items: def.items
57
+ }));
58
+ }
59
+ /**
60
+ * Extract all default values from a template.
61
+ *
62
+ * Returns an object with all variable names mapped to their default values.
63
+ * These defaults are guaranteed to work - template can always render with them.
64
+ *
65
+ * Returns empty object if template has no variables.
66
+ *
67
+ * @param template - Layout template
68
+ * @returns Object mapping variable names to default values
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const defaults = getTemplateDefaults(template);
73
+ * // { hyresobjektsnummer: '2022-F2008', showLegend: true, scaleDenom: 100 }
74
+ *
75
+ * // Can always render with defaults (fail-safe)
76
+ * const { svg } = await renderDrawing({
77
+ * template,
78
+ * models,
79
+ * variables: defaults // Guaranteed to work
80
+ * });
81
+ * ```
82
+ */
83
+ export function getTemplateDefaults(template) {
84
+ if (!template.variables)
85
+ return {};
86
+ const defaults = {};
87
+ for (const [name, def] of Object.entries(template.variables)) {
88
+ defaults[name] = def.default;
89
+ }
90
+ return defaults;
91
+ }
92
+ /**
93
+ * Validate a value against a variable definition.
94
+ *
95
+ * Checks type and constraint validation (min/max, pattern, enum, etc.).
96
+ *
97
+ * @param value - Value to validate
98
+ * @param varDef - Variable definition with constraints
99
+ * @returns Validation result with ok flag and optional error message
100
+ */
101
+ function validateVariable(value, varDef) {
102
+ // Type check
103
+ const actualType = Array.isArray(value) ? 'array' : typeof value;
104
+ if (varDef.type === 'number' && actualType !== 'number') {
105
+ return { ok: false, error: `Expected number, got ${actualType}` };
106
+ }
107
+ if (varDef.type === 'string' && actualType !== 'string') {
108
+ return { ok: false, error: `Expected string, got ${actualType}` };
109
+ }
110
+ if (varDef.type === 'boolean' && actualType !== 'boolean') {
111
+ return { ok: false, error: `Expected boolean, got ${actualType}` };
112
+ }
113
+ if (varDef.type === 'array' && actualType !== 'array') {
114
+ return { ok: false, error: `Expected array, got ${actualType}` };
115
+ }
116
+ // String validation
117
+ if (varDef.type === 'string' && typeof value === 'string') {
118
+ if (varDef.minLength !== undefined && value.length < varDef.minLength) {
119
+ return { ok: false, error: `String too short (min ${varDef.minLength})` };
120
+ }
121
+ if (varDef.maxLength !== undefined && value.length > varDef.maxLength) {
122
+ return { ok: false, error: `String too long (max ${varDef.maxLength})` };
123
+ }
124
+ if (varDef.pattern) {
125
+ try {
126
+ const regex = new RegExp(varDef.pattern);
127
+ if (!regex.test(value)) {
128
+ return { ok: false, error: `Does not match pattern ${varDef.pattern}` };
129
+ }
130
+ }
131
+ catch {
132
+ return { ok: false, error: `Invalid pattern: ${varDef.pattern}` };
133
+ }
134
+ }
135
+ if (varDef.enum && !varDef.enum.includes(value)) {
136
+ return { ok: false, error: `Not in allowed values: ${varDef.enum.join(', ')}` };
137
+ }
138
+ }
139
+ // Number validation
140
+ if (varDef.type === 'number' && typeof value === 'number') {
141
+ if (!Number.isFinite(value)) {
142
+ return { ok: false, error: 'Must be a finite number' };
143
+ }
144
+ if (varDef.min !== undefined && value < varDef.min) {
145
+ return { ok: false, error: `Too small (min ${varDef.min})` };
146
+ }
147
+ if (varDef.max !== undefined && value > varDef.max) {
148
+ return { ok: false, error: `Too large (max ${varDef.max})` };
149
+ }
150
+ }
151
+ return { ok: true };
152
+ }
153
+ /**
154
+ * Resolve template variables by merging user values with defaults.
155
+ *
156
+ * This is a **fail-safe** function:
157
+ * - Missing values → use default
158
+ * - Invalid values → use default + warn
159
+ * - Unknown variables → warn + ignore
160
+ *
161
+ * The result is ALWAYS valid and complete (safe to use for rendering).
162
+ *
163
+ * @param template - Layout template with variable definitions
164
+ * @param userValues - Optional user-provided values (can be partial or undefined)
165
+ * @returns Object with resolved values and any validation warnings
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * // User provides partial values
170
+ * const { values, warnings } = resolveTemplateValues(template, {
171
+ * hyresobjektsnummer: '2022-F2009' // Valid
172
+ * // Other vars use defaults
173
+ * });
174
+ * // values = { hyresobjektsnummer: '2022-F2009', showLegend: true, scaleDenom: 100 }
175
+ * // warnings = []
176
+ *
177
+ * // User provides invalid value
178
+ * const { values, warnings } = resolveTemplateValues(template, {
179
+ * scaleDenom: 9999 // Out of range (max: 500)
180
+ * });
181
+ * // values = { scaleDenom: 100, ... } ← Fell back to default
182
+ * // warnings = ["Invalid 'scaleDenom': Too large (max 500) - using default '100'"]
183
+ *
184
+ * // Always safe to render
185
+ * const resolvedTemplate = applyTemplateVariables(template, values);
186
+ * ```
187
+ */
188
+ export function resolveTemplateValues(template, userValues) {
189
+ const defaults = getTemplateDefaults(template);
190
+ const warnings = [];
191
+ // Start with all defaults (fail-safe!)
192
+ const values = { ...defaults };
193
+ // No user values or no variables → return defaults
194
+ if (!userValues || !template.variables) {
195
+ return { values, warnings };
196
+ }
197
+ // Merge and validate user values
198
+ for (const [name, value] of Object.entries(userValues)) {
199
+ const varDef = template.variables[name];
200
+ // Unknown variable
201
+ if (!varDef) {
202
+ warnings.push(`Unknown variable '${name}' - ignoring`);
203
+ continue;
204
+ }
205
+ // Validate value
206
+ const validation = validateVariable(value, varDef);
207
+ if (!validation.ok) {
208
+ warnings.push(`Invalid '${name}': ${validation.error} - using default '${defaults[name]}'`);
209
+ continue;
210
+ }
211
+ // Valid → use it
212
+ values[name] = value;
213
+ }
214
+ return { values, warnings };
215
+ }
216
+ /**
217
+ * Apply variables to a template by substituting {{vars.*}} references.
218
+ *
219
+ * Recursively scans the template and replaces all {{vars.variableName}} references
220
+ * with the corresponding values from the provided values object.
221
+ *
222
+ * Returns a new template with all variables resolved (does not mutate input).
223
+ *
224
+ * @param template - Original template with {{vars.*}} references
225
+ * @param values - Resolved variable values (from resolveTemplateValues)
226
+ * @returns New template with all {{vars.*}} replaced by actual values
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * const template = {
231
+ * elements: [
232
+ * { kind: 'text', text: 'Hyresobjekt: {{vars.hyresobjektsnummer}}' },
233
+ * { kind: 'viewport', clip: { where: { 'BIP.id': '{{vars.hyresobjektsnummer}}' } } }
234
+ * ]
235
+ * };
236
+ *
237
+ * const values = { hyresobjektsnummer: '2022-F2009' };
238
+ * const resolved = applyTemplateVariables(template, values);
239
+ * // {
240
+ * // elements: [
241
+ * // { kind: 'text', text: 'Hyresobjekt: 2022-F2009' },
242
+ * // { kind: 'viewport', clip: { where: { 'BIP.id': '2022-F2009' } } }
243
+ * // ]
244
+ * // }
245
+ * ```
246
+ */
247
+ export function applyTemplateVariables(template, values) {
248
+ // Deep clone to avoid mutation
249
+ const resolved = JSON.parse(JSON.stringify(template));
250
+ // Recursively replace {{vars.*}} in all string values
251
+ function replaceInValue(obj) {
252
+ if (typeof obj === 'string') {
253
+ return interpolateVariables(obj, values);
254
+ }
255
+ if (Array.isArray(obj)) {
256
+ return obj.map(replaceInValue);
257
+ }
258
+ if (obj && typeof obj === 'object') {
259
+ const result = {};
260
+ for (const [key, val] of Object.entries(obj)) {
261
+ result[key] = replaceInValue(val);
262
+ }
263
+ return result;
264
+ }
265
+ return obj;
266
+ }
267
+ // Apply to all template properties that might contain variable references
268
+ resolved.elements = replaceInValue(resolved.elements);
269
+ if (resolved.assets) {
270
+ resolved.assets = replaceInValue(resolved.assets);
271
+ }
272
+ return resolved;
273
+ }
274
+ /**
275
+ * Interpolate {{vars.*}} references in a string.
276
+ *
277
+ * Replaces all occurrences of {{vars.variableName}} with the corresponding value.
278
+ * If variable is not found, keeps the placeholder and logs a warning.
279
+ *
280
+ * @param str - String potentially containing {{vars.*}} references
281
+ * @param values - Variable values
282
+ * @returns String with all {{vars.*}} replaced
283
+ */
284
+ function interpolateVariables(str, values) {
285
+ return str.replace(/\{\{vars\.(\w+)\}\}/g, (match, varName) => {
286
+ if (varName in values) {
287
+ const value = values[varName];
288
+ // Convert to string (handles numbers, booleans, etc.)
289
+ return String(value);
290
+ }
291
+ console.warn(`[templateVariables] Variable '${varName}' not found - keeping placeholder`);
292
+ return match; // Keep {{vars.varName}} as-is
293
+ });
294
+ }
295
+ //# sourceMappingURL=templateVariables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templateVariables.js","sourceRoot":"/","sources":["layout/templateVariables.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Template variable extraction, validation, and resolution.\r\n *\r\n * This module provides utilities for working with parameterized templates:\r\n * - Extract variable definitions for UI generation\r\n * - Get default values (fail-safe fallback)\r\n * - Resolve user-provided values with validation\r\n * - Apply variables to template (substitute {{vars.*}} references)\r\n *\r\n * @module templateVariables\r\n */\r\n\r\nimport type { LayoutTemplate, TemplateVariableDef, TemplateVariableInfo } from './types';\r\n\r\n/**\r\n * Extract all variable definitions from a template.\r\n *\r\n * Returns an array of variable info objects suitable for UI generation.\r\n * Returns empty array if template has no variables.\r\n *\r\n * @param template - Layout template (may or may not have variables)\r\n * @returns Array of variable definitions with metadata\r\n *\r\n * @example\r\n * ```typescript\r\n * const vars = getTemplateVariables(template);\r\n * // [\r\n * // { name: 'hyresobjektsnummer', type: 'string', default: '2022-F2008', label: 'Hyresobjekt', ... },\r\n * // { name: 'showLegend', type: 'boolean', default: true, label: 'Show Legend', ... }\r\n * // ]\r\n *\r\n * // Use for UI generation\r\n * vars.forEach(v => {\r\n * if (v.type === 'string') {\r\n * renderTextField(v.label, v.default);\r\n * } else if (v.type === 'boolean') {\r\n * renderCheckbox(v.label, v.default);\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport function getTemplateVariables(template: LayoutTemplate): TemplateVariableInfo[] {\r\n if (!template.variables) return [];\r\n\r\n return Object.entries(template.variables).map(([name, def]) => ({\r\n name,\r\n type: def.type,\r\n default: def.default,\r\n label: def.label ?? name,\r\n description: def.description,\r\n format: def.format,\r\n min: def.min,\r\n max: def.max,\r\n step: def.step,\r\n minLength: def.minLength,\r\n maxLength: def.maxLength,\r\n pattern: def.pattern,\r\n enum: def.enum,\r\n items: def.items\r\n }));\r\n}\r\n\r\n/**\r\n * Extract all default values from a template.\r\n *\r\n * Returns an object with all variable names mapped to their default values.\r\n * These defaults are guaranteed to work - template can always render with them.\r\n *\r\n * Returns empty object if template has no variables.\r\n *\r\n * @param template - Layout template\r\n * @returns Object mapping variable names to default values\r\n *\r\n * @example\r\n * ```typescript\r\n * const defaults = getTemplateDefaults(template);\r\n * // { hyresobjektsnummer: '2022-F2008', showLegend: true, scaleDenom: 100 }\r\n *\r\n * // Can always render with defaults (fail-safe)\r\n * const { svg } = await renderDrawing({\r\n * template,\r\n * models,\r\n * variables: defaults // Guaranteed to work\r\n * });\r\n * ```\r\n */\r\nexport function getTemplateDefaults(template: LayoutTemplate): Record<string, any> {\r\n if (!template.variables) return {};\r\n\r\n const defaults: Record<string, any> = {};\r\n for (const [name, def] of Object.entries(template.variables)) {\r\n defaults[name] = def.default;\r\n }\r\n return defaults;\r\n}\r\n\r\n/**\r\n * Validate a value against a variable definition.\r\n *\r\n * Checks type and constraint validation (min/max, pattern, enum, etc.).\r\n *\r\n * @param value - Value to validate\r\n * @param varDef - Variable definition with constraints\r\n * @returns Validation result with ok flag and optional error message\r\n */\r\nfunction validateVariable(value: any, varDef: TemplateVariableDef): { ok: boolean; error?: string } {\r\n // Type check\r\n const actualType = Array.isArray(value) ? 'array' : typeof value;\r\n if (varDef.type === 'number' && actualType !== 'number') {\r\n return { ok: false, error: `Expected number, got ${actualType}` };\r\n }\r\n if (varDef.type === 'string' && actualType !== 'string') {\r\n return { ok: false, error: `Expected string, got ${actualType}` };\r\n }\r\n if (varDef.type === 'boolean' && actualType !== 'boolean') {\r\n return { ok: false, error: `Expected boolean, got ${actualType}` };\r\n }\r\n if (varDef.type === 'array' && actualType !== 'array') {\r\n return { ok: false, error: `Expected array, got ${actualType}` };\r\n }\r\n\r\n // String validation\r\n if (varDef.type === 'string' && typeof value === 'string') {\r\n if (varDef.minLength !== undefined && value.length < varDef.minLength) {\r\n return { ok: false, error: `String too short (min ${varDef.minLength})` };\r\n }\r\n if (varDef.maxLength !== undefined && value.length > varDef.maxLength) {\r\n return { ok: false, error: `String too long (max ${varDef.maxLength})` };\r\n }\r\n if (varDef.pattern) {\r\n try {\r\n const regex = new RegExp(varDef.pattern);\r\n if (!regex.test(value)) {\r\n return { ok: false, error: `Does not match pattern ${varDef.pattern}` };\r\n }\r\n } catch {\r\n return { ok: false, error: `Invalid pattern: ${varDef.pattern}` };\r\n }\r\n }\r\n if (varDef.enum && !varDef.enum.includes(value)) {\r\n return { ok: false, error: `Not in allowed values: ${varDef.enum.join(', ')}` };\r\n }\r\n }\r\n\r\n // Number validation\r\n if (varDef.type === 'number' && typeof value === 'number') {\r\n if (!Number.isFinite(value)) {\r\n return { ok: false, error: 'Must be a finite number' };\r\n }\r\n if (varDef.min !== undefined && value < varDef.min) {\r\n return { ok: false, error: `Too small (min ${varDef.min})` };\r\n }\r\n if (varDef.max !== undefined && value > varDef.max) {\r\n return { ok: false, error: `Too large (max ${varDef.max})` };\r\n }\r\n }\r\n\r\n return { ok: true };\r\n}\r\n\r\n/**\r\n * Resolve template variables by merging user values with defaults.\r\n *\r\n * This is a **fail-safe** function:\r\n * - Missing values → use default\r\n * - Invalid values → use default + warn\r\n * - Unknown variables → warn + ignore\r\n *\r\n * The result is ALWAYS valid and complete (safe to use for rendering).\r\n *\r\n * @param template - Layout template with variable definitions\r\n * @param userValues - Optional user-provided values (can be partial or undefined)\r\n * @returns Object with resolved values and any validation warnings\r\n *\r\n * @example\r\n * ```typescript\r\n * // User provides partial values\r\n * const { values, warnings } = resolveTemplateValues(template, {\r\n * hyresobjektsnummer: '2022-F2009' // Valid\r\n * // Other vars use defaults\r\n * });\r\n * // values = { hyresobjektsnummer: '2022-F2009', showLegend: true, scaleDenom: 100 }\r\n * // warnings = []\r\n *\r\n * // User provides invalid value\r\n * const { values, warnings } = resolveTemplateValues(template, {\r\n * scaleDenom: 9999 // Out of range (max: 500)\r\n * });\r\n * // values = { scaleDenom: 100, ... } ← Fell back to default\r\n * // warnings = [\"Invalid 'scaleDenom': Too large (max 500) - using default '100'\"]\r\n *\r\n * // Always safe to render\r\n * const resolvedTemplate = applyTemplateVariables(template, values);\r\n * ```\r\n */\r\nexport function resolveTemplateValues(\r\n template: LayoutTemplate,\r\n userValues?: Record<string, any>\r\n): { values: Record<string, any>; warnings: string[] } {\r\n const defaults = getTemplateDefaults(template);\r\n const warnings: string[] = [];\r\n\r\n // Start with all defaults (fail-safe!)\r\n const values = { ...defaults };\r\n\r\n // No user values or no variables → return defaults\r\n if (!userValues || !template.variables) {\r\n return { values, warnings };\r\n }\r\n\r\n // Merge and validate user values\r\n for (const [name, value] of Object.entries(userValues)) {\r\n const varDef = template.variables[name];\r\n\r\n // Unknown variable\r\n if (!varDef) {\r\n warnings.push(`Unknown variable '${name}' - ignoring`);\r\n continue;\r\n }\r\n\r\n // Validate value\r\n const validation = validateVariable(value, varDef);\r\n if (!validation.ok) {\r\n warnings.push(`Invalid '${name}': ${validation.error} - using default '${defaults[name]}'`);\r\n continue;\r\n }\r\n\r\n // Valid → use it\r\n values[name] = value;\r\n }\r\n\r\n return { values, warnings };\r\n}\r\n\r\n/**\r\n * Apply variables to a template by substituting {{vars.*}} references.\r\n *\r\n * Recursively scans the template and replaces all {{vars.variableName}} references\r\n * with the corresponding values from the provided values object.\r\n *\r\n * Returns a new template with all variables resolved (does not mutate input).\r\n *\r\n * @param template - Original template with {{vars.*}} references\r\n * @param values - Resolved variable values (from resolveTemplateValues)\r\n * @returns New template with all {{vars.*}} replaced by actual values\r\n *\r\n * @example\r\n * ```typescript\r\n * const template = {\r\n * elements: [\r\n * { kind: 'text', text: 'Hyresobjekt: {{vars.hyresobjektsnummer}}' },\r\n * { kind: 'viewport', clip: { where: { 'BIP.id': '{{vars.hyresobjektsnummer}}' } } }\r\n * ]\r\n * };\r\n *\r\n * const values = { hyresobjektsnummer: '2022-F2009' };\r\n * const resolved = applyTemplateVariables(template, values);\r\n * // {\r\n * // elements: [\r\n * // { kind: 'text', text: 'Hyresobjekt: 2022-F2009' },\r\n * // { kind: 'viewport', clip: { where: { 'BIP.id': '2022-F2009' } } }\r\n * // ]\r\n * // }\r\n * ```\r\n */\r\nexport function applyTemplateVariables(template: LayoutTemplate, values: Record<string, any>): LayoutTemplate {\r\n // Deep clone to avoid mutation\r\n const resolved: LayoutTemplate = JSON.parse(JSON.stringify(template));\r\n\r\n // Recursively replace {{vars.*}} in all string values\r\n function replaceInValue(obj: any): any {\r\n if (typeof obj === 'string') {\r\n return interpolateVariables(obj, values);\r\n }\r\n if (Array.isArray(obj)) {\r\n return obj.map(replaceInValue);\r\n }\r\n if (obj && typeof obj === 'object') {\r\n const result: any = {};\r\n for (const [key, val] of Object.entries(obj)) {\r\n result[key] = replaceInValue(val);\r\n }\r\n return result;\r\n }\r\n return obj;\r\n }\r\n\r\n // Apply to all template properties that might contain variable references\r\n resolved.elements = replaceInValue(resolved.elements);\r\n if (resolved.assets) {\r\n resolved.assets = replaceInValue(resolved.assets);\r\n }\r\n\r\n return resolved;\r\n}\r\n\r\n/**\r\n * Interpolate {{vars.*}} references in a string.\r\n *\r\n * Replaces all occurrences of {{vars.variableName}} with the corresponding value.\r\n * If variable is not found, keeps the placeholder and logs a warning.\r\n *\r\n * @param str - String potentially containing {{vars.*}} references\r\n * @param values - Variable values\r\n * @returns String with all {{vars.*}} replaced\r\n */\r\nfunction interpolateVariables(str: string, values: Record<string, any>): string {\r\n return str.replace(/\\{\\{vars\\.(\\w+)\\}\\}/g, (match, varName) => {\r\n if (varName in values) {\r\n const value = values[varName];\r\n // Convert to string (handles numbers, booleans, etc.)\r\n return String(value);\r\n }\r\n console.warn(`[templateVariables] Variable '${varName}' not found - keeping placeholder`);\r\n return match; // Keep {{vars.varName}} as-is\r\n });\r\n}\r\n"]}
@@ -0,0 +1,5 @@
1
+ /** Type guard: true for plain objects, false for arrays, null, and primitives. */
2
+ export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
3
+ /** Safely read a property from an unknown value. Returns undefined for non-objects. */
4
+ export declare const getProp: (obj: unknown, key: string) => unknown;
5
+ //# sourceMappingURL=typeGuards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeGuards.d.ts","sourceRoot":"/","sources":["layout/typeGuards.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAExE,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,OAAO,GAAI,KAAK,OAAO,EAAE,KAAK,MAAM,KAAG,OAEnD,CAAC"}
@@ -0,0 +1,9 @@
1
+ /** Type guard: true for plain objects, false for arrays, null, and primitives. */
2
+ export const isRecord = (value) => {
3
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
4
+ };
5
+ /** Safely read a property from an unknown value. Returns undefined for non-objects. */
6
+ export const getProp = (obj, key) => {
7
+ return isRecord(obj) ? obj[key] : undefined;
8
+ };
9
+ //# sourceMappingURL=typeGuards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeGuards.js","sourceRoot":"/","sources":["layout/typeGuards.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE;IACzE,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChF,CAAC,CAAC;AAEF,uFAAuF;AACvF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAY,EAAE,GAAW,EAAW,EAAE;IAC1D,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC,CAAC","sourcesContent":["/** Type guard: true for plain objects, false for arrays, null, and primitives. */\r\nexport const isRecord = (value: unknown): value is Record<string, unknown> => {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value);\r\n};\r\n\r\n/** Safely read a property from an unknown value. Returns undefined for non-objects. */\r\nexport const getProp = (obj: unknown, key: string): unknown => {\r\n return isRecord(obj) ? obj[key] : undefined;\r\n};\r\n"]}