@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,120 @@
|
|
|
1
|
+
import type { OfficeDrawingRequest } from '../types.cjs';
|
|
2
|
+
import { OfficeError } from './errors.cjs';
|
|
3
|
+
export declare const officeDrawingLimits: {
|
|
4
|
+
/** Drawings per render. */
|
|
5
|
+
maxDrawings: number;
|
|
6
|
+
/** Image bytes placed per render. */
|
|
7
|
+
maxImageBytes: number;
|
|
8
|
+
/** Largest raster edge in pixels. */
|
|
9
|
+
maxPixels: number;
|
|
10
|
+
};
|
|
11
|
+
/** What renders images for the post pass: the render-worker or the browser. */
|
|
12
|
+
export interface OfficeImageHost {
|
|
13
|
+
/** Reads an image URL (never called for `data:` URLs, which are decoded here). */
|
|
14
|
+
fetch(url: string): Promise<{
|
|
15
|
+
bytes: Uint8Array;
|
|
16
|
+
contentType: string;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Turns SVG or another format into a PNG. With `size`, the picture is drawn at that many pixels;
|
|
20
|
+
* without, at its natural size.
|
|
21
|
+
*/
|
|
22
|
+
toPng(input: {
|
|
23
|
+
bytes: Uint8Array;
|
|
24
|
+
contentType: string;
|
|
25
|
+
}, size?: {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
}): Promise<Uint8Array>;
|
|
29
|
+
}
|
|
30
|
+
/** Collects the drawing requests of one render and hands out their placeholders. */
|
|
31
|
+
export declare class DrawingCollector {
|
|
32
|
+
readonly nonce: string;
|
|
33
|
+
readonly requests: OfficeDrawingRequest[];
|
|
34
|
+
/** Set when a template asked for more drawings than allowed; the engines wrap the error thrown. */
|
|
35
|
+
exceeded: OfficeError | null;
|
|
36
|
+
constructor(nonce: string);
|
|
37
|
+
readonly register: (request: OfficeDrawingRequest) => string;
|
|
38
|
+
pattern(): RegExp;
|
|
39
|
+
/** Indexes of the drawings a filled part uses, in order. */
|
|
40
|
+
usedIn(xml: string): number[];
|
|
41
|
+
}
|
|
42
|
+
/** A drawing ready to place. */
|
|
43
|
+
export type ResolvedDrawing = {
|
|
44
|
+
kind: 'picture';
|
|
45
|
+
media: string;
|
|
46
|
+
widthEmu: number;
|
|
47
|
+
heightEmu: number;
|
|
48
|
+
alt: string; /** A size was asked for. */
|
|
49
|
+
sized: boolean;
|
|
50
|
+
} | {
|
|
51
|
+
kind: 'page-break';
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'nothing';
|
|
54
|
+
};
|
|
55
|
+
export interface PreparedMedia {
|
|
56
|
+
name: string;
|
|
57
|
+
bytes: Uint8Array;
|
|
58
|
+
extension: 'png' | 'jpeg';
|
|
59
|
+
}
|
|
60
|
+
/** A size option in EMU: a number is pixels at 96 dpi, a string may carry `px`, `pt`, `mm`, `cm` or `in`. */
|
|
61
|
+
export declare function toEmu(value: number | string | undefined): number | null;
|
|
62
|
+
/** Natural size in pixels of a PNG, JPEG, GIF or SVG; null when it cannot be read. */
|
|
63
|
+
export declare function imageSize(bytes: Uint8Array, contentType: string): {
|
|
64
|
+
width: number;
|
|
65
|
+
height: number;
|
|
66
|
+
} | null;
|
|
67
|
+
/** Width and height of an SVG from its attributes, else from its viewBox. */
|
|
68
|
+
export declare function svgSize(svg: string): {
|
|
69
|
+
width: number;
|
|
70
|
+
height: number;
|
|
71
|
+
} | null;
|
|
72
|
+
/** Decodes a `data:` URL; null for anything else. */
|
|
73
|
+
export declare function decodeDataUrl(url: string): {
|
|
74
|
+
bytes: Uint8Array;
|
|
75
|
+
contentType: string;
|
|
76
|
+
} | null;
|
|
77
|
+
/**
|
|
78
|
+
* Turns the requests into pictures: fetched or decoded, converted to PNG where Word needs it, sized
|
|
79
|
+
* (the given size, else the natural size at 96 dpi, never wider than `maxWidthEmu`), and shared when
|
|
80
|
+
* the same picture appears again. A picture that cannot be read becomes nothing and a warning.
|
|
81
|
+
*/
|
|
82
|
+
export declare class DrawingResolver {
|
|
83
|
+
private readonly requests;
|
|
84
|
+
private readonly host;
|
|
85
|
+
private readonly mediaPrefix;
|
|
86
|
+
readonly media: PreparedMedia[];
|
|
87
|
+
readonly warnings: string[];
|
|
88
|
+
private readonly resolved;
|
|
89
|
+
private readonly byKey;
|
|
90
|
+
private imageBytes;
|
|
91
|
+
constructor(requests: readonly OfficeDrawingRequest[], host: OfficeImageHost | undefined, mediaPrefix: string);
|
|
92
|
+
resolve(index: number, maxWidthEmu: number): Promise<ResolvedDrawing>;
|
|
93
|
+
private resolveOne;
|
|
94
|
+
private prepare;
|
|
95
|
+
}
|
|
96
|
+
/** The text width of a Word part's last section in EMU; 16 cm when it names none. */
|
|
97
|
+
export declare function textWidthEmu(xml: string): number;
|
|
98
|
+
/** A picture in a run, as Word writes one (`wp:inline`); namespaces are declared on the elements. */
|
|
99
|
+
export declare function inlinePicture(picture: Extract<ResolvedDrawing, {
|
|
100
|
+
kind: 'picture';
|
|
101
|
+
}>, rId: string, id: number): string;
|
|
102
|
+
/** The highest drawing id of a part, so new pictures start after it. */
|
|
103
|
+
export declare function highestDrawingId(xml: string): number;
|
|
104
|
+
/**
|
|
105
|
+
* Replaces the drawing placeholders of a filled Word part. A placeholder inside `w:t` splits its run:
|
|
106
|
+
* the text before stays in the run, the picture (or page break) gets a run of its own with the same
|
|
107
|
+
* run properties, and the text after continues in a copy of the run.
|
|
108
|
+
*/
|
|
109
|
+
export declare function placeDrawings(xml: string, pattern: RegExp, markupFor: (index: number) => string): string;
|
|
110
|
+
/** Adds image relationships to a part's `.rels` (created when the part has none). */
|
|
111
|
+
export declare function withRelationships(rels: string | null, relationships: Array<{
|
|
112
|
+
id: string;
|
|
113
|
+
target: string;
|
|
114
|
+
}>): string;
|
|
115
|
+
/** Relationship ids a `.rels` already uses. */
|
|
116
|
+
export declare function relationshipIds(rels: string | null): Set<string>;
|
|
117
|
+
/** `[Content_Types].xml` with defaults for the picture formats it lacks. */
|
|
118
|
+
export declare function withImageTypes(contentTypes: string, extensions: ReadonlySet<'png' | 'jpeg'>): string;
|
|
119
|
+
/** `word/document.xml` → `word/_rels/document.xml.rels`. */
|
|
120
|
+
export declare function relsPathOf(part: string): string;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { OfficeDrawingRequest } from '../types.js';
|
|
2
|
+
import { OfficeError } from './errors.js';
|
|
3
|
+
export declare const officeDrawingLimits: {
|
|
4
|
+
/** Drawings per render. */
|
|
5
|
+
maxDrawings: number;
|
|
6
|
+
/** Image bytes placed per render. */
|
|
7
|
+
maxImageBytes: number;
|
|
8
|
+
/** Largest raster edge in pixels. */
|
|
9
|
+
maxPixels: number;
|
|
10
|
+
};
|
|
11
|
+
/** What renders images for the post pass: the render-worker or the browser. */
|
|
12
|
+
export interface OfficeImageHost {
|
|
13
|
+
/** Reads an image URL (never called for `data:` URLs, which are decoded here). */
|
|
14
|
+
fetch(url: string): Promise<{
|
|
15
|
+
bytes: Uint8Array;
|
|
16
|
+
contentType: string;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Turns SVG or another format into a PNG. With `size`, the picture is drawn at that many pixels;
|
|
20
|
+
* without, at its natural size.
|
|
21
|
+
*/
|
|
22
|
+
toPng(input: {
|
|
23
|
+
bytes: Uint8Array;
|
|
24
|
+
contentType: string;
|
|
25
|
+
}, size?: {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
}): Promise<Uint8Array>;
|
|
29
|
+
}
|
|
30
|
+
/** Collects the drawing requests of one render and hands out their placeholders. */
|
|
31
|
+
export declare class DrawingCollector {
|
|
32
|
+
readonly nonce: string;
|
|
33
|
+
readonly requests: OfficeDrawingRequest[];
|
|
34
|
+
/** Set when a template asked for more drawings than allowed; the engines wrap the error thrown. */
|
|
35
|
+
exceeded: OfficeError | null;
|
|
36
|
+
constructor(nonce: string);
|
|
37
|
+
readonly register: (request: OfficeDrawingRequest) => string;
|
|
38
|
+
pattern(): RegExp;
|
|
39
|
+
/** Indexes of the drawings a filled part uses, in order. */
|
|
40
|
+
usedIn(xml: string): number[];
|
|
41
|
+
}
|
|
42
|
+
/** A drawing ready to place. */
|
|
43
|
+
export type ResolvedDrawing = {
|
|
44
|
+
kind: 'picture';
|
|
45
|
+
media: string;
|
|
46
|
+
widthEmu: number;
|
|
47
|
+
heightEmu: number;
|
|
48
|
+
alt: string; /** A size was asked for. */
|
|
49
|
+
sized: boolean;
|
|
50
|
+
} | {
|
|
51
|
+
kind: 'page-break';
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'nothing';
|
|
54
|
+
};
|
|
55
|
+
export interface PreparedMedia {
|
|
56
|
+
name: string;
|
|
57
|
+
bytes: Uint8Array;
|
|
58
|
+
extension: 'png' | 'jpeg';
|
|
59
|
+
}
|
|
60
|
+
/** A size option in EMU: a number is pixels at 96 dpi, a string may carry `px`, `pt`, `mm`, `cm` or `in`. */
|
|
61
|
+
export declare function toEmu(value: number | string | undefined): number | null;
|
|
62
|
+
/** Natural size in pixels of a PNG, JPEG, GIF or SVG; null when it cannot be read. */
|
|
63
|
+
export declare function imageSize(bytes: Uint8Array, contentType: string): {
|
|
64
|
+
width: number;
|
|
65
|
+
height: number;
|
|
66
|
+
} | null;
|
|
67
|
+
/** Width and height of an SVG from its attributes, else from its viewBox. */
|
|
68
|
+
export declare function svgSize(svg: string): {
|
|
69
|
+
width: number;
|
|
70
|
+
height: number;
|
|
71
|
+
} | null;
|
|
72
|
+
/** Decodes a `data:` URL; null for anything else. */
|
|
73
|
+
export declare function decodeDataUrl(url: string): {
|
|
74
|
+
bytes: Uint8Array;
|
|
75
|
+
contentType: string;
|
|
76
|
+
} | null;
|
|
77
|
+
/**
|
|
78
|
+
* Turns the requests into pictures: fetched or decoded, converted to PNG where Word needs it, sized
|
|
79
|
+
* (the given size, else the natural size at 96 dpi, never wider than `maxWidthEmu`), and shared when
|
|
80
|
+
* the same picture appears again. A picture that cannot be read becomes nothing and a warning.
|
|
81
|
+
*/
|
|
82
|
+
export declare class DrawingResolver {
|
|
83
|
+
private readonly requests;
|
|
84
|
+
private readonly host;
|
|
85
|
+
private readonly mediaPrefix;
|
|
86
|
+
readonly media: PreparedMedia[];
|
|
87
|
+
readonly warnings: string[];
|
|
88
|
+
private readonly resolved;
|
|
89
|
+
private readonly byKey;
|
|
90
|
+
private imageBytes;
|
|
91
|
+
constructor(requests: readonly OfficeDrawingRequest[], host: OfficeImageHost | undefined, mediaPrefix: string);
|
|
92
|
+
resolve(index: number, maxWidthEmu: number): Promise<ResolvedDrawing>;
|
|
93
|
+
private resolveOne;
|
|
94
|
+
private prepare;
|
|
95
|
+
}
|
|
96
|
+
/** The text width of a Word part's last section in EMU; 16 cm when it names none. */
|
|
97
|
+
export declare function textWidthEmu(xml: string): number;
|
|
98
|
+
/** A picture in a run, as Word writes one (`wp:inline`); namespaces are declared on the elements. */
|
|
99
|
+
export declare function inlinePicture(picture: Extract<ResolvedDrawing, {
|
|
100
|
+
kind: 'picture';
|
|
101
|
+
}>, rId: string, id: number): string;
|
|
102
|
+
/** The highest drawing id of a part, so new pictures start after it. */
|
|
103
|
+
export declare function highestDrawingId(xml: string): number;
|
|
104
|
+
/**
|
|
105
|
+
* Replaces the drawing placeholders of a filled Word part. A placeholder inside `w:t` splits its run:
|
|
106
|
+
* the text before stays in the run, the picture (or page break) gets a run of its own with the same
|
|
107
|
+
* run properties, and the text after continues in a copy of the run.
|
|
108
|
+
*/
|
|
109
|
+
export declare function placeDrawings(xml: string, pattern: RegExp, markupFor: (index: number) => string): string;
|
|
110
|
+
/** Adds image relationships to a part's `.rels` (created when the part has none). */
|
|
111
|
+
export declare function withRelationships(rels: string | null, relationships: Array<{
|
|
112
|
+
id: string;
|
|
113
|
+
target: string;
|
|
114
|
+
}>): string;
|
|
115
|
+
/** Relationship ids a `.rels` already uses. */
|
|
116
|
+
export declare function relationshipIds(rels: string | null): Set<string>;
|
|
117
|
+
/** `[Content_Types].xml` with defaults for the picture formats it lacks. */
|
|
118
|
+
export declare function withImageTypes(contentTypes: string, extensions: ReadonlySet<'png' | 'jpeg'>): string;
|
|
119
|
+
/** `word/document.xml` → `word/_rels/document.xml.rels`. */
|
|
120
|
+
export declare function relsPathOf(part: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failures of the office container code (spec 22 §2.1, §8). The codes are the API's problem codes, so
|
|
3
|
+
* the gateway and the worker pass them on unchanged.
|
|
4
|
+
*/
|
|
5
|
+
export type OfficeErrorCode = 'file_type_unsupported' | 'source_encrypted' | 'office_document_invalid' | 'office_document_too_large';
|
|
6
|
+
export declare class OfficeError extends Error {
|
|
7
|
+
readonly code: OfficeErrorCode;
|
|
8
|
+
readonly details: Record<string, unknown>;
|
|
9
|
+
constructor(code: OfficeErrorCode, message: string, details?: Record<string, unknown>);
|
|
10
|
+
}
|
|
11
|
+
/** Limits of spec 22 §2.1 and §4.3. */
|
|
12
|
+
export declare const officeLimits: {
|
|
13
|
+
/** Entries in one container. */
|
|
14
|
+
readonly maxEntries: 2000;
|
|
15
|
+
/** Sum of the uncompressed sizes the central directory declares. */
|
|
16
|
+
readonly maxDeclaredBytes: number;
|
|
17
|
+
/** One part we inflate; enforced while inflating, because the declared size can lie. */
|
|
18
|
+
readonly maxPartBytes: number;
|
|
19
|
+
/** A conversion upload or a template file. */
|
|
20
|
+
readonly maxFileBytes: number;
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failures of the office container code (spec 22 §2.1, §8). The codes are the API's problem codes, so
|
|
3
|
+
* the gateway and the worker pass them on unchanged.
|
|
4
|
+
*/
|
|
5
|
+
export type OfficeErrorCode = 'file_type_unsupported' | 'source_encrypted' | 'office_document_invalid' | 'office_document_too_large';
|
|
6
|
+
export declare class OfficeError extends Error {
|
|
7
|
+
readonly code: OfficeErrorCode;
|
|
8
|
+
readonly details: Record<string, unknown>;
|
|
9
|
+
constructor(code: OfficeErrorCode, message: string, details?: Record<string, unknown>);
|
|
10
|
+
}
|
|
11
|
+
/** Limits of spec 22 §2.1 and §4.3. */
|
|
12
|
+
export declare const officeLimits: {
|
|
13
|
+
/** Entries in one container. */
|
|
14
|
+
readonly maxEntries: 2000;
|
|
15
|
+
/** Sum of the uncompressed sizes the central directory declares. */
|
|
16
|
+
readonly maxDeclaredBytes: number;
|
|
17
|
+
/** One part we inflate; enforced while inflating, because the declared size can lie. */
|
|
18
|
+
readonly maxPartBytes: number;
|
|
19
|
+
/** A conversion upload or a template file. */
|
|
20
|
+
readonly maxFileBytes: number;
|
|
21
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { OfficeDiagnostic } from './tags.cjs';
|
|
2
|
+
import { type ZipArchive } from './zip.cjs';
|
|
3
|
+
/**
|
|
4
|
+
* Fonts an office document uses and whether the converter has them (spec 22 §4.6). A converted
|
|
5
|
+
* document renders only with fonts the sidecar has or the document embeds; the list of installed
|
|
6
|
+
* families is passed in (`OFFICE_FONT_FAMILIES` in `@formfeed/api-types`, generated from the image),
|
|
7
|
+
* so the engine stays free of that dependency.
|
|
8
|
+
*/
|
|
9
|
+
export interface DocumentFont {
|
|
10
|
+
name: string;
|
|
11
|
+
embedded: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Office fonts LibreOffice replaces with a family of the same metrics, so lines break the same. */
|
|
14
|
+
export declare const METRIC_COMPATIBLE: Readonly<Record<string, string>>;
|
|
15
|
+
export declare function documentFonts(archive: ZipArchive): DocumentFont[];
|
|
16
|
+
/**
|
|
17
|
+
* One diagnostic per font the converter will replace: info when a metric-compatible family stands
|
|
18
|
+
* in, a warning otherwise, because the layout will differ (Aptos, Office's default since 2024, has no
|
|
19
|
+
* free substitute).
|
|
20
|
+
*/
|
|
21
|
+
export declare function fontDiagnostics(fonts: readonly DocumentFont[], installed: readonly string[], part?: string): OfficeDiagnostic[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { OfficeDiagnostic } from './tags.js';
|
|
2
|
+
import { type ZipArchive } from './zip.js';
|
|
3
|
+
/**
|
|
4
|
+
* Fonts an office document uses and whether the converter has them (spec 22 §4.6). A converted
|
|
5
|
+
* document renders only with fonts the sidecar has or the document embeds; the list of installed
|
|
6
|
+
* families is passed in (`OFFICE_FONT_FAMILIES` in `@formfeed/api-types`, generated from the image),
|
|
7
|
+
* so the engine stays free of that dependency.
|
|
8
|
+
*/
|
|
9
|
+
export interface DocumentFont {
|
|
10
|
+
name: string;
|
|
11
|
+
embedded: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Office fonts LibreOffice replaces with a family of the same metrics, so lines break the same. */
|
|
14
|
+
export declare const METRIC_COMPATIBLE: Readonly<Record<string, string>>;
|
|
15
|
+
export declare function documentFonts(archive: ZipArchive): DocumentFont[];
|
|
16
|
+
/**
|
|
17
|
+
* One diagnostic per font the converter will replace: info when a metric-compatible family stands
|
|
18
|
+
* in, a warning otherwise, because the layout will differ (Aptos, Office's default since 2024, has no
|
|
19
|
+
* free substitute).
|
|
20
|
+
*/
|
|
21
|
+
export declare function fontDiagnostics(fonts: readonly DocumentFont[], installed: readonly string[], part?: string): OfficeDiagnostic[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function makeIdsUnique(xml: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function makeIdsUnique(xml: string): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@formfeed/engine/office`: the office container code of spec 22 (ZIP, format detection, the checks
|
|
3
|
+
* and the sanitiser of §2.1). No template engine is imported here, so the gateway Worker can use it
|
|
4
|
+
* without bundling Nunjucks, Liquid or Handlebars.
|
|
5
|
+
*/
|
|
6
|
+
export { OfficeError, officeLimits, type OfficeErrorCode } from './errors.cjs';
|
|
7
|
+
export { cfbStreamNames, detectOfficeFormat, hasDoctype, isHtml, isMacroPart, officeContentTypes, officeFormats, type DetectedOffice, type OdfFormat, type OfficeFormat, type OoxmlFormat, } from './detect.cjs';
|
|
8
|
+
export { parseAttributes, remoteResourceCount, removeExternalRelationships, sanitiseForConversion, type RemovedRelationship, type SanitisedDocument, } from './sanitise.cjs';
|
|
9
|
+
export { STRUCTURAL_ELEMENT, applyStructure, blockRole, dropTaggedFallbacks, type StructuredPart } from './structure.cjs';
|
|
10
|
+
export { makeIdsUnique } from './ids.cjs';
|
|
11
|
+
export { starterDocument } from './starter.cjs';
|
|
12
|
+
export { starterPresentation } from './starter-pptx.cjs';
|
|
13
|
+
export { officeDrawingLimits, type OfficeImageHost } from './drawings.cjs';
|
|
14
|
+
export { METRIC_COMPATIBLE, documentFonts, fontDiagnostics, type DocumentFont } from './fonts.cjs';
|
|
15
|
+
export { findTags, listTags, normaliseTags, paragraphAtSource, undoAutocorrect, type NormalisedTags, type OfficeDiagnostic, type OfficeDiagnosticCode, type OfficeTag, } from './tags.cjs';
|
|
16
|
+
export { createNonce, fromTemplateOutput, layoutText, toTemplateSource, type FilledPart, type TemplateSource, type TextFlavour, } from './template-text.cjs';
|
|
17
|
+
export { assertWellFormed, decodeText, escapeText, stripForbidden, tokenize, type XmlToken } from './xml.cjs';
|
|
18
|
+
export { crc32, decodeXml, isSafeEntryName, isZip, readEntry, readText, readZip, writeZip, type ZipArchive, type ZipEntry, type ZipLimits, type ZipWriteEntry, } from './zip.cjs';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@formfeed/engine/office`: the office container code of spec 22 (ZIP, format detection, the checks
|
|
3
|
+
* and the sanitiser of §2.1). No template engine is imported here, so the gateway Worker can use it
|
|
4
|
+
* without bundling Nunjucks, Liquid or Handlebars.
|
|
5
|
+
*/
|
|
6
|
+
export { OfficeError, officeLimits, type OfficeErrorCode } from './errors.js';
|
|
7
|
+
export { cfbStreamNames, detectOfficeFormat, hasDoctype, isHtml, isMacroPart, officeContentTypes, officeFormats, type DetectedOffice, type OdfFormat, type OfficeFormat, type OoxmlFormat, } from './detect.js';
|
|
8
|
+
export { parseAttributes, remoteResourceCount, removeExternalRelationships, sanitiseForConversion, type RemovedRelationship, type SanitisedDocument, } from './sanitise.js';
|
|
9
|
+
export { STRUCTURAL_ELEMENT, applyStructure, blockRole, dropTaggedFallbacks, type StructuredPart } from './structure.js';
|
|
10
|
+
export { makeIdsUnique } from './ids.js';
|
|
11
|
+
export { starterDocument } from './starter.js';
|
|
12
|
+
export { starterPresentation } from './starter-pptx.js';
|
|
13
|
+
export { officeDrawingLimits, type OfficeImageHost } from './drawings.js';
|
|
14
|
+
export { METRIC_COMPATIBLE, documentFonts, fontDiagnostics, type DocumentFont } from './fonts.js';
|
|
15
|
+
export { findTags, listTags, normaliseTags, paragraphAtSource, undoAutocorrect, type NormalisedTags, type OfficeDiagnostic, type OfficeDiagnosticCode, type OfficeTag, } from './tags.js';
|
|
16
|
+
export { createNonce, fromTemplateOutput, layoutText, toTemplateSource, type FilledPart, type TemplateSource, type TextFlavour, } from './template-text.js';
|
|
17
|
+
export { assertWellFormed, decodeText, escapeText, stripForbidden, tokenize, type XmlToken } from './xml.js';
|
|
18
|
+
export { crc32, decodeXml, isSafeEntryName, isZip, readEntry, readText, readZip, writeZip, type ZipArchive, type ZipEntry, type ZipLimits, type ZipWriteEntry, } from './zip.js';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { EngineSyntaxError, RenderError } from '../errors.cjs';
|
|
2
|
+
import type { EngineId, RenderContext, VariableRef } from '../types.cjs';
|
|
3
|
+
import { type OfficeImageHost } from './drawings.cjs';
|
|
4
|
+
import { type DocumentFont } from './fonts.cjs';
|
|
5
|
+
import { type OfficeDiagnostic, type OfficeTag } from './tags.cjs';
|
|
6
|
+
/**
|
|
7
|
+
* Fills an office template (spec 22 §4.3): the office counterpart of `renderVersion`, the same code in
|
|
8
|
+
* the browser (quick preview) and the render-worker. Imports the template engines, so it lives in the
|
|
9
|
+
* main entry, not in `@formfeed/engine/office`.
|
|
10
|
+
*/
|
|
11
|
+
export interface OfficeRenderOptions {
|
|
12
|
+
engine: EngineId;
|
|
13
|
+
data: unknown;
|
|
14
|
+
/** Locale, helpers and limits as for HTML templates; `mode` is set to `office` here. */
|
|
15
|
+
context: RenderContext;
|
|
16
|
+
/** For tests: the source of the placeholder nonce. */
|
|
17
|
+
random?: () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Loads and draws pictures for `image`, `qrcode`, `barcode` and `epcQr` (spec 22 §4.4): the
|
|
20
|
+
* render-worker's asset cache and Chromium, or the browser's fetch and canvas. Without one, only
|
|
21
|
+
* PNG and JPEG data URLs are placed and everything else becomes a warning.
|
|
22
|
+
*/
|
|
23
|
+
images?: OfficeImageHost;
|
|
24
|
+
}
|
|
25
|
+
export interface OfficeRenderResult {
|
|
26
|
+
bytes: Uint8Array;
|
|
27
|
+
format: 'docx' | 'pptx';
|
|
28
|
+
warnings: string[];
|
|
29
|
+
/** Info and warnings; errors throw `OfficeTemplateError` instead. */
|
|
30
|
+
diagnostics: OfficeDiagnostic[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A template that cannot be filled as written; the diagnostics say where. An engine's syntax or
|
|
34
|
+
* runtime error travels as `cause`, so callers can tell the two apart.
|
|
35
|
+
*/
|
|
36
|
+
export declare class OfficeTemplateError extends Error {
|
|
37
|
+
readonly diagnostics: OfficeDiagnostic[];
|
|
38
|
+
readonly part?: string | undefined;
|
|
39
|
+
readonly cause?: (EngineSyntaxError | RenderError) | undefined;
|
|
40
|
+
constructor(message: string, diagnostics: OfficeDiagnostic[], part?: string | undefined, cause?: (EngineSyntaxError | RenderError) | undefined);
|
|
41
|
+
/** `template_syntax_error` or `template_runtime_error`, as the API reports it. */
|
|
42
|
+
get code(): 'template_syntax_error' | 'template_runtime_error';
|
|
43
|
+
}
|
|
44
|
+
/** Filled parts together may not exceed this before zipping (spec 22 §4.3 step 6). */
|
|
45
|
+
export declare const OFFICE_FILLED_MAX_BYTES: number;
|
|
46
|
+
/** A diagnostic of the office template page: the office checks' codes, or an engine's. */
|
|
47
|
+
export type OfficeAnalysisDiagnostic = Omit<OfficeDiagnostic, 'code'> & {
|
|
48
|
+
code: string;
|
|
49
|
+
};
|
|
50
|
+
export interface OfficeAnalysis {
|
|
51
|
+
format: 'docx' | 'pptx';
|
|
52
|
+
/** Every tag, in part and document order. */
|
|
53
|
+
tags: OfficeTag[];
|
|
54
|
+
/** Structure, tag and engine diagnostics, and the fonts the converter replaces. */
|
|
55
|
+
diagnostics: OfficeAnalysisDiagnostic[];
|
|
56
|
+
/** Data paths the template reads, for the schema and data panels. */
|
|
57
|
+
variables: Array<Pick<VariableRef, 'path' | 'kind'>>;
|
|
58
|
+
fonts: DocumentFont[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `analyze` over an office template (spec 22 §4.3, §6): what the office template page lists. The
|
|
62
|
+
* engine analyses each part's template text, and its positions are turned into paragraphs, because
|
|
63
|
+
* a line of the extracted text means nothing to someone looking at the document. Throws `OfficeError`
|
|
64
|
+
* for a file that is not a Word or PowerPoint template.
|
|
65
|
+
*/
|
|
66
|
+
export declare function analyzeOffice(file: Uint8Array, options: {
|
|
67
|
+
engine: EngineId;
|
|
68
|
+
sampleData?: unknown;
|
|
69
|
+
installedFonts?: readonly string[];
|
|
70
|
+
}): OfficeAnalysis;
|
|
71
|
+
/**
|
|
72
|
+
* The parts a template can fill (body, headers, footers and notes of Word; slides and notes of
|
|
73
|
+
* PowerPoint) with their XML, in archive order: what the dev kit's snapshots compare.
|
|
74
|
+
*/
|
|
75
|
+
export declare function officeTextParts(file: Uint8Array): Array<{
|
|
76
|
+
name: string;
|
|
77
|
+
xml: string;
|
|
78
|
+
}>;
|
|
79
|
+
export declare function renderOffice(file: Uint8Array, options: OfficeRenderOptions): Promise<OfficeRenderResult>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { EngineSyntaxError, RenderError } from '../errors.js';
|
|
2
|
+
import type { EngineId, RenderContext, VariableRef } from '../types.js';
|
|
3
|
+
import { type OfficeImageHost } from './drawings.js';
|
|
4
|
+
import { type DocumentFont } from './fonts.js';
|
|
5
|
+
import { type OfficeDiagnostic, type OfficeTag } from './tags.js';
|
|
6
|
+
/**
|
|
7
|
+
* Fills an office template (spec 22 §4.3): the office counterpart of `renderVersion`, the same code in
|
|
8
|
+
* the browser (quick preview) and the render-worker. Imports the template engines, so it lives in the
|
|
9
|
+
* main entry, not in `@formfeed/engine/office`.
|
|
10
|
+
*/
|
|
11
|
+
export interface OfficeRenderOptions {
|
|
12
|
+
engine: EngineId;
|
|
13
|
+
data: unknown;
|
|
14
|
+
/** Locale, helpers and limits as for HTML templates; `mode` is set to `office` here. */
|
|
15
|
+
context: RenderContext;
|
|
16
|
+
/** For tests: the source of the placeholder nonce. */
|
|
17
|
+
random?: () => number;
|
|
18
|
+
/**
|
|
19
|
+
* Loads and draws pictures for `image`, `qrcode`, `barcode` and `epcQr` (spec 22 §4.4): the
|
|
20
|
+
* render-worker's asset cache and Chromium, or the browser's fetch and canvas. Without one, only
|
|
21
|
+
* PNG and JPEG data URLs are placed and everything else becomes a warning.
|
|
22
|
+
*/
|
|
23
|
+
images?: OfficeImageHost;
|
|
24
|
+
}
|
|
25
|
+
export interface OfficeRenderResult {
|
|
26
|
+
bytes: Uint8Array;
|
|
27
|
+
format: 'docx' | 'pptx';
|
|
28
|
+
warnings: string[];
|
|
29
|
+
/** Info and warnings; errors throw `OfficeTemplateError` instead. */
|
|
30
|
+
diagnostics: OfficeDiagnostic[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A template that cannot be filled as written; the diagnostics say where. An engine's syntax or
|
|
34
|
+
* runtime error travels as `cause`, so callers can tell the two apart.
|
|
35
|
+
*/
|
|
36
|
+
export declare class OfficeTemplateError extends Error {
|
|
37
|
+
readonly diagnostics: OfficeDiagnostic[];
|
|
38
|
+
readonly part?: string | undefined;
|
|
39
|
+
readonly cause?: (EngineSyntaxError | RenderError) | undefined;
|
|
40
|
+
constructor(message: string, diagnostics: OfficeDiagnostic[], part?: string | undefined, cause?: (EngineSyntaxError | RenderError) | undefined);
|
|
41
|
+
/** `template_syntax_error` or `template_runtime_error`, as the API reports it. */
|
|
42
|
+
get code(): 'template_syntax_error' | 'template_runtime_error';
|
|
43
|
+
}
|
|
44
|
+
/** Filled parts together may not exceed this before zipping (spec 22 §4.3 step 6). */
|
|
45
|
+
export declare const OFFICE_FILLED_MAX_BYTES: number;
|
|
46
|
+
/** A diagnostic of the office template page: the office checks' codes, or an engine's. */
|
|
47
|
+
export type OfficeAnalysisDiagnostic = Omit<OfficeDiagnostic, 'code'> & {
|
|
48
|
+
code: string;
|
|
49
|
+
};
|
|
50
|
+
export interface OfficeAnalysis {
|
|
51
|
+
format: 'docx' | 'pptx';
|
|
52
|
+
/** Every tag, in part and document order. */
|
|
53
|
+
tags: OfficeTag[];
|
|
54
|
+
/** Structure, tag and engine diagnostics, and the fonts the converter replaces. */
|
|
55
|
+
diagnostics: OfficeAnalysisDiagnostic[];
|
|
56
|
+
/** Data paths the template reads, for the schema and data panels. */
|
|
57
|
+
variables: Array<Pick<VariableRef, 'path' | 'kind'>>;
|
|
58
|
+
fonts: DocumentFont[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `analyze` over an office template (spec 22 §4.3, §6): what the office template page lists. The
|
|
62
|
+
* engine analyses each part's template text, and its positions are turned into paragraphs, because
|
|
63
|
+
* a line of the extracted text means nothing to someone looking at the document. Throws `OfficeError`
|
|
64
|
+
* for a file that is not a Word or PowerPoint template.
|
|
65
|
+
*/
|
|
66
|
+
export declare function analyzeOffice(file: Uint8Array, options: {
|
|
67
|
+
engine: EngineId;
|
|
68
|
+
sampleData?: unknown;
|
|
69
|
+
installedFonts?: readonly string[];
|
|
70
|
+
}): OfficeAnalysis;
|
|
71
|
+
/**
|
|
72
|
+
* The parts a template can fill (body, headers, footers and notes of Word; slides and notes of
|
|
73
|
+
* PowerPoint) with their XML, in archive order: what the dev kit's snapshots compare.
|
|
74
|
+
*/
|
|
75
|
+
export declare function officeTextParts(file: Uint8Array): Array<{
|
|
76
|
+
name: string;
|
|
77
|
+
xml: string;
|
|
78
|
+
}>;
|
|
79
|
+
export declare function renderOffice(file: Uint8Array, options: OfficeRenderOptions): Promise<OfficeRenderResult>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type OfficeFormat } from './detect.cjs';
|
|
2
|
+
/**
|
|
3
|
+
* Prepares a customer document for LibreOffice (spec 22 §2.1). Detection and the container checks
|
|
4
|
+
* run first; then every XML part is checked for a DOCTYPE, and OOXML relationship parts lose their
|
|
5
|
+
* external relationships except hyperlinks, so nothing in the document asks LibreOffice to load a
|
|
6
|
+
* remote or local resource. The sidecar refuses such loads as well; this is the layer we control.
|
|
7
|
+
*/
|
|
8
|
+
export interface RemovedRelationship {
|
|
9
|
+
part: string;
|
|
10
|
+
id: string;
|
|
11
|
+
type: string;
|
|
12
|
+
target: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SanitisedDocument {
|
|
15
|
+
format: OfficeFormat;
|
|
16
|
+
/** The input itself when nothing had to change. */
|
|
17
|
+
bytes: Uint8Array;
|
|
18
|
+
removed: RemovedRelationship[];
|
|
19
|
+
/** What the customer should know about the conversion, for the render's warnings. */
|
|
20
|
+
notes: string[];
|
|
21
|
+
}
|
|
22
|
+
/** How many remote resources an HTML document references; they stay empty in the PDF. */
|
|
23
|
+
export declare function remoteResourceCount(html: string): number;
|
|
24
|
+
export declare function sanitiseForConversion(bytes: Uint8Array): SanitisedDocument;
|
|
25
|
+
/**
|
|
26
|
+
* Removes every `<Relationship TargetMode="External">` whose type is not a hyperlink. An allowlist,
|
|
27
|
+
* not a list of loading types: a type we do not know is not one we let LibreOffice resolve.
|
|
28
|
+
* References to a removed id stay in the source part; LibreOffice skips a relationship it cannot
|
|
29
|
+
* find, which the sidecar tests keep proven.
|
|
30
|
+
*/
|
|
31
|
+
export declare function removeExternalRelationships(xml: string): {
|
|
32
|
+
xml: string;
|
|
33
|
+
removed: Omit<RemovedRelationship, 'part'>[];
|
|
34
|
+
};
|
|
35
|
+
export declare function parseAttributes(source: string): Record<string, string>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type OfficeFormat } from './detect.js';
|
|
2
|
+
/**
|
|
3
|
+
* Prepares a customer document for LibreOffice (spec 22 §2.1). Detection and the container checks
|
|
4
|
+
* run first; then every XML part is checked for a DOCTYPE, and OOXML relationship parts lose their
|
|
5
|
+
* external relationships except hyperlinks, so nothing in the document asks LibreOffice to load a
|
|
6
|
+
* remote or local resource. The sidecar refuses such loads as well; this is the layer we control.
|
|
7
|
+
*/
|
|
8
|
+
export interface RemovedRelationship {
|
|
9
|
+
part: string;
|
|
10
|
+
id: string;
|
|
11
|
+
type: string;
|
|
12
|
+
target: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SanitisedDocument {
|
|
15
|
+
format: OfficeFormat;
|
|
16
|
+
/** The input itself when nothing had to change. */
|
|
17
|
+
bytes: Uint8Array;
|
|
18
|
+
removed: RemovedRelationship[];
|
|
19
|
+
/** What the customer should know about the conversion, for the render's warnings. */
|
|
20
|
+
notes: string[];
|
|
21
|
+
}
|
|
22
|
+
/** How many remote resources an HTML document references; they stay empty in the PDF. */
|
|
23
|
+
export declare function remoteResourceCount(html: string): number;
|
|
24
|
+
export declare function sanitiseForConversion(bytes: Uint8Array): SanitisedDocument;
|
|
25
|
+
/**
|
|
26
|
+
* Removes every `<Relationship TargetMode="External">` whose type is not a hyperlink. An allowlist,
|
|
27
|
+
* not a list of loading types: a type we do not know is not one we let LibreOffice resolve.
|
|
28
|
+
* References to a removed id stay in the source part; LibreOffice skips a relationship it cannot
|
|
29
|
+
* find, which the sidecar tests keep proven.
|
|
30
|
+
*/
|
|
31
|
+
export declare function removeExternalRelationships(xml: string): {
|
|
32
|
+
xml: string;
|
|
33
|
+
removed: Omit<RemovedRelationship, 'part'>[];
|
|
34
|
+
};
|
|
35
|
+
export declare function parseAttributes(source: string): Record<string, string>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ResolvedDrawing } from './drawings.cjs';
|
|
2
|
+
/**
|
|
3
|
+
* Pictures on slides (spec 22 §10 step 7). A slide cannot hold a picture inside text, so a drawing
|
|
4
|
+
* placeholder in a text box becomes a picture shape (`p:pic`) beside it:
|
|
5
|
+
*
|
|
6
|
+
* - a text box that holds nothing but drawings is replaced by them, placed in its box, so a member
|
|
7
|
+
* draws a box where the code goes and types `{{ qrcode(url) }}` into it;
|
|
8
|
+
* - otherwise the placeholder is removed from the text and the picture is placed over the box, in
|
|
9
|
+
* front of the text;
|
|
10
|
+
* - a picture without a size of its own is fitted into the box, keeping its aspect; several pictures
|
|
11
|
+
* share the box from top to bottom. A box that grows with its text (`a:spAutoFit`, PowerPoint's
|
|
12
|
+
* default for text boxes) is only as high as one line, so there the width alone decides;
|
|
13
|
+
* - a shape whose position comes from the slide layout (no `a:xfrm` of its own) puts the pictures in
|
|
14
|
+
* the middle of the slide.
|
|
15
|
+
*/
|
|
16
|
+
export interface SlideBox {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
cx: number;
|
|
20
|
+
cy: number;
|
|
21
|
+
}
|
|
22
|
+
/** `p:sldSz` of `ppt/presentation.xml`; 16:9 at 33.867 cm by 19.05 cm when it names none. */
|
|
23
|
+
export declare function slideSize(presentation: string | null): {
|
|
24
|
+
cx: number;
|
|
25
|
+
cy: number;
|
|
26
|
+
};
|
|
27
|
+
/** A picture shape, with the namespaces it uses declared on itself. */
|
|
28
|
+
export declare function slidePicture(picture: Extract<ResolvedDrawing, {
|
|
29
|
+
kind: 'picture';
|
|
30
|
+
}>, rId: string, id: number, box: SlideBox): string;
|
|
31
|
+
/** Where each picture goes: its own size or fitted into its share of the box, centred in it. */
|
|
32
|
+
export declare function layoutPictures(pictures: ReadonlyArray<Extract<ResolvedDrawing, {
|
|
33
|
+
kind: 'picture';
|
|
34
|
+
}>>, box: SlideBox, growsWithText?: boolean): SlideBox[];
|
|
35
|
+
/**
|
|
36
|
+
* Replaces the drawing placeholders of a filled slide (or notes) part with picture shapes. `picture`
|
|
37
|
+
* returns the placed markup for a resolved drawing, with its relationship and id.
|
|
38
|
+
*/
|
|
39
|
+
export declare function placeSlidePictures(xml: string, pattern: RegExp, drawingFor: (index: number) => ResolvedDrawing | undefined, pictureMarkup: (picture: Extract<ResolvedDrawing, {
|
|
40
|
+
kind: 'picture';
|
|
41
|
+
}>, box: SlideBox) => string, slide: {
|
|
42
|
+
cx: number;
|
|
43
|
+
cy: number;
|
|
44
|
+
}): {
|
|
45
|
+
xml: string;
|
|
46
|
+
warnings: string[];
|
|
47
|
+
};
|