@formfeed/engine 0.3.5 → 0.3.6

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.3.5",
3
+ "version": "0.3.6",
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
@@ -1,7 +1,8 @@
1
1
  export * from './lib/types.cjs';
2
2
  export { EngineSyntaxError, RenderError, RenderLimitError } from './lib/errors.cjs';
3
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';
4
+ export { DefaultHelperRegistry, EPC_MAX_BYTES, builtinHelpers, chartMarkup, chartPayload, createHelperRegistry, defaultHelpers, epcPayload, escapeHtml, helperDocs, ibanChecksum, imageMarkup, normaliseIban, qrSvg, svgDataUri, toDate, toNumber, validateEpc, } from './lib/helpers/index.cjs';
5
+ export type { EpcInput, EpcPayment, EpcProblem, QrOptions } from './lib/helpers/index.cjs';
5
6
  export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, getEngine, handlebarsEngine, jinja2Engine, liquidEngine, liquidBuiltinFilters, nunjucksBuiltinFilters, } from './lib/engines/index.cjs';
6
7
  export { diffSchemas, inferSchema, inferSchemaFromDataSets, schemaPaths } from './lib/schema.cjs';
7
8
  export { defaultOutput, imageOutput, isOfficeKind, isOutputFormat, officeKinds, outputFormats, outputsForKind, type OfficeKind, type OutputFormat, } from './lib/output.cjs';
package/types/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export * from './lib/types.js';
2
2
  export { EngineSyntaxError, RenderError, RenderLimitError } from './lib/errors.js';
3
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';
4
+ export { DefaultHelperRegistry, EPC_MAX_BYTES, builtinHelpers, chartMarkup, chartPayload, createHelperRegistry, defaultHelpers, epcPayload, escapeHtml, helperDocs, ibanChecksum, imageMarkup, normaliseIban, qrSvg, svgDataUri, toDate, toNumber, validateEpc, } from './lib/helpers/index.js';
5
+ export type { EpcInput, EpcPayment, EpcProblem, QrOptions } from './lib/helpers/index.js';
5
6
  export { analyzeHandlebars, analyzeJinja2, analyzeLiquid, engineIds, engines, getEngine, handlebarsEngine, jinja2Engine, liquidEngine, liquidBuiltinFilters, nunjucksBuiltinFilters, } from './lib/engines/index.js';
6
7
  export { diffSchemas, inferSchema, inferSchemaFromDataSets, schemaPaths } from './lib/schema.js';
7
8
  export { defaultOutput, imageOutput, isOfficeKind, isOutputFormat, officeKinds, outputFormats, outputsForKind, type OfficeKind, type OutputFormat, } from './lib/output.js';
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The SEPA credit transfer QR code, EPC069-12 version 002 — the GiroCode a German invoice carries
3
+ * so a banking app fills the transfer in by scanning it (spec 05 §2, `epcQr`).
4
+ *
5
+ * The payload is built here and validated here, apart from the helper registration, so the browser
6
+ * can have both without the rest of the engine: `helpers/codes.ts` also brings bwip-js in for
7
+ * barcodes, which is far larger than everything on this page put together.
8
+ */
9
+ /**
10
+ * A complete payment. A caller that has one should say so with this type; the two functions below
11
+ * take `EpcInput` instead, because a template hands over whatever the data happened to hold and
12
+ * telling someone what is missing is the whole job of `validateEpc`.
13
+ */
14
+ export interface EpcPayment {
15
+ /** The beneficiary, at most 70 characters. Required. */
16
+ name: string;
17
+ /** The beneficiary's IBAN. Required. */
18
+ iban: string;
19
+ /** Optional with version 002 inside SEPA; 8 or 11 characters. */
20
+ bic?: string;
21
+ /** Euro; the code carries no other currency. */
22
+ amount?: number | string;
23
+ /** Structured remittance information, at most 35 characters. Excludes `text`. */
24
+ reference?: string;
25
+ /** Unstructured remittance information, at most 140 characters. Excludes `reference`. */
26
+ text?: string;
27
+ /** Purpose code (AT-44), at most 4 characters. */
28
+ purpose?: string;
29
+ }
30
+ /** What a caller actually hands over: the same fields, none of them guaranteed to be there. */
31
+ export type EpcInput = Partial<EpcPayment>;
32
+ /** EPC QR (GiroCode) payload, version 002, UTF-8, SCT. */
33
+ export declare function epcPayload(input: EpcInput): string;
34
+ /**
35
+ * What is wrong with a payment, as a code rather than a sentence: the engine has no locale, and the
36
+ * one caller that shows these to a person says them in two languages.
37
+ */
38
+ export interface EpcProblem {
39
+ field: keyof EpcPayment | 'payload';
40
+ code: 'required' | 'too_long' | 'iban_characters' | 'iban_country_length' | 'iban_checksum' | 'bic_format' | 'not_a_number' | 'out_of_range' | 'reference_or_text';
41
+ /** The limit that was passed, where there is one. */
42
+ max?: number;
43
+ /** What the value actually is, where a number says more than the code alone. */
44
+ actual?: number;
45
+ }
46
+ /** The whole payload must fit 331 bytes, and a German umlaut is two of them. */
47
+ export declare const EPC_MAX_BYTES = 331;
48
+ /** Spaces and case are the writer's business, not the code's. */
49
+ export declare const normaliseIban: (iban: string) => string;
50
+ /**
51
+ * Whether an IBAN's check digits match its body (ISO 7064 mod 97-10). The remainder is taken digit
52
+ * by digit because the rearranged number runs to 30-odd digits, well past a safe integer.
53
+ */
54
+ export declare function ibanChecksum(iban: string): boolean;
55
+ /** Everything wrong with a payment, in the order a form shows its fields; empty when it is valid. */
56
+ export declare function validateEpc(input: EpcInput): EpcProblem[];
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The SEPA credit transfer QR code, EPC069-12 version 002 — the GiroCode a German invoice carries
3
+ * so a banking app fills the transfer in by scanning it (spec 05 §2, `epcQr`).
4
+ *
5
+ * The payload is built here and validated here, apart from the helper registration, so the browser
6
+ * can have both without the rest of the engine: `helpers/codes.ts` also brings bwip-js in for
7
+ * barcodes, which is far larger than everything on this page put together.
8
+ */
9
+ /**
10
+ * A complete payment. A caller that has one should say so with this type; the two functions below
11
+ * take `EpcInput` instead, because a template hands over whatever the data happened to hold and
12
+ * telling someone what is missing is the whole job of `validateEpc`.
13
+ */
14
+ export interface EpcPayment {
15
+ /** The beneficiary, at most 70 characters. Required. */
16
+ name: string;
17
+ /** The beneficiary's IBAN. Required. */
18
+ iban: string;
19
+ /** Optional with version 002 inside SEPA; 8 or 11 characters. */
20
+ bic?: string;
21
+ /** Euro; the code carries no other currency. */
22
+ amount?: number | string;
23
+ /** Structured remittance information, at most 35 characters. Excludes `text`. */
24
+ reference?: string;
25
+ /** Unstructured remittance information, at most 140 characters. Excludes `reference`. */
26
+ text?: string;
27
+ /** Purpose code (AT-44), at most 4 characters. */
28
+ purpose?: string;
29
+ }
30
+ /** What a caller actually hands over: the same fields, none of them guaranteed to be there. */
31
+ export type EpcInput = Partial<EpcPayment>;
32
+ /** EPC QR (GiroCode) payload, version 002, UTF-8, SCT. */
33
+ export declare function epcPayload(input: EpcInput): string;
34
+ /**
35
+ * What is wrong with a payment, as a code rather than a sentence: the engine has no locale, and the
36
+ * one caller that shows these to a person says them in two languages.
37
+ */
38
+ export interface EpcProblem {
39
+ field: keyof EpcPayment | 'payload';
40
+ code: 'required' | 'too_long' | 'iban_characters' | 'iban_country_length' | 'iban_checksum' | 'bic_format' | 'not_a_number' | 'out_of_range' | 'reference_or_text';
41
+ /** The limit that was passed, where there is one. */
42
+ max?: number;
43
+ /** What the value actually is, where a number says more than the code alone. */
44
+ actual?: number;
45
+ }
46
+ /** The whole payload must fit 331 bytes, and a German umlaut is two of them. */
47
+ export declare const EPC_MAX_BYTES = 331;
48
+ /** Spaces and case are the writer's business, not the code's. */
49
+ export declare const normaliseIban: (iban: string) => string;
50
+ /**
51
+ * Whether an IBAN's check digits match its body (ISO 7064 mod 97-10). The remainder is taken digit
52
+ * by digit because the rearranged number runs to 30-odd digits, well past a safe integer.
53
+ */
54
+ export declare function ibanChecksum(iban: string): boolean;
55
+ /** Everything wrong with a payment, in the order a form shows its fields; empty when it is valid. */
56
+ export declare function validateEpc(input: EpcInput): EpcProblem[];
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Codes without the engine: QR rendering and the EPC (GiroCode) payload with its validation, for a
3
+ * caller that wants them in a browser and nothing else. `@formfeed/engine/codes` in this workspace;
4
+ * the published package exposes the same functions from its single entry.
5
+ */
6
+ export { EPC_MAX_BYTES, epcPayload, ibanChecksum, normaliseIban, validateEpc, type EpcInput, type EpcPayment, type EpcProblem, } from './epc.cjs';
7
+ export { qrSvg, svgDataUri, type QrOptions } from './qr.cjs';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Codes without the engine: QR rendering and the EPC (GiroCode) payload with its validation, for a
3
+ * caller that wants them in a browser and nothing else. `@formfeed/engine/codes` in this workspace;
4
+ * the published package exposes the same functions from its single entry.
5
+ */
6
+ export { EPC_MAX_BYTES, epcPayload, ibanChecksum, normaliseIban, validateEpc, type EpcInput, type EpcPayment, type EpcProblem, } from './epc.js';
7
+ export { qrSvg, svgDataUri, type QrOptions } from './qr.js';
@@ -0,0 +1,11 @@
1
+ /** QR rendering, without the barcode symbologies `helpers/codes.ts` also registers. */
2
+ export interface 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
+ /** An SVG as the `src` of an `<img>`, which is how the helpers put a code into a document. */
11
+ export declare const svgDataUri: (svg: string) => string;
@@ -0,0 +1,11 @@
1
+ /** QR rendering, without the barcode symbologies `helpers/codes.ts` also registers. */
2
+ export interface 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
+ /** An SVG as the `src` of an `<img>`, which is how the helpers put a code into a document. */
11
+ export declare const svgDataUri: (svg: string) => string;
@@ -1,21 +1,2 @@
1
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
2
  export declare const codeHelpers: HelperDefinition[];
21
- export {};
@@ -1,21 +1,2 @@
1
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
2
  export declare const codeHelpers: HelperDefinition[];
21
- export {};
@@ -1,5 +1,6 @@
1
1
  import type { HelperDefinition } from '../types.cjs';
2
- export declare function toNumber(value: unknown): number;
2
+ import { toNumber } from '../values.cjs';
3
+ export { toNumber };
3
4
  export declare function toDate(value: unknown, tz: string): Date | null;
4
5
  export declare function escapeHtml(value: string): string;
5
6
  export declare const formatHelpers: HelperDefinition[];
@@ -1,5 +1,6 @@
1
1
  import type { HelperDefinition } from '../types.js';
2
- export declare function toNumber(value: unknown): number;
2
+ import { toNumber } from '../values.js';
3
+ export { toNumber };
3
4
  export declare function toDate(value: unknown, tz: string): Date | null;
4
5
  export declare function escapeHtml(value: string): string;
5
6
  export declare const formatHelpers: HelperDefinition[];
@@ -1,8 +1,9 @@
1
- import type { HelperDefinition, HelperDoc } from '../types.cjs';
1
+ import type { HelperDefinition, HelperDocEntry } from '../types.cjs';
2
2
  import { DefaultHelperRegistry } from './registry.cjs';
3
3
  export { DefaultHelperRegistry } from './registry.cjs';
4
4
  export { escapeHtml, toDate, toNumber } from './format.cjs';
5
- export { epcPayload, qrSvg } from './codes.cjs';
5
+ export { EPC_MAX_BYTES, epcPayload, ibanChecksum, normaliseIban, qrSvg, svgDataUri, validateEpc } from '../codes/index.cjs';
6
+ export type { EpcInput, EpcPayment, EpcProblem, QrOptions } from '../codes/index.cjs';
6
7
  export { chartMarkup, chartPayload, imageMarkup } from './document.cjs';
7
8
  export { officeUnsupported, officeUnsupportedHelpers } from './office.cjs';
8
9
  export type { ChartSpec, ImageOptions } from './document.cjs';
@@ -12,7 +13,4 @@ export declare function createHelperRegistry(extra?: HelperDefinition[]): Defaul
12
13
  /** Lazily built default registry, shared by analyze() and the engines when none is supplied. */
13
14
  export declare function defaultHelpers(): DefaultHelperRegistry;
14
15
  /** Documentation entries that feed editor hover and completion (spec 05 §2). */
15
- export declare function helperDocs(registry?: DefaultHelperRegistry): Array<HelperDoc & {
16
- name: string;
17
- aliases: string[];
18
- }>;
16
+ export declare function helperDocs(registry?: DefaultHelperRegistry): HelperDocEntry[];
@@ -1,8 +1,9 @@
1
- import type { HelperDefinition, HelperDoc } from '../types.js';
1
+ import type { HelperDefinition, HelperDocEntry } from '../types.js';
2
2
  import { DefaultHelperRegistry } from './registry.js';
3
3
  export { DefaultHelperRegistry } from './registry.js';
4
4
  export { escapeHtml, toDate, toNumber } from './format.js';
5
- export { epcPayload, qrSvg } from './codes.js';
5
+ export { EPC_MAX_BYTES, epcPayload, ibanChecksum, normaliseIban, qrSvg, svgDataUri, validateEpc } from '../codes/index.js';
6
+ export type { EpcInput, EpcPayment, EpcProblem, QrOptions } from '../codes/index.js';
6
7
  export { chartMarkup, chartPayload, imageMarkup } from './document.js';
7
8
  export { officeUnsupported, officeUnsupportedHelpers } from './office.js';
8
9
  export type { ChartSpec, ImageOptions } from './document.js';
@@ -12,7 +13,4 @@ export declare function createHelperRegistry(extra?: HelperDefinition[]): Defaul
12
13
  /** Lazily built default registry, shared by analyze() and the engines when none is supplied. */
13
14
  export declare function defaultHelpers(): DefaultHelperRegistry;
14
15
  /** Documentation entries that feed editor hover and completion (spec 05 §2). */
15
- export declare function helperDocs(registry?: DefaultHelperRegistry): Array<HelperDoc & {
16
- name: string;
17
- aliases: string[];
18
- }>;
16
+ export declare function helperDocs(registry?: DefaultHelperRegistry): HelperDocEntry[];
@@ -119,9 +119,22 @@ export type HelperCategory = 'format' | 'text' | 'collection' | 'logic' | 'code'
119
119
  export interface HelperDoc {
120
120
  signature: string;
121
121
  description: string;
122
- example: string;
122
+ /**
123
+ * The same call written for each engine, so the reference and the editor can show the reader the
124
+ * one they can paste. They differ in more than punctuation — Jinja2 passes filter arguments in
125
+ * parentheses, Liquid after a colon, Handlebars positionally — and `helper-examples.spec.ts`
126
+ * renders every one of them, so none of the three can be wrong.
127
+ */
128
+ examples: Record<EngineId, string>;
123
129
  category: HelperCategory;
124
130
  }
131
+ /** A helper's documentation with the name it is registered under. What `helperDocs()` returns. */
132
+ export interface HelperDocEntry extends HelperDoc {
133
+ name: string;
134
+ aliases: string[];
135
+ /** The Jinja2 example, for readers written before `examples`. */
136
+ example: string;
137
+ }
125
138
  export interface HelperDefinition {
126
139
  name: string;
127
140
  /** Other names the helper answers to (apitemplate.io compatibility aliases). */
@@ -119,9 +119,22 @@ export type HelperCategory = 'format' | 'text' | 'collection' | 'logic' | 'code'
119
119
  export interface HelperDoc {
120
120
  signature: string;
121
121
  description: string;
122
- example: string;
122
+ /**
123
+ * The same call written for each engine, so the reference and the editor can show the reader the
124
+ * one they can paste. They differ in more than punctuation — Jinja2 passes filter arguments in
125
+ * parentheses, Liquid after a colon, Handlebars positionally — and `helper-examples.spec.ts`
126
+ * renders every one of them, so none of the three can be wrong.
127
+ */
128
+ examples: Record<EngineId, string>;
123
129
  category: HelperCategory;
124
130
  }
131
+ /** A helper's documentation with the name it is registered under. What `helperDocs()` returns. */
132
+ export interface HelperDocEntry extends HelperDoc {
133
+ name: string;
134
+ aliases: string[];
135
+ /** The Jinja2 example, for readers written before `examples`. */
136
+ example: string;
137
+ }
125
138
  export interface HelperDefinition {
126
139
  name: string;
127
140
  /** Other names the helper answers to (apitemplate.io compatibility aliases). */
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Value coercions small enough that a module may want them without the rest of the engine. They
3
+ * live here rather than in `helpers/format.ts`, which pulls in date-fns, marked and n2words: the
4
+ * landing site's GiroCode tool imports `lib/codes` in the browser and would otherwise carry all
5
+ * three for the sake of one eight-line function.
6
+ */
7
+ /** A number from whatever the data holds; `NaN` when it is not a number at all. */
8
+ export declare function toNumber(value: unknown): number;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Value coercions small enough that a module may want them without the rest of the engine. They
3
+ * live here rather than in `helpers/format.ts`, which pulls in date-fns, marked and n2words: the
4
+ * landing site's GiroCode tool imports `lib/codes` in the browser and would otherwise carry all
5
+ * three for the sake of one eight-line function.
6
+ */
7
+ /** A number from whatever the data holds; `NaN` when it is not a number at all. */
8
+ export declare function toNumber(value: unknown): number;