@rastr/pdf-template 0.0.0-stage → 0.1.0-beta.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/conditions.ts","../src/format.ts","../src/expressions.ts","../src/validate.ts","../src/font-metrics.ts","../src/layout.ts","../src/store.ts"],"sourcesContent":["export type { Align, Bands, ColumnOverride, Element, FontRef, ImageElement, LineElement, Locale, PageSetup, RectElement, ReportTemplate, StyleRef, TableBand, TextElement, TextStyle, Weight } from './template';\nexport { TemplateError } from './errors';\nexport type { TemplateIssue } from './errors';\nexport { validateTemplate } from './validate';\nexport { evaluateText, parseExpression } from './expressions';\nexport type { ExpressionFilter, ExpressionPart } from './expressions';\nexport { compileCondition } from './conditions';\nexport { defaultText, formatValue } from './format';\nexport { measureText, MM_PER_PT, parseFontMetrics } from './font-metrics';\nexport type { FontMetrics } from './font-metrics';\nexport { layoutReport, layoutReportAsync, round2, wrapText } from './layout';\nexport type { LayoutDocument, LayoutItem, LayoutPage, ReportColumn, ReportInput } from './layout';\nexport { createLocalTemplateStore, createRestTemplateStore, templateLoader, TemplateStoreError } from './store';\nexport type { StoredTemplate, TemplateSave, TemplateStore, TemplateSummary } from './store';\nexport type { PreviewData, PreviewField, PreviewImage, PreviewSource } from './preview';\n","export interface TemplateIssue {\n /** Path in the template, e.g. \"bands.pageHeader[1].text\". */\n readonly path: string;\n readonly message: string;\n}\n\n/** An invalid template, expression, condition or font; lists every issue found. */\nexport class TemplateError extends Error {\n readonly issues: readonly TemplateIssue[];\n\n constructor(issues: readonly TemplateIssue[]) {\n super(issues.map(issue => (issue.path ? `${issue.path}: ${issue.message}` : issue.message)).join('; '));\n this.name = 'TemplateError';\n this.issues = issues;\n }\n}\n\nexport function fail(message: string, path: string = ''): never {\n throw new TemplateError([{ path, message }]);\n}\n","import { fail } from './errors';\n\ntype Literal = number | string | boolean | null;\ntype Operator = '==' | '!=' | '<' | '<=' | '>' | '>=';\ninterface Comparison {\n readonly field: string;\n readonly op: Operator;\n readonly literal: Literal;\n}\n\nconst COMPARISON: RegExp = /^row\\.([A-Za-z_][A-Za-z0-9_]*)\\s*(==|!=|<=|>=|<|>)\\s*(-?[0-9]+(?:\\.[0-9]+)?|'[^']*'|true|false|null)$/;\n\nfunction parseComparison(source: string, whole: string): Comparison {\n const match: RegExpExecArray | null = COMPARISON.exec(source.trim());\n if (!match) fail(`Invalid condition \"${whole}\"; use row.field == literal joined by && or ||`);\n const [, field, op, raw] = match as unknown as [string, string, Operator, string];\n const literal: Literal = raw === 'true' ? true : raw === 'false' ? false : raw === 'null' ? null : raw.startsWith(\"'\") ? raw.slice(1, -1) : Number(raw);\n return { field, op, literal };\n}\n\nfunction compare(value: unknown, op: Operator, literal: Literal): boolean {\n const actual: unknown = value === undefined ? null : value;\n if (op === '==' || op === '!=') {\n const equal: boolean = actual === literal;\n return op === '==' ? equal : !equal;\n }\n // Ordering only between two numbers or two strings (ordinal); anything else is false.\n if (!((typeof actual === 'number' && typeof literal === 'number') || (typeof actual === 'string' && typeof literal === 'string'))) return false;\n const a: number | string = actual;\n const b: number | string = literal;\n switch (op) {\n case '<':\n return a < b;\n case '<=':\n return a <= b;\n case '>':\n return a > b;\n default:\n return a >= b;\n }\n}\n\n/** row.field (==|!=|<|<=|>|>=) literal, joined by && (binds tighter) and ||; no parentheses. */\nexport function compileCondition(source: string): (row: Readonly<Record<string, unknown>>) => boolean {\n if (/'[^']*$/.test(source.replace(/'[^']*'/g, ''))) fail(`Unterminated text in condition \"${source}\"`);\n // Split outside of quoted literals.\n const masked: string = source.replace(/'[^']*'/g, match => '\\u0000'.repeat(match.length));\n const splitAt = (text: string, mask: string, separator: string): string[] => {\n const parts: string[] = [];\n let start: number = 0;\n for (let i: number = mask.indexOf(separator); i >= 0; i = mask.indexOf(separator, i + separator.length)) {\n parts.push(text.slice(start, i));\n start = i + separator.length;\n }\n parts.push(text.slice(start));\n return parts;\n };\n const maskedOr: string[] = splitAt(masked, masked, '||');\n let offset: number = 0;\n const groups: Comparison[][] = maskedOr.map(maskedGroup => {\n const group: string = source.slice(offset, offset + maskedGroup.length);\n offset += maskedGroup.length + 2;\n let inner: number = 0;\n return splitAt(maskedGroup, maskedGroup, '&&').map(maskedPart => {\n const part: string = group.slice(inner, inner + maskedPart.length);\n inner += maskedPart.length + 2;\n return parseComparison(part, source);\n });\n });\n return row => groups.some(group => group.every(c => compare(Object.prototype.hasOwnProperty.call(row, c.field) ? row[c.field] : null, c.op, c.literal)));\n}\n","import { fail } from './errors';\nimport type { Locale } from './template';\n\nconst NBSP: string = ' ';\nconst ISO_DATE: RegExp = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/;\n/**\n * The only date-time texts read as instants (same grammar in C#): yyyy-MM-dd, optionally with\n * [T or space]HH:mm[:ss[.fraction]] and Z or ±HH:mm. Without an offset the value is UTC, so the result\n * does not depend on the machine's zone. Anything else stays text.\n */\nconst ISO_DATETIME: RegExp = /^([0-9]{4})-([0-9]{2})-([0-9]{2})(?:[T ]([0-9]{2}):([0-9]{2})(?::([0-9]{2})(?:\\.([0-9]{1,9}))?)?)?(Z|[+-][0-9]{2}:[0-9]{2})?$/;\n/** Instants of years 1–9999 (the range .NET DateTimeOffset supports). */\nconst MIN_MS: number = -62135596800000;\nconst MAX_MS: number = 253402300799999;\n\ninterface LocaleRules {\n readonly group: string;\n readonly decimal: string;\n}\n\nconst RULES: Readonly<Record<Locale, LocaleRules>> = {\n cs: { group: NBSP, decimal: ',' },\n en: { group: ',', decimal: '.' },\n};\n\nexport const FORMAT_NAMES: ReadonlySet<string> = new Set(['currency', 'number', 'percent', 'date', 'datetime']);\n\n/** A number from a number or a numeric string; null otherwise. */\nexport function toNumber(value: unknown): number | null {\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n if (typeof value === 'string' && value.trim() !== '' && /^-?[0-9]+(\\.[0-9]+)?$/.test(value.trim())) return Number(value);\n return null;\n}\n\n/**\n * Rounds half away from zero at 15 significant digits, the same as C# (decimal)double + Math.Round\n * with MidpointRounding.AwayFromZero; returns the digits as text.\n */\nfunction fixed(value: number, decimals: number): { negative: boolean; integer: string; fraction: string } {\n const scaled: number = Number((Math.abs(value) * 10 ** decimals).toPrecision(15));\n const rounded: number = Math.floor(scaled + 0.5);\n const digits: string = rounded.toFixed(0).padStart(decimals + 1, '0');\n const integer: string = digits.slice(0, digits.length - decimals);\n const fraction: string = decimals > 0 ? digits.slice(-decimals) : '';\n return { negative: value < 0 && rounded !== 0, integer, fraction };\n}\n\nfunction group(integer: string, separator: string): string {\n return integer.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n}\n\n/** Grouped number with the locale's separators; decimals default to 0 for integers and 2 otherwise. */\nexport function formatNumber(value: number, decimals: number | null, locale: Locale): string {\n const places: number = decimals ?? (Number.isInteger(value) ? 0 : 2);\n const rules: LocaleRules = RULES[locale];\n const parts = fixed(value, places);\n const text: string = group(parts.integer, rules.group) + (places > 0 ? rules.decimal + parts.fraction : '');\n return parts.negative ? `-${text}` : text;\n}\n\ninterface LocalTime {\n readonly year: number;\n readonly month: number;\n readonly day: number;\n readonly hour: number;\n readonly minute: number;\n}\n\nconst zoneFormats: Map<string, Intl.DateTimeFormat> = new Map();\n\n/** Calendar date and time of an instant in an IANA time zone. */\nexport function inTimeZone(date: Date, timeZone: string): LocalTime {\n let format: Intl.DateTimeFormat | undefined = zoneFormats.get(timeZone);\n if (!format) {\n try {\n format = new Intl.DateTimeFormat('en-US', {\n timeZone,\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n hourCycle: 'h23',\n });\n } catch {\n fail(`Unknown time zone \"${timeZone}\"`, 'timeZone');\n }\n zoneFormats.set(timeZone, format);\n }\n const parts: Record<string, string> = {};\n for (const part of format.formatToParts(date)) parts[part.type] = part.value;\n return { year: Number(parts['year']), month: Number(parts['month']), day: Number(parts['day']), hour: Number(parts['hour']) % 24, minute: Number(parts['minute']) };\n}\n\n/** A calendar day: 'yyyy-MM-dd' as written, an instant as the day in the time zone. */\nfunction toDay(value: unknown, timeZone: string): LocalTime | null {\n if (typeof value === 'string') {\n const match: RegExpExecArray | null = ISO_DATE.exec(value);\n if (match) return { year: Number(match[1]), month: Number(match[2]), day: Number(match[3]), hour: 0, minute: 0 };\n }\n const instant: Date | null = toInstant(value);\n return instant ? inTimeZone(instant, timeZone) : null;\n}\n\nfunction inRange(ms: number): Date | null {\n return Number.isFinite(ms) && ms >= MIN_MS && ms <= MAX_MS ? new Date(ms) : null;\n}\n\nfunction toInstant(value: unknown): Date | null {\n if (value instanceof Date) return inRange(value.getTime());\n if (typeof value === 'number') return inRange(Math.trunc(value));\n if (typeof value !== 'string') return null;\n const match: RegExpExecArray | null = ISO_DATETIME.exec(value);\n if (!match) return null;\n const [year, month, day, hour, minute, second] = [1, 2, 3, 4, 5, 6].map(i => Number(match[i] ?? 0)) as [number, number, number, number, number, number];\n const millisecond: number = Number((match[7] ?? '').padEnd(3, '0').slice(0, 3));\n if (month < 1 || month > 12 || day < 1 || hour > 23 || minute > 59 || second > 59) return null;\n const utc: Date = new Date(Date.UTC(2000, month - 1, day, hour, minute, second, millisecond));\n utc.setUTCFullYear(year);\n // Date.UTC rolls over invalid days (31 April → 1 May); such values are not dates.\n if (utc.getUTCDate() !== day || utc.getUTCMonth() !== month - 1) return null;\n const zone: string | undefined = match[8];\n const offset: number = zone === undefined || zone === 'Z' ? 0 : (zone.startsWith('-') ? -1 : 1) * (Number(zone.slice(1, 3)) * 60 + Number(zone.slice(4, 6)));\n return inRange(utc.getTime() - offset * 60000);\n}\n\nfunction dateText(time: LocalTime, locale: Locale): string {\n return locale === 'cs' ? `${time.day}.${NBSP}${time.month}.${NBSP}${time.year}` : `${time.month}/${time.day}/${time.year}`;\n}\n\nfunction timeText(time: LocalTime, locale: Locale): string {\n const minute: string = String(time.minute).padStart(2, '0');\n if (locale === 'cs') return `${time.hour}:${minute}`;\n const hour12: number = time.hour % 12 === 0 ? 12 : time.hour % 12;\n return `${hour12}:${minute}${NBSP}${time.hour < 12 ? 'AM' : 'PM'}`;\n}\n\nfunction argNumber(arg: string | undefined, spec: string): number | null {\n if (arg === undefined || arg === '') return null;\n const parsed: number = Number(arg);\n if (!Number.isInteger(parsed) || parsed < 0 || parsed > 10) fail(`Invalid decimals in \"${spec}\"`);\n return parsed;\n}\n\n/** Throws TemplateError for an unknown format or invalid arguments. */\nexport function checkFormatSpec(spec: string): void {\n const [name, ...args] = spec.split(':');\n if (!name || !FORMAT_NAMES.has(name)) fail(`Unknown format \"${spec}\"`);\n if (name === 'currency') {\n if (args[0] !== undefined && !/^[A-Z]{3}$/.test(args[0])) fail(`Invalid currency in \"${spec}\"`);\n argNumber(args[1], spec);\n } else if (name === 'number' || name === 'percent') {\n argNumber(args[0], spec);\n } else if (args.length > 0) {\n fail(`Format \"${name}\" takes no arguments`);\n }\n}\n\n/**\n * Formats a value with a spec: currency[:CODE[:decimals]], number[:decimals], percent[:decimals],\n * date, datetime. Values that do not fit the spec are returned as text; null and undefined are empty.\n */\nexport function formatValue(value: unknown, spec: string, locale: Locale, timeZone: string): string {\n if (value === null || value === undefined) return '';\n checkFormatSpec(spec);\n const [name, ...args] = spec.split(':');\n switch (name) {\n case 'currency': {\n const number: number | null = toNumber(value);\n if (number === null) return String(value);\n const code: string = args[0] ?? 'CZK';\n const text: string = formatNumber(number, argNumber(args[1], spec) ?? 2, locale);\n const negative: boolean = text.startsWith('-');\n const digits: string = negative ? text.slice(1) : text;\n if (locale === 'cs') return `${negative ? '-' : ''}${digits}${NBSP}${code === 'CZK' ? 'Kč' : code}`;\n return `${negative ? '-' : ''}${code}${NBSP}${digits}`;\n }\n case 'number': {\n const number: number | null = toNumber(value);\n return number === null ? String(value) : formatNumber(number, argNumber(args[0], spec), locale);\n }\n case 'percent': {\n const number: number | null = toNumber(value);\n if (number === null) return String(value);\n const text: string = formatNumber(number * 100, argNumber(args[0], spec) ?? 0, locale);\n return locale === 'cs' ? `${text}${NBSP}%` : `${text}%`;\n }\n case 'date': {\n const day: LocalTime | null = toDay(value, timeZone);\n return day ? dateText(day, locale) : String(value);\n }\n default: {\n const instant: Date | null = toInstant(value);\n if (!instant) return String(value);\n const time: LocalTime = inTimeZone(instant, timeZone);\n return `${dateText(time, locale)}${NBSP}${timeText(time, locale)}`;\n }\n }\n}\n\n/** Text of a value without a format: numbers grouped, booleans Ano/Ne (Yes/No), objects empty. */\nexport function defaultText(value: unknown, locale: Locale): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'number') return Number.isFinite(value) ? formatNumber(value, null, locale) : '';\n if (typeof value === 'boolean') return locale === 'cs' ? (value ? 'Ano' : 'Ne') : value ? 'Yes' : 'No';\n if (typeof value === 'string') return value;\n return '';\n}\n","import { fail } from './errors';\nimport { checkFormatSpec, defaultText, FORMAT_NAMES, formatValue } from './format';\nimport type { Locale } from './template';\n\nexport interface ExpressionFilter {\n readonly name: string;\n readonly args: readonly string[];\n}\n\nexport type ExpressionPart =\n | { readonly kind: 'text'; readonly value: string }\n | { readonly kind: 'expr'; readonly path: readonly string[]; readonly filters: readonly ExpressionFilter[] };\n\nexport const FILTER_NAMES: ReadonlySet<string> = new Set([...FORMAT_NAMES, 'upper', 'default']);\n/** Keys that would reach prototypes; never allowed in paths. */\nconst FORBIDDEN_KEYS: ReadonlySet<string> = new Set(['__proto__', 'prototype', 'constructor']);\nconst IDENTIFIER: RegExp = /^[A-Za-z_][A-Za-z0-9_]*/;\n\n/** Tokenizer over one {{ … }} body: path ( \"|\" name ( \":\" arg )* )* with arg = number | 'text' | word. */\nfunction parseBody(body: string): ExpressionPart {\n let rest: string = body.trim();\n const take = (pattern: RegExp): string | null => {\n const match: RegExpExecArray | null = pattern.exec(rest);\n if (!match) return null;\n rest = rest.slice(match[0].length).trimStart();\n return match[0];\n };\n const path: string[] = [];\n do {\n const key: string | null = take(IDENTIFIER);\n if (key === null) fail(`Expected a name in \"{{${body}}}\"`);\n if (FORBIDDEN_KEYS.has(key)) fail(`\"${key}\" is not allowed in \"{{${body}}}\"`);\n path.push(key);\n } while (take(/^\\./) !== null);\n const filters: ExpressionFilter[] = [];\n while (take(/^\\|/) !== null) {\n const name: string | null = take(IDENTIFIER);\n if (name === null) fail(`Expected a filter name in \"{{${body}}}\"`);\n if (!FILTER_NAMES.has(name)) fail(`Unknown filter \"${name}\"`);\n const args: string[] = [];\n while (take(/^:/) !== null) {\n const quoted: string | null = take(/^'[^']*'/);\n const arg: string | null = quoted !== null ? quoted.slice(1, -1) : take(/^-?[A-Za-z0-9_.]+/);\n if (arg === null) fail(`Expected an argument for \"${name}\" in \"{{${body}}}\"`);\n args.push(arg);\n }\n if (name === 'default' && args.length !== 1) fail(`\"default\" takes one argument`);\n if (name === 'upper' && args.length > 0) fail(`\"upper\" takes no arguments`);\n if (FORMAT_NAMES.has(name)) checkFormatSpec([name, ...args].join(':'));\n filters.push({ name, args });\n }\n if (rest !== '') fail(`Unexpected \"${rest}\" in \"{{${body}}}\"`);\n return { kind: 'expr', path, filters };\n}\n\n/** Splits text into literal parts and {{ path | filter:arg }} expressions; throws TemplateError. */\nexport function parseExpression(text: string): ExpressionPart[] {\n const parts: ExpressionPart[] = [];\n let index: number = 0;\n while (index < text.length) {\n const open: number = text.indexOf('{{', index);\n if (open < 0) {\n parts.push({ kind: 'text', value: text.slice(index) });\n break;\n }\n if (open > index) parts.push({ kind: 'text', value: text.slice(index, open) });\n const close: number = text.indexOf('}}', open + 2);\n if (close < 0) fail(`Unterminated \"{{\" in \"${text}\"`);\n parts.push(parseBody(text.slice(open + 2, close)));\n index = close + 2;\n }\n return parts;\n}\n\n/** Own-property lookup only, so nothing on prototypes is reachable. */\nexport function lookup(scope: unknown, path: readonly string[]): unknown {\n let current: unknown = scope;\n for (const key of path) {\n if (current === null || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, key)) return undefined;\n current = (current as Record<string, unknown>)[key];\n }\n return current;\n}\n\n/** Simple (one-to-one) uppercase per code point, the same as .NET Rune.ToUpperInvariant: ß stays ß. */\nfunction toUpper(text: string): string {\n let result: string = '';\n for (const char of text) {\n const upper: string = char.toUpperCase();\n result += [...upper].length === 1 ? upper : char;\n }\n return result;\n}\n\nconst isEmpty = (value: unknown): boolean => value === null || value === undefined || value === '';\n\nexport function evaluateText(parts: readonly ExpressionPart[], scope: unknown, locale: Locale, timeZone: string): string {\n let text: string = '';\n for (const part of parts) {\n if (part.kind === 'text') {\n text += part.value;\n continue;\n }\n let value: unknown = lookup(scope, part.path);\n let formatted: boolean = false;\n for (const filter of part.filters) {\n if (filter.name === 'default') {\n if (isEmpty(value)) value = filter.args[0];\n } else if (filter.name === 'upper') {\n value = toUpper(formatted ? String(value) : defaultText(value, locale));\n formatted = true;\n } else if (!isEmpty(value)) {\n value = formatValue(value, [filter.name, ...filter.args].join(':'), locale, timeZone);\n formatted = true;\n }\n }\n text += formatted ? String(value) : defaultText(value, locale);\n }\n return text;\n}\n","import { compileCondition } from './conditions';\nimport { TemplateError } from './errors';\nimport type { TemplateIssue } from './errors';\nimport { parseExpression } from './expressions';\nimport { checkFormatSpec } from './format';\nimport type { ReportTemplate } from './template';\n\nexport { TemplateError } from './errors';\n\ntype Json = Record<string, unknown>;\n\nconst isRecord = (value: unknown): value is Json => typeof value === 'object' && value !== null && !Array.isArray(value);\nconst isNumber = (value: unknown): value is number => typeof value === 'number' && Number.isFinite(value);\nconst COLOR: RegExp = /^#[0-9a-fA-F]{6}$/;\nconst BANDS: ReadonlySet<string> = new Set(['reportHeader', 'pageHeader', 'table', 'reportFooter', 'pageFooter']);\nconst ALIGNS: ReadonlySet<unknown> = new Set(['start', 'center', 'end']);\n\n/** Collects issues instead of stopping at the first one, so authors see every problem at once. */\nclass Checker {\n readonly issues: TemplateIssue[] = [];\n\n add(path: string, message: string): void {\n this.issues.push({ path, message });\n }\n\n /** Runs a check that throws TemplateError (expressions, conditions, formats) and records it at path. */\n guard(path: string, check: () => void): void {\n try {\n check();\n } catch (error) {\n if (error instanceof TemplateError) this.add(path, error.issues.map(i => i.message).join('; '));\n else throw error;\n }\n }\n\n number(value: unknown, path: string, options: { readonly optional?: boolean; readonly min?: number; readonly positive?: boolean } = {}): void {\n if (value === undefined && options.optional) return;\n if (!isNumber(value)) this.add(path, 'must be a number');\n else if (options.positive && value <= 0) this.add(path, 'must be greater than 0');\n else if (options.min !== undefined && value < options.min) this.add(path, `must be at least ${options.min}`);\n }\n\n color(value: unknown, path: string): void {\n if (value !== undefined && !(typeof value === 'string' && COLOR.test(value))) this.add(path, 'must be a color #rrggbb');\n }\n\n oneOf(value: unknown, allowed: ReadonlySet<unknown>, path: string, optional: boolean = false): void {\n if (value === undefined && optional) return;\n if (!allowed.has(value)) this.add(path, `must be one of ${[...allowed].join(', ')}`);\n }\n}\n\nfunction checkStyle(c: Checker, style: unknown, path: string): void {\n if (!isRecord(style)) {\n c.add(path, 'must be an object');\n return;\n }\n if (style['font'] !== undefined && typeof style['font'] !== 'string') c.add(`${path}.font`, 'must be a text');\n c.number(style['size'], `${path}.size`, { optional: true, positive: true });\n c.oneOf(style['weight'], new Set([400, 600, 700]), `${path}.weight`, true);\n c.color(style['color'], `${path}.color`);\n c.color(style['background'], `${path}.background`);\n}\n\nfunction checkStyleRef(c: Checker, ref: unknown, styles: Json, path: string): void {\n if (ref === undefined) return;\n if (typeof ref === 'string') {\n if (!Object.prototype.hasOwnProperty.call(styles, ref)) c.add(path, `unknown style \"${ref}\"`);\n } else {\n checkStyle(c, ref, path);\n }\n}\n\nfunction checkText(c: Checker, value: unknown, path: string): void {\n if (typeof value !== 'string') c.add(path, 'must be a text');\n else c.guard(path, () => parseExpression(value));\n}\n\nfunction checkElement(c: Checker, element: unknown, styles: Json, path: string): void {\n if (!isRecord(element)) {\n c.add(path, 'must be an object');\n return;\n }\n switch (element['type']) {\n case 'text':\n checkText(c, element['text'], `${path}.text`);\n c.number(element['x'], `${path}.x`);\n c.number(element['y'], `${path}.y`);\n c.number(element['w'], `${path}.w`, { optional: true, positive: true });\n c.oneOf(element['align'], ALIGNS, `${path}.align`, true);\n checkStyleRef(c, element['style'], styles, `${path}.style`);\n return;\n case 'image':\n checkText(c, element['src'], `${path}.src`);\n c.number(element['x'], `${path}.x`);\n c.number(element['y'], `${path}.y`);\n c.number(element['w'], `${path}.w`, { positive: true });\n c.number(element['h'], `${path}.h`, { optional: true, positive: true });\n return;\n case 'line':\n for (const key of ['x1', 'y1', 'x2', 'y2']) c.number(element[key], `${path}.${key}`);\n c.color(element['color'], `${path}.color`);\n c.number(element['width'], `${path}.width`, { optional: true, positive: true });\n return;\n case 'rect':\n c.number(element['x'], `${path}.x`);\n c.number(element['y'], `${path}.y`);\n c.number(element['w'], `${path}.w`, { positive: true });\n c.number(element['h'], `${path}.h`, { positive: true });\n c.color(element['fill'], `${path}.fill`);\n c.color(element['stroke'], `${path}.stroke`);\n c.number(element['strokeWidth'], `${path}.strokeWidth`, { optional: true, positive: true });\n return;\n default:\n c.add(`${path}.type`, 'must be text, image, line or rect');\n }\n}\n\nfunction checkTable(c: Checker, table: unknown, styles: Json, path: string): void {\n if (!isRecord(table)) {\n c.add(path, 'must be an object');\n return;\n }\n const columns: unknown = table['columns'];\n if (columns !== 'fromGrid' && !(Array.isArray(columns) && columns.every(field => typeof field === 'string'))) {\n c.add(`${path}.columns`, 'must be \"fromGrid\" or a list of fields');\n }\n const overrides: unknown = table['overrides'];\n if (overrides !== undefined) {\n if (!isRecord(overrides)) c.add(`${path}.overrides`, 'must be an object');\n else {\n for (const [field, override] of Object.entries(overrides)) {\n const at: string = `${path}.overrides.${field}`;\n if (!isRecord(override)) {\n c.add(at, 'must be an object');\n continue;\n }\n c.number(override['width'], `${at}.width`, { optional: true, positive: true });\n c.oneOf(override['align'], ALIGNS, `${at}.align`, true);\n if (override['format'] !== undefined) {\n const format: unknown = override['format'];\n if (typeof format !== 'string') c.add(`${at}.format`, 'must be a text');\n else c.guard(`${at}.format`, () => checkFormatSpec(format));\n }\n if (override['caption'] !== undefined && typeof override['caption'] !== 'string') c.add(`${at}.caption`, 'must be a text');\n }\n }\n }\n const header: unknown = table['header'];\n if (header !== undefined) {\n if (!isRecord(header)) c.add(`${path}.header`, 'must be an object');\n else {\n c.color(header['background'], `${path}.header.background`);\n if (header['repeatOnEachPage'] !== undefined && typeof header['repeatOnEachPage'] !== 'boolean') c.add(`${path}.header.repeatOnEachPage`, 'must be true or false');\n checkStyleRef(c, header['style'], styles, `${path}.header.style`);\n }\n }\n c.color(table['zebra'], `${path}.zebra`);\n const rowStyles: unknown = table['rowStyles'];\n if (rowStyles !== undefined) {\n if (!Array.isArray(rowStyles)) c.add(`${path}.rowStyles`, 'must be a list');\n else {\n rowStyles.forEach((rule: unknown, index: number) => {\n const at: string = `${path}.rowStyles[${index}]`;\n if (!isRecord(rule)) {\n c.add(at, 'must be an object');\n return;\n }\n const when: unknown = rule['when'];\n if (typeof when !== 'string') c.add(`${at}.when`, 'must be a text');\n else c.guard(`${at}.when`, () => compileCondition(when));\n checkStyleRef(c, rule['style'], styles, `${at}.style`);\n });\n }\n }\n if (table['summary'] !== undefined && typeof table['summary'] !== 'boolean') c.add(`${path}.summary`, 'must be true or false');\n}\n\n/** Validates a template (e.g. parsed JSON from storage); throws TemplateError listing every issue. */\nexport function validateTemplate(json: unknown): ReportTemplate {\n const c: Checker = new Checker();\n if (!isRecord(json)) throw new TemplateError([{ path: '', message: 'Template must be an object' }]);\n if (json['version'] !== 1) c.add('version', 'must be 1');\n\n const page: unknown = json['page'];\n if (!isRecord(page)) c.add('page', 'must be an object');\n else {\n c.oneOf(page['size'], new Set(['A4', 'A3', 'Letter']), 'page.size');\n c.oneOf(page['orientation'], new Set(['portrait', 'landscape']), 'page.orientation');\n const margins: unknown = page['margins'];\n if (!(Array.isArray(margins) && margins.length === 4 && margins.every(m => isNumber(m) && m >= 0))) c.add('page.margins', 'must be [top, right, bottom, left] in mm');\n c.oneOf(page['unit'], new Set(['mm']), 'page.unit');\n }\n\n const fonts: unknown = json['fonts'];\n if (!Array.isArray(fonts)) c.add('fonts', 'must be a list');\n else {\n fonts.forEach((font: unknown, index: number) => {\n const at: string = `fonts[${index}]`;\n if (!isRecord(font)) return c.add(at, 'must be an object');\n if (typeof font['family'] !== 'string' || font['family'] === '') c.add(`${at}.family`, 'must be a name');\n if (typeof font['src'] !== 'string' || font['src'] === '') c.add(`${at}.src`, 'must be a URL');\n c.oneOf(font['weight'], new Set([400, 700]), `${at}.weight`, true);\n });\n }\n\n const styles: Json = isRecord(json['styles']) ? json['styles'] : {};\n if (!isRecord(json['styles'])) c.add('styles', 'must be an object');\n for (const [name, style] of Object.entries(styles)) checkStyle(c, style, `styles.${name}`);\n\n const bands: unknown = json['bands'];\n if (!isRecord(bands)) c.add('bands', 'must be an object');\n else {\n for (const [name, band] of Object.entries(bands)) {\n if (!BANDS.has(name)) {\n c.add(`bands.${name}`, 'unknown band');\n } else if (name === 'table') {\n checkTable(c, band, styles, 'bands.table');\n } else if (!Array.isArray(band)) {\n c.add(`bands.${name}`, 'must be a list of elements');\n } else {\n band.forEach((element: unknown, index: number) => checkElement(c, element, styles, `bands.${name}[${index}]`));\n }\n }\n }\n if (c.issues.length > 0) throw new TemplateError(c.issues);\n return json as unknown as ReportTemplate;\n}\n","import { fail } from './errors';\n\n/** Horizontal metrics of a TrueType/OpenType font, enough to measure text without shaping. */\nexport interface FontMetrics {\n readonly unitsPerEm: number;\n readonly ascender: number;\n readonly descender: number;\n /** Glyph for a code point; 0 (.notdef) when the font has none. */\n glyphId(codePoint: number): number;\n advance(glyphId: number): number;\n}\n\nexport const MM_PER_PT: number = 25.4 / 72;\n\ninterface Table {\n readonly offset: number;\n readonly length: number;\n}\n\nconst invalid = (reason: string): never => fail(`Invalid font file: ${reason}`, 'font');\n\n/** Reads head, hhea, hmtx and cmap (format 12 preferred, else format 4); kerning and shaping are not used. */\nexport function parseFontMetrics(data: Uint8Array): FontMetrics {\n const view: DataView = new DataView(data.buffer, data.byteOffset, data.byteLength);\n const u16 = (at: number): number => {\n if (at < 0 || at + 2 > data.byteLength) invalid('truncated');\n return view.getUint16(at);\n };\n const i16 = (at: number): number => {\n if (at < 0 || at + 2 > data.byteLength) invalid('truncated');\n return view.getInt16(at);\n };\n const u32 = (at: number): number => {\n if (at < 0 || at + 4 > data.byteLength) invalid('truncated');\n return view.getUint32(at);\n };\n\n const tables: Map<string, Table> = new Map();\n const count: number = u16(4);\n for (let i: number = 0; i < count; i++) {\n const at: number = 12 + i * 16;\n const tag: string = String.fromCharCode(data[at]!, data[at + 1]!, data[at + 2]!, data[at + 3]!);\n tables.set(tag, { offset: u32(at + 8), length: u32(at + 12) });\n }\n const table = (tag: string): Table => {\n const found: Table | undefined = tables.get(tag);\n if (!found || found.offset + found.length > data.byteLength) invalid(`missing or truncated \"${tag}\" table`);\n return found!;\n };\n\n const head: Table = table('head');\n const unitsPerEm: number = u16(head.offset + 18);\n if (unitsPerEm === 0) invalid('unitsPerEm is 0');\n const hhea: Table = table('hhea');\n const ascender: number = i16(hhea.offset + 4);\n const descender: number = i16(hhea.offset + 6);\n const numberOfHMetrics: number = u16(hhea.offset + 34);\n const hmtx: Table = table('hmtx');\n if (numberOfHMetrics === 0 || numberOfHMetrics * 4 > hmtx.length) invalid('hmtx does not match hhea');\n\n const cmap: Table = table('cmap');\n let format12: number | null = null;\n let format4: number | null = null;\n const subtables: number = u16(cmap.offset + 2);\n for (let i: number = 0; i < subtables; i++) {\n const at: number = cmap.offset + 4 + i * 8;\n const platform: number = u16(at);\n const encoding: number = u16(at + 2);\n const offset: number = cmap.offset + u32(at + 4);\n const format: number = u16(offset);\n const unicode: boolean = platform === 0 || (platform === 3 && (encoding === 1 || encoding === 10));\n if (!unicode) continue;\n if (format === 12 && format12 === null) format12 = offset;\n if (format === 4 && format4 === null) format4 = offset;\n }\n if (format12 === null && format4 === null) invalid('no Unicode cmap');\n\n const lookup12 = (at: number, codePoint: number): number => {\n const groups: number = u32(at + 12);\n let low: number = 0;\n let high: number = groups - 1;\n while (low <= high) {\n const mid: number = (low + high) >> 1;\n const group: number = at + 16 + mid * 12;\n const start: number = u32(group);\n const end: number = u32(group + 4);\n if (codePoint < start) high = mid - 1;\n else if (codePoint > end) low = mid + 1;\n else return u32(group + 8) + (codePoint - start);\n }\n return 0;\n };\n\n const lookup4 = (at: number, codePoint: number): number => {\n if (codePoint > 0xffff) return 0;\n const segments: number = u16(at + 6) / 2;\n const ends: number = at + 14;\n const starts: number = ends + segments * 2 + 2;\n const deltas: number = starts + segments * 2;\n const ranges: number = deltas + segments * 2;\n for (let i: number = 0; i < segments; i++) {\n if (codePoint > u16(ends + i * 2)) continue;\n const start: number = u16(starts + i * 2);\n if (codePoint < start) return 0;\n const delta: number = i16(deltas + i * 2);\n const rangeOffset: number = u16(ranges + i * 2);\n if (rangeOffset === 0) return (codePoint + delta) & 0xffff;\n const glyph: number = u16(ranges + i * 2 + rangeOffset + (codePoint - start) * 2);\n return glyph === 0 ? 0 : (glyph + delta) & 0xffff;\n }\n return 0;\n };\n\n const advances: Map<number, number> = new Map();\n return {\n unitsPerEm,\n ascender,\n descender,\n glyphId: (codePoint: number): number => (format12 !== null ? lookup12(format12, codePoint) : lookup4(format4!, codePoint)),\n advance(glyphId: number): number {\n // Glyphs past numberOfHMetrics share the last advance (monospaced tail).\n const index: number = Math.min(glyphId, numberOfHMetrics - 1);\n let advance: number | undefined = advances.get(index);\n if (advance === undefined) {\n advance = u16(hmtx.offset + index * 4);\n advances.set(index, advance);\n }\n return advance;\n },\n };\n}\n\n/** Width of text in mm at a size in pt; code points without a glyph are measured as .notdef and listed. */\nexport function measureText(text: string, metrics: FontMetrics, sizePt: number): { readonly widthMm: number; readonly missing: readonly number[] } {\n let units: number = 0;\n const missing: number[] = [];\n for (const char of text) {\n const codePoint: number = char.codePointAt(0)!;\n const glyph: number = metrics.glyphId(codePoint);\n if (glyph === 0 && !missing.includes(codePoint)) missing.push(codePoint);\n units += metrics.advance(glyph);\n }\n return { widthMm: (units / metrics.unitsPerEm) * sizePt * MM_PER_PT, missing };\n}\n","import { compileCondition } from './conditions';\nimport { fail } from './errors';\nimport { evaluateText, lookup, parseExpression } from './expressions';\nimport type { ExpressionPart } from './expressions';\nimport { measureText, MM_PER_PT } from './font-metrics';\nimport type { FontMetrics } from './font-metrics';\nimport { defaultText, formatValue } from './format';\nimport type { Align, Element, FontRef, Locale, ReportTemplate, StyleRef, TableBand, TextStyle } from './template';\n\n/*\n * Layout algorithm (mirrored 1:1 by Rastr.Export LayoutEngine; keep both in sync):\n * - mm everywhere, font size in pt, line height = size × 1.2, baseline = top + ascender/unitsPerEm × size.\n * - Bands: pageHeader on every page at the top margin, reportHeader below it on page 1, table rows\n * flow with the header repeated, reportFooter after the table (whole, on a new page when it does\n * not fit), pageFooter on every page at the bottom margin. Header/footer heights are measured with\n * page = pages = 1, then drawn with the real numbers.\n * - Every coordinate is rounded to 0.01 mm at output (half away from zero, 15 significant digits).\n */\n\nexport interface ReportColumn {\n readonly field: string;\n readonly caption: string;\n /** Width from the grid in mm; null for a flexible column. */\n readonly widthMm: number | null;\n readonly align: Align;\n readonly format?: string;\n}\n\nexport interface ReportInput {\n readonly columns: readonly ReportColumn[];\n readonly rows: readonly Readonly<Record<string, unknown>>[];\n /** Grid texts per row and field, used when the column has no format. */\n readonly texts?: readonly Readonly<Record<string, string>>[];\n /** Summary texts per field, drawn as the last table row when the template asks for it (table.summary). */\n readonly summaryRow?: Readonly<Record<string, string>>;\n /** company, user, filter, summary, printedAtUtc (ISO) … */\n readonly context: Readonly<Record<string, unknown>>;\n readonly locale: Locale;\n readonly timeZone: string;\n readonly imageSizes?: Readonly<Record<string, { readonly width: number; readonly height: number }>>;\n}\n\nexport type LayoutItem =\n | {\n readonly kind: 'text';\n readonly x: number;\n readonly y: number;\n readonly baseline: number;\n readonly text: string;\n readonly font: string;\n readonly weight: 400 | 700;\n readonly size: number;\n readonly color: string;\n }\n | { readonly kind: 'rect'; readonly x: number; readonly y: number; readonly w: number; readonly h: number; readonly fill: string | null; readonly stroke: string | null; readonly strokeWidth: number }\n | { readonly kind: 'line'; readonly x1: number; readonly y1: number; readonly x2: number; readonly y2: number; readonly color: string; readonly width: number }\n | { readonly kind: 'image'; readonly x: number; readonly y: number; readonly w: number; readonly h: number; readonly src: string };\n\nexport interface LayoutPage {\n readonly items: readonly LayoutItem[];\n}\n\nexport interface LayoutDocument {\n readonly page: { readonly width: number; readonly height: number };\n readonly pages: readonly LayoutPage[];\n readonly fonts: readonly FontRef[];\n readonly warnings: readonly string[];\n}\n\nconst PAGE_SIZES: Readonly<Record<string, readonly [number, number]>> = { A4: [210, 297], A3: [297, 420], Letter: [215.9, 279.4] };\nconst DEFAULT_STYLE: Required<Omit<TextStyle, 'background'>> = { font: 'Noto Sans', size: 8, weight: 400, color: '#1b1f24' };\nconst LINE_HEIGHT: number = 1.2;\nconst CELL_PADDING_X: number = 1.5;\nconst CELL_PADDING_Y: number = 1;\nconst MIN_AUTO_COLUMN: number = 20;\nconst HEADER_RULE_COLOR: string = '#d5d9df';\nconst HEADER_RULE_WIDTH: number = 0.3;\nconst DEFAULT_LINE_WIDTH: number = 0.2;\nconst EPSILON: number = 1e-9;\n\n/** Half away from zero at 0.01 after 15 significant digits (C#: same formula). */\nexport function round2(value: number): number {\n const scaled: number = Number((Math.abs(value) * 100).toPrecision(15));\n const rounded: number = Math.floor(scaled + 0.5) / 100;\n return value < 0 && rounded !== 0 ? -rounded : rounded;\n}\n\ninterface ResolvedStyle {\n readonly font: string;\n readonly size: number;\n readonly weight: 400 | 700;\n readonly color: string;\n readonly background: string | null;\n}\n\nconst lineHeight = (size: number): number => size * LINE_HEIGHT * MM_PER_PT;\n\n/** Greedy word wrap at spaces (U+00A0 does not break); a word longer than the line breaks by characters. */\nexport function wrapText(text: string, widthMm: number, metrics: FontMetrics, sizePt: number): string[] {\n const width = (value: string): number => measureText(value, metrics, sizePt).widthMm;\n const lines: string[] = [];\n for (const paragraph of text.split('\\n')) {\n let line: string = '';\n let started: boolean = false;\n for (const word of paragraph.split(' ')) {\n const candidate: string = started ? `${line} ${word}` : word;\n if (width(candidate) <= widthMm + EPSILON) {\n line = candidate;\n started = true;\n continue;\n }\n if (started) lines.push(line);\n if (width(word) <= widthMm + EPSILON) {\n line = word;\n started = true;\n continue;\n }\n // Break the word by characters; every line takes at least one character.\n let chunk: string = '';\n for (const char of word) {\n if (chunk !== '' && width(chunk + char) > widthMm + EPSILON) {\n lines.push(chunk);\n chunk = '';\n }\n chunk += char;\n }\n line = chunk;\n started = true;\n }\n lines.push(line);\n }\n return lines;\n}\n\ninterface Cursor {\n items: LayoutItem[];\n}\n\n/** Table rows laid out between two yields of layoutReportAsync. */\nconst ROWS_PER_STEP: number = 500;\n\n/** Lays out a report: absolute boxes per page, ready for jsPDF or PDFsharp to draw. */\nexport function layoutReport(template: ReportTemplate, input: ReportInput, fonts: ReadonlyMap<string, FontMetrics>): LayoutDocument {\n const steps: Generator<void, LayoutDocument> = layoutSteps(template, input, fonts);\n for (;;) {\n const step: IteratorResult<void, LayoutDocument> = steps.next();\n if (step.done) return step.value;\n }\n}\n\n/** The same layout, yielding to the event loop every few hundred rows so large reports do not freeze the page. */\nexport async function layoutReportAsync(template: ReportTemplate, input: ReportInput, fonts: ReadonlyMap<string, FontMetrics>): Promise<LayoutDocument> {\n const steps: Generator<void, LayoutDocument> = layoutSteps(template, input, fonts);\n for (;;) {\n const step: IteratorResult<void, LayoutDocument> = steps.next();\n if (step.done) return step.value;\n await new Promise<void>(resolve => setTimeout(resolve, 0));\n }\n}\n\nfunction* layoutSteps(template: ReportTemplate, input: ReportInput, fonts: ReadonlyMap<string, FontMetrics>): Generator<void, LayoutDocument> {\n const warnings: string[] = [];\n const warn = (message: string): void => {\n if (!warnings.includes(message)) warnings.push(message);\n };\n const [baseWidth, baseHeight] = PAGE_SIZES[template.page.size] ?? fail(`Unknown page size \"${template.page.size}\"`, 'page.size');\n const landscape: boolean = template.page.orientation === 'landscape';\n const pageWidth: number = landscape ? baseHeight : baseWidth;\n const pageHeight: number = landscape ? baseWidth : baseHeight;\n const [marginTop, marginRight, marginBottom, marginLeft] = template.page.margins;\n const contentLeft: number = marginLeft;\n const contentWidth: number = pageWidth - marginLeft - marginRight;\n const contentBottom: number = pageHeight - marginBottom;\n\n const base: TextStyle = template.styles['base'] ?? {};\n const resolve = (...refs: (StyleRef | undefined)[]): ResolvedStyle => {\n let style: TextStyle = { ...DEFAULT_STYLE, ...base };\n for (const ref of refs) {\n if (ref === undefined) continue;\n style = { ...style, ...(typeof ref === 'string' ? (template.styles[ref] ?? {}) : ref) };\n }\n return {\n font: style.font ?? DEFAULT_STYLE.font,\n size: style.size ?? DEFAULT_STYLE.size,\n weight: (style.weight ?? 400) >= 600 ? 700 : 400,\n color: style.color ?? DEFAULT_STYLE.color,\n background: style.background ?? null,\n };\n };\n const metricsOf = (style: ResolvedStyle): FontMetrics => {\n const exact: FontMetrics | undefined = fonts.get(`${style.font}|${style.weight}`);\n if (exact) return exact;\n const regular: FontMetrics | undefined = fonts.get(`${style.font}|400`);\n if (!regular) fail(`Font \"${style.font}\" is not available`, 'font');\n warn(`Font \"${style.font}\" has no bold variant; regular is used`);\n return regular;\n };\n const checkGlyphs = (text: string, style: ResolvedStyle, metrics: FontMetrics): void => {\n for (const codePoint of measureText(text, metrics, style.size).missing) {\n if (codePoint === 0x20 || codePoint === 0xa0) continue;\n warn(`Missing glyph U+${codePoint.toString(16).toUpperCase().padStart(4, '0')} in ${style.font}`);\n }\n };\n\n const parsed: Map<string, ExpressionPart[]> = new Map();\n const evaluate = (text: string, scope: Readonly<Record<string, unknown>>): string => {\n let parts: ExpressionPart[] | undefined = parsed.get(text);\n if (!parts) {\n parts = parseExpression(text);\n parsed.set(text, parts);\n }\n for (const part of parts) {\n // A summary the grid does not compute is a template mistake worth telling about; other paths may be empty on purpose.\n if (part.kind === 'expr' && part.path[0] === 'summary' && lookup(scope, part.path) === undefined) warn(`Summary \"${part.path.join('.')}\" is not in the data`);\n }\n return evaluateText(parts, scope, input.locale, input.timeZone);\n };\n\n const textItems = (out: LayoutItem[], lines: readonly string[], left: number, top: number, width: number, align: Align, style: ResolvedStyle, metrics: FontMetrics): void => {\n const height: number = lineHeight(style.size);\n const ascent: number = (metrics.ascender / metrics.unitsPerEm) * style.size * MM_PER_PT;\n lines.forEach((line, index) => {\n if (line === '') return;\n checkGlyphs(line, style, metrics);\n const lineWidth: number = measureText(line, metrics, style.size).widthMm;\n const x: number = align === 'center' ? left + (width - lineWidth) / 2 : align === 'end' ? left + width - lineWidth : left;\n const y: number = top + index * height;\n out.push({ kind: 'text', x: round2(x), y: round2(y), baseline: round2(y + ascent), text: line, font: style.font, weight: style.weight, size: style.size, color: style.color });\n });\n };\n\n /** Draws band elements at top; returns the band height (max element bottom). */\n const drawBand = (elements: readonly Element[] | undefined, top: number, scope: Readonly<Record<string, unknown>>, out: LayoutItem[] | null): number => {\n let height: number = 0;\n for (const element of elements ?? []) {\n switch (element.type) {\n case 'text': {\n const style: ResolvedStyle = resolve(element.style);\n const metrics: FontMetrics = metricsOf(style);\n const width: number = Math.max(element.w ?? contentWidth - element.x, 1);\n const lines: string[] = wrapText(evaluate(element.text, scope), width, metrics, style.size);\n const blockHeight: number = lines.length * lineHeight(style.size);\n if (out) {\n if (style.background) {\n out.push({ kind: 'rect', x: round2(contentLeft + element.x), y: round2(top + element.y), w: round2(width), h: round2(blockHeight), fill: style.background, stroke: null, strokeWidth: 0 });\n }\n textItems(out, lines, contentLeft + element.x, top + element.y, width, element.align ?? 'start', style, metrics);\n }\n height = Math.max(height, element.y + blockHeight);\n break;\n }\n case 'image': {\n const src: string = evaluate(element.src, scope);\n const size = input.imageSizes?.[src];\n const imageHeight: number = element.h ?? (size && size.width > 0 ? (element.w * size.height) / size.width : element.w);\n if (out && src !== '') out.push({ kind: 'image', x: round2(contentLeft + element.x), y: round2(top + element.y), w: round2(element.w), h: round2(imageHeight), src });\n height = Math.max(height, element.y + imageHeight);\n break;\n }\n case 'line':\n if (out) {\n out.push({\n kind: 'line',\n x1: round2(contentLeft + element.x1),\n y1: round2(top + element.y1),\n x2: round2(contentLeft + element.x2),\n y2: round2(top + element.y2),\n color: element.color ?? resolve().color,\n width: element.width ?? DEFAULT_LINE_WIDTH,\n });\n }\n height = Math.max(height, element.y1, element.y2);\n break;\n case 'rect':\n if (out) {\n out.push({\n kind: 'rect',\n x: round2(contentLeft + element.x),\n y: round2(top + element.y),\n w: round2(element.w),\n h: round2(element.h),\n fill: element.fill ?? null,\n stroke: element.stroke ?? null,\n strokeWidth: element.strokeWidth ?? DEFAULT_LINE_WIDTH,\n });\n }\n height = Math.max(height, element.y + element.h);\n break;\n }\n }\n return height;\n };\n\n const measureScope: Readonly<Record<string, unknown>> = { ...input.context, page: 1, pages: 1 };\n const pageHeaderHeight: number = drawBand(template.bands.pageHeader, 0, measureScope, null);\n const pageFooterHeight: number = drawBand(template.bands.pageFooter, 0, measureScope, null);\n const bodyTop: number = marginTop + pageHeaderHeight;\n const bodyBottom: number = contentBottom - pageFooterHeight;\n\n // Body items per page; page-dependent bands are drawn after the page count is known.\n const bodies: Cursor[] = [{ items: [] }];\n type Deferred = { readonly page: number; readonly top: number; readonly elements: readonly Element[] };\n const deferred: Deferred[] = [];\n let cursor: number = bodyTop;\n const newPage = (): void => {\n bodies.push({ items: [] });\n cursor = bodyTop;\n };\n const current = (): LayoutItem[] => bodies[bodies.length - 1]!.items;\n\n if (template.bands.reportHeader) {\n const height: number = drawBand(template.bands.reportHeader, cursor, measureScope, null);\n deferred.push({ page: 0, top: cursor, elements: template.bands.reportHeader });\n cursor += height;\n }\n\n if (template.bands.table) yield* layoutTable(template.bands.table);\n\n if (template.bands.reportFooter) {\n const height: number = drawBand(template.bands.reportFooter, 0, measureScope, null);\n if (cursor + height > bodyBottom + EPSILON && cursor > bodyTop + EPSILON) newPage();\n deferred.push({ page: bodies.length - 1, top: cursor, elements: template.bands.reportFooter });\n cursor += height;\n }\n\n const pages: number = bodies.length;\n const result: LayoutPage[] = bodies.map((body, index) => {\n const scope: Readonly<Record<string, unknown>> = { ...input.context, page: index + 1, pages };\n const items: LayoutItem[] = [];\n drawBand(template.bands.pageHeader, marginTop, scope, items);\n for (const band of deferred.filter(d => d.page === index && d.elements === template.bands.reportHeader)) drawBand(band.elements, band.top, scope, items);\n items.push(...body.items);\n for (const band of deferred.filter(d => d.page === index && d.elements === template.bands.reportFooter)) drawBand(band.elements, band.top, scope, items);\n drawBand(template.bands.pageFooter, contentBottom - pageFooterHeight, scope, items);\n return { items };\n });\n\n return { page: { width: pageWidth, height: pageHeight }, pages: result, fonts: template.fonts, warnings };\n\n function* layoutTable(table: TableBand): Generator<void> {\n const fields: readonly string[] = table.columns === 'fromGrid' ? input.columns.map(c => c.field) : table.columns;\n const columns: ReportColumn[] = [];\n for (const field of fields) {\n const column: ReportColumn | undefined = input.columns.find(c => c.field === field);\n if (column) columns.push(column);\n else warn(`Column \"${field}\" is not in the data`);\n }\n if (columns.length === 0) return;\n\n // Widths: template override (mm), grid width, or an equal share of what is left.\n const explicit: (number | null)[] = columns.map(c => table.overrides?.[c.field]?.width ?? null);\n const preferred: (number | null)[] = columns.map((c, i) => (explicit[i] !== null ? null : c.widthMm));\n const fixedSum: number = explicit.reduce<number>((sum, w) => sum + (w ?? 0), 0);\n const gridSum: number = preferred.reduce<number>((sum, w) => sum + (w ?? 0), 0);\n const autoCount: number = columns.filter((_, i) => explicit[i] === null && preferred[i] === null).length;\n const autoWidth: number = autoCount > 0 ? Math.max((contentWidth - fixedSum - gridSum) / autoCount, MIN_AUTO_COLUMN) : 0;\n let widths: number[] = columns.map((_, i) => explicit[i] ?? preferred[i] ?? autoWidth);\n const total: number = widths.reduce((sum, w) => sum + w, 0);\n if (total > contentWidth + EPSILON) {\n const flexible: number = total - fixedSum;\n const room: number = contentWidth - fixedSum;\n // Shrink the columns without an explicit width first; all of them when that is not enough.\n widths = room > EPSILON && flexible > EPSILON ? widths.map((w, i) => (explicit[i] !== null ? w : (w * room) / flexible)) : widths.map(w => (w * contentWidth) / total);\n }\n const lefts: number[] = [];\n widths.reduce((left, width) => {\n lefts.push(left);\n return left + width;\n }, contentLeft);\n const tableWidth: number = widths.reduce((sum, w) => sum + w, 0);\n const aligns: Align[] = columns.map(c => table.overrides?.[c.field]?.align ?? c.align);\n\n const headerStyle: ResolvedStyle = resolve({ weight: 700 }, table.header?.style);\n const headerTexts: string[] = columns.map(c => table.overrides?.[c.field]?.caption ?? c.caption);\n const rowStyles = (table.rowStyles ?? []).map(rule => ({ test: compileCondition(rule.when), style: rule.style }));\n\n type Row = { readonly lines: string[][]; readonly height: number; readonly style: ResolvedStyle; readonly metrics: FontMetrics };\n const measureRow = (cells: readonly string[], style: ResolvedStyle): Row => {\n const metrics: FontMetrics = metricsOf(style);\n const lines: string[][] = cells.map((text, i) => wrapText(text, Math.max(widths[i]! - 2 * CELL_PADDING_X, 1), metrics, style.size));\n const height: number = Math.max(...lines.map(l => l.length)) * lineHeight(style.size) + 2 * CELL_PADDING_Y;\n return { lines, height, style, metrics };\n };\n const drawRow = (row: Row, top: number, background: string | null, maxHeight: number): void => {\n const out: LayoutItem[] = current();\n const height: number = Math.min(row.height, maxHeight);\n if (background) out.push({ kind: 'rect', x: round2(contentLeft), y: round2(top), w: round2(tableWidth), h: round2(height), fill: background, stroke: null, strokeWidth: 0 });\n const fit: number = Math.floor((height - 2 * CELL_PADDING_Y) / lineHeight(row.style.size) + EPSILON);\n row.lines.forEach((lines, i) => {\n textItems(out, lines.slice(0, Math.max(fit, 0)), lefts[i]! + CELL_PADDING_X, top + CELL_PADDING_Y, widths[i]! - 2 * CELL_PADDING_X, aligns[i]!, row.style, row.metrics);\n });\n };\n\n const header: Row = measureRow(headerTexts, headerStyle);\n const drawHeader = (): void => {\n drawRow(header, cursor, table.header?.background ?? null, header.height);\n current().push({ kind: 'line', x1: round2(contentLeft), y1: round2(cursor + header.height), x2: round2(contentLeft + tableWidth), y2: round2(cursor + header.height), color: HEADER_RULE_COLOR, width: HEADER_RULE_WIDTH });\n cursor += header.height;\n };\n const repeatHeader: boolean = table.header?.repeatOnEachPage ?? true;\n\n for (let index: number = 0; index < input.rows.length; index++) {\n if (index > 0 && index % ROWS_PER_STEP === 0) yield;\n const data: Readonly<Record<string, unknown>> = input.rows[index]!;\n const texts: Readonly<Record<string, string>> | undefined = input.texts?.[index];\n const cells: string[] = columns.map(column => {\n const value: unknown = data[column.field];\n const format: string | undefined = table.overrides?.[column.field]?.format ?? column.format;\n if (format) return formatValue(value, format, input.locale, input.timeZone);\n const text: string | undefined = texts?.[column.field];\n return text !== undefined ? text : defaultText(value, input.locale);\n });\n const matched: StyleRef[] = rowStyles.filter(rule => rule.test(data)).map(rule => rule.style);\n const style: ResolvedStyle = resolve(...matched);\n const row: Row = measureRow(cells, style);\n const zebra: string | null = index % 2 === 1 ? (table.zebra ?? null) : null;\n\n if (index === 0) {\n // Keep the header with the first row.\n if (cursor + header.height + row.height > bodyBottom + EPSILON && cursor > bodyTop + EPSILON) newPage();\n drawHeader();\n } else if (cursor + row.height > bodyBottom + EPSILON) {\n // A row that does not fit moves to a new page; one taller than a page is cut there.\n newPage();\n if (repeatHeader) drawHeader();\n }\n const room: number = bodyBottom - cursor;\n if (row.height > room + EPSILON) warn(`Row ${index + 1} is taller than a page and was cut`);\n if (zebra) current().push({ kind: 'rect', x: round2(contentLeft), y: round2(cursor), w: round2(tableWidth), h: round2(Math.min(row.height, room)), fill: zebra, stroke: null, strokeWidth: 0 });\n drawRow(row, cursor, style.background, room);\n cursor += Math.min(row.height, room);\n }\n if (input.rows.length === 0) drawHeader();\n\n if (table.summary === true && input.summaryRow) {\n const summaryRow: Readonly<Record<string, string>> = input.summaryRow;\n const row: Row = measureRow(columns.map(column => summaryRow[column.field] ?? ''), resolve({ weight: 700 }));\n if (cursor + row.height > bodyBottom + EPSILON) {\n newPage();\n if (repeatHeader) drawHeader();\n }\n const room: number = bodyBottom - cursor;\n current().push({ kind: 'line', x1: round2(contentLeft), y1: round2(cursor), x2: round2(contentLeft + tableWidth), y2: round2(cursor), color: HEADER_RULE_COLOR, width: HEADER_RULE_WIDTH });\n drawRow(row, cursor, null, room);\n cursor += Math.min(row.height, room);\n }\n }\n}\n","import type { TemplateIssue } from './errors';\nimport type { ReportTemplate } from './template';\n\n/** A stored template without its content (lists). */\nexport interface TemplateSummary {\n readonly id: string;\n readonly gridId: string;\n readonly name: string;\n readonly isDefault: boolean;\n /** Visible to the whole company, otherwise only to its author; the server decides what that means. */\n readonly shared: boolean;\n /** ISO 8601 UTC. */\n readonly updatedAtUtc: string;\n}\n\nexport interface StoredTemplate extends TemplateSummary {\n /** Validate before use: it may come from an older version or be edited by hand. */\n readonly template: unknown;\n}\n\nexport interface TemplateSave {\n /** Without id a new template is created. */\n readonly id?: string;\n readonly gridId: string;\n readonly name: string;\n readonly isDefault: boolean;\n readonly shared: boolean;\n readonly template: ReportTemplate;\n}\n\n/** Report templates per grid; implemented over localStorage, REST (contracts/wire/pdf-templates.md) or by the application. */\nexport interface TemplateStore {\n list(gridId: string): Promise<readonly TemplateSummary[]>;\n load(id: string): Promise<StoredTemplate>;\n save(input: TemplateSave): Promise<TemplateSummary>;\n remove(id: string): Promise<void>;\n}\n\n/** A failed store operation; status is the HTTP status (404 unknown id, 400 invalid template with issues). */\nexport class TemplateStoreError extends Error {\n readonly status: number;\n readonly issues: readonly TemplateIssue[];\n\n constructor(message: string, status: number, issues: readonly TemplateIssue[] = []) {\n super(message);\n this.name = 'TemplateStoreError';\n this.status = status;\n this.issues = issues;\n }\n}\n\nconst DEFAULT_KEY: string = 'rastr.pdf-templates';\n\nfunction summary(stored: StoredTemplate): TemplateSummary {\n return { id: stored.id, gridId: stored.gridId, name: stored.name, isDefault: stored.isDefault, shared: stored.shared, updatedAtUtc: stored.updatedAtUtc };\n}\n\n/** Templates in one localStorage key; keeps at most one default per grid. */\nexport function createLocalTemplateStore(\n options: { readonly storage?: Storage; readonly key?: string; readonly now?: () => Date; readonly newId?: () => string } = {},\n): TemplateStore {\n const key: string = options.key ?? DEFAULT_KEY;\n const storage = (): Storage => options.storage ?? globalThis.localStorage;\n const now: () => Date = options.now ?? (() => new Date());\n const newId: () => string = options.newId ?? (() => crypto.randomUUID());\n\n const read = (): StoredTemplate[] => {\n try {\n const parsed: unknown = JSON.parse(storage().getItem(key) ?? '[]');\n return Array.isArray(parsed) ? (parsed as StoredTemplate[]) : [];\n } catch {\n // Unreadable content (edited by hand, another version) is treated as no templates.\n return [];\n }\n };\n const write = (templates: readonly StoredTemplate[]): void => storage().setItem(key, JSON.stringify(templates));\n\n return {\n list: async gridId => read().filter(t => t.gridId === gridId).map(summary),\n async load(id) {\n const found: StoredTemplate | undefined = read().find(t => t.id === id);\n if (!found) throw new TemplateStoreError(`Template ${id} does not exist`, 404);\n return found;\n },\n async save(input) {\n const templates: StoredTemplate[] = read();\n const id: string = input.id ?? newId();\n const stored: StoredTemplate = {\n id,\n gridId: input.gridId,\n name: input.name,\n isDefault: input.isDefault,\n shared: input.shared,\n updatedAtUtc: now().toISOString(),\n template: input.template,\n };\n const index: number = templates.findIndex(t => t.id === id);\n if (index >= 0) templates[index] = stored;\n else templates.push(stored);\n const result: StoredTemplate[] = input.isDefault\n ? templates.map(t => (t.gridId === input.gridId && t.id !== id && t.isDefault ? { ...t, isDefault: false } : t))\n : templates;\n write(result);\n return summary(stored);\n },\n async remove(id) {\n write(read().filter(t => t.id !== id));\n },\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Store over the REST contract in contracts/wire/pdf-templates.md. */\nexport function createRestTemplateStore(options: { readonly url: string; readonly fetch?: typeof fetch; readonly headers?: () => HeadersInit }): TemplateStore {\n const base: string = options.url.replace(/\\/+$/, '');\n const request = async (method: string, path: string, body?: unknown): Promise<Response> => {\n const headers: Headers = new Headers(options.headers?.());\n if (body !== undefined) headers.set('Content-Type', 'application/json');\n const fetchImpl: typeof fetch = options.fetch ?? globalThis.fetch;\n const response: Response = await fetchImpl(`${base}${path}`, {\n method,\n headers,\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n });\n if (response.ok) return response;\n let problem: unknown = null;\n try {\n problem = await response.json();\n } catch {\n // No ProblemDetails body.\n }\n const issues: TemplateIssue[] = isRecord(problem) && Array.isArray(problem['issues']) ? (problem['issues'] as TemplateIssue[]) : [];\n const detail: unknown = isRecord(problem) ? (problem['detail'] ?? problem['title']) : null;\n throw new TemplateStoreError(typeof detail === 'string' ? detail : `Template request failed (HTTP ${response.status})`, response.status, issues);\n };\n const body = (input: TemplateSave): Omit<TemplateSave, 'id'> => ({ gridId: input.gridId, name: input.name, isDefault: input.isDefault, shared: input.shared, template: input.template });\n return {\n list: async gridId => (await request('GET', `?gridId=${encodeURIComponent(gridId)}`)).json() as Promise<TemplateSummary[]>,\n load: async id => (await request('GET', `/${encodeURIComponent(id)}`)).json() as Promise<StoredTemplate>,\n save: async input =>\n (input.id === undefined ? await request('POST', '', body(input)) : await request('PUT', `/${encodeURIComponent(input.id)}`, body(input))).json() as Promise<TemplateSummary>,\n async remove(id) {\n await request('DELETE', `/${encodeURIComponent(id)}`);\n },\n };\n}\n\n/** For GridPdfOptions.template: the grid's default template, or null (the built-in look). */\nexport function templateLoader(store: TemplateStore, gridId: string): () => Promise<unknown | null> {\n return async () => {\n const found: TemplateSummary | undefined = (await store.list(gridId)).find(t => t.isDefault);\n return found ? (await store.load(found.id)).template : null;\n };\n}\n"],"mappings":"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","names":["group","group","isRecord","body"]}
@@ -0,0 +1,324 @@
1
+ type Locale = 'cs' | 'en';
2
+ type Align = 'start' | 'center' | 'end';
3
+ type Weight = 400 | 600 | 700;
4
+ interface PageSetup {
5
+ readonly size: 'A4' | 'A3' | 'Letter';
6
+ readonly orientation: 'portrait' | 'landscape';
7
+ /** Top, right, bottom, left in mm. */
8
+ readonly margins: readonly [number, number, number, number];
9
+ readonly unit: 'mm';
10
+ }
11
+ interface FontRef {
12
+ readonly family: string;
13
+ readonly src: string;
14
+ readonly weight?: 400 | 700;
15
+ }
16
+ interface TextStyle {
17
+ readonly font?: string;
18
+ /** pt */
19
+ readonly size?: number;
20
+ readonly weight?: Weight;
21
+ readonly color?: string;
22
+ readonly background?: string;
23
+ }
24
+ type StyleRef = string | TextStyle;
25
+ interface TextElement {
26
+ readonly type: 'text';
27
+ readonly text: string;
28
+ readonly x: number;
29
+ readonly y: number;
30
+ readonly w?: number;
31
+ readonly align?: Align;
32
+ readonly style?: StyleRef;
33
+ }
34
+ interface ImageElement {
35
+ readonly type: 'image';
36
+ readonly src: string;
37
+ readonly x: number;
38
+ readonly y: number;
39
+ readonly w: number;
40
+ readonly h?: number;
41
+ }
42
+ interface LineElement {
43
+ readonly type: 'line';
44
+ readonly x1: number;
45
+ readonly y1: number;
46
+ readonly x2: number;
47
+ readonly y2: number;
48
+ readonly color?: string;
49
+ /** mm */
50
+ readonly width?: number;
51
+ }
52
+ interface RectElement {
53
+ readonly type: 'rect';
54
+ readonly x: number;
55
+ readonly y: number;
56
+ readonly w: number;
57
+ readonly h: number;
58
+ readonly fill?: string;
59
+ readonly stroke?: string;
60
+ readonly strokeWidth?: number;
61
+ }
62
+ type Element = TextElement | ImageElement | LineElement | RectElement;
63
+ interface ColumnOverride {
64
+ /** mm */
65
+ readonly width?: number;
66
+ readonly align?: Align;
67
+ readonly format?: string;
68
+ readonly caption?: string;
69
+ }
70
+ interface TableBand {
71
+ readonly columns: 'fromGrid' | readonly string[];
72
+ readonly overrides?: Readonly<Record<string, ColumnOverride>>;
73
+ readonly header?: {
74
+ readonly background?: string;
75
+ readonly repeatOnEachPage?: boolean;
76
+ readonly style?: StyleRef;
77
+ };
78
+ readonly zebra?: string;
79
+ readonly rowStyles?: readonly {
80
+ readonly when: string;
81
+ readonly style: StyleRef;
82
+ }[];
83
+ /** Validated, not rendered in v1 (grouping is v2). */
84
+ readonly groupHeader?: unknown;
85
+ /** Draws ReportInput.summaryRow as the bold last row of the table. */
86
+ readonly summary?: boolean;
87
+ }
88
+ interface Bands {
89
+ readonly reportHeader?: readonly Element[];
90
+ readonly pageHeader?: readonly Element[];
91
+ readonly table?: TableBand;
92
+ readonly reportFooter?: readonly Element[];
93
+ readonly pageFooter?: readonly Element[];
94
+ }
95
+ interface ReportTemplate {
96
+ readonly version: 1;
97
+ readonly page: PageSetup;
98
+ readonly fonts: readonly FontRef[];
99
+ readonly styles: Readonly<Record<string, TextStyle>>;
100
+ readonly bands: Bands;
101
+ }
102
+
103
+ interface TemplateIssue {
104
+ /** Path in the template, e.g. "bands.pageHeader[1].text". */
105
+ readonly path: string;
106
+ readonly message: string;
107
+ }
108
+ /** An invalid template, expression, condition or font; lists every issue found. */
109
+ declare class TemplateError extends Error {
110
+ readonly issues: readonly TemplateIssue[];
111
+ constructor(issues: readonly TemplateIssue[]);
112
+ }
113
+
114
+ /** Validates a template (e.g. parsed JSON from storage); throws TemplateError listing every issue. */
115
+ declare function validateTemplate(json: unknown): ReportTemplate;
116
+
117
+ interface ExpressionFilter {
118
+ readonly name: string;
119
+ readonly args: readonly string[];
120
+ }
121
+ type ExpressionPart = {
122
+ readonly kind: 'text';
123
+ readonly value: string;
124
+ } | {
125
+ readonly kind: 'expr';
126
+ readonly path: readonly string[];
127
+ readonly filters: readonly ExpressionFilter[];
128
+ };
129
+ /** Splits text into literal parts and {{ path | filter:arg }} expressions; throws TemplateError. */
130
+ declare function parseExpression(text: string): ExpressionPart[];
131
+ declare function evaluateText(parts: readonly ExpressionPart[], scope: unknown, locale: Locale, timeZone: string): string;
132
+
133
+ /** row.field (==|!=|<|<=|>|>=) literal, joined by && (binds tighter) and ||; no parentheses. */
134
+ declare function compileCondition(source: string): (row: Readonly<Record<string, unknown>>) => boolean;
135
+
136
+ /**
137
+ * Formats a value with a spec: currency[:CODE[:decimals]], number[:decimals], percent[:decimals],
138
+ * date, datetime. Values that do not fit the spec are returned as text; null and undefined are empty.
139
+ */
140
+ declare function formatValue(value: unknown, spec: string, locale: Locale, timeZone: string): string;
141
+ /** Text of a value without a format: numbers grouped, booleans Ano/Ne (Yes/No), objects empty. */
142
+ declare function defaultText(value: unknown, locale: Locale): string;
143
+
144
+ /** Horizontal metrics of a TrueType/OpenType font, enough to measure text without shaping. */
145
+ interface FontMetrics {
146
+ readonly unitsPerEm: number;
147
+ readonly ascender: number;
148
+ readonly descender: number;
149
+ /** Glyph for a code point; 0 (.notdef) when the font has none. */
150
+ glyphId(codePoint: number): number;
151
+ advance(glyphId: number): number;
152
+ }
153
+ declare const MM_PER_PT: number;
154
+ /** Reads head, hhea, hmtx and cmap (format 12 preferred, else format 4); kerning and shaping are not used. */
155
+ declare function parseFontMetrics(data: Uint8Array): FontMetrics;
156
+ /** Width of text in mm at a size in pt; code points without a glyph are measured as .notdef and listed. */
157
+ declare function measureText(text: string, metrics: FontMetrics, sizePt: number): {
158
+ readonly widthMm: number;
159
+ readonly missing: readonly number[];
160
+ };
161
+
162
+ interface ReportColumn {
163
+ readonly field: string;
164
+ readonly caption: string;
165
+ /** Width from the grid in mm; null for a flexible column. */
166
+ readonly widthMm: number | null;
167
+ readonly align: Align;
168
+ readonly format?: string;
169
+ }
170
+ interface ReportInput {
171
+ readonly columns: readonly ReportColumn[];
172
+ readonly rows: readonly Readonly<Record<string, unknown>>[];
173
+ /** Grid texts per row and field, used when the column has no format. */
174
+ readonly texts?: readonly Readonly<Record<string, string>>[];
175
+ /** Summary texts per field, drawn as the last table row when the template asks for it (table.summary). */
176
+ readonly summaryRow?: Readonly<Record<string, string>>;
177
+ /** company, user, filter, summary, printedAtUtc (ISO) … */
178
+ readonly context: Readonly<Record<string, unknown>>;
179
+ readonly locale: Locale;
180
+ readonly timeZone: string;
181
+ readonly imageSizes?: Readonly<Record<string, {
182
+ readonly width: number;
183
+ readonly height: number;
184
+ }>>;
185
+ }
186
+ type LayoutItem = {
187
+ readonly kind: 'text';
188
+ readonly x: number;
189
+ readonly y: number;
190
+ readonly baseline: number;
191
+ readonly text: string;
192
+ readonly font: string;
193
+ readonly weight: 400 | 700;
194
+ readonly size: number;
195
+ readonly color: string;
196
+ } | {
197
+ readonly kind: 'rect';
198
+ readonly x: number;
199
+ readonly y: number;
200
+ readonly w: number;
201
+ readonly h: number;
202
+ readonly fill: string | null;
203
+ readonly stroke: string | null;
204
+ readonly strokeWidth: number;
205
+ } | {
206
+ readonly kind: 'line';
207
+ readonly x1: number;
208
+ readonly y1: number;
209
+ readonly x2: number;
210
+ readonly y2: number;
211
+ readonly color: string;
212
+ readonly width: number;
213
+ } | {
214
+ readonly kind: 'image';
215
+ readonly x: number;
216
+ readonly y: number;
217
+ readonly w: number;
218
+ readonly h: number;
219
+ readonly src: string;
220
+ };
221
+ interface LayoutPage {
222
+ readonly items: readonly LayoutItem[];
223
+ }
224
+ interface LayoutDocument {
225
+ readonly page: {
226
+ readonly width: number;
227
+ readonly height: number;
228
+ };
229
+ readonly pages: readonly LayoutPage[];
230
+ readonly fonts: readonly FontRef[];
231
+ readonly warnings: readonly string[];
232
+ }
233
+ /** Half away from zero at 0.01 after 15 significant digits (C#: same formula). */
234
+ declare function round2(value: number): number;
235
+ /** Greedy word wrap at spaces (U+00A0 does not break); a word longer than the line breaks by characters. */
236
+ declare function wrapText(text: string, widthMm: number, metrics: FontMetrics, sizePt: number): string[];
237
+ /** Lays out a report: absolute boxes per page, ready for jsPDF or PDFsharp to draw. */
238
+ declare function layoutReport(template: ReportTemplate, input: ReportInput, fonts: ReadonlyMap<string, FontMetrics>): LayoutDocument;
239
+ /** The same layout, yielding to the event loop every few hundred rows so large reports do not freeze the page. */
240
+ declare function layoutReportAsync(template: ReportTemplate, input: ReportInput, fonts: ReadonlyMap<string, FontMetrics>): Promise<LayoutDocument>;
241
+
242
+ /** A stored template without its content (lists). */
243
+ interface TemplateSummary {
244
+ readonly id: string;
245
+ readonly gridId: string;
246
+ readonly name: string;
247
+ readonly isDefault: boolean;
248
+ /** Visible to the whole company, otherwise only to its author; the server decides what that means. */
249
+ readonly shared: boolean;
250
+ /** ISO 8601 UTC. */
251
+ readonly updatedAtUtc: string;
252
+ }
253
+ interface StoredTemplate extends TemplateSummary {
254
+ /** Validate before use: it may come from an older version or be edited by hand. */
255
+ readonly template: unknown;
256
+ }
257
+ interface TemplateSave {
258
+ /** Without id a new template is created. */
259
+ readonly id?: string;
260
+ readonly gridId: string;
261
+ readonly name: string;
262
+ readonly isDefault: boolean;
263
+ readonly shared: boolean;
264
+ readonly template: ReportTemplate;
265
+ }
266
+ /** Report templates per grid; implemented over localStorage, REST (contracts/wire/pdf-templates.md) or by the application. */
267
+ interface TemplateStore {
268
+ list(gridId: string): Promise<readonly TemplateSummary[]>;
269
+ load(id: string): Promise<StoredTemplate>;
270
+ save(input: TemplateSave): Promise<TemplateSummary>;
271
+ remove(id: string): Promise<void>;
272
+ }
273
+ /** A failed store operation; status is the HTTP status (404 unknown id, 400 invalid template with issues). */
274
+ declare class TemplateStoreError extends Error {
275
+ readonly status: number;
276
+ readonly issues: readonly TemplateIssue[];
277
+ constructor(message: string, status: number, issues?: readonly TemplateIssue[]);
278
+ }
279
+ /** Templates in one localStorage key; keeps at most one default per grid. */
280
+ declare function createLocalTemplateStore(options?: {
281
+ readonly storage?: Storage;
282
+ readonly key?: string;
283
+ readonly now?: () => Date;
284
+ readonly newId?: () => string;
285
+ }): TemplateStore;
286
+ /** Store over the REST contract in contracts/wire/pdf-templates.md. */
287
+ declare function createRestTemplateStore(options: {
288
+ readonly url: string;
289
+ readonly fetch?: typeof fetch;
290
+ readonly headers?: () => HeadersInit;
291
+ }): TemplateStore;
292
+ /** For GridPdfOptions.template: the grid's default template, or null (the built-in look). */
293
+ declare function templateLoader(store: TemplateStore, gridId: string): () => Promise<unknown | null>;
294
+
295
+ /** A grid column the template can use (visible export columns, in grid order). */
296
+ interface PreviewField {
297
+ readonly field: string;
298
+ readonly caption: string;
299
+ /** Width from the grid in mm; null for a flexible column. */
300
+ readonly widthMm: number | null;
301
+ /** Summary types of the column in the grid (sum, avg, min, max, count, custom), offered as summary.<type>.<field>. */
302
+ readonly summaries?: readonly string[];
303
+ }
304
+ interface PreviewImage {
305
+ readonly dataUrl: string;
306
+ readonly width: number;
307
+ readonly height: number;
308
+ }
309
+ /** Everything a live preview needs: sample rows with the export context, fonts and images. */
310
+ interface PreviewData {
311
+ readonly input: ReportInput;
312
+ /** TrueType files by "family|400" / "family|700". */
313
+ readonly fonts: ReadonlyMap<string, Uint8Array>;
314
+ readonly metrics: ReadonlyMap<string, FontMetrics>;
315
+ /** Images by resolved src; missing ones could not be loaded. */
316
+ readonly images: ReadonlyMap<string, PreviewImage>;
317
+ }
318
+ /** Sample data for the template designer; @rastr/export-pdf builds one from a grid (gridPreviewSource). */
319
+ interface PreviewSource {
320
+ fields(): readonly PreviewField[];
321
+ load(template: ReportTemplate, rows: number): Promise<PreviewData>;
322
+ }
323
+
324
+ export { type Align, type Bands, type ColumnOverride, type Element, type ExpressionFilter, type ExpressionPart, type FontMetrics, type FontRef, type ImageElement, type LayoutDocument, type LayoutItem, type LayoutPage, type LineElement, type Locale, MM_PER_PT, type PageSetup, type PreviewData, type PreviewField, type PreviewImage, type PreviewSource, type RectElement, type ReportColumn, type ReportInput, type ReportTemplate, type StoredTemplate, type StyleRef, type TableBand, TemplateError, type TemplateIssue, type TemplateSave, type TemplateStore, TemplateStoreError, type TemplateSummary, type TextElement, type TextStyle, type Weight, compileCondition, createLocalTemplateStore, createRestTemplateStore, defaultText, evaluateText, formatValue, layoutReport, layoutReportAsync, measureText, parseExpression, parseFontMetrics, round2, templateLoader, validateTemplate, wrapText };