@llc3233149/core 0.9.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/dist/canvaskit.d.ts +9 -0
- package/dist/canvaskit.d.ts.map +1 -0
- package/dist/canvaskit.js +55 -0
- package/dist/canvaskit.js.map +1 -0
- package/dist/clipboard.d.ts +32 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +345 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/color.d.ts +28 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +67 -0
- package/dist/color.js.map +1 -0
- package/dist/constants.d.ts +159 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +224 -0
- package/dist/constants.js.map +1 -0
- package/dist/copy.d.ts +20 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +64 -0
- package/dist/copy.js.map +1 -0
- package/dist/fig-export-worker.d.ts +2 -0
- package/dist/fig-export-worker.d.ts.map +1 -0
- package/dist/fig-export-worker.js +17 -0
- package/dist/fig-export-worker.js.map +1 -0
- package/dist/fig-export.d.ts +13 -0
- package/dist/fig-export.d.ts.map +1 -0
- package/dist/fig-export.js +243 -0
- package/dist/fig-export.js.map +1 -0
- package/dist/figma-api.d.ts +268 -0
- package/dist/figma-api.d.ts.map +1 -0
- package/dist/figma-api.js +1074 -0
- package/dist/figma-api.js.map +1 -0
- package/dist/figma-rest-import.d.ts +122 -0
- package/dist/figma-rest-import.d.ts.map +1 -0
- package/dist/figma-rest-import.js +319 -0
- package/dist/figma-rest-import.js.map +1 -0
- package/dist/fonts.d.ts +24 -0
- package/dist/fonts.d.ts.map +1 -0
- package/dist/fonts.js +356 -0
- package/dist/fonts.js.map +1 -0
- package/dist/geometry.d.ts +14 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +47 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/kiwi/codec.d.ts +292 -0
- package/dist/kiwi/codec.d.ts.map +1 -0
- package/dist/kiwi/codec.js +340 -0
- package/dist/kiwi/codec.js.map +1 -0
- package/dist/kiwi/fig-file.d.ts +4 -0
- package/dist/kiwi/fig-file.d.ts.map +1 -0
- package/dist/kiwi/fig-file.js +236 -0
- package/dist/kiwi/fig-file.js.map +1 -0
- package/dist/kiwi/fig-import.d.ts +4 -0
- package/dist/kiwi/fig-import.d.ts.map +1 -0
- package/dist/kiwi/fig-import.js +248 -0
- package/dist/kiwi/fig-import.js.map +1 -0
- package/dist/kiwi/fig-parse-worker.d.ts +7 -0
- package/dist/kiwi/fig-parse-worker.d.ts.map +1 -0
- package/dist/kiwi/fig-parse-worker.js +184 -0
- package/dist/kiwi/fig-parse-worker.js.map +1 -0
- package/dist/kiwi/instance-overrides.d.ts +66 -0
- package/dist/kiwi/instance-overrides.d.ts.map +1 -0
- package/dist/kiwi/instance-overrides.js +644 -0
- package/dist/kiwi/instance-overrides.js.map +1 -0
- package/dist/kiwi/kiwi-convert.d.ts +19 -0
- package/dist/kiwi/kiwi-convert.d.ts.map +1 -0
- package/dist/kiwi/kiwi-convert.js +678 -0
- package/dist/kiwi/kiwi-convert.js.map +1 -0
- package/dist/kiwi/kiwi-schema/bb.d.ts +25 -0
- package/dist/kiwi/kiwi-schema/bb.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/bb.js +225 -0
- package/dist/kiwi/kiwi-schema/bb.js.map +1 -0
- package/dist/kiwi/kiwi-schema/binary.d.ts +5 -0
- package/dist/kiwi/kiwi-schema/binary.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/binary.js +86 -0
- package/dist/kiwi/kiwi-schema/binary.js.map +1 -0
- package/dist/kiwi/kiwi-schema/index.d.ts +6 -0
- package/dist/kiwi/kiwi-schema/index.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/index.js +5 -0
- package/dist/kiwi/kiwi-schema/index.js.map +1 -0
- package/dist/kiwi/kiwi-schema/js.d.ts +4 -0
- package/dist/kiwi/kiwi-schema/js.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/js.js +282 -0
- package/dist/kiwi/kiwi-schema/js.js.map +1 -0
- package/dist/kiwi/kiwi-schema/parser.d.ts +5 -0
- package/dist/kiwi/kiwi-schema/parser.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/parser.js +228 -0
- package/dist/kiwi/kiwi-schema/parser.js.map +1 -0
- package/dist/kiwi/kiwi-schema/schema.d.ts +22 -0
- package/dist/kiwi/kiwi-schema/schema.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/schema.js +2 -0
- package/dist/kiwi/kiwi-schema/schema.js.map +1 -0
- package/dist/kiwi/kiwi-schema/util.d.ts +3 -0
- package/dist/kiwi/kiwi-schema/util.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/util.js +10 -0
- package/dist/kiwi/kiwi-schema/util.js.map +1 -0
- package/dist/kiwi/protocol.d.ts +172 -0
- package/dist/kiwi/protocol.d.ts.map +1 -0
- package/dist/kiwi/protocol.js +214 -0
- package/dist/kiwi/protocol.js.map +1 -0
- package/dist/kiwi/schema.d.ts +3 -0
- package/dist/kiwi/schema.d.ts.map +1 -0
- package/dist/kiwi/schema.js +2285 -0
- package/dist/kiwi/schema.js.map +1 -0
- package/dist/kiwi-serialize.d.ts +17 -0
- package/dist/kiwi-serialize.d.ts.map +1 -0
- package/dist/kiwi-serialize.js +419 -0
- package/dist/kiwi-serialize.js.map +1 -0
- package/dist/layout.d.ts +9 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +533 -0
- package/dist/layout.js.map +1 -0
- package/dist/profiler/draw-call-counter.d.ts +9 -0
- package/dist/profiler/draw-call-counter.d.ts.map +1 -0
- package/dist/profiler/draw-call-counter.js +37 -0
- package/dist/profiler/draw-call-counter.js.map +1 -0
- package/dist/profiler/frame-capture.d.ts +34 -0
- package/dist/profiler/frame-capture.d.ts.map +1 -0
- package/dist/profiler/frame-capture.js +90 -0
- package/dist/profiler/frame-capture.js.map +1 -0
- package/dist/profiler/frame-stats.d.ts +33 -0
- package/dist/profiler/frame-stats.d.ts.map +1 -0
- package/dist/profiler/frame-stats.js +103 -0
- package/dist/profiler/frame-stats.js.map +1 -0
- package/dist/profiler/gpu-timer.d.ts +15 -0
- package/dist/profiler/gpu-timer.d.ts.map +1 -0
- package/dist/profiler/gpu-timer.js +77 -0
- package/dist/profiler/gpu-timer.js.map +1 -0
- package/dist/profiler/hud-renderer.d.ts +22 -0
- package/dist/profiler/hud-renderer.d.ts.map +1 -0
- package/dist/profiler/hud-renderer.js +200 -0
- package/dist/profiler/hud-renderer.js.map +1 -0
- package/dist/profiler/index.d.ts +9 -0
- package/dist/profiler/index.d.ts.map +1 -0
- package/dist/profiler/index.js +8 -0
- package/dist/profiler/index.js.map +1 -0
- package/dist/profiler/phase-timer.d.ts +9 -0
- package/dist/profiler/phase-timer.d.ts.map +1 -0
- package/dist/profiler/phase-timer.js +51 -0
- package/dist/profiler/phase-timer.js.map +1 -0
- package/dist/profiler/render-profiler.d.ts +41 -0
- package/dist/profiler/render-profiler.d.ts.map +1 -0
- package/dist/profiler/render-profiler.js +142 -0
- package/dist/profiler/render-profiler.js.map +1 -0
- package/dist/render/components.d.ts +25 -0
- package/dist/render/components.d.ts.map +1 -0
- package/dist/render/components.js +55 -0
- package/dist/render/components.js.map +1 -0
- package/dist/render/emoji-icons.d.ts +5 -0
- package/dist/render/emoji-icons.d.ts.map +1 -0
- package/dist/render/emoji-icons.js +55 -0
- package/dist/render/emoji-icons.js.map +1 -0
- package/dist/render/export-code.d.ts +9 -0
- package/dist/render/export-code.d.ts.map +1 -0
- package/dist/render/export-code.js +335 -0
- package/dist/render/export-code.js.map +1 -0
- package/dist/render/export-jsx.d.ts +5 -0
- package/dist/render/export-jsx.d.ts.map +1 -0
- package/dist/render/export-jsx.js +621 -0
- package/dist/render/export-jsx.js.map +1 -0
- package/dist/render/index.d.ts +8 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +8 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/jsx-runtime.d.ts +31 -0
- package/dist/render/jsx-runtime.d.ts.map +1 -0
- package/dist/render/jsx-runtime.js +13 -0
- package/dist/render/jsx-runtime.js.map +1 -0
- package/dist/render/mini-react.d.ts +14 -0
- package/dist/render/mini-react.d.ts.map +1 -0
- package/dist/render/mini-react.js +16 -0
- package/dist/render/mini-react.js.map +1 -0
- package/dist/render/render-jsx.d.ts +24 -0
- package/dist/render/render-jsx.d.ts.map +1 -0
- package/dist/render/render-jsx.js +51 -0
- package/dist/render/render-jsx.js.map +1 -0
- package/dist/render/renderer.d.ts +16 -0
- package/dist/render/renderer.d.ts.map +1 -0
- package/dist/render/renderer.js +437 -0
- package/dist/render/renderer.js.map +1 -0
- package/dist/render/tailwind.d.ts +20 -0
- package/dist/render/tailwind.d.ts.map +1 -0
- package/dist/render/tailwind.js +115 -0
- package/dist/render/tailwind.js.map +1 -0
- package/dist/render/tree.d.ts +72 -0
- package/dist/render/tree.d.ts.map +1 -0
- package/dist/render/tree.js +63 -0
- package/dist/render/tree.js.map +1 -0
- package/dist/render-image.d.ts +19 -0
- package/dist/render-image.d.ts.map +1 -0
- package/dist/render-image.js +84 -0
- package/dist/render-image.js.map +1 -0
- package/dist/renderer/effects.d.ts +9 -0
- package/dist/renderer/effects.d.ts.map +1 -0
- package/dist/renderer/effects.js +44 -0
- package/dist/renderer/effects.js.map +1 -0
- package/dist/renderer/fills.d.ts +9 -0
- package/dist/renderer/fills.d.ts.map +1 -0
- package/dist/renderer/fills.js +189 -0
- package/dist/renderer/fills.js.map +1 -0
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/renderer/index.js +2 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/renderer/label-cache.d.ts +43 -0
- package/dist/renderer/label-cache.d.ts.map +1 -0
- package/dist/renderer/label-cache.js +85 -0
- package/dist/renderer/label-cache.js.map +1 -0
- package/dist/renderer/labels.d.ts +6 -0
- package/dist/renderer/labels.d.ts.map +1 -0
- package/dist/renderer/labels.js +126 -0
- package/dist/renderer/labels.js.map +1 -0
- package/dist/renderer/lru-cache.d.ts +20 -0
- package/dist/renderer/lru-cache.d.ts.map +1 -0
- package/dist/renderer/lru-cache.js +65 -0
- package/dist/renderer/lru-cache.js.map +1 -0
- package/dist/renderer/overlays.d.ts +25 -0
- package/dist/renderer/overlays.d.ts.map +1 -0
- package/dist/renderer/overlays.js +783 -0
- package/dist/renderer/overlays.js.map +1 -0
- package/dist/renderer/renderer.d.ts +229 -0
- package/dist/renderer/renderer.d.ts.map +1 -0
- package/dist/renderer/renderer.js +909 -0
- package/dist/renderer/renderer.js.map +1 -0
- package/dist/renderer/rulers.d.ts +8 -0
- package/dist/renderer/rulers.d.ts.map +1 -0
- package/dist/renderer/rulers.js +147 -0
- package/dist/renderer/rulers.js.map +1 -0
- package/dist/renderer/scene.d.ts +11 -0
- package/dist/renderer/scene.d.ts.map +1 -0
- package/dist/renderer/scene.js +392 -0
- package/dist/renderer/scene.js.map +1 -0
- package/dist/renderer/shapes.d.ts +13 -0
- package/dist/renderer/shapes.d.ts.map +1 -0
- package/dist/renderer/shapes.js +160 -0
- package/dist/renderer/shapes.js.map +1 -0
- package/dist/renderer/strokes.d.ts +9 -0
- package/dist/renderer/strokes.d.ts.map +1 -0
- package/dist/renderer/strokes.js +180 -0
- package/dist/renderer/strokes.js.map +1 -0
- package/dist/rpc/commands.d.ts +202 -0
- package/dist/rpc/commands.d.ts.map +1 -0
- package/dist/rpc/commands.js +429 -0
- package/dist/rpc/commands.js.map +1 -0
- package/dist/rpc/index.d.ts +3 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +2 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/scene-graph.d.ts +318 -0
- package/dist/scene-graph.d.ts.map +1 -0
- package/dist/scene-graph.js +803 -0
- package/dist/scene-graph.js.map +1 -0
- package/dist/snap.d.ts +16 -0
- package/dist/snap.d.ts.map +1 -0
- package/dist/snap.js +97 -0
- package/dist/snap.js.map +1 -0
- package/dist/style-runs.d.ts +20 -0
- package/dist/style-runs.d.ts.map +1 -0
- package/dist/style-runs.js +168 -0
- package/dist/style-runs.js.map +1 -0
- package/dist/svg-export/defs.d.ts +19 -0
- package/dist/svg-export/defs.d.ts.map +1 -0
- package/dist/svg-export/defs.js +191 -0
- package/dist/svg-export/defs.js.map +1 -0
- package/dist/svg-export/index.d.ts +8 -0
- package/dist/svg-export/index.d.ts.map +1 -0
- package/dist/svg-export/index.js +318 -0
- package/dist/svg-export/index.js.map +1 -0
- package/dist/svg-export/paths.d.ts +9 -0
- package/dist/svg-export/paths.d.ts.map +1 -0
- package/dist/svg-export/paths.js +189 -0
- package/dist/svg-export/paths.js.map +1 -0
- package/dist/svg-node.d.ts +8 -0
- package/dist/svg-node.d.ts.map +1 -0
- package/dist/svg-node.js +48 -0
- package/dist/svg-node.js.map +1 -0
- package/dist/text-editor.d.ts +57 -0
- package/dist/text-editor.d.ts.map +1 -0
- package/dist/text-editor.js +337 -0
- package/dist/text-editor.js.map +1 -0
- package/dist/tools/ai-adapter.d.ts +22 -0
- package/dist/tools/ai-adapter.d.ts.map +1 -0
- package/dist/tools/ai-adapter.js +121 -0
- package/dist/tools/ai-adapter.js.map +1 -0
- package/dist/tools/analyze.d.ts +22 -0
- package/dist/tools/analyze.d.ts.map +1 -0
- package/dist/tools/analyze.js +677 -0
- package/dist/tools/analyze.js.map +1 -0
- package/dist/tools/create.d.ts +8 -0
- package/dist/tools/create.d.ts.map +1 -0
- package/dist/tools/create.js +204 -0
- package/dist/tools/create.js.map +1 -0
- package/dist/tools/describe.d.ts +9 -0
- package/dist/tools/describe.d.ts.map +1 -0
- package/dist/tools/describe.js +295 -0
- package/dist/tools/describe.js.map +1 -0
- package/dist/tools/export-code.d.ts +2 -0
- package/dist/tools/export-code.d.ts.map +1 -0
- package/dist/tools/export-code.js +34 -0
- package/dist/tools/export-code.js.map +1 -0
- package/dist/tools/export-tailwind-config.d.ts +27 -0
- package/dist/tools/export-tailwind-config.d.ts.map +1 -0
- package/dist/tools/export-tailwind-config.js +215 -0
- package/dist/tools/export-tailwind-config.js.map +1 -0
- package/dist/tools/icons.d.ts +5 -0
- package/dist/tools/icons.d.ts.map +1 -0
- package/dist/tools/icons.js +192 -0
- package/dist/tools/icons.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/modify.d.ts +22 -0
- package/dist/tools/modify.d.ts.map +1 -0
- package/dist/tools/modify.js +653 -0
- package/dist/tools/modify.js.map +1 -0
- package/dist/tools/patterns.d.ts +2 -0
- package/dist/tools/patterns.d.ts.map +1 -0
- package/dist/tools/patterns.js +173 -0
- package/dist/tools/patterns.js.map +1 -0
- package/dist/tools/read.d.ts +17 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +379 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/registry.d.ts +3 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +124 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/schema.d.ts +46 -0
- package/dist/tools/schema.d.ts.map +1 -0
- package/dist/tools/schema.js +17 -0
- package/dist/tools/schema.js.map +1 -0
- package/dist/tools/structure.d.ts +18 -0
- package/dist/tools/structure.d.ts.map +1 -0
- package/dist/tools/structure.js +345 -0
- package/dist/tools/structure.js.map +1 -0
- package/dist/tools/variables.d.ts +12 -0
- package/dist/tools/variables.d.ts.map +1 -0
- package/dist/tools/variables.js +190 -0
- package/dist/tools/variables.js.map +1 -0
- package/dist/tools/vector.d.ts +15 -0
- package/dist/tools/vector.d.ts.map +1 -0
- package/dist/tools/vector.js +312 -0
- package/dist/tools/vector.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/undo.d.ts +33 -0
- package/dist/undo.d.ts.map +1 -0
- package/dist/undo.js +98 -0
- package/dist/undo.js.map +1 -0
- package/dist/vector.d.ts +14 -0
- package/dist/vector.d.ts.map +1 -0
- package/dist/vector.js +334 -0
- package/dist/vector.js.map +1 -0
- package/dist/xpath.d.ts +8 -0
- package/dist/xpath.d.ts.map +1 -0
- package/dist/xpath.js +199 -0
- package/dist/xpath.js.map +1 -0
- package/package.json +54 -0
- package/src/canvaskit.ts +66 -0
- package/src/clipboard.ts +444 -0
- package/src/color.ts +83 -0
- package/src/constants.ts +277 -0
- package/src/copy.ts +75 -0
- package/src/fig-export-worker.ts +28 -0
- package/src/fig-export.ts +321 -0
- package/src/figma-api.ts +1297 -0
- package/src/figma-rest-import.ts +443 -0
- package/src/fonts.ts +369 -0
- package/src/geometry.ts +73 -0
- package/src/global.d.ts +20 -0
- package/src/index.ts +247 -0
- package/src/kiwi/codec.ts +614 -0
- package/src/kiwi/fig-file.ts +248 -0
- package/src/kiwi/fig-import.ts +300 -0
- package/src/kiwi/fig-parse-worker.ts +213 -0
- package/src/kiwi/instance-overrides.ts +682 -0
- package/src/kiwi/kiwi-convert.ts +771 -0
- package/src/kiwi/kiwi-schema/bb.ts +244 -0
- package/src/kiwi/kiwi-schema/binary.ts +102 -0
- package/src/kiwi/kiwi-schema/index.ts +5 -0
- package/src/kiwi/kiwi-schema/js.ts +339 -0
- package/src/kiwi/kiwi-schema/parser.ts +287 -0
- package/src/kiwi/kiwi-schema/schema.ts +24 -0
- package/src/kiwi/kiwi-schema/util.ts +10 -0
- package/src/kiwi/protocol.ts +237 -0
- package/src/kiwi/schema.ts +2286 -0
- package/src/kiwi-serialize.ts +467 -0
- package/src/layout.ts +608 -0
- package/src/profiler/draw-call-counter.ts +43 -0
- package/src/profiler/frame-capture.ts +139 -0
- package/src/profiler/frame-stats.ts +122 -0
- package/src/profiler/gpu-timer.ts +93 -0
- package/src/profiler/hud-renderer.ts +242 -0
- package/src/profiler/index.ts +8 -0
- package/src/profiler/phase-timer.ts +62 -0
- package/src/profiler/render-profiler.ts +163 -0
- package/src/render/components.ts +69 -0
- package/src/render/emoji-icons.ts +60 -0
- package/src/render/export-code.ts +366 -0
- package/src/render/export-jsx.ts +633 -0
- package/src/render/index.ts +38 -0
- package/src/render/jsx-runtime.ts +36 -0
- package/src/render/mini-react.ts +30 -0
- package/src/render/render-jsx.ts +74 -0
- package/src/render/renderer.ts +508 -0
- package/src/render/tailwind.ts +114 -0
- package/src/render/tree.ts +137 -0
- package/src/render-image.ts +139 -0
- package/src/renderer/effects.ts +64 -0
- package/src/renderer/fills.ts +248 -0
- package/src/renderer/index.ts +1 -0
- package/src/renderer/label-cache.ts +114 -0
- package/src/renderer/labels.ts +168 -0
- package/src/renderer/lru-cache.ts +71 -0
- package/src/renderer/overlays.ts +1089 -0
- package/src/renderer/renderer.ts +1226 -0
- package/src/renderer/rulers.ts +230 -0
- package/src/renderer/scene.ts +554 -0
- package/src/renderer/shapes.ts +193 -0
- package/src/renderer/strokes.ts +221 -0
- package/src/rpc/commands.ts +667 -0
- package/src/rpc/index.ts +25 -0
- package/src/scene-graph.ts +1254 -0
- package/src/snap.ts +122 -0
- package/src/style-runs.ts +234 -0
- package/src/svg-export/defs.ts +255 -0
- package/src/svg-export/index.ts +427 -0
- package/src/svg-export/paths.ts +212 -0
- package/src/svg-node.ts +62 -0
- package/src/text-editor.ts +349 -0
- package/src/tools/ai-adapter.ts +144 -0
- package/src/tools/analyze.ts +786 -0
- package/src/tools/create.ts +206 -0
- package/src/tools/describe.ts +280 -0
- package/src/tools/export-code.ts +41 -0
- package/src/tools/export-tailwind-config.ts +266 -0
- package/src/tools/icons.ts +213 -0
- package/src/tools/index.ts +6 -0
- package/src/tools/modify.ts +651 -0
- package/src/tools/patterns.ts +189 -0
- package/src/tools/read.ts +401 -0
- package/src/tools/registry.ts +155 -0
- package/src/tools/schema.ts +65 -0
- package/src/tools/structure.ts +348 -0
- package/src/tools/variables.ts +193 -0
- package/src/tools/vector.ts +311 -0
- package/src/types.ts +32 -0
- package/src/undo.ts +126 -0
- package/src/vector.ts +413 -0
- package/src/xpath.ts +259 -0
package/src/vector.ts
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HandleMirroring,
|
|
3
|
+
VectorNetwork,
|
|
4
|
+
VectorRegion,
|
|
5
|
+
VectorSegment,
|
|
6
|
+
VectorVertex,
|
|
7
|
+
WindingRule
|
|
8
|
+
} from './scene-graph'
|
|
9
|
+
import type { CanvasKit, Path } from 'canvaskit-wasm'
|
|
10
|
+
import type { Rect } from './types'
|
|
11
|
+
|
|
12
|
+
// --- vectorNetworkBlob binary format ---
|
|
13
|
+
// Header: [numVertices:u32, numSegments:u32, numRegions:u32] (12 bytes)
|
|
14
|
+
// Vertex: [styleOverrideIdx:u32, x:f32, y:f32] (12 bytes)
|
|
15
|
+
// Segment: [styleOverrideIdx:u32, start:u32, tsX:f32, tsY:f32, end:u32, teX:f32, teY:f32] (28 bytes)
|
|
16
|
+
// Region: [windingRule:u32, numLoops:u32, {numSegs:u32, segIdx...}... ] (variable)
|
|
17
|
+
|
|
18
|
+
interface StyleOverride {
|
|
19
|
+
styleID: number
|
|
20
|
+
handleMirroring?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function decodeVectorNetworkBlob(
|
|
24
|
+
data: Uint8Array,
|
|
25
|
+
styleOverrideTable?: StyleOverride[]
|
|
26
|
+
): VectorNetwork {
|
|
27
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength)
|
|
28
|
+
let o = 0
|
|
29
|
+
|
|
30
|
+
const nV = view.getUint32(o, true)
|
|
31
|
+
o += 4
|
|
32
|
+
const nS = view.getUint32(o, true)
|
|
33
|
+
o += 4
|
|
34
|
+
const nR = view.getUint32(o, true)
|
|
35
|
+
o += 4
|
|
36
|
+
|
|
37
|
+
const styleMap = new Map<number, StyleOverride>()
|
|
38
|
+
if (styleOverrideTable) {
|
|
39
|
+
for (const entry of styleOverrideTable) {
|
|
40
|
+
styleMap.set(entry.styleID, entry)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const vertices: VectorVertex[] = []
|
|
45
|
+
for (let i = 0; i < nV; i++) {
|
|
46
|
+
const styleIdx = view.getUint32(o, true)
|
|
47
|
+
o += 4
|
|
48
|
+
const x = view.getFloat32(o, true)
|
|
49
|
+
o += 4
|
|
50
|
+
const y = view.getFloat32(o, true)
|
|
51
|
+
o += 4
|
|
52
|
+
|
|
53
|
+
const override = styleMap.get(styleIdx)
|
|
54
|
+
vertices.push({
|
|
55
|
+
x,
|
|
56
|
+
y,
|
|
57
|
+
handleMirroring: (override?.handleMirroring as HandleMirroring | undefined) ?? 'NONE'
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const segments: VectorSegment[] = []
|
|
62
|
+
for (let i = 0; i < nS; i++) {
|
|
63
|
+
o += 4 // styleOverrideIdx (unused for segments currently)
|
|
64
|
+
const start = view.getUint32(o, true)
|
|
65
|
+
o += 4
|
|
66
|
+
const tsX = view.getFloat32(o, true)
|
|
67
|
+
o += 4
|
|
68
|
+
const tsY = view.getFloat32(o, true)
|
|
69
|
+
o += 4
|
|
70
|
+
const end = view.getUint32(o, true)
|
|
71
|
+
o += 4
|
|
72
|
+
const teX = view.getFloat32(o, true)
|
|
73
|
+
o += 4
|
|
74
|
+
const teY = view.getFloat32(o, true)
|
|
75
|
+
o += 4
|
|
76
|
+
|
|
77
|
+
segments.push({
|
|
78
|
+
start,
|
|
79
|
+
end,
|
|
80
|
+
tangentStart: { x: tsX, y: tsY },
|
|
81
|
+
tangentEnd: { x: teX, y: teY }
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const regions: VectorRegion[] = []
|
|
86
|
+
for (let i = 0; i < nR; i++) {
|
|
87
|
+
const windingRuleU32 = view.getUint32(o, true)
|
|
88
|
+
o += 4
|
|
89
|
+
const windingRule: WindingRule = windingRuleU32 === 0 ? 'EVENODD' : 'NONZERO'
|
|
90
|
+
const numLoops = view.getUint32(o, true)
|
|
91
|
+
o += 4
|
|
92
|
+
const loops: number[][] = []
|
|
93
|
+
for (let j = 0; j < numLoops; j++) {
|
|
94
|
+
const numSegs = view.getUint32(o, true)
|
|
95
|
+
o += 4
|
|
96
|
+
const loop: number[] = []
|
|
97
|
+
for (let k = 0; k < numSegs; k++) {
|
|
98
|
+
loop.push(view.getUint32(o, true))
|
|
99
|
+
o += 4
|
|
100
|
+
}
|
|
101
|
+
loops.push(loop)
|
|
102
|
+
}
|
|
103
|
+
regions.push({ windingRule, loops })
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { vertices, segments, regions }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function encodeVectorNetworkBlob(network: VectorNetwork): Uint8Array {
|
|
110
|
+
const { vertices, segments, regions } = network
|
|
111
|
+
|
|
112
|
+
let regionBytes = 0
|
|
113
|
+
for (const region of regions) {
|
|
114
|
+
regionBytes += 8 // windingRule + numLoops
|
|
115
|
+
for (const loop of region.loops) {
|
|
116
|
+
regionBytes += 4 + loop.length * 4 // numSegs + indices
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const totalBytes = 12 + vertices.length * 12 + segments.length * 28 + regionBytes
|
|
121
|
+
const buf = new ArrayBuffer(totalBytes)
|
|
122
|
+
const view = new DataView(buf)
|
|
123
|
+
let o = 0
|
|
124
|
+
|
|
125
|
+
view.setUint32(o, vertices.length, true)
|
|
126
|
+
o += 4
|
|
127
|
+
view.setUint32(o, segments.length, true)
|
|
128
|
+
o += 4
|
|
129
|
+
view.setUint32(o, regions.length, true)
|
|
130
|
+
o += 4
|
|
131
|
+
|
|
132
|
+
for (const v of vertices) {
|
|
133
|
+
view.setUint32(o, 0, true)
|
|
134
|
+
o += 4 // styleOverrideIdx (TODO: encode handleMirroring)
|
|
135
|
+
view.setFloat32(o, v.x, true)
|
|
136
|
+
o += 4
|
|
137
|
+
view.setFloat32(o, v.y, true)
|
|
138
|
+
o += 4
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (const seg of segments) {
|
|
142
|
+
view.setUint32(o, 0, true)
|
|
143
|
+
o += 4 // styleOverrideIdx
|
|
144
|
+
view.setUint32(o, seg.start, true)
|
|
145
|
+
o += 4
|
|
146
|
+
view.setFloat32(o, seg.tangentStart.x, true)
|
|
147
|
+
o += 4
|
|
148
|
+
view.setFloat32(o, seg.tangentStart.y, true)
|
|
149
|
+
o += 4
|
|
150
|
+
view.setUint32(o, seg.end, true)
|
|
151
|
+
o += 4
|
|
152
|
+
view.setFloat32(o, seg.tangentEnd.x, true)
|
|
153
|
+
o += 4
|
|
154
|
+
view.setFloat32(o, seg.tangentEnd.y, true)
|
|
155
|
+
o += 4
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (const region of regions) {
|
|
159
|
+
view.setUint32(o, region.windingRule === 'EVENODD' ? 0 : 1, true)
|
|
160
|
+
o += 4
|
|
161
|
+
view.setUint32(o, region.loops.length, true)
|
|
162
|
+
o += 4
|
|
163
|
+
for (const loop of region.loops) {
|
|
164
|
+
view.setUint32(o, loop.length, true)
|
|
165
|
+
o += 4
|
|
166
|
+
for (const segIdx of loop) {
|
|
167
|
+
view.setUint32(o, segIdx, true)
|
|
168
|
+
o += 4
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return new Uint8Array(buf)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function vectorNetworkToPath(ck: CanvasKit, network: VectorNetwork): Path[] {
|
|
177
|
+
const { vertices, segments, regions } = network
|
|
178
|
+
|
|
179
|
+
if (regions.length > 0) {
|
|
180
|
+
const paths: Path[] = []
|
|
181
|
+
for (const region of regions) {
|
|
182
|
+
const regionPath = new ck.Path()
|
|
183
|
+
for (const loop of region.loops) {
|
|
184
|
+
addLoopToPath(regionPath, loop, segments, vertices)
|
|
185
|
+
}
|
|
186
|
+
regionPath.setFillType(
|
|
187
|
+
region.windingRule === 'EVENODD' ? ck.FillType.EvenOdd : ck.FillType.Winding
|
|
188
|
+
)
|
|
189
|
+
paths.push(regionPath)
|
|
190
|
+
}
|
|
191
|
+
return paths
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// No regions — draw all segments as open paths, tracking direction
|
|
195
|
+
const path = new ck.Path()
|
|
196
|
+
const visited = new Set<number>()
|
|
197
|
+
const chains = buildChains(segments, vertices.length)
|
|
198
|
+
|
|
199
|
+
for (const chain of chains) {
|
|
200
|
+
if (chain.length === 0) continue
|
|
201
|
+
// Determine starting vertex by tracing chain direction
|
|
202
|
+
let current = findChainStart(chain, segments)
|
|
203
|
+
path.moveTo(vertices[current].x, vertices[current].y)
|
|
204
|
+
|
|
205
|
+
for (const segIdx of chain) {
|
|
206
|
+
visited.add(segIdx)
|
|
207
|
+
const seg = segments[segIdx]
|
|
208
|
+
const forward = seg.start === current
|
|
209
|
+
addSegmentDirected(path, seg, vertices, forward)
|
|
210
|
+
current = forward ? seg.end : seg.start
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
for (let i = 0; i < segments.length; i++) {
|
|
215
|
+
if (visited.has(i)) continue
|
|
216
|
+
const seg = segments[i]
|
|
217
|
+
path.moveTo(vertices[seg.start].x, vertices[seg.start].y)
|
|
218
|
+
addSegmentDirected(path, seg, vertices, true)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return [path]
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function addLoopToPath(
|
|
225
|
+
path: Path,
|
|
226
|
+
loop: number[],
|
|
227
|
+
segments: VectorSegment[],
|
|
228
|
+
vertices: VectorVertex[]
|
|
229
|
+
): void {
|
|
230
|
+
if (loop.length === 0) return
|
|
231
|
+
|
|
232
|
+
// Region loops have pre-oriented segments — always draw forward
|
|
233
|
+
const firstSeg = segments[loop[0]]
|
|
234
|
+
path.moveTo(vertices[firstSeg.start].x, vertices[firstSeg.start].y)
|
|
235
|
+
|
|
236
|
+
for (const segIdx of loop) {
|
|
237
|
+
addSegmentDirected(path, segments[segIdx], vertices, true)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const lastSeg = segments[loop[loop.length - 1]]
|
|
241
|
+
if (lastSeg.end === firstSeg.start) {
|
|
242
|
+
path.close()
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function addSegmentDirected(
|
|
247
|
+
path: Path,
|
|
248
|
+
seg: VectorSegment,
|
|
249
|
+
vertices: VectorVertex[],
|
|
250
|
+
forward: boolean
|
|
251
|
+
): void {
|
|
252
|
+
const p0 = forward ? vertices[seg.start] : vertices[seg.end]
|
|
253
|
+
const p3 = forward ? vertices[seg.end] : vertices[seg.start]
|
|
254
|
+
const ts = seg.tangentStart
|
|
255
|
+
const te = seg.tangentEnd
|
|
256
|
+
|
|
257
|
+
const isLine = ts.x === 0 && ts.y === 0 && te.x === 0 && te.y === 0
|
|
258
|
+
if (isLine) {
|
|
259
|
+
path.lineTo(p3.x, p3.y)
|
|
260
|
+
} else if (forward) {
|
|
261
|
+
path.cubicTo(p0.x + ts.x, p0.y + ts.y, p3.x + te.x, p3.y + te.y, p3.x, p3.y)
|
|
262
|
+
} else {
|
|
263
|
+
// Reversed cubic: swap control points
|
|
264
|
+
path.cubicTo(p0.x + te.x, p0.y + te.y, p3.x + ts.x, p3.y + ts.y, p3.x, p3.y)
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function findChainStart(chain: number[], segments: VectorSegment[]): number {
|
|
269
|
+
if (chain.length < 2) return segments[chain[0]].start
|
|
270
|
+
|
|
271
|
+
const first = segments[chain[0]]
|
|
272
|
+
const second = segments[chain[1]]
|
|
273
|
+
// The shared vertex between first and second is the "end" of the first
|
|
274
|
+
// segment in this chain — so the start is the other vertex.
|
|
275
|
+
if (first.start === second.start || first.start === second.end) return first.end
|
|
276
|
+
return first.start
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function buildChains(segments: VectorSegment[], _vertexCount: number): number[][] {
|
|
280
|
+
if (segments.length === 0) return []
|
|
281
|
+
|
|
282
|
+
// Build adjacency: for each vertex, which segments connect to it
|
|
283
|
+
const adj = new Map<number, number[]>()
|
|
284
|
+
for (let i = 0; i < segments.length; i++) {
|
|
285
|
+
const s = segments[i]
|
|
286
|
+
if (!adj.has(s.start)) adj.set(s.start, [])
|
|
287
|
+
if (!adj.has(s.end)) adj.set(s.end, [])
|
|
288
|
+
adj.get(s.start)?.push(i)
|
|
289
|
+
adj.get(s.end)?.push(i)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const visited = new Set<number>()
|
|
293
|
+
const chains: number[][] = []
|
|
294
|
+
|
|
295
|
+
// Start from degree-1 vertices (endpoints) or any unvisited
|
|
296
|
+
const degree1 = [...adj.entries()].filter(([, segs]) => segs.length === 1).map(([v]) => v)
|
|
297
|
+
|
|
298
|
+
const startVertices = degree1.length > 0 ? degree1 : [segments[0].start]
|
|
299
|
+
|
|
300
|
+
for (const startVertex of startVertices) {
|
|
301
|
+
let current = startVertex
|
|
302
|
+
const chain: number[] = []
|
|
303
|
+
|
|
304
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
305
|
+
while (true) {
|
|
306
|
+
const segs = adj.get(current)
|
|
307
|
+
if (!segs) break
|
|
308
|
+
|
|
309
|
+
const nextSeg = segs.find((s) => !visited.has(s))
|
|
310
|
+
if (nextSeg === undefined) break
|
|
311
|
+
|
|
312
|
+
visited.add(nextSeg)
|
|
313
|
+
chain.push(nextSeg)
|
|
314
|
+
|
|
315
|
+
const seg = segments[nextSeg]
|
|
316
|
+
current = seg.start === current ? seg.end : seg.start
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (chain.length > 0) chains.push(chain)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return chains
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function computeVectorBounds(network: VectorNetwork): Rect {
|
|
326
|
+
if (network.vertices.length === 0) {
|
|
327
|
+
return { x: 0, y: 0, width: 0, height: 0 }
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
let minX = Infinity
|
|
331
|
+
let minY = Infinity
|
|
332
|
+
let maxX = -Infinity
|
|
333
|
+
let maxY = -Infinity
|
|
334
|
+
|
|
335
|
+
for (const v of network.vertices) {
|
|
336
|
+
minX = Math.min(minX, v.x)
|
|
337
|
+
minY = Math.min(minY, v.y)
|
|
338
|
+
maxX = Math.max(maxX, v.x)
|
|
339
|
+
maxY = Math.max(maxY, v.y)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Also consider bezier control points for tighter bounds
|
|
343
|
+
for (const seg of network.segments) {
|
|
344
|
+
const start = network.vertices[seg.start]
|
|
345
|
+
const end = network.vertices[seg.end]
|
|
346
|
+
const cp1x = start.x + seg.tangentStart.x
|
|
347
|
+
const cp1y = start.y + seg.tangentStart.y
|
|
348
|
+
const cp2x = end.x + seg.tangentEnd.x
|
|
349
|
+
const cp2y = end.y + seg.tangentEnd.y
|
|
350
|
+
|
|
351
|
+
minX = Math.min(minX, cp1x, cp2x)
|
|
352
|
+
minY = Math.min(minY, cp1y, cp2y)
|
|
353
|
+
maxX = Math.max(maxX, cp1x, cp2x)
|
|
354
|
+
maxY = Math.max(maxY, cp1y, cp2y)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const CMD_CLOSE = 0
|
|
361
|
+
const CMD_MOVE_TO = 1
|
|
362
|
+
const CMD_LINE_TO = 2
|
|
363
|
+
const CMD_CUBIC_TO = 4
|
|
364
|
+
|
|
365
|
+
export function geometryBlobToPath(
|
|
366
|
+
ck: CanvasKit,
|
|
367
|
+
blob: Uint8Array,
|
|
368
|
+
windingRule: WindingRule
|
|
369
|
+
): Path {
|
|
370
|
+
const path = new ck.Path()
|
|
371
|
+
if (!(blob.buffer instanceof ArrayBuffer)) return path
|
|
372
|
+
const dv = new DataView(blob.buffer, blob.byteOffset, blob.byteLength)
|
|
373
|
+
let o = 0
|
|
374
|
+
|
|
375
|
+
while (o < blob.length) {
|
|
376
|
+
const cmd = blob[o++]
|
|
377
|
+
switch (cmd) {
|
|
378
|
+
case CMD_CLOSE:
|
|
379
|
+
path.close()
|
|
380
|
+
break
|
|
381
|
+
case CMD_MOVE_TO: {
|
|
382
|
+
const x = dv.getFloat32(o, true)
|
|
383
|
+
const y = dv.getFloat32(o + 4, true)
|
|
384
|
+
o += 8
|
|
385
|
+
path.moveTo(x, y)
|
|
386
|
+
break
|
|
387
|
+
}
|
|
388
|
+
case CMD_LINE_TO: {
|
|
389
|
+
const x = dv.getFloat32(o, true)
|
|
390
|
+
const y = dv.getFloat32(o + 4, true)
|
|
391
|
+
o += 8
|
|
392
|
+
path.lineTo(x, y)
|
|
393
|
+
break
|
|
394
|
+
}
|
|
395
|
+
case CMD_CUBIC_TO: {
|
|
396
|
+
const x1 = dv.getFloat32(o, true)
|
|
397
|
+
const y1 = dv.getFloat32(o + 4, true)
|
|
398
|
+
const x2 = dv.getFloat32(o + 8, true)
|
|
399
|
+
const y2 = dv.getFloat32(o + 12, true)
|
|
400
|
+
const x = dv.getFloat32(o + 16, true)
|
|
401
|
+
const y = dv.getFloat32(o + 20, true)
|
|
402
|
+
o += 24
|
|
403
|
+
path.cubicTo(x1, y1, x2, y2, x, y)
|
|
404
|
+
break
|
|
405
|
+
}
|
|
406
|
+
default:
|
|
407
|
+
return path
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
path.setFillType(windingRule === 'EVENODD' ? ck.FillType.EvenOdd : ck.FillType.Winding)
|
|
412
|
+
return path
|
|
413
|
+
}
|
package/src/xpath.ts
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import type { IDomFacade } from 'fontoxpath'
|
|
2
|
+
import type { SceneGraph, SceneNode } from './scene-graph'
|
|
3
|
+
|
|
4
|
+
const NODE_TYPES = {
|
|
5
|
+
ELEMENT_NODE: 1,
|
|
6
|
+
ATTRIBUTE_NODE: 2,
|
|
7
|
+
TEXT_NODE: 3,
|
|
8
|
+
DOCUMENT_NODE: 9
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const QUERYABLE_ATTRS = [
|
|
12
|
+
'name',
|
|
13
|
+
'width',
|
|
14
|
+
'height',
|
|
15
|
+
'x',
|
|
16
|
+
'y',
|
|
17
|
+
'visible',
|
|
18
|
+
'opacity',
|
|
19
|
+
'cornerRadius',
|
|
20
|
+
'fontSize',
|
|
21
|
+
'fontFamily',
|
|
22
|
+
'fontWeight',
|
|
23
|
+
'layoutMode',
|
|
24
|
+
'itemSpacing',
|
|
25
|
+
'paddingTop',
|
|
26
|
+
'paddingBottom',
|
|
27
|
+
'paddingLeft',
|
|
28
|
+
'paddingRight',
|
|
29
|
+
'strokeWeight',
|
|
30
|
+
'rotation',
|
|
31
|
+
'locked',
|
|
32
|
+
'blendMode',
|
|
33
|
+
'text',
|
|
34
|
+
'lineHeight',
|
|
35
|
+
'letterSpacing'
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
interface XPathDocument {
|
|
39
|
+
nodeType: number
|
|
40
|
+
nodeName: string
|
|
41
|
+
documentElement: XPathNode
|
|
42
|
+
_children?: XPathNode[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface XPathAttr {
|
|
46
|
+
nodeType: number
|
|
47
|
+
nodeName: string
|
|
48
|
+
name: string
|
|
49
|
+
localName: string
|
|
50
|
+
namespaceURI: null
|
|
51
|
+
prefix: null
|
|
52
|
+
value: string
|
|
53
|
+
ownerElement: XPathNode
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface XPathNode {
|
|
57
|
+
nodeType: number
|
|
58
|
+
nodeName: string
|
|
59
|
+
localName: string
|
|
60
|
+
namespaceURI: null
|
|
61
|
+
prefix: null
|
|
62
|
+
_sceneNode: SceneNode
|
|
63
|
+
_attrs?: XPathAttr[]
|
|
64
|
+
_parent?: XPathNode | null
|
|
65
|
+
_children?: XPathNode[]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function wrapNode(
|
|
69
|
+
_graph: SceneGraph,
|
|
70
|
+
node: SceneNode,
|
|
71
|
+
parent?: XPathNode | XPathDocument | null
|
|
72
|
+
): XPathNode {
|
|
73
|
+
const wrapped: XPathNode = {
|
|
74
|
+
nodeType: NODE_TYPES.ELEMENT_NODE,
|
|
75
|
+
nodeName: node.type,
|
|
76
|
+
localName: node.type,
|
|
77
|
+
namespaceURI: null,
|
|
78
|
+
prefix: null,
|
|
79
|
+
_sceneNode: node,
|
|
80
|
+
_parent: parent as XPathNode | null
|
|
81
|
+
}
|
|
82
|
+
return wrapped
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function createDocument(graph: SceneGraph, rootNode: SceneNode): XPathDocument {
|
|
86
|
+
const doc: XPathDocument = {
|
|
87
|
+
nodeType: NODE_TYPES.DOCUMENT_NODE,
|
|
88
|
+
nodeName: '#document',
|
|
89
|
+
documentElement: null as unknown as XPathNode
|
|
90
|
+
}
|
|
91
|
+
const root = wrapNode(graph, rootNode, doc as unknown as XPathNode)
|
|
92
|
+
doc.documentElement = root
|
|
93
|
+
doc._children = [root]
|
|
94
|
+
return doc
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getAttrs(wrapped: XPathNode): XPathAttr[] {
|
|
98
|
+
if (wrapped._attrs) return wrapped._attrs
|
|
99
|
+
|
|
100
|
+
const node = wrapped._sceneNode
|
|
101
|
+
const attrs: XPathAttr[] = []
|
|
102
|
+
|
|
103
|
+
for (const attrName of QUERYABLE_ATTRS) {
|
|
104
|
+
if (attrName in node) {
|
|
105
|
+
const value = (node as unknown as Record<string, unknown>)[attrName]
|
|
106
|
+
if (value === undefined || value === null || typeof value === 'symbol') continue
|
|
107
|
+
const stringValue =
|
|
108
|
+
typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean)
|
|
109
|
+
attrs.push({
|
|
110
|
+
nodeType: NODE_TYPES.ATTRIBUTE_NODE,
|
|
111
|
+
nodeName: attrName,
|
|
112
|
+
name: attrName,
|
|
113
|
+
localName: attrName,
|
|
114
|
+
namespaceURI: null,
|
|
115
|
+
prefix: null,
|
|
116
|
+
value: stringValue,
|
|
117
|
+
ownerElement: wrapped
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
wrapped._attrs = attrs
|
|
123
|
+
return attrs
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function getChildren(graph: SceneGraph, wrapped: XPathNode): XPathNode[] {
|
|
127
|
+
if (wrapped._children) return wrapped._children
|
|
128
|
+
|
|
129
|
+
const node = wrapped._sceneNode
|
|
130
|
+
wrapped._children = node.childIds
|
|
131
|
+
.map((id) => graph.getNode(id))
|
|
132
|
+
.filter((n): n is SceneNode => n !== undefined)
|
|
133
|
+
.map((child) => wrapNode(graph, child, wrapped))
|
|
134
|
+
|
|
135
|
+
return wrapped._children
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function isDocument(node: unknown): node is XPathDocument {
|
|
139
|
+
return (node as XPathDocument).nodeType === NODE_TYPES.DOCUMENT_NODE
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function createDomFacade(graph: SceneGraph) {
|
|
143
|
+
return {
|
|
144
|
+
getAllAttributes(node: XPathNode | XPathDocument): XPathAttr[] {
|
|
145
|
+
if (isDocument(node)) return []
|
|
146
|
+
return getAttrs(node)
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
getAttribute(node: XPathNode | XPathDocument, attributeName: string): string | null {
|
|
150
|
+
if (isDocument(node)) return null
|
|
151
|
+
const sceneNode = node._sceneNode
|
|
152
|
+
if (attributeName in sceneNode) {
|
|
153
|
+
const value = (sceneNode as unknown as Record<string, unknown>)[attributeName]
|
|
154
|
+
if (value === undefined || value === null || typeof value === 'symbol') return null
|
|
155
|
+
return typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean)
|
|
156
|
+
}
|
|
157
|
+
return null
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
getChildNodes(node: XPathNode | XPathDocument): XPathNode[] {
|
|
161
|
+
if (isDocument(node)) return node._children ?? []
|
|
162
|
+
return getChildren(graph, node)
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
getData(node: XPathAttr): string {
|
|
166
|
+
return node.value
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
getFirstChild(node: XPathNode | XPathDocument): XPathNode | null {
|
|
170
|
+
if (isDocument(node)) return node.documentElement
|
|
171
|
+
const children = getChildren(graph, node)
|
|
172
|
+
return children[0] ?? null
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
getLastChild(node: XPathNode | XPathDocument): XPathNode | null {
|
|
176
|
+
if (isDocument(node)) return node.documentElement
|
|
177
|
+
const children = getChildren(graph, node)
|
|
178
|
+
return children[children.length - 1] ?? null
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
getNextSibling(node: XPathNode | XPathDocument): XPathNode | null {
|
|
182
|
+
if (isDocument(node)) return null
|
|
183
|
+
const parent = node._parent
|
|
184
|
+
if (!parent) return null
|
|
185
|
+
const siblings = getChildren(graph, parent)
|
|
186
|
+
const idx = siblings.indexOf(node)
|
|
187
|
+
return siblings[idx + 1] ?? null
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
getParentNode(node: XPathNode | XPathDocument): XPathNode | XPathDocument | null {
|
|
191
|
+
if (isDocument(node)) return null
|
|
192
|
+
return node._parent ?? null
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
getPreviousSibling(node: XPathNode | XPathDocument): XPathNode | null {
|
|
196
|
+
if (isDocument(node)) return null
|
|
197
|
+
const parent = node._parent
|
|
198
|
+
if (!parent) return null
|
|
199
|
+
const siblings = getChildren(graph, parent)
|
|
200
|
+
const idx = siblings.indexOf(node)
|
|
201
|
+
return idx > 0 ? siblings[idx - 1] : null
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface XPathQueryOptions {
|
|
207
|
+
limit?: number
|
|
208
|
+
page?: string
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export async function queryByXPath(
|
|
212
|
+
graph: SceneGraph,
|
|
213
|
+
selector: string,
|
|
214
|
+
options: XPathQueryOptions = {}
|
|
215
|
+
): Promise<SceneNode[]> {
|
|
216
|
+
const { limit = 1000 } = options
|
|
217
|
+
const pages = graph.getPages()
|
|
218
|
+
const targetPages = options.page
|
|
219
|
+
? pages.filter((p) => p.name === options.page)
|
|
220
|
+
: pages
|
|
221
|
+
|
|
222
|
+
if (targetPages.length === 0) return []
|
|
223
|
+
|
|
224
|
+
const { evaluateXPathToNodes } = await import('fontoxpath')
|
|
225
|
+
const domFacade = createDomFacade(graph) as unknown as IDomFacade
|
|
226
|
+
const results: SceneNode[] = []
|
|
227
|
+
|
|
228
|
+
for (const page of targetPages) {
|
|
229
|
+
const doc = createDocument(graph, page)
|
|
230
|
+
const nodes = evaluateXPathToNodes(selector, doc, domFacade)
|
|
231
|
+
|
|
232
|
+
for (const node of nodes) {
|
|
233
|
+
if (results.length >= limit) break
|
|
234
|
+
const sceneNode = (node as XPathNode)._sceneNode
|
|
235
|
+
if (sceneNode.type !== 'CANVAS') {
|
|
236
|
+
results.push(sceneNode)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (results.length >= limit) break
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return results
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export async function matchByXPath(
|
|
247
|
+
graph: SceneGraph,
|
|
248
|
+
selector: string,
|
|
249
|
+
node: SceneNode
|
|
250
|
+
): Promise<boolean> {
|
|
251
|
+
const { evaluateXPathToBoolean } = await import('fontoxpath')
|
|
252
|
+
const domFacade = createDomFacade(graph) as unknown as IDomFacade
|
|
253
|
+
const wrapped = wrapNode(graph, node)
|
|
254
|
+
try {
|
|
255
|
+
return evaluateXPathToBoolean(`self::*[${selector}]`, wrapped, domFacade)
|
|
256
|
+
} catch {
|
|
257
|
+
return false
|
|
258
|
+
}
|
|
259
|
+
}
|