@formfeed/engine 0.2.0 → 0.3.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/THIRD_PARTY_LICENSES.md +31 -0
- package/index.cjs +4204 -166
- package/index.js +4204 -166
- package/package.json +1 -1
- package/types/index.d.cts +19 -9
- package/types/index.d.ts +19 -9
- package/types/lib/assemble.d.cts +24 -9
- package/types/lib/assemble.d.ts +24 -9
- package/types/lib/brand.d.cts +46 -0
- package/types/lib/brand.d.ts +46 -0
- package/types/lib/helpers/document.d.cts +24 -0
- package/types/lib/helpers/document.d.ts +24 -0
- package/types/lib/helpers/index.d.cts +1 -0
- package/types/lib/helpers/index.d.ts +1 -0
- package/types/lib/helpers/office.d.cts +4 -0
- package/types/lib/helpers/office.d.ts +4 -0
- package/types/lib/import/apitemplate.d.cts +60 -0
- package/types/lib/import/apitemplate.d.ts +60 -0
- package/types/lib/office/detect.d.cts +36 -0
- package/types/lib/office/detect.d.ts +36 -0
- package/types/lib/office/drawings.d.cts +120 -0
- package/types/lib/office/drawings.d.ts +120 -0
- package/types/lib/office/errors.d.cts +21 -0
- package/types/lib/office/errors.d.ts +21 -0
- package/types/lib/office/fonts.d.cts +21 -0
- package/types/lib/office/fonts.d.ts +21 -0
- package/types/lib/office/ids.d.cts +1 -0
- package/types/lib/office/ids.d.ts +1 -0
- package/types/lib/office/index.d.cts +18 -0
- package/types/lib/office/index.d.ts +18 -0
- package/types/lib/office/render.d.cts +79 -0
- package/types/lib/office/render.d.ts +79 -0
- package/types/lib/office/sanitise.d.cts +35 -0
- package/types/lib/office/sanitise.d.ts +35 -0
- package/types/lib/office/slides.d.cts +47 -0
- package/types/lib/office/slides.d.ts +47 -0
- package/types/lib/office/starter-pptx.d.cts +6 -0
- package/types/lib/office/starter-pptx.d.ts +6 -0
- package/types/lib/office/starter.d.cts +24 -0
- package/types/lib/office/starter.d.ts +24 -0
- package/types/lib/office/structure.d.cts +51 -0
- package/types/lib/office/structure.d.ts +51 -0
- package/types/lib/office/tags.d.cts +51 -0
- package/types/lib/office/tags.d.ts +51 -0
- package/types/lib/office/template-text.d.cts +59 -0
- package/types/lib/office/template-text.d.ts +59 -0
- package/types/lib/office/xml.d.cts +44 -0
- package/types/lib/office/xml.d.ts +44 -0
- package/types/lib/office/zip.d.cts +49 -0
- package/types/lib/office/zip.d.ts +49 -0
- package/types/lib/output.d.cts +29 -0
- package/types/lib/output.d.ts +29 -0
- package/types/lib/preview.d.cts +9 -1
- package/types/lib/preview.d.ts +9 -1
- package/types/lib/schema-diff.d.cts +27 -0
- package/types/lib/schema-diff.d.ts +27 -0
- package/types/lib/schema.d.cts +8 -0
- package/types/lib/schema.d.ts +8 -0
- package/types/lib/snippets.d.cts +38 -1
- package/types/lib/snippets.d.ts +38 -1
- package/types/lib/source-positions.d.cts +27 -0
- package/types/lib/source-positions.d.ts +27 -0
- package/types/lib/types.d.cts +37 -1
- package/types/lib/types.d.ts +37 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formats of a render and the one rule for the format a request gets when it names none.
|
|
3
|
+
* Imported without the renderers as `@formfeed/engine/output` (the gateway), so it depends on
|
|
4
|
+
* nothing.
|
|
5
|
+
*/
|
|
6
|
+
/** The API's `output` values. JPEG is `jpg` here; settings spell it `jpeg`. */
|
|
7
|
+
export declare const outputFormats: readonly ["pdf", "png", "jpg", "webp", "docx", "pptx"];
|
|
8
|
+
export type OutputFormat = (typeof outputFormats)[number];
|
|
9
|
+
export type ImageOutput = 'png' | 'jpg' | 'webp';
|
|
10
|
+
/** Template kinds whose template is a Word or PowerPoint file (spec 22 §4.1). */
|
|
11
|
+
export declare const officeKinds: readonly ["docx", "pptx"];
|
|
12
|
+
export type OfficeKind = (typeof officeKinds)[number];
|
|
13
|
+
export declare function isOutputFormat(value: unknown): value is OutputFormat;
|
|
14
|
+
export declare function isOfficeKind(value: unknown): value is OfficeKind;
|
|
15
|
+
/**
|
|
16
|
+
* The outputs a source may request (spec 22 §4.1): an office template its own format or a PDF;
|
|
17
|
+
* everything else (PDF and image templates, ad-hoc HTML, URLs) PDF or an image.
|
|
18
|
+
*/
|
|
19
|
+
export declare function outputsForKind(kind: string | null | undefined): readonly OutputFormat[];
|
|
20
|
+
/** `settings.image.format` as an output; `jpg` is accepted too, anything else is PNG. */
|
|
21
|
+
export declare function imageOutput(settings: unknown): ImageOutput;
|
|
22
|
+
/**
|
|
23
|
+
* The output of a render that names none: a PDF template renders a PDF, an image template the format
|
|
24
|
+
* of its `settings.image.format` (PNG without one), an office template `settings.office.output` (its
|
|
25
|
+
* own format without one). Settings are the template's with the request's merged over them, so a
|
|
26
|
+
* request can pick the format without naming `output`. Sources without a kind (ad-hoc HTML, URLs)
|
|
27
|
+
* render PDFs.
|
|
28
|
+
*/
|
|
29
|
+
export declare function defaultOutput(kind: string | null | undefined, ...settings: unknown[]): OutputFormat;
|
package/types/lib/preview.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TemplateKind, type TemplateSettings } from './assemble.cjs';
|
|
2
2
|
/**
|
|
3
3
|
* Preview documents shared by the web editor and `formfeed dev` (spec 06 §3, spec 15 §4): the
|
|
4
4
|
* assembled document of `renderVersion` wrapped for the screen. Flow mode shows one page-wide
|
|
@@ -18,6 +18,14 @@ export declare function paperOf(settings: TemplateSettings): {
|
|
|
18
18
|
};
|
|
19
19
|
/** Chromium's header/footer placeholders replaced for the screen. */
|
|
20
20
|
export declare const pageNumberSpans: (html: string, page: string, total: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Zoom gestures inside a preview frame: Ctrl+wheel (a touchpad pinch arrives as one too) and
|
|
23
|
+
* Ctrl+plus/minus/0 would zoom the whole app, and the sandboxed frame's events never reach the app,
|
|
24
|
+
* so the frame cancels them and asks the parent by message:
|
|
25
|
+
* `{ type: 'formfeed:zoom', deltaY, deltaMode }` or `{ type: 'formfeed:zoom', step: 'in' | 'out' | 'reset' }`.
|
|
26
|
+
* The office quick preview's frame uses the same script.
|
|
27
|
+
*/
|
|
28
|
+
export declare const zoomGestureScript = "<script>\n(function () {\n var say = function (message) { try { parent.postMessage(message, '*'); } catch (e) {} };\n window.addEventListener('wheel', function (event) {\n if (!event.ctrlKey && !event.metaKey) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', deltaY: event.deltaY, deltaMode: event.deltaMode });\n }, { passive: false });\n window.addEventListener('keydown', function (event) {\n if (!(event.ctrlKey || event.metaKey) || event.altKey) return;\n var step = event.key === '+' || event.key === '=' ? 'in' : event.key === '-' ? 'out' : event.key === '0' ? 'reset' : null;\n if (!step) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', step: step });\n });\n})();\n</script>";
|
|
21
29
|
export declare function flowDocument(draft: RenderedDraft): string;
|
|
22
30
|
export interface PagedOptions {
|
|
23
31
|
/** URL of the Paged.js polyfill the frame can load. */
|
package/types/lib/preview.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TemplateKind, type TemplateSettings } from './assemble.js';
|
|
2
2
|
/**
|
|
3
3
|
* Preview documents shared by the web editor and `formfeed dev` (spec 06 §3, spec 15 §4): the
|
|
4
4
|
* assembled document of `renderVersion` wrapped for the screen. Flow mode shows one page-wide
|
|
@@ -18,6 +18,14 @@ export declare function paperOf(settings: TemplateSettings): {
|
|
|
18
18
|
};
|
|
19
19
|
/** Chromium's header/footer placeholders replaced for the screen. */
|
|
20
20
|
export declare const pageNumberSpans: (html: string, page: string, total: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Zoom gestures inside a preview frame: Ctrl+wheel (a touchpad pinch arrives as one too) and
|
|
23
|
+
* Ctrl+plus/minus/0 would zoom the whole app, and the sandboxed frame's events never reach the app,
|
|
24
|
+
* so the frame cancels them and asks the parent by message:
|
|
25
|
+
* `{ type: 'formfeed:zoom', deltaY, deltaMode }` or `{ type: 'formfeed:zoom', step: 'in' | 'out' | 'reset' }`.
|
|
26
|
+
* The office quick preview's frame uses the same script.
|
|
27
|
+
*/
|
|
28
|
+
export declare const zoomGestureScript = "<script>\n(function () {\n var say = function (message) { try { parent.postMessage(message, '*'); } catch (e) {} };\n window.addEventListener('wheel', function (event) {\n if (!event.ctrlKey && !event.metaKey) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', deltaY: event.deltaY, deltaMode: event.deltaMode });\n }, { passive: false });\n window.addEventListener('keydown', function (event) {\n if (!(event.ctrlKey || event.metaKey) || event.altKey) return;\n var step = event.key === '+' || event.key === '=' ? 'in' : event.key === '-' ? 'out' : event.key === '0' ? 'reset' : null;\n if (!step) return;\n event.preventDefault();\n say({ type: 'formfeed:zoom', step: step });\n });\n})();\n</script>";
|
|
21
29
|
export declare function flowDocument(draft: RenderedDraft): string;
|
|
22
30
|
export interface PagedOptions {
|
|
23
31
|
/** URL of the Paged.js polyfill the frame can load. */
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compares two data schemas from the caller's point of view (spec 19 §3.1): the caller sends data,
|
|
3
|
+
* the template reads it. A change is breaking when data that fitted the previous schema may no
|
|
4
|
+
* longer fit the next one. Keywords this module does not analyse compare by deep equality and count
|
|
5
|
+
* as breaking when they differ, so the check asks rather than waves a change through.
|
|
6
|
+
*
|
|
7
|
+
* Worker-safe (no Node APIs): the gateway runs it before publishing and before moving a channel.
|
|
8
|
+
*/
|
|
9
|
+
export type SchemaChangeKind = 'field-added-required' | 'field-added-optional' | 'field-removed' | 'field-became-required' | 'field-became-optional' | 'type-narrowed' | 'type-widened' | 'enum-values-removed' | 'enum-values-added' | 'enum-added' | 'enum-removed' | 'const-changed' | 'constraint-tightened' | 'constraint-relaxed' | 'additional-properties-closed' | 'additional-properties-opened' | 'keyword-changed';
|
|
10
|
+
export interface SchemaChange {
|
|
11
|
+
/** Dotted field path (`customer.email`, `items[]`); empty for the root. */
|
|
12
|
+
path: string;
|
|
13
|
+
/** JSON pointer into the next schema (or the previous one for a removal). */
|
|
14
|
+
pointer: string;
|
|
15
|
+
kind: SchemaChangeKind;
|
|
16
|
+
breaking: boolean;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SchemaDiff {
|
|
20
|
+
breaking: SchemaChange[];
|
|
21
|
+
safe: SchemaChange[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The changes from `previous` to `next`, split into breaking and safe. `null` on either side means
|
|
25
|
+
* "no schema": nothing to compare, so the result is empty.
|
|
26
|
+
*/
|
|
27
|
+
export declare function diffSchemas(previous: unknown, next: unknown): SchemaDiff;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compares two data schemas from the caller's point of view (spec 19 §3.1): the caller sends data,
|
|
3
|
+
* the template reads it. A change is breaking when data that fitted the previous schema may no
|
|
4
|
+
* longer fit the next one. Keywords this module does not analyse compare by deep equality and count
|
|
5
|
+
* as breaking when they differ, so the check asks rather than waves a change through.
|
|
6
|
+
*
|
|
7
|
+
* Worker-safe (no Node APIs): the gateway runs it before publishing and before moving a channel.
|
|
8
|
+
*/
|
|
9
|
+
export type SchemaChangeKind = 'field-added-required' | 'field-added-optional' | 'field-removed' | 'field-became-required' | 'field-became-optional' | 'type-narrowed' | 'type-widened' | 'enum-values-removed' | 'enum-values-added' | 'enum-added' | 'enum-removed' | 'const-changed' | 'constraint-tightened' | 'constraint-relaxed' | 'additional-properties-closed' | 'additional-properties-opened' | 'keyword-changed';
|
|
10
|
+
export interface SchemaChange {
|
|
11
|
+
/** Dotted field path (`customer.email`, `items[]`); empty for the root. */
|
|
12
|
+
path: string;
|
|
13
|
+
/** JSON pointer into the next schema (or the previous one for a removal). */
|
|
14
|
+
pointer: string;
|
|
15
|
+
kind: SchemaChangeKind;
|
|
16
|
+
breaking: boolean;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SchemaDiff {
|
|
20
|
+
breaking: SchemaChange[];
|
|
21
|
+
safe: SchemaChange[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The changes from `previous` to `next`, split into breaking and safe. `null` on either side means
|
|
25
|
+
* "no schema": nothing to compare, so the result is empty.
|
|
26
|
+
*/
|
|
27
|
+
export declare function diffSchemas(previous: unknown, next: unknown): SchemaDiff;
|
package/types/lib/schema.d.cts
CHANGED
|
@@ -13,6 +13,12 @@ export interface JsonSchema {
|
|
|
13
13
|
additionalProperties?: boolean;
|
|
14
14
|
}
|
|
15
15
|
export declare function inferSchema(sample: unknown): JsonSchema;
|
|
16
|
+
/**
|
|
17
|
+
* One schema over several data sets (spec 19 §2.5): a field is required only when every set has
|
|
18
|
+
* it, the way array elements are merged. The editor's "Store as contract" uses it, so a field that
|
|
19
|
+
* only one data set carries becomes optional.
|
|
20
|
+
*/
|
|
21
|
+
export declare function inferSchemaFromDataSets(samples: unknown[]): JsonSchema;
|
|
16
22
|
/** Flat list of dotted paths with their types, for completion items in the editor. */
|
|
17
23
|
export declare function schemaPaths(schema: JsonSchema, prefix?: string[]): Array<{
|
|
18
24
|
path: string[];
|
|
@@ -20,3 +26,5 @@ export declare function schemaPaths(schema: JsonSchema, prefix?: string[]): Arra
|
|
|
20
26
|
format?: string;
|
|
21
27
|
example?: unknown;
|
|
22
28
|
}>;
|
|
29
|
+
export { diffSchemas } from './schema-diff.cjs';
|
|
30
|
+
export type { SchemaChange, SchemaChangeKind, SchemaDiff } from './schema-diff.cjs';
|
package/types/lib/schema.d.ts
CHANGED
|
@@ -13,6 +13,12 @@ export interface JsonSchema {
|
|
|
13
13
|
additionalProperties?: boolean;
|
|
14
14
|
}
|
|
15
15
|
export declare function inferSchema(sample: unknown): JsonSchema;
|
|
16
|
+
/**
|
|
17
|
+
* One schema over several data sets (spec 19 §2.5): a field is required only when every set has
|
|
18
|
+
* it, the way array elements are merged. The editor's "Store as contract" uses it, so a field that
|
|
19
|
+
* only one data set carries becomes optional.
|
|
20
|
+
*/
|
|
21
|
+
export declare function inferSchemaFromDataSets(samples: unknown[]): JsonSchema;
|
|
16
22
|
/** Flat list of dotted paths with their types, for completion items in the editor. */
|
|
17
23
|
export declare function schemaPaths(schema: JsonSchema, prefix?: string[]): Array<{
|
|
18
24
|
path: string[];
|
|
@@ -20,3 +26,5 @@ export declare function schemaPaths(schema: JsonSchema, prefix?: string[]): Arra
|
|
|
20
26
|
format?: string;
|
|
21
27
|
example?: unknown;
|
|
22
28
|
}>;
|
|
29
|
+
export { diffSchemas } from './schema-diff.js';
|
|
30
|
+
export type { SchemaChange, SchemaChangeKind, SchemaDiff } from './schema-diff.js';
|
package/types/lib/snippets.d.cts
CHANGED
|
@@ -3,20 +3,57 @@ import type { EngineId } from './types.cjs';
|
|
|
3
3
|
* Snippet library (spec 06 §2): building blocks in every engine's syntax with the sample data keys
|
|
4
4
|
* they expect, so inserting one also completes the data panel.
|
|
5
5
|
*/
|
|
6
|
+
export type SnippetGroup = 'letter' | 'invoice' | 'page' | 'report';
|
|
6
7
|
export interface Snippet {
|
|
7
8
|
id: string;
|
|
8
9
|
title: string;
|
|
9
10
|
description: string;
|
|
11
|
+
/** Where the library lists the block. */
|
|
12
|
+
group: SnippetGroup;
|
|
13
|
+
/** Document kinds the block makes sense in; absent means both (page breaks and footers are PDF only). */
|
|
14
|
+
kinds?: Array<'pdf' | 'image'>;
|
|
15
|
+
/**
|
|
16
|
+
* The document the block belongs in; absent means the template body. Header and footer blocks
|
|
17
|
+
* style themselves inline, because Chromium renders those templates without the page's CSS.
|
|
18
|
+
*/
|
|
19
|
+
target?: 'header' | 'footer';
|
|
10
20
|
/** Source per engine; `$0` marks the final cursor position (Monaco snippet syntax). */
|
|
11
21
|
source: Record<EngineId, string>;
|
|
12
22
|
/** Sample data merged (deep, without overwriting) into the template's sample data. */
|
|
13
23
|
sampleData?: Record<string, unknown>;
|
|
14
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* CSS whose rules are appended when the stylesheet lacks their selector (`mergeSnippetCss`).
|
|
26
|
+
* Colours and heading fonts read the brand kit's `--brand-*` variables with a neutral fallback.
|
|
27
|
+
*/
|
|
15
28
|
css?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Label texts per language for the `t` calls in `source`, merged into the template's dictionaries
|
|
31
|
+
* without overwriting (`mergeSnippetI18n`), so a German template gets German labels.
|
|
32
|
+
*/
|
|
33
|
+
i18n?: Record<string, Record<string, string>>;
|
|
16
34
|
}
|
|
17
35
|
export declare const snippets: Snippet[];
|
|
18
36
|
export declare function snippetsFor(engine: EngineId): Array<Snippet & {
|
|
19
37
|
code: string;
|
|
20
38
|
}>;
|
|
39
|
+
/** Snippet code without Monaco tab stops (`$0`, `$1`, `${1:default}` keeps its default), as it renders. */
|
|
40
|
+
export declare function snippetText(code: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* The line that includes a partial in the engine's syntax, the form the gateway's
|
|
43
|
+
* `sharedPartialsFor` recognises; `undefined` for a name that syntax cannot carry. Liquid uses
|
|
44
|
+
* `include`, because `render` hides the template's data from the partial.
|
|
45
|
+
*/
|
|
46
|
+
export declare function partialInclude(engine: EngineId, name: string): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Appends the rules of a snippet's CSS whose selector list the stylesheet does not have yet, so a
|
|
49
|
+
* template that already styles `.ff-lines` itself keeps that rule and still gets the others.
|
|
50
|
+
*/
|
|
51
|
+
export declare function mergeSnippetCss(css: string, snippetCss: string | undefined): string;
|
|
52
|
+
/**
|
|
53
|
+
* Adds a snippet's label texts to the template's dictionaries without overwriting a key: English
|
|
54
|
+
* always (the `t` helper's last fallback), plus every language the template renders in or already
|
|
55
|
+
* has a dictionary for. A `de-DE` dictionary gets its keys through `de`, which `t` reads next.
|
|
56
|
+
*/
|
|
57
|
+
export declare function mergeSnippetI18n(dictionaries: unknown, extra: Snippet['i18n'], locale: string): unknown;
|
|
21
58
|
/** Deep merge that keeps existing values; arrays are taken from the base when present. */
|
|
22
59
|
export declare function mergeSampleData(base: unknown, extra: Record<string, unknown> | undefined): unknown;
|
package/types/lib/snippets.d.ts
CHANGED
|
@@ -3,20 +3,57 @@ import type { EngineId } from './types.js';
|
|
|
3
3
|
* Snippet library (spec 06 §2): building blocks in every engine's syntax with the sample data keys
|
|
4
4
|
* they expect, so inserting one also completes the data panel.
|
|
5
5
|
*/
|
|
6
|
+
export type SnippetGroup = 'letter' | 'invoice' | 'page' | 'report';
|
|
6
7
|
export interface Snippet {
|
|
7
8
|
id: string;
|
|
8
9
|
title: string;
|
|
9
10
|
description: string;
|
|
11
|
+
/** Where the library lists the block. */
|
|
12
|
+
group: SnippetGroup;
|
|
13
|
+
/** Document kinds the block makes sense in; absent means both (page breaks and footers are PDF only). */
|
|
14
|
+
kinds?: Array<'pdf' | 'image'>;
|
|
15
|
+
/**
|
|
16
|
+
* The document the block belongs in; absent means the template body. Header and footer blocks
|
|
17
|
+
* style themselves inline, because Chromium renders those templates without the page's CSS.
|
|
18
|
+
*/
|
|
19
|
+
target?: 'header' | 'footer';
|
|
10
20
|
/** Source per engine; `$0` marks the final cursor position (Monaco snippet syntax). */
|
|
11
21
|
source: Record<EngineId, string>;
|
|
12
22
|
/** Sample data merged (deep, without overwriting) into the template's sample data. */
|
|
13
23
|
sampleData?: Record<string, unknown>;
|
|
14
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* CSS whose rules are appended when the stylesheet lacks their selector (`mergeSnippetCss`).
|
|
26
|
+
* Colours and heading fonts read the brand kit's `--brand-*` variables with a neutral fallback.
|
|
27
|
+
*/
|
|
15
28
|
css?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Label texts per language for the `t` calls in `source`, merged into the template's dictionaries
|
|
31
|
+
* without overwriting (`mergeSnippetI18n`), so a German template gets German labels.
|
|
32
|
+
*/
|
|
33
|
+
i18n?: Record<string, Record<string, string>>;
|
|
16
34
|
}
|
|
17
35
|
export declare const snippets: Snippet[];
|
|
18
36
|
export declare function snippetsFor(engine: EngineId): Array<Snippet & {
|
|
19
37
|
code: string;
|
|
20
38
|
}>;
|
|
39
|
+
/** Snippet code without Monaco tab stops (`$0`, `$1`, `${1:default}` keeps its default), as it renders. */
|
|
40
|
+
export declare function snippetText(code: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* The line that includes a partial in the engine's syntax, the form the gateway's
|
|
43
|
+
* `sharedPartialsFor` recognises; `undefined` for a name that syntax cannot carry. Liquid uses
|
|
44
|
+
* `include`, because `render` hides the template's data from the partial.
|
|
45
|
+
*/
|
|
46
|
+
export declare function partialInclude(engine: EngineId, name: string): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Appends the rules of a snippet's CSS whose selector list the stylesheet does not have yet, so a
|
|
49
|
+
* template that already styles `.ff-lines` itself keeps that rule and still gets the others.
|
|
50
|
+
*/
|
|
51
|
+
export declare function mergeSnippetCss(css: string, snippetCss: string | undefined): string;
|
|
52
|
+
/**
|
|
53
|
+
* Adds a snippet's label texts to the template's dictionaries without overwriting a key: English
|
|
54
|
+
* always (the `t` helper's last fallback), plus every language the template renders in or already
|
|
55
|
+
* has a dictionary for. A `de-DE` dictionary gets its keys through `de`, which `t` reads next.
|
|
56
|
+
*/
|
|
57
|
+
export declare function mergeSnippetI18n(dictionaries: unknown, extra: Snippet['i18n'], locale: string): unknown;
|
|
21
58
|
/** Deep merge that keeps existing values; arrays are taken from the base when present. */
|
|
22
59
|
export declare function mergeSampleData(base: unknown, extra: Record<string, unknown> | undefined): unknown;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EngineId } from './types.cjs';
|
|
2
|
+
/**
|
|
3
|
+
* Click-to-source for the editor's previews (spec 06 §3): every HTML start tag written literally in
|
|
4
|
+
* the template source gets `data-ff-src="<file>:<line>:<column>"` right after its tag name, so the
|
|
5
|
+
* rendered element says where it came from instead of the editor searching the template for it.
|
|
6
|
+
* Elements from a loop all point at the loop body, which is the line that wrote them.
|
|
7
|
+
*
|
|
8
|
+
* The annotation must never change what the template means: tags inside template syntax, in
|
|
9
|
+
* blocks whose output is captured or filtered as a string (`{% set %}…{% endset %}`, `{% filter %}`,
|
|
10
|
+
* `{% capture %}`), in raw and comment blocks, in `<script>`/`<style>`/`<textarea>`/`<title>` and
|
|
11
|
+
* HTML comments, closing tags, declarations, tags whose name is built by template syntax and tags
|
|
12
|
+
* that already carry the attribute stay untouched. Removing the attribute from the rendered output
|
|
13
|
+
* gives the document of the original source. Preview only: saved versions, API renders and the
|
|
14
|
+
* render-worker never see it.
|
|
15
|
+
*/
|
|
16
|
+
export type SourceFile = 'body' | 'header' | 'footer';
|
|
17
|
+
export declare const sourceAttribute = "data-ff-src";
|
|
18
|
+
export interface SourceLocation {
|
|
19
|
+
file: SourceFile;
|
|
20
|
+
/** 1-based, as Monaco counts. */
|
|
21
|
+
line: number;
|
|
22
|
+
/** 1-based UTF-16 column of the tag's `<`. */
|
|
23
|
+
column: number;
|
|
24
|
+
}
|
|
25
|
+
/** Parses a `data-ff-src` value; null when it is not one. */
|
|
26
|
+
export declare function parseSourceAttribute(value: string | null | undefined): SourceLocation | null;
|
|
27
|
+
export declare function annotateSourcePositions(source: string, engine: EngineId, file: SourceFile): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EngineId } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Click-to-source for the editor's previews (spec 06 §3): every HTML start tag written literally in
|
|
4
|
+
* the template source gets `data-ff-src="<file>:<line>:<column>"` right after its tag name, so the
|
|
5
|
+
* rendered element says where it came from instead of the editor searching the template for it.
|
|
6
|
+
* Elements from a loop all point at the loop body, which is the line that wrote them.
|
|
7
|
+
*
|
|
8
|
+
* The annotation must never change what the template means: tags inside template syntax, in
|
|
9
|
+
* blocks whose output is captured or filtered as a string (`{% set %}…{% endset %}`, `{% filter %}`,
|
|
10
|
+
* `{% capture %}`), in raw and comment blocks, in `<script>`/`<style>`/`<textarea>`/`<title>` and
|
|
11
|
+
* HTML comments, closing tags, declarations, tags whose name is built by template syntax and tags
|
|
12
|
+
* that already carry the attribute stay untouched. Removing the attribute from the rendered output
|
|
13
|
+
* gives the document of the original source. Preview only: saved versions, API renders and the
|
|
14
|
+
* render-worker never see it.
|
|
15
|
+
*/
|
|
16
|
+
export type SourceFile = 'body' | 'header' | 'footer';
|
|
17
|
+
export declare const sourceAttribute = "data-ff-src";
|
|
18
|
+
export interface SourceLocation {
|
|
19
|
+
file: SourceFile;
|
|
20
|
+
/** 1-based, as Monaco counts. */
|
|
21
|
+
line: number;
|
|
22
|
+
/** 1-based UTF-16 column of the tag's `<`. */
|
|
23
|
+
column: number;
|
|
24
|
+
}
|
|
25
|
+
/** Parses a `data-ff-src` value; null when it is not one. */
|
|
26
|
+
export declare function parseSourceAttribute(value: string | null | undefined): SourceLocation | null;
|
|
27
|
+
export declare function annotateSourcePositions(source: string, engine: EngineId, file: SourceFile): string;
|
package/types/lib/types.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BrandContext } from './brand.cjs';
|
|
1
2
|
/**
|
|
2
3
|
* Shared contracts of `@formfeed/engine` (spec 05). Used by the Angular editor (browser) and the
|
|
3
4
|
* Fly.io render-worker (Node); nothing here may touch Node-only APIs.
|
|
@@ -84,6 +85,18 @@ export interface RenderContext {
|
|
|
84
85
|
i18n?: Record<string, Record<string, string>>;
|
|
85
86
|
/** Base URL for `asset()` (workspace asset root on the CDN). */
|
|
86
87
|
assetBaseUrl?: string;
|
|
88
|
+
/**
|
|
89
|
+
* The organisation's brand kit (spec 18): the template global `brand` (request data of the same
|
|
90
|
+
* name wins) and the `--brand-*` variables the assembler injects.
|
|
91
|
+
*/
|
|
92
|
+
brand?: BrandContext;
|
|
93
|
+
/**
|
|
94
|
+
* `office` renders the text of an office part (spec 22 §4.3): the engines do not escape, because the
|
|
95
|
+
* text is escaped as a whole when the markup is restored (`office/template-text.ts`). HTML by default.
|
|
96
|
+
*/
|
|
97
|
+
mode?: 'html' | 'office';
|
|
98
|
+
/** Office mode, set by `renderOffice`: see `HelperContext.drawing`. */
|
|
99
|
+
drawing?: (request: OfficeDrawingRequest) => string;
|
|
87
100
|
}
|
|
88
101
|
export interface CompileOptions {
|
|
89
102
|
/** Name used in error messages and as the root include name. */
|
|
@@ -128,7 +141,30 @@ export interface HelperContext {
|
|
|
128
141
|
currency: string;
|
|
129
142
|
i18n?: Record<string, Record<string, string>>;
|
|
130
143
|
assetBaseUrl?: string;
|
|
131
|
-
|
|
144
|
+
/** `office` while an office template is filled (spec 22 §4.4); helpers that emit markup behave differently. */
|
|
145
|
+
mode?: 'html' | 'office';
|
|
146
|
+
/**
|
|
147
|
+
* Office mode: registers a drawing (a code, an image or a page break) and returns the placeholder
|
|
148
|
+
* the post pass turns into it. Set by `renderOffice`.
|
|
149
|
+
*/
|
|
150
|
+
drawing?: (request: OfficeDrawingRequest) => string;
|
|
151
|
+
}
|
|
152
|
+
/** What a helper asks the office post pass to place where its placeholder stands. */
|
|
153
|
+
export type OfficeDrawingRequest = {
|
|
154
|
+
kind: 'svg';
|
|
155
|
+
svg: string;
|
|
156
|
+
width?: number | string;
|
|
157
|
+
height?: number | string;
|
|
158
|
+
alt?: string;
|
|
159
|
+
} | {
|
|
160
|
+
kind: 'url';
|
|
161
|
+
url: string;
|
|
162
|
+
width?: number | string;
|
|
163
|
+
height?: number | string;
|
|
164
|
+
alt?: string;
|
|
165
|
+
} | {
|
|
166
|
+
kind: 'page-break';
|
|
167
|
+
};
|
|
132
168
|
export interface HelperRegistry {
|
|
133
169
|
/** Registered helpers keyed by canonical name. */
|
|
134
170
|
readonly definitions: ReadonlyMap<string, HelperDefinition>;
|
package/types/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BrandContext } from './brand.js';
|
|
1
2
|
/**
|
|
2
3
|
* Shared contracts of `@formfeed/engine` (spec 05). Used by the Angular editor (browser) and the
|
|
3
4
|
* Fly.io render-worker (Node); nothing here may touch Node-only APIs.
|
|
@@ -84,6 +85,18 @@ export interface RenderContext {
|
|
|
84
85
|
i18n?: Record<string, Record<string, string>>;
|
|
85
86
|
/** Base URL for `asset()` (workspace asset root on the CDN). */
|
|
86
87
|
assetBaseUrl?: string;
|
|
88
|
+
/**
|
|
89
|
+
* The organisation's brand kit (spec 18): the template global `brand` (request data of the same
|
|
90
|
+
* name wins) and the `--brand-*` variables the assembler injects.
|
|
91
|
+
*/
|
|
92
|
+
brand?: BrandContext;
|
|
93
|
+
/**
|
|
94
|
+
* `office` renders the text of an office part (spec 22 §4.3): the engines do not escape, because the
|
|
95
|
+
* text is escaped as a whole when the markup is restored (`office/template-text.ts`). HTML by default.
|
|
96
|
+
*/
|
|
97
|
+
mode?: 'html' | 'office';
|
|
98
|
+
/** Office mode, set by `renderOffice`: see `HelperContext.drawing`. */
|
|
99
|
+
drawing?: (request: OfficeDrawingRequest) => string;
|
|
87
100
|
}
|
|
88
101
|
export interface CompileOptions {
|
|
89
102
|
/** Name used in error messages and as the root include name. */
|
|
@@ -128,7 +141,30 @@ export interface HelperContext {
|
|
|
128
141
|
currency: string;
|
|
129
142
|
i18n?: Record<string, Record<string, string>>;
|
|
130
143
|
assetBaseUrl?: string;
|
|
131
|
-
|
|
144
|
+
/** `office` while an office template is filled (spec 22 §4.4); helpers that emit markup behave differently. */
|
|
145
|
+
mode?: 'html' | 'office';
|
|
146
|
+
/**
|
|
147
|
+
* Office mode: registers a drawing (a code, an image or a page break) and returns the placeholder
|
|
148
|
+
* the post pass turns into it. Set by `renderOffice`.
|
|
149
|
+
*/
|
|
150
|
+
drawing?: (request: OfficeDrawingRequest) => string;
|
|
151
|
+
}
|
|
152
|
+
/** What a helper asks the office post pass to place where its placeholder stands. */
|
|
153
|
+
export type OfficeDrawingRequest = {
|
|
154
|
+
kind: 'svg';
|
|
155
|
+
svg: string;
|
|
156
|
+
width?: number | string;
|
|
157
|
+
height?: number | string;
|
|
158
|
+
alt?: string;
|
|
159
|
+
} | {
|
|
160
|
+
kind: 'url';
|
|
161
|
+
url: string;
|
|
162
|
+
width?: number | string;
|
|
163
|
+
height?: number | string;
|
|
164
|
+
alt?: string;
|
|
165
|
+
} | {
|
|
166
|
+
kind: 'page-break';
|
|
167
|
+
};
|
|
132
168
|
export interface HelperRegistry {
|
|
133
169
|
/** Registered helpers keyed by canonical name. */
|
|
134
170
|
readonly definitions: ReadonlyMap<string, HelperDefinition>;
|