@hirokisakabe/pom 7.4.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -58,16 +58,20 @@ npm install @hirokisakabe/pom
|
|
|
58
58
|
import { buildPptx } from "@hirokisakabe/pom";
|
|
59
59
|
|
|
60
60
|
const xml = `
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
</
|
|
61
|
+
<Slide>
|
|
62
|
+
<VStack w="100%" h="max" padding="48" gap="24" alignItems="start">
|
|
63
|
+
<Text fontSize="48" bold="true">Presentation Title</Text>
|
|
64
|
+
<Text fontSize="24" color="666666">Subtitle</Text>
|
|
65
|
+
</VStack>
|
|
66
|
+
</Slide>
|
|
65
67
|
`;
|
|
66
68
|
|
|
67
69
|
const { pptx } = await buildPptx(xml, { w: 1280, h: 720 });
|
|
68
70
|
await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
69
71
|
```
|
|
70
72
|
|
|
73
|
+
Each slide must be wrapped in a `<Slide>` element. To produce multiple slides, list multiple `<Slide>` elements at the top level.
|
|
74
|
+
|
|
71
75
|
## Available Nodes
|
|
72
76
|
|
|
73
77
|
| Node | Description |
|
|
@@ -7,6 +7,10 @@ export declare const TAG_TO_TYPE: Record<string, string>;
|
|
|
7
7
|
/**
|
|
8
8
|
* XML 文字列を POMNode 配列に変換する。
|
|
9
9
|
*
|
|
10
|
+
* 最上位は `<Slide>` 要素のみが許容される。各 `<Slide>` が 1 つのスライドに
|
|
11
|
+
* 対応し、その子要素がスライドのルート POMNode となる。子要素が複数ある場合は
|
|
12
|
+
* 暗黙的に VStack でラップされる。
|
|
13
|
+
*
|
|
10
14
|
* XML タグは POM ノードタイプにマッピングされ、属性値は Zod スキーマを参照して
|
|
11
15
|
* 適切な型(number, boolean, array, object)に変換される。
|
|
12
16
|
* 未知のタグ名が指定された場合はエラーがスローされる。
|
|
@@ -16,9 +20,11 @@ export declare const TAG_TO_TYPE: Record<string, string>;
|
|
|
16
20
|
* import { parseXml, buildPptx } from "@hirokisakabe/pom";
|
|
17
21
|
*
|
|
18
22
|
* const xml = `
|
|
19
|
-
* <
|
|
20
|
-
* <
|
|
21
|
-
*
|
|
23
|
+
* <Slide>
|
|
24
|
+
* <VStack gap="16" padding="32">
|
|
25
|
+
* <Text fontSize="32" bold="true">売上レポート</Text>
|
|
26
|
+
* </VStack>
|
|
27
|
+
* </Slide>
|
|
22
28
|
* `;
|
|
23
29
|
*
|
|
24
30
|
* const nodes = parseXml(xml);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseXml.d.ts","sourceRoot":"","sources":["../../src/parseXml/parseXml.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAgBb,MAAM,aAAa,CAAC;AAYrB,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,MAAM,EAAE,MAAM,EAAE,CAAC;gBACrB,MAAM,EAAE,MAAM,EAAE;CAM7B;AAGD,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAoB9C,CAAC;AA6pCF
|
|
1
|
+
{"version":3,"file":"parseXml.d.ts","sourceRoot":"","sources":["../../src/parseXml/parseXml.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,OAAO,EAgBb,MAAM,aAAa,CAAC;AAYrB,qBAAa,aAAc,SAAQ,KAAK;IACtC,SAAgB,MAAM,EAAE,MAAM,EAAE,CAAC;gBACrB,MAAM,EAAE,MAAM,EAAE;CAM7B;AAGD,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAoB9C,CAAC;AA6pCF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,CA6DrD"}
|
|
@@ -867,6 +867,10 @@ function convertPomNode(nodeType, tagName, attrs, childElements, textContent, er
|
|
|
867
867
|
/**
|
|
868
868
|
* XML 文字列を POMNode 配列に変換する。
|
|
869
869
|
*
|
|
870
|
+
* 最上位は `<Slide>` 要素のみが許容される。各 `<Slide>` が 1 つのスライドに
|
|
871
|
+
* 対応し、その子要素がスライドのルート POMNode となる。子要素が複数ある場合は
|
|
872
|
+
* 暗黙的に VStack でラップされる。
|
|
873
|
+
*
|
|
870
874
|
* XML タグは POM ノードタイプにマッピングされ、属性値は Zod スキーマを参照して
|
|
871
875
|
* 適切な型(number, boolean, array, object)に変換される。
|
|
872
876
|
* 未知のタグ名が指定された場合はエラーがスローされる。
|
|
@@ -876,9 +880,11 @@ function convertPomNode(nodeType, tagName, attrs, childElements, textContent, er
|
|
|
876
880
|
* import { parseXml, buildPptx } from "@hirokisakabe/pom";
|
|
877
881
|
*
|
|
878
882
|
* const xml = `
|
|
879
|
-
* <
|
|
880
|
-
* <
|
|
881
|
-
*
|
|
883
|
+
* <Slide>
|
|
884
|
+
* <VStack gap="16" padding="32">
|
|
885
|
+
* <Text fontSize="32" bold="true">売上レポート</Text>
|
|
886
|
+
* </VStack>
|
|
887
|
+
* </Slide>
|
|
882
888
|
* `;
|
|
883
889
|
*
|
|
884
890
|
* const nodes = parseXml(xml);
|
|
@@ -903,10 +909,37 @@ export function parseXml(xmlString) {
|
|
|
903
909
|
const rootElement = parsed[0];
|
|
904
910
|
const rootChildren = (rootElement["__root__"] ?? []);
|
|
905
911
|
const errors = [];
|
|
906
|
-
const
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
912
|
+
const slideElements = rootChildren.filter((child) => !isTextNode(child));
|
|
913
|
+
const nodes = [];
|
|
914
|
+
for (const slideEl of slideElements) {
|
|
915
|
+
const tagName = getTagName(slideEl);
|
|
916
|
+
if (tagName !== "Slide") {
|
|
917
|
+
errors.push(`Top-level element must be <Slide>, but got <${tagName}>. Wrap your slide content in <Slide>...</Slide>.`);
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
if (Object.keys(getAttributes(slideEl)).length > 0) {
|
|
921
|
+
errors.push(`<Slide>: Attributes are not supported`);
|
|
922
|
+
}
|
|
923
|
+
const slideChildren = getChildElements(slideEl);
|
|
924
|
+
if (slideChildren.length === 0) {
|
|
925
|
+
errors.push(`<Slide> must contain at least one child element`);
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
const converted = slideChildren
|
|
929
|
+
.map((child) => convertElement(child, errors))
|
|
930
|
+
.filter((c) => c !== null);
|
|
931
|
+
if (converted.length === 0)
|
|
932
|
+
continue;
|
|
933
|
+
if (converted.length === 1) {
|
|
934
|
+
nodes.push(converted[0]);
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
nodes.push({
|
|
938
|
+
type: "vstack",
|
|
939
|
+
children: converted,
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
}
|
|
910
943
|
if (errors.length > 0) {
|
|
911
944
|
throw new ParseXmlError(errors);
|
|
912
945
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../../../src/registry/definitions/layer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../../../src/registry/definitions/layer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,eAAO,MAAM,YAAY,EAAE,cA8D1B,CAAC"}
|
|
@@ -44,7 +44,7 @@ export const layerNodeDef = {
|
|
|
44
44
|
}
|
|
45
45
|
const adjustedParentX = absoluteX + childX - childLayout.left;
|
|
46
46
|
const adjustedParentY = absoluteY + childY - childLayout.top;
|
|
47
|
-
return
|
|
47
|
+
return await toPositioned(child, ctx, map, adjustedParentX, adjustedParentY);
|
|
48
48
|
})),
|
|
49
49
|
};
|
|
50
50
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hirokisakabe/pom",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "AI-friendly PowerPoint generation with a Flexbox layout engine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,18 +45,18 @@
|
|
|
45
45
|
"access": "public"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@size-limit/file": "^12.0
|
|
49
|
-
"@types/node": "^25.
|
|
48
|
+
"@size-limit/file": "^12.1.0",
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
50
|
"@types/opentype.js": "^1.3.8",
|
|
51
51
|
"@types/pngjs": "6.0.5",
|
|
52
|
-
"@vitest/coverage-v8": "^4.1.
|
|
53
|
-
"@vitest/ui": "^4.1.
|
|
54
|
-
"lucide-static": "^1.
|
|
52
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
53
|
+
"@vitest/ui": "^4.1.5",
|
|
54
|
+
"lucide-static": "^1.11.0",
|
|
55
55
|
"pixelmatch": "7.1.0",
|
|
56
56
|
"pngjs": "7.0.0",
|
|
57
|
-
"size-limit": "^12.0
|
|
57
|
+
"size-limit": "^12.1.0",
|
|
58
58
|
"tsx": "4.21.0",
|
|
59
|
-
"typescript-eslint": "^8.
|
|
59
|
+
"typescript-eslint": "^8.59.0"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@resvg/resvg-wasm": "^2.6.2",
|