frontend-app-api: make app node serializable
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -47,6 +47,49 @@ describe('buildAppGraph', () => {
|
||||
]);
|
||||
expect([...graph.rootNodes.keys()]).toEqual(['a', 'b', 'c']);
|
||||
expect([...graph.orphanNodes.keys()]).toEqual(['dx1']);
|
||||
|
||||
expect(JSON.parse(JSON.stringify([...graph.rootNodes.values()])))
|
||||
.toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"id": "a",
|
||||
},
|
||||
{
|
||||
"attachments": {
|
||||
"x": [
|
||||
{
|
||||
"id": "bx1",
|
||||
},
|
||||
{
|
||||
"id": "bx2",
|
||||
},
|
||||
],
|
||||
"y": [
|
||||
{
|
||||
"id": "by1",
|
||||
},
|
||||
],
|
||||
},
|
||||
"id": "b",
|
||||
},
|
||||
{
|
||||
"id": "c",
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(String(graph.rootNodes.get('a'))).toMatchInlineSnapshot(`"<a />"`);
|
||||
expect(String(graph.rootNodes.get('b'))).toMatchInlineSnapshot(`
|
||||
"<b>
|
||||
x [
|
||||
<bx1 />
|
||||
<bx2 />
|
||||
]
|
||||
y [
|
||||
<by1 />
|
||||
]
|
||||
</b>"
|
||||
`);
|
||||
expect(String(graph.rootNodes.get('c'))).toMatchInlineSnapshot(`"<c />"`);
|
||||
});
|
||||
|
||||
it('should create a graph out of order', () => {
|
||||
@@ -61,6 +104,20 @@ describe('buildAppGraph', () => {
|
||||
]);
|
||||
expect([...graph.rootNodes.keys()]).toEqual(['a', 'b', 'c']);
|
||||
expect([...graph.orphanNodes.keys()]).toEqual(['dx1']);
|
||||
|
||||
expect(String(graph.rootNodes.get('a'))).toMatchInlineSnapshot(`"<a />"`);
|
||||
expect(String(graph.rootNodes.get('b'))).toMatchInlineSnapshot(`
|
||||
"<b>
|
||||
x [
|
||||
<bx2 />
|
||||
<bx1 />
|
||||
]
|
||||
y [
|
||||
<by1 />
|
||||
]
|
||||
</b>"
|
||||
`);
|
||||
expect(String(graph.rootNodes.get('c'))).toMatchInlineSnapshot(`"<c />"`);
|
||||
});
|
||||
|
||||
it('throws an error when duplicated extensions are detected', () => {
|
||||
|
||||
@@ -14,14 +14,71 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AppNode, AppNodeEdges, AppNodeSpec, Mutable } from './types';
|
||||
import {
|
||||
AppGraph,
|
||||
AppNode,
|
||||
AppNodeEdges,
|
||||
AppNodeInstance,
|
||||
AppNodeSpec,
|
||||
Mutable,
|
||||
} from './types';
|
||||
|
||||
function indent(str: string) {
|
||||
return str.replace(/^/gm, ' ');
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
class SerializableAppNode implements AppNode {
|
||||
public readonly spec: AppNodeSpec;
|
||||
public readonly edges: AppNodeEdges = { attachments: new Map() };
|
||||
public readonly instance?: AppNodeInstance;
|
||||
|
||||
constructor(spec: AppNodeSpec) {
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
const dataRefs = this.instance && [...this.instance.getDataRefs()];
|
||||
return {
|
||||
id: this.spec.id,
|
||||
output:
|
||||
dataRefs && dataRefs.length > 0
|
||||
? dataRefs.map(ref => ref.id)
|
||||
: undefined,
|
||||
attachments:
|
||||
this.edges.attachments.size > 0
|
||||
? Object.fromEntries(this.edges.attachments)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
toString() {
|
||||
const dataRefs = this.instance && [...this.instance.getDataRefs()];
|
||||
const out =
|
||||
dataRefs && dataRefs.length > 0
|
||||
? ` out=[${[...dataRefs.keys()].join(', ')}]`
|
||||
: '';
|
||||
|
||||
if (this.edges.attachments.size === 0) {
|
||||
return `<${this.spec.id}${out} />`;
|
||||
}
|
||||
|
||||
return [
|
||||
`<${this.spec.id}${out}>`,
|
||||
...[...this.edges.attachments.entries()].map(([k, v]) =>
|
||||
indent([`${k} [`, ...v.map(e => indent(e.toString())), `]`].join('\n')),
|
||||
),
|
||||
`</${this.spec.id}>`,
|
||||
].join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the app graph by iterating through all node specs and constructing the app
|
||||
* tree with all attachments in the same order as they appear in the input specs array.
|
||||
* @internal
|
||||
*/
|
||||
export function buildAppGraph(specs: AppNodeSpec[]) {
|
||||
export function buildAppGraph(specs: AppNodeSpec[]): AppGraph {
|
||||
const nodes = new Map<string, AppNode>();
|
||||
const rootNodes = new Map<string, AppNode>();
|
||||
// While iterating through the inputs specs we keep track of all nodes that were created
|
||||
@@ -39,12 +96,7 @@ export function buildAppGraph(specs: AppNodeSpec[]) {
|
||||
throw new Error(`Unexpected duplicate extension id '${spec.id}'`);
|
||||
}
|
||||
|
||||
const node: AppNode = {
|
||||
spec,
|
||||
edges: {
|
||||
attachments: new Map(),
|
||||
},
|
||||
};
|
||||
const node = new SerializableAppNode(spec);
|
||||
nodes.set(spec.id, node);
|
||||
|
||||
if (spec.attachTo) {
|
||||
|
||||
@@ -52,7 +52,7 @@ export interface AppNodeEdges {
|
||||
* @public
|
||||
*/
|
||||
export interface AppNodeInstance {
|
||||
getDataRefs(): ExtensionDataRef<unknown>[];
|
||||
getDataRefs(): Iterable<ExtensionDataRef<unknown>>;
|
||||
getData<T>(ref: ExtensionDataRef<T>): T | unknown;
|
||||
}
|
||||
|
||||
@@ -71,4 +71,5 @@ export interface AppNode {
|
||||
|
||||
export interface AppGraph {
|
||||
rootNodes: Map<string, AppNode>;
|
||||
orphanNodes: Map<string, AppNode>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user