@qvac/harness 0.7.2 → 0.8.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/CHANGELOG.md +70 -1
- package/NOTICE.md +16 -0
- package/dist-lib/lib/capabilities/completion.d.ts +1 -0
- package/dist-lib/lib/capabilities/completion.js +46 -8
- package/dist-lib/lib/capabilities/tool-turns.d.ts +3 -0
- package/dist-lib/lib/capabilities/tool-turns.js +7 -0
- package/dist-lib/lib/context-window.js +2 -2
- package/dist-lib/lib/helpers/run-outcome.d.ts +4 -1
- package/dist-lib/lib/helpers/run-outcome.js +14 -8
- package/dist-lib/lib/helpers/tool-call-markup.js +4 -4
- package/dist-lib/lib/hooks/built-in/arg-repair.js +7 -0
- package/dist-lib/lib/office/engine/codes.d.ts +62 -0
- package/dist-lib/lib/office/engine/codes.js +61 -0
- package/dist-lib/lib/office/engine/docx/document.d.ts +216 -0
- package/dist-lib/lib/office/engine/docx/document.js +1152 -0
- package/dist-lib/lib/office/engine/docx/index.d.ts +7 -0
- package/dist-lib/lib/office/engine/docx/index.js +8 -0
- package/dist-lib/lib/office/engine/docx/styles.d.ts +31 -0
- package/dist-lib/lib/office/engine/docx/styles.js +173 -0
- package/dist-lib/lib/office/engine/docx/template.d.ts +18 -0
- package/dist-lib/lib/office/engine/docx/template.js +133 -0
- package/dist-lib/lib/office/engine/docx/text.d.ts +55 -0
- package/dist-lib/lib/office/engine/docx/text.js +538 -0
- package/dist-lib/lib/office/engine/drawingml/chart.d.ts +63 -0
- package/dist-lib/lib/office/engine/drawingml/chart.js +539 -0
- package/dist-lib/lib/office/engine/drawingml/text.d.ts +35 -0
- package/dist-lib/lib/office/engine/drawingml/text.js +352 -0
- package/dist-lib/lib/office/engine/errors.d.ts +6 -0
- package/dist-lib/lib/office/engine/errors.js +12 -0
- package/dist-lib/lib/office/engine/image.d.ts +8 -0
- package/dist-lib/lib/office/engine/image.js +48 -0
- package/dist-lib/lib/office/engine/index.d.ts +12 -0
- package/dist-lib/lib/office/engine/index.js +7 -0
- package/dist-lib/lib/office/engine/opc/content-types.d.ts +17 -0
- package/dist-lib/lib/office/engine/opc/content-types.js +74 -0
- package/dist-lib/lib/office/engine/opc/media.d.ts +13 -0
- package/dist-lib/lib/office/engine/opc/media.js +11 -0
- package/dist-lib/lib/office/engine/opc/package.d.ts +51 -0
- package/dist-lib/lib/office/engine/opc/package.js +324 -0
- package/dist-lib/lib/office/engine/opc/paths.d.ts +7 -0
- package/dist-lib/lib/office/engine/opc/paths.js +46 -0
- package/dist-lib/lib/office/engine/opc/properties.d.ts +7 -0
- package/dist-lib/lib/office/engine/opc/properties.js +75 -0
- package/dist-lib/lib/office/engine/opc/relationships.d.ts +23 -0
- package/dist-lib/lib/office/engine/opc/relationships.js +65 -0
- package/dist-lib/lib/office/engine/opc/zip.d.ts +15 -0
- package/dist-lib/lib/office/engine/opc/zip.js +264 -0
- package/dist-lib/lib/office/engine/pptx/fit.d.ts +12 -0
- package/dist-lib/lib/office/engine/pptx/fit.js +37 -0
- package/dist-lib/lib/office/engine/pptx/index.d.ts +8 -0
- package/dist-lib/lib/office/engine/pptx/index.js +8 -0
- package/dist-lib/lib/office/engine/pptx/inherit.d.ts +29 -0
- package/dist-lib/lib/office/engine/pptx/inherit.js +155 -0
- package/dist-lib/lib/office/engine/pptx/notes.d.ts +5 -0
- package/dist-lib/lib/office/engine/pptx/notes.js +85 -0
- package/dist-lib/lib/office/engine/pptx/presentation.d.ts +54 -0
- package/dist-lib/lib/office/engine/pptx/presentation.js +749 -0
- package/dist-lib/lib/office/engine/pptx/read.d.ts +9 -0
- package/dist-lib/lib/office/engine/pptx/read.js +66 -0
- package/dist-lib/lib/office/engine/pptx/shapes.d.ts +52 -0
- package/dist-lib/lib/office/engine/pptx/shapes.js +276 -0
- package/dist-lib/lib/office/engine/pptx/slides.d.ts +27 -0
- package/dist-lib/lib/office/engine/pptx/slides.js +123 -0
- package/dist-lib/lib/office/engine/pptx/template.d.ts +20 -0
- package/dist-lib/lib/office/engine/pptx/template.js +391 -0
- package/dist-lib/lib/office/engine/pptx/types.d.ts +120 -0
- package/dist-lib/lib/office/engine/pptx/types.js +1 -0
- package/dist-lib/lib/office/engine/units.d.ts +3 -0
- package/dist-lib/lib/office/engine/units.js +12 -0
- package/dist-lib/lib/office/engine/utf8.d.ts +2 -0
- package/dist-lib/lib/office/engine/utf8.js +103 -0
- package/dist-lib/lib/office/engine/xlsx/formula.d.ts +49 -0
- package/dist-lib/lib/office/engine/xlsx/formula.js +381 -0
- package/dist-lib/lib/office/engine/xlsx/index.d.ts +8 -0
- package/dist-lib/lib/office/engine/xlsx/index.js +8 -0
- package/dist-lib/lib/office/engine/xlsx/refs.d.ts +22 -0
- package/dist-lib/lib/office/engine/xlsx/refs.js +82 -0
- package/dist-lib/lib/office/engine/xlsx/reshape.d.ts +21 -0
- package/dist-lib/lib/office/engine/xlsx/reshape.js +424 -0
- package/dist-lib/lib/office/engine/xlsx/sheet.d.ts +108 -0
- package/dist-lib/lib/office/engine/xlsx/sheet.js +662 -0
- package/dist-lib/lib/office/engine/xlsx/strings.d.ts +15 -0
- package/dist-lib/lib/office/engine/xlsx/strings.js +93 -0
- package/dist-lib/lib/office/engine/xlsx/styles.d.ts +38 -0
- package/dist-lib/lib/office/engine/xlsx/styles.js +369 -0
- package/dist-lib/lib/office/engine/xlsx/template.d.ts +7 -0
- package/dist-lib/lib/office/engine/xlsx/template.js +54 -0
- package/dist-lib/lib/office/engine/xlsx/workbook.d.ts +161 -0
- package/dist-lib/lib/office/engine/xlsx/workbook.js +850 -0
- package/dist-lib/lib/office/engine/xlsx/write.d.ts +2 -0
- package/dist-lib/lib/office/engine/xlsx/write.js +42 -0
- package/dist-lib/lib/office/engine/xml.d.ts +45 -0
- package/dist-lib/lib/office/engine/xml.js +258 -0
- package/dist-lib/lib/tools/exec/scope.d.ts +2 -0
- package/dist-lib/lib/tools/exec/scope.js +33 -2
- package/dist-lib/lib/tools/pdf/build.d.ts +43 -0
- package/dist-lib/lib/tools/pdf/build.js +150 -0
- package/dist-lib/lib/tools/pdf/images.d.ts +7 -0
- package/dist-lib/lib/tools/pdf/images.js +82 -0
- package/dist-lib/lib/tools/pdf/request.d.ts +63 -0
- package/dist-lib/lib/tools/pdf/request.js +335 -0
- package/dist-lib/lib/tools/pdf.d.ts +6 -0
- package/dist-lib/lib/tools/pdf.js +302 -0
- package/dist-lib/lib/tools/skill.js +14 -0
- package/dist-lib/lib/tools/weather-lookup/geocode.d.ts +26 -0
- package/dist-lib/lib/tools/weather-lookup/geocode.js +110 -0
- package/dist-lib/lib/tools/weather-lookup/place.js +5 -1
- package/dist-lib/lib/tools/weather-lookup.d.ts +2 -1
- package/dist-lib/lib/tools/weather-lookup.js +115 -84
- package/package.json +29 -1
- package/worker/harness-sidecar.mjs +3 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Document } from './document.ts';
|
|
2
|
+
import type { OpenOptions } from '../opc/package.ts';
|
|
3
|
+
import type { CreateOptions } from './template.ts';
|
|
4
|
+
export { Document } from './document.ts';
|
|
5
|
+
export type * from './document.ts';
|
|
6
|
+
export declare function open(bytes: Uint8Array | ArrayBuffer, opts?: OpenOptions): Document;
|
|
7
|
+
export declare function create(opts?: CreateOptions): Document;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Document, Element } from '../xml.ts';
|
|
2
|
+
import type { Package } from '../opc/package.ts';
|
|
3
|
+
export interface StyleInfo {
|
|
4
|
+
el: Element;
|
|
5
|
+
id: string;
|
|
6
|
+
type: string;
|
|
7
|
+
name: string;
|
|
8
|
+
isDefault: boolean;
|
|
9
|
+
basedOn: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface FormattedStyle {
|
|
12
|
+
style: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class Styles {
|
|
15
|
+
package: Package;
|
|
16
|
+
part: string | null;
|
|
17
|
+
constructor(pkg: Package, part: string | null);
|
|
18
|
+
get doc(): Document | null;
|
|
19
|
+
all(): StyleInfo[];
|
|
20
|
+
names(type?: string): string[];
|
|
21
|
+
byId(id: string | null): StyleInfo | null;
|
|
22
|
+
resolve(ref: unknown, type?: string): StyleInfo | null;
|
|
23
|
+
require(ref: unknown, type?: string): StyleInfo;
|
|
24
|
+
defaultParagraph(): StyleInfo | null;
|
|
25
|
+
nameOf(styleId: string | null): string;
|
|
26
|
+
headingLevel(styleId: string | null): number | null;
|
|
27
|
+
numIdOf(styleId: string | null): string | null;
|
|
28
|
+
isList(styleId: string | null): boolean;
|
|
29
|
+
format(ref: unknown, input: unknown): FormattedStyle;
|
|
30
|
+
private chain;
|
|
31
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import * as xml from '../xml.js';
|
|
2
|
+
import * as text from './text.js';
|
|
3
|
+
import { DocsError } from '../errors.js';
|
|
4
|
+
const W = xml.ns.w;
|
|
5
|
+
const STYLE_ORDER = [
|
|
6
|
+
'name',
|
|
7
|
+
'aliases',
|
|
8
|
+
'basedOn',
|
|
9
|
+
'next',
|
|
10
|
+
'link',
|
|
11
|
+
'autoRedefine',
|
|
12
|
+
'hidden',
|
|
13
|
+
'uiPriority',
|
|
14
|
+
'semiHidden',
|
|
15
|
+
'unhideWhenUsed',
|
|
16
|
+
'qFormat',
|
|
17
|
+
'locked',
|
|
18
|
+
'personal',
|
|
19
|
+
'personalCompose',
|
|
20
|
+
'personalReply',
|
|
21
|
+
'rsid',
|
|
22
|
+
'pPr',
|
|
23
|
+
'rPr',
|
|
24
|
+
'tblPr',
|
|
25
|
+
'trPr',
|
|
26
|
+
'tcPr',
|
|
27
|
+
'tblStylePr'
|
|
28
|
+
];
|
|
29
|
+
function displayName(name) {
|
|
30
|
+
if (name !== name.toLowerCase())
|
|
31
|
+
return name;
|
|
32
|
+
return name.replace(/(^|\s)\S/g, (c) => c.toUpperCase());
|
|
33
|
+
}
|
|
34
|
+
function wVal(el) {
|
|
35
|
+
return el ? el.getAttributeNS(W, 'val') : null;
|
|
36
|
+
}
|
|
37
|
+
export class Styles {
|
|
38
|
+
package;
|
|
39
|
+
part;
|
|
40
|
+
constructor(pkg, part) {
|
|
41
|
+
this.package = pkg;
|
|
42
|
+
this.part = part;
|
|
43
|
+
}
|
|
44
|
+
get doc() {
|
|
45
|
+
return this.part ? this.package.xml(this.part) : null;
|
|
46
|
+
}
|
|
47
|
+
all() {
|
|
48
|
+
const doc = this.doc;
|
|
49
|
+
if (!doc) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
return xml.children(xml.root(doc), W, 'style').map((el) => {
|
|
53
|
+
const id = text.wGet(el, 'styleId');
|
|
54
|
+
const name = wVal(xml.child(el, W, 'name')) || id;
|
|
55
|
+
return {
|
|
56
|
+
el,
|
|
57
|
+
id,
|
|
58
|
+
type: text.wGet(el, 'type') || 'paragraph',
|
|
59
|
+
name: displayName(name),
|
|
60
|
+
isDefault: ['1', 'true', 'on'].includes(text.wGet(el, 'default')),
|
|
61
|
+
basedOn: wVal(xml.child(el, W, 'basedOn'))
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
names(type = 'paragraph') {
|
|
66
|
+
return this.all()
|
|
67
|
+
.filter((s) => s.type === type)
|
|
68
|
+
.map((s) => s.name);
|
|
69
|
+
}
|
|
70
|
+
byId(id) {
|
|
71
|
+
return this.all().find((s) => s.id === id) ?? null;
|
|
72
|
+
}
|
|
73
|
+
resolve(ref, type = 'paragraph') {
|
|
74
|
+
const wanted = String(ref).toLowerCase();
|
|
75
|
+
const styles = this.all().filter((s) => s.type === type);
|
|
76
|
+
return (styles.find((s) => s.id === ref) ??
|
|
77
|
+
styles.find((s) => s.name.toLowerCase() === wanted) ??
|
|
78
|
+
styles.find((s) => s.id.toLowerCase() === wanted.replace(/\s+/g, '')) ??
|
|
79
|
+
null);
|
|
80
|
+
}
|
|
81
|
+
require(ref, type = 'paragraph') {
|
|
82
|
+
const style = this.resolve(ref, type);
|
|
83
|
+
if (!style) {
|
|
84
|
+
const names = this.names(type).map((n) => `"${n}"`);
|
|
85
|
+
throw new DocsError('STYLE_NOT_FOUND', `the document has no ${type} style "${String(ref)}"; it has ${names.join(', ') || 'none'}`);
|
|
86
|
+
}
|
|
87
|
+
return style;
|
|
88
|
+
}
|
|
89
|
+
defaultParagraph() {
|
|
90
|
+
return this.all().find((s) => s.type === 'paragraph' && s.isDefault) ?? null;
|
|
91
|
+
}
|
|
92
|
+
nameOf(styleId) {
|
|
93
|
+
const style = styleId ? this.byId(styleId) : this.defaultParagraph();
|
|
94
|
+
if (style) {
|
|
95
|
+
return style.name;
|
|
96
|
+
}
|
|
97
|
+
return styleId || 'Normal';
|
|
98
|
+
}
|
|
99
|
+
headingLevel(styleId) {
|
|
100
|
+
let style = styleId ? this.byId(styleId) : this.defaultParagraph();
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
while (style && !seen.has(style.id)) {
|
|
103
|
+
seen.add(style.id);
|
|
104
|
+
const level = ownHeadingLevel(style);
|
|
105
|
+
if (level !== null) {
|
|
106
|
+
return level;
|
|
107
|
+
}
|
|
108
|
+
style = style.basedOn ? this.byId(style.basedOn) : null;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
numIdOf(styleId) {
|
|
113
|
+
for (const style of this.chain(styleId)) {
|
|
114
|
+
const pPr = xml.child(style.el, W, 'pPr');
|
|
115
|
+
const numPr = pPr ? xml.child(pPr, W, 'numPr') : null;
|
|
116
|
+
const numId = numPr ? wVal(xml.child(numPr, W, 'numId')) : null;
|
|
117
|
+
if (numId) {
|
|
118
|
+
return numId;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
isList(styleId) {
|
|
124
|
+
const numId = this.numIdOf(styleId);
|
|
125
|
+
return numId !== null && numId !== '0';
|
|
126
|
+
}
|
|
127
|
+
format(ref, input) {
|
|
128
|
+
const format = text.validateFormat(input);
|
|
129
|
+
const style = this.require(ref);
|
|
130
|
+
const doc = xml.owner(style.el);
|
|
131
|
+
const { align, ...run } = format;
|
|
132
|
+
if (Object.keys(run).length) {
|
|
133
|
+
const rPr = xml.child(style.el, W, 'rPr') ??
|
|
134
|
+
xml.insertOrdered(style.el, text.wEl(doc, 'rPr'), STYLE_ORDER);
|
|
135
|
+
text.applyRunFormat(rPr, run);
|
|
136
|
+
}
|
|
137
|
+
if (align) {
|
|
138
|
+
const pPr = xml.child(style.el, W, 'pPr') ??
|
|
139
|
+
xml.insertOrdered(style.el, text.wEl(doc, 'pPr'), STYLE_ORDER);
|
|
140
|
+
text.wAttr(text.ensure(pPr, 'jc', text.PARAGRAPH_ORDER), 'val', text.ALIGNMENTS[align]);
|
|
141
|
+
}
|
|
142
|
+
if (this.part) {
|
|
143
|
+
this.package.touch(this.part);
|
|
144
|
+
}
|
|
145
|
+
return { style: style.name };
|
|
146
|
+
}
|
|
147
|
+
chain(styleId) {
|
|
148
|
+
const out = [];
|
|
149
|
+
const seen = new Set();
|
|
150
|
+
let style = styleId ? this.byId(styleId) : null;
|
|
151
|
+
while (style && !seen.has(style.id)) {
|
|
152
|
+
seen.add(style.id);
|
|
153
|
+
out.push(style);
|
|
154
|
+
style = style.basedOn ? this.byId(style.basedOn) : null;
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function ownHeadingLevel(style) {
|
|
160
|
+
const match = /^heading ([1-9])$/i.exec(style.name);
|
|
161
|
+
if (match) {
|
|
162
|
+
return Number(match[1]);
|
|
163
|
+
}
|
|
164
|
+
if (style.name.toLowerCase() === 'title') {
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
const pPr = xml.child(style.el, W, 'pPr');
|
|
168
|
+
const outline = pPr ? wVal(xml.child(pPr, W, 'outlineLvl')) : null;
|
|
169
|
+
if (outline !== null && outline !== '' && Number(outline) < 9) {
|
|
170
|
+
return Number(outline) + 1;
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Package } from '../opc/package.ts';
|
|
2
|
+
export interface Fonts {
|
|
3
|
+
heading: string;
|
|
4
|
+
body: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CreateOptions {
|
|
7
|
+
title?: string;
|
|
8
|
+
page?: 'letter' | 'a4';
|
|
9
|
+
size?: number;
|
|
10
|
+
fonts?: Partial<Fonts>;
|
|
11
|
+
}
|
|
12
|
+
interface Page {
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
}
|
|
16
|
+
export declare const PAGES: Record<string, Page>;
|
|
17
|
+
export declare function build(pkg: Package, input?: unknown): void;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as xml from '../xml.js';
|
|
2
|
+
import { DocsError } from '../errors.js';
|
|
3
|
+
import { isRecord } from '../../../guards.js';
|
|
4
|
+
const W = xml.ns.w;
|
|
5
|
+
const R = xml.ns.r;
|
|
6
|
+
const REL_BASE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';
|
|
7
|
+
const WML = 'application/vnd.openxmlformats-officedocument.wordprocessingml.';
|
|
8
|
+
const TYPES = {
|
|
9
|
+
document: WML + 'document.main+xml',
|
|
10
|
+
styles: WML + 'styles+xml',
|
|
11
|
+
numbering: WML + 'numbering+xml',
|
|
12
|
+
settings: WML + 'settings+xml',
|
|
13
|
+
core: 'application/vnd.openxmlformats-package.core-properties+xml',
|
|
14
|
+
app: 'application/vnd.openxmlformats-officedocument.extended-properties+xml'
|
|
15
|
+
};
|
|
16
|
+
export const PAGES = {
|
|
17
|
+
letter: { width: 12240, height: 15840 },
|
|
18
|
+
a4: { width: 11906, height: 16838 }
|
|
19
|
+
};
|
|
20
|
+
const BULLETS = ['\u2022', 'o', '\u25AA'];
|
|
21
|
+
const BULLET_FONTS = [null, 'Courier New', 'Wingdings'];
|
|
22
|
+
const NUMBER_FORMATS = ['decimal', 'lowerLetter', 'lowerRoman'];
|
|
23
|
+
function escape(value) {
|
|
24
|
+
return String(value)
|
|
25
|
+
.replace(/&/g, '&')
|
|
26
|
+
.replace(/</g, '<')
|
|
27
|
+
.replace(/>/g, '>')
|
|
28
|
+
.replace(/"/g, '"');
|
|
29
|
+
}
|
|
30
|
+
function fontsOf(input) {
|
|
31
|
+
const fonts = { heading: 'Calibri Light', body: 'Calibri' };
|
|
32
|
+
if (isRecord(input)) {
|
|
33
|
+
Object.assign(fonts, input);
|
|
34
|
+
}
|
|
35
|
+
for (const [key, value] of Object.entries(fonts)) {
|
|
36
|
+
if (!['heading', 'body'].includes(key)) {
|
|
37
|
+
throw new DocsError('INVALID_OPTIONS', `unknown font "${key}"; use heading or body`);
|
|
38
|
+
}
|
|
39
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
40
|
+
throw new DocsError('INVALID_OPTIONS', `font ${key} must be a typeface name`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { heading: String(fonts.heading), body: String(fonts.body) };
|
|
44
|
+
}
|
|
45
|
+
function options(opts) {
|
|
46
|
+
const page = PAGES[String(opts.page || 'letter').toLowerCase()];
|
|
47
|
+
if (!page) {
|
|
48
|
+
throw new DocsError('INVALID_OPTIONS', 'page must be "letter" or "a4"');
|
|
49
|
+
}
|
|
50
|
+
const fonts = fontsOf(opts.fonts);
|
|
51
|
+
const size = opts.size === undefined ? 11 : opts.size;
|
|
52
|
+
if (!(typeof size === 'number' && size >= 6 && size <= 72)) {
|
|
53
|
+
throw new DocsError('INVALID_OPTIONS', `size is the body text size in points, from 6 to 72, got ${String(size)}`);
|
|
54
|
+
}
|
|
55
|
+
return { page, fonts, size, title: opts.title };
|
|
56
|
+
}
|
|
57
|
+
function fontsXml(face) {
|
|
58
|
+
const f = escape(face);
|
|
59
|
+
return `<w:rFonts w:ascii="${f}" w:hAnsi="${f}" w:eastAsia="${f}" w:cs="${f}"/>`;
|
|
60
|
+
}
|
|
61
|
+
function heading(style) {
|
|
62
|
+
const { id, name, level, size, color, before } = style;
|
|
63
|
+
return `<w:style w:type="paragraph" w:styleId="${id}"><w:name w:val="${name}"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:uiPriority w:val="9"/><w:qFormat/><w:pPr><w:keepNext/><w:keepLines/><w:spacing w:before="${before}" w:after="0"/><w:outlineLvl w:val="${level}"/></w:pPr><w:rPr>{heading}<w:color w:val="${color}"/><w:sz w:val="${size}"/><w:szCs w:val="${size}"/></w:rPr></w:style>`;
|
|
64
|
+
}
|
|
65
|
+
function stylesXml(fonts, size) {
|
|
66
|
+
const half = Math.round(size * 2);
|
|
67
|
+
const body = fontsXml(fonts.body);
|
|
68
|
+
const head = fontsXml(fonts.heading);
|
|
69
|
+
const styles = [
|
|
70
|
+
`<w:docDefaults><w:rPrDefault><w:rPr>${body}<w:sz w:val="${half}"/><w:szCs w:val="${half}"/><w:lang w:val="en-US"/></w:rPr></w:rPrDefault><w:pPrDefault><w:pPr><w:spacing w:after="160" w:line="259" w:lineRule="auto"/></w:pPr></w:pPrDefault></w:docDefaults>`,
|
|
71
|
+
'<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style>',
|
|
72
|
+
'<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont"><w:name w:val="Default Paragraph Font"/><w:uiPriority w:val="1"/><w:semiHidden/><w:unhideWhenUsed/></w:style>',
|
|
73
|
+
'<w:style w:type="table" w:default="1" w:styleId="TableNormal"><w:name w:val="Normal Table"/><w:uiPriority w:val="99"/><w:semiHidden/><w:unhideWhenUsed/><w:tblPr><w:tblInd w:w="0" w:type="dxa"/><w:tblCellMar><w:top w:w="0" w:type="dxa"/><w:left w:w="108" w:type="dxa"/><w:bottom w:w="0" w:type="dxa"/><w:right w:w="108" w:type="dxa"/></w:tblCellMar></w:tblPr></w:style>',
|
|
74
|
+
'<w:style w:type="numbering" w:default="1" w:styleId="NoList"><w:name w:val="No List"/><w:uiPriority w:val="99"/><w:semiHidden/><w:unhideWhenUsed/></w:style>',
|
|
75
|
+
`<w:style w:type="paragraph" w:styleId="Title"><w:name w:val="Title"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:uiPriority w:val="10"/><w:qFormat/><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/><w:contextualSpacing/></w:pPr><w:rPr>${head}<w:kern w:val="28"/><w:sz w:val="56"/><w:szCs w:val="56"/></w:rPr></w:style>`,
|
|
76
|
+
`<w:style w:type="paragraph" w:styleId="Subtitle"><w:name w:val="Subtitle"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:uiPriority w:val="11"/><w:qFormat/><w:rPr><w:color w:val="5A5A5A"/><w:spacing w:val="15"/><w:sz w:val="${half + 6}"/><w:szCs w:val="${half + 6}"/></w:rPr></w:style>`,
|
|
77
|
+
heading({
|
|
78
|
+
id: 'Heading1',
|
|
79
|
+
name: 'heading 1',
|
|
80
|
+
level: 0,
|
|
81
|
+
size: 32,
|
|
82
|
+
color: '2F5496',
|
|
83
|
+
before: 240
|
|
84
|
+
}),
|
|
85
|
+
heading({ id: 'Heading2', name: 'heading 2', level: 1, size: 26, color: '2F5496', before: 40 }),
|
|
86
|
+
heading({ id: 'Heading3', name: 'heading 3', level: 2, size: 24, color: '1F3763', before: 40 }),
|
|
87
|
+
'<w:style w:type="paragraph" w:styleId="ListBullet"><w:name w:val="List Bullet"/><w:basedOn w:val="Normal"/><w:uiPriority w:val="99"/><w:unhideWhenUsed/><w:qFormat/><w:pPr><w:numPr><w:numId w:val="1"/></w:numPr><w:contextualSpacing/></w:pPr></w:style>',
|
|
88
|
+
'<w:style w:type="paragraph" w:styleId="ListNumber"><w:name w:val="List Number"/><w:basedOn w:val="Normal"/><w:uiPriority w:val="99"/><w:unhideWhenUsed/><w:qFormat/><w:pPr><w:numPr><w:numId w:val="2"/></w:numPr><w:contextualSpacing/></w:pPr></w:style>',
|
|
89
|
+
'<w:style w:type="paragraph" w:styleId="Quote"><w:name w:val="Quote"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:uiPriority w:val="29"/><w:qFormat/><w:pPr><w:spacing w:before="200"/><w:ind w:left="864" w:right="864"/><w:jc w:val="center"/></w:pPr><w:rPr><w:i/><w:iCs/><w:color w:val="404040"/></w:rPr></w:style>',
|
|
90
|
+
'<w:style w:type="table" w:styleId="TableGrid"><w:name w:val="Table Grid"/><w:basedOn w:val="TableNormal"/><w:uiPriority w:val="39"/><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/></w:pPr><w:tblPr><w:tblBorders><w:top w:val="single" w:sz="4" w:space="0" w:color="auto"/><w:left w:val="single" w:sz="4" w:space="0" w:color="auto"/><w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto"/><w:right w:val="single" w:sz="4" w:space="0" w:color="auto"/><w:insideH w:val="single" w:sz="4" w:space="0" w:color="auto"/><w:insideV w:val="single" w:sz="4" w:space="0" w:color="auto"/></w:tblBorders></w:tblPr></w:style>'
|
|
91
|
+
];
|
|
92
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:styles xmlns:w="${W}">${styles.join('').replace(/\{heading\}/g, head)}</w:styles>`;
|
|
93
|
+
}
|
|
94
|
+
function levelXml(level) {
|
|
95
|
+
const font = level.font
|
|
96
|
+
? `<w:rPr><w:rFonts w:ascii="${level.font}" w:hAnsi="${level.font}" w:hint="default"/></w:rPr>`
|
|
97
|
+
: '';
|
|
98
|
+
return `<w:lvl w:ilvl="${level.ilvl}"><w:start w:val="1"/><w:numFmt w:val="${level.format}"/><w:lvlText w:val="${level.text}"/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="${360 + 360 * level.ilvl}" w:hanging="360"/></w:pPr>${font}</w:lvl>`;
|
|
99
|
+
}
|
|
100
|
+
function numberingXml() {
|
|
101
|
+
const nine = Array.from({ length: 9 }, (_, i) => i);
|
|
102
|
+
const bulletLevels = nine
|
|
103
|
+
.map((i) => levelXml({ ilvl: i, format: 'bullet', text: BULLETS[i % 3], font: BULLET_FONTS[i % 3] }))
|
|
104
|
+
.join('');
|
|
105
|
+
const numberLevels = nine
|
|
106
|
+
.map((i) => levelXml({ ilvl: i, format: NUMBER_FORMATS[i % 3], text: `%${i + 1}.`, font: null }))
|
|
107
|
+
.join('');
|
|
108
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:numbering xmlns:w="${W}"><w:abstractNum w:abstractNumId="0"><w:multiLevelType w:val="hybridMultilevel"/>${bulletLevels}</w:abstractNum><w:abstractNum w:abstractNumId="1"><w:multiLevelType w:val="hybridMultilevel"/>${numberLevels}</w:abstractNum><w:num w:numId="1"><w:abstractNumId w:val="0"/></w:num><w:num w:numId="2"><w:abstractNumId w:val="1"/></w:num></w:numbering>`;
|
|
109
|
+
}
|
|
110
|
+
function documentXml(page) {
|
|
111
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<w:document xmlns:w="${W}" xmlns:r="${R}" xmlns:wp="${xml.ns.wp}" xmlns:a="${xml.ns.a}" xmlns:pic="${xml.ns.pic}"><w:body><w:p/><w:sectPr><w:pgSz w:w="${page.width}" w:h="${page.height}"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720" w:gutter="0"/><w:cols w:space="720"/></w:sectPr></w:body></w:document>`;
|
|
112
|
+
}
|
|
113
|
+
function addProperties(pkg, title) {
|
|
114
|
+
const heading = title ? `<dc:title>${escape(title)}</dc:title>` : '';
|
|
115
|
+
pkg.add('/docProps/core.xml', xml.parse(`<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/">${heading}</cp:coreProperties>`), TYPES.core);
|
|
116
|
+
pkg.add('/docProps/app.xml', xml.parse('<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"><Application>QVAC</Application></Properties>'), TYPES.app);
|
|
117
|
+
const rels = pkg.rels('/');
|
|
118
|
+
rels.add(REL_BASE + 'officeDocument', '/word/document.xml');
|
|
119
|
+
rels.add('http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', '/docProps/core.xml');
|
|
120
|
+
rels.add(REL_BASE + 'extended-properties', '/docProps/app.xml');
|
|
121
|
+
}
|
|
122
|
+
export function build(pkg, input = {}) {
|
|
123
|
+
const { page, fonts, size, title } = options(isRecord(input) ? input : {});
|
|
124
|
+
pkg.add('/word/document.xml', xml.parse(documentXml(page)), TYPES.document);
|
|
125
|
+
pkg.add('/word/styles.xml', xml.parse(stylesXml(fonts, size)), TYPES.styles);
|
|
126
|
+
pkg.add('/word/numbering.xml', xml.parse(numberingXml()), TYPES.numbering);
|
|
127
|
+
pkg.add('/word/settings.xml', xml.parse(`<w:settings xmlns:w="${W}"><w:defaultTabStop w:val="720"/><w:characterSpacingControl w:val="doNotCompress"/><w:compat><w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="15"/></w:compat></w:settings>`), TYPES.settings);
|
|
128
|
+
const main = pkg.rels('/word/document.xml');
|
|
129
|
+
main.add(REL_BASE + 'styles', '/word/styles.xml');
|
|
130
|
+
main.add(REL_BASE + 'numbering', '/word/numbering.xml');
|
|
131
|
+
main.add(REL_BASE + 'settings', '/word/settings.xml');
|
|
132
|
+
addProperties(pkg, title);
|
|
133
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Document, Element } from '../xml.ts';
|
|
2
|
+
export type Alignment = 'left' | 'center' | 'right' | 'justify';
|
|
3
|
+
export interface RunFormat {
|
|
4
|
+
bold?: boolean;
|
|
5
|
+
italic?: boolean;
|
|
6
|
+
underline?: boolean;
|
|
7
|
+
size?: number;
|
|
8
|
+
color?: string;
|
|
9
|
+
font?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface Format extends RunFormat {
|
|
12
|
+
align?: Alignment;
|
|
13
|
+
}
|
|
14
|
+
export interface Run extends RunFormat {
|
|
15
|
+
text: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ParagraphSpec {
|
|
18
|
+
text?: string;
|
|
19
|
+
runs?: (string | Run)[];
|
|
20
|
+
style?: string;
|
|
21
|
+
styleId?: string;
|
|
22
|
+
align?: Alignment;
|
|
23
|
+
pageBreak?: boolean;
|
|
24
|
+
level?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface Removed {
|
|
27
|
+
hyperlinks?: number;
|
|
28
|
+
images?: number;
|
|
29
|
+
fields?: number;
|
|
30
|
+
contentControls?: number;
|
|
31
|
+
equations?: number;
|
|
32
|
+
objects?: number;
|
|
33
|
+
breaks?: number;
|
|
34
|
+
}
|
|
35
|
+
export type WAttributes = Record<string, string | number | undefined | null>;
|
|
36
|
+
export declare const W: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
37
|
+
export declare const RUN_ORDER: string[];
|
|
38
|
+
export declare const PARAGRAPH_ORDER: string[];
|
|
39
|
+
export declare const ALIGNMENTS: Record<Alignment, string>;
|
|
40
|
+
export declare const FORMAT_KEYS: readonly string[];
|
|
41
|
+
export declare const RUN_KEYS: readonly string[];
|
|
42
|
+
export declare function wGet(el: Element | null, name: string): string;
|
|
43
|
+
export declare function paragraphText(el: Element): string;
|
|
44
|
+
export declare function blockText(el: Element): string;
|
|
45
|
+
export declare function hasPageBreak(p: Element): boolean;
|
|
46
|
+
export declare function wAttr(el: Element, name: string, value: string | number): void;
|
|
47
|
+
export declare function wEl(doc: Document, local: string, attributes?: WAttributes): Element;
|
|
48
|
+
export declare function validateFormat(format: unknown, known?: readonly string[]): Format;
|
|
49
|
+
export declare function applyRunFormat(rPr: Element, format: RunFormat): void;
|
|
50
|
+
export declare function ensure(parent: Element, local: string, order?: readonly string[]): Element;
|
|
51
|
+
export declare function setAlign(p: Element, align: Alignment): void;
|
|
52
|
+
export declare function normalizeRuns(input: unknown): Run[];
|
|
53
|
+
export declare function assertUntracked(p: Element, where: string): void;
|
|
54
|
+
export declare function replaceContent(p: Element, input: unknown): Removed;
|
|
55
|
+
export declare function buildParagraph(doc: Document, input: unknown, template: Element | null): Element;
|