@formfeed/engine 0.1.0 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formfeed/engine",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "The Formfeed template engine (Jinja2, Liquid, Handlebars) for the browser and Node.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/types/index.d.cts CHANGED
@@ -6,7 +6,13 @@ export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, ge
6
6
  export { inferSchema, schemaPaths } from './lib/schema.cjs';
7
7
  export { mergeSampleData, snippets, snippetsFor } from './lib/snippets.cjs';
8
8
  export { importApitemplate, slugFromName } from './lib/import/apitemplate.cjs';
9
- export type { ApitemplateExport, ImportNote, ImportResult, } from './lib/import/apitemplate.cjs';
9
+ export type { ApitemplateExport } from './lib/import/apitemplate.cjs';
10
+ export type { ImportNote, ImportResult, ImportSource } from './lib/import/common.cjs';
11
+ export { importPdfmonkey, strftimeToDateFns } from './lib/import/pdfmonkey.cjs';
12
+ export type { PdfmonkeyImportOptions, PdfmonkeySettings, PdfmonkeyTemplate } from './lib/import/pdfmonkey.cjs';
13
+ export { importJsreport, jsreportTemplates, readJsreportExport } from './lib/import/jsreport.cjs';
14
+ export type { JsreportBundle, JsreportImportOptions, JsreportTemplate } from './lib/import/jsreport.cjs';
15
+ export { convertScss, isScss } from './lib/import/scss.cjs';
10
16
  export type { Snippet } from './lib/snippets.cjs';
11
17
  export type { JsonSchema } from './lib/schema.cjs';
12
18
  export { assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.cjs';
package/types/index.d.ts CHANGED
@@ -6,7 +6,13 @@ export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, ge
6
6
  export { inferSchema, schemaPaths } from './lib/schema.js';
7
7
  export { mergeSampleData, snippets, snippetsFor } from './lib/snippets.js';
8
8
  export { importApitemplate, slugFromName } from './lib/import/apitemplate.js';
9
- export type { ApitemplateExport, ImportNote, ImportResult, } from './lib/import/apitemplate.js';
9
+ export type { ApitemplateExport } from './lib/import/apitemplate.js';
10
+ export type { ImportNote, ImportResult, ImportSource } from './lib/import/common.js';
11
+ export { importPdfmonkey, strftimeToDateFns } from './lib/import/pdfmonkey.js';
12
+ export type { PdfmonkeyImportOptions, PdfmonkeySettings, PdfmonkeyTemplate } from './lib/import/pdfmonkey.js';
13
+ export { importJsreport, jsreportTemplates, readJsreportExport } from './lib/import/jsreport.js';
14
+ export type { JsreportBundle, JsreportImportOptions, JsreportTemplate } from './lib/import/jsreport.js';
15
+ export { convertScss, isScss } from './lib/import/scss.js';
10
16
  export type { Snippet } from './lib/snippets.js';
11
17
  export type { JsonSchema } from './lib/schema.js';
12
18
  export { assembleDocument, chartInitScript, defaultSettings, fontFaceCss, mergeSettings, pageSize, printReset, renderVersion, } from './lib/assemble.js';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Python's `str.format` for the Jinja2 engine (spec 05 §8): templates from apitemplate.io format
3
+ * numbers with it, e.g. `"{:,.2f}".format(total)`, including nested fields in the spec
4
+ * (`"{:,.{}f}".format(value, places)`). Covers positional, numbered and named fields, attribute
5
+ * lookups (`{0.name}`), `{{`/`}}` escapes and the format mini-language: fill and alignment, sign,
6
+ * `#`, zero padding, width, `,`/`_` grouping, precision and the types `s d n b o x X e E f F g G %`.
7
+ */
8
+ /** Formats one value with a format spec (the part after `:`). */
9
+ export declare function formatValue(value: unknown, spec: string): string;
10
+ /**
11
+ * `template.format(*positional, **named)`. Unknown fields format as empty text instead of raising,
12
+ * because a template should render rather than fail on a missing value.
13
+ */
14
+ export declare function pythonFormat(template: string, positional: unknown[], named?: Record<string, unknown>): string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Python's `str.format` for the Jinja2 engine (spec 05 §8): templates from apitemplate.io format
3
+ * numbers with it, e.g. `"{:,.2f}".format(total)`, including nested fields in the spec
4
+ * (`"{:,.{}f}".format(value, places)`). Covers positional, numbered and named fields, attribute
5
+ * lookups (`{0.name}`), `{{`/`}}` escapes and the format mini-language: fill and alignment, sign,
6
+ * `#`, zero padding, width, `,`/`_` grouping, precision and the types `s d n b o x X e E f F g G %`.
7
+ */
8
+ /** Formats one value with a format spec (the part after `:`). */
9
+ export declare function formatValue(value: unknown, spec: string): string;
10
+ /**
11
+ * `template.format(*positional, **named)`. Unknown fields format as empty text instead of raising,
12
+ * because a template should render rather than fail on a missing value.
13
+ */
14
+ export declare function pythonFormat(template: string, positional: unknown[], named?: Record<string, unknown>): string;
@@ -1,4 +1,6 @@
1
- import type { TemplateSettings } from '../assemble.cjs';
1
+ import { type ImportResult } from './common.cjs';
2
+ export { slugFromName } from './common.cjs';
3
+ export type { ImportNote, ImportResult } from './common.cjs';
2
4
  /**
3
5
  * apitemplate.io importer (spec 10 §4, spec 05 §8): turns an exported template (HTML body, CSS,
4
6
  * settings, sample JSON) into a Formfeed draft and a report of what needs attention. The Jinja2
@@ -16,30 +18,4 @@ export interface ApitemplateExport {
16
18
  /** Their template format; JPEG and PNG become image templates. */
17
19
  format?: string | null;
18
20
  }
19
- export interface ImportNote {
20
- code: string;
21
- message: string;
22
- line?: number;
23
- column?: number;
24
- /** Path under docs.formfeed.dev with the details. */
25
- docs?: string;
26
- }
27
- export interface ImportResult {
28
- name: string;
29
- slug: string;
30
- kind: 'pdf' | 'image';
31
- engine: 'jinja2';
32
- html: string;
33
- css: string;
34
- head: string;
35
- settings: TemplateSettings;
36
- sampleData: unknown;
37
- /** Compile or analysis errors: the draft is created, but it will not render as is. */
38
- errors: ImportNote[];
39
- /** Unknown filters, unsupported Python constructs, ignored settings. */
40
- warnings: ImportNote[];
41
- /** What the importer changed or mapped. */
42
- changes: string[];
43
- }
44
- export declare function slugFromName(name: string): string;
45
21
  export declare function importApitemplate(input: ApitemplateExport): ImportResult;
@@ -1,4 +1,6 @@
1
- import type { TemplateSettings } from '../assemble.js';
1
+ import { type ImportResult } from './common.js';
2
+ export { slugFromName } from './common.js';
3
+ export type { ImportNote, ImportResult } from './common.js';
2
4
  /**
3
5
  * apitemplate.io importer (spec 10 §4, spec 05 §8): turns an exported template (HTML body, CSS,
4
6
  * settings, sample JSON) into a Formfeed draft and a report of what needs attention. The Jinja2
@@ -16,30 +18,4 @@ export interface ApitemplateExport {
16
18
  /** Their template format; JPEG and PNG become image templates. */
17
19
  format?: string | null;
18
20
  }
19
- export interface ImportNote {
20
- code: string;
21
- message: string;
22
- line?: number;
23
- column?: number;
24
- /** Path under docs.formfeed.dev with the details. */
25
- docs?: string;
26
- }
27
- export interface ImportResult {
28
- name: string;
29
- slug: string;
30
- kind: 'pdf' | 'image';
31
- engine: 'jinja2';
32
- html: string;
33
- css: string;
34
- head: string;
35
- settings: TemplateSettings;
36
- sampleData: unknown;
37
- /** Compile or analysis errors: the draft is created, but it will not render as is. */
38
- errors: ImportNote[];
39
- /** Unknown filters, unsupported Python constructs, ignored settings. */
40
- warnings: ImportNote[];
41
- /** What the importer changed or mapped. */
42
- changes: string[];
43
- }
44
- export declare function slugFromName(name: string): string;
45
21
  export declare function importApitemplate(input: ApitemplateExport): ImportResult;
@@ -0,0 +1,67 @@
1
+ import type { TemplateSettings } from '../assemble.cjs';
2
+ import type { EngineId } from '../types.cjs';
3
+ /**
4
+ * What every importer shares (spec 10 §4): the result shape the app and the CLI turn into a draft,
5
+ * the notes of the report, and the final check that compiles and analyses the converted template
6
+ * against its sample data, so the report shows exactly what the editor would.
7
+ */
8
+ export type ImportSource = 'apitemplate' | 'pdfmonkey' | 'jsreport';
9
+ export interface ImportNote {
10
+ code: string;
11
+ message: string;
12
+ line?: number;
13
+ column?: number;
14
+ /** Path under docs.formfeed.dev with the details. */
15
+ docs?: string;
16
+ }
17
+ export interface ImportResult {
18
+ source: ImportSource;
19
+ name: string;
20
+ slug: string;
21
+ kind: 'pdf' | 'image';
22
+ engine: EngineId;
23
+ html: string;
24
+ css: string;
25
+ head: string;
26
+ settings: TemplateSettings;
27
+ sampleData: unknown;
28
+ /** Compile or analysis errors: the draft is created, but it will not render as is. */
29
+ errors: ImportNote[];
30
+ /** Unknown filters, unsupported constructs, ignored settings. */
31
+ warnings: ImportNote[];
32
+ /** What the importer changed or mapped. */
33
+ changes: string[];
34
+ }
35
+ export declare function slugFromName(name: string): string;
36
+ export declare function parseSample(value: unknown): {
37
+ data: unknown;
38
+ error?: string;
39
+ };
40
+ export declare function positionOf(source: string, index: number): {
41
+ line: number;
42
+ column: number;
43
+ };
44
+ /** Every match of `pattern` in `source` as a note with its position. */
45
+ export declare function notesFor(source: string, pattern: RegExp, note: Omit<ImportNote, 'line' | 'column'>, { once }?: {
46
+ once?: boolean;
47
+ }): ImportNote[];
48
+ /** Docs pages the generic diagnostics point at, per importer. */
49
+ export interface CheckDocs {
50
+ syntax: string;
51
+ filters: string;
52
+ sampleData: string;
53
+ }
54
+ /**
55
+ * Compiles and analyses the converted template with the engine it will run on. Errors stop the
56
+ * render (the draft is still created); everything else is a warning. Duplicates of one error at
57
+ * the same line are dropped, since compile and analyse often report the same syntax error.
58
+ */
59
+ export declare function checkTemplate(engineId: EngineId, html: string, sampleData: unknown, name: string, docs: CheckDocs): {
60
+ errors: ImportNote[];
61
+ warnings: ImportNote[];
62
+ };
63
+ /** `210`, `210mm`, `8.5in` → a CSS length; bare numbers are millimetres. */
64
+ export declare function lengthMm(value: unknown): string | undefined;
65
+ /** A binary value as base64: a base64 string, a serialised Node Buffer, or a byte array. */
66
+ export declare function toBase64(value: unknown): string | undefined;
67
+ export declare function mimeOf(name: string): string;
@@ -0,0 +1,67 @@
1
+ import type { TemplateSettings } from '../assemble.js';
2
+ import type { EngineId } from '../types.js';
3
+ /**
4
+ * What every importer shares (spec 10 §4): the result shape the app and the CLI turn into a draft,
5
+ * the notes of the report, and the final check that compiles and analyses the converted template
6
+ * against its sample data, so the report shows exactly what the editor would.
7
+ */
8
+ export type ImportSource = 'apitemplate' | 'pdfmonkey' | 'jsreport';
9
+ export interface ImportNote {
10
+ code: string;
11
+ message: string;
12
+ line?: number;
13
+ column?: number;
14
+ /** Path under docs.formfeed.dev with the details. */
15
+ docs?: string;
16
+ }
17
+ export interface ImportResult {
18
+ source: ImportSource;
19
+ name: string;
20
+ slug: string;
21
+ kind: 'pdf' | 'image';
22
+ engine: EngineId;
23
+ html: string;
24
+ css: string;
25
+ head: string;
26
+ settings: TemplateSettings;
27
+ sampleData: unknown;
28
+ /** Compile or analysis errors: the draft is created, but it will not render as is. */
29
+ errors: ImportNote[];
30
+ /** Unknown filters, unsupported constructs, ignored settings. */
31
+ warnings: ImportNote[];
32
+ /** What the importer changed or mapped. */
33
+ changes: string[];
34
+ }
35
+ export declare function slugFromName(name: string): string;
36
+ export declare function parseSample(value: unknown): {
37
+ data: unknown;
38
+ error?: string;
39
+ };
40
+ export declare function positionOf(source: string, index: number): {
41
+ line: number;
42
+ column: number;
43
+ };
44
+ /** Every match of `pattern` in `source` as a note with its position. */
45
+ export declare function notesFor(source: string, pattern: RegExp, note: Omit<ImportNote, 'line' | 'column'>, { once }?: {
46
+ once?: boolean;
47
+ }): ImportNote[];
48
+ /** Docs pages the generic diagnostics point at, per importer. */
49
+ export interface CheckDocs {
50
+ syntax: string;
51
+ filters: string;
52
+ sampleData: string;
53
+ }
54
+ /**
55
+ * Compiles and analyses the converted template with the engine it will run on. Errors stop the
56
+ * render (the draft is still created); everything else is a warning. Duplicates of one error at
57
+ * the same line are dropped, since compile and analyse often report the same syntax error.
58
+ */
59
+ export declare function checkTemplate(engineId: EngineId, html: string, sampleData: unknown, name: string, docs: CheckDocs): {
60
+ errors: ImportNote[];
61
+ warnings: ImportNote[];
62
+ };
63
+ /** `210`, `210mm`, `8.5in` → a CSS length; bare numbers are millimetres. */
64
+ export declare function lengthMm(value: unknown): string | undefined;
65
+ /** A binary value as base64: a base64 string, a serialised Node Buffer, or a byte array. */
66
+ export declare function toBase64(value: unknown): string | undefined;
67
+ export declare function mimeOf(name: string): string;
@@ -0,0 +1,90 @@
1
+ import { type ImportResult } from './common.cjs';
2
+ /**
3
+ * jsreport importer (spec 10 §4). jsreport is the open-source report server many teams run
4
+ * themselves; its export (`.jsrexport`, a zip with one JSON file per entity) carries templates,
5
+ * sample data, assets, components and scripts. Templates with the Handlebars engine and the
6
+ * chrome-pdf or chrome-image recipe map almost one to one onto Formfeed: the header and footer are
7
+ * Chromium header templates in both, and the chrome options are Formfeed's settings.
8
+ *
9
+ * - `{{asset}}` calls are resolved from the export: small files become data URIs or inline text.
10
+ * A larger one keeps its `{{asset}}` call and a warning: the helper resolves against the
11
+ * workspace file library, so the file has to be uploaded there under the same name.
12
+ * - Child templates and components are inlined (stored partials do not take part in API renders).
13
+ * - Custom helpers are JavaScript, which Formfeed does not run: each one is reported, and the
14
+ * engine's analysis marks every call to it.
15
+ * - jsrender, EJS and Pug templates, scripts, pdf-utils operations and non-PDF recipes are reported.
16
+ *
17
+ * The caller unzips the export (`readJsreportExport` takes the file map), so the engine stays free
18
+ * of a zip library.
19
+ */
20
+ export interface JsreportEntity {
21
+ _id?: string;
22
+ shortid?: string;
23
+ name?: string;
24
+ folder?: {
25
+ shortid?: string;
26
+ } | null;
27
+ [key: string]: unknown;
28
+ }
29
+ export interface JsreportTemplate extends JsreportEntity {
30
+ content?: string;
31
+ engine?: string;
32
+ recipe?: string;
33
+ helpers?: string;
34
+ chrome?: Record<string, unknown> | null;
35
+ chromeImage?: Record<string, unknown> | null;
36
+ data?: {
37
+ shortid?: string;
38
+ } | null;
39
+ scripts?: Array<{
40
+ shortid?: string;
41
+ }> | null;
42
+ pdfOperations?: unknown[] | null;
43
+ pdfMeta?: Record<string, unknown> | null;
44
+ pdfPassword?: Record<string, unknown> | null;
45
+ localization?: {
46
+ language?: string;
47
+ } | null;
48
+ }
49
+ export interface JsreportBundle {
50
+ templates: JsreportTemplate[];
51
+ data: Array<JsreportEntity & {
52
+ dataJson?: string;
53
+ }>;
54
+ assets: Array<JsreportEntity & {
55
+ content?: unknown;
56
+ link?: string;
57
+ isSharedHelper?: boolean;
58
+ }>;
59
+ components: Array<JsreportEntity & {
60
+ content?: string;
61
+ helpers?: string;
62
+ engine?: string;
63
+ }>;
64
+ scripts: Array<JsreportEntity & {
65
+ content?: string;
66
+ }>;
67
+ folders: JsreportEntity[];
68
+ /** jsreport version from metadata.json. */
69
+ version?: string;
70
+ }
71
+ export interface JsreportImportOptions {
72
+ /** Assets up to this size are inlined as data URIs (default 256 KB); larger ones become `{{asset}}`. */
73
+ inlineAssetBytes?: number;
74
+ }
75
+ /**
76
+ * The entities of an unzipped `.jsrexport`: file path → file text. Entity files are
77
+ * `<collection>/<name>-<id>.json`; everything else (metadata, versions, settings) is ignored.
78
+ */
79
+ export declare function readJsreportExport(files: Record<string, string>): JsreportBundle;
80
+ /** The templates of an export for a picker: name, folder path, engine and recipe. */
81
+ export declare function jsreportTemplates(bundle: JsreportBundle): Array<{
82
+ ref: string;
83
+ name: string;
84
+ path: string;
85
+ engine: string;
86
+ recipe: string;
87
+ }>;
88
+ /** Names of the functions a jsreport helpers script defines. */
89
+ export declare function helperNames(script: string): string[];
90
+ export declare function importJsreport(bundle: JsreportBundle, ref: string, options?: JsreportImportOptions): ImportResult;
@@ -0,0 +1,90 @@
1
+ import { type ImportResult } from './common.js';
2
+ /**
3
+ * jsreport importer (spec 10 §4). jsreport is the open-source report server many teams run
4
+ * themselves; its export (`.jsrexport`, a zip with one JSON file per entity) carries templates,
5
+ * sample data, assets, components and scripts. Templates with the Handlebars engine and the
6
+ * chrome-pdf or chrome-image recipe map almost one to one onto Formfeed: the header and footer are
7
+ * Chromium header templates in both, and the chrome options are Formfeed's settings.
8
+ *
9
+ * - `{{asset}}` calls are resolved from the export: small files become data URIs or inline text.
10
+ * A larger one keeps its `{{asset}}` call and a warning: the helper resolves against the
11
+ * workspace file library, so the file has to be uploaded there under the same name.
12
+ * - Child templates and components are inlined (stored partials do not take part in API renders).
13
+ * - Custom helpers are JavaScript, which Formfeed does not run: each one is reported, and the
14
+ * engine's analysis marks every call to it.
15
+ * - jsrender, EJS and Pug templates, scripts, pdf-utils operations and non-PDF recipes are reported.
16
+ *
17
+ * The caller unzips the export (`readJsreportExport` takes the file map), so the engine stays free
18
+ * of a zip library.
19
+ */
20
+ export interface JsreportEntity {
21
+ _id?: string;
22
+ shortid?: string;
23
+ name?: string;
24
+ folder?: {
25
+ shortid?: string;
26
+ } | null;
27
+ [key: string]: unknown;
28
+ }
29
+ export interface JsreportTemplate extends JsreportEntity {
30
+ content?: string;
31
+ engine?: string;
32
+ recipe?: string;
33
+ helpers?: string;
34
+ chrome?: Record<string, unknown> | null;
35
+ chromeImage?: Record<string, unknown> | null;
36
+ data?: {
37
+ shortid?: string;
38
+ } | null;
39
+ scripts?: Array<{
40
+ shortid?: string;
41
+ }> | null;
42
+ pdfOperations?: unknown[] | null;
43
+ pdfMeta?: Record<string, unknown> | null;
44
+ pdfPassword?: Record<string, unknown> | null;
45
+ localization?: {
46
+ language?: string;
47
+ } | null;
48
+ }
49
+ export interface JsreportBundle {
50
+ templates: JsreportTemplate[];
51
+ data: Array<JsreportEntity & {
52
+ dataJson?: string;
53
+ }>;
54
+ assets: Array<JsreportEntity & {
55
+ content?: unknown;
56
+ link?: string;
57
+ isSharedHelper?: boolean;
58
+ }>;
59
+ components: Array<JsreportEntity & {
60
+ content?: string;
61
+ helpers?: string;
62
+ engine?: string;
63
+ }>;
64
+ scripts: Array<JsreportEntity & {
65
+ content?: string;
66
+ }>;
67
+ folders: JsreportEntity[];
68
+ /** jsreport version from metadata.json. */
69
+ version?: string;
70
+ }
71
+ export interface JsreportImportOptions {
72
+ /** Assets up to this size are inlined as data URIs (default 256 KB); larger ones become `{{asset}}`. */
73
+ inlineAssetBytes?: number;
74
+ }
75
+ /**
76
+ * The entities of an unzipped `.jsrexport`: file path → file text. Entity files are
77
+ * `<collection>/<name>-<id>.json`; everything else (metadata, versions, settings) is ignored.
78
+ */
79
+ export declare function readJsreportExport(files: Record<string, string>): JsreportBundle;
80
+ /** The templates of an export for a picker: name, folder path, engine and recipe. */
81
+ export declare function jsreportTemplates(bundle: JsreportBundle): Array<{
82
+ ref: string;
83
+ name: string;
84
+ path: string;
85
+ engine: string;
86
+ recipe: string;
87
+ }>;
88
+ /** Names of the functions a jsreport helpers script defines. */
89
+ export declare function helperNames(script: string): string[];
90
+ export declare function importJsreport(bundle: JsreportBundle, ref: string, options?: JsreportImportOptions): ImportResult;
@@ -0,0 +1,77 @@
1
+ import { type ImportResult } from './common.cjs';
2
+ /**
3
+ * PDFMonkey importer (spec 10 §4). A PDFMonkey code template is HTML with Ruby Liquid 4, a CSS or
4
+ * SCSS stylesheet, sample data as a JSON string and settings, all returned by
5
+ * `GET /api/v1/document_templates/{id}`. Formfeed's Liquid engine is LiquidJS with the shared
6
+ * helpers, so the converter rewrites what differs:
7
+ *
8
+ * - `date` takes date-fns tokens here, strftime there; `in_time_zone` becomes `date`'s timezone.
9
+ * - PDFMonkey's own filters map to helpers (`slice_by` → `chunk`, `with_delimiter` → `number`
10
+ * with a locale that has the same separators) or are reported: the engine runs with strict
11
+ * filters, so an unmapped one would fail the render.
12
+ * - Ruby's lax parser accepts `| filter, key: value`; LiquidJS needs `| filter: key: value`.
13
+ * - Snippets (`load_snippets` + `include`) and inline `{% partial %}` blocks are inlined, because
14
+ * stored partials do not take part in API renders.
15
+ * - Settings: paper, orientation, margins (PDFMonkey's default is 10 mm), the simple
16
+ * left/center/right header and footer with `[page]`/`[topage]`, or the advanced HTML one.
17
+ *
18
+ * Builder templates (their visual builder) have an undocumented format and are not supported.
19
+ */
20
+ export interface PdfmonkeyMargin {
21
+ top?: number | string | null;
22
+ right?: number | string | null;
23
+ bottom?: number | string | null;
24
+ left?: number | string | null;
25
+ }
26
+ export interface PdfmonkeyHeaderFooter {
27
+ left?: string | null;
28
+ center?: string | null;
29
+ right?: string | null;
30
+ /** "Advanced mode": full-width HTML with Liquid; overrides left/center/right. */
31
+ content?: string | null;
32
+ }
33
+ export interface PdfmonkeySettings {
34
+ paper_format?: string | null;
35
+ paper_width?: number | string | null;
36
+ paper_height?: number | string | null;
37
+ orientation?: string | null;
38
+ margin?: PdfmonkeyMargin | null;
39
+ header?: PdfmonkeyHeaderFooter | null;
40
+ footer?: PdfmonkeyHeaderFooter | null;
41
+ inject_javascript?: boolean | null;
42
+ use_emojis?: boolean | null;
43
+ transparent_background?: boolean | null;
44
+ use_paged?: boolean | null;
45
+ use_forms?: boolean | null;
46
+ [key: string]: unknown;
47
+ }
48
+ export interface PdfmonkeyTemplate {
49
+ id?: string;
50
+ identifier?: string | null;
51
+ edition_mode?: string | null;
52
+ output_type?: string | null;
53
+ body?: string | null;
54
+ body_draft?: string | null;
55
+ scss_style?: string | null;
56
+ scss_style_draft?: string | null;
57
+ sample_data?: unknown;
58
+ sample_data_draft?: unknown;
59
+ settings?: PdfmonkeySettings | null;
60
+ settings_draft?: PdfmonkeySettings | null;
61
+ }
62
+ export interface PdfmonkeyImportOptions {
63
+ /** Import the unpublished draft instead of the published version. */
64
+ draft?: boolean;
65
+ /** Snippet code by name, for templates that `load_snippets`; PDFMonkey's API does not return it. */
66
+ snippets?: Record<string, string>;
67
+ /** A Sass compiler; without one, SCSS is converted as far as that works without (see scss.ts). */
68
+ compileScss?: (source: string) => string;
69
+ }
70
+ /** A strftime format as date-fns tokens; `unmapped` lists the directives without an equivalent. */
71
+ export declare function strftimeToDateFns(format: string): {
72
+ format: string;
73
+ unmapped: string[];
74
+ };
75
+ export declare function importPdfmonkey(input: PdfmonkeyTemplate | {
76
+ document_template: PdfmonkeyTemplate;
77
+ }, options?: PdfmonkeyImportOptions): ImportResult;
@@ -0,0 +1,77 @@
1
+ import { type ImportResult } from './common.js';
2
+ /**
3
+ * PDFMonkey importer (spec 10 §4). A PDFMonkey code template is HTML with Ruby Liquid 4, a CSS or
4
+ * SCSS stylesheet, sample data as a JSON string and settings, all returned by
5
+ * `GET /api/v1/document_templates/{id}`. Formfeed's Liquid engine is LiquidJS with the shared
6
+ * helpers, so the converter rewrites what differs:
7
+ *
8
+ * - `date` takes date-fns tokens here, strftime there; `in_time_zone` becomes `date`'s timezone.
9
+ * - PDFMonkey's own filters map to helpers (`slice_by` → `chunk`, `with_delimiter` → `number`
10
+ * with a locale that has the same separators) or are reported: the engine runs with strict
11
+ * filters, so an unmapped one would fail the render.
12
+ * - Ruby's lax parser accepts `| filter, key: value`; LiquidJS needs `| filter: key: value`.
13
+ * - Snippets (`load_snippets` + `include`) and inline `{% partial %}` blocks are inlined, because
14
+ * stored partials do not take part in API renders.
15
+ * - Settings: paper, orientation, margins (PDFMonkey's default is 10 mm), the simple
16
+ * left/center/right header and footer with `[page]`/`[topage]`, or the advanced HTML one.
17
+ *
18
+ * Builder templates (their visual builder) have an undocumented format and are not supported.
19
+ */
20
+ export interface PdfmonkeyMargin {
21
+ top?: number | string | null;
22
+ right?: number | string | null;
23
+ bottom?: number | string | null;
24
+ left?: number | string | null;
25
+ }
26
+ export interface PdfmonkeyHeaderFooter {
27
+ left?: string | null;
28
+ center?: string | null;
29
+ right?: string | null;
30
+ /** "Advanced mode": full-width HTML with Liquid; overrides left/center/right. */
31
+ content?: string | null;
32
+ }
33
+ export interface PdfmonkeySettings {
34
+ paper_format?: string | null;
35
+ paper_width?: number | string | null;
36
+ paper_height?: number | string | null;
37
+ orientation?: string | null;
38
+ margin?: PdfmonkeyMargin | null;
39
+ header?: PdfmonkeyHeaderFooter | null;
40
+ footer?: PdfmonkeyHeaderFooter | null;
41
+ inject_javascript?: boolean | null;
42
+ use_emojis?: boolean | null;
43
+ transparent_background?: boolean | null;
44
+ use_paged?: boolean | null;
45
+ use_forms?: boolean | null;
46
+ [key: string]: unknown;
47
+ }
48
+ export interface PdfmonkeyTemplate {
49
+ id?: string;
50
+ identifier?: string | null;
51
+ edition_mode?: string | null;
52
+ output_type?: string | null;
53
+ body?: string | null;
54
+ body_draft?: string | null;
55
+ scss_style?: string | null;
56
+ scss_style_draft?: string | null;
57
+ sample_data?: unknown;
58
+ sample_data_draft?: unknown;
59
+ settings?: PdfmonkeySettings | null;
60
+ settings_draft?: PdfmonkeySettings | null;
61
+ }
62
+ export interface PdfmonkeyImportOptions {
63
+ /** Import the unpublished draft instead of the published version. */
64
+ draft?: boolean;
65
+ /** Snippet code by name, for templates that `load_snippets`; PDFMonkey's API does not return it. */
66
+ snippets?: Record<string, string>;
67
+ /** A Sass compiler; without one, SCSS is converted as far as that works without (see scss.ts). */
68
+ compileScss?: (source: string) => string;
69
+ }
70
+ /** A strftime format as date-fns tokens; `unmapped` lists the directives without an equivalent. */
71
+ export declare function strftimeToDateFns(format: string): {
72
+ format: string;
73
+ unmapped: string[];
74
+ };
75
+ export declare function importPdfmonkey(input: PdfmonkeyTemplate | {
76
+ document_template: PdfmonkeyTemplate;
77
+ }, options?: PdfmonkeyImportOptions): ImportResult;
@@ -0,0 +1,17 @@
1
+ import { type ImportNote } from './common.cjs';
2
+ /**
3
+ * SCSS → CSS for imported stylesheets (PDFMonkey stores "CSS or SCSS"). Formfeed styles are CSS,
4
+ * and the engine must stay free of a Sass compiler, so the caller may pass one (`compile`): the app
5
+ * loads `sass` on demand, the CLI when it is installed. Without it, the plain-CSS subset that most
6
+ * stylesheets use is converted here: `//` comment lines go, top-level `$variables` are substituted,
7
+ * and everything that needs a real compiler (mixins, functions, control flow) is reported with its
8
+ * line. Nested rules are left as they are: Chromium renders CSS nesting natively.
9
+ */
10
+ export interface ScssResult {
11
+ css: string;
12
+ warnings: ImportNote[];
13
+ changes: string[];
14
+ }
15
+ /** True when the stylesheet uses anything beyond CSS (nesting aside, which CSS has too). */
16
+ export declare function isScss(source: string): boolean;
17
+ export declare function convertScss(source: string, compile?: (source: string) => string): ScssResult;
@@ -0,0 +1,17 @@
1
+ import { type ImportNote } from './common.js';
2
+ /**
3
+ * SCSS → CSS for imported stylesheets (PDFMonkey stores "CSS or SCSS"). Formfeed styles are CSS,
4
+ * and the engine must stay free of a Sass compiler, so the caller may pass one (`compile`): the app
5
+ * loads `sass` on demand, the CLI when it is installed. Without it, the plain-CSS subset that most
6
+ * stylesheets use is converted here: `//` comment lines go, top-level `$variables` are substituted,
7
+ * and everything that needs a real compiler (mixins, functions, control flow) is reported with its
8
+ * line. Nested rules are left as they are: Chromium renders CSS nesting natively.
9
+ */
10
+ export interface ScssResult {
11
+ css: string;
12
+ warnings: ImportNote[];
13
+ changes: string[];
14
+ }
15
+ /** True when the stylesheet uses anything beyond CSS (nesting aside, which CSS has too). */
16
+ export declare function isScss(source: string): boolean;
17
+ export declare function convertScss(source: string, compile?: (source: string) => string): ScssResult;