@dou-ui/sheet-xlsx 0.0.0-stage → 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.js +94 -0
- package/dist/messages.js.map +1 -0
- package/dist/read-styles.js +301 -0
- package/dist/read-styles.js.map +1 -0
- package/dist/read.js +1099 -0
- package/dist/read.js.map +1 -0
- package/dist/styles.js +124 -0
- package/dist/styles.js.map +1 -0
- package/dist/types/index.d.ts +25 -0
- package/dist/types/messages.d.ts +20 -0
- package/dist/types/read-styles.d.ts +28 -0
- package/dist/types/read.d.ts +36 -0
- package/dist/types/styles.d.ts +33 -0
- package/dist/types/write.d.ts +13 -0
- package/dist/types/xml-read.d.ts +45 -0
- package/dist/types/xml.d.ts +8 -0
- package/dist/types/zip.d.ts +32 -0
- package/dist/write.js +799 -0
- package/dist/write.js.map +1 -0
- package/dist/xml-read.js +166 -0
- package/dist/xml-read.js.map +1 -0
- package/dist/xml.js +20 -0
- package/dist/xml.js.map +1 -0
- package/dist/zip.js +168 -0
- package/dist/zip.js.map +1 -0
- package/package.json +44 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 daidr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @dou-ui/sheet-xlsx
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[DouUI](https://github.com/daidr/dou-ui) 电子表格的 .xlsx 导入导出:把 `@dou-ui/sheet` 的工作簿导出为 .xlsx,或从 .xlsx 读入,不依赖第三方库。
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
bun add @dou-ui/sheet-xlsx @dou-ui/sheet
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
用法见 [文档](https://ui.daidr.me/sheet/xlsx)。
|
|
10
|
+
|
|
11
|
+
许可证:MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { sheetXlsxLocales, sheetXlsxMessagesFor } from "./messages.js";
|
|
2
|
+
import { readXlsx } from "./read.js";
|
|
3
|
+
import { writeXlsx } from "./write.js";
|
|
4
|
+
import { defineSheetExporter, defineSheetImporter } from "@dou-ui/sheet/core";
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
7
|
+
/**
|
|
8
|
+
* The name in the export menu, said as the sheet's language says CSV's:
|
|
9
|
+
* `CSV 文件 (.csv)` becomes `XLSX 文件 (.xlsx)`.
|
|
10
|
+
*/
|
|
11
|
+
var defaultLabel = (m) => m.file.csv.includes("CSV") ? m.file.csv.replaceAll("CSV", "XLSX").replaceAll(".csv", ".xlsx") : "XLSX (.xlsx)";
|
|
12
|
+
/** Writes the workbook, one sheet or the selected cells as an .xlsx file. */
|
|
13
|
+
var xlsxExporter = defineSheetExporter({
|
|
14
|
+
name: "xlsx",
|
|
15
|
+
label: defaultLabel,
|
|
16
|
+
extension: "xlsx",
|
|
17
|
+
mime: MIME,
|
|
18
|
+
scopes: [
|
|
19
|
+
"workbook",
|
|
20
|
+
"sheet",
|
|
21
|
+
"selection"
|
|
22
|
+
],
|
|
23
|
+
async export(source, options) {
|
|
24
|
+
const bytes = await writeXlsx(source, options);
|
|
25
|
+
return new Blob([bytes], { type: MIME });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
var isZip = (head) => head[0] === 80 && head[1] === 75 && head[2] === 3 && head[3] === 4;
|
|
29
|
+
/** Reads an .xlsx file as a workbook; what it can't bring over comes back in `warnings`. */
|
|
30
|
+
var xlsxImporter = defineSheetImporter({
|
|
31
|
+
name: "xlsx",
|
|
32
|
+
label: defaultLabel,
|
|
33
|
+
accept: [
|
|
34
|
+
".xlsx",
|
|
35
|
+
".xlsm",
|
|
36
|
+
MIME,
|
|
37
|
+
"application/vnd.ms-excel.sheet.macroEnabled.12"
|
|
38
|
+
],
|
|
39
|
+
sniff: isZip,
|
|
40
|
+
import: (file, context, options) => readXlsx(file, {
|
|
41
|
+
locale: context.locale,
|
|
42
|
+
signal: context.signal,
|
|
43
|
+
...options
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* The .xlsx extension: adds exporting and importing .xlsx files to the
|
|
48
|
+
* toolbar, to `exportFile('xlsx')` / `saveFile('xlsx')` and to `importFile`.
|
|
49
|
+
*/
|
|
50
|
+
function xlsx(options = {}) {
|
|
51
|
+
const { label, ...defaults } = options;
|
|
52
|
+
return {
|
|
53
|
+
name: "xlsx",
|
|
54
|
+
exporters: [{
|
|
55
|
+
...xlsxExporter,
|
|
56
|
+
label: label ?? xlsxExporter.label,
|
|
57
|
+
export: (source, own) => xlsxExporter.export(source, {
|
|
58
|
+
...defaults,
|
|
59
|
+
...own
|
|
60
|
+
})
|
|
61
|
+
}],
|
|
62
|
+
importers: [{
|
|
63
|
+
...xlsxImporter,
|
|
64
|
+
label: label ?? xlsxImporter.label,
|
|
65
|
+
import: (file, context, own) => xlsxImporter.import(file, context, {
|
|
66
|
+
...defaults,
|
|
67
|
+
...own
|
|
68
|
+
})
|
|
69
|
+
}]
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export { readXlsx, sheetXlsxLocales, sheetXlsxMessagesFor, writeXlsx, xlsx, xlsxExporter, xlsxImporter };
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { SheetExtension, SheetLabel } from '@dou-ui/sheet'\n// only the file side of the sheet, so that a Worker writing .xlsx files loads no components\nimport { defineSheetExporter, defineSheetImporter } from '@dou-ui/sheet/core'\nimport { readXlsx, type SheetXlsxImportOptions, type SheetXlsxImportResult } from './read'\nimport { writeXlsx, type SheetXlsxExportOptions } from './write'\n\nexport { writeXlsx, type SheetXlsxExportOptions } from './write'\nexport {\n readXlsx,\n type SheetXlsxErrorCode,\n type SheetXlsxImportOptions,\n type SheetXlsxImportResult,\n type SheetXlsxReadOptions,\n type SheetXlsxWarning,\n} from './read'\nexport { sheetXlsxLocales, sheetXlsxMessagesFor } from './messages'\nexport type { SheetXlsxMessages, SheetXlsxMessagesInput, SheetXlsxWarningCode } from './messages'\n\ndeclare module '@dou-ui/sheet' {\n interface SheetExporterOptions {\n xlsx: SheetXlsxExportOptions\n }\n}\n\nconst MIME = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\n\n/**\n * The name in the export menu, said as the sheet's language says CSV's:\n * `CSV 文件 (.csv)` becomes `XLSX 文件 (.xlsx)`.\n */\nconst defaultLabel: SheetLabel = (m) =>\n m.file.csv.includes('CSV')\n ? m.file.csv.replaceAll('CSV', 'XLSX').replaceAll('.csv', '.xlsx')\n : 'XLSX (.xlsx)'\n\n/** Writes the workbook, one sheet or the selected cells as an .xlsx file. */\nexport const xlsxExporter = defineSheetExporter<SheetXlsxExportOptions>({\n name: 'xlsx',\n label: defaultLabel,\n extension: 'xlsx',\n mime: MIME,\n scopes: ['workbook', 'sheet', 'selection'],\n async export(source, options) {\n const bytes = await writeXlsx(source, options)\n return new Blob([bytes as BlobPart], { type: MIME })\n },\n})\n\n// a zip starts so; whether it is an .xlsx file shows once it is read\nconst isZip = (head: Uint8Array) =>\n head[0] === 0x50 && head[1] === 0x4b && head[2] === 0x03 && head[3] === 0x04\n\n/** Reads an .xlsx file as a workbook; what it can't bring over comes back in `warnings`. */\nexport const xlsxImporter = defineSheetImporter<SheetXlsxImportOptions, SheetXlsxImportResult>({\n name: 'xlsx',\n label: defaultLabel,\n accept: ['.xlsx', '.xlsm', MIME, 'application/vnd.ms-excel.sheet.macroEnabled.12'],\n sniff: isZip,\n import: (file, context, options) =>\n readXlsx(file, { locale: context.locale, signal: context.signal, ...options }),\n})\n\nexport interface SheetXlsxOptions extends SheetXlsxExportOptions, SheetXlsxImportOptions {\n /** The name in the toolbar's export menu, and of the files in the import hints. */\n label?: SheetLabel\n}\n\n/**\n * The .xlsx extension: adds exporting and importing .xlsx files to the\n * toolbar, to `exportFile('xlsx')` / `saveFile('xlsx')` and to `importFile`.\n */\nexport function xlsx(options: SheetXlsxOptions = {}): SheetExtension {\n const { label, ...defaults } = options\n return {\n name: 'xlsx',\n exporters: [\n {\n ...xlsxExporter,\n label: label ?? xlsxExporter.label,\n export: (source, own) => xlsxExporter.export(source, { ...defaults, ...own }),\n },\n ],\n importers: [\n {\n ...xlsxImporter,\n label: label ?? xlsxImporter.label,\n import: (file, context, own) => xlsxImporter.import(file, context, { ...defaults, ...own }),\n },\n ],\n }\n}\n"],"mappings":";;;;;AAwBA,IAAM,OAAO;;;;;AAMb,IAAM,gBAA4B,MAChC,EAAE,KAAK,IAAI,SAAS,KAAK,IACrB,EAAE,KAAK,IAAI,WAAW,OAAO,MAAM,CAAC,CAAC,WAAW,QAAQ,OAAO,IAC/D;;AAGN,IAAa,eAAe,oBAA4C;CACtE,MAAM;CACN,OAAO;CACP,WAAW;CACX,MAAM;CACN,QAAQ;EAAC;EAAY;EAAS;CAAW;CACzC,MAAM,OAAO,QAAQ,SAAS;EAC5B,MAAM,QAAQ,MAAM,UAAU,QAAQ,OAAO;EAC7C,OAAO,IAAI,KAAK,CAAC,KAAiB,GAAG,EAAE,MAAM,KAAK,CAAC;CACrD;AACF,CAAC;AAGD,IAAM,SAAS,SACb,KAAK,OAAO,MAAQ,KAAK,OAAO,MAAQ,KAAK,OAAO,KAAQ,KAAK,OAAO;;AAG1E,IAAa,eAAe,oBAAmE;CAC7F,MAAM;CACN,OAAO;CACP,QAAQ;EAAC;EAAS;EAAS;EAAM;CAAgD;CACjF,OAAO;CACP,SAAS,MAAM,SAAS,YACtB,SAAS,MAAM;EAAE,QAAQ,QAAQ;EAAQ,QAAQ,QAAQ;EAAQ,GAAG;CAAQ,CAAC;AACjF,CAAC;;;;;AAWD,SAAgB,KAAK,UAA4B,CAAC,GAAmB;CACnE,MAAM,EAAE,OAAO,GAAG,aAAa;CAC/B,OAAO;EACL,MAAM;EACN,WAAW,CACT;GACE,GAAG;GACH,OAAO,SAAS,aAAa;GAC7B,SAAS,QAAQ,QAAQ,aAAa,OAAO,QAAQ;IAAE,GAAG;IAAU,GAAG;GAAI,CAAC;EAC9E,CACF;EACA,WAAW,CACT;GACE,GAAG;GACH,OAAO,SAAS,aAAa;GAC7B,SAAS,MAAM,SAAS,QAAQ,aAAa,OAAO,MAAM,SAAS;IAAE,GAAG;IAAU,GAAG;GAAI,CAAC;EAC5F,CACF;CACF;AACF"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/messages.ts
|
|
2
|
+
var zhCN = {
|
|
3
|
+
warnings: {
|
|
4
|
+
border: "边框",
|
|
5
|
+
font: "字号",
|
|
6
|
+
richText: "单元格里部分文字的格式",
|
|
7
|
+
image: "图片和形状",
|
|
8
|
+
chart: "图表",
|
|
9
|
+
pivot: "数据透视表",
|
|
10
|
+
table: "表格对象和引用它的公式",
|
|
11
|
+
macro: "宏",
|
|
12
|
+
hyperlink: "指向其他文件的超链接",
|
|
13
|
+
password: "工作表和工作簿保护的密码",
|
|
14
|
+
hiddenSheet: "隐藏的工作表",
|
|
15
|
+
external: "引用其他文件的公式",
|
|
16
|
+
name: "定义的名称",
|
|
17
|
+
conditional: "无法对应的条件格式",
|
|
18
|
+
validation: "无法对应的数据验证",
|
|
19
|
+
filter: "无法对应的筛选条件"
|
|
20
|
+
},
|
|
21
|
+
notXlsx: "这不是 .xlsx 文件",
|
|
22
|
+
damaged: "文件已损坏",
|
|
23
|
+
locked: "文件设了密码,请先在原来的软件里取消密码"
|
|
24
|
+
};
|
|
25
|
+
var zhTW = {
|
|
26
|
+
warnings: {
|
|
27
|
+
border: "框線",
|
|
28
|
+
font: "字級",
|
|
29
|
+
richText: "儲存格裡部分文字的格式",
|
|
30
|
+
image: "圖片和圖形",
|
|
31
|
+
chart: "圖表",
|
|
32
|
+
pivot: "樞紐分析表",
|
|
33
|
+
table: "表格物件和參照它的公式",
|
|
34
|
+
macro: "巨集",
|
|
35
|
+
hyperlink: "指向其他檔案的超連結",
|
|
36
|
+
password: "工作表和活頁簿保護的密碼",
|
|
37
|
+
hiddenSheet: "隱藏的工作表",
|
|
38
|
+
external: "參照其他檔案的公式",
|
|
39
|
+
name: "定義的名稱",
|
|
40
|
+
conditional: "無法對應的設定格式化條件",
|
|
41
|
+
validation: "無法對應的資料驗證",
|
|
42
|
+
filter: "無法對應的篩選條件"
|
|
43
|
+
},
|
|
44
|
+
notXlsx: "這不是 .xlsx 檔案",
|
|
45
|
+
damaged: "檔案已損毀",
|
|
46
|
+
locked: "檔案設了密碼,請先在原來的軟體裡取消密碼"
|
|
47
|
+
};
|
|
48
|
+
var en = {
|
|
49
|
+
warnings: {
|
|
50
|
+
border: "Borders",
|
|
51
|
+
font: "Font sizes",
|
|
52
|
+
richText: "Formatting of part of the text in a cell",
|
|
53
|
+
image: "Pictures and shapes",
|
|
54
|
+
chart: "Charts",
|
|
55
|
+
pivot: "Pivot tables",
|
|
56
|
+
table: "Tables and formulas that refer to them",
|
|
57
|
+
macro: "Macros",
|
|
58
|
+
hyperlink: "Hyperlinks to other files",
|
|
59
|
+
password: "Passwords of sheet and workbook protection",
|
|
60
|
+
hiddenSheet: "Hidden sheets",
|
|
61
|
+
external: "Formulas that refer to other files",
|
|
62
|
+
name: "Defined names",
|
|
63
|
+
conditional: "Conditional formats the sheet doesn't have",
|
|
64
|
+
validation: "Data validations the sheet doesn't have",
|
|
65
|
+
filter: "Filter conditions the sheet doesn't have"
|
|
66
|
+
},
|
|
67
|
+
notXlsx: "This isn't an .xlsx file",
|
|
68
|
+
damaged: "The file is damaged",
|
|
69
|
+
locked: "The file has a password; remove it in the program it came from first"
|
|
70
|
+
};
|
|
71
|
+
var sheetXlsxLocales = {
|
|
72
|
+
"zh-CN": zhCN,
|
|
73
|
+
"zh-TW": zhTW,
|
|
74
|
+
en
|
|
75
|
+
};
|
|
76
|
+
/** The texts for a language, such as `zh-CN`; Chinese or English by its first part, English otherwise. */
|
|
77
|
+
function sheetXlsxMessagesFor(locale = "zh-CN") {
|
|
78
|
+
return sheetXlsxLocales[locale] ?? sheetXlsxLocales[locale.split("-")[0]] ?? (locale.startsWith("zh") ? zhCN : en);
|
|
79
|
+
}
|
|
80
|
+
/** A language's texts with some of them given instead. */
|
|
81
|
+
function mergeXlsxMessages(base, own) {
|
|
82
|
+
if (!own) return base;
|
|
83
|
+
return {
|
|
84
|
+
...base,
|
|
85
|
+
...own,
|
|
86
|
+
warnings: {
|
|
87
|
+
...base.warnings,
|
|
88
|
+
...own.warnings
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export { mergeXlsxMessages, sheetXlsxLocales, sheetXlsxMessagesFor };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","names":[],"sources":["../src/messages.ts"],"sourcesContent":["/** The texts of reading .xlsx files: what couldn't be brought over, and why a file couldn't be read. */\nexport interface SheetXlsxMessages {\n /** What a file had that the sheet can't hold, by warning code: a short noun phrase each, to be listed. */\n warnings: Record<SheetXlsxWarningCode, string>\n /** Why a file couldn't be read, shown in the sheet's hint. */\n notXlsx: string\n damaged: string\n locked: string\n}\n\n/** What `readXlsx` couldn't bring over, as the `code` of its warnings. */\nexport type SheetXlsxWarningCode =\n | 'border'\n | 'font'\n | 'richText'\n | 'image'\n | 'chart'\n | 'pivot'\n | 'table'\n | 'macro'\n | 'hyperlink'\n | 'password'\n | 'hiddenSheet'\n | 'external'\n | 'name'\n | 'conditional'\n | 'validation'\n | 'filter'\n\nconst zhCN: SheetXlsxMessages = {\n warnings: {\n border: '边框',\n font: '字号',\n richText: '单元格里部分文字的格式',\n image: '图片和形状',\n chart: '图表',\n pivot: '数据透视表',\n table: '表格对象和引用它的公式',\n macro: '宏',\n hyperlink: '指向其他文件的超链接',\n password: '工作表和工作簿保护的密码',\n hiddenSheet: '隐藏的工作表',\n external: '引用其他文件的公式',\n name: '定义的名称',\n conditional: '无法对应的条件格式',\n validation: '无法对应的数据验证',\n filter: '无法对应的筛选条件',\n },\n notXlsx: '这不是 .xlsx 文件',\n damaged: '文件已损坏',\n locked: '文件设了密码,请先在原来的软件里取消密码',\n}\n\nconst zhTW: SheetXlsxMessages = {\n warnings: {\n border: '框線',\n font: '字級',\n richText: '儲存格裡部分文字的格式',\n image: '圖片和圖形',\n chart: '圖表',\n pivot: '樞紐分析表',\n table: '表格物件和參照它的公式',\n macro: '巨集',\n hyperlink: '指向其他檔案的超連結',\n password: '工作表和活頁簿保護的密碼',\n hiddenSheet: '隱藏的工作表',\n external: '參照其他檔案的公式',\n name: '定義的名稱',\n conditional: '無法對應的設定格式化條件',\n validation: '無法對應的資料驗證',\n filter: '無法對應的篩選條件',\n },\n notXlsx: '這不是 .xlsx 檔案',\n damaged: '檔案已損毀',\n locked: '檔案設了密碼,請先在原來的軟體裡取消密碼',\n}\n\nconst en: SheetXlsxMessages = {\n warnings: {\n border: 'Borders',\n font: 'Font sizes',\n richText: 'Formatting of part of the text in a cell',\n image: 'Pictures and shapes',\n chart: 'Charts',\n pivot: 'Pivot tables',\n table: 'Tables and formulas that refer to them',\n macro: 'Macros',\n hyperlink: 'Hyperlinks to other files',\n password: 'Passwords of sheet and workbook protection',\n hiddenSheet: 'Hidden sheets',\n external: 'Formulas that refer to other files',\n name: 'Defined names',\n conditional: \"Conditional formats the sheet doesn't have\",\n validation: \"Data validations the sheet doesn't have\",\n filter: \"Filter conditions the sheet doesn't have\",\n },\n notXlsx: \"This isn't an .xlsx file\",\n damaged: 'The file is damaged',\n locked: 'The file has a password; remove it in the program it came from first',\n}\n\nexport const sheetXlsxLocales: Record<string, SheetXlsxMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\n/** The texts for a language, such as `zh-CN`; Chinese or English by its first part, English otherwise. */\nexport function sheetXlsxMessagesFor(locale = 'zh-CN'): SheetXlsxMessages {\n return (\n sheetXlsxLocales[locale] ??\n sheetXlsxLocales[locale.split('-')[0]!] ??\n (locale.startsWith('zh') ? zhCN : en)\n )\n}\n\n/** Texts to use instead, in part: any of them, and any of the warnings. */\nexport type SheetXlsxMessagesInput = Partial<Omit<SheetXlsxMessages, 'warnings'>> & {\n warnings?: Partial<SheetXlsxMessages['warnings']>\n}\n\n/** A language's texts with some of them given instead. */\nexport function mergeXlsxMessages(\n base: SheetXlsxMessages,\n own: SheetXlsxMessagesInput | undefined,\n): SheetXlsxMessages {\n if (!own) return base\n return { ...base, ...own, warnings: { ...base.warnings, ...own.warnings } }\n}\n"],"mappings":";AA6BA,IAAM,OAA0B;CAC9B,UAAU;EACR,QAAQ;EACR,MAAM;EACN,UAAU;EACV,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,WAAW;EACX,UAAU;EACV,aAAa;EACb,UAAU;EACV,MAAM;EACN,aAAa;EACb,YAAY;EACZ,QAAQ;CACV;CACA,SAAS;CACT,SAAS;CACT,QAAQ;AACV;AAEA,IAAM,OAA0B;CAC9B,UAAU;EACR,QAAQ;EACR,MAAM;EACN,UAAU;EACV,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,WAAW;EACX,UAAU;EACV,aAAa;EACb,UAAU;EACV,MAAM;EACN,aAAa;EACb,YAAY;EACZ,QAAQ;CACV;CACA,SAAS;CACT,SAAS;CACT,QAAQ;AACV;AAEA,IAAM,KAAwB;CAC5B,UAAU;EACR,QAAQ;EACR,MAAM;EACN,UAAU;EACV,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,WAAW;EACX,UAAU;EACV,aAAa;EACb,UAAU;EACV,MAAM;EACN,aAAa;EACb,YAAY;EACZ,QAAQ;CACV;CACA,SAAS;CACT,SAAS;CACT,QAAQ;AACV;AAEA,IAAa,mBAAsD;CACjE,SAAS;CACT,SAAS;CACT;AACF;;AAGA,SAAgB,qBAAqB,SAAS,SAA4B;CACxE,OACE,iBAAiB,WACjB,iBAAiB,OAAO,MAAM,GAAG,CAAC,CAAC,QAClC,OAAO,WAAW,IAAI,IAAI,OAAO;AAEtC;;AAQA,SAAgB,kBACd,MACA,KACmB;CACnB,IAAI,CAAC,KAAK,OAAO;CACjB,OAAO;EAAE,GAAG;EAAM,GAAG;EAAK,UAAU;GAAE,GAAG,KAAK;GAAU,GAAG,IAAI;EAAS;CAAE;AAC5E"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { childOf, childrenOf, isNotOff, isOff, isOn } from "./xml-read.js";
|
|
2
|
+
// src/read-styles.ts
|
|
3
|
+
/** The 56 colors older files name by number, from 8; 0 to 7 are the first eight again. */
|
|
4
|
+
var PALETTE = [
|
|
5
|
+
"000000",
|
|
6
|
+
"FFFFFF",
|
|
7
|
+
"FF0000",
|
|
8
|
+
"00FF00",
|
|
9
|
+
"0000FF",
|
|
10
|
+
"FFFF00",
|
|
11
|
+
"FF00FF",
|
|
12
|
+
"00FFFF",
|
|
13
|
+
"800000",
|
|
14
|
+
"008000",
|
|
15
|
+
"000080",
|
|
16
|
+
"808000",
|
|
17
|
+
"800080",
|
|
18
|
+
"008080",
|
|
19
|
+
"C0C0C0",
|
|
20
|
+
"808080",
|
|
21
|
+
"9999FF",
|
|
22
|
+
"993366",
|
|
23
|
+
"FFFFCC",
|
|
24
|
+
"CCFFFF",
|
|
25
|
+
"660066",
|
|
26
|
+
"FF8080",
|
|
27
|
+
"0066CC",
|
|
28
|
+
"CCCCFF",
|
|
29
|
+
"000080",
|
|
30
|
+
"FF00FF",
|
|
31
|
+
"FFFF00",
|
|
32
|
+
"00FFFF",
|
|
33
|
+
"800080",
|
|
34
|
+
"800000",
|
|
35
|
+
"008080",
|
|
36
|
+
"0000FF",
|
|
37
|
+
"00CCFF",
|
|
38
|
+
"CCFFFF",
|
|
39
|
+
"CCFFCC",
|
|
40
|
+
"FFFF99",
|
|
41
|
+
"99CCFF",
|
|
42
|
+
"FF99CC",
|
|
43
|
+
"CC99FF",
|
|
44
|
+
"FFCC99",
|
|
45
|
+
"3366FF",
|
|
46
|
+
"33CCCC",
|
|
47
|
+
"99CC00",
|
|
48
|
+
"FFCC00",
|
|
49
|
+
"FF9900",
|
|
50
|
+
"FF6600",
|
|
51
|
+
"666699",
|
|
52
|
+
"969696",
|
|
53
|
+
"003366",
|
|
54
|
+
"339966",
|
|
55
|
+
"003300",
|
|
56
|
+
"333300",
|
|
57
|
+
"993300",
|
|
58
|
+
"993366",
|
|
59
|
+
"333399",
|
|
60
|
+
"333333"
|
|
61
|
+
];
|
|
62
|
+
/** The theme's colors in the order cells name them: light 1, dark 1, light 2, dark 2, accents, links. */
|
|
63
|
+
function themeColors(theme) {
|
|
64
|
+
const scheme = theme && findNode(theme, "clrScheme");
|
|
65
|
+
if (!scheme) return [];
|
|
66
|
+
const color = (name) => {
|
|
67
|
+
const node = childOf(scheme, name);
|
|
68
|
+
const value = childOf(node, "srgbClr")?.attrs.val ?? childOf(node, "sysClr")?.attrs.lastClr;
|
|
69
|
+
return value && /^[0-9a-f]{6}$/i.test(value) ? value.toUpperCase() : void 0;
|
|
70
|
+
};
|
|
71
|
+
return [
|
|
72
|
+
...[
|
|
73
|
+
"lt1",
|
|
74
|
+
"dk1",
|
|
75
|
+
"lt2",
|
|
76
|
+
"dk2",
|
|
77
|
+
"accent1",
|
|
78
|
+
"accent2",
|
|
79
|
+
"accent3",
|
|
80
|
+
"accent4"
|
|
81
|
+
],
|
|
82
|
+
"accent5",
|
|
83
|
+
"accent6",
|
|
84
|
+
"hlink",
|
|
85
|
+
"folHlink"
|
|
86
|
+
].map(color);
|
|
87
|
+
}
|
|
88
|
+
function findNode(node, name) {
|
|
89
|
+
if (node.name === name) return node;
|
|
90
|
+
for (const child of node.children) {
|
|
91
|
+
const found = findNode(child, name);
|
|
92
|
+
if (found) return found;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** A channel of a color from its hue, as HSL works it out. */
|
|
96
|
+
var hue = (p, q, t) => {
|
|
97
|
+
if (t < 0) t += 1;
|
|
98
|
+
if (t > 1) t -= 1;
|
|
99
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
100
|
+
if (t < 1 / 2) return q;
|
|
101
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
102
|
+
return p;
|
|
103
|
+
};
|
|
104
|
+
/** A color lighter (`tint` above 0) or darker, as the file's tints work: on its lightness. */
|
|
105
|
+
function tinted(hex, tint) {
|
|
106
|
+
if (!tint) return hex;
|
|
107
|
+
const [r, g, b] = [
|
|
108
|
+
0,
|
|
109
|
+
2,
|
|
110
|
+
4
|
|
111
|
+
].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255);
|
|
112
|
+
const max = Math.max(r, g, b);
|
|
113
|
+
const min = Math.min(r, g, b);
|
|
114
|
+
let h = 0;
|
|
115
|
+
let s = 0;
|
|
116
|
+
let l = (max + min) / 2;
|
|
117
|
+
if (max !== min) {
|
|
118
|
+
const d = max - min;
|
|
119
|
+
s = l > .5 ? d / (2 - max - min) : d / (max + min);
|
|
120
|
+
h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
121
|
+
h /= 6;
|
|
122
|
+
}
|
|
123
|
+
l = tint < 0 ? l * (1 + tint) : l * (1 - tint) + tint;
|
|
124
|
+
let rgb;
|
|
125
|
+
if (!s) rgb = [
|
|
126
|
+
l,
|
|
127
|
+
l,
|
|
128
|
+
l
|
|
129
|
+
];
|
|
130
|
+
else {
|
|
131
|
+
const q = l < .5 ? l * (1 + s) : l + s - l * s;
|
|
132
|
+
const p = 2 * l - q;
|
|
133
|
+
rgb = [
|
|
134
|
+
hue(p, q, h + 1 / 3),
|
|
135
|
+
hue(p, q, h),
|
|
136
|
+
hue(p, q, h - 1 / 3)
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
return rgb.map((c) => Math.round(Math.min(1, Math.max(0, c)) * 255).toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
140
|
+
}
|
|
141
|
+
/** A color element as `#rrggbb`; `undefined` for the automatic color or one the file doesn't say. */
|
|
142
|
+
function colorOf(node, theme) {
|
|
143
|
+
if (!node || isOn(node.attrs.auto)) return void 0;
|
|
144
|
+
const { rgb, indexed } = node.attrs;
|
|
145
|
+
let hex;
|
|
146
|
+
if (rgb && /^[0-9a-f]{6,8}$/i.test(rgb)) hex = rgb.slice(-6).toUpperCase();
|
|
147
|
+
else if (node.attrs.theme != null) hex = theme[+node.attrs.theme];
|
|
148
|
+
else if (indexed != null) hex = PALETTE[+indexed];
|
|
149
|
+
if (!hex) return void 0;
|
|
150
|
+
const tint = Number(node.attrs.tint ?? 0);
|
|
151
|
+
return `#${(Number.isFinite(tint) ? tinted(hex, tint) : hex).toLowerCase()}`;
|
|
152
|
+
}
|
|
153
|
+
var BUILTIN_FORMATS = {
|
|
154
|
+
1: "0",
|
|
155
|
+
2: "0.00",
|
|
156
|
+
3: "#,##0",
|
|
157
|
+
4: "#,##0.00",
|
|
158
|
+
9: "0%",
|
|
159
|
+
10: "0.00%",
|
|
160
|
+
11: "0.00E+00",
|
|
161
|
+
12: "# ?/?",
|
|
162
|
+
13: "# ??/??",
|
|
163
|
+
14: "yyyy-mm-dd",
|
|
164
|
+
15: "d-mmm-yy",
|
|
165
|
+
16: "d-mmm",
|
|
166
|
+
17: "mmm-yy",
|
|
167
|
+
18: "h:mm AM/PM",
|
|
168
|
+
19: "h:mm:ss AM/PM",
|
|
169
|
+
20: "hh:mm",
|
|
170
|
+
21: "hh:mm:ss",
|
|
171
|
+
22: "yyyy-mm-dd hh:mm",
|
|
172
|
+
37: "#,##0 ;(#,##0)",
|
|
173
|
+
38: "#,##0 ;[Red](#,##0)",
|
|
174
|
+
39: "#,##0.00;(#,##0.00)",
|
|
175
|
+
40: "#,##0.00;[Red](#,##0.00)",
|
|
176
|
+
45: "mm:ss",
|
|
177
|
+
46: "[h]:mm:ss",
|
|
178
|
+
47: "mm:ss.0",
|
|
179
|
+
48: "##0.0E+0",
|
|
180
|
+
49: "@"
|
|
181
|
+
};
|
|
182
|
+
for (const id of [
|
|
183
|
+
27,
|
|
184
|
+
28,
|
|
185
|
+
29,
|
|
186
|
+
30,
|
|
187
|
+
31,
|
|
188
|
+
34,
|
|
189
|
+
35,
|
|
190
|
+
36,
|
|
191
|
+
50,
|
|
192
|
+
51,
|
|
193
|
+
52,
|
|
194
|
+
53,
|
|
195
|
+
54,
|
|
196
|
+
57,
|
|
197
|
+
58
|
|
198
|
+
]) BUILTIN_FORMATS[id] = "yyyy-mm-dd";
|
|
199
|
+
for (const id of [
|
|
200
|
+
32,
|
|
201
|
+
33,
|
|
202
|
+
55,
|
|
203
|
+
56
|
|
204
|
+
]) BUILTIN_FORMATS[id] = "hh:mm";
|
|
205
|
+
/** What a number format makes of a number: a date, a time, or a number. */
|
|
206
|
+
function formatKind(code) {
|
|
207
|
+
if (!code) return "number";
|
|
208
|
+
const parts = code.split(";")[0].replace(/"[^"]*"|\\.|_.|\*./g, "").replace(/\[(?![hms]+\])[^\]]*\]/gi, "");
|
|
209
|
+
if (/\[[hms]+\]/i.test(parts)) return "number";
|
|
210
|
+
if (/[yd]/i.test(parts)) return "date";
|
|
211
|
+
if (/[hs]/i.test(parts)) return "time";
|
|
212
|
+
if (/m/i.test(parts.replace(/General/gi, ""))) return "date";
|
|
213
|
+
return "number";
|
|
214
|
+
}
|
|
215
|
+
var ALIGN = {
|
|
216
|
+
left: "left",
|
|
217
|
+
center: "center",
|
|
218
|
+
centerContinuous: "center",
|
|
219
|
+
right: "right"
|
|
220
|
+
};
|
|
221
|
+
var VALIGN = {
|
|
222
|
+
top: "top",
|
|
223
|
+
center: "middle"
|
|
224
|
+
};
|
|
225
|
+
/** A font's parts as a style: bold, italic, underline, strike and its color unless it is the usual one. */
|
|
226
|
+
function fontStyle(font, theme, usual) {
|
|
227
|
+
const style = {};
|
|
228
|
+
if (!font) return style;
|
|
229
|
+
const on = (name) => {
|
|
230
|
+
const node = childOf(font, name);
|
|
231
|
+
return !!node && isNotOff(node.attrs.val) && node.attrs.val !== "none";
|
|
232
|
+
};
|
|
233
|
+
if (on("b")) style.bold = true;
|
|
234
|
+
if (on("i")) style.italic = true;
|
|
235
|
+
if (on("u")) style.underline = true;
|
|
236
|
+
if (on("strike")) style.strike = true;
|
|
237
|
+
const color = colorOf(childOf(font, "color"), theme);
|
|
238
|
+
if (color && color !== usual && color !== "#000000") style.color = color;
|
|
239
|
+
return style;
|
|
240
|
+
}
|
|
241
|
+
/** A fill's color; `undefined` for no fill. */
|
|
242
|
+
function fillColor(fill, theme, differential = false) {
|
|
243
|
+
const pattern = childOf(fill, "patternFill");
|
|
244
|
+
if (!pattern) return void 0;
|
|
245
|
+
const type = pattern.attrs.patternType;
|
|
246
|
+
if (differential) return colorOf(childOf(pattern, "bgColor") ?? childOf(pattern, "fgColor"), theme);
|
|
247
|
+
if (!type || type === "none" || type === "gray125") return void 0;
|
|
248
|
+
return colorOf(childOf(pattern, "fgColor") ?? childOf(pattern, "bgColor"), theme);
|
|
249
|
+
}
|
|
250
|
+
var hasBorder = (border) => !!border && border.children.some((side) => side.attrs.style && side.attrs.style !== "none");
|
|
251
|
+
var sizeOf = (font) => childOf(font, "sz")?.attrs.val;
|
|
252
|
+
/** The looks of the file's cells and conditional formats, from its style sheet. */
|
|
253
|
+
function readStyles(sheet, theme) {
|
|
254
|
+
const formats = /* @__PURE__ */ new Map();
|
|
255
|
+
for (const node of childrenOf(childOf(sheet, "numFmts"), "numFmt")) formats.set(+node.attrs.numFmtId, node.attrs.formatCode ?? "");
|
|
256
|
+
const fonts = childrenOf(childOf(sheet, "fonts"), "font");
|
|
257
|
+
const fills = childrenOf(childOf(sheet, "fills"), "fill");
|
|
258
|
+
const borders = childrenOf(childOf(sheet, "borders"), "border");
|
|
259
|
+
const usualFont = fonts[0];
|
|
260
|
+
const usualColor = colorOf(childOf(usualFont, "color"), theme);
|
|
261
|
+
return {
|
|
262
|
+
looks: childrenOf(childOf(sheet, "cellXfs"), "xf").map((xf) => {
|
|
263
|
+
const id = +(xf.attrs.numFmtId ?? 0);
|
|
264
|
+
const code = formats.get(id) ?? BUILTIN_FORMATS[id];
|
|
265
|
+
const format = code && code !== "General" ? code.replace(/\\([-\s/:.,()])/g, "$1") : void 0;
|
|
266
|
+
const font = fonts[+(xf.attrs.fontId ?? 0)];
|
|
267
|
+
const style = fontStyle(font, theme, usualColor);
|
|
268
|
+
const background = fillColor(fills[+(xf.attrs.fillId ?? 0)], theme);
|
|
269
|
+
if (background) style.background = background;
|
|
270
|
+
const alignment = childOf(xf, "alignment");
|
|
271
|
+
if (alignment) {
|
|
272
|
+
const align = ALIGN[alignment.attrs.horizontal ?? ""];
|
|
273
|
+
const valign = VALIGN[alignment.attrs.vertical ?? ""];
|
|
274
|
+
if (align) style.align = align;
|
|
275
|
+
if (valign) style.valign = valign;
|
|
276
|
+
if (isOn(alignment.attrs.wrapText)) style.wrap = true;
|
|
277
|
+
}
|
|
278
|
+
const protection = childOf(xf, "protection");
|
|
279
|
+
if (protection && isOff(protection.attrs.locked)) style.locked = false;
|
|
280
|
+
const plain = !Object.keys(style).length;
|
|
281
|
+
return {
|
|
282
|
+
style: plain ? void 0 : style,
|
|
283
|
+
key: plain ? void 0 : JSON.stringify(style),
|
|
284
|
+
format,
|
|
285
|
+
kind: formatKind(format),
|
|
286
|
+
quote: isOn(xf.attrs.quotePrefix),
|
|
287
|
+
border: hasBorder(borders[+(xf.attrs.borderId ?? 0)]),
|
|
288
|
+
font: !!font && sizeOf(font) != null && sizeOf(font) !== sizeOf(usualFont)
|
|
289
|
+
};
|
|
290
|
+
}),
|
|
291
|
+
differentials: childrenOf(childOf(sheet, "dxfs"), "dxf").map((dxf) => {
|
|
292
|
+
const style = fontStyle(childOf(dxf, "font"), theme);
|
|
293
|
+
const background = fillColor(childOf(dxf, "fill"), theme, true);
|
|
294
|
+
if (background) style.background = background;
|
|
295
|
+
return style;
|
|
296
|
+
})
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
export { colorOf, formatKind, readStyles, themeColors };
|
|
300
|
+
|
|
301
|
+
//# sourceMappingURL=read-styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-styles.js","names":[],"sources":["../src/read-styles.ts"],"sourcesContent":["import type { SheetStyle } from '@dou-ui/sheet/core'\nimport { childOf, childrenOf, isNotOff, isOff, isOn, type XmlNode } from './xml-read'\n\n/** The 56 colors older files name by number, from 8; 0 to 7 are the first eight again. */\nconst PALETTE = [\n '000000',\n 'FFFFFF',\n 'FF0000',\n '00FF00',\n '0000FF',\n 'FFFF00',\n 'FF00FF',\n '00FFFF',\n '800000',\n '008000',\n '000080',\n '808000',\n '800080',\n '008080',\n 'C0C0C0',\n '808080',\n '9999FF',\n '993366',\n 'FFFFCC',\n 'CCFFFF',\n '660066',\n 'FF8080',\n '0066CC',\n 'CCCCFF',\n '000080',\n 'FF00FF',\n 'FFFF00',\n '00FFFF',\n '800080',\n '800000',\n '008080',\n '0000FF',\n '00CCFF',\n 'CCFFFF',\n 'CCFFCC',\n 'FFFF99',\n '99CCFF',\n 'FF99CC',\n 'CC99FF',\n 'FFCC99',\n '3366FF',\n '33CCCC',\n '99CC00',\n 'FFCC00',\n 'FF9900',\n 'FF6600',\n '666699',\n '969696',\n '003366',\n '339966',\n '003300',\n '333300',\n '993300',\n '993366',\n '333399',\n '333333',\n]\n\n/** The theme's colors in the order cells name them: light 1, dark 1, light 2, dark 2, accents, links. */\nexport function themeColors(theme: XmlNode | undefined) {\n const scheme = theme && findNode(theme, 'clrScheme')\n if (!scheme) return []\n const color = (name: string) => {\n const node = childOf(scheme, name)\n const value = childOf(node, 'srgbClr')?.attrs.val ?? childOf(node, 'sysClr')?.attrs.lastClr\n return value && /^[0-9a-f]{6}$/i.test(value) ? value.toUpperCase() : undefined\n }\n const order = ['lt1', 'dk1', 'lt2', 'dk2', 'accent1', 'accent2', 'accent3', 'accent4']\n return [...order, 'accent5', 'accent6', 'hlink', 'folHlink'].map(color)\n}\n\nfunction findNode(node: XmlNode, name: string): XmlNode | undefined {\n if (node.name === name) return node\n for (const child of node.children) {\n const found = findNode(child, name)\n if (found) return found\n }\n return undefined\n}\n\n/** A channel of a color from its hue, as HSL works it out. */\nconst hue = (p: number, q: number, t: number) => {\n if (t < 0) t += 1\n if (t > 1) t -= 1\n if (t < 1 / 6) return p + (q - p) * 6 * t\n if (t < 1 / 2) return q\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6\n return p\n}\n\n/** A color lighter (`tint` above 0) or darker, as the file's tints work: on its lightness. */\nfunction tinted(hex: string, tint: number) {\n if (!tint) return hex\n const [r, g, b] = [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255) as [\n number,\n number,\n number,\n ]\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n let h = 0\n let s = 0\n let l = (max + min) / 2\n if (max !== min) {\n const d = max - min\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4\n h /= 6\n }\n l = tint < 0 ? l * (1 + tint) : l * (1 - tint) + tint\n let rgb: number[]\n if (!s) rgb = [l, l, l]\n else {\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\n const p = 2 * l - q\n rgb = [hue(p, q, h + 1 / 3), hue(p, q, h), hue(p, q, h - 1 / 3)]\n }\n return rgb\n .map((c) =>\n Math.round(Math.min(1, Math.max(0, c)) * 255)\n .toString(16)\n .padStart(2, '0'),\n )\n .join('')\n .toUpperCase()\n}\n\n/** A color element as `#rrggbb`; `undefined` for the automatic color or one the file doesn't say. */\nexport function colorOf(node: XmlNode | undefined, theme: (string | undefined)[]) {\n if (!node || isOn(node.attrs.auto)) return undefined\n const { rgb, indexed } = node.attrs\n let hex: string | undefined\n if (rgb && /^[0-9a-f]{6,8}$/i.test(rgb)) hex = rgb.slice(-6).toUpperCase()\n else if (node.attrs.theme != null) hex = theme[+node.attrs.theme]\n else if (indexed != null) hex = PALETTE[+indexed]\n if (!hex) return undefined\n const tint = Number(node.attrs.tint ?? 0)\n return `#${(Number.isFinite(tint) ? tinted(hex, tint) : hex).toLowerCase()}`\n}\n\nconst BUILTIN_FORMATS: Record<number, string> = {\n 1: '0',\n 2: '0.00',\n 3: '#,##0',\n 4: '#,##0.00',\n 9: '0%',\n 10: '0.00%',\n 11: '0.00E+00',\n 12: '# ?/?',\n 13: '# ??/??',\n 14: 'yyyy-mm-dd',\n 15: 'd-mmm-yy',\n 16: 'd-mmm',\n 17: 'mmm-yy',\n 18: 'h:mm AM/PM',\n 19: 'h:mm:ss AM/PM',\n 20: 'hh:mm',\n 21: 'hh:mm:ss',\n 22: 'yyyy-mm-dd hh:mm',\n 37: '#,##0 ;(#,##0)',\n 38: '#,##0 ;[Red](#,##0)',\n 39: '#,##0.00;(#,##0.00)',\n 40: '#,##0.00;[Red](#,##0.00)',\n 45: 'mm:ss',\n 46: '[h]:mm:ss',\n 47: 'mm:ss.0',\n 48: '##0.0E+0',\n 49: '@',\n}\n// formats each language's files give their own way of writing a date or time\nfor (const id of [27, 28, 29, 30, 31, 34, 35, 36, 50, 51, 52, 53, 54, 57, 58])\n BUILTIN_FORMATS[id] = 'yyyy-mm-dd'\nfor (const id of [32, 33, 55, 56]) BUILTIN_FORMATS[id] = 'hh:mm'\n\n/** What a number format makes of a number: a date, a time, or a number. */\nexport function formatKind(code: string | undefined): 'date' | 'time' | 'number' {\n if (!code) return 'number'\n // quoted and escaped text, and colors and conditions in brackets, aren't parts\n const parts = code\n .split(';')[0]!\n .replace(/\"[^\"]*\"|\\\\.|_.|\\*./g, '')\n .replace(/\\[(?![hms]+\\])[^\\]]*\\]/gi, '')\n // elapsed time, such as `[h]:mm`, is shown on the number\n if (/\\[[hms]+\\]/i.test(parts)) return 'number'\n if (/[yd]/i.test(parts)) return 'date'\n if (/[hs]/i.test(parts)) return 'time'\n // months alone, such as `mmmm`\n if (/m/i.test(parts.replace(/General/gi, ''))) return 'date'\n return 'number'\n}\n\n/** A look a cell takes, by its style number. */\nexport interface CellLookIn {\n /** The style, in plain colors; `undefined` for none. */\n style?: SheetStyle\n /** Its key, the same for the same style. */\n key?: string\n /** The number format, `undefined` for General. */\n format?: string\n kind: 'date' | 'time' | 'number'\n /** Text that is kept as text even when it reads as a formula. */\n quote: boolean\n /** What it has that the sheet can't hold. */\n border: boolean\n font: boolean\n}\n\nconst ALIGN: Record<string, SheetStyle['align']> = {\n left: 'left',\n center: 'center',\n centerContinuous: 'center',\n right: 'right',\n}\n// bottom is where other programs put text unless told otherwise, so it isn't kept as a style\nconst VALIGN: Record<string, SheetStyle['valign']> = {\n top: 'top',\n center: 'middle',\n}\n\n/** A font's parts as a style: bold, italic, underline, strike and its color unless it is the usual one. */\nfunction fontStyle(font: XmlNode | undefined, theme: (string | undefined)[], usual?: string) {\n const style: SheetStyle = {}\n if (!font) return style\n const on = (name: string) => {\n const node = childOf(font, name)\n return !!node && isNotOff(node.attrs.val) && node.attrs.val !== 'none'\n }\n if (on('b')) style.bold = true\n if (on('i')) style.italic = true\n if (on('u')) style.underline = true\n if (on('strike')) style.strike = true\n const color = colorOf(childOf(font, 'color'), theme)\n if (color && color !== usual && color !== '#000000') style.color = color\n return style\n}\n\n/** A fill's color; `undefined` for no fill. */\nfunction fillColor(fill: XmlNode | undefined, theme: (string | undefined)[], differential = false) {\n const pattern = childOf(fill, 'patternFill')\n if (!pattern) return undefined\n const type = pattern.attrs.patternType\n // a conditional format's solid fill gives its color as the background one\n if (differential)\n return colorOf(childOf(pattern, 'bgColor') ?? childOf(pattern, 'fgColor'), theme)\n if (!type || type === 'none' || type === 'gray125') return undefined\n return colorOf(childOf(pattern, 'fgColor') ?? childOf(pattern, 'bgColor'), theme)\n}\n\nconst hasBorder = (border: XmlNode | undefined) =>\n !!border && border.children.some((side) => side.attrs.style && side.attrs.style !== 'none')\n\nconst sizeOf = (font: XmlNode | undefined) => childOf(font, 'sz')?.attrs.val\n\n/** The looks of the file's cells and conditional formats, from its style sheet. */\nexport function readStyles(sheet: XmlNode | undefined, theme: (string | undefined)[]) {\n const formats = new Map<number, string>()\n for (const node of childrenOf(childOf(sheet, 'numFmts'), 'numFmt'))\n formats.set(+node.attrs.numFmtId!, node.attrs.formatCode ?? '')\n const fonts = childrenOf(childOf(sheet, 'fonts'), 'font')\n const fills = childrenOf(childOf(sheet, 'fills'), 'fill')\n const borders = childrenOf(childOf(sheet, 'borders'), 'border')\n const usualFont = fonts[0]\n const usualColor = colorOf(childOf(usualFont, 'color'), theme)\n\n const looks: CellLookIn[] = childrenOf(childOf(sheet, 'cellXfs'), 'xf').map((xf) => {\n const id = +(xf.attrs.numFmtId ?? 0)\n const code = formats.get(id) ?? BUILTIN_FORMATS[id]\n // escaped characters that read the same without the escape, as some programs write them\n const format = code && code !== 'General' ? code.replace(/\\\\([-\\s/:.,()])/g, '$1') : undefined\n const font = fonts[+(xf.attrs.fontId ?? 0)]\n const style = fontStyle(font, theme, usualColor)\n const background = fillColor(fills[+(xf.attrs.fillId ?? 0)], theme)\n if (background) style.background = background\n const alignment = childOf(xf, 'alignment')\n if (alignment) {\n const align = ALIGN[alignment.attrs.horizontal ?? '']\n const valign = VALIGN[alignment.attrs.vertical ?? '']\n if (align) style.align = align\n if (valign) style.valign = valign\n if (isOn(alignment.attrs.wrapText)) style.wrap = true\n }\n // cells are locked unless this says otherwise\n const protection = childOf(xf, 'protection')\n if (protection && isOff(protection.attrs.locked)) style.locked = false\n const plain = !Object.keys(style).length\n return {\n style: plain ? undefined : style,\n key: plain ? undefined : JSON.stringify(style),\n format,\n kind: formatKind(format),\n quote: isOn(xf.attrs.quotePrefix),\n border: hasBorder(borders[+(xf.attrs.borderId ?? 0)]),\n // a size of its own; typefaces differ between computers anyway, so they aren't counted\n font: !!font && sizeOf(font) != null && sizeOf(font) !== sizeOf(usualFont),\n }\n })\n\n const differentials = childrenOf(childOf(sheet, 'dxfs'), 'dxf').map((dxf) => {\n const style = fontStyle(childOf(dxf, 'font'), theme)\n const background = fillColor(childOf(dxf, 'fill'), theme, true)\n if (background) style.background = background\n return style\n })\n return { looks, differentials }\n}\n"],"mappings":"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"}
|