@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,49 @@
|
|
|
1
|
+
export type RefKind = 'cell' | 'range' | 'columns' | 'rows';
|
|
2
|
+
export interface Point {
|
|
3
|
+
col?: number;
|
|
4
|
+
row?: number;
|
|
5
|
+
absCol?: boolean;
|
|
6
|
+
absRow?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface Ref {
|
|
9
|
+
kind: RefKind;
|
|
10
|
+
start: Point;
|
|
11
|
+
end: Point | null;
|
|
12
|
+
length: number;
|
|
13
|
+
}
|
|
14
|
+
export interface Change {
|
|
15
|
+
sheet: string;
|
|
16
|
+
axis: 'row' | 'col';
|
|
17
|
+
at: number;
|
|
18
|
+
count: number;
|
|
19
|
+
kind: 'insert' | 'delete';
|
|
20
|
+
}
|
|
21
|
+
export interface RefContext {
|
|
22
|
+
sheet: string | null;
|
|
23
|
+
original: string;
|
|
24
|
+
}
|
|
25
|
+
export interface Handlers {
|
|
26
|
+
onRef?: (ref: Ref, context: RefContext) => string | null;
|
|
27
|
+
onSheet?: (names: string[], text: string) => string;
|
|
28
|
+
onTable?: (name: string) => void;
|
|
29
|
+
}
|
|
30
|
+
export interface Rename {
|
|
31
|
+
from: string;
|
|
32
|
+
to: string;
|
|
33
|
+
}
|
|
34
|
+
export interface Offset {
|
|
35
|
+
rows: number;
|
|
36
|
+
cols: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function scan(formula: string, handlers?: Handlers): string;
|
|
39
|
+
export declare function sheetsIn(formula: string): string[];
|
|
40
|
+
export declare function tablesIn(formula: string): string[];
|
|
41
|
+
export declare function usesTable(formula: string, table: string): boolean;
|
|
42
|
+
export declare function mentions(formula: string, sheet: string): boolean;
|
|
43
|
+
export declare function renameSheet(formula: string, rename: Rename): string;
|
|
44
|
+
export declare function shift(formula: string, offset: Offset): string;
|
|
45
|
+
export declare function moveIndex(i: number, change: Change): number | null;
|
|
46
|
+
export declare function moveSpan(span: [number, number], change: Change): [number, number] | null;
|
|
47
|
+
export declare function adjust(formula: string, ownSheet: string | null, change: Change): string;
|
|
48
|
+
export declare function references(formula: string, ownSheet: string | null, sheet: string): boolean;
|
|
49
|
+
export declare function adjustRange(range: string, change: Change): string | null;
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import * as refs from './refs.js';
|
|
2
|
+
const NAME_START = /[A-Za-z_À-]/;
|
|
3
|
+
const WORD = /[A-Za-z0-9_.À-]/;
|
|
4
|
+
const BARE_PREFIX = /[A-Za-z_À-][\w.À-]*(?::[A-Za-z_À-][\w.À-]*)?!/y;
|
|
5
|
+
const CELL_RANGE = /(\$?)([A-Za-z]{1,3})(\$?)(\d{1,7})(?::(\$?)([A-Za-z]{1,3})(\$?)(\d{1,7}))?(?![A-Za-z0-9_(![])/y;
|
|
6
|
+
const COLUMN_RANGE = /(\$?)([A-Za-z]{1,3}):(\$?)([A-Za-z]{1,3})(?![A-Za-z0-9_(![])/y;
|
|
7
|
+
const ROW_RANGE = /(\$?)(\d{1,7}):(\$?)(\d{1,7})(?![A-Za-z0-9_(.![])/y;
|
|
8
|
+
const WORKBOOK = /\[[^\]]*\]/;
|
|
9
|
+
function quoted(text, at, quote) {
|
|
10
|
+
let i = at + 1;
|
|
11
|
+
while (i < text.length) {
|
|
12
|
+
if (text[i] === quote && text[i + 1] === quote) {
|
|
13
|
+
i += 2;
|
|
14
|
+
}
|
|
15
|
+
else if (text[i] === quote) {
|
|
16
|
+
return i + 1;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
i++;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return text.length;
|
|
23
|
+
}
|
|
24
|
+
function matchAt(re, text, at) {
|
|
25
|
+
re.lastIndex = at;
|
|
26
|
+
return re.exec(text);
|
|
27
|
+
}
|
|
28
|
+
function inColumns(letters) {
|
|
29
|
+
return letters === undefined || refs.columnIndex(letters) < refs.MAX_COLUMNS;
|
|
30
|
+
}
|
|
31
|
+
function cellRef(m) {
|
|
32
|
+
const start = {
|
|
33
|
+
col: refs.columnIndex(m[2]),
|
|
34
|
+
row: Number(m[4]) - 1,
|
|
35
|
+
absCol: m[1] === '$',
|
|
36
|
+
absRow: m[3] === '$'
|
|
37
|
+
};
|
|
38
|
+
const end = m[6]
|
|
39
|
+
? {
|
|
40
|
+
col: refs.columnIndex(m[6]),
|
|
41
|
+
row: Number(m[8]) - 1,
|
|
42
|
+
absCol: m[5] === '$',
|
|
43
|
+
absRow: m[7] === '$'
|
|
44
|
+
}
|
|
45
|
+
: null;
|
|
46
|
+
return { kind: end ? 'range' : 'cell', start, end, length: m[0].length };
|
|
47
|
+
}
|
|
48
|
+
function readRef(text, at) {
|
|
49
|
+
const cells = matchAt(CELL_RANGE, text, at);
|
|
50
|
+
if (cells && inColumns(cells[2]) && inColumns(cells[6])) {
|
|
51
|
+
return cellRef(cells);
|
|
52
|
+
}
|
|
53
|
+
const columns = matchAt(COLUMN_RANGE, text, at);
|
|
54
|
+
if (columns && inColumns(columns[2]) && inColumns(columns[4])) {
|
|
55
|
+
return {
|
|
56
|
+
kind: 'columns',
|
|
57
|
+
start: { col: refs.columnIndex(columns[2]), absCol: columns[1] === '$' },
|
|
58
|
+
end: { col: refs.columnIndex(columns[4]), absCol: columns[3] === '$' },
|
|
59
|
+
length: columns[0].length
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const rows = matchAt(ROW_RANGE, text, at);
|
|
63
|
+
if (!rows) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
kind: 'rows',
|
|
68
|
+
start: { row: Number(rows[2]) - 1, absRow: rows[1] === '$' },
|
|
69
|
+
end: { row: Number(rows[4]) - 1, absRow: rows[3] === '$' },
|
|
70
|
+
length: rows[0].length
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function bracketEnd(text, at) {
|
|
74
|
+
let depth = 0;
|
|
75
|
+
for (let i = at; i < text.length; i++) {
|
|
76
|
+
const ch = text[i];
|
|
77
|
+
if (ch === "'") {
|
|
78
|
+
i++;
|
|
79
|
+
}
|
|
80
|
+
else if (ch === '[') {
|
|
81
|
+
depth++;
|
|
82
|
+
}
|
|
83
|
+
else if (ch === ']' && --depth === 0) {
|
|
84
|
+
return i + 1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return text.length;
|
|
88
|
+
}
|
|
89
|
+
function emitExternal(state, text) {
|
|
90
|
+
state.out += text;
|
|
91
|
+
state.at += text.length;
|
|
92
|
+
state.sheet = text;
|
|
93
|
+
state.external = true;
|
|
94
|
+
}
|
|
95
|
+
function emitSheet(state, handlers, prefix) {
|
|
96
|
+
const name = prefix.startsWith("'")
|
|
97
|
+
? prefix.slice(1, -2).replace(/''/g, "'")
|
|
98
|
+
: prefix.slice(0, -1);
|
|
99
|
+
if (WORKBOOK.test(name)) {
|
|
100
|
+
emitExternal(state, prefix);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const names = name.split(':');
|
|
104
|
+
state.sheet = name;
|
|
105
|
+
state.external = false;
|
|
106
|
+
state.out += handlers.onSheet ? handlers.onSheet(names, prefix) : prefix;
|
|
107
|
+
state.at += prefix.length;
|
|
108
|
+
}
|
|
109
|
+
function bracketStep(state, handlers) {
|
|
110
|
+
const { formula, at } = state;
|
|
111
|
+
if (formula[at] !== '[') {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const end = bracketEnd(formula, at);
|
|
115
|
+
let start = at;
|
|
116
|
+
while (start > 0 && WORD.test(formula[start - 1])) {
|
|
117
|
+
start--;
|
|
118
|
+
}
|
|
119
|
+
const prefix = start === at ? matchAt(BARE_PREFIX, formula, end) : null;
|
|
120
|
+
if (prefix || (start === at && formula[end] === '!')) {
|
|
121
|
+
emitExternal(state, formula.slice(at, end) + (prefix ? prefix[0] : '!'));
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (start < at && !state.external) {
|
|
125
|
+
handlers.onTable?.(formula.slice(start, at));
|
|
126
|
+
}
|
|
127
|
+
state.out += formula.slice(at, end);
|
|
128
|
+
state.at = end;
|
|
129
|
+
state.sheet = null;
|
|
130
|
+
state.external = false;
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
function quotedStep(state, handlers) {
|
|
134
|
+
const { formula, at } = state;
|
|
135
|
+
const ch = formula[at];
|
|
136
|
+
if (ch !== '"' && ch !== "'") {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
const end = quoted(formula, at, ch);
|
|
140
|
+
if (ch === "'" && formula[end] === '!') {
|
|
141
|
+
emitSheet(state, handlers, formula.slice(at, end + 1));
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
state.out += formula.slice(at, end);
|
|
145
|
+
state.at = end;
|
|
146
|
+
if (ch === '"') {
|
|
147
|
+
state.sheet = null;
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
function referenceStep(state, handlers) {
|
|
152
|
+
const { formula, at } = state;
|
|
153
|
+
const prev = at > 0 ? formula[at - 1] : '';
|
|
154
|
+
if (WORD.test(prev) || prev === '$') {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
const bare = state.sheet === null && NAME_START.test(formula[at]) ? matchAt(BARE_PREFIX, formula, at) : null;
|
|
158
|
+
if (bare) {
|
|
159
|
+
emitSheet(state, handlers, bare[0]);
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
const ref = readRef(formula, at);
|
|
163
|
+
if (!ref) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const original = formula.slice(at, at + ref.length);
|
|
167
|
+
const next = handlers.onRef && !state.external ? handlers.onRef(ref, { sheet: state.sheet, original }) : null;
|
|
168
|
+
state.out += next ?? original;
|
|
169
|
+
state.at += ref.length;
|
|
170
|
+
state.sheet = null;
|
|
171
|
+
state.external = false;
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
function plainStep(state) {
|
|
175
|
+
const ch = state.formula[state.at];
|
|
176
|
+
if (state.sheet !== null && !WORD.test(ch)) {
|
|
177
|
+
state.sheet = null;
|
|
178
|
+
state.external = false;
|
|
179
|
+
}
|
|
180
|
+
state.out += ch;
|
|
181
|
+
state.at++;
|
|
182
|
+
}
|
|
183
|
+
export function scan(formula, handlers = {}) {
|
|
184
|
+
const state = { formula, at: 0, sheet: null, external: false, out: '' };
|
|
185
|
+
while (state.at < formula.length) {
|
|
186
|
+
if (!bracketStep(state, handlers) &&
|
|
187
|
+
!quotedStep(state, handlers) &&
|
|
188
|
+
!referenceStep(state, handlers)) {
|
|
189
|
+
plainStep(state);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return state.out;
|
|
193
|
+
}
|
|
194
|
+
export function sheetsIn(formula) {
|
|
195
|
+
const found = [];
|
|
196
|
+
scan(formula, {
|
|
197
|
+
onSheet: (names, text) => {
|
|
198
|
+
found.push(...names);
|
|
199
|
+
return text;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
return found;
|
|
203
|
+
}
|
|
204
|
+
export function tablesIn(formula) {
|
|
205
|
+
const found = [];
|
|
206
|
+
scan(formula, { onTable: (name) => found.push(name) });
|
|
207
|
+
return found;
|
|
208
|
+
}
|
|
209
|
+
export function usesTable(formula, table) {
|
|
210
|
+
const wanted = table.toLowerCase();
|
|
211
|
+
return tablesIn(formula).some((name) => name.toLowerCase() === wanted);
|
|
212
|
+
}
|
|
213
|
+
export function mentions(formula, sheet) {
|
|
214
|
+
const wanted = sheet.toLowerCase();
|
|
215
|
+
return sheetsIn(formula).some((name) => name.toLowerCase() === wanted);
|
|
216
|
+
}
|
|
217
|
+
export function renameSheet(formula, rename) {
|
|
218
|
+
const wanted = rename.from.toLowerCase();
|
|
219
|
+
return scan(formula, {
|
|
220
|
+
onSheet: (names, text) => {
|
|
221
|
+
if (!names.some((name) => name.toLowerCase() === wanted)) {
|
|
222
|
+
return text;
|
|
223
|
+
}
|
|
224
|
+
const next = names.map((name) => (name.toLowerCase() === wanted ? rename.to : name));
|
|
225
|
+
return `${quoteSheets(next)}!`;
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function quoteSheets(names) {
|
|
230
|
+
const quoted = names.map((name) => refs.quoteSheet(name));
|
|
231
|
+
if (quoted.every((name, i) => name === names[i])) {
|
|
232
|
+
return names.join(':');
|
|
233
|
+
}
|
|
234
|
+
return `'${names.map((name) => name.replace(/'/g, "''")).join(':')}'`;
|
|
235
|
+
}
|
|
236
|
+
function formatCell(p) {
|
|
237
|
+
return `${p.absCol ? '$' : ''}${refs.column(p.col ?? 0)}${p.absRow ? '$' : ''}${(p.row ?? 0) + 1}`;
|
|
238
|
+
}
|
|
239
|
+
function formatRef(ref) {
|
|
240
|
+
const { start } = ref;
|
|
241
|
+
const end = ref.end ?? ref.start;
|
|
242
|
+
if (ref.kind === 'cell') {
|
|
243
|
+
return formatCell(start);
|
|
244
|
+
}
|
|
245
|
+
if (ref.kind === 'range') {
|
|
246
|
+
return `${formatCell(start)}:${formatCell(end)}`;
|
|
247
|
+
}
|
|
248
|
+
if (ref.kind === 'columns') {
|
|
249
|
+
return `${start.absCol ? '$' : ''}${refs.column(start.col ?? 0)}:${end.absCol ? '$' : ''}${refs.column(end.col ?? 0)}`;
|
|
250
|
+
}
|
|
251
|
+
return `${start.absRow ? '$' : ''}${(start.row ?? 0) + 1}:${end.absRow ? '$' : ''}${(end.row ?? 0) + 1}`;
|
|
252
|
+
}
|
|
253
|
+
function outside(p) {
|
|
254
|
+
const badCol = p.col !== undefined && (p.col < 0 || p.col >= refs.MAX_COLUMNS);
|
|
255
|
+
const badRow = p.row !== undefined && (p.row < 0 || p.row >= refs.MAX_ROWS);
|
|
256
|
+
return badCol || badRow;
|
|
257
|
+
}
|
|
258
|
+
const BROKEN = '\u0000';
|
|
259
|
+
function moved(p, offset) {
|
|
260
|
+
const col = p.col !== undefined && !p.absCol ? p.col + offset.cols : p.col;
|
|
261
|
+
const row = p.row !== undefined && !p.absRow ? p.row + offset.rows : p.row;
|
|
262
|
+
return { ...p, col, row };
|
|
263
|
+
}
|
|
264
|
+
export function shift(formula, offset) {
|
|
265
|
+
const out = scan(formula, {
|
|
266
|
+
onRef: (ref) => {
|
|
267
|
+
const start = moved(ref.start, offset);
|
|
268
|
+
const end = ref.end ? moved(ref.end, offset) : null;
|
|
269
|
+
const broken = outside(start) || (end !== null && outside(end));
|
|
270
|
+
return broken ? BROKEN : formatRef({ ...ref, start, end });
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
return out.includes(BROKEN) ? '#REF!' : out;
|
|
274
|
+
}
|
|
275
|
+
function limit(change) {
|
|
276
|
+
return change.axis === 'row' ? refs.MAX_ROWS : refs.MAX_COLUMNS;
|
|
277
|
+
}
|
|
278
|
+
export function moveIndex(i, change) {
|
|
279
|
+
const { at, count, kind } = change;
|
|
280
|
+
if (kind === 'insert') {
|
|
281
|
+
if (i < at) {
|
|
282
|
+
return i;
|
|
283
|
+
}
|
|
284
|
+
return i + count < limit(change) ? i + count : null;
|
|
285
|
+
}
|
|
286
|
+
if (i < at) {
|
|
287
|
+
return i;
|
|
288
|
+
}
|
|
289
|
+
if (i >= at + count) {
|
|
290
|
+
return i - count;
|
|
291
|
+
}
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
function spanStart(a, change) {
|
|
295
|
+
if (a < change.at)
|
|
296
|
+
return a;
|
|
297
|
+
return a >= change.at + change.count ? a - change.count : change.at;
|
|
298
|
+
}
|
|
299
|
+
function spanEnd(b, change) {
|
|
300
|
+
if (b < change.at)
|
|
301
|
+
return b;
|
|
302
|
+
return b >= change.at + change.count ? b - change.count : change.at - 1;
|
|
303
|
+
}
|
|
304
|
+
export function moveSpan(span, change) {
|
|
305
|
+
const [a, b] = span;
|
|
306
|
+
const { at, count } = change;
|
|
307
|
+
if (change.kind === 'insert') {
|
|
308
|
+
const last = limit(change) - 1;
|
|
309
|
+
const first = a >= at ? a + count : a;
|
|
310
|
+
return first > last ? null : [first, b >= at ? Math.min(b + count, last) : b];
|
|
311
|
+
}
|
|
312
|
+
const first = spanStart(a, change);
|
|
313
|
+
const last = spanEnd(b, change);
|
|
314
|
+
return last < first ? null : [first, last];
|
|
315
|
+
}
|
|
316
|
+
function adjustRef(ref, change) {
|
|
317
|
+
const key = change.axis === 'row' ? 'row' : 'col';
|
|
318
|
+
const from = ref.start[key];
|
|
319
|
+
if (from === undefined) {
|
|
320
|
+
return ref;
|
|
321
|
+
}
|
|
322
|
+
if (ref.kind === 'cell') {
|
|
323
|
+
const moved = moveIndex(from, change);
|
|
324
|
+
return moved === null ? null : { ...ref, start: { ...ref.start, [key]: moved } };
|
|
325
|
+
}
|
|
326
|
+
const to = ref.end?.[key];
|
|
327
|
+
if (!ref.end || to === undefined) {
|
|
328
|
+
return ref;
|
|
329
|
+
}
|
|
330
|
+
const span = moveSpan([from, to], change);
|
|
331
|
+
if (span === null) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
return { ...ref, start: { ...ref.start, [key]: span[0] }, end: { ...ref.end, [key]: span[1] } };
|
|
335
|
+
}
|
|
336
|
+
export function adjust(formula, ownSheet, change) {
|
|
337
|
+
const target = change.sheet.toLowerCase();
|
|
338
|
+
const own = ownSheet ? ownSheet.toLowerCase() : null;
|
|
339
|
+
return scan(formula, {
|
|
340
|
+
onRef: (ref, { sheet, original }) => {
|
|
341
|
+
const pointsAt = sheet !== null ? sheet.toLowerCase() : own;
|
|
342
|
+
if (pointsAt !== target) {
|
|
343
|
+
return original;
|
|
344
|
+
}
|
|
345
|
+
const moved = adjustRef(ref, change);
|
|
346
|
+
return moved === null ? '#REF!' : formatRef(moved);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
export function references(formula, ownSheet, sheet) {
|
|
351
|
+
const target = sheet.toLowerCase();
|
|
352
|
+
const own = ownSheet ? ownSheet.toLowerCase() : null;
|
|
353
|
+
let hit = false;
|
|
354
|
+
scan(formula, {
|
|
355
|
+
onRef: (ref, { sheet: prefix, original }) => {
|
|
356
|
+
if ((prefix !== null ? prefix.toLowerCase() : own) === target) {
|
|
357
|
+
hit = true;
|
|
358
|
+
}
|
|
359
|
+
return original;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
return hit;
|
|
363
|
+
}
|
|
364
|
+
function plain(p) {
|
|
365
|
+
return { ...p, absCol: false, absRow: false };
|
|
366
|
+
}
|
|
367
|
+
export function adjustRange(range, change) {
|
|
368
|
+
const ref = readRef(range, 0);
|
|
369
|
+
if (!ref || ref.length !== range.length) {
|
|
370
|
+
return range;
|
|
371
|
+
}
|
|
372
|
+
const moved = adjustRef(ref, change);
|
|
373
|
+
if (moved === null) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
return formatRef({
|
|
377
|
+
...moved,
|
|
378
|
+
start: plain(moved.start),
|
|
379
|
+
end: moved.end ? plain(moved.end) : null
|
|
380
|
+
});
|
|
381
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Workbook } from './workbook.ts';
|
|
2
|
+
import type { OpenOptions } from '../opc/package.ts';
|
|
3
|
+
import type { CreateOptions } from './template.ts';
|
|
4
|
+
export { Workbook };
|
|
5
|
+
export type { SheetRef, SheetInfo, SheetChart, WorkbookRead, Placed, RowSpan, Changed, Renamed, CellCount, Deleted, SheetCount, AddedSheet, CellValue, CellRead, CreateOptions, ReadOptions, CellOptions, CellInput, Cells, InsertRowsOptions, DeleteRowsOptions, DeleteColumnsOptions, ColumnWidthOptions, AddSheetOptions, ImageOptions, SeriesRange, SheetChartSpec } from './workbook.ts';
|
|
6
|
+
export type { CellStyle, CellAlign } from './styles.ts';
|
|
7
|
+
export declare function open(bytes: Uint8Array | ArrayBuffer, opts?: OpenOptions): Workbook;
|
|
8
|
+
export declare function create(opts?: CreateOptions): Workbook;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface Position {
|
|
2
|
+
row: number;
|
|
3
|
+
col: number;
|
|
4
|
+
}
|
|
5
|
+
export interface Area {
|
|
6
|
+
top: number;
|
|
7
|
+
left: number;
|
|
8
|
+
bottom: number;
|
|
9
|
+
right: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const MAX_ROWS = 1048576;
|
|
12
|
+
export declare const MAX_COLUMNS = 16384;
|
|
13
|
+
export declare function column(index: number): string;
|
|
14
|
+
export declare function columnIndex(letters: string): number;
|
|
15
|
+
export declare function cell(row: number, col: number): string;
|
|
16
|
+
export declare function parse(ref: unknown): Position;
|
|
17
|
+
export declare function parseRange(ref: unknown): Area;
|
|
18
|
+
export declare function range(area: Area): string;
|
|
19
|
+
export declare function quoteSheet(name: string): string;
|
|
20
|
+
export declare function absolute(sheet: string, area: Area): string;
|
|
21
|
+
export declare function columnArg(value: unknown): number;
|
|
22
|
+
export declare function rowArg(value: unknown, name?: string): number;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { DocsError } from '../errors.js';
|
|
2
|
+
export const MAX_ROWS = 1048576;
|
|
3
|
+
export const MAX_COLUMNS = 16384;
|
|
4
|
+
export function column(index) {
|
|
5
|
+
let n = index + 1;
|
|
6
|
+
let out = '';
|
|
7
|
+
while (n > 0) {
|
|
8
|
+
const rem = (n - 1) % 26;
|
|
9
|
+
out = String.fromCharCode(65 + rem) + out;
|
|
10
|
+
n = Math.floor((n - 1) / 26);
|
|
11
|
+
}
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
14
|
+
export function columnIndex(letters) {
|
|
15
|
+
let n = 0;
|
|
16
|
+
for (const ch of letters.toUpperCase()) {
|
|
17
|
+
n = n * 26 + (ch.charCodeAt(0) - 64);
|
|
18
|
+
}
|
|
19
|
+
return n - 1;
|
|
20
|
+
}
|
|
21
|
+
export function cell(row, col) {
|
|
22
|
+
return `${column(col)}${row + 1}`;
|
|
23
|
+
}
|
|
24
|
+
export function parse(ref) {
|
|
25
|
+
const match = typeof ref === 'string' ? /^\$?([A-Za-z]{1,3})\$?([0-9]{1,7})$/.exec(ref.trim()) : null;
|
|
26
|
+
if (!match) {
|
|
27
|
+
throw new DocsError('INVALID_CELL', `"${String(ref)}" is not a cell reference like A1 or C12`);
|
|
28
|
+
}
|
|
29
|
+
const col = columnIndex(match[1]);
|
|
30
|
+
const row = Number(match[2]) - 1;
|
|
31
|
+
if (row < 0 || row >= MAX_ROWS || col >= MAX_COLUMNS) {
|
|
32
|
+
throw new DocsError('INVALID_CELL', `${String(ref)} is outside the sheet`);
|
|
33
|
+
}
|
|
34
|
+
return { row, col };
|
|
35
|
+
}
|
|
36
|
+
export function parseRange(ref) {
|
|
37
|
+
if (typeof ref !== 'string') {
|
|
38
|
+
throw new DocsError('INVALID_RANGE', 'a range is text like A1:D20');
|
|
39
|
+
}
|
|
40
|
+
const [a, b = a] = ref.split(':');
|
|
41
|
+
const start = parse(a);
|
|
42
|
+
const end = parse(b);
|
|
43
|
+
return {
|
|
44
|
+
top: Math.min(start.row, end.row),
|
|
45
|
+
left: Math.min(start.col, end.col),
|
|
46
|
+
bottom: Math.max(start.row, end.row),
|
|
47
|
+
right: Math.max(start.col, end.col)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function range(area) {
|
|
51
|
+
const start = cell(area.top, area.left);
|
|
52
|
+
return area.top === area.bottom && area.left === area.right
|
|
53
|
+
? start
|
|
54
|
+
: `${start}:${cell(area.bottom, area.right)}`;
|
|
55
|
+
}
|
|
56
|
+
export function quoteSheet(name) {
|
|
57
|
+
return /^[A-Za-z_][A-Za-z0-9_.]*$/.test(name) && !/^[A-Za-z]{1,3}[0-9]+$/.test(name)
|
|
58
|
+
? name
|
|
59
|
+
: `'${name.replace(/'/g, "''")}'`;
|
|
60
|
+
}
|
|
61
|
+
export function absolute(sheet, area) {
|
|
62
|
+
const start = `$${column(area.left)}$${area.top + 1}`;
|
|
63
|
+
if (area.top === area.bottom && area.left === area.right) {
|
|
64
|
+
return `${quoteSheet(sheet)}!${start}`;
|
|
65
|
+
}
|
|
66
|
+
return `${quoteSheet(sheet)}!${start}:$${column(area.right)}$${area.bottom + 1}`;
|
|
67
|
+
}
|
|
68
|
+
export function columnArg(value) {
|
|
69
|
+
if (typeof value === 'string' && /^[A-Za-z]{1,3}$/.test(value)) {
|
|
70
|
+
return columnIndex(value);
|
|
71
|
+
}
|
|
72
|
+
if (typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= MAX_COLUMNS) {
|
|
73
|
+
return value - 1;
|
|
74
|
+
}
|
|
75
|
+
throw new DocsError('INVALID_CELL', `a column is a letter like "C" or a number from 1, got ${String(value)}`);
|
|
76
|
+
}
|
|
77
|
+
export function rowArg(value, name = 'row') {
|
|
78
|
+
if (typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= MAX_ROWS) {
|
|
79
|
+
return value - 1;
|
|
80
|
+
}
|
|
81
|
+
throw new DocsError('INVALID_CELL', `${name} is a row number from 1, got ${String(value)}`);
|
|
82
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Document, Element } from '../xml.ts';
|
|
2
|
+
import type { Package } from '../opc/package.ts';
|
|
3
|
+
import type { Change } from './formula.ts';
|
|
4
|
+
import type { EditState, Sheet, SheetEntry } from './sheet.ts';
|
|
5
|
+
export interface ReshapeHost {
|
|
6
|
+
package: Package;
|
|
7
|
+
main: string;
|
|
8
|
+
state: EditState;
|
|
9
|
+
entries(): SheetEntry[];
|
|
10
|
+
definedNames(): Element[];
|
|
11
|
+
chartParts(): string[];
|
|
12
|
+
drawingOf(sheet: Sheet): string | null;
|
|
13
|
+
sheetFor(entry: SheetEntry): Sheet;
|
|
14
|
+
}
|
|
15
|
+
export declare function formulaElements(doc: Document): Element[];
|
|
16
|
+
export declare function tableNames(pkg: Package, sheetPart: string): string[];
|
|
17
|
+
export declare function renamePivotSources(pkg: Package, from: string, to: string): void;
|
|
18
|
+
export declare function blockers(host: ReshapeHost, sheet: Sheet, change: Change): string[];
|
|
19
|
+
export declare function expandShared(sheet: Sheet): boolean;
|
|
20
|
+
export declare function apply(host: ReshapeHost, target: Sheet, change: Change): void;
|
|
21
|
+
export declare function prepare(host: ReshapeHost, target: Sheet): void;
|