Skip to content

Commit 69d59d4

Browse files
committed
JSON generator: use node definition metadata
1 parent 1113bce commit 69d59d4

File tree

2 files changed

+61
-31
lines changed

2 files changed

+61
-31
lines changed

src/interop/json.ts

+30-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {ensureNodeDefinition, Node} from "../model/model";
2-
import {ReferenceByName} from "../model/naming";
32
import {Indexer} from "./indexing";
43

54
export const TO_JSON_SYMBOL = Symbol("toJSON");
@@ -14,46 +13,51 @@ export class JSONGenerator {
1413
}
1514
}
1615

17-
Node.prototype[TO_JSON_SYMBOL] = function (withIds?: Indexer) {
18-
const def = ensureNodeDefinition(this);
16+
export function defaultToJSON(node: Node, withIds?: Indexer) {
17+
const def = ensureNodeDefinition(node);
1918
const result = {
2019
type: (def.package ? def.package + "." : "") + def.name
2120
};
2221

2322
if (withIds) {
24-
const id = withIds.getId(this);
25-
if (id)
23+
const id = withIds.getId(node);
24+
if (id) {
2625
result["id"] = id;
26+
}
2727
}
2828

29-
const node = this as Node;
30-
for(const p in node) {
31-
if(p == 'parent' || p == 'parseTreeNode') {
32-
continue;
33-
}
34-
const element = node[p];
35-
if(element !== undefined && element !== null) {
36-
const containment = node.containment(p);
37-
if(containment) {
38-
if(containment.multiple) {
39-
result[p] = element.map(e => toJSON(e));
40-
} else {
41-
result[p] = toJSON(element, withIds);
29+
for(const p in node.nodeDefinition.features) {
30+
const feature = node.nodeDefinition.features[p];
31+
if(feature.child) {
32+
if(feature.multiple) {
33+
const children = node.getChildren(p);
34+
if (children.length > 0) {
35+
result[p] = children.map(e => toJSON(e, withIds));
36+
}
37+
} else {
38+
const child = node.getChild(p);
39+
if (child) {
40+
result[p] = toJSON(child, withIds);
4241
}
4342
}
44-
else if (element instanceof ReferenceByName) {
45-
const reference = element as ReferenceByName<any>;
43+
} else if (feature.reference) {
44+
const reference = node.getReference(p);
45+
if (reference) {
4646
result[p] = {
47-
name: reference.name
48-
}
49-
if (withIds) {
50-
result[p]["referred"] = reference.resolved ? withIds.getId(reference.referred) : undefined;
47+
name: reference.name,
48+
referred: reference.resolved ? withIds?.getId(reference.referred) : undefined
5149
}
5250
}
53-
else if(typeof node[p] !== "function") {
54-
result[p] = node[p];
51+
} else {
52+
const attributeValue = node.getAttributeValue(p);
53+
if (attributeValue !== undefined) {
54+
result[p] = attributeValue;
5555
}
5656
}
5757
}
5858
return result;
5959
}
60+
61+
Node.prototype[TO_JSON_SYMBOL] = function (withIds?: Indexer) {
62+
return defaultToJSON(this as Node, withIds);
63+
}

tests/json.test.ts

+31-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import {expect} from "chai";
22

3-
import {ASTNode, Child, Children, GenericNode, Node, PossiblyNamed, Reference, ReferenceByName} from "../src";
3+
import {
4+
ASTNode,
5+
Attribute,
6+
Child,
7+
Children,
8+
GenericNode,
9+
Node,
10+
PossiblyNamed,
11+
Reference,
12+
ReferenceByName
13+
} from "../src";
414
import {Indexer, JSONGenerator} from "../src";
515

616
describe('JSON generator', function() {
@@ -182,6 +192,7 @@ describe('JSON generator', function() {
182192

183193
@ASTNode("", "NodeWithChildren")
184194
class NodeWithChildren extends Node {
195+
@Attribute()
185196
payload: number;
186197
@Child()
187198
singleChild: NodeWithChildren;
@@ -191,26 +202,41 @@ class NodeWithChildren extends Node {
191202

192203
@ASTNode("", "DummyNamedNode")
193204
class DummyNamedNode extends Node implements PossiblyNamed {
194-
constructor(public name?: string) {
205+
@Attribute()
206+
public name?: string;
207+
208+
constructor(name?: string) {
195209
super();
210+
this.name = name;
196211
}
197212
}
198213

199214
@ASTNode("", "NodeWithReference")
200215
class NodeWithReference extends Node implements PossiblyNamed {
201-
constructor(public name?: string, public reference?: ReferenceByName<DummyNamedNode>) {
216+
@Attribute()
217+
public name?: string;
218+
@Reference()
219+
public reference?: ReferenceByName<DummyNamedNode>;
220+
221+
constructor(name?: string, reference?: ReferenceByName<DummyNamedNode>) {
202222
super();
223+
this.name = name;
224+
this.reference = reference;
203225
}
204226

205227
@Child() namedNode?: DummyNamedNode;
206228
}
207229

208230
@ASTNode("", "NodeWithSelfReference")
209231
class NodeWithSelfReference extends Node implements PossiblyNamed {
210-
@Reference() public reference?: ReferenceByName<NodeWithSelfReference>;
232+
@Attribute()
233+
public name?: string;
234+
@Reference()
235+
public reference?: ReferenceByName<NodeWithSelfReference>;
211236

212-
constructor(public name?: string, reference?: ReferenceByName<NodeWithSelfReference>) {
237+
constructor(name?: string, reference?: ReferenceByName<NodeWithSelfReference>) {
213238
super();
239+
this.name = name;
214240
this.reference = reference;
215241
}
216242
}

0 commit comments

Comments
 (0)