@qianxiang-ai/fu-report-viewer-engine 0.0.0-stage → 1.1.7
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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/legacy-converter.d.ts +5 -0
- package/dist/legacy-converter.d.ts.map +1 -0
- package/dist/legacy-converter.js +667 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +27 -3
- package/README.md +0 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ViewerRenderModel } from '@qianxiang-ai/fu-report-contracts';
|
|
2
|
+
import type { NativeConversionOptions, NativeRichTextNode, NativeViewerDocument } from './types.js';
|
|
3
|
+
export declare function convertLegacyViewerModel(model: ViewerRenderModel, options?: NativeConversionOptions): NativeViewerDocument;
|
|
4
|
+
export declare function parseLegacyRichText(value: unknown, depth?: number): readonly NativeRichTextNode[];
|
|
5
|
+
//# sourceMappingURL=legacy-converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-converter.d.ts","sourceRoot":"","sources":["../src/legacy-converter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;AAC1E,OAAO,KAAK,EAMV,uBAAuB,EAKvB,kBAAkB,EAClB,oBAAoB,EAErB,MAAM,YAAY,CAAA;AA4BnB,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE,uBAA4B,GACpC,oBAAoB,CAgBtB;AAyKD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,SAAS,kBAAkB,EAAE,CA4B5F"}
|
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
const DATASET_REFERENCE_SOURCE = '[#$]\\{([A-Za-z_][A-Za-z0-9_.-]{0,127})\\.([A-Za-z_][A-Za-z0-9_.-]{0,127})\\}(\\.group\\(\\))?';
|
|
2
|
+
const DATASET_REFERENCE = new RegExp(DATASET_REFERENCE_SOURCE, 'g');
|
|
3
|
+
const EXACT_DATASET_REFERENCE = new RegExp(`^${DATASET_REFERENCE_SOURCE}$`);
|
|
4
|
+
const ROW_EXPRESSION = /^=ROW\(\s*\)$/i;
|
|
5
|
+
const SAFE_COLOR = /^(?:#[0-9a-fA-F]{3,8}|rgba?\([0-9.,%\s]+\)|transparent)$/;
|
|
6
|
+
const MAX_TRACKS = 50_000;
|
|
7
|
+
export function convertLegacyViewerModel(model, options = {}) {
|
|
8
|
+
const root = object(model.renderTree);
|
|
9
|
+
const sheets = sourceSheets(root).map(item => convertSheet(item, options));
|
|
10
|
+
if (sheets.length === 0) {
|
|
11
|
+
sheets.push(convertSheet({ id: 'default', name: model.title, order: 0, document: {} }, options));
|
|
12
|
+
}
|
|
13
|
+
const requested = string(root.activeSheetId, sheets[0]?.id ?? 'default');
|
|
14
|
+
const activeSheetId = sheets.some(sheet => sheet.id === requested) ? requested : sheets[0].id;
|
|
15
|
+
return deepFreeze({
|
|
16
|
+
schemaVersion: 'native-v1',
|
|
17
|
+
reportId: model.reportId,
|
|
18
|
+
revision: model.revision,
|
|
19
|
+
title: model.title,
|
|
20
|
+
activeSheetId,
|
|
21
|
+
sheets
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function sourceSheets(root) {
|
|
25
|
+
if (!Array.isArray(root.sheets)) {
|
|
26
|
+
return [{ id: 'default', name: string(root.name, '默认 Sheet'), order: 0, document: root }];
|
|
27
|
+
}
|
|
28
|
+
return root.sheets.slice(0, 256).map((value, index) => {
|
|
29
|
+
const sheet = object(value);
|
|
30
|
+
return {
|
|
31
|
+
id: safeIdentifier(sheet.id, index === 0 ? 'default' : `sheet-${index}`),
|
|
32
|
+
name: string(sheet.name, `Sheet ${index + 1}`).slice(0, 128),
|
|
33
|
+
order: integer(sheet.order, index),
|
|
34
|
+
document: object(sheet.document)
|
|
35
|
+
};
|
|
36
|
+
}).sort((left, right) => left.order - right.order);
|
|
37
|
+
}
|
|
38
|
+
function convertSheet(source, options) {
|
|
39
|
+
const document = source.document;
|
|
40
|
+
const defaultRowHeight = clamp(number(options.defaultRowHeight, 26), 12, 240);
|
|
41
|
+
const defaultColumnWidth = clamp(number(options.defaultColumnWidth, 100), 24, 1000);
|
|
42
|
+
const expanded = expandRows(object(document.rows), options.datasets ?? {}, defaultRowHeight);
|
|
43
|
+
const expandedRowShift = Math.max(0, ...expanded.map(row => row.outputRow - row.sourceRow));
|
|
44
|
+
const rowCount = clamp(Math.max(1, ...expanded.map(row => row.outputRow + 1), areaEnd(document, 'eri') + 1 + expandedRowShift), 1, MAX_TRACKS);
|
|
45
|
+
const columnCount = clamp(Math.max(1, maxCellColumn(expanded) + 1, areaEnd(document, 'eci') + 1), 1, 2048);
|
|
46
|
+
const hidden = object(document.hidden);
|
|
47
|
+
const hiddenRows = integerSet(hidden.rows);
|
|
48
|
+
const hiddenColumns = integerSet(hidden.cols);
|
|
49
|
+
const rows = tracks(rowCount, defaultRowHeight, index => {
|
|
50
|
+
const row = expanded.find(item => item.outputRow === index);
|
|
51
|
+
return row?.height ?? defaultRowHeight;
|
|
52
|
+
}, hiddenRows);
|
|
53
|
+
const columnsSource = object(document.cols);
|
|
54
|
+
const columns = tracks(columnCount, defaultColumnWidth, index => number(object(columnsSource[String(index)]).width, defaultColumnWidth), hiddenColumns);
|
|
55
|
+
const sourceToOutput = new Map();
|
|
56
|
+
expanded.forEach(row => {
|
|
57
|
+
if (!sourceToOutput.has(row.sourceRow))
|
|
58
|
+
sourceToOutput.set(row.sourceRow, row.outputRow);
|
|
59
|
+
});
|
|
60
|
+
const merges = mergeRanges(document, expanded, sourceToOutput);
|
|
61
|
+
const covered = coveredCells(merges);
|
|
62
|
+
const styles = Array.isArray(document.styles) ? document.styles.map(object) : [];
|
|
63
|
+
const cells = [];
|
|
64
|
+
for (const row of expanded) {
|
|
65
|
+
for (const [columnKey, rawCell] of Object.entries(row.cells)) {
|
|
66
|
+
const column = integer(columnKey, -1);
|
|
67
|
+
if (column < 0 || column >= columns.length || covered.has(`${row.outputRow}:${column}`))
|
|
68
|
+
continue;
|
|
69
|
+
const cell = object(rawCell);
|
|
70
|
+
const merge = merges.find(item => item.row === row.outputRow && item.column === column);
|
|
71
|
+
const rowspan = merge?.rowspan ?? 1;
|
|
72
|
+
const colspan = merge?.colspan ?? 1;
|
|
73
|
+
const bounds = cellBounds(rows, columns, row.outputRow, column, rowspan, colspan);
|
|
74
|
+
const style = normalizeStyle(styles[integer(cell.style, -1)] ?? object(cell.style));
|
|
75
|
+
const padding = normalizePadding(cell.padding ?? styles[integer(cell.style, -1)]?.padding);
|
|
76
|
+
const value = resolveCellValue(cell, row, options.datasets ?? {});
|
|
77
|
+
if (cell.virtual && value.text.trim() === '')
|
|
78
|
+
continue;
|
|
79
|
+
cells.push({
|
|
80
|
+
id: `cell-${row.outputRow}-${column}`,
|
|
81
|
+
row: row.outputRow,
|
|
82
|
+
column,
|
|
83
|
+
rowspan,
|
|
84
|
+
colspan,
|
|
85
|
+
bounds,
|
|
86
|
+
contentBox: inset(bounds, padding),
|
|
87
|
+
zIndex: integer(cell.zIndex, 1),
|
|
88
|
+
text: value.text,
|
|
89
|
+
richText: value.richText,
|
|
90
|
+
hyperlink: safeLink(cell.hyperlink ?? cell.link),
|
|
91
|
+
style,
|
|
92
|
+
dynamicGroup: value.dynamicGroup
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
collapseDynamicGroups(cells, rows);
|
|
97
|
+
const visibleCells = cells.filter(cell => cell.rowspan > 0).map(({ dynamicGroup: _ignored, ...cell }) => cell);
|
|
98
|
+
const layers = convertLayers(document, rows, columns, sourceToOutput);
|
|
99
|
+
const width = columns.reduce((sum, track) => sum + track.size, 0);
|
|
100
|
+
const height = rows.reduce((sum, track) => sum + track.size, 0);
|
|
101
|
+
return {
|
|
102
|
+
id: source.id,
|
|
103
|
+
name: source.name,
|
|
104
|
+
order: source.order,
|
|
105
|
+
width,
|
|
106
|
+
height,
|
|
107
|
+
rows,
|
|
108
|
+
columns,
|
|
109
|
+
cells: visibleCells,
|
|
110
|
+
layers,
|
|
111
|
+
pages: paginate(rows, object(document.printConfig)),
|
|
112
|
+
frozen: freezePoint(string(document.freeze, ''), rows, columns)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function expandRows(rows, datasets, defaultHeight) {
|
|
116
|
+
const sourceIndexes = Object.keys(rows).map(value => integer(value, -1))
|
|
117
|
+
.filter(value => value >= 0).sort((a, b) => a - b);
|
|
118
|
+
const result = [];
|
|
119
|
+
let outputRow = 0;
|
|
120
|
+
let previousSourceRow = -1;
|
|
121
|
+
for (const sourceRow of sourceIndexes) {
|
|
122
|
+
outputRow += Math.max(0, sourceRow - previousSourceRow - 1);
|
|
123
|
+
const row = object(rows[String(sourceRow)]);
|
|
124
|
+
const cells = object(row.cells);
|
|
125
|
+
const binding = findRowBinding(cells);
|
|
126
|
+
const data = binding ? datasets[binding] : undefined;
|
|
127
|
+
const repetitions = data ? (data.length ? [...data] : [undefined]) : [undefined];
|
|
128
|
+
for (const [datasetIndex, datasetRow] of repetitions.entries()) {
|
|
129
|
+
result.push({
|
|
130
|
+
sourceRow,
|
|
131
|
+
outputRow: outputRow++,
|
|
132
|
+
datasetIndex,
|
|
133
|
+
height: clamp(number(row.height, defaultHeight), 0, 1000),
|
|
134
|
+
cells,
|
|
135
|
+
datasetRow,
|
|
136
|
+
binding
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
previousSourceRow = sourceRow;
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
function findRowBinding(cells) {
|
|
144
|
+
for (const value of Object.values(cells)) {
|
|
145
|
+
const match = DATASET_REFERENCE.exec(string(object(value).text, ''));
|
|
146
|
+
DATASET_REFERENCE.lastIndex = 0;
|
|
147
|
+
if (match?.[1])
|
|
148
|
+
return match[1];
|
|
149
|
+
}
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
function resolveCellValue(cell, row, datasets) {
|
|
153
|
+
const raw = cell.text ?? cell.value ?? '';
|
|
154
|
+
const text = string(raw, '');
|
|
155
|
+
if (ROW_EXPRESSION.test(text.trim())) {
|
|
156
|
+
return { text: String(row.binding ? row.datasetIndex + 1 : row.outputRow + 1) };
|
|
157
|
+
}
|
|
158
|
+
const expression = EXACT_DATASET_REFERENCE.exec(text);
|
|
159
|
+
if (expression?.[1] && expression[2]) {
|
|
160
|
+
return {
|
|
161
|
+
text: datasetValue(expression[1], expression[2], row, datasets),
|
|
162
|
+
dynamicGroup: expression[3] ? `${expression[1]}.${expression[2]}` : undefined
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const resolvedText = text.replace(DATASET_REFERENCE, (_match, binding, field) => datasetValue(binding, field, row, datasets));
|
|
166
|
+
const richTextSource = cell.richText ?? (cell.display === 'richText' ? resolvedText : undefined);
|
|
167
|
+
const richText = richTextSource === undefined ? undefined : parseLegacyRichText(richTextSource);
|
|
168
|
+
return { text: resolvedText.slice(0, 100_000), richText };
|
|
169
|
+
}
|
|
170
|
+
function datasetValue(binding, field, row, datasets) {
|
|
171
|
+
const source = binding === row.binding ? row.datasetRow : datasets[binding]?.[0];
|
|
172
|
+
const value = source?.[field];
|
|
173
|
+
return value == null ? '' : String(value);
|
|
174
|
+
}
|
|
175
|
+
export function parseLegacyRichText(value, depth = 0) {
|
|
176
|
+
if (depth > 12)
|
|
177
|
+
return [];
|
|
178
|
+
if (typeof value === 'string') {
|
|
179
|
+
const text = value.slice(0, 100_000);
|
|
180
|
+
return /<\/?[a-z][^>]*>/i.test(text) ? parseLegacyHtmlRichText(text) : [{ type: 'text', text }];
|
|
181
|
+
}
|
|
182
|
+
const values = Array.isArray(value) ? value : [value];
|
|
183
|
+
const result = [];
|
|
184
|
+
for (const raw of values.slice(0, 10_000)) {
|
|
185
|
+
if (typeof raw === 'string') {
|
|
186
|
+
result.push({ type: 'text', text: raw.slice(0, 100_000) });
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const node = object(raw);
|
|
190
|
+
const type = string(node.type, 'text');
|
|
191
|
+
if (type === 'br' || type === 'lineBreak') {
|
|
192
|
+
result.push({ type: 'lineBreak' });
|
|
193
|
+
}
|
|
194
|
+
else if (['div', 'paragraph', 'span', 'strong', 'emphasis', 'em'].includes(type)) {
|
|
195
|
+
result.push({
|
|
196
|
+
type: type === 'em' ? 'emphasis' : type,
|
|
197
|
+
children: parseLegacyRichText(node.children ?? node.content ?? [], depth + 1),
|
|
198
|
+
style: sanitizeRichTextStyle(node.style)
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
result.push({ type: 'text', text: string(node.text, '').slice(0, 100_000) });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
function parseLegacyHtmlRichText(value) {
|
|
208
|
+
const root = [];
|
|
209
|
+
const stack = [{ tag: 'root', children: root }];
|
|
210
|
+
const tokens = value.match(/<!--[\s\S]*?-->|<[^>]*>|[^<]+/g) ?? [];
|
|
211
|
+
for (const token of tokens.slice(0, 20_000)) {
|
|
212
|
+
if (!token.startsWith('<')) {
|
|
213
|
+
stack[stack.length - 1].children.push({ type: 'text', text: decodeHtmlEntities(token) });
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (token.startsWith('<!--') || /^<!/i.test(token))
|
|
217
|
+
continue;
|
|
218
|
+
const closing = /^<\s*\/\s*([a-z0-9]+)/i.exec(token);
|
|
219
|
+
if (closing?.[1]) {
|
|
220
|
+
const tag = closing[1].toLowerCase();
|
|
221
|
+
while (stack.length > 1) {
|
|
222
|
+
const current = stack.pop();
|
|
223
|
+
if (current?.tag === tag)
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const opening = /^<\s*([a-z0-9]+)/i.exec(token);
|
|
229
|
+
if (!opening?.[1])
|
|
230
|
+
continue;
|
|
231
|
+
const tag = opening[1].toLowerCase();
|
|
232
|
+
if (tag === 'br') {
|
|
233
|
+
stack[stack.length - 1].children.push({ type: 'lineBreak' });
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const type = richTextElementType(tag);
|
|
237
|
+
if (!type)
|
|
238
|
+
continue;
|
|
239
|
+
const children = [];
|
|
240
|
+
const styleMatch = /\bstyle\s*=\s*(["'])([\s\S]*?)\1/i.exec(token);
|
|
241
|
+
const style = sanitizeRichTextStyle(styleMatch?.[2]);
|
|
242
|
+
const node = { type, children, ...(Object.keys(style).length ? { style } : {}) };
|
|
243
|
+
stack[stack.length - 1].children.push(node);
|
|
244
|
+
if (!/\/\s*>$/.test(token))
|
|
245
|
+
stack.push({ tag, node, children });
|
|
246
|
+
}
|
|
247
|
+
return root;
|
|
248
|
+
}
|
|
249
|
+
function richTextElementType(tag) {
|
|
250
|
+
if (tag === 'div')
|
|
251
|
+
return 'div';
|
|
252
|
+
if (tag === 'p')
|
|
253
|
+
return 'paragraph';
|
|
254
|
+
if (tag === 'span')
|
|
255
|
+
return 'span';
|
|
256
|
+
if (tag === 'strong' || tag === 'b')
|
|
257
|
+
return 'strong';
|
|
258
|
+
if (tag === 'em' || tag === 'i')
|
|
259
|
+
return 'emphasis';
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
function sanitizeRichTextStyle(value) {
|
|
263
|
+
const source = typeof value === 'string'
|
|
264
|
+
? value
|
|
265
|
+
: Object.entries(object(value)).map(([key, item]) => `${key}:${String(item)}`).join(';');
|
|
266
|
+
const result = {};
|
|
267
|
+
for (const declaration of source.split(';').slice(0, 64)) {
|
|
268
|
+
const separator = declaration.indexOf(':');
|
|
269
|
+
if (separator < 1)
|
|
270
|
+
continue;
|
|
271
|
+
const key = declaration.slice(0, separator).trim().toLowerCase();
|
|
272
|
+
const raw = declaration.slice(separator + 1).trim();
|
|
273
|
+
const name = RICH_TEXT_STYLE_NAMES[key];
|
|
274
|
+
if (!name || !safeRichTextStyleValue(key, raw))
|
|
275
|
+
continue;
|
|
276
|
+
result[name] = raw;
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
const RICH_TEXT_STYLE_NAMES = {
|
|
281
|
+
'background': 'background', 'background-color': 'backgroundColor', 'box-sizing': 'boxSizing',
|
|
282
|
+
'color': 'color', 'display': 'display', 'font-size': 'fontSize', 'font-style': 'fontStyle',
|
|
283
|
+
'font-weight': 'fontWeight', 'height': 'height', 'line-height': 'lineHeight', 'margin': 'margin',
|
|
284
|
+
'margin-bottom': 'marginBottom', 'margin-left': 'marginLeft', 'margin-right': 'marginRight',
|
|
285
|
+
'margin-top': 'marginTop', 'padding': 'padding', 'padding-bottom': 'paddingBottom',
|
|
286
|
+
'padding-left': 'paddingLeft', 'padding-right': 'paddingRight', 'padding-top': 'paddingTop',
|
|
287
|
+
'text-align': 'textAlign', 'text-decoration': 'textDecoration', 'width': 'width'
|
|
288
|
+
};
|
|
289
|
+
function safeRichTextStyleValue(key, value) {
|
|
290
|
+
if (!value || value.length > 128 || /url\s*\(|expression\s*\(|javascript:|@import|var\s*\(/i.test(value))
|
|
291
|
+
return false;
|
|
292
|
+
if (key === 'color' || key === 'background' || key === 'background-color') {
|
|
293
|
+
return /^(?:#[0-9a-f]{3,8}|rgba?\([\d\s.,%]+\)|transparent|black|white)$/i.test(value);
|
|
294
|
+
}
|
|
295
|
+
if (key === 'box-sizing')
|
|
296
|
+
return /^(?:border-box|content-box)$/.test(value);
|
|
297
|
+
if (key === 'display')
|
|
298
|
+
return /^(?:block|inline|inline-block|flex)$/.test(value);
|
|
299
|
+
if (key === 'font-style')
|
|
300
|
+
return /^(?:normal|italic|oblique)$/.test(value);
|
|
301
|
+
if (key === 'font-weight')
|
|
302
|
+
return /^(?:normal|bold|[1-9]00)$/.test(value);
|
|
303
|
+
if (key === 'text-align')
|
|
304
|
+
return /^(?:left|center|right|justify)$/.test(value);
|
|
305
|
+
if (key === 'text-decoration')
|
|
306
|
+
return /^(?:none|underline|line-through)$/.test(value);
|
|
307
|
+
return /^(?:-?\d+(?:\.\d+)?(?:px|em|rem|%|vh|vw)?|auto)(?:\s+(?:-?\d+(?:\.\d+)?(?:px|em|rem|%|vh|vw)?|auto)){0,3}$/.test(value);
|
|
308
|
+
}
|
|
309
|
+
function decodeHtmlEntities(value) {
|
|
310
|
+
return value.replace(/&(?:amp|lt|gt|quot|#39);/g, entity => ({
|
|
311
|
+
'&': '&', '<': '<', '>': '>', '"': '"', ''': "'"
|
|
312
|
+
})[entity] ?? entity);
|
|
313
|
+
}
|
|
314
|
+
function mergeRanges(document, rows, sourceToOutput) {
|
|
315
|
+
const result = [];
|
|
316
|
+
if (Array.isArray(document.merges)) {
|
|
317
|
+
for (const merge of document.merges.slice(0, 100_000)) {
|
|
318
|
+
const parsed = parseA1Range(string(merge, ''));
|
|
319
|
+
if (!parsed)
|
|
320
|
+
continue;
|
|
321
|
+
const start = sourceToOutput.get(parsed.row) ?? parsed.row;
|
|
322
|
+
const end = sourceToOutput.get(parsed.endRow) ?? parsed.endRow;
|
|
323
|
+
result.push({ row: start, column: parsed.column, rowspan: end - start + 1, colspan: parsed.endColumn - parsed.column + 1 });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
for (const row of rows) {
|
|
327
|
+
for (const [columnKey, raw] of Object.entries(row.cells)) {
|
|
328
|
+
const merge = object(raw).merge;
|
|
329
|
+
if (!Array.isArray(merge) || merge.length < 2)
|
|
330
|
+
continue;
|
|
331
|
+
const rowspan = clamp(integer(merge[0], 0) + 1, 1, 10_000);
|
|
332
|
+
const colspan = clamp(integer(merge[1], 0) + 1, 1, 2048);
|
|
333
|
+
result.push({ row: row.outputRow, column: integer(columnKey, 0), rowspan, colspan });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const unique = new Map(result.map(item => [`${item.row}:${item.column}`, item]));
|
|
337
|
+
return [...unique.values()];
|
|
338
|
+
}
|
|
339
|
+
function coveredCells(merges) {
|
|
340
|
+
const covered = new Set();
|
|
341
|
+
for (const merge of merges) {
|
|
342
|
+
for (let row = merge.row; row < merge.row + merge.rowspan; row++) {
|
|
343
|
+
for (let column = merge.column; column < merge.column + merge.colspan; column++) {
|
|
344
|
+
if (row !== merge.row || column !== merge.column)
|
|
345
|
+
covered.add(`${row}:${column}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return covered;
|
|
350
|
+
}
|
|
351
|
+
function collapseDynamicGroups(cells, rows) {
|
|
352
|
+
const groups = new Map();
|
|
353
|
+
for (const cell of cells) {
|
|
354
|
+
if (!cell.dynamicGroup)
|
|
355
|
+
continue;
|
|
356
|
+
const key = `${cell.column}:${cell.dynamicGroup}`;
|
|
357
|
+
const list = groups.get(key) ?? [];
|
|
358
|
+
list.push(cell);
|
|
359
|
+
groups.set(key, list);
|
|
360
|
+
}
|
|
361
|
+
for (const list of groups.values()) {
|
|
362
|
+
list.sort((a, b) => a.row - b.row);
|
|
363
|
+
let anchor;
|
|
364
|
+
for (const cell of list) {
|
|
365
|
+
if (anchor && cell.row === anchor.row + anchor.rowspan && cell.text === anchor.text) {
|
|
366
|
+
anchor.rowspan += 1;
|
|
367
|
+
anchor.bounds = { ...anchor.bounds, height: anchor.bounds.height + (rows[cell.row]?.size ?? 0) };
|
|
368
|
+
anchor.contentBox = { ...anchor.contentBox, height: Math.max(0, anchor.contentBox.height + (rows[cell.row]?.size ?? 0)) };
|
|
369
|
+
cell.rowspan = 0;
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
anchor = cell;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function convertLayers(document, rows, columns, sourceToOutput) {
|
|
378
|
+
const result = [];
|
|
379
|
+
let zIndex = 10;
|
|
380
|
+
const addBase = (raw, type) => {
|
|
381
|
+
const item = object(raw);
|
|
382
|
+
const row = sourceToOutput.get(integer(item.row, 0)) ?? integer(item.row, 0);
|
|
383
|
+
const column = integer(item.col, 0);
|
|
384
|
+
const natural = cellBounds(rows, columns, row, column, clamp(integer(item.rowspan, 1), 1, 10_000), clamp(integer(item.colspan, 1), 1, 2048));
|
|
385
|
+
const bounds = {
|
|
386
|
+
x: natural.x + number(item.offsetX, 0),
|
|
387
|
+
y: natural.y + number(item.offsetY, 0),
|
|
388
|
+
width: clamp(number(item.width, natural.width), 1, 100_000),
|
|
389
|
+
height: clamp(number(item.height, natural.height), 1, 100_000)
|
|
390
|
+
};
|
|
391
|
+
return { item, id: safeIdentifier(item.layer_id, `${type}-${zIndex}`), bounds, contentBox: inset(bounds, [4, 4, 4, 4]), zIndex: zIndex++, type };
|
|
392
|
+
};
|
|
393
|
+
for (const raw of arrays(document.imgList, document.images)) {
|
|
394
|
+
const base = addBase(raw, 'image');
|
|
395
|
+
const source = safeResource(base.item.src ?? base.item.source);
|
|
396
|
+
if (source)
|
|
397
|
+
result.push({ ...base, type: 'image', source, alt: string(base.item.alt, '报表图片').slice(0, 512) });
|
|
398
|
+
}
|
|
399
|
+
for (const raw of arrays(document.chartList, document.charts)) {
|
|
400
|
+
const item = object(raw);
|
|
401
|
+
const config = parseObject(item.config);
|
|
402
|
+
const series = Array.isArray(config.series) ? object(config.series[0]) : {};
|
|
403
|
+
const rawChartType = string(series.type, string(object(item.extData).chartType, 'bar'));
|
|
404
|
+
if (rawChartType === 'map') {
|
|
405
|
+
const base = addBase(raw, 'map');
|
|
406
|
+
const points = (Array.isArray(series.data) ? series.data : []).slice(0, 2000).map(value => {
|
|
407
|
+
const point = object(value);
|
|
408
|
+
return { name: string(point.name, ''), value: number(point.value, 0) };
|
|
409
|
+
});
|
|
410
|
+
result.push({ ...base, type: 'map', title: string(object(config.title).text, ''), points });
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
const base = addBase(raw, 'chart');
|
|
414
|
+
const data = (Array.isArray(series.data) ? series.data : []).slice(0, 2000);
|
|
415
|
+
const axisCategories = Array.isArray(object(config.xAxis).data) ? object(config.xAxis).data : [];
|
|
416
|
+
const categories = data.map((value, index) => string(object(value).name, string(axisCategories[index], String(index + 1))));
|
|
417
|
+
const values = data.map(value => number(object(value).value ?? value, 0));
|
|
418
|
+
result.push({
|
|
419
|
+
...base,
|
|
420
|
+
type: 'chart',
|
|
421
|
+
chartType: normalizeChartType(rawChartType),
|
|
422
|
+
title: string(object(config.title).text, ''),
|
|
423
|
+
categories,
|
|
424
|
+
values
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
for (const raw of arrays(document.barcodeList)) {
|
|
429
|
+
const base = addBase(raw, 'barcode');
|
|
430
|
+
const config = parseObject(base.item.jsonString);
|
|
431
|
+
result.push({
|
|
432
|
+
...base,
|
|
433
|
+
type: 'barcode',
|
|
434
|
+
text: string(config.barcodeContent ?? config.text, '').slice(0, 2048),
|
|
435
|
+
label: string(config.text ?? config.barcodeContent, '').slice(0, 2048),
|
|
436
|
+
color: color(config.lineColor, '#000000'),
|
|
437
|
+
background: color(config.background, '#ffffff'),
|
|
438
|
+
displayValue: config.displayValue !== false,
|
|
439
|
+
fontSize: clamp(number(config.fontSize, 14), 6, 96)
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
for (const raw of arrays(document.qrcodeList)) {
|
|
443
|
+
const base = addBase(raw, 'qrcode');
|
|
444
|
+
const config = parseObject(base.item.jsonString);
|
|
445
|
+
result.push({
|
|
446
|
+
...base,
|
|
447
|
+
type: 'qrcode',
|
|
448
|
+
text: string(config.text, '').slice(0, 4096),
|
|
449
|
+
color: color(config.colorDark, '#000000'),
|
|
450
|
+
background: color(config.colorLight, '#ffffff')
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
for (const raw of arrays(document.richTextList)) {
|
|
454
|
+
const base = addBase(raw, 'richText');
|
|
455
|
+
result.push({ ...base, type: 'richText', nodes: parseLegacyRichText(base.item.content ?? base.item.text) });
|
|
456
|
+
}
|
|
457
|
+
return result.sort((a, b) => a.zIndex - b.zIndex);
|
|
458
|
+
}
|
|
459
|
+
function normalizeChartType(value) {
|
|
460
|
+
if (value === 'line' || value === 'pie' || value === 'scatter' || value === 'funnel'
|
|
461
|
+
|| value === 'radar' || value === 'gauge' || value === 'pictorialBar')
|
|
462
|
+
return value;
|
|
463
|
+
return 'bar';
|
|
464
|
+
}
|
|
465
|
+
function paginate(rows, config) {
|
|
466
|
+
const paperHeightMm = string(config.layout, 'portrait') === 'landscape'
|
|
467
|
+
? number(config.width, 297) : number(config.height, 297);
|
|
468
|
+
const margin = clamp(number(config.marginY, 10), 0, paperHeightMm / 3);
|
|
469
|
+
const pageHeight = Math.max(96, (paperHeightMm - margin * 2) * 96 / 25.4);
|
|
470
|
+
const pages = [];
|
|
471
|
+
let firstRow = 0;
|
|
472
|
+
let top = 0;
|
|
473
|
+
while (firstRow < rows.length) {
|
|
474
|
+
let lastRow = firstRow;
|
|
475
|
+
while (lastRow + 1 < rows.length && rows[lastRow + 1].offset + rows[lastRow + 1].size - top <= pageHeight)
|
|
476
|
+
lastRow++;
|
|
477
|
+
pages.push({ index: pages.length, top, height: pageHeight, firstRow, lastRow });
|
|
478
|
+
firstRow = lastRow + 1;
|
|
479
|
+
top = rows[firstRow]?.offset ?? rows.reduce((sum, row) => sum + row.size, 0);
|
|
480
|
+
}
|
|
481
|
+
return pages;
|
|
482
|
+
}
|
|
483
|
+
function freezePoint(value, rows, columns) {
|
|
484
|
+
const match = /^([A-Z]+)([1-9]\d*)$/.exec(value.toUpperCase());
|
|
485
|
+
if (!match?.[1] || !match[2])
|
|
486
|
+
return { x: 0, y: 0 };
|
|
487
|
+
const column = lettersToColumn(match[1]);
|
|
488
|
+
const row = Number(match[2]) - 1;
|
|
489
|
+
return {
|
|
490
|
+
x: columns[column]?.offset ?? columns.reduce((sum, track) => sum + track.size, 0),
|
|
491
|
+
y: rows[row]?.offset ?? rows.reduce((sum, track) => sum + track.size, 0)
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
function tracks(count, fallback, size, hidden) {
|
|
495
|
+
const result = [];
|
|
496
|
+
let offset = 0;
|
|
497
|
+
for (let index = 0; index < count; index++) {
|
|
498
|
+
const isHidden = hidden.has(index);
|
|
499
|
+
const current = isHidden ? 0 : clamp(number(size(index), fallback), 0, 2000);
|
|
500
|
+
result.push({ index, offset, size: current, hidden: isHidden });
|
|
501
|
+
offset += current;
|
|
502
|
+
}
|
|
503
|
+
return result;
|
|
504
|
+
}
|
|
505
|
+
function cellBounds(rows, columns, row, column, rowspan, colspan) {
|
|
506
|
+
return {
|
|
507
|
+
x: columns[column]?.offset ?? 0,
|
|
508
|
+
y: rows[row]?.offset ?? 0,
|
|
509
|
+
width: sumTrack(columns, column, colspan),
|
|
510
|
+
height: sumTrack(rows, row, rowspan)
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
function sumTrack(tracks, start, count) {
|
|
514
|
+
let result = 0;
|
|
515
|
+
for (let index = start; index < Math.min(tracks.length, start + count); index++)
|
|
516
|
+
result += tracks[index].size;
|
|
517
|
+
return result;
|
|
518
|
+
}
|
|
519
|
+
function normalizeStyle(source) {
|
|
520
|
+
const font = object(source.font);
|
|
521
|
+
const border = object(source.border);
|
|
522
|
+
return {
|
|
523
|
+
background: color(source.bgcolor ?? source.background, '#FFFFFF'),
|
|
524
|
+
color: color(source.color, '#111827'),
|
|
525
|
+
fontFamily: safeFont(font.name),
|
|
526
|
+
fontSize: clamp(number(font.size, 11), 6, 96),
|
|
527
|
+
fontWeight: font.bold === true ? 'bold' : 'normal',
|
|
528
|
+
fontStyle: font.italic === true ? 'italic' : 'normal',
|
|
529
|
+
textAlign: enumValue(source.align, ['left', 'center', 'right'], 'left'),
|
|
530
|
+
verticalAlign: enumValue(source.valign, ['top', 'middle', 'bottom'], 'middle'),
|
|
531
|
+
whiteSpace: source.textwrap === false ? 'nowrap' : 'pre-wrap',
|
|
532
|
+
borderTop: borderValue(border.top),
|
|
533
|
+
borderRight: borderValue(border.right),
|
|
534
|
+
borderBottom: borderValue(border.bottom),
|
|
535
|
+
borderLeft: borderValue(border.left)
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function normalizePadding(value) {
|
|
539
|
+
if (Array.isArray(value)) {
|
|
540
|
+
const values = value.slice(0, 4).map(item => clamp(number(item, 4), 0, 100));
|
|
541
|
+
if (values.length === 2)
|
|
542
|
+
return [values[0], values[1], values[0], values[1]];
|
|
543
|
+
if (values.length === 4)
|
|
544
|
+
return values;
|
|
545
|
+
}
|
|
546
|
+
const padding = clamp(number(value, 4), 0, 100);
|
|
547
|
+
return [padding, padding, padding, padding];
|
|
548
|
+
}
|
|
549
|
+
function inset(bounds, padding) {
|
|
550
|
+
return {
|
|
551
|
+
x: bounds.x + padding[3],
|
|
552
|
+
y: bounds.y + padding[0],
|
|
553
|
+
width: Math.max(0, bounds.width - padding[1] - padding[3]),
|
|
554
|
+
height: Math.max(0, bounds.height - padding[0] - padding[2])
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function borderValue(value) {
|
|
558
|
+
if (!Array.isArray(value) || value.length < 2)
|
|
559
|
+
return '1px solid #E5E7EB';
|
|
560
|
+
const width = string(value[0], 'thin') === 'thick' ? 3 : string(value[0], 'thin') === 'medium' ? 2 : 1;
|
|
561
|
+
return `${width}px solid ${color(value[1], '#9CA3AF')}`;
|
|
562
|
+
}
|
|
563
|
+
function parseA1Range(value) {
|
|
564
|
+
const match = /^([A-Z]+)([1-9]\d*):([A-Z]+)([1-9]\d*)$/i.exec(value);
|
|
565
|
+
if (!match?.[1] || !match[2] || !match[3] || !match[4])
|
|
566
|
+
return undefined;
|
|
567
|
+
return { row: Number(match[2]) - 1, column: lettersToColumn(match[1]), endRow: Number(match[4]) - 1, endColumn: lettersToColumn(match[3]) };
|
|
568
|
+
}
|
|
569
|
+
function lettersToColumn(value) {
|
|
570
|
+
let result = 0;
|
|
571
|
+
for (const character of value.toUpperCase())
|
|
572
|
+
result = result * 26 + character.charCodeAt(0) - 64;
|
|
573
|
+
return Math.max(0, result - 1);
|
|
574
|
+
}
|
|
575
|
+
function areaEnd(document, key) {
|
|
576
|
+
return clamp(integer(object(document.area)[key], 0), 0, MAX_TRACKS - 1);
|
|
577
|
+
}
|
|
578
|
+
function maxCellColumn(rows) {
|
|
579
|
+
let result = 0;
|
|
580
|
+
for (const row of rows)
|
|
581
|
+
for (const key of Object.keys(row.cells))
|
|
582
|
+
result = Math.max(result, integer(key, 0));
|
|
583
|
+
return result;
|
|
584
|
+
}
|
|
585
|
+
function arrays(...values) {
|
|
586
|
+
return values.flatMap(value => Array.isArray(value) ? value : []).slice(0, 100_000);
|
|
587
|
+
}
|
|
588
|
+
function parseObject(value) {
|
|
589
|
+
if (typeof value !== 'string')
|
|
590
|
+
return object(value);
|
|
591
|
+
try {
|
|
592
|
+
return object(JSON.parse(value));
|
|
593
|
+
}
|
|
594
|
+
catch {
|
|
595
|
+
return {};
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function safeResource(value) {
|
|
599
|
+
const source = string(value, '').trim();
|
|
600
|
+
if (!source || source.startsWith('//') || source.includes('\\') || /[\u0000-\u001f]/.test(source))
|
|
601
|
+
return undefined;
|
|
602
|
+
if (source.startsWith('/') || /^[A-Za-z0-9_.-]+\//.test(source))
|
|
603
|
+
return source;
|
|
604
|
+
try {
|
|
605
|
+
const url = new URL(source);
|
|
606
|
+
return ['http:', 'https:'].includes(url.protocol) && !url.username && !url.password ? source : undefined;
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
return undefined;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function safeLink(value) {
|
|
613
|
+
const link = string(value, '').trim();
|
|
614
|
+
if (!link)
|
|
615
|
+
return undefined;
|
|
616
|
+
if (link.startsWith('/') && !link.startsWith('//') && !link.includes('\\'))
|
|
617
|
+
return link;
|
|
618
|
+
try {
|
|
619
|
+
const url = new URL(link);
|
|
620
|
+
return url.protocol === 'https:' && !url.username && !url.password ? link : undefined;
|
|
621
|
+
}
|
|
622
|
+
catch {
|
|
623
|
+
return undefined;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function safeIdentifier(value, fallback) {
|
|
627
|
+
const result = string(value, fallback);
|
|
628
|
+
return /^[A-Za-z0-9_.-]{1,128}$/.test(result) ? result : fallback;
|
|
629
|
+
}
|
|
630
|
+
function safeFont(value) {
|
|
631
|
+
const font = string(value, 'Microsoft YaHei');
|
|
632
|
+
return /^[\p{L}\p{N} _,-]{1,128}$/u.test(font) ? font : 'Microsoft YaHei';
|
|
633
|
+
}
|
|
634
|
+
function color(value, fallback) {
|
|
635
|
+
const candidate = string(value, fallback).trim();
|
|
636
|
+
return SAFE_COLOR.test(candidate) ? candidate : fallback;
|
|
637
|
+
}
|
|
638
|
+
function integerSet(value) {
|
|
639
|
+
return new Set((Array.isArray(value) ? value : []).map(item => integer(item, -1)).filter(item => item >= 0));
|
|
640
|
+
}
|
|
641
|
+
function object(value) {
|
|
642
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
643
|
+
}
|
|
644
|
+
function string(value, fallback) {
|
|
645
|
+
return typeof value === 'string' ? value : value == null ? fallback : String(value);
|
|
646
|
+
}
|
|
647
|
+
function number(value, fallback) {
|
|
648
|
+
const result = typeof value === 'number' ? value : Number(value);
|
|
649
|
+
return Number.isFinite(result) ? result : fallback;
|
|
650
|
+
}
|
|
651
|
+
function integer(value, fallback) {
|
|
652
|
+
return Math.trunc(number(value, fallback));
|
|
653
|
+
}
|
|
654
|
+
function clamp(value, minimum, maximum) {
|
|
655
|
+
return Math.min(maximum, Math.max(minimum, value));
|
|
656
|
+
}
|
|
657
|
+
function enumValue(value, values, fallback) {
|
|
658
|
+
return values.includes(value) ? value : fallback;
|
|
659
|
+
}
|
|
660
|
+
function deepFreeze(value) {
|
|
661
|
+
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
662
|
+
Object.freeze(value);
|
|
663
|
+
for (const child of Object.values(value))
|
|
664
|
+
deepFreeze(child);
|
|
665
|
+
}
|
|
666
|
+
return value;
|
|
667
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export interface NativeBounds {
|
|
2
|
+
readonly x: number;
|
|
3
|
+
readonly y: number;
|
|
4
|
+
readonly width: number;
|
|
5
|
+
readonly height: number;
|
|
6
|
+
}
|
|
7
|
+
export interface NativeAxisTrack {
|
|
8
|
+
readonly index: number;
|
|
9
|
+
readonly offset: number;
|
|
10
|
+
readonly size: number;
|
|
11
|
+
readonly hidden: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface NativeCellStyle {
|
|
14
|
+
readonly background: string;
|
|
15
|
+
readonly color: string;
|
|
16
|
+
readonly fontFamily: string;
|
|
17
|
+
readonly fontSize: number;
|
|
18
|
+
readonly fontWeight: 'normal' | 'bold';
|
|
19
|
+
readonly fontStyle: 'normal' | 'italic';
|
|
20
|
+
readonly textAlign: 'left' | 'center' | 'right';
|
|
21
|
+
readonly verticalAlign: 'top' | 'middle' | 'bottom';
|
|
22
|
+
readonly whiteSpace: 'normal' | 'pre-wrap' | 'nowrap';
|
|
23
|
+
readonly borderTop: string;
|
|
24
|
+
readonly borderRight: string;
|
|
25
|
+
readonly borderBottom: string;
|
|
26
|
+
readonly borderLeft: string;
|
|
27
|
+
}
|
|
28
|
+
export type NativeRichTextStyle = Readonly<Record<string, string>>;
|
|
29
|
+
export type NativeRichTextNode = {
|
|
30
|
+
readonly type: 'text';
|
|
31
|
+
readonly text: string;
|
|
32
|
+
} | {
|
|
33
|
+
readonly type: 'lineBreak';
|
|
34
|
+
} | {
|
|
35
|
+
readonly type: 'div' | 'paragraph' | 'span' | 'strong' | 'emphasis';
|
|
36
|
+
readonly children: readonly NativeRichTextNode[];
|
|
37
|
+
readonly style?: NativeRichTextStyle;
|
|
38
|
+
};
|
|
39
|
+
export interface NativeCell {
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly row: number;
|
|
42
|
+
readonly column: number;
|
|
43
|
+
readonly rowspan: number;
|
|
44
|
+
readonly colspan: number;
|
|
45
|
+
readonly bounds: NativeBounds;
|
|
46
|
+
readonly contentBox: NativeBounds;
|
|
47
|
+
readonly zIndex: number;
|
|
48
|
+
readonly text: string;
|
|
49
|
+
readonly richText?: readonly NativeRichTextNode[];
|
|
50
|
+
readonly hyperlink?: string;
|
|
51
|
+
readonly style: NativeCellStyle;
|
|
52
|
+
}
|
|
53
|
+
export interface NativeLayerBase {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly bounds: NativeBounds;
|
|
56
|
+
readonly contentBox: NativeBounds;
|
|
57
|
+
readonly zIndex: number;
|
|
58
|
+
}
|
|
59
|
+
export type NativeChartType = 'bar' | 'line' | 'pie' | 'scatter' | 'funnel' | 'radar' | 'gauge' | 'pictorialBar';
|
|
60
|
+
export type NativeLayer = (NativeLayerBase & {
|
|
61
|
+
readonly type: 'image';
|
|
62
|
+
readonly source: string;
|
|
63
|
+
readonly alt: string;
|
|
64
|
+
}) | (NativeLayerBase & {
|
|
65
|
+
readonly type: 'chart';
|
|
66
|
+
readonly chartType: NativeChartType;
|
|
67
|
+
readonly title: string;
|
|
68
|
+
readonly categories: readonly string[];
|
|
69
|
+
readonly values: readonly number[];
|
|
70
|
+
}) | (NativeLayerBase & {
|
|
71
|
+
readonly type: 'map';
|
|
72
|
+
readonly title: string;
|
|
73
|
+
readonly points: readonly {
|
|
74
|
+
readonly name: string;
|
|
75
|
+
readonly value: number;
|
|
76
|
+
}[];
|
|
77
|
+
}) | (NativeLayerBase & {
|
|
78
|
+
readonly type: 'barcode';
|
|
79
|
+
readonly text: string;
|
|
80
|
+
readonly label: string;
|
|
81
|
+
readonly color: string;
|
|
82
|
+
readonly background: string;
|
|
83
|
+
readonly displayValue: boolean;
|
|
84
|
+
readonly fontSize: number;
|
|
85
|
+
}) | (NativeLayerBase & {
|
|
86
|
+
readonly type: 'qrcode';
|
|
87
|
+
readonly text: string;
|
|
88
|
+
readonly color: string;
|
|
89
|
+
readonly background: string;
|
|
90
|
+
}) | (NativeLayerBase & {
|
|
91
|
+
readonly type: 'richText';
|
|
92
|
+
readonly nodes: readonly NativeRichTextNode[];
|
|
93
|
+
});
|
|
94
|
+
export interface NativePage {
|
|
95
|
+
readonly index: number;
|
|
96
|
+
readonly top: number;
|
|
97
|
+
readonly height: number;
|
|
98
|
+
readonly firstRow: number;
|
|
99
|
+
readonly lastRow: number;
|
|
100
|
+
}
|
|
101
|
+
export interface NativeViewerSheet {
|
|
102
|
+
readonly id: string;
|
|
103
|
+
readonly name: string;
|
|
104
|
+
readonly order: number;
|
|
105
|
+
readonly width: number;
|
|
106
|
+
readonly height: number;
|
|
107
|
+
readonly rows: readonly NativeAxisTrack[];
|
|
108
|
+
readonly columns: readonly NativeAxisTrack[];
|
|
109
|
+
readonly cells: readonly NativeCell[];
|
|
110
|
+
readonly layers: readonly NativeLayer[];
|
|
111
|
+
readonly pages: readonly NativePage[];
|
|
112
|
+
readonly frozen: {
|
|
113
|
+
readonly x: number;
|
|
114
|
+
readonly y: number;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export interface NativeViewerDocument {
|
|
118
|
+
readonly schemaVersion: 'native-v1';
|
|
119
|
+
readonly reportId: string;
|
|
120
|
+
readonly revision: string;
|
|
121
|
+
readonly title: string;
|
|
122
|
+
readonly activeSheetId: string;
|
|
123
|
+
readonly sheets: readonly NativeViewerSheet[];
|
|
124
|
+
}
|
|
125
|
+
export type NativeDatasetRow = Readonly<Record<string, string | boolean | null>>;
|
|
126
|
+
export type NativeDatasetValues = Readonly<Record<string, readonly NativeDatasetRow[]>>;
|
|
127
|
+
export interface NativeConversionOptions {
|
|
128
|
+
readonly datasets?: NativeDatasetValues;
|
|
129
|
+
readonly defaultRowHeight?: number;
|
|
130
|
+
readonly defaultColumnWidth?: number;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qianxiang-ai/fu-report-viewer-engine",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.1.7",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
5
|
+
"author": "位志国 <ijunfu@aliyun.com>",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public",
|
|
20
|
+
"registry": "https://registry.npmjs.org/"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@qianxiang-ai/fu-report-contracts": "1.1.7"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "node ../../scripts/clean-dist.mjs && tsc -p tsconfig.json",
|
|
27
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
28
|
+
"test": "vitest run src"
|
|
29
|
+
}
|
|
6
30
|
}
|
package/README.md
DELETED