1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | 'use strict';
|
15 |
|
16 | function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
|
17 |
|
18 | function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
|
19 |
|
20 | function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
|
21 |
|
22 | function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
23 |
|
24 | const Logger = require('@accordproject/ergo-compiler').Logger;
|
25 |
|
26 | const crypto = require('crypto');
|
27 |
|
28 | const Util = require('@accordproject/ergo-compiler').Util;
|
29 |
|
30 | const moment = require('moment-mini');
|
31 |
|
32 |
|
33 | moment.fn.toJSON = Util.momentToJson;
|
34 |
|
35 | const RelationshipDeclaration = require('composer-concerto').RelationshipDeclaration;
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | class TemplateInstance {
|
50 | |
51 |
|
52 |
|
53 |
|
54 | constructor(template) {
|
55 | if (this.constructor === TemplateInstance) {
|
56 | throw new TypeError('Abstract class "TemplateInstance" cannot be instantiated directly.');
|
57 | }
|
58 |
|
59 | this.template = template;
|
60 | this.data = null;
|
61 | this.composerData = null;
|
62 | }
|
63 | |
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | setData(data) {
|
72 |
|
73 | const templateModel = this.getTemplate().getTemplateModel();
|
74 |
|
75 | if (data.$class !== templateModel.getFullyQualifiedName()) {
|
76 | throw new Error("Invalid data, must be a valid instance of the template model ".concat(templateModel.getFullyQualifiedName(), " but got: ").concat(JSON.stringify(data), " "));
|
77 | }
|
78 |
|
79 |
|
80 | Logger.debug('Setting clause data: ' + JSON.stringify(data));
|
81 | const resource = this.getTemplate().getSerializer().fromJSON(data);
|
82 | resource.validate();
|
83 |
|
84 | this.data = data;
|
85 |
|
86 | this.composerData = resource;
|
87 | }
|
88 | |
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 | getData() {
|
96 | return this.data;
|
97 | }
|
98 | |
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | getDataAsComposerObject() {
|
106 | return this.composerData;
|
107 | }
|
108 | |
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 | parse(text, currentTime) {
|
116 |
|
117 | const now = Util.setCurrentTime(currentTime);
|
118 | const utcOffset = now.utcOffset();
|
119 | let parser = this.getTemplate().getParserManager().getParser();
|
120 | parser.feed(text);
|
121 |
|
122 | if (parser.results.length !== 1) {
|
123 | const head = JSON.stringify(parser.results[0]);
|
124 | parser.results.forEach(function (element) {
|
125 | if (head !== JSON.stringify(element)) {
|
126 | throw new Error('Ambiguous text. Got ' + parser.results.length + ' ASTs for text: ' + text);
|
127 | }
|
128 | }, this);
|
129 | }
|
130 |
|
131 | let ast = parser.results[0];
|
132 | Logger.debug('Result of parsing: ' + JSON.stringify(ast));
|
133 |
|
134 | if (!ast) {
|
135 | throw new Error('Parsing clause text returned a null AST. This may mean the text is valid, but not complete.');
|
136 | }
|
137 |
|
138 | ast = TemplateInstance.convertDateTimes(ast, utcOffset);
|
139 | this.setData(ast);
|
140 | }
|
141 | |
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | static pad(n, width) {
|
151 | let z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '0';
|
152 | n = n + '';
|
153 | return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
|
154 | }
|
155 | |
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | static convertDateTimes(obj, utcOffset) {
|
165 | if (obj.$class === 'ParsedDateTime') {
|
166 | let instance = null;
|
167 |
|
168 | if (obj.timezone) {
|
169 | instance = moment([obj.years, obj.months, obj.days, obj.hours, obj.minutes, obj.seconds, obj.milliseconds]).utcOffset(obj.timezone, true);
|
170 | } else {
|
171 | instance = moment(obj).utcOffset(utcOffset, true);
|
172 | }
|
173 |
|
174 | if (!instance) {
|
175 | throw new Error("Failed to handle datetime ".concat(JSON.stringify(obj, null, 4)));
|
176 | }
|
177 |
|
178 | const result = instance.format('YYYY-MM-DDTHH:mm:ss.SSSZ');
|
179 |
|
180 | if (result === 'Invalid date') {
|
181 | throw new Error("Failed to handle datetime ".concat(JSON.stringify(obj, null, 4)));
|
182 | }
|
183 |
|
184 | return result;
|
185 | } else if (typeof obj === 'object' && obj !== null) {
|
186 | Object.entries(obj).forEach((_ref) => {
|
187 | let _ref2 = _slicedToArray(_ref, 2),
|
188 | key = _ref2[0],
|
189 | value = _ref2[1];
|
190 |
|
191 | obj[key] = TemplateInstance.convertDateTimes(value, utcOffset);
|
192 | });
|
193 | }
|
194 |
|
195 | return obj;
|
196 | }
|
197 | |
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 | generateText() {
|
206 | if (!this.composerData) {
|
207 | throw new Error('Data has not been set. Call setData or parse before calling this method.');
|
208 | }
|
209 |
|
210 | const ast = this.getTemplate().getParserManager().getTemplateAst();
|
211 |
|
212 | let result = '';
|
213 |
|
214 | for (let n = 0; n < ast.data.length; n++) {
|
215 | const thing = ast.data[n];
|
216 |
|
217 | switch (thing.type) {
|
218 | case 'LastChunk':
|
219 | case 'Chunk':
|
220 | result += thing.value;
|
221 | break;
|
222 |
|
223 | case 'BooleanBinding':
|
224 | {
|
225 | const property = this.getTemplate().getTemplateModel().getProperty(thing.fieldName.value);
|
226 |
|
227 | if (this.composerData[property.getName()]) {
|
228 | result += thing.string.value.substring(1, thing.string.value.length - 1);
|
229 | }
|
230 | }
|
231 | break;
|
232 |
|
233 | case 'FormattedBinding':
|
234 | case 'Binding':
|
235 | {
|
236 | const property = this.getTemplate().getTemplateModel().getProperty(thing.fieldName.value);
|
237 | const value = this.composerData[property.getName()];
|
238 | result += this.convertPropertyToString(property, value, thing.format ? thing.format.value : null);
|
239 | }
|
240 | break;
|
241 |
|
242 | default:
|
243 | throw new Error('Unrecognized item: ' + thing.type);
|
244 | }
|
245 | }
|
246 |
|
247 | return result;
|
248 | }
|
249 | |
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | convertClassToString(clazz, obj) {
|
259 | const properties = clazz.getProperties();
|
260 | let result = '';
|
261 |
|
262 | for (let n = 0; n < properties.length; n++) {
|
263 | const child = properties[n];
|
264 | result += this.convertPropertyToString(child, obj[child.getName()]);
|
265 |
|
266 | if (n < properties.length - 1) {
|
267 | result += ' ';
|
268 | }
|
269 | }
|
270 |
|
271 | return result;
|
272 | }
|
273 | |
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 |
|
283 | static formatDateTime(date, format) {
|
284 | if (!format) {
|
285 | format = 'MM/DD/YYYY';
|
286 | }
|
287 |
|
288 | const instance = moment.parseZone(date);
|
289 | return instance.format(format);
|
290 | }
|
291 | |
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 | convertPropertyToString(property, obj, format) {
|
302 | if (property.isOptional() === false && !obj) {
|
303 | throw new Error("Required property ".concat(property.getFullyQualifiedName(), " is null."));
|
304 | }
|
305 |
|
306 | if (property instanceof RelationshipDeclaration) {
|
307 | return "\"".concat(obj.getIdentifier(), "\"");
|
308 | }
|
309 |
|
310 | if (property.isTypeEnum()) {
|
311 | return obj;
|
312 | }
|
313 |
|
314 | if (format) {
|
315 |
|
316 | format = format.substr(1, format.length - 2);
|
317 | }
|
318 |
|
319 |
|
320 |
|
321 |
|
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 | switch (property.getFullyQualifiedTypeName()) {
|
332 | case 'String':
|
333 | return "\"".concat(obj, "\"");
|
334 |
|
335 | case 'Integer':
|
336 | case 'Long':
|
337 | case 'Double':
|
338 | return obj.toString();
|
339 |
|
340 | case 'DateTime':
|
341 | return TemplateInstance.formatDateTime(obj, format);
|
342 |
|
343 | case 'Boolean':
|
344 | if (obj) {
|
345 | return 'true';
|
346 | } else {
|
347 | return 'false';
|
348 | }
|
349 |
|
350 | default:
|
351 | return this.convertClassToString(this.getTemplate().getTemplateModel().getModelFile().getModelManager().getType(property.getFullyQualifiedTypeName()), obj);
|
352 | }
|
353 | }
|
354 | |
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 | getIdentifier() {
|
362 | let hash = '';
|
363 |
|
364 | if (this.data) {
|
365 | const textToHash = JSON.stringify(this.getData());
|
366 | const hasher = crypto.createHash('sha256');
|
367 | hasher.update(textToHash);
|
368 | hash = '-' + hasher.digest('hex');
|
369 | }
|
370 |
|
371 | return this.getTemplate().getIdentifier() + hash;
|
372 | }
|
373 | |
374 |
|
375 |
|
376 |
|
377 |
|
378 |
|
379 | getTemplate() {
|
380 | return this.template;
|
381 | }
|
382 | |
383 |
|
384 |
|
385 |
|
386 |
|
387 |
|
388 | getTemplateLogic() {
|
389 | return this.template.getTemplateLogic();
|
390 | }
|
391 | |
392 |
|
393 |
|
394 |
|
395 |
|
396 |
|
397 | toJSON() {
|
398 | return {
|
399 | template: this.getTemplate().getIdentifier(),
|
400 | data: this.getData()
|
401 | };
|
402 | }
|
403 |
|
404 | }
|
405 |
|
406 | module.exports = TemplateInstance; |
\ | No newline at end of file |