1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | 'use strict';
|
16 |
|
17 | const ClassDeclaration = require('../introspect/classdeclaration');
|
18 | const Field = require('../introspect/field');
|
19 | const RelationshipDeclaration = require('../introspect/relationshipdeclaration');
|
20 | const Resource = require('../model/resource');
|
21 | const Identifiable = require('../model/identifiable');
|
22 | const Typed = require('../model/typed');
|
23 | const Concept = require('../model/concept');
|
24 | const ModelUtil = require('../modelutil');
|
25 | const Util = require('../util');
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | class JSONGenerator {
|
38 |
|
39 | |
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 | constructor(convertResourcesToRelationships, permitResourcesForRelationships, deduplicateResources, convertResourcesToId, ergo) {
|
53 | this.convertResourcesToRelationships = convertResourcesToRelationships;
|
54 | this.permitResourcesForRelationships = permitResourcesForRelationships;
|
55 | this.deduplicateResources = deduplicateResources;
|
56 | this.convertResourcesToId = convertResourcesToId;
|
57 | this.ergo = ergo;
|
58 | }
|
59 |
|
60 | |
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | visit(thing, parameters) {
|
68 | if (thing instanceof ClassDeclaration) {
|
69 | return this.visitClassDeclaration(thing, parameters);
|
70 | } else if (thing instanceof RelationshipDeclaration) {
|
71 | return this.visitRelationshipDeclaration(thing, parameters);
|
72 | } else if (thing instanceof Field) {
|
73 | return this.visitField(thing, parameters);
|
74 | } else {
|
75 | throw new Error('Unrecognised ' + JSON.stringify(thing));
|
76 | }
|
77 | }
|
78 |
|
79 | |
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | visitClassDeclaration(classDeclaration, parameters) {
|
87 |
|
88 | const obj = parameters.stack.pop();
|
89 | if (!((obj instanceof Resource) || (obj instanceof Concept))) {
|
90 | throw new Error('Expected a Resource or a Concept, but found ' + obj);
|
91 | }
|
92 |
|
93 | let result = {};
|
94 | let id = null;
|
95 |
|
96 | if (obj instanceof Identifiable && this.deduplicateResources) {
|
97 | id = obj.toURI();
|
98 | if( parameters.dedupeResources.has(id)) {
|
99 | return id;
|
100 | }
|
101 | else {
|
102 | parameters.dedupeResources.add(id);
|
103 | }
|
104 | }
|
105 |
|
106 | result.$class = classDeclaration.getFullyQualifiedName();
|
107 | if(this.deduplicateResources && id) {
|
108 | result.$id = id;
|
109 | }
|
110 |
|
111 |
|
112 | const properties = classDeclaration.getProperties();
|
113 | for (let index in properties) {
|
114 | const property = properties[index];
|
115 | const value = obj[property.getName()];
|
116 | if (!Util.isNull(value)) {
|
117 | parameters.stack.push(value);
|
118 | result[property.getName()] = property.accept(this, parameters);
|
119 | }
|
120 | }
|
121 |
|
122 | return result;
|
123 | }
|
124 |
|
125 | |
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | visitField(field, parameters) {
|
133 | const obj = parameters.stack.pop();
|
134 | let result;
|
135 | if (field.isArray()) {
|
136 | let array = [];
|
137 |
|
138 | for (let index in obj) {
|
139 | const item = obj[index];
|
140 | if (!field.isPrimitive() && !ModelUtil.isEnum(field)) {
|
141 | parameters.stack.push(item, Typed);
|
142 | const classDeclaration = parameters.modelManager.getType(item.getFullyQualifiedType());
|
143 | array.push(classDeclaration.accept(this, parameters));
|
144 | } else {
|
145 | array.push(this.convertToJSON(field, item));
|
146 | }
|
147 | }
|
148 | result = array;
|
149 | } else if (field.isPrimitive()) {
|
150 | result = this.convertToJSON(field, obj);
|
151 | } else if (ModelUtil.isEnum(field)) {
|
152 | if (this.ergo) {
|
153 |
|
154 | const enumDeclaration = field.getParent().getModelFile().getType(field.getType());
|
155 | const enumName = enumDeclaration.getFullyQualifiedName();
|
156 | const properties = enumDeclaration.getProperties();
|
157 | let either = { 'left' : obj };
|
158 | for(let n=0; n < properties.length; n++) {
|
159 | const property = properties[n];
|
160 | if(property.getName() === obj) {
|
161 | break;
|
162 | } else {
|
163 | either = { 'right' : either };
|
164 | }
|
165 | }
|
166 | result = { 'type' : [enumName], 'data': either };
|
167 | } else {
|
168 | result = this.convertToJSON(field, obj);
|
169 | }
|
170 | } else {
|
171 | parameters.stack.push(obj);
|
172 | const classDeclaration = parameters.modelManager.getType(obj.getFullyQualifiedType());
|
173 | result = classDeclaration.accept(this, parameters);
|
174 | }
|
175 |
|
176 | return result;
|
177 | }
|
178 |
|
179 | |
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 | convertToJSON(field, obj) {
|
187 | switch (field.getType()) {
|
188 | case 'DateTime':
|
189 | {
|
190 | if (this.ergo) {
|
191 | return obj;
|
192 | } else {
|
193 | return obj.isUtc() ? obj.format('YYYY-MM-DDTHH:mm:ss.SSS[Z]') : obj.format('YYYY-MM-DDTHH:mm:ss.SSSZ');
|
194 | }
|
195 | }
|
196 | case 'Integer':
|
197 | case 'Long': {
|
198 | if (this.ergo) {
|
199 | return { nat: obj };
|
200 | } else {
|
201 | return obj;
|
202 | }
|
203 | }
|
204 | case 'Double':
|
205 | case 'Boolean':
|
206 | default:
|
207 | {
|
208 | return obj;
|
209 | }
|
210 | }
|
211 | }
|
212 |
|
213 | |
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 | visitRelationshipDeclaration(relationshipDeclaration, parameters) {
|
221 | const obj = parameters.stack.pop();
|
222 | let result;
|
223 |
|
224 | if (relationshipDeclaration.isArray()) {
|
225 | let array = [];
|
226 |
|
227 | for (let index in obj) {
|
228 | const item = obj[index];
|
229 | if (this.permitResourcesForRelationships && item instanceof Resource) {
|
230 | let fqi = item.getFullyQualifiedIdentifier();
|
231 | if (parameters.seenResources.has(fqi)) {
|
232 | let relationshipText = this.getRelationshipText(relationshipDeclaration, item);
|
233 | array.push(relationshipText);
|
234 | } else {
|
235 | parameters.seenResources.add(fqi);
|
236 | parameters.stack.push(item, Resource);
|
237 | const classDecl = parameters.modelManager.getType(relationshipDeclaration.getFullyQualifiedTypeName());
|
238 | array.push(classDecl.accept(this, parameters));
|
239 | parameters.seenResources.delete(fqi);
|
240 | }
|
241 | } else {
|
242 | let relationshipText = this.getRelationshipText(relationshipDeclaration, item);
|
243 | array.push(relationshipText);
|
244 | }
|
245 | }
|
246 | result = array;
|
247 | } else if (this.permitResourcesForRelationships && obj instanceof Resource) {
|
248 | let fqi = obj.getFullyQualifiedIdentifier();
|
249 | if (parameters.seenResources.has(fqi)) {
|
250 | let relationshipText = this.getRelationshipText(relationshipDeclaration, obj);
|
251 | result = relationshipText;
|
252 | } else {
|
253 | parameters.seenResources.add(fqi);
|
254 | parameters.stack.push(obj, Resource);
|
255 | const classDecl = parameters.modelManager.getType(relationshipDeclaration.getFullyQualifiedTypeName());
|
256 | result = classDecl.accept(this, parameters);
|
257 | parameters.seenResources.delete(fqi);
|
258 | }
|
259 | } else {
|
260 | let relationshipText = this.getRelationshipText(relationshipDeclaration, obj);
|
261 | result = relationshipText;
|
262 | }
|
263 | return result;
|
264 | }
|
265 |
|
266 | |
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 | getRelationshipText(relationshipDeclaration, relationshipOrResource) {
|
273 | if (relationshipOrResource instanceof Resource) {
|
274 | const allowRelationships =
|
275 | this.convertResourcesToRelationships || this.permitResourcesForRelationships;
|
276 | if (!allowRelationships) {
|
277 | throw new Error('Did not find a relationship for ' + relationshipDeclaration.getFullyQualifiedTypeName() + ' found ' + relationshipOrResource);
|
278 | }
|
279 | }
|
280 | if (this.convertResourcesToId) {
|
281 | return relationshipOrResource.getIdentifier();
|
282 | } else {
|
283 | return relationshipOrResource.toURI();
|
284 | }
|
285 | }
|
286 | }
|
287 |
|
288 | module.exports = JSONGenerator;
|