xlkit 1.2.0 → 1.2.3
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 -21
- package/README.md +57 -0
- package/dist/index.cjs +37 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +44 -23
- package/dist/index.js.map +1 -1
- package/package.json +2 -13
- package/bin/cli.js +0 -15
- package/demo/index.html +0 -12
- package/demo/main.tsx +0 -23
- package/demo/vite.config.ts +0 -7
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 xlkit contributors
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xlkit contributors
|
|
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
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# xlkit
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="logo.png" alt="xlkit logo" width="200">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
**Declarative Excel generation library** - See the final Excel structure from your code
|
|
8
|
+
|
|
9
|
+
[Documentation](https://yn1323.github.io/xlkit/)
|
|
10
|
+
|
|
11
|
+
Built on top of ExcelJS, providing a more intuitive and declarative API.
|
|
12
|
+
|
|
13
|
+
## Comparison with ExcelJS
|
|
14
|
+
|
|
15
|
+
| Aspect | ExcelJS (Imperative) | xlkit (Declarative) |
|
|
16
|
+
|--------|---------------------|---------------------|
|
|
17
|
+
| Style | Operate cells one by one | Declare the final structure |
|
|
18
|
+
| Clarity | Hard to see the result from code | Easy to see the result from code |
|
|
19
|
+
| Analogy | jQuery | React |
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install xlkit
|
|
25
|
+
# or
|
|
26
|
+
pnpm add xlkit
|
|
27
|
+
# or
|
|
28
|
+
yarn add xlkit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { xlkit } from "xlkit";
|
|
35
|
+
|
|
36
|
+
const output = await xlkit()
|
|
37
|
+
.sheet("Sales")
|
|
38
|
+
.table({
|
|
39
|
+
preset: "basic",
|
|
40
|
+
columns: [
|
|
41
|
+
{ key: "name", label: "Product" },
|
|
42
|
+
{ key: "price", label: "Price" },
|
|
43
|
+
{ key: "quantity", label: "Quantity" },
|
|
44
|
+
],
|
|
45
|
+
data: [
|
|
46
|
+
{ name: "Apple", price: 100, quantity: 50 },
|
|
47
|
+
{ name: "Orange", price: 80, quantity: 100 },
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
.getNode();
|
|
51
|
+
|
|
52
|
+
await output.saveToFile("report.xlsx");
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -38,9 +38,6 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
// src/engine/writer.ts
|
|
39
39
|
var import_exceljs = __toESM(require("exceljs"), 1);
|
|
40
40
|
|
|
41
|
-
// src/engine/sheet-writer.ts
|
|
42
|
-
var import_node_fs = require("fs");
|
|
43
|
-
|
|
44
41
|
// src/styles/converter.ts
|
|
45
42
|
function convertToExcelJSStyle(style) {
|
|
46
43
|
if (!style) return {};
|
|
@@ -238,7 +235,7 @@ var TABLE_PRESETS = {
|
|
|
238
235
|
function getPreset(presetName) {
|
|
239
236
|
const preset = TABLE_PRESETS[presetName];
|
|
240
237
|
if (!preset) {
|
|
241
|
-
throw new Error(
|
|
238
|
+
throw new Error(`Unknown preset name: ${presetName}`);
|
|
242
239
|
}
|
|
243
240
|
return preset;
|
|
244
241
|
}
|
|
@@ -262,6 +259,14 @@ function isSpaceBlock(block) {
|
|
|
262
259
|
return block.type === "space";
|
|
263
260
|
}
|
|
264
261
|
|
|
262
|
+
// src/utils/buffer.ts
|
|
263
|
+
function isBuffer(value) {
|
|
264
|
+
return typeof Buffer !== "undefined" && Buffer.isBuffer(value);
|
|
265
|
+
}
|
|
266
|
+
function isUrl(value) {
|
|
267
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
268
|
+
}
|
|
269
|
+
|
|
265
270
|
// src/types/column.ts
|
|
266
271
|
function isLeafColumn(column) {
|
|
267
272
|
return "key" in column;
|
|
@@ -392,21 +397,21 @@ var SheetWriter = class {
|
|
|
392
397
|
/**
|
|
393
398
|
* SheetStateを書き込む
|
|
394
399
|
*/
|
|
395
|
-
writeSheet(sheetState) {
|
|
400
|
+
async writeSheet(sheetState) {
|
|
396
401
|
for (const block of sheetState.blocks) {
|
|
397
|
-
this.writeBlock(block);
|
|
402
|
+
await this.writeBlock(block);
|
|
398
403
|
}
|
|
399
404
|
}
|
|
400
405
|
/**
|
|
401
406
|
* ブロックを書き込む
|
|
402
407
|
*/
|
|
403
|
-
writeBlock(block) {
|
|
408
|
+
async writeBlock(block) {
|
|
404
409
|
if (isTableBlock(block)) {
|
|
405
410
|
this.writeTable(block.options);
|
|
406
411
|
} else if (isTextBlock(block)) {
|
|
407
412
|
this.writeText(block.input);
|
|
408
413
|
} else if (isImageBlock(block)) {
|
|
409
|
-
this.writeImage(block.options);
|
|
414
|
+
await this.writeImage(block.options);
|
|
410
415
|
} else if (isSpaceBlock(block)) {
|
|
411
416
|
this.writeSpace(block.lines);
|
|
412
417
|
}
|
|
@@ -639,13 +644,20 @@ var SheetWriter = class {
|
|
|
639
644
|
/**
|
|
640
645
|
* 画像を書き込む
|
|
641
646
|
*/
|
|
642
|
-
writeImage(options) {
|
|
647
|
+
async writeImage(options) {
|
|
643
648
|
const { source, width = 100, height = 100, row, col = 0 } = options;
|
|
644
649
|
let imageBuffer;
|
|
645
|
-
if (
|
|
650
|
+
if (isBuffer(source)) {
|
|
646
651
|
imageBuffer = source;
|
|
652
|
+
} else if (isUrl(source)) {
|
|
653
|
+
const response = await fetch(source);
|
|
654
|
+
imageBuffer = await response.arrayBuffer();
|
|
647
655
|
} else {
|
|
648
|
-
|
|
656
|
+
if (typeof window !== "undefined") {
|
|
657
|
+
throw new Error("File path is not supported in browser. Use URL or Buffer.");
|
|
658
|
+
}
|
|
659
|
+
const fs = require("fs");
|
|
660
|
+
imageBuffer = fs.readFileSync(source);
|
|
649
661
|
}
|
|
650
662
|
const imageId = this.workbook.addImage({
|
|
651
663
|
buffer: imageBuffer,
|
|
@@ -674,7 +686,7 @@ async function writeWorkbook(state) {
|
|
|
674
686
|
for (const sheetState of state.sheets) {
|
|
675
687
|
const worksheet = workbook.addWorksheet(sheetState.name);
|
|
676
688
|
const writer = new SheetWriter(workbook, worksheet);
|
|
677
|
-
writer.writeSheet(sheetState);
|
|
689
|
+
await writer.writeSheet(sheetState);
|
|
678
690
|
}
|
|
679
691
|
return workbook;
|
|
680
692
|
}
|
|
@@ -730,30 +742,32 @@ var EXCEL_LIMITS = {
|
|
|
730
742
|
};
|
|
731
743
|
function validateSheetName(name) {
|
|
732
744
|
if (name.length > EXCEL_LIMITS.SHEET_NAME_MAX_LENGTH) {
|
|
733
|
-
throw new Error("
|
|
745
|
+
throw new Error("Sheet name must be 31 characters or less");
|
|
734
746
|
}
|
|
735
747
|
for (const char of EXCEL_LIMITS.SHEET_NAME_INVALID_CHARS) {
|
|
736
748
|
if (name.includes(char)) {
|
|
737
|
-
throw new Error(
|
|
749
|
+
throw new Error(`Sheet name contains invalid character: ${char}`);
|
|
738
750
|
}
|
|
739
751
|
}
|
|
740
752
|
if (name.trim().length === 0) {
|
|
741
|
-
throw new Error("
|
|
753
|
+
throw new Error("Sheet name cannot be only whitespace");
|
|
742
754
|
}
|
|
743
755
|
}
|
|
744
756
|
function validateDataSize(rowCount, columnCount) {
|
|
745
757
|
if (rowCount > EXCEL_LIMITS.MAX_ROWS) {
|
|
746
|
-
throw new Error("
|
|
758
|
+
throw new Error("Row count exceeds Excel limit (1,048,576 rows)");
|
|
747
759
|
}
|
|
748
760
|
if (columnCount > EXCEL_LIMITS.MAX_COLUMNS) {
|
|
749
|
-
throw new Error("
|
|
761
|
+
throw new Error("Column count exceeds Excel limit (16,384 columns)");
|
|
750
762
|
}
|
|
751
763
|
}
|
|
752
764
|
|
|
753
765
|
// src/schemas/image.ts
|
|
754
766
|
var import_zod = require("zod");
|
|
755
767
|
var imageSourceSchema = import_zod.z.union([
|
|
756
|
-
import_zod.z.
|
|
768
|
+
import_zod.z.custom((val) => isBuffer(val), {
|
|
769
|
+
message: "Expected Buffer"
|
|
770
|
+
}),
|
|
757
771
|
import_zod.z.string().url(),
|
|
758
772
|
// URL形式
|
|
759
773
|
import_zod.z.string().min(1)
|
|
@@ -893,7 +907,7 @@ var SheetBuilder = class {
|
|
|
893
907
|
*/
|
|
894
908
|
space(lines = 1) {
|
|
895
909
|
if (lines <= 0) {
|
|
896
|
-
throw new Error("space()
|
|
910
|
+
throw new Error("space() argument must be a positive integer");
|
|
897
911
|
}
|
|
898
912
|
const block = { type: "space", lines };
|
|
899
913
|
this.sheetState.blocks.push(block);
|
|
@@ -934,7 +948,7 @@ var WorkbookBuilder = class {
|
|
|
934
948
|
const sheetName = name ?? `Sheet${this.state.sheets.length + 1}`;
|
|
935
949
|
validateSheetName(sheetName);
|
|
936
950
|
if (this.state.sheets.some((s) => s.name === sheetName)) {
|
|
937
|
-
throw new Error(
|
|
951
|
+
throw new Error(`Sheet name "${sheetName}" already exists`);
|
|
938
952
|
}
|
|
939
953
|
const sheetState = { name: sheetName, blocks: [] };
|
|
940
954
|
this.state.sheets.push(sheetState);
|
|
@@ -1145,7 +1159,7 @@ var WorkbookReader = class {
|
|
|
1145
1159
|
sheet(name) {
|
|
1146
1160
|
const worksheet = this.workbook.getWorksheet(name);
|
|
1147
1161
|
if (!worksheet) {
|
|
1148
|
-
throw new Error(
|
|
1162
|
+
throw new Error(`Sheet "${name}" not found`);
|
|
1149
1163
|
}
|
|
1150
1164
|
return new SheetReader(worksheet);
|
|
1151
1165
|
}
|
|
@@ -1155,7 +1169,7 @@ var WorkbookReader = class {
|
|
|
1155
1169
|
sheetAt(index) {
|
|
1156
1170
|
const worksheet = this.workbook.worksheets[index];
|
|
1157
1171
|
if (!worksheet) {
|
|
1158
|
-
throw new Error(
|
|
1172
|
+
throw new Error(`Sheet at index ${index} not found`);
|
|
1159
1173
|
}
|
|
1160
1174
|
return new SheetReader(worksheet);
|
|
1161
1175
|
}
|
|
@@ -1168,7 +1182,7 @@ var WorkbookReader = class {
|
|
|
1168
1182
|
};
|
|
1169
1183
|
async function read(source) {
|
|
1170
1184
|
const workbook = new import_exceljs2.default.Workbook();
|
|
1171
|
-
if (
|
|
1185
|
+
if (isBuffer(source)) {
|
|
1172
1186
|
await workbook.xlsx.load(source);
|
|
1173
1187
|
} else {
|
|
1174
1188
|
await workbook.xlsx.readFile(source);
|