feat: make node definitions type safe with zod

This commit is contained in:
max_richter 2024-04-22 00:33:04 +02:00
parent 4c7c4cac2c
commit ad197db873
28 changed files with 221 additions and 147 deletions

View File

@ -6,6 +6,7 @@
<link rel="icon" href="%sveltekit.assets%/svelte.svg" /> <link rel="icon" href="%sveltekit.assets%/svelte.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head% %sveltekit.head%
<title>Nodes</title>
<script> <script>
var store = localStorage.getItem("node-settings"); var store = localStorage.getItem("node-settings");
if (store) { if (store) {

View File

@ -11,7 +11,7 @@
let value: string = ""; let value: string = "";
let activeNodeId: string = ""; let activeNodeId: string = "";
const allNodes = graph.getNodeTypes(); const allNodes = graph.getNodeDefinitions();
function filterNodes() { function filterNodes() {
return allNodes.filter((node) => node.id.includes(value)); return allNodes.filter((node) => node.id.includes(value));

View File

@ -51,7 +51,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
} }
this.inputSockets.set(s); this.inputSockets.set(s);
}); });
this.execute = throttle(() => this._execute(), 50); this.execute = throttle(() => this._execute(), 10);
} }
serialize(): Graph { serialize(): Graph {
@ -83,7 +83,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
this.emit("result", this.serialize()); this.emit("result", this.serialize());
} }
getNodeTypes() { getNodeDefinitions() {
return this.registry.getAllNodes(); return this.registry.getAllNodes();
} }
@ -184,7 +184,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any, "
// load settings // load settings
const settingTypes: Record<string, NodeInput> = {}; const settingTypes: Record<string, NodeInput> = {};
const settingValues = graph.settings || {}; const settingValues = graph.settings || {};
const types = this.getNodeTypes(); const types = this.getNodeDefinitions();
for (const type of types) { for (const type of types) {
if (type.inputs) { if (type.inputs) {
for (const key in type.inputs) { for (const key in type.inputs) {

View File

@ -8,6 +8,7 @@
import Camera from "../Camera.svelte"; import Camera from "../Camera.svelte";
import GraphView from "./GraphView.svelte"; import GraphView from "./GraphView.svelte";
import type { Node, Node as NodeType, Socket } from "@nodes/types"; import type { Node, Node as NodeType, Socket } from "@nodes/types";
import { NodeDefinitionSchema } from "@nodes/types";
import FloatingEdge from "../edges/FloatingEdge.svelte"; import FloatingEdge from "../edges/FloatingEdge.svelte";
import { import {
activeNodeId, activeNodeId,
@ -20,7 +21,7 @@
import { createKeyMap } from "../../helpers/createKeyMap"; import { createKeyMap } from "../../helpers/createKeyMap";
import BoxSelection from "../BoxSelection.svelte"; import BoxSelection from "../BoxSelection.svelte";
import AddMenu from "../AddMenu.svelte"; import AddMenu from "../AddMenu.svelte";
import { get } from "svelte/store"; import { createWasmWrapper } from "@nodes/utils";
export let graph: GraphManager; export let graph: GraphManager;
@ -759,9 +760,15 @@
addMenuPosition = null; addMenuPosition = null;
} }
let isDragging = false;
function handleDrop(event: DragEvent) { function handleDrop(event: DragEvent) {
event.preventDefault();
isDragging = false;
if (!event.dataTransfer) return; if (!event.dataTransfer) return;
const nodeId = event.dataTransfer.getData("data/node-id"); const nodeId = event.dataTransfer.getData("data/node-id");
if (nodeId) {
let mx = event.clientX - rect.x; let mx = event.clientX - rect.x;
let my = event.clientY - rect.y; let my = event.clientY - rect.y;
@ -780,9 +787,36 @@
position: pos, position: pos,
}); });
}); });
} else if (event.dataTransfer.files.length) {
const files = event.dataTransfer.files;
const reader = new FileReader();
reader.onload = (e) => {
const buffer = e.target?.result;
if (buffer) {
const wrapper = createWasmWrapper(buffer);
const definition = wrapper.get_definition();
const res = NodeDefinitionSchema.parse(definition);
console.log(wrapper, res);
}
};
reader.readAsArrayBuffer(files[0]);
console.log({ files });
}
}
function handleDragEnter(e: DragEvent) {
e.preventDefault();
isDragging = true;
console.log(e);
} }
function handlerDragOver(e: DragEvent) { function handlerDragOver(e: DragEvent) {
isDragging = true;
e.preventDefault();
}
function handleDragEnd(e: DragEvent) {
isDragging = false;
e.preventDefault(); e.preventDefault();
} }
@ -807,11 +841,20 @@
tabindex="0" tabindex="0"
bind:clientWidth={width} bind:clientWidth={width}
bind:clientHeight={height} bind:clientHeight={height}
on:dragenter={handleDragEnter}
on:dragover={handlerDragOver} on:dragover={handlerDragOver}
on:drop={handleDrop} on:drop={handleDrop}
on:keydown={keymap.handleKeyboardEvent} on:keydown={keymap.handleKeyboardEvent}
on:mousedown={handleMouseDown} on:mousedown={handleMouseDown}
> >
<input
type="file"
accept="application/wasm"
disabled={!isDragging}
on:dragend={handleDragEnd}
on:dragleave={handleDragEnd}
/>
<Canvas shadows={false} renderMode="on-demand" colorManagementEnabled={false}> <Canvas shadows={false} renderMode="on-demand" colorManagementEnabled={false}>
<Camera bind:camera position={cameraPosition} /> <Camera bind:camera position={cameraPosition} />
@ -856,4 +899,15 @@
transition: opacity 0.3s ease; transition: opacity 0.3s ease;
height: 100%; height: 100%;
} }
input {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
background: red;
opacity: 0.5;
}
input:disabled {
display: none;
}
</style> </style>

View File

@ -1,4 +1,4 @@
import type { NodeRegistry, NodeType } from "@nodes/types"; import type { NodeRegistry, NodeDefinition } from "@nodes/types";
import { createWasmWrapper } from "@nodes/utils"; import { createWasmWrapper } from "@nodes/utils";
import { createLogger } from "./helpers"; import { createLogger } from "./helpers";
@ -6,18 +6,14 @@ const log = createLogger("node-registry");
export class RemoteNodeRegistry implements NodeRegistry { export class RemoteNodeRegistry implements NodeRegistry {
status: "loading" | "ready" | "error" = "loading"; status: "loading" | "ready" | "error" = "loading";
private nodes: Map<string, NodeType> = new Map(); private nodes: Map<string, NodeDefinition> = new Map();
constructor(private url: string) { } constructor(private url: string) { }
async loadNode(id: `${string}/${string}/${string}`) { async loadNode(id: `${string}/${string}/${string}`) {
const wasmResponse = await this.fetchNode(id); const wasmResponse = await this.fetchNode(id);
// Setup Wasm wrapper const wrapper = createWasmWrapper(wasmResponse);
const wrapper = createWasmWrapper();
const module = new WebAssembly.Module(wasmResponse);
const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper });
wrapper.setInstance(instance);
const definition = wrapper.get_definition(); const definition = wrapper.get_definition();

View File

@ -13,9 +13,7 @@ export async function getWasm(id: `${string}/${string}/${string}`) {
const file = await fs.readFile(filePath); const file = await fs.readFile(filePath);
const bytes = new Uint8Array(file); return new Uint8Array(file);
return bytes;
} }
@ -24,10 +22,7 @@ export async function getNodeWasm(id: `${string}/${string}/${string}`) {
const wasmBytes = await getWasm(id); const wasmBytes = await getWasm(id);
if (!wasmBytes) return null; if (!wasmBytes) return null;
const wrapper = createWasmWrapper(); const wrapper = createWasmWrapper(wasmBytes);
const module = new WebAssembly.Module(wasmBytes);
const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper });
wrapper.setInstance(instance)
return wrapper; return wrapper;
} }

View File

@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import NodeHtml from "$lib/graph-interface/node/NodeHTML.svelte"; import NodeHtml from "$lib/graph-interface/node/NodeHTML.svelte";
import type { NodeType } from "@nodes/types"; import type { NodeDefinitions } from "@nodes/types";
export let node: NodeType; export let node: NodeDefinitions;
let dragging = false; let dragging = false;

View File

@ -1,19 +1,10 @@
<script lang="ts"> <script lang="ts">
import type { GraphManager } from "$lib/graph-interface/graph-manager";
import Node from "$lib/graph-interface/node/Node.svelte";
import localStore from "$lib/helpers/localStore"; import localStore from "$lib/helpers/localStore";
import type { RemoteNodeRegistry } from "$lib/node-registry-client"; import type { RemoteNodeRegistry } from "$lib/node-registry-client";
import { Canvas } from "@threlte/core";
import BreadCrumbs from "./BreadCrumbs.svelte"; import BreadCrumbs from "./BreadCrumbs.svelte";
import NodeHtml from "$lib/graph-interface/node/NodeHTML.svelte";
import DraggableNode from "./DraggableNode.svelte"; import DraggableNode from "./DraggableNode.svelte";
export let nodeRegistry: RemoteNodeRegistry; export let nodeRegistry: RemoteNodeRegistry;
export let manager: GraphManager;
function handleImport() {
nodeRegistry.load([$activeId]);
}
const activeId = localStore< const activeId = localStore<
`${string}` | `${string}/${string}` | `${string}/${string}/${string}` `${string}` | `${string}/${string}` | `${string}/${string}/${string}`

View File

@ -1,21 +1,21 @@
import type { Graph, NodeRegistry, NodeType, RuntimeExecutor } from "@nodes/types"; import type { Graph, NodeRegistry, NodeDefinition, RuntimeExecutor } from "@nodes/types";
import { fastHash, concat_encoded, encodeFloat, encode } from "@nodes/utils" import { fastHash, concat_encoded, encodeFloat, encode } from "@nodes/utils"
export class MemoryRuntimeExecutor implements RuntimeExecutor { export class MemoryRuntimeExecutor implements RuntimeExecutor {
private typeMap: Map<string, NodeType> = new Map(); private definitionMap: Map<string, NodeDefinition> = new Map();
private cache: Record<string, { eol: number, value: any }> = {}; private cache: Record<string, { eol: number, value: any }> = {};
constructor(private registry: NodeRegistry) { } constructor(private registry: NodeRegistry) { }
private getNodeTypes(graph: Graph) { private getNodeDefinitions(graph: Graph) {
if (this.registry.status !== "ready") { if (this.registry.status !== "ready") {
throw new Error("Node registry is not ready"); throw new Error("Node registry is not ready");
} }
const typeMap = new Map<string, NodeType>(); const typeMap = new Map<string, NodeDefinition>();
for (const node of graph.nodes) { for (const node of graph.nodes) {
if (!typeMap.has(node.type)) { if (!typeMap.has(node.type)) {
const type = this.registry.getNode(node.type); const type = this.registry.getNode(node.type);
@ -29,8 +29,8 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
private addMetaData(graph: Graph) { private addMetaData(graph: Graph) {
// First, lets check if all nodes have a type // First, lets check if all nodes have a definition
this.typeMap = this.getNodeTypes(graph); this.definitionMap = this.getNodeDefinitions(graph);
const outputNode = graph.nodes.find(node => node.type.endsWith("/output")); const outputNode = graph.nodes.find(node => node.type.endsWith("/output"));
if (!outputNode) { if (!outputNode) {
@ -115,7 +115,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
for (const node of sortedNodes) { for (const node of sortedNodes) {
const node_type = this.typeMap.get(node.type)!; const node_type = this.definitionMap.get(node.type)!;
if (node?.tmp && node_type?.execute) { if (node?.tmp && node_type?.execute) {
const inputs: Record<string, string | number | boolean> = {}; const inputs: Record<string, string | number | boolean> = {};

View File

@ -105,6 +105,7 @@
top: 0px; top: 0px;
position: absolute; position: absolute;
display: grid; display: grid;
z-index: 2;
grid-template-columns: 30px 1fr; grid-template-columns: 30px 1fr;
height: 100%; height: 100%;
right: 0px; right: 0px;

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/array",
"outputs": [ "outputs": [
"float" "float"
], ],

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/box",
"outputs": [ "outputs": [
"model" "model"
], ],

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/float",
"outputs": [ "outputs": [
"float" "float"
], ],

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/math",
"outputs": [ "outputs": [
"float" "float"
], ],

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/output",
"outputs": [], "outputs": [],
"inputs": { "inputs": {
"input": { "input": {

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/random",
"outputs": [ "outputs": [
"float" "float"
], ],

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/stem",
"outputs": [ "outputs": [
"plant" "plant"
], ],

View File

@ -31,9 +31,9 @@ pub fn execute(input: &[i32]) -> Vec<i32> {
for i in 0..res_curve { for i in 0..res_curve {
let a = i as f32 / (res_curve - 1) as f32; let a = i as f32 / (res_curve - 1) as f32;
path_p[i * 4] = origin[0] + (a * 8.0).sin() * 0.2; path_p[i * 4] = origin[0];
path_p[i * 4 + 1] = origin[1] + a * length; path_p[i * 4 + 1] = origin[1] + a * length;
path_p[i * 4 + 2] = origin[2] + ((a + 2.0) * 8.0).sin() * 0.2; path_p[i * 4 + 2] = origin[2];
path_p[i * 4 + 3] = thickness * (1.0 - a); path_p[i * 4 + 3] = thickness * (1.0 - a);
} }

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/sum",
"outputs": [ "outputs": [
"float" "float"
], ],

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/triangle",
"outputs": [ "outputs": [
"model" "model"
], ],

View File

@ -1,5 +1,5 @@
use macros::include_definition_file; use macros::include_definition_file;
use utils::{decode_float, encode_float, evaluate_arg, evaluate_float, get_args, wrap_arg}; use utils::{decode_float, encode_float, evaluate_arg, get_args, wrap_arg};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use web_sys::console; use web_sys::console;

View File

@ -1,4 +1,5 @@
{ {
"id": "max/plantarium/vec3",
"outputs": [ "outputs": [
"vec3" "vec3"
], ],

View File

@ -5,14 +5,14 @@ use std::env;
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use syn::{parse_macro_input, LitStr}; use syn::{parse_macro_input, LitStr};
use types::NodeType; use types::NodeDefinition;
#[proc_macro] #[proc_macro]
pub fn define_node(input: TokenStream) -> TokenStream { pub fn node_definition(input: TokenStream) -> TokenStream {
let input_string = parse_macro_input!(input as LitStr).value(); let input_string = parse_macro_input!(input as LitStr).value();
// Validate JSON format // Validate JSON format
let json: NodeType = match serde_json::from_str(&input_string) { let json: NodeDefinition = match serde_json::from_str(&input_string) {
Ok(json) => json, Ok(json) => json,
Err(e) => panic!("Invalid JSON input: {}", e), Err(e) => panic!("Invalid JSON input: {}", e),
}; };
@ -49,7 +49,7 @@ pub fn include_definition_file(input: TokenStream) -> TokenStream {
}); });
// Optionally, validate that the content is valid JSON // Optionally, validate that the content is valid JSON
let _: NodeType = serde_json::from_str(&json_content) let _: NodeDefinition = serde_json::from_str(&json_content)
.unwrap_or_else(|err| panic!("JSON file contains invalid JSON: {}", err)); .unwrap_or_else(|err| panic!("JSON file contains invalid JSON: {}", err));
// Generate the function that returns the JSON string // Generate the function that returns the JSON string

View File

@ -1,4 +1,5 @@
import type { NodeInput } from "./inputs"; import { z } from "zod";
import { NodeInputSchema } from "./inputs";
export type { NodeInput } from "./inputs"; export type { NodeInput } from "./inputs";
export type Node = { export type Node = {
@ -12,7 +13,7 @@ export type Node = {
parents?: Node[], parents?: Node[],
children?: Node[], children?: Node[],
inputNodes?: Record<string, Node> inputNodes?: Record<string, Node>
type?: NodeType; type?: NodeDefinition;
downX?: number; downX?: number;
downY?: number; downY?: number;
x?: number; x?: number;
@ -28,15 +29,19 @@ export type Node = {
position: [x: number, y: number] position: [x: number, y: number]
} }
export type NodeType = { export const NodeDefinitionSchema = z.object({
id: string; id: z.string(),
inputs?: Record<string, NodeInput> inputs: z.record(NodeInputSchema).optional(),
outputs?: string[]; outputs: z.array(z.string()).optional(),
meta?: { meta: z.object({
title?: string; description: z.string().optional(),
}, title: z.string().optional(),
execute?: (args: Int32Array) => Int32Array; }).optional(),
} });
export type NodeDefinition = z.infer<typeof NodeDefinitionSchema> & {
execute(input: Int32Array): Int32Array;
};
export type Socket = { export type Socket = {
node: Node; node: Node;
@ -63,12 +68,12 @@ export interface NodeRegistry {
* @param id - The id of the node to get * @param id - The id of the node to get
* @returns The node with the given id, or undefined if no such node exists * @returns The node with the given id, or undefined if no such node exists
*/ */
getNode: (id: string) => NodeType | undefined; getNode: (id: string) => NodeDefinition | undefined;
/** /**
* Get all nodes * Get all nodes
* @returns An array of all nodes * @returns An array of all nodes
*/ */
getAllNodes: () => NodeType[]; getAllNodes: () => NodeDefinition[];
} }
export interface RuntimeExecutor { export interface RuntimeExecutor {

View File

@ -1,65 +1,78 @@
type NodeInputFloat = { import { z } from "zod";
type: "float";
element?: "slider";
value?: number;
min?: number;
max?: number;
step?: number;
}
type NodeInputInteger = { const DefaultOptionsSchema = z.object({
type: "integer"; internal: z.boolean().optional(),
element?: "slider"; external: z.boolean().optional(),
value?: number; setting: z.string().optional(),
min?: number; label: z.string().optional(),
max?: number; description: z.string().optional(),
} accepts: z.array(z.string()).optional(),
});
type NodeInputBoolean = {
type: "boolean";
value?: boolean;
}
type NodeInputSelect = {
type: "select";
options: string[];
value?: number;
}
type NodeInputSeed = {
type: "seed"
value?: number;
}
type NodeInputVec3 = {
type: "vec3";
value?: number[];
}
type NodeInputModel = {
type: "model";
}
type NodeInputPlant = {
type: "plant"
}
type InputTypes = (NodeInputSeed | NodeInputBoolean | NodeInputFloat | NodeInputInteger | NodeInputSelect | NodeInputSeed | NodeInputVec3 | NodeInputModel | NodeInputPlant);
type InputId = InputTypes["type"];
type DefaultOptions = {
internal?: boolean;
external?: boolean;
setting?: string;
label?: string | false;
}
export type NodeInput = InputTypes & {
type: InputId | InputId[];
} & DefaultOptions;
export type NodeInputType<T extends Record<string, NodeInput>> = { export const NodeInputFloatSchema = z.object({
[K in keyof T]: T[K]["value"] ...DefaultOptionsSchema.shape,
}; type: z.literal("float"),
element: z.literal("slider").optional(),
value: z.number().optional(),
min: z.number().optional(),
max: z.number().optional(),
step: z.number().optional(),
});
export const NodeInputIntegerSchema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal("integer"),
element: z.literal("slider").optional(),
value: z.number().optional(),
min: z.number().optional(),
max: z.number().optional(),
});
export const NodeInputBooleanSchema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal("boolean"),
vale: z.boolean().optional(),
});
export const NodeInputSelectSchema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal("select"),
value: z.number().optional(),
});
export const NodeInputSeedSchema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal("seed"),
value: z.number().optional(),
});
export const NodeInputVec3Schema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal("vec3"),
value: z.array(z.number()).optional(),
});
export const NodeInputModelSchema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal("model"),
});
export const NodeInputPlantSchema = z.object({
...DefaultOptionsSchema.shape,
type: z.literal("plant"),
});
export const NodeInputSchema = z.union([
NodeInputSeedSchema,
NodeInputBooleanSchema,
NodeInputFloatSchema,
NodeInputIntegerSchema,
NodeInputSelectSchema,
NodeInputSeedSchema,
NodeInputVec3Schema,
NodeInputModelSchema,
NodeInputPlantSchema
]);
export type NodeInput = z.infer<typeof InputSchema>;

View File

@ -90,7 +90,7 @@ pub struct DefaultOptions {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)] #[serde(untagged)]
pub enum NodeTypeOrArray { pub enum NodeDefinitionOrArray {
Single(InputTypes), Single(InputTypes),
Multiple(Vec<String>), Multiple(Vec<String>),
} }
@ -124,10 +124,10 @@ impl<'de> Deserialize<'de> for NodeInput {
} }
#[derive(Deserialize, Debug, Serialize)] #[derive(Deserialize, Debug, Serialize)]
pub struct NodeType { pub struct NodeDefinition {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub inputs: Option<HashMap<String, NodeInput>>, pub inputs: Option<HashMap<String, NodeInput>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub outputs: Option<Vec<String>>, pub outputs: Option<Vec<String>>,
} }

View File

@ -1,4 +1,4 @@
use crate::{decode_float, log}; use crate::decode_float;
pub fn get_args(args: &[i32]) -> Vec<&[i32]> { pub fn get_args(args: &[i32]) -> Vec<&[i32]> {
let mut idx: usize = 0; let mut idx: usize = 0;

View File

@ -1,4 +1,4 @@
import { NodeType } from "@nodes/types"; import { NodeDefinition } from "@nodes/types";
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
const cachedTextEncoder = new TextEncoder(); const cachedTextEncoder = new TextEncoder();
@ -17,12 +17,9 @@ const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
}; };
}); });
export function createWasmWrapper() { function createWrapper() {
let wasm: any; let wasm: any;
let cachedUint8Memory0: Uint8Array | null = null; let cachedUint8Memory0: Uint8Array | null = null;
let cachedInt32Memory0: Int32Array | null = null; let cachedInt32Memory0: Int32Array | null = null;
let cachedUint32Memory0: Uint32Array | null = null; let cachedUint32Memory0: Uint32Array | null = null;
@ -120,7 +117,7 @@ export function createWasmWrapper() {
deferred1_0 = r0; deferred1_0 = r0;
deferred1_1 = r1; deferred1_1 = r1;
const string = getStringFromWasm0(r0, r1); const string = getStringFromWasm0(r0, r1);
return JSON.parse(string) as Omit<NodeType, "id">; return JSON.parse(string) as NodeDefinition;
} finally { } finally {
wasm.__wbindgen_add_to_stack_pointer(16); wasm.__wbindgen_add_to_stack_pointer(16);
wasm.__wbindgen_free(deferred1_0, deferred1_1, 1); wasm.__wbindgen_free(deferred1_0, deferred1_1, 1);
@ -226,9 +223,12 @@ export function createWasmWrapper() {
wasm = instance.exports; wasm = instance.exports;
}, },
exports: {
// Expose other methods that interact with the wasm instance // Expose other methods that interact with the wasm instance
execute, execute,
get_definition, get_definition,
},
__wbindgen_string_new, __wbindgen_string_new,
__wbindgen_object_drop_ref, __wbindgen_object_drop_ref,
@ -240,3 +240,11 @@ export function createWasmWrapper() {
}; };
} }
export function createWasmWrapper(wasmBuffer: ArrayBuffer) {
const wrapper = createWrapper();
const module = new WebAssembly.Module(wasmBuffer);
const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper });
wrapper.setInstance(instance);
return wrapper.exports;
}