@formfeed/engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +54 -0
- package/index.cjs +3306 -0
- package/index.js +3273 -0
- package/package.json +70 -0
- package/types/index.d.cts +17 -0
- package/types/index.d.ts +17 -0
- package/types/lib/analysis/tags.d.cts +36 -0
- package/types/lib/analysis/tags.d.ts +36 -0
- package/types/lib/assemble.d.cts +147 -0
- package/types/lib/assemble.d.ts +147 -0
- package/types/lib/engines/handlebars.d.cts +3 -0
- package/types/lib/engines/handlebars.d.ts +3 -0
- package/types/lib/engines/index.d.cts +7 -0
- package/types/lib/engines/index.d.ts +7 -0
- package/types/lib/engines/jinja2.d.cts +5 -0
- package/types/lib/engines/jinja2.d.ts +5 -0
- package/types/lib/engines/liquid.d.cts +16 -0
- package/types/lib/engines/liquid.d.ts +16 -0
- package/types/lib/errors.d.cts +24 -0
- package/types/lib/errors.d.ts +24 -0
- package/types/lib/helpers/codes.d.cts +21 -0
- package/types/lib/helpers/codes.d.ts +21 -0
- package/types/lib/helpers/collections.d.cts +2 -0
- package/types/lib/helpers/collections.d.ts +2 -0
- package/types/lib/helpers/document.d.cts +29 -0
- package/types/lib/helpers/document.d.ts +29 -0
- package/types/lib/helpers/format.d.cts +5 -0
- package/types/lib/helpers/format.d.ts +5 -0
- package/types/lib/helpers/index.d.cts +17 -0
- package/types/lib/helpers/index.d.ts +17 -0
- package/types/lib/helpers/logic.d.cts +2 -0
- package/types/lib/helpers/logic.d.ts +2 -0
- package/types/lib/helpers/registry.d.cts +18 -0
- package/types/lib/helpers/registry.d.ts +18 -0
- package/types/lib/import/apitemplate.d.cts +45 -0
- package/types/lib/import/apitemplate.d.ts +45 -0
- package/types/lib/limits.d.cts +10 -0
- package/types/lib/limits.d.ts +10 -0
- package/types/lib/preview.d.cts +30 -0
- package/types/lib/preview.d.ts +30 -0
- package/types/lib/schema.d.cts +22 -0
- package/types/lib/schema.d.ts +22 -0
- package/types/lib/snippets.d.cts +22 -0
- package/types/lib/snippets.d.ts +22 -0
- package/types/lib/types.d.cts +140 -0
- package/types/lib/types.d.ts +140 -0
- package/types/types/modules.d.cts +85 -0
- package/types/types/modules.d.ts +85 -0
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@formfeed/engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The Formfeed template engine (Jinja2, Liquid, Handlebars) for the browser and Node.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./index.cjs",
|
|
8
|
+
"module": "./index.js",
|
|
9
|
+
"types": "./types/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./types/index.d.ts",
|
|
14
|
+
"default": "./index.js"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./types/index.d.cts",
|
|
18
|
+
"default": "./index.cjs"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"*.js",
|
|
25
|
+
"*.cjs",
|
|
26
|
+
"types",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"THIRD_PARTY_LICENSES.md"
|
|
30
|
+
],
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@date-fns/tz": "^1.5.0",
|
|
34
|
+
"bwip-js": "^4.11.4",
|
|
35
|
+
"date-fns": "^4.4.0",
|
|
36
|
+
"handlebars": "^4.7.9",
|
|
37
|
+
"liquidjs": "^10.29.0",
|
|
38
|
+
"marked": "^18.0.11",
|
|
39
|
+
"n2words": "^6.1.2",
|
|
40
|
+
"nunjucks": "^3.2.4",
|
|
41
|
+
"qrcode": "^1.5.4"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"formfeed",
|
|
45
|
+
"templates",
|
|
46
|
+
"template-engine",
|
|
47
|
+
"jinja2",
|
|
48
|
+
"liquid",
|
|
49
|
+
"handlebars",
|
|
50
|
+
"pdf"
|
|
51
|
+
],
|
|
52
|
+
"homepage": "https://docs.formfeed.dev/devkit/engine-package",
|
|
53
|
+
"author": {
|
|
54
|
+
"name": "Formfeed",
|
|
55
|
+
"email": "support@formfeed.dev",
|
|
56
|
+
"url": "https://formfeed.dev"
|
|
57
|
+
},
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+https://github.com/formfeed-dev/formfeed.git",
|
|
61
|
+
"directory": "packages/engine"
|
|
62
|
+
},
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/formfeed-dev/formfeed/issues",
|
|
65
|
+
"email": "support@formfeed.dev"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=22"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './lib/types.cjs';
|
|
2
|
+
export { EngineSyntaxError, RenderError, RenderLimitError } from './lib/errors.cjs';
|
|
3
|
+
export { defaultLimits, depthGuard, enforceLimits } from './lib/limits.cjs';
|
|
4
|
+
export { DefaultHelperRegistry, builtinHelpers, chartMarkup, chartPayload, createHelperRegistry, defaultHelpers, epcPayload, escapeHtml, helperDocs, imageMarkup, qrSvg, toDate, toNumber, } from './lib/helpers/index.cjs';
|
|
5
|
+
export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, getEngine, handlebarsEngine, jinja2Engine, liquidEngine, liquidBuiltinFilters, nunjucksBuiltinFilters, } from './lib/engines/index.cjs';
|
|
6
|
+
export { inferSchema, schemaPaths } from './lib/schema.cjs';
|
|
7
|
+
export { mergeSampleData, snippets, snippetsFor } from './lib/snippets.cjs';
|
|
8
|
+
export { importApitemplate, slugFromName } from './lib/import/apitemplate.cjs';
|
|
9
|
+
export type { ApitemplateExport, ImportNote, ImportResult, } from './lib/import/apitemplate.cjs';
|
|
10
|
+
export type { Snippet } from './lib/snippets.cjs';
|
|
11
|
+
export type { JsonSchema } from './lib/schema.cjs';
|
|
12
|
+
export { assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.cjs';
|
|
13
|
+
export type { ChartSpec, ImageOptions } from './lib/helpers/index.cjs';
|
|
14
|
+
export { flowDocument, pagedDocument, pageNumberSpans, paperOf } from './lib/preview.cjs';
|
|
15
|
+
export type { PagedOptions, RenderedDraft } from './lib/preview.cjs';
|
|
16
|
+
export type { AssembleExtras, AssembleInput, AssembleVendor, FontFace, RenderedDocument, TemplateKind, TemplateSettings, VersionSource, } from './lib/assemble.cjs';
|
|
17
|
+
export { resolvePath, scanBlocks, jinjaTags, liquidTags, } from './lib/analysis/tags.cjs';
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from './lib/types.js';
|
|
2
|
+
export { EngineSyntaxError, RenderError, RenderLimitError } from './lib/errors.js';
|
|
3
|
+
export { defaultLimits, depthGuard, enforceLimits } from './lib/limits.js';
|
|
4
|
+
export { DefaultHelperRegistry, builtinHelpers, chartMarkup, chartPayload, createHelperRegistry, defaultHelpers, epcPayload, escapeHtml, helperDocs, imageMarkup, qrSvg, toDate, toNumber, } from './lib/helpers/index.js';
|
|
5
|
+
export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, getEngine, handlebarsEngine, jinja2Engine, liquidEngine, liquidBuiltinFilters, nunjucksBuiltinFilters, } from './lib/engines/index.js';
|
|
6
|
+
export { inferSchema, schemaPaths } from './lib/schema.js';
|
|
7
|
+
export { mergeSampleData, snippets, snippetsFor } from './lib/snippets.js';
|
|
8
|
+
export { importApitemplate, slugFromName } from './lib/import/apitemplate.js';
|
|
9
|
+
export type { ApitemplateExport, ImportNote, ImportResult, } from './lib/import/apitemplate.js';
|
|
10
|
+
export type { Snippet } from './lib/snippets.js';
|
|
11
|
+
export type { JsonSchema } from './lib/schema.js';
|
|
12
|
+
export { assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.js';
|
|
13
|
+
export type { ChartSpec, ImageOptions } from './lib/helpers/index.js';
|
|
14
|
+
export { flowDocument, pagedDocument, pageNumberSpans, paperOf } from './lib/preview.js';
|
|
15
|
+
export type { PagedOptions, RenderedDraft } from './lib/preview.js';
|
|
16
|
+
export type { AssembleExtras, AssembleInput, AssembleVendor, FontFace, RenderedDocument, TemplateKind, TemplateSettings, VersionSource, } from './lib/assemble.js';
|
|
17
|
+
export { resolvePath, scanBlocks, jinjaTags, liquidTags, } from './lib/analysis/tags.js';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BlockRef, Diagnostic, Position, Range, VariableRef } from '../types.cjs';
|
|
2
|
+
/** Builds a range from a 1-based start position and a length on the same line. */
|
|
3
|
+
export declare function rangeAt(line: number, column: number, length: number): Range;
|
|
4
|
+
/** Converts a 0-based offset into a 1-based position. */
|
|
5
|
+
export declare function positionOf(source: string, offset: number): Position;
|
|
6
|
+
export declare function rangeOf(source: string, start: number, end: number): Range;
|
|
7
|
+
interface TagSpec {
|
|
8
|
+
/** Regex over the whole source; group 1 = tag keyword, group 2 = the rest of the tag. */
|
|
9
|
+
pattern: RegExp;
|
|
10
|
+
openers: Record<string, BlockRef['type']>;
|
|
11
|
+
/** Closing keyword → opening keyword. */
|
|
12
|
+
closers: Record<string, string>;
|
|
13
|
+
/** Keywords that continue a block without opening or closing one. */
|
|
14
|
+
continuations: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare const jinjaTags: TagSpec;
|
|
17
|
+
export declare const liquidTags: TagSpec;
|
|
18
|
+
/**
|
|
19
|
+
* Pairs opening and closing block tags by text scan. Works even when the parser bails out on the
|
|
20
|
+
* first error, so the editor gets every mismatch at once (spec 05 §3).
|
|
21
|
+
*/
|
|
22
|
+
export declare function scanBlocks(source: string, spec: TagSpec): {
|
|
23
|
+
blocks: BlockRef[];
|
|
24
|
+
diagnostics: Diagnostic[];
|
|
25
|
+
};
|
|
26
|
+
/** Looks a path up in sample data; arrays are traversed by union of their items' keys. */
|
|
27
|
+
export declare function resolvePath(data: unknown, path: string[]): {
|
|
28
|
+
found: boolean;
|
|
29
|
+
value: unknown;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Warns for `read` variables whose path is missing from the sample data. Loop variables are
|
|
33
|
+
* resolved through their source (`for line in invoice.lines` → `invoice.lines[]`) when known.
|
|
34
|
+
*/
|
|
35
|
+
export declare function missingPathDiagnostics(variables: VariableRef[], sampleData: unknown, loopSources: Map<string, string[] | null>, builtinRoots: Set<string>): Diagnostic[];
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BlockRef, Diagnostic, Position, Range, VariableRef } from '../types.js';
|
|
2
|
+
/** Builds a range from a 1-based start position and a length on the same line. */
|
|
3
|
+
export declare function rangeAt(line: number, column: number, length: number): Range;
|
|
4
|
+
/** Converts a 0-based offset into a 1-based position. */
|
|
5
|
+
export declare function positionOf(source: string, offset: number): Position;
|
|
6
|
+
export declare function rangeOf(source: string, start: number, end: number): Range;
|
|
7
|
+
interface TagSpec {
|
|
8
|
+
/** Regex over the whole source; group 1 = tag keyword, group 2 = the rest of the tag. */
|
|
9
|
+
pattern: RegExp;
|
|
10
|
+
openers: Record<string, BlockRef['type']>;
|
|
11
|
+
/** Closing keyword → opening keyword. */
|
|
12
|
+
closers: Record<string, string>;
|
|
13
|
+
/** Keywords that continue a block without opening or closing one. */
|
|
14
|
+
continuations: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare const jinjaTags: TagSpec;
|
|
17
|
+
export declare const liquidTags: TagSpec;
|
|
18
|
+
/**
|
|
19
|
+
* Pairs opening and closing block tags by text scan. Works even when the parser bails out on the
|
|
20
|
+
* first error, so the editor gets every mismatch at once (spec 05 §3).
|
|
21
|
+
*/
|
|
22
|
+
export declare function scanBlocks(source: string, spec: TagSpec): {
|
|
23
|
+
blocks: BlockRef[];
|
|
24
|
+
diagnostics: Diagnostic[];
|
|
25
|
+
};
|
|
26
|
+
/** Looks a path up in sample data; arrays are traversed by union of their items' keys. */
|
|
27
|
+
export declare function resolvePath(data: unknown, path: string[]): {
|
|
28
|
+
found: boolean;
|
|
29
|
+
value: unknown;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Warns for `read` variables whose path is missing from the sample data. Loop variables are
|
|
33
|
+
* resolved through their source (`for line in invoice.lines` → `invoice.lines[]`) when known.
|
|
34
|
+
*/
|
|
35
|
+
export declare function missingPathDiagnostics(variables: VariableRef[], sampleData: unknown, loopSources: Map<string, string[] | null>, builtinRoots: Set<string>): Diagnostic[];
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { EngineId, RenderContext } from './types.cjs';
|
|
2
|
+
/** Template settings (spec 01 §3); every field optional, `defaultSettings()` fills the rest. */
|
|
3
|
+
export interface TemplateSettings {
|
|
4
|
+
paper?: {
|
|
5
|
+
format?: string;
|
|
6
|
+
width?: string | null;
|
|
7
|
+
height?: string | null;
|
|
8
|
+
unit?: 'mm' | 'in' | 'px';
|
|
9
|
+
landscape?: boolean;
|
|
10
|
+
};
|
|
11
|
+
margin?: {
|
|
12
|
+
top?: string;
|
|
13
|
+
right?: string;
|
|
14
|
+
bottom?: string;
|
|
15
|
+
left?: string;
|
|
16
|
+
};
|
|
17
|
+
header?: {
|
|
18
|
+
html?: string;
|
|
19
|
+
height?: string;
|
|
20
|
+
} | null;
|
|
21
|
+
footer?: {
|
|
22
|
+
html?: string;
|
|
23
|
+
height?: string;
|
|
24
|
+
} | null;
|
|
25
|
+
printBackground?: boolean;
|
|
26
|
+
scale?: number;
|
|
27
|
+
preferCssPageSize?: boolean;
|
|
28
|
+
pageRanges?: string;
|
|
29
|
+
waitFor?: {
|
|
30
|
+
networkIdle?: boolean;
|
|
31
|
+
selector?: string | null;
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
delayMs?: number;
|
|
34
|
+
};
|
|
35
|
+
pdf?: {
|
|
36
|
+
tagged?: boolean;
|
|
37
|
+
outline?: boolean;
|
|
38
|
+
metadata?: {
|
|
39
|
+
title?: string;
|
|
40
|
+
author?: string;
|
|
41
|
+
subject?: string;
|
|
42
|
+
keywords?: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
image?: {
|
|
46
|
+
width?: number;
|
|
47
|
+
height?: number;
|
|
48
|
+
deviceScaleFactor?: number;
|
|
49
|
+
format?: 'png' | 'jpeg' | 'webp';
|
|
50
|
+
quality?: number;
|
|
51
|
+
fullPage?: boolean;
|
|
52
|
+
transparent?: boolean;
|
|
53
|
+
clipSelector?: string | null;
|
|
54
|
+
};
|
|
55
|
+
locale?: string;
|
|
56
|
+
timezone?: string;
|
|
57
|
+
currency?: string;
|
|
58
|
+
tailwind?: boolean;
|
|
59
|
+
watermark?: {
|
|
60
|
+
text?: string;
|
|
61
|
+
opacity?: number;
|
|
62
|
+
} | null;
|
|
63
|
+
}
|
|
64
|
+
export type TemplateKind = 'pdf' | 'image';
|
|
65
|
+
export declare function defaultSettings(): Required<Pick<TemplateSettings, 'paper' | 'margin' | 'printBackground' | 'scale' | 'preferCssPageSize' | 'locale' | 'timezone' | 'currency'>> & TemplateSettings;
|
|
66
|
+
/** Deep merge where `override` wins; `null` removes a section (e.g. `header: null`). */
|
|
67
|
+
export declare function mergeSettings(...layers: Array<TemplateSettings | null | undefined>): TemplateSettings;
|
|
68
|
+
/** `@page` size expression from the paper settings. */
|
|
69
|
+
export declare function pageSize(settings: TemplateSettings): string;
|
|
70
|
+
/** Default print reset of spec 05 §5. */
|
|
71
|
+
export declare function printReset(settings: TemplateSettings, kind?: TemplateKind): string;
|
|
72
|
+
/** An organisation font (spec 05 §6) reachable by URL from the preview frame or the worker. */
|
|
73
|
+
export interface FontFace {
|
|
74
|
+
family: string;
|
|
75
|
+
weight?: number;
|
|
76
|
+
style?: 'normal' | 'italic';
|
|
77
|
+
format?: 'woff2' | 'woff' | 'ttf' | 'otf';
|
|
78
|
+
url: string;
|
|
79
|
+
}
|
|
80
|
+
/** Browser-side vendor scripts the assembler wires in when the document needs them. */
|
|
81
|
+
export interface AssembleVendor {
|
|
82
|
+
/** Chart.js UMD build: a URL the frame can load, or the source to inline (render-worker). */
|
|
83
|
+
chartJs?: {
|
|
84
|
+
src: string;
|
|
85
|
+
} | {
|
|
86
|
+
inline: string;
|
|
87
|
+
};
|
|
88
|
+
/** `@tailwindcss/browser` for the preview; the worker compiles Tailwind ahead and passes `extraCss`. */
|
|
89
|
+
tailwind?: {
|
|
90
|
+
src: string;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Optional inputs that vary per host (preview frame vs. worker) rather than per template. */
|
|
94
|
+
export interface AssembleExtras {
|
|
95
|
+
fonts?: FontFace[];
|
|
96
|
+
vendor?: AssembleVendor;
|
|
97
|
+
/** Stylesheet appended after the template CSS (compiled Tailwind in the worker). */
|
|
98
|
+
extraCss?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* `@font-face` rules for the organisation fonts a template refers to (spec 05 §6): a font is
|
|
102
|
+
* injected when its family name appears anywhere in the template's CSS, head or HTML.
|
|
103
|
+
*/
|
|
104
|
+
export declare function fontFaceCss(fonts: FontFace[] | undefined, referencedIn: string): string;
|
|
105
|
+
/** Draws every `canvas[data-ff-chart]` placed by the `chart` helper; runs after the body is parsed. */
|
|
106
|
+
export declare function chartInitScript(): string;
|
|
107
|
+
export interface AssembleInput extends AssembleExtras {
|
|
108
|
+
/** Rendered body HTML (engine output). */
|
|
109
|
+
html: string;
|
|
110
|
+
css?: string;
|
|
111
|
+
head?: string;
|
|
112
|
+
settings?: TemplateSettings;
|
|
113
|
+
kind?: TemplateKind;
|
|
114
|
+
/** Base URL for relative asset references (`<base href>`); omitted when undefined. */
|
|
115
|
+
assetBaseUrl?: string;
|
|
116
|
+
/** Preview marks the document so the preview frame can style it; print is what Chromium gets. */
|
|
117
|
+
mode?: 'preview' | 'print';
|
|
118
|
+
title?: string;
|
|
119
|
+
}
|
|
120
|
+
/** Produces the full document handed to Chromium or the preview frame (spec 05 §5). */
|
|
121
|
+
export declare function assembleDocument(input: AssembleInput): string;
|
|
122
|
+
export interface VersionSource {
|
|
123
|
+
engine: EngineId;
|
|
124
|
+
html: string;
|
|
125
|
+
css?: string;
|
|
126
|
+
head?: string;
|
|
127
|
+
settings?: TemplateSettings;
|
|
128
|
+
kind?: TemplateKind;
|
|
129
|
+
}
|
|
130
|
+
export interface RenderedDocument {
|
|
131
|
+
/** Complete HTML document. */
|
|
132
|
+
document: string;
|
|
133
|
+
/** Rendered header/footer HTML for Chromium's `headerTemplate`/`footerTemplate`, when configured. */
|
|
134
|
+
headerHtml?: string;
|
|
135
|
+
footerHtml?: string;
|
|
136
|
+
/** PDF metadata title after template rendering. */
|
|
137
|
+
title?: string;
|
|
138
|
+
settings: TemplateSettings;
|
|
139
|
+
/** Font faces and extra CSS the header/footer templates need inlined (Chromium loads no external CSS there). */
|
|
140
|
+
inlineCss: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Renders a template version end to end: body, header, footer and metadata with the same engine and
|
|
144
|
+
* data, then assembles the document. Header and footer are rendered without autoescape differences:
|
|
145
|
+
* they are HTML by definition.
|
|
146
|
+
*/
|
|
147
|
+
export declare function renderVersion(version: VersionSource, data: unknown, ctx: RenderContext, mode?: 'preview' | 'print', extras?: AssembleExtras): Promise<RenderedDocument>;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { EngineId, RenderContext } from './types.js';
|
|
2
|
+
/** Template settings (spec 01 §3); every field optional, `defaultSettings()` fills the rest. */
|
|
3
|
+
export interface TemplateSettings {
|
|
4
|
+
paper?: {
|
|
5
|
+
format?: string;
|
|
6
|
+
width?: string | null;
|
|
7
|
+
height?: string | null;
|
|
8
|
+
unit?: 'mm' | 'in' | 'px';
|
|
9
|
+
landscape?: boolean;
|
|
10
|
+
};
|
|
11
|
+
margin?: {
|
|
12
|
+
top?: string;
|
|
13
|
+
right?: string;
|
|
14
|
+
bottom?: string;
|
|
15
|
+
left?: string;
|
|
16
|
+
};
|
|
17
|
+
header?: {
|
|
18
|
+
html?: string;
|
|
19
|
+
height?: string;
|
|
20
|
+
} | null;
|
|
21
|
+
footer?: {
|
|
22
|
+
html?: string;
|
|
23
|
+
height?: string;
|
|
24
|
+
} | null;
|
|
25
|
+
printBackground?: boolean;
|
|
26
|
+
scale?: number;
|
|
27
|
+
preferCssPageSize?: boolean;
|
|
28
|
+
pageRanges?: string;
|
|
29
|
+
waitFor?: {
|
|
30
|
+
networkIdle?: boolean;
|
|
31
|
+
selector?: string | null;
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
delayMs?: number;
|
|
34
|
+
};
|
|
35
|
+
pdf?: {
|
|
36
|
+
tagged?: boolean;
|
|
37
|
+
outline?: boolean;
|
|
38
|
+
metadata?: {
|
|
39
|
+
title?: string;
|
|
40
|
+
author?: string;
|
|
41
|
+
subject?: string;
|
|
42
|
+
keywords?: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
image?: {
|
|
46
|
+
width?: number;
|
|
47
|
+
height?: number;
|
|
48
|
+
deviceScaleFactor?: number;
|
|
49
|
+
format?: 'png' | 'jpeg' | 'webp';
|
|
50
|
+
quality?: number;
|
|
51
|
+
fullPage?: boolean;
|
|
52
|
+
transparent?: boolean;
|
|
53
|
+
clipSelector?: string | null;
|
|
54
|
+
};
|
|
55
|
+
locale?: string;
|
|
56
|
+
timezone?: string;
|
|
57
|
+
currency?: string;
|
|
58
|
+
tailwind?: boolean;
|
|
59
|
+
watermark?: {
|
|
60
|
+
text?: string;
|
|
61
|
+
opacity?: number;
|
|
62
|
+
} | null;
|
|
63
|
+
}
|
|
64
|
+
export type TemplateKind = 'pdf' | 'image';
|
|
65
|
+
export declare function defaultSettings(): Required<Pick<TemplateSettings, 'paper' | 'margin' | 'printBackground' | 'scale' | 'preferCssPageSize' | 'locale' | 'timezone' | 'currency'>> & TemplateSettings;
|
|
66
|
+
/** Deep merge where `override` wins; `null` removes a section (e.g. `header: null`). */
|
|
67
|
+
export declare function mergeSettings(...layers: Array<TemplateSettings | null | undefined>): TemplateSettings;
|
|
68
|
+
/** `@page` size expression from the paper settings. */
|
|
69
|
+
export declare function pageSize(settings: TemplateSettings): string;
|
|
70
|
+
/** Default print reset of spec 05 §5. */
|
|
71
|
+
export declare function printReset(settings: TemplateSettings, kind?: TemplateKind): string;
|
|
72
|
+
/** An organisation font (spec 05 §6) reachable by URL from the preview frame or the worker. */
|
|
73
|
+
export interface FontFace {
|
|
74
|
+
family: string;
|
|
75
|
+
weight?: number;
|
|
76
|
+
style?: 'normal' | 'italic';
|
|
77
|
+
format?: 'woff2' | 'woff' | 'ttf' | 'otf';
|
|
78
|
+
url: string;
|
|
79
|
+
}
|
|
80
|
+
/** Browser-side vendor scripts the assembler wires in when the document needs them. */
|
|
81
|
+
export interface AssembleVendor {
|
|
82
|
+
/** Chart.js UMD build: a URL the frame can load, or the source to inline (render-worker). */
|
|
83
|
+
chartJs?: {
|
|
84
|
+
src: string;
|
|
85
|
+
} | {
|
|
86
|
+
inline: string;
|
|
87
|
+
};
|
|
88
|
+
/** `@tailwindcss/browser` for the preview; the worker compiles Tailwind ahead and passes `extraCss`. */
|
|
89
|
+
tailwind?: {
|
|
90
|
+
src: string;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Optional inputs that vary per host (preview frame vs. worker) rather than per template. */
|
|
94
|
+
export interface AssembleExtras {
|
|
95
|
+
fonts?: FontFace[];
|
|
96
|
+
vendor?: AssembleVendor;
|
|
97
|
+
/** Stylesheet appended after the template CSS (compiled Tailwind in the worker). */
|
|
98
|
+
extraCss?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* `@font-face` rules for the organisation fonts a template refers to (spec 05 §6): a font is
|
|
102
|
+
* injected when its family name appears anywhere in the template's CSS, head or HTML.
|
|
103
|
+
*/
|
|
104
|
+
export declare function fontFaceCss(fonts: FontFace[] | undefined, referencedIn: string): string;
|
|
105
|
+
/** Draws every `canvas[data-ff-chart]` placed by the `chart` helper; runs after the body is parsed. */
|
|
106
|
+
export declare function chartInitScript(): string;
|
|
107
|
+
export interface AssembleInput extends AssembleExtras {
|
|
108
|
+
/** Rendered body HTML (engine output). */
|
|
109
|
+
html: string;
|
|
110
|
+
css?: string;
|
|
111
|
+
head?: string;
|
|
112
|
+
settings?: TemplateSettings;
|
|
113
|
+
kind?: TemplateKind;
|
|
114
|
+
/** Base URL for relative asset references (`<base href>`); omitted when undefined. */
|
|
115
|
+
assetBaseUrl?: string;
|
|
116
|
+
/** Preview marks the document so the preview frame can style it; print is what Chromium gets. */
|
|
117
|
+
mode?: 'preview' | 'print';
|
|
118
|
+
title?: string;
|
|
119
|
+
}
|
|
120
|
+
/** Produces the full document handed to Chromium or the preview frame (spec 05 §5). */
|
|
121
|
+
export declare function assembleDocument(input: AssembleInput): string;
|
|
122
|
+
export interface VersionSource {
|
|
123
|
+
engine: EngineId;
|
|
124
|
+
html: string;
|
|
125
|
+
css?: string;
|
|
126
|
+
head?: string;
|
|
127
|
+
settings?: TemplateSettings;
|
|
128
|
+
kind?: TemplateKind;
|
|
129
|
+
}
|
|
130
|
+
export interface RenderedDocument {
|
|
131
|
+
/** Complete HTML document. */
|
|
132
|
+
document: string;
|
|
133
|
+
/** Rendered header/footer HTML for Chromium's `headerTemplate`/`footerTemplate`, when configured. */
|
|
134
|
+
headerHtml?: string;
|
|
135
|
+
footerHtml?: string;
|
|
136
|
+
/** PDF metadata title after template rendering. */
|
|
137
|
+
title?: string;
|
|
138
|
+
settings: TemplateSettings;
|
|
139
|
+
/** Font faces and extra CSS the header/footer templates need inlined (Chromium loads no external CSS there). */
|
|
140
|
+
inlineCss: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Renders a template version end to end: body, header, footer and metadata with the same engine and
|
|
144
|
+
* data, then assembles the document. Header and footer are rendered without autoescape differences:
|
|
145
|
+
* they are HTML by definition.
|
|
146
|
+
*/
|
|
147
|
+
export declare function renderVersion(version: VersionSource, data: unknown, ctx: RenderContext, mode?: 'preview' | 'print', extras?: AssembleExtras): Promise<RenderedDocument>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Engine, EngineId } from '../types.cjs';
|
|
2
|
+
export { analyzeHandlebars, handlebarsEngine } from './handlebars.cjs';
|
|
3
|
+
export { analyzeJinja2, jinja2Engine, nunjucksBuiltinFilters } from './jinja2.cjs';
|
|
4
|
+
export { analyzeLiquid, liquidBuiltinFilters, liquidEngine } from './liquid.cjs';
|
|
5
|
+
export declare const engines: Record<EngineId, Engine>;
|
|
6
|
+
export declare const engineIds: EngineId[];
|
|
7
|
+
export declare function getEngine(id: EngineId | string): Engine;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Engine, EngineId } from '../types.js';
|
|
2
|
+
export { analyzeHandlebars, handlebarsEngine } from './handlebars.js';
|
|
3
|
+
export { analyzeJinja2, jinja2Engine, nunjucksBuiltinFilters } from './jinja2.js';
|
|
4
|
+
export { analyzeLiquid, liquidBuiltinFilters, liquidEngine } from './liquid.js';
|
|
5
|
+
export declare const engines: Record<EngineId, Engine>;
|
|
6
|
+
export declare const engineIds: EngineId[];
|
|
7
|
+
export declare function getEngine(id: EngineId | string): Engine;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Analysis, AnalyzeOptions, Engine } from '../types.cjs';
|
|
2
|
+
/** Nunjucks built-in filters that count as known even without a helper of the same name. */
|
|
3
|
+
export declare const nunjucksBuiltinFilters: Set<string>;
|
|
4
|
+
export declare function analyzeJinja2(source: string, opts?: AnalyzeOptions): Analysis;
|
|
5
|
+
export declare const jinja2Engine: Engine;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Analysis, AnalyzeOptions, Engine } from '../types.js';
|
|
2
|
+
/** Nunjucks built-in filters that count as known even without a helper of the same name. */
|
|
3
|
+
export declare const nunjucksBuiltinFilters: Set<string>;
|
|
4
|
+
export declare function analyzeJinja2(source: string, opts?: AnalyzeOptions): Analysis;
|
|
5
|
+
export declare const jinja2Engine: Engine;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Analysis, AnalyzeOptions, Engine } from '../types.cjs';
|
|
2
|
+
/** LiquidJS standard filters (Shopify set) that count as known. */
|
|
3
|
+
export declare const liquidBuiltinFilters: Set<string>;
|
|
4
|
+
/**
|
|
5
|
+
* LiquidJS hands keyword filter arguments (`| image: width: 120, fit: 'cover'`) over as `[key, value]`
|
|
6
|
+
* pairs after the positional ones. They become one trailing options object, the shape the helpers
|
|
7
|
+
* take in Jinja2 (`{ width: 120 }`) and Handlebars (hash arguments), so all engines share one helper.
|
|
8
|
+
*
|
|
9
|
+
* Which arguments are keywords comes from the parsed filter token (`isKeyword`), never from the
|
|
10
|
+
* value: at runtime a `[key, value]` pair and a two-element array of strings look the same, and
|
|
11
|
+
* guessing by shape turned `['red', 'green'] | join: ', '` into the keyword argument `red: 'green'`
|
|
12
|
+
* — a list that worked with three entries silently broke with exactly two.
|
|
13
|
+
*/
|
|
14
|
+
export declare function collectKeywordArgs(args: unknown[], isKeyword: (index: number) => boolean): unknown[];
|
|
15
|
+
export declare function analyzeLiquid(source: string, opts?: AnalyzeOptions): Analysis;
|
|
16
|
+
export declare const liquidEngine: Engine;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Analysis, AnalyzeOptions, Engine } from '../types.js';
|
|
2
|
+
/** LiquidJS standard filters (Shopify set) that count as known. */
|
|
3
|
+
export declare const liquidBuiltinFilters: Set<string>;
|
|
4
|
+
/**
|
|
5
|
+
* LiquidJS hands keyword filter arguments (`| image: width: 120, fit: 'cover'`) over as `[key, value]`
|
|
6
|
+
* pairs after the positional ones. They become one trailing options object, the shape the helpers
|
|
7
|
+
* take in Jinja2 (`{ width: 120 }`) and Handlebars (hash arguments), so all engines share one helper.
|
|
8
|
+
*
|
|
9
|
+
* Which arguments are keywords comes from the parsed filter token (`isKeyword`), never from the
|
|
10
|
+
* value: at runtime a `[key, value]` pair and a two-element array of strings look the same, and
|
|
11
|
+
* guessing by shape turned `['red', 'green'] | join: ', '` into the keyword argument `red: 'green'`
|
|
12
|
+
* — a list that worked with three entries silently broke with exactly two.
|
|
13
|
+
*/
|
|
14
|
+
export declare function collectKeywordArgs(args: unknown[], isKeyword: (index: number) => boolean): unknown[];
|
|
15
|
+
export declare function analyzeLiquid(source: string, opts?: AnalyzeOptions): Analysis;
|
|
16
|
+
export declare const liquidEngine: Engine;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { EngineId, Position } from './types.cjs';
|
|
2
|
+
/** Parse or compile failure with a location the editor can jump to. */
|
|
3
|
+
export declare class EngineSyntaxError extends Error {
|
|
4
|
+
readonly engine: EngineId;
|
|
5
|
+
readonly line: number;
|
|
6
|
+
readonly column: number;
|
|
7
|
+
readonly name = "EngineSyntaxError";
|
|
8
|
+
constructor(engine: EngineId, message: string, line: number, column: number);
|
|
9
|
+
get position(): Position;
|
|
10
|
+
}
|
|
11
|
+
/** A render exceeded one of the limits in `RenderLimits` (spec 05 §7). */
|
|
12
|
+
export declare class RenderLimitError extends Error {
|
|
13
|
+
readonly limit: 'ms' | 'outputBytes' | 'includeDepth';
|
|
14
|
+
readonly name = "RenderLimitError";
|
|
15
|
+
constructor(limit: 'ms' | 'outputBytes' | 'includeDepth', message: string);
|
|
16
|
+
}
|
|
17
|
+
/** Runtime failure inside a template (unknown filter at render time, helper threw, ...). */
|
|
18
|
+
export declare class RenderError extends Error {
|
|
19
|
+
readonly engine: EngineId;
|
|
20
|
+
readonly line?: number | undefined;
|
|
21
|
+
readonly column?: number | undefined;
|
|
22
|
+
readonly name = "RenderError";
|
|
23
|
+
constructor(engine: EngineId, message: string, line?: number | undefined, column?: number | undefined);
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { EngineId, Position } from './types.js';
|
|
2
|
+
/** Parse or compile failure with a location the editor can jump to. */
|
|
3
|
+
export declare class EngineSyntaxError extends Error {
|
|
4
|
+
readonly engine: EngineId;
|
|
5
|
+
readonly line: number;
|
|
6
|
+
readonly column: number;
|
|
7
|
+
readonly name = "EngineSyntaxError";
|
|
8
|
+
constructor(engine: EngineId, message: string, line: number, column: number);
|
|
9
|
+
get position(): Position;
|
|
10
|
+
}
|
|
11
|
+
/** A render exceeded one of the limits in `RenderLimits` (spec 05 §7). */
|
|
12
|
+
export declare class RenderLimitError extends Error {
|
|
13
|
+
readonly limit: 'ms' | 'outputBytes' | 'includeDepth';
|
|
14
|
+
readonly name = "RenderLimitError";
|
|
15
|
+
constructor(limit: 'ms' | 'outputBytes' | 'includeDepth', message: string);
|
|
16
|
+
}
|
|
17
|
+
/** Runtime failure inside a template (unknown filter at render time, helper threw, ...). */
|
|
18
|
+
export declare class RenderError extends Error {
|
|
19
|
+
readonly engine: EngineId;
|
|
20
|
+
readonly line?: number | undefined;
|
|
21
|
+
readonly column?: number | undefined;
|
|
22
|
+
readonly name = "RenderError";
|
|
23
|
+
constructor(engine: EngineId, message: string, line?: number | undefined, column?: number | undefined);
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HelperDefinition } from '../types.cjs';
|
|
2
|
+
type QrOptions = {
|
|
3
|
+
size?: number;
|
|
4
|
+
ecc?: 'L' | 'M' | 'Q' | 'H';
|
|
5
|
+
margin?: number;
|
|
6
|
+
color?: string;
|
|
7
|
+
background?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function qrSvg(value: string, options?: QrOptions): string;
|
|
10
|
+
/** EPC QR (GiroCode) payload, version 002, UTF-8, SCT. */
|
|
11
|
+
export declare function epcPayload(input: {
|
|
12
|
+
name: string;
|
|
13
|
+
iban: string;
|
|
14
|
+
bic?: string;
|
|
15
|
+
amount?: number | string;
|
|
16
|
+
reference?: string;
|
|
17
|
+
text?: string;
|
|
18
|
+
purpose?: string;
|
|
19
|
+
}): string;
|
|
20
|
+
export declare const codeHelpers: HelperDefinition[];
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HelperDefinition } from '../types.js';
|
|
2
|
+
type QrOptions = {
|
|
3
|
+
size?: number;
|
|
4
|
+
ecc?: 'L' | 'M' | 'Q' | 'H';
|
|
5
|
+
margin?: number;
|
|
6
|
+
color?: string;
|
|
7
|
+
background?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function qrSvg(value: string, options?: QrOptions): string;
|
|
10
|
+
/** EPC QR (GiroCode) payload, version 002, UTF-8, SCT. */
|
|
11
|
+
export declare function epcPayload(input: {
|
|
12
|
+
name: string;
|
|
13
|
+
iban: string;
|
|
14
|
+
bic?: string;
|
|
15
|
+
amount?: number | string;
|
|
16
|
+
reference?: string;
|
|
17
|
+
text?: string;
|
|
18
|
+
purpose?: string;
|
|
19
|
+
}): string;
|
|
20
|
+
export declare const codeHelpers: HelperDefinition[];
|
|
21
|
+
export {};
|