@dxos/app-graph 0.3.4-main.e2d9be5 → 0.3.4-next.1e21f62
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/lib/browser/index.mjs +3 -3
- package/dist/lib/browser/index.mjs.map +2 -2
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +3 -3
- package/dist/lib/node/index.cjs.map +2 -2
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/action.d.ts +4 -1
- package/dist/types/src/action.d.ts.map +1 -1
- package/dist/types/src/graph-builder.d.ts +1 -1
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/node.d.ts +6 -3
- package/dist/types/src/node.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/action.ts +7 -1
- package/src/graph-builder.ts +13 -7
- package/src/node.ts +9 -3
|
@@ -133,7 +133,6 @@ var GraphBuilder = class {
|
|
|
133
133
|
actionsMap: {},
|
|
134
134
|
// TODO(burdon): Document.
|
|
135
135
|
...partial,
|
|
136
|
-
// TODO(wittjosiah): Default sort.
|
|
137
136
|
get children() {
|
|
138
137
|
return Object.values(node.childrenMap);
|
|
139
138
|
},
|
|
@@ -204,14 +203,14 @@ var GraphBuilder = class {
|
|
|
204
203
|
});
|
|
205
204
|
}
|
|
206
205
|
});
|
|
206
|
+
partial.actions && partial.actions.forEach((action) => node.addAction(action));
|
|
207
207
|
return node;
|
|
208
208
|
}
|
|
209
209
|
_createAction(partial) {
|
|
210
210
|
const action = deepSignal2({
|
|
211
211
|
properties: {},
|
|
212
|
-
actionsMap: {},
|
|
213
212
|
...partial,
|
|
214
|
-
|
|
213
|
+
actionsMap: {},
|
|
215
214
|
get actions() {
|
|
216
215
|
return Object.values(action.actionsMap);
|
|
217
216
|
},
|
|
@@ -242,6 +241,7 @@ var GraphBuilder = class {
|
|
|
242
241
|
});
|
|
243
242
|
}
|
|
244
243
|
});
|
|
244
|
+
partial.actions && partial.actions.forEach((subAction) => action.addAction(subAction));
|
|
245
245
|
return action;
|
|
246
246
|
}
|
|
247
247
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/graph.ts", "../../../src/graph-builder.ts", "../../../src/node.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { deepSignal } from 'deepsignal/react';\n// TODO(wittjosiah): Remove lodash dependency.\nimport get from 'lodash.get';\n\nimport { type Label } from './action';\nimport { type Node } from './node';\n\nexport type TraversalOptions = {\n /**\n * The node to start traversing from. Defaults to the root node.\n */\n node?: Node;\n\n /**\n * The direction to traverse the graph. Defaults to 'down'.\n */\n direction?: 'up' | 'down';\n\n /**\n * A predicate to filter nodes which are passed to the `visitor` callback.\n */\n filter?: (node: Node) => boolean;\n\n /**\n * A callback which is called for each node visited during traversal.\n */\n visitor?: (node: Node) => void;\n};\n\n/**\n * The Graph represents...\n */\nexport class Graph {\n // TODO(burdon): Document.\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n private readonly _index = deepSignal<{ [key: string]: string[] }>({});\n\n constructor(private readonly _root: Node) {}\n\n toJSON() {\n const toLabel = (label: Label) => (Array.isArray(label) ? `${label[1].ns}[${label[0]}]` : label);\n const toJSON = (node: Node): any => {\n return {\n id: node.id.slice(0, 16),\n label: toLabel(node.label),\n children: node.children.length ? node.children.map((node) => toJSON(node)) : undefined,\n actions: node.actions.length\n ? node.actions.map(({ id, label }) => ({\n id,\n label: toLabel(label),\n }))\n : undefined,\n };\n };\n\n return toJSON(this._root);\n }\n\n /**\n * The root node of the graph which is the entry point for all knowledge.\n */\n get root(): Node {\n return this._root;\n }\n\n /**\n * Get the path through the graph from the root to the node with the given id.\n */\n getPath(id: string): string[] | undefined {\n return this._index[id];\n }\n\n /**\n * @internal\n */\n _setPath(id: string, path: string[]) {\n this._index[id] = path;\n }\n\n /**\n * Find the node with the given id in the graph.\n */\n findNode(id: string): Node | undefined {\n const path = this.getPath(id);\n if (!path) {\n return undefined;\n }\n\n return path.length > 0 ? get(this._root, path) : this._root;\n }\n\n /**\n * Recursive breadth-first traversal.\n */\n traverse({ node = this._root, direction = 'down', filter, visitor }: TraversalOptions, depth = 0): void {\n if (!filter || filter(node)) {\n visitor?.(node);\n }\n\n if (direction === 'down') {\n Object.values(node.children).forEach((child) => this.traverse({ node: child, filter, visitor }));\n } else if (direction === 'up' && node.parent) {\n this.traverse({ node: node.parent, direction, filter, visitor }, depth + 1);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { untracked } from '@preact/signals-react';\nimport { type RevertDeepSignal, deepSignal } from 'deepsignal/react';\nimport Mousetrap from 'mousetrap';\n\nimport { EventSubscriptions } from '@dxos/async';\n\nimport { type Action } from './action';\nimport { Graph } from './graph';\nimport { type Node, type NodeBuilder } from './node';\n\n/**\n * The builder...\n */\nexport class GraphBuilder {\n private readonly _nodeBuilders = new Map<string, NodeBuilder>();\n private readonly _unsubscribe = new Map<string, EventSubscriptions>();\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addNodeBuilder(id: string, builder: NodeBuilder): GraphBuilder {\n this._nodeBuilders.set(id, builder);\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeNodeBuilder(id: string): GraphBuilder {\n this._nodeBuilders.delete(id);\n return this;\n }\n\n /**\n * Construct the graph, starting by calling all registered node builders on the root node.\n * Node builders will be filtered out as they are used such that they are only used once on any given path.\n * @param previousGraph If provided, the graph will be updated in place.\n * @param startingPath If provided, the graph will be updated starting at the given path.\n */\n build(previousGraph?: Graph, startingPath: string[] = []): Graph {\n const graph: Graph = previousGraph ?? new Graph(this._createNode(() => graph, { id: 'root', label: 'Root' }));\n return this._build(graph, graph.root, startingPath);\n }\n\n /**\n * Called recursively.\n */\n private _build(graph: Graph, node: Node, path: string[] = [], ignoreBuilders: string[] = []): Graph {\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n graph._setPath(node.id, path);\n\n // TODO(burdon): Document.\n const subscriptions = this._unsubscribe.get(node.id) ?? new EventSubscriptions();\n subscriptions.clear();\n\n Array.from(this._nodeBuilders.entries())\n .filter(([id]) => ignoreBuilders.findIndex((ignore) => ignore === id) === -1)\n .forEach(([_, builder]) => {\n const unsubscribe = builder(node);\n unsubscribe && subscriptions.add(unsubscribe);\n });\n\n this._unsubscribe.set(node.id, subscriptions);\n\n return graph;\n }\n\n private _createNode<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n getGraph: () => Graph,\n partial: Pick<Node, 'id' | 'label'> & Partial<Node<TData, TProperties>>,\n path: string[] = [],\n ignoreBuilders: string[] = [],\n ): Node<TData, TProperties> {\n // TODO(burdon): Document implications and rationale of deepSignal.\n const node: Node<TData, TProperties> = deepSignal({\n parent: null,\n data: null as TData, // TODO(burdon): Allow null property?\n properties: {} as TProperties,\n childrenMap: {},\n actionsMap: {},\n // TODO(burdon): Document.\n ...partial,\n\n // TODO(wittjosiah): Default sort.\n get children() {\n return Object.values(node.childrenMap);\n },\n get actions() {\n return Object.values(node.actionsMap);\n },\n\n addProperty: (key, value) => {\n untracked(() => {\n (node.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n untracked(() => {\n delete (node.properties as Record<string, any>)[key];\n });\n },\n\n addNode: (builder, ...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const builders = [...ignoreBuilders, builder];\n const childPath = [...path, 'childrenMap', partial.id];\n const child = this._createNode(getGraph, { ...partial, parent: node }, childPath, builders);\n node.childrenMap[child.id] = child;\n // TOOD(burdon): Defer triggering recursive updates until task has completed.\n this._build(getGraph(), child, childPath, builders);\n return child;\n });\n });\n },\n removeNode: (id) => {\n return untracked(() => {\n const child = node.childrenMap[id];\n delete node.childrenMap[id];\n return child;\n });\n },\n\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const action = this._createAction(partial);\n if (action.keyBinding) {\n Mousetrap.bind(action.keyBinding, () => {\n action.invoke();\n });\n }\n\n node.actionsMap[action.id] = action;\n return action;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const action = node.actionsMap[id];\n if (action.keyBinding) {\n Mousetrap.unbind(action.keyBinding);\n }\n\n delete node.actionsMap[id];\n return action;\n });\n },\n }) as RevertDeepSignal<Node<TData, TProperties>>;\n\n return node;\n }\n\n private _createAction<TProperties extends Record<string, any> = Record<string, any>>(\n partial: Pick<Action, 'id' | 'label' | 'invoke'> & Partial<Action<TProperties>>,\n ): Action<TProperties> {\n const action: Action<TProperties> = deepSignal({\n properties: {} as TProperties,\n actionsMap: {},\n ...partial,\n // TODO(wittjosiah): Default sort.\n get actions() {\n return Object.values(action.actionsMap);\n },\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const subAction = this._createAction(partial);\n action.actionsMap[subAction.id] = subAction;\n return subAction;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const subAction = action.actionsMap[id];\n delete action.actionsMap[id];\n return subAction;\n });\n },\n addProperty: (key, value) => {\n return untracked(() => {\n (action.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n return untracked(() => {\n delete (action.properties as Record<string, any>)[key];\n });\n },\n }) as RevertDeepSignal<Action<TProperties>>;\n\n return action;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport type { IconProps } from '@phosphor-icons/react';\nimport { type FC } from 'react';\n\nimport type { UnsubscribeCallback } from '@dxos/async';\n\nimport { type Action, type Label } from './action';\n\n/**\n * Called when a node is added to the graph, allowing other node builders to add children, actions or properties.\n */\nexport type NodeBuilder = (parent: Node) => UnsubscribeCallback | void;\n\n/**\n * Represents a node in the graph.\n */\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = {\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Parent node in the graph.\n */\n parent: Node | null;\n\n /**\n * Label to be used when displaying the node.\n * For default labels, use a translated string.\n *\n * @example 'My Node'\n * @example ['unknown node label, { ns: 'example-plugin' }]\n */\n label: Label;\n\n /**\n * Description to be used when displaying a detailed view of the node.\n * For default descriptions, use a translated string.\n */\n description?: Label;\n\n /**\n * Icon to be used when displaying the node.\n */\n icon?: FC<IconProps>;\n\n /**\n * Properties of the node relevant to displaying the node.\n */\n // TODO(burdon): Make this extensible and move label, description, and icon into here?\n properties: TProperties;\n\n /**\n * Data the node represents.\n */\n // TODO(burdon): Type system (e.g., minimally provide identifier string vs. TypedObject vs. Graph mixin type system)?\n // type field would prevent convoluted sniffing of object properties. And allow direct pass-through for ECHO TypedObjects.\n // TODO(burdon): In some places `null` is cast to TData so make optional?\n data: TData;\n\n /**\n * Children of the node stored by their id.\n */\n // TODO(burdon): Rename nodes/nodeMap?\n childrenMap: Record<string, Node>;\n\n /**\n * Actions of the node stored by their id.\n */\n actionsMap: Record<string, Action>;\n\n /**\n * Children of the node in default order.\n */\n get children(): Node[];\n\n /**\n * Actions of the node in default order.\n */\n get actions(): Action[];\n\n addProperty(key: string, value: any): void;\n removeProperty(key: string): void;\n\n addNode<TChildData = null, TChildProperties extends Record<string, any> = Record<string, any>>(\n id: string,\n ...node: (Pick<Node, 'id' | 'label'> & Partial<Node<TChildData, TChildProperties>>)[]\n ): Node<TChildData, TChildProperties>[];\n removeNode(id: string): Node;\n\n addAction<TActionProperties extends Record<string, any> = Record<string, any>>(\n ...action: (Pick<Action, 'id' | 'label' | 'invoke'> & Partial<Action<TActionProperties>>)[]\n ): Action<TActionProperties>[];\n removeAction(id: string): Action;\n};\n\nexport const isGraphNode = (data: unknown): data is Node =>\n data && typeof data === 'object' ? 'id' in data && 'label' in data : false;\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { deepSignal } from 'deepsignal/react';\n// TODO(wittjosiah): Remove lodash dependency.\nimport get from 'lodash.get';\n\nimport { type Label } from './action';\nimport { type Node } from './node';\n\nexport type TraversalOptions = {\n /**\n * The node to start traversing from. Defaults to the root node.\n */\n node?: Node;\n\n /**\n * The direction to traverse the graph. Defaults to 'down'.\n */\n direction?: 'up' | 'down';\n\n /**\n * A predicate to filter nodes which are passed to the `visitor` callback.\n */\n filter?: (node: Node) => boolean;\n\n /**\n * A callback which is called for each node visited during traversal.\n */\n visitor?: (node: Node) => void;\n};\n\n/**\n * The Graph represents...\n */\nexport class Graph {\n // TODO(burdon): Document.\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n private readonly _index = deepSignal<{ [key: string]: string[] }>({});\n\n constructor(private readonly _root: Node) {}\n\n toJSON() {\n const toLabel = (label: Label) => (Array.isArray(label) ? `${label[1].ns}[${label[0]}]` : label);\n const toJSON = (node: Node): any => {\n return {\n id: node.id.slice(0, 16),\n label: toLabel(node.label),\n children: node.children.length ? node.children.map((node) => toJSON(node)) : undefined,\n actions: node.actions.length\n ? node.actions.map(({ id, label }) => ({\n id,\n label: toLabel(label),\n }))\n : undefined,\n };\n };\n\n return toJSON(this._root);\n }\n\n /**\n * The root node of the graph which is the entry point for all knowledge.\n */\n get root(): Node {\n return this._root;\n }\n\n /**\n * Get the path through the graph from the root to the node with the given id.\n */\n getPath(id: string): string[] | undefined {\n return this._index[id];\n }\n\n /**\n * @internal\n */\n _setPath(id: string, path: string[]) {\n this._index[id] = path;\n }\n\n /**\n * Find the node with the given id in the graph.\n */\n findNode(id: string): Node | undefined {\n const path = this.getPath(id);\n if (!path) {\n return undefined;\n }\n\n return path.length > 0 ? get(this._root, path) : this._root;\n }\n\n /**\n * Recursive breadth-first traversal.\n */\n traverse({ node = this._root, direction = 'down', filter, visitor }: TraversalOptions, depth = 0): void {\n if (!filter || filter(node)) {\n visitor?.(node);\n }\n\n if (direction === 'down') {\n Object.values(node.children).forEach((child) => this.traverse({ node: child, filter, visitor }));\n } else if (direction === 'up' && node.parent) {\n this.traverse({ node: node.parent, direction, filter, visitor }, depth + 1);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { untracked } from '@preact/signals-react';\nimport { type RevertDeepSignal, deepSignal } from 'deepsignal/react';\nimport Mousetrap from 'mousetrap';\n\nimport { EventSubscriptions } from '@dxos/async';\n\nimport type { ActionArg, Action } from './action';\nimport { Graph } from './graph';\nimport type { NodeArg, Node, NodeBuilder } from './node';\n\n/**\n * The builder...\n */\nexport class GraphBuilder {\n private readonly _nodeBuilders = new Map<string, NodeBuilder>();\n private readonly _unsubscribe = new Map<string, EventSubscriptions>();\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addNodeBuilder(id: string, builder: NodeBuilder): GraphBuilder {\n this._nodeBuilders.set(id, builder);\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeNodeBuilder(id: string): GraphBuilder {\n this._nodeBuilders.delete(id);\n return this;\n }\n\n /**\n * Construct the graph, starting by calling all registered node builders on the root node.\n * Node builders will be filtered out as they are used such that they are only used once on any given path.\n * @param previousGraph If provided, the graph will be updated in place.\n * @param startingPath If provided, the graph will be updated starting at the given path.\n */\n build(previousGraph?: Graph, startingPath: string[] = []): Graph {\n const graph: Graph = previousGraph ?? new Graph(this._createNode(() => graph, { id: 'root', label: 'Root' }));\n return this._build(graph, graph.root, startingPath);\n }\n\n /**\n * Called recursively.\n */\n private _build(graph: Graph, node: Node, path: string[] = [], ignoreBuilders: string[] = []): Graph {\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n graph._setPath(node.id, path);\n\n // TODO(burdon): Document.\n const subscriptions = this._unsubscribe.get(node.id) ?? new EventSubscriptions();\n subscriptions.clear();\n\n Array.from(this._nodeBuilders.entries())\n .filter(([id]) => ignoreBuilders.findIndex((ignore) => ignore === id) === -1)\n .forEach(([_, builder]) => {\n const unsubscribe = builder(node);\n unsubscribe && subscriptions.add(unsubscribe);\n });\n\n this._unsubscribe.set(node.id, subscriptions);\n\n return graph;\n }\n\n private _createNode<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n getGraph: () => Graph,\n partial: NodeArg<TData, TProperties>,\n path: string[] = [],\n ignoreBuilders: string[] = [],\n ): Node<TData, TProperties> {\n // TODO(burdon): Document implications and rationale of deepSignal.\n const node: Node<TData, TProperties> = deepSignal({\n parent: null,\n data: null as TData, // TODO(burdon): Allow null property?\n properties: {} as TProperties,\n childrenMap: {},\n actionsMap: {},\n // TODO(burdon): Document.\n ...partial,\n\n get children() {\n return Object.values(node.childrenMap);\n },\n get actions() {\n return Object.values(node.actionsMap);\n },\n\n addProperty: (key, value) => {\n untracked(() => {\n (node.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n untracked(() => {\n delete (node.properties as Record<string, any>)[key];\n });\n },\n\n addNode: (builder, ...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const builders = [...ignoreBuilders, builder];\n const childPath = [...path, 'childrenMap', partial.id];\n const child = this._createNode(getGraph, { ...partial, parent: node }, childPath, builders);\n node.childrenMap[child.id] = child;\n // TOOD(burdon): Defer triggering recursive updates until task has completed.\n this._build(getGraph(), child, childPath, builders);\n return child;\n });\n });\n },\n removeNode: (id) => {\n return untracked(() => {\n const child = node.childrenMap[id];\n delete node.childrenMap[id];\n return child;\n });\n },\n\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const action = this._createAction(partial);\n if (action.keyBinding) {\n Mousetrap.bind(action.keyBinding, () => {\n action.invoke();\n });\n }\n\n node.actionsMap[action.id] = action;\n return action;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const action = node.actionsMap[id];\n if (action.keyBinding) {\n Mousetrap.unbind(action.keyBinding);\n }\n\n delete node.actionsMap[id];\n return action;\n });\n },\n }) as RevertDeepSignal<Node<TData, TProperties>>;\n\n // Only actions added at this stage are available to subsequent builders.\n // `addNode` immediately passes the new node to other builders.\n // As such, actions added later with `addAction` are not available to those builders.\n // Having actions available to subsequent builders is useful for building groups.\n partial.actions && partial.actions.forEach((action) => node.addAction(action));\n\n return node;\n }\n\n private _createAction<TProperties extends Record<string, any> = Record<string, any>>(\n partial: ActionArg<TProperties>,\n ): Action<TProperties> {\n const action: Action<TProperties> = deepSignal({\n properties: {} as TProperties,\n ...partial,\n actionsMap: {},\n get actions() {\n return Object.values(action.actionsMap);\n },\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const subAction = this._createAction(partial);\n action.actionsMap[subAction.id] = subAction;\n return subAction;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const subAction = action.actionsMap[id];\n delete action.actionsMap[id];\n return subAction;\n });\n },\n addProperty: (key, value) => {\n return untracked(() => {\n (action.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n return untracked(() => {\n delete (action.properties as Record<string, any>)[key];\n });\n },\n }) as RevertDeepSignal<Action<TProperties>>;\n\n partial.actions && partial.actions.forEach((subAction) => action.addAction(subAction));\n\n return action;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport type { IconProps } from '@phosphor-icons/react';\nimport { type FC } from 'react';\n\nimport type { UnsubscribeCallback } from '@dxos/async';\n\nimport { type ActionArg, type Action, type Label } from './action';\n\n/**\n * Called when a node is added to the graph, allowing other node builders to add children, actions or properties.\n */\nexport type NodeBuilder = (parent: Node) => UnsubscribeCallback | void;\n\n/**\n * Represents a node in the graph.\n */\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = {\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Parent node in the graph.\n */\n parent: Node | null;\n\n /**\n * Label to be used when displaying the node.\n * For default labels, use a translated string.\n *\n * @example 'My Node'\n * @example ['unknown node label, { ns: 'example-plugin' }]\n */\n label: Label;\n\n /**\n * Description to be used when displaying a detailed view of the node.\n * For default descriptions, use a translated string.\n */\n description?: Label;\n\n /**\n * Icon to be used when displaying the node.\n */\n icon?: FC<IconProps>;\n\n /**\n * Properties of the node relevant to displaying the node.\n */\n // TODO(burdon): Make this extensible and move label, description, and icon into here?\n properties: TProperties;\n\n /**\n * Data the node represents.\n */\n // TODO(burdon): Type system (e.g., minimally provide identifier string vs. TypedObject vs. Graph mixin type system)?\n // type field would prevent convoluted sniffing of object properties. And allow direct pass-through for ECHO TypedObjects.\n // TODO(burdon): In some places `null` is cast to TData so make optional?\n data: TData;\n\n /**\n * Children of the node stored by their id.\n */\n // TODO(burdon): Rename nodes/nodeMap?\n childrenMap: Record<string, Node>;\n\n /**\n * Actions of the node stored by their id.\n */\n actionsMap: Record<string, Action>;\n\n /**\n * Children of the node in default order.\n */\n get children(): Node[];\n\n /**\n * Actions of the node in default order.\n */\n get actions(): Action[];\n\n addProperty(key: string, value: any): void;\n removeProperty(key: string): void;\n\n addNode<TChildData = null, TChildProperties extends Record<string, any> = Record<string, any>>(\n id: string,\n ...node: NodeArg<TChildData, TChildProperties>[]\n ): Node<TChildData, TChildProperties>[];\n removeNode(id: string): Node;\n\n addAction<TActionProperties extends Record<string, any> = Record<string, any>>(\n ...action: ActionArg<TActionProperties>[]\n ): Action<TActionProperties>[];\n removeAction(id: string): Action;\n};\n\nexport type NodeArg<TData = null, TProperties extends Record<string, any> = Record<string, any>> = Pick<\n Node,\n 'id' | 'label'\n> &\n Partial<Omit<Node<TData, TProperties>, 'id' | 'label' | 'actions'>> & { actions?: ActionArg[] };\n\nexport const isGraphNode = (data: unknown): data is Node =>\n data && typeof data === 'object' ? 'id' in data && 'label' in data : false;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["deepSignal", "get", "Graph", "constructor", "_root", "_index", "deepSignal", "toJSON", "toLabel", "label", "Array", "isArray", "ns", "node", "id", "slice", "children", "length", "map", "undefined", "actions", "root", "getPath", "_setPath", "path", "findNode", "get", "traverse", "direction", "filter", "visitor", "depth", "Object", "values", "forEach", "child", "parent", "untracked", "deepSignal", "Mousetrap", "EventSubscriptions", "GraphBuilder", "_nodeBuilders", "Map", "_unsubscribe", "addNodeBuilder", "id", "builder", "set", "removeNodeBuilder", "delete", "build", "previousGraph", "startingPath", "graph", "Graph", "_createNode", "label", "_build", "root", "node", "path", "ignoreBuilders", "_setPath", "subscriptions", "get", "EventSubscriptions", "clear", "Array", "from", "entries", "filter", "findIndex", "ignore", "forEach", "_", "unsubscribe", "add", "getGraph", "partial", "deepSignal", "parent", "data", "properties", "childrenMap", "actionsMap", "children", "Object", "values", "actions", "addProperty", "key", "value", "untracked", "removeProperty", "addNode", "partials", "map", "builders", "childPath", "child", "removeNode", "addAction", "action", "_createAction", "keyBinding", "Mousetrap", "bind", "invoke", "removeAction", "unbind", "subAction", "isGraphNode", "data"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/sdk/app-graph/src/action.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/sdk/app-graph/src/action.ts":{"bytes":3043,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/graph.ts":{"bytes":9066,"imports":[{"path":"deepsignal/react","kind":"import-statement","external":true},{"path":"lodash.get","kind":"import-statement","external":true}],"format":"esm"},"packages/sdk/app-graph/src/graph-builder.ts":{"bytes":22642,"imports":[{"path":"@preact/signals-react","kind":"import-statement","external":true},{"path":"deepsignal/react","kind":"import-statement","external":true},{"path":"mousetrap","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"}],"format":"esm"},"packages/sdk/app-graph/src/node.ts":{"bytes":4772,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/index.ts":{"bytes":722,"imports":[{"path":"packages/sdk/app-graph/src/action.ts","kind":"import-statement","original":"./action"},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/graph-builder.ts","kind":"import-statement","original":"./graph-builder"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/testing.ts":{"bytes":11884,"imports":[],"format":"esm"}},"outputs":{"packages/sdk/app-graph/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":19252},"packages/sdk/app-graph/dist/lib/browser/index.mjs":{"imports":[{"path":"deepsignal/react","kind":"import-statement","external":true},{"path":"lodash.get","kind":"import-statement","external":true},{"path":"@preact/signals-react","kind":"import-statement","external":true},{"path":"deepsignal/react","kind":"import-statement","external":true},{"path":"mousetrap","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true}],"exports":["Graph","GraphBuilder","isGraphNode"],"entryPoint":"packages/sdk/app-graph/src/index.ts","inputs":{"packages/sdk/app-graph/src/index.ts":{"bytesInOutput":0},"packages/sdk/app-graph/src/graph.ts":{"bytesInOutput":1818},"packages/sdk/app-graph/src/graph-builder.ts":{"bytesInOutput":5294},"packages/sdk/app-graph/src/node.ts":{"bytesInOutput":104}},"bytes":7428},"packages/sdk/app-graph/dist/lib/browser/testing.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":6167},"packages/sdk/app-graph/dist/lib/browser/testing.mjs":{"imports":[],"exports":["buildGraph","createTestNodeBuilder"],"entryPoint":"packages/sdk/app-graph/src/testing.ts","inputs":{"packages/sdk/app-graph/src/testing.ts":{"bytesInOutput":2180}},"bytes":2308}}}
|
package/dist/lib/node/index.cjs
CHANGED
|
@@ -171,7 +171,6 @@ var GraphBuilder = class {
|
|
|
171
171
|
actionsMap: {},
|
|
172
172
|
// TODO(burdon): Document.
|
|
173
173
|
...partial,
|
|
174
|
-
// TODO(wittjosiah): Default sort.
|
|
175
174
|
get children() {
|
|
176
175
|
return Object.values(node.childrenMap);
|
|
177
176
|
},
|
|
@@ -242,14 +241,14 @@ var GraphBuilder = class {
|
|
|
242
241
|
});
|
|
243
242
|
}
|
|
244
243
|
});
|
|
244
|
+
partial.actions && partial.actions.forEach((action) => node.addAction(action));
|
|
245
245
|
return node;
|
|
246
246
|
}
|
|
247
247
|
_createAction(partial) {
|
|
248
248
|
const action = (0, import_react2.deepSignal)({
|
|
249
249
|
properties: {},
|
|
250
|
-
actionsMap: {},
|
|
251
250
|
...partial,
|
|
252
|
-
|
|
251
|
+
actionsMap: {},
|
|
253
252
|
get actions() {
|
|
254
253
|
return Object.values(action.actionsMap);
|
|
255
254
|
},
|
|
@@ -280,6 +279,7 @@ var GraphBuilder = class {
|
|
|
280
279
|
});
|
|
281
280
|
}
|
|
282
281
|
});
|
|
282
|
+
partial.actions && partial.actions.forEach((subAction) => action.addAction(subAction));
|
|
283
283
|
return action;
|
|
284
284
|
}
|
|
285
285
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/index.ts", "../../../src/graph.ts", "../../../src/graph-builder.ts", "../../../src/node.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nexport * from './action';\nexport * from './graph';\nexport * from './graph-builder';\nexport * from './node';\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { deepSignal } from 'deepsignal/react';\n// TODO(wittjosiah): Remove lodash dependency.\nimport get from 'lodash.get';\n\nimport { type Label } from './action';\nimport { type Node } from './node';\n\nexport type TraversalOptions = {\n /**\n * The node to start traversing from. Defaults to the root node.\n */\n node?: Node;\n\n /**\n * The direction to traverse the graph. Defaults to 'down'.\n */\n direction?: 'up' | 'down';\n\n /**\n * A predicate to filter nodes which are passed to the `visitor` callback.\n */\n filter?: (node: Node) => boolean;\n\n /**\n * A callback which is called for each node visited during traversal.\n */\n visitor?: (node: Node) => void;\n};\n\n/**\n * The Graph represents...\n */\nexport class Graph {\n // TODO(burdon): Document.\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n private readonly _index = deepSignal<{ [key: string]: string[] }>({});\n\n constructor(private readonly _root: Node) {}\n\n toJSON() {\n const toLabel = (label: Label) => (Array.isArray(label) ? `${label[1].ns}[${label[0]}]` : label);\n const toJSON = (node: Node): any => {\n return {\n id: node.id.slice(0, 16),\n label: toLabel(node.label),\n children: node.children.length ? node.children.map((node) => toJSON(node)) : undefined,\n actions: node.actions.length\n ? node.actions.map(({ id, label }) => ({\n id,\n label: toLabel(label),\n }))\n : undefined,\n };\n };\n\n return toJSON(this._root);\n }\n\n /**\n * The root node of the graph which is the entry point for all knowledge.\n */\n get root(): Node {\n return this._root;\n }\n\n /**\n * Get the path through the graph from the root to the node with the given id.\n */\n getPath(id: string): string[] | undefined {\n return this._index[id];\n }\n\n /**\n * @internal\n */\n _setPath(id: string, path: string[]) {\n this._index[id] = path;\n }\n\n /**\n * Find the node with the given id in the graph.\n */\n findNode(id: string): Node | undefined {\n const path = this.getPath(id);\n if (!path) {\n return undefined;\n }\n\n return path.length > 0 ? get(this._root, path) : this._root;\n }\n\n /**\n * Recursive breadth-first traversal.\n */\n traverse({ node = this._root, direction = 'down', filter, visitor }: TraversalOptions, depth = 0): void {\n if (!filter || filter(node)) {\n visitor?.(node);\n }\n\n if (direction === 'down') {\n Object.values(node.children).forEach((child) => this.traverse({ node: child, filter, visitor }));\n } else if (direction === 'up' && node.parent) {\n this.traverse({ node: node.parent, direction, filter, visitor }, depth + 1);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { untracked } from '@preact/signals-react';\nimport { type RevertDeepSignal, deepSignal } from 'deepsignal/react';\nimport Mousetrap from 'mousetrap';\n\nimport { EventSubscriptions } from '@dxos/async';\n\nimport { type Action } from './action';\nimport { Graph } from './graph';\nimport { type Node, type NodeBuilder } from './node';\n\n/**\n * The builder...\n */\nexport class GraphBuilder {\n private readonly _nodeBuilders = new Map<string, NodeBuilder>();\n private readonly _unsubscribe = new Map<string, EventSubscriptions>();\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addNodeBuilder(id: string, builder: NodeBuilder): GraphBuilder {\n this._nodeBuilders.set(id, builder);\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeNodeBuilder(id: string): GraphBuilder {\n this._nodeBuilders.delete(id);\n return this;\n }\n\n /**\n * Construct the graph, starting by calling all registered node builders on the root node.\n * Node builders will be filtered out as they are used such that they are only used once on any given path.\n * @param previousGraph If provided, the graph will be updated in place.\n * @param startingPath If provided, the graph will be updated starting at the given path.\n */\n build(previousGraph?: Graph, startingPath: string[] = []): Graph {\n const graph: Graph = previousGraph ?? new Graph(this._createNode(() => graph, { id: 'root', label: 'Root' }));\n return this._build(graph, graph.root, startingPath);\n }\n\n /**\n * Called recursively.\n */\n private _build(graph: Graph, node: Node, path: string[] = [], ignoreBuilders: string[] = []): Graph {\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n graph._setPath(node.id, path);\n\n // TODO(burdon): Document.\n const subscriptions = this._unsubscribe.get(node.id) ?? new EventSubscriptions();\n subscriptions.clear();\n\n Array.from(this._nodeBuilders.entries())\n .filter(([id]) => ignoreBuilders.findIndex((ignore) => ignore === id) === -1)\n .forEach(([_, builder]) => {\n const unsubscribe = builder(node);\n unsubscribe && subscriptions.add(unsubscribe);\n });\n\n this._unsubscribe.set(node.id, subscriptions);\n\n return graph;\n }\n\n private _createNode<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n getGraph: () => Graph,\n partial: Pick<Node, 'id' | 'label'> & Partial<Node<TData, TProperties>>,\n path: string[] = [],\n ignoreBuilders: string[] = [],\n ): Node<TData, TProperties> {\n // TODO(burdon): Document implications and rationale of deepSignal.\n const node: Node<TData, TProperties> = deepSignal({\n parent: null,\n data: null as TData, // TODO(burdon): Allow null property?\n properties: {} as TProperties,\n childrenMap: {},\n actionsMap: {},\n // TODO(burdon): Document.\n ...partial,\n\n // TODO(wittjosiah): Default sort.\n get children() {\n return Object.values(node.childrenMap);\n },\n get actions() {\n return Object.values(node.actionsMap);\n },\n\n addProperty: (key, value) => {\n untracked(() => {\n (node.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n untracked(() => {\n delete (node.properties as Record<string, any>)[key];\n });\n },\n\n addNode: (builder, ...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const builders = [...ignoreBuilders, builder];\n const childPath = [...path, 'childrenMap', partial.id];\n const child = this._createNode(getGraph, { ...partial, parent: node }, childPath, builders);\n node.childrenMap[child.id] = child;\n // TOOD(burdon): Defer triggering recursive updates until task has completed.\n this._build(getGraph(), child, childPath, builders);\n return child;\n });\n });\n },\n removeNode: (id) => {\n return untracked(() => {\n const child = node.childrenMap[id];\n delete node.childrenMap[id];\n return child;\n });\n },\n\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const action = this._createAction(partial);\n if (action.keyBinding) {\n Mousetrap.bind(action.keyBinding, () => {\n action.invoke();\n });\n }\n\n node.actionsMap[action.id] = action;\n return action;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const action = node.actionsMap[id];\n if (action.keyBinding) {\n Mousetrap.unbind(action.keyBinding);\n }\n\n delete node.actionsMap[id];\n return action;\n });\n },\n }) as RevertDeepSignal<Node<TData, TProperties>>;\n\n return node;\n }\n\n private _createAction<TProperties extends Record<string, any> = Record<string, any>>(\n partial: Pick<Action, 'id' | 'label' | 'invoke'> & Partial<Action<TProperties>>,\n ): Action<TProperties> {\n const action: Action<TProperties> = deepSignal({\n properties: {} as TProperties,\n actionsMap: {},\n ...partial,\n // TODO(wittjosiah): Default sort.\n get actions() {\n return Object.values(action.actionsMap);\n },\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const subAction = this._createAction(partial);\n action.actionsMap[subAction.id] = subAction;\n return subAction;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const subAction = action.actionsMap[id];\n delete action.actionsMap[id];\n return subAction;\n });\n },\n addProperty: (key, value) => {\n return untracked(() => {\n (action.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n return untracked(() => {\n delete (action.properties as Record<string, any>)[key];\n });\n },\n }) as RevertDeepSignal<Action<TProperties>>;\n\n return action;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport type { IconProps } from '@phosphor-icons/react';\nimport { type FC } from 'react';\n\nimport type { UnsubscribeCallback } from '@dxos/async';\n\nimport { type Action, type Label } from './action';\n\n/**\n * Called when a node is added to the graph, allowing other node builders to add children, actions or properties.\n */\nexport type NodeBuilder = (parent: Node) => UnsubscribeCallback | void;\n\n/**\n * Represents a node in the graph.\n */\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = {\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Parent node in the graph.\n */\n parent: Node | null;\n\n /**\n * Label to be used when displaying the node.\n * For default labels, use a translated string.\n *\n * @example 'My Node'\n * @example ['unknown node label, { ns: 'example-plugin' }]\n */\n label: Label;\n\n /**\n * Description to be used when displaying a detailed view of the node.\n * For default descriptions, use a translated string.\n */\n description?: Label;\n\n /**\n * Icon to be used when displaying the node.\n */\n icon?: FC<IconProps>;\n\n /**\n * Properties of the node relevant to displaying the node.\n */\n // TODO(burdon): Make this extensible and move label, description, and icon into here?\n properties: TProperties;\n\n /**\n * Data the node represents.\n */\n // TODO(burdon): Type system (e.g., minimally provide identifier string vs. TypedObject vs. Graph mixin type system)?\n // type field would prevent convoluted sniffing of object properties. And allow direct pass-through for ECHO TypedObjects.\n // TODO(burdon): In some places `null` is cast to TData so make optional?\n data: TData;\n\n /**\n * Children of the node stored by their id.\n */\n // TODO(burdon): Rename nodes/nodeMap?\n childrenMap: Record<string, Node>;\n\n /**\n * Actions of the node stored by their id.\n */\n actionsMap: Record<string, Action>;\n\n /**\n * Children of the node in default order.\n */\n get children(): Node[];\n\n /**\n * Actions of the node in default order.\n */\n get actions(): Action[];\n\n addProperty(key: string, value: any): void;\n removeProperty(key: string): void;\n\n addNode<TChildData = null, TChildProperties extends Record<string, any> = Record<string, any>>(\n id: string,\n ...node: (Pick<Node, 'id' | 'label'> & Partial<Node<TChildData, TChildProperties>>)[]\n ): Node<TChildData, TChildProperties>[];\n removeNode(id: string): Node;\n\n addAction<TActionProperties extends Record<string, any> = Record<string, any>>(\n ...action: (Pick<Action, 'id' | 'label' | 'invoke'> & Partial<Action<TActionProperties>>)[]\n ): Action<TActionProperties>[];\n removeAction(id: string): Action;\n};\n\nexport const isGraphNode = (data: unknown): data is Node =>\n data && typeof data === 'object' ? 'id' in data && 'label' in data : false;\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nexport * from './action';\nexport * from './graph';\nexport * from './graph-builder';\nexport * from './node';\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { deepSignal } from 'deepsignal/react';\n// TODO(wittjosiah): Remove lodash dependency.\nimport get from 'lodash.get';\n\nimport { type Label } from './action';\nimport { type Node } from './node';\n\nexport type TraversalOptions = {\n /**\n * The node to start traversing from. Defaults to the root node.\n */\n node?: Node;\n\n /**\n * The direction to traverse the graph. Defaults to 'down'.\n */\n direction?: 'up' | 'down';\n\n /**\n * A predicate to filter nodes which are passed to the `visitor` callback.\n */\n filter?: (node: Node) => boolean;\n\n /**\n * A callback which is called for each node visited during traversal.\n */\n visitor?: (node: Node) => void;\n};\n\n/**\n * The Graph represents...\n */\nexport class Graph {\n // TODO(burdon): Document.\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n private readonly _index = deepSignal<{ [key: string]: string[] }>({});\n\n constructor(private readonly _root: Node) {}\n\n toJSON() {\n const toLabel = (label: Label) => (Array.isArray(label) ? `${label[1].ns}[${label[0]}]` : label);\n const toJSON = (node: Node): any => {\n return {\n id: node.id.slice(0, 16),\n label: toLabel(node.label),\n children: node.children.length ? node.children.map((node) => toJSON(node)) : undefined,\n actions: node.actions.length\n ? node.actions.map(({ id, label }) => ({\n id,\n label: toLabel(label),\n }))\n : undefined,\n };\n };\n\n return toJSON(this._root);\n }\n\n /**\n * The root node of the graph which is the entry point for all knowledge.\n */\n get root(): Node {\n return this._root;\n }\n\n /**\n * Get the path through the graph from the root to the node with the given id.\n */\n getPath(id: string): string[] | undefined {\n return this._index[id];\n }\n\n /**\n * @internal\n */\n _setPath(id: string, path: string[]) {\n this._index[id] = path;\n }\n\n /**\n * Find the node with the given id in the graph.\n */\n findNode(id: string): Node | undefined {\n const path = this.getPath(id);\n if (!path) {\n return undefined;\n }\n\n return path.length > 0 ? get(this._root, path) : this._root;\n }\n\n /**\n * Recursive breadth-first traversal.\n */\n traverse({ node = this._root, direction = 'down', filter, visitor }: TraversalOptions, depth = 0): void {\n if (!filter || filter(node)) {\n visitor?.(node);\n }\n\n if (direction === 'down') {\n Object.values(node.children).forEach((child) => this.traverse({ node: child, filter, visitor }));\n } else if (direction === 'up' && node.parent) {\n this.traverse({ node: node.parent, direction, filter, visitor }, depth + 1);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { untracked } from '@preact/signals-react';\nimport { type RevertDeepSignal, deepSignal } from 'deepsignal/react';\nimport Mousetrap from 'mousetrap';\n\nimport { EventSubscriptions } from '@dxos/async';\n\nimport type { ActionArg, Action } from './action';\nimport { Graph } from './graph';\nimport type { NodeArg, Node, NodeBuilder } from './node';\n\n/**\n * The builder...\n */\nexport class GraphBuilder {\n private readonly _nodeBuilders = new Map<string, NodeBuilder>();\n private readonly _unsubscribe = new Map<string, EventSubscriptions>();\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addNodeBuilder(id: string, builder: NodeBuilder): GraphBuilder {\n this._nodeBuilders.set(id, builder);\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeNodeBuilder(id: string): GraphBuilder {\n this._nodeBuilders.delete(id);\n return this;\n }\n\n /**\n * Construct the graph, starting by calling all registered node builders on the root node.\n * Node builders will be filtered out as they are used such that they are only used once on any given path.\n * @param previousGraph If provided, the graph will be updated in place.\n * @param startingPath If provided, the graph will be updated starting at the given path.\n */\n build(previousGraph?: Graph, startingPath: string[] = []): Graph {\n const graph: Graph = previousGraph ?? new Graph(this._createNode(() => graph, { id: 'root', label: 'Root' }));\n return this._build(graph, graph.root, startingPath);\n }\n\n /**\n * Called recursively.\n */\n private _build(graph: Graph, node: Node, path: string[] = [], ignoreBuilders: string[] = []): Graph {\n // TODO(wittjosiah): Should this support multiple paths to the same node?\n graph._setPath(node.id, path);\n\n // TODO(burdon): Document.\n const subscriptions = this._unsubscribe.get(node.id) ?? new EventSubscriptions();\n subscriptions.clear();\n\n Array.from(this._nodeBuilders.entries())\n .filter(([id]) => ignoreBuilders.findIndex((ignore) => ignore === id) === -1)\n .forEach(([_, builder]) => {\n const unsubscribe = builder(node);\n unsubscribe && subscriptions.add(unsubscribe);\n });\n\n this._unsubscribe.set(node.id, subscriptions);\n\n return graph;\n }\n\n private _createNode<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n getGraph: () => Graph,\n partial: NodeArg<TData, TProperties>,\n path: string[] = [],\n ignoreBuilders: string[] = [],\n ): Node<TData, TProperties> {\n // TODO(burdon): Document implications and rationale of deepSignal.\n const node: Node<TData, TProperties> = deepSignal({\n parent: null,\n data: null as TData, // TODO(burdon): Allow null property?\n properties: {} as TProperties,\n childrenMap: {},\n actionsMap: {},\n // TODO(burdon): Document.\n ...partial,\n\n get children() {\n return Object.values(node.childrenMap);\n },\n get actions() {\n return Object.values(node.actionsMap);\n },\n\n addProperty: (key, value) => {\n untracked(() => {\n (node.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n untracked(() => {\n delete (node.properties as Record<string, any>)[key];\n });\n },\n\n addNode: (builder, ...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const builders = [...ignoreBuilders, builder];\n const childPath = [...path, 'childrenMap', partial.id];\n const child = this._createNode(getGraph, { ...partial, parent: node }, childPath, builders);\n node.childrenMap[child.id] = child;\n // TOOD(burdon): Defer triggering recursive updates until task has completed.\n this._build(getGraph(), child, childPath, builders);\n return child;\n });\n });\n },\n removeNode: (id) => {\n return untracked(() => {\n const child = node.childrenMap[id];\n delete node.childrenMap[id];\n return child;\n });\n },\n\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const action = this._createAction(partial);\n if (action.keyBinding) {\n Mousetrap.bind(action.keyBinding, () => {\n action.invoke();\n });\n }\n\n node.actionsMap[action.id] = action;\n return action;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const action = node.actionsMap[id];\n if (action.keyBinding) {\n Mousetrap.unbind(action.keyBinding);\n }\n\n delete node.actionsMap[id];\n return action;\n });\n },\n }) as RevertDeepSignal<Node<TData, TProperties>>;\n\n // Only actions added at this stage are available to subsequent builders.\n // `addNode` immediately passes the new node to other builders.\n // As such, actions added later with `addAction` are not available to those builders.\n // Having actions available to subsequent builders is useful for building groups.\n partial.actions && partial.actions.forEach((action) => node.addAction(action));\n\n return node;\n }\n\n private _createAction<TProperties extends Record<string, any> = Record<string, any>>(\n partial: ActionArg<TProperties>,\n ): Action<TProperties> {\n const action: Action<TProperties> = deepSignal({\n properties: {} as TProperties,\n ...partial,\n actionsMap: {},\n get actions() {\n return Object.values(action.actionsMap);\n },\n addAction: (...partials) => {\n return untracked(() => {\n return partials.map((partial) => {\n const subAction = this._createAction(partial);\n action.actionsMap[subAction.id] = subAction;\n return subAction;\n });\n });\n },\n removeAction: (id) => {\n return untracked(() => {\n const subAction = action.actionsMap[id];\n delete action.actionsMap[id];\n return subAction;\n });\n },\n addProperty: (key, value) => {\n return untracked(() => {\n (action.properties as Record<string, any>)[key] = value;\n });\n },\n removeProperty: (key) => {\n return untracked(() => {\n delete (action.properties as Record<string, any>)[key];\n });\n },\n }) as RevertDeepSignal<Action<TProperties>>;\n\n partial.actions && partial.actions.forEach((subAction) => action.addAction(subAction));\n\n return action;\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport type { IconProps } from '@phosphor-icons/react';\nimport { type FC } from 'react';\n\nimport type { UnsubscribeCallback } from '@dxos/async';\n\nimport { type ActionArg, type Action, type Label } from './action';\n\n/**\n * Called when a node is added to the graph, allowing other node builders to add children, actions or properties.\n */\nexport type NodeBuilder = (parent: Node) => UnsubscribeCallback | void;\n\n/**\n * Represents a node in the graph.\n */\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = {\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Parent node in the graph.\n */\n parent: Node | null;\n\n /**\n * Label to be used when displaying the node.\n * For default labels, use a translated string.\n *\n * @example 'My Node'\n * @example ['unknown node label, { ns: 'example-plugin' }]\n */\n label: Label;\n\n /**\n * Description to be used when displaying a detailed view of the node.\n * For default descriptions, use a translated string.\n */\n description?: Label;\n\n /**\n * Icon to be used when displaying the node.\n */\n icon?: FC<IconProps>;\n\n /**\n * Properties of the node relevant to displaying the node.\n */\n // TODO(burdon): Make this extensible and move label, description, and icon into here?\n properties: TProperties;\n\n /**\n * Data the node represents.\n */\n // TODO(burdon): Type system (e.g., minimally provide identifier string vs. TypedObject vs. Graph mixin type system)?\n // type field would prevent convoluted sniffing of object properties. And allow direct pass-through for ECHO TypedObjects.\n // TODO(burdon): In some places `null` is cast to TData so make optional?\n data: TData;\n\n /**\n * Children of the node stored by their id.\n */\n // TODO(burdon): Rename nodes/nodeMap?\n childrenMap: Record<string, Node>;\n\n /**\n * Actions of the node stored by their id.\n */\n actionsMap: Record<string, Action>;\n\n /**\n * Children of the node in default order.\n */\n get children(): Node[];\n\n /**\n * Actions of the node in default order.\n */\n get actions(): Action[];\n\n addProperty(key: string, value: any): void;\n removeProperty(key: string): void;\n\n addNode<TChildData = null, TChildProperties extends Record<string, any> = Record<string, any>>(\n id: string,\n ...node: NodeArg<TChildData, TChildProperties>[]\n ): Node<TChildData, TChildProperties>[];\n removeNode(id: string): Node;\n\n addAction<TActionProperties extends Record<string, any> = Record<string, any>>(\n ...action: ActionArg<TActionProperties>[]\n ): Action<TActionProperties>[];\n removeAction(id: string): Action;\n};\n\nexport type NodeArg<TData = null, TProperties extends Record<string, any> = Record<string, any>> = Pick<\n Node,\n 'id' | 'label'\n> &\n Partial<Omit<Node<TData, TProperties>, 'id' | 'label' | 'actions'>> & { actions?: ActionArg[] };\n\nexport const isGraphNode = (data: unknown): data is Node =>\n data && typeof data === 'object' ? 'id' in data && 'label' in data : false;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Graph", "constructor", "_root", "_index", "deepSignal", "toJSON", "toLabel", "label", "Array", "isArray", "ns", "node", "id", "slice", "children", "length", "map", "undefined", "actions", "root", "getPath", "_setPath", "path", "findNode", "get", "traverse", "direction", "filter", "visitor", "depth", "Object", "values", "forEach", "child", "parent", "import_react", "GraphBuilder", "_nodeBuilders", "Map", "_unsubscribe", "addNodeBuilder", "id", "builder", "set", "removeNodeBuilder", "delete", "build", "previousGraph", "startingPath", "graph", "Graph", "_createNode", "label", "_build", "root", "node", "path", "ignoreBuilders", "_setPath", "subscriptions", "get", "EventSubscriptions", "clear", "Array", "from", "entries", "filter", "findIndex", "ignore", "forEach", "_", "unsubscribe", "add", "getGraph", "partial", "deepSignal", "parent", "data", "properties", "childrenMap", "actionsMap", "children", "Object", "values", "actions", "addProperty", "key", "value", "untracked", "removeProperty", "addNode", "partials", "map", "builders", "childPath", "child", "removeNode", "addAction", "action", "_createAction", "keyBinding", "Mousetrap", "bind", "invoke", "removeAction", "unbind", "subAction", "isGraphNode", "data"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/sdk/app-graph/src/action.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/sdk/app-graph/src/action.ts":{"bytes":3043,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/graph.ts":{"bytes":9066,"imports":[{"path":"deepsignal/react","kind":"import-statement","external":true},{"path":"lodash.get","kind":"import-statement","external":true}],"format":"esm"},"packages/sdk/app-graph/src/graph-builder.ts":{"bytes":22642,"imports":[{"path":"@preact/signals-react","kind":"import-statement","external":true},{"path":"deepsignal/react","kind":"import-statement","external":true},{"path":"mousetrap","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"}],"format":"esm"},"packages/sdk/app-graph/src/node.ts":{"bytes":4772,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/index.ts":{"bytes":722,"imports":[{"path":"packages/sdk/app-graph/src/action.ts","kind":"import-statement","original":"./action"},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/graph-builder.ts","kind":"import-statement","original":"./graph-builder"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/testing.ts":{"bytes":11884,"imports":[],"format":"esm"}},"outputs":{"packages/sdk/app-graph/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":19410},"packages/sdk/app-graph/dist/lib/node/index.cjs":{"imports":[{"path":"deepsignal/react","kind":"require-call","external":true},{"path":"lodash.get","kind":"require-call","external":true},{"path":"@preact/signals-react","kind":"require-call","external":true},{"path":"deepsignal/react","kind":"require-call","external":true},{"path":"mousetrap","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/sdk/app-graph/src/index.ts","inputs":{"packages/sdk/app-graph/src/index.ts":{"bytesInOutput":185},"packages/sdk/app-graph/src/graph.ts":{"bytesInOutput":1882},"packages/sdk/app-graph/src/graph-builder.ts":{"bytesInOutput":5642},"packages/sdk/app-graph/src/node.ts":{"bytesInOutput":104}},"bytes":9541},"packages/sdk/app-graph/dist/lib/node/testing.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":6196},"packages/sdk/app-graph/dist/lib/node/testing.cjs":{"imports":[],"exports":[],"entryPoint":"packages/sdk/app-graph/src/testing.ts","inputs":{"packages/sdk/app-graph/src/testing.ts":{"bytesInOutput":2371}},"bytes":3378}}}
|
|
@@ -47,7 +47,10 @@ export type Action<TProperties extends Record<string, any> = Record<string, any>
|
|
|
47
47
|
invoke: () => MaybePromise<any>;
|
|
48
48
|
addProperty(key: string, value: any): void;
|
|
49
49
|
removeProperty(key: string): void;
|
|
50
|
-
addAction<TActionProperties extends Record<string, any> = Record<string, any>>(...action:
|
|
50
|
+
addAction<TActionProperties extends Record<string, any> = Record<string, any>>(...action: ActionArg<TActionProperties>[]): Action<TActionProperties>[];
|
|
51
51
|
removeAction(id: string): Action;
|
|
52
52
|
};
|
|
53
|
+
export type ActionArg<TProperties extends Record<string, any> = Record<string, any>> = Pick<Action, 'id' | 'label' | 'invoke'> & Partial<Omit<Action<TProperties>, 'id' | 'label' | 'invoke' | 'actions'>> & {
|
|
54
|
+
actions?: ActionArg[];
|
|
55
|
+
};
|
|
53
56
|
//# sourceMappingURL=action.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../../src/action.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IAClF;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;;;OAMG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,UAAU,EAAE,WAAW,CAAC;IAExB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnC;;OAEG;IAEH,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;IAExB,MAAM,EAAE,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IAEhC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAC3C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,SAAS,CAAC,iBAAiB,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3E,GAAG,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../../src/action.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IAClF;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;;;OAMG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,UAAU,EAAE,WAAW,CAAC;IAExB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnC;;OAEG;IAEH,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;IAExB,MAAM,EAAE,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IAEhC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAC3C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,SAAS,CAAC,iBAAiB,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3E,GAAG,MAAM,EAAE,SAAS,CAAC,iBAAiB,CAAC,EAAE,GACxC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,IAAI,CACzF,MAAM,EACN,IAAI,GAAG,OAAO,GAAG,QAAQ,CAC1B,GACC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-builder.d.ts","sourceRoot":"","sources":["../../../src/graph-builder.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,
|
|
1
|
+
{"version":3,"file":"graph-builder.d.ts","sourceRoot":"","sources":["../../../src/graph-builder.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAiB,WAAW,EAAE,MAAM,QAAQ,CAAC;AAEzD;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAChE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IAEtE;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,YAAY;IAK9D;;OAEG;IACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY;IAK3C;;;;;OAKG;IACH,KAAK,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,YAAY,GAAE,MAAM,EAAO,GAAG,KAAK;IAKhE;;OAEG;IACH,OAAO,CAAC,MAAM;IAoBd,OAAO,CAAC,WAAW;IA4FnB,OAAO,CAAC,aAAa;CA0CtB"}
|
package/dist/types/src/node.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IconProps } from '@phosphor-icons/react';
|
|
2
2
|
import { type FC } from 'react';
|
|
3
3
|
import type { UnsubscribeCallback } from '@dxos/async';
|
|
4
|
-
import { type Action, type Label } from './action';
|
|
4
|
+
import { type ActionArg, type Action, type Label } from './action';
|
|
5
5
|
/**
|
|
6
6
|
* Called when a node is added to the graph, allowing other node builders to add children, actions or properties.
|
|
7
7
|
*/
|
|
@@ -61,10 +61,13 @@ export type Node<TData = any, TProperties extends Record<string, any> = Record<s
|
|
|
61
61
|
get actions(): Action[];
|
|
62
62
|
addProperty(key: string, value: any): void;
|
|
63
63
|
removeProperty(key: string): void;
|
|
64
|
-
addNode<TChildData = null, TChildProperties extends Record<string, any> = Record<string, any>>(id: string, ...node:
|
|
64
|
+
addNode<TChildData = null, TChildProperties extends Record<string, any> = Record<string, any>>(id: string, ...node: NodeArg<TChildData, TChildProperties>[]): Node<TChildData, TChildProperties>[];
|
|
65
65
|
removeNode(id: string): Node;
|
|
66
|
-
addAction<TActionProperties extends Record<string, any> = Record<string, any>>(...action:
|
|
66
|
+
addAction<TActionProperties extends Record<string, any> = Record<string, any>>(...action: ActionArg<TActionProperties>[]): Action<TActionProperties>[];
|
|
67
67
|
removeAction(id: string): Action;
|
|
68
68
|
};
|
|
69
|
+
export type NodeArg<TData = null, TProperties extends Record<string, any> = Record<string, any>> = Pick<Node, 'id' | 'label'> & Partial<Omit<Node<TData, TProperties>, 'id' | 'label' | 'actions'>> & {
|
|
70
|
+
actions?: ActionArg[];
|
|
71
|
+
};
|
|
69
72
|
export declare const isGraphNode: (data: unknown) => data is Node<any, Record<string, any>>;
|
|
70
73
|
//# sourceMappingURL=node.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/node.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/node.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAEnE;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,IAAI,KAAK,mBAAmB,GAAG,IAAI,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,IAAI,CAAC,KAAK,GAAG,GAAG,EAAE,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IAC7F;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,MAAM,EAAE,IAAI,GAAG,IAAI,CAAC;IAEpB;;;;;;OAMG;IACH,KAAK,EAAE,KAAK,CAAC;IAEb;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC;IAEpB;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;IAErB;;OAEG;IAEH,UAAU,EAAE,WAAW,CAAC;IAExB;;OAEG;IAIH,IAAI,EAAE,KAAK,CAAC;IAEZ;;OAEG;IAEH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAElC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEnC;;OAEG;IACH,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;IAEvB;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;IAExB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAC3C,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,OAAO,CAAC,UAAU,GAAG,IAAI,EAAE,gBAAgB,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3F,EAAE,EAAE,MAAM,EACV,GAAG,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,gBAAgB,CAAC,EAAE,GAC/C,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,EAAE,CAAC;IACxC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B,SAAS,CAAC,iBAAiB,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3E,GAAG,MAAM,EAAE,SAAS,CAAC,iBAAiB,CAAC,EAAE,GACxC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,OAAO,CAAC,KAAK,GAAG,IAAI,EAAE,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,IAAI,CACrG,IAAI,EACJ,IAAI,GAAG,OAAO,CACf,GACC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC;AAElG,eAAO,MAAM,WAAW,SAAU,OAAO,2CACmC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/app-graph",
|
|
3
|
-
"version": "0.3.4-
|
|
3
|
+
"version": "0.3.4-next.1e21f62",
|
|
4
4
|
"description": "Constructs knowledge graphs for the purpose of building applications on top of",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"lodash.get": "^4.4.2",
|
|
39
39
|
"lodash.set": "^4.3.2",
|
|
40
40
|
"mousetrap": "^1.6.5",
|
|
41
|
-
"@dxos/async": "0.3.4-
|
|
42
|
-
"@dxos/debug": "0.3.4-
|
|
43
|
-
"@dxos/invariant": "0.3.4-
|
|
44
|
-
"@dxos/util": "0.3.4-
|
|
41
|
+
"@dxos/async": "0.3.4-next.1e21f62",
|
|
42
|
+
"@dxos/debug": "0.3.4-next.1e21f62",
|
|
43
|
+
"@dxos/invariant": "0.3.4-next.1e21f62",
|
|
44
|
+
"@dxos/util": "0.3.4-next.1e21f62"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@faker-js/faker": "^8.0.2",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"react": "^18.2.0",
|
|
55
55
|
"react-dom": "^18.2.0",
|
|
56
56
|
"vite": "^4.3.9",
|
|
57
|
-
"@dxos/react-
|
|
58
|
-
"@dxos/react-ui
|
|
59
|
-
"@dxos/react-
|
|
57
|
+
"@dxos/react-client": "0.3.4-next.1e21f62",
|
|
58
|
+
"@dxos/react-ui": "0.3.4-next.1e21f62",
|
|
59
|
+
"@dxos/react-ui-theme": "0.3.4-next.1e21f62"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@phosphor-icons/react": "^2.0.5",
|
package/src/action.ts
CHANGED
|
@@ -63,7 +63,13 @@ export type Action<TProperties extends Record<string, any> = Record<string, any>
|
|
|
63
63
|
removeProperty(key: string): void;
|
|
64
64
|
|
|
65
65
|
addAction<TActionProperties extends Record<string, any> = Record<string, any>>(
|
|
66
|
-
...action:
|
|
66
|
+
...action: ActionArg<TActionProperties>[]
|
|
67
67
|
): Action<TActionProperties>[];
|
|
68
68
|
removeAction(id: string): Action;
|
|
69
69
|
};
|
|
70
|
+
|
|
71
|
+
export type ActionArg<TProperties extends Record<string, any> = Record<string, any>> = Pick<
|
|
72
|
+
Action,
|
|
73
|
+
'id' | 'label' | 'invoke'
|
|
74
|
+
> &
|
|
75
|
+
Partial<Omit<Action<TProperties>, 'id' | 'label' | 'invoke' | 'actions'>> & { actions?: ActionArg[] };
|
package/src/graph-builder.ts
CHANGED
|
@@ -8,9 +8,9 @@ import Mousetrap from 'mousetrap';
|
|
|
8
8
|
|
|
9
9
|
import { EventSubscriptions } from '@dxos/async';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import type { ActionArg, Action } from './action';
|
|
12
12
|
import { Graph } from './graph';
|
|
13
|
-
import {
|
|
13
|
+
import type { NodeArg, Node, NodeBuilder } from './node';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* The builder...
|
|
@@ -71,7 +71,7 @@ export class GraphBuilder {
|
|
|
71
71
|
|
|
72
72
|
private _createNode<TData = null, TProperties extends Record<string, any> = Record<string, any>>(
|
|
73
73
|
getGraph: () => Graph,
|
|
74
|
-
partial:
|
|
74
|
+
partial: NodeArg<TData, TProperties>,
|
|
75
75
|
path: string[] = [],
|
|
76
76
|
ignoreBuilders: string[] = [],
|
|
77
77
|
): Node<TData, TProperties> {
|
|
@@ -85,7 +85,6 @@ export class GraphBuilder {
|
|
|
85
85
|
// TODO(burdon): Document.
|
|
86
86
|
...partial,
|
|
87
87
|
|
|
88
|
-
// TODO(wittjosiah): Default sort.
|
|
89
88
|
get children() {
|
|
90
89
|
return Object.values(node.childrenMap);
|
|
91
90
|
},
|
|
@@ -153,17 +152,22 @@ export class GraphBuilder {
|
|
|
153
152
|
},
|
|
154
153
|
}) as RevertDeepSignal<Node<TData, TProperties>>;
|
|
155
154
|
|
|
155
|
+
// Only actions added at this stage are available to subsequent builders.
|
|
156
|
+
// `addNode` immediately passes the new node to other builders.
|
|
157
|
+
// As such, actions added later with `addAction` are not available to those builders.
|
|
158
|
+
// Having actions available to subsequent builders is useful for building groups.
|
|
159
|
+
partial.actions && partial.actions.forEach((action) => node.addAction(action));
|
|
160
|
+
|
|
156
161
|
return node;
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
private _createAction<TProperties extends Record<string, any> = Record<string, any>>(
|
|
160
|
-
partial:
|
|
165
|
+
partial: ActionArg<TProperties>,
|
|
161
166
|
): Action<TProperties> {
|
|
162
167
|
const action: Action<TProperties> = deepSignal({
|
|
163
168
|
properties: {} as TProperties,
|
|
164
|
-
actionsMap: {},
|
|
165
169
|
...partial,
|
|
166
|
-
|
|
170
|
+
actionsMap: {},
|
|
167
171
|
get actions() {
|
|
168
172
|
return Object.values(action.actionsMap);
|
|
169
173
|
},
|
|
@@ -195,6 +199,8 @@ export class GraphBuilder {
|
|
|
195
199
|
},
|
|
196
200
|
}) as RevertDeepSignal<Action<TProperties>>;
|
|
197
201
|
|
|
202
|
+
partial.actions && partial.actions.forEach((subAction) => action.addAction(subAction));
|
|
203
|
+
|
|
198
204
|
return action;
|
|
199
205
|
}
|
|
200
206
|
}
|
package/src/node.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { type FC } from 'react';
|
|
|
7
7
|
|
|
8
8
|
import type { UnsubscribeCallback } from '@dxos/async';
|
|
9
9
|
|
|
10
|
-
import { type Action, type Label } from './action';
|
|
10
|
+
import { type ActionArg, type Action, type Label } from './action';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Called when a node is added to the graph, allowing other node builders to add children, actions or properties.
|
|
@@ -88,15 +88,21 @@ export type Node<TData = any, TProperties extends Record<string, any> = Record<s
|
|
|
88
88
|
|
|
89
89
|
addNode<TChildData = null, TChildProperties extends Record<string, any> = Record<string, any>>(
|
|
90
90
|
id: string,
|
|
91
|
-
...node:
|
|
91
|
+
...node: NodeArg<TChildData, TChildProperties>[]
|
|
92
92
|
): Node<TChildData, TChildProperties>[];
|
|
93
93
|
removeNode(id: string): Node;
|
|
94
94
|
|
|
95
95
|
addAction<TActionProperties extends Record<string, any> = Record<string, any>>(
|
|
96
|
-
...action:
|
|
96
|
+
...action: ActionArg<TActionProperties>[]
|
|
97
97
|
): Action<TActionProperties>[];
|
|
98
98
|
removeAction(id: string): Action;
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
+
export type NodeArg<TData = null, TProperties extends Record<string, any> = Record<string, any>> = Pick<
|
|
102
|
+
Node,
|
|
103
|
+
'id' | 'label'
|
|
104
|
+
> &
|
|
105
|
+
Partial<Omit<Node<TData, TProperties>, 'id' | 'label' | 'actions'>> & { actions?: ActionArg[] };
|
|
106
|
+
|
|
101
107
|
export const isGraphNode = (data: unknown): data is Node =>
|
|
102
108
|
data && typeof data === 'object' ? 'id' in data && 'label' in data : false;
|