UNPKG

9.07 kBJavaScriptView Raw
1/*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15'use strict';
16
17var Boolean = require('./plugins/Boolean');
18var Integer = require('./plugins/Integer');
19var Long = require('./plugins/Long');
20var Double = require('./plugins/Double');
21var String = require('./plugins/String');
22var DateTime = require('./plugins/DateTime');
23var Resource = require('./plugins/Resource');
24var MonetaryAmount = require('./plugins/MonetaryAmount');
25var seqFunParser = require('./combinators').seqFunParser;
26var withParser = require('./combinators').withParser;
27var Introspector = require('@accordproject/concerto-core').Introspector;
28var ModelVisitor = require('./ModelVisitor');
29var {
30 templateMarkManager,
31 templateToTokens,
32 tokensToUntypedTemplateMarkFragment,
33 templateMarkTypingFromType
34} = require('./templatemarkutil');
35
36/**
37 * Adds entry to parsing table
38 * @param {object} table the parsing table
39 * @param {object} entry the entry for a given type
40 */
41function addEntryToParsingTable(table, entry) {
42 Object.assign(table, entry);
43}
44
45/**
46 * Clone a CiceroMark node
47 * @param {*} serializer the Concerto serializer
48 * @param {*} nodes the nodes to visit
49 * @return {*} the cloned nodes
50 */
51function concertoNodes(serializer, nodes) {
52 var rootNode = {
53 '$class': 'org.accordproject.commonmark.Document',
54 'xmlns': 'http://commonmark.org/xml/1.0',
55 'nodes': nodes
56 };
57 return serializer.fromJSON(rootNode).nodes;
58}
59
60/**
61 * Parsing table for variables
62 * This maps types to their parser
63 * @return {object} the default parsing table
64 */
65function defaultParsingTable() {
66 var table = {};
67 addEntryToParsingTable(table, Boolean);
68 addEntryToParsingTable(table, Integer);
69 addEntryToParsingTable(table, Long);
70 addEntryToParsingTable(table, Double);
71 addEntryToParsingTable(table, String);
72 addEntryToParsingTable(table, DateTime);
73 addEntryToParsingTable(table, Resource);
74 addEntryToParsingTable(table, MonetaryAmount);
75 return table;
76}
77
78/**
79 * Maintains a parsing table
80 * @class
81 */
82class ParsingTable {
83 /**
84 * Create the ParsingTable
85 * @param {*} modelManager - the model manager
86 * @param {*} parserFunOfTemplateMark - how to get a parser from a TemplateMark DOM
87 * @param {*} draftVisitNodes - visitor for drafting
88 */
89 constructor(modelManager, parserFunOfTemplateMark, draftVisitNodes) {
90 this.modelManager = modelManager;
91 this.introspector = new Introspector(this.modelManager);
92
93 // Mapping from types to parsers/drafters
94 this.parsingTable = defaultParsingTable();
95
96 // Hook: How to compile from template mark to parser
97 this.parseFromTemplateMark = function (nodes, elementType, params) {
98 var childrenParser = seqFunParser(nodes.map(function (x) {
99 return parserFunOfTemplateMark(x, params);
100 }));
101 return r => {
102 return withParser(elementType, childrenParser(r));
103 };
104 };
105 // Hook: How to draft from template mark to parser
106 this.draftFromTemplateMark = function (nodes, elementType, params) {
107 return data => {
108 var cNodes = concertoNodes(params.templateMarkSerializer, nodes);
109 var childrenParameters = {
110 parserManager: params.parserManager,
111 templateMarkModelManager: params.templateMarkModelManager,
112 templateMarkSerializer: params.templateMarkSerializer,
113 data: data,
114 kind: 'clause'
115 };
116 return draftVisitNodes(params.visitor, cNodes, childrenParameters);
117 };
118 };
119 // Hook: How to compile from CTO to ciceromark
120 this.templateMarkFromModel = function (name, model, elementType) {
121 var modelVisitor = new ModelVisitor();
122 var genericParameters = {
123 name: name
124 };
125 var generic = model.accept(modelVisitor, genericParameters);
126 var validated = templateMarkManager.serializer.toJSON(templateMarkManager.serializer.fromJSON(generic));
127 return validated.nodes;
128 };
129 }
130
131 /**
132 * Gets parsing table for variables
133 * @return {object} the parsing table
134 */
135 getParsingTable() {
136 return this.parsingTable;
137 }
138
139 /**
140 * Sets parsing table for variables
141 * @param {object} table the parsing table
142 */
143 setParsingTable(table) {
144 this.parsingTable = table;
145 }
146
147 /**
148 * Adds parsing table for variables
149 * @param {object} table the parsing table
150 */
151 addParsingTable(table) {
152 this.parsingTable = Object.assign(this.parsingTable, table);
153 }
154
155 /**
156 * Adds entry to parsing table
157 * @param {object} entry the entry for a given type
158 */
159 addParsingTableEntry(entry) {
160 addEntryToParsingTable(this.parsingTable, entry);
161 }
162
163 /**
164 * Compile a CTO model into its TemplateMark equivalent
165 * @param {string} name the property name
166 * @param {object} parsingTable the parsing table
167 * @param {string} elementType the type
168 */
169 compileModel(name, parsingTable, elementType) {
170 var model = this.introspector.getClassDeclaration(elementType);
171 var templateMark = this.templateMarkFromModel(name, model, elementType);
172 parsingTable[elementType] = {};
173 parsingTable[elementType].templatemark = {};
174 parsingTable[elementType].templatemark.nodes = templateMark;
175 }
176
177 /**
178 * Compile an entry into its JavaScript equivalent
179 * @param {object} entry the parsing table entry for this type
180 * @param {string} elementType the type
181 * @param {object} parseParams parameters for the nested parse generation
182 * @param {object} draftParams parameters for the nested draft generation
183 */
184 compileEntry(entry, elementType, parseParams, draftParams) {
185 if (Object.prototype.hasOwnProperty.call(entry, 'inline')) {
186 var tokenStream = templateToTokens(entry.inline);
187 var template = tokensToUntypedTemplateMarkFragment(tokenStream);
188 entry.templatemark = {};
189 entry.templatemark.nodes = template.nodes[0].nodes[0].nodes; // XXX not robust beyond a paragraph
190 }
191
192 if (Object.prototype.hasOwnProperty.call(entry, 'templatemark')) {
193 var _template = entry.templatemark.nodes;
194 var typedTemplate = templateMarkTypingFromType(_template, this.modelManager, elementType);
195 if (parseParams) {
196 var parse = this.parseFromTemplateMark(typedTemplate, elementType, parseParams);
197 if (!Object.prototype.hasOwnProperty.call(entry, 'javascript')) {
198 entry.javascript = {};
199 }
200 entry.javascript.parse = format => parse;
201 }
202 if (draftParams) {
203 var draft = this.draftFromTemplateMark(typedTemplate, elementType, draftParams);
204 if (!Object.prototype.hasOwnProperty.call(entry, 'javascript')) {
205 entry.javascript = {};
206 }
207 entry.javascript.draft = draft;
208 }
209 }
210 }
211
212 /**
213 * Gets parser for a given type
214 * @param {string} name - the property
215 * @param {string} elementType - the type of this node
216 * @param {string} format - the format
217 * @param {object} parseParams - parameters for the nested parse generation
218 * @return {*} the parser
219 */
220 getParser(name, elementType, format, parseParams) {
221 var parsingTable = this.getParsingTable();
222 if (!parsingTable[elementType]) {
223 this.compileModel(name, parsingTable, elementType);
224 }
225 var entry = parsingTable[elementType];
226 if (!Object.prototype.hasOwnProperty.call(entry, 'javascript' || !entry.javascript.parse)) {
227 this.compileEntry(entry, elementType, parseParams, null);
228 }
229 if (Object.prototype.hasOwnProperty.call(entry, 'javascript') && entry.javascript.parse) {
230 return entry.javascript.parse(format, parseParams.parserManager);
231 } else {
232 throw new Error('No known parser for type ' + elementType);
233 }
234 }
235
236 /**
237 * Gets drafter for a given type
238 * @param {string} name the property
239 * @param {string} elementType the type
240 * @param {string} format the format
241 * @param {object} draftParams parameters for the nested draft generation
242 * @return {*} the drafter
243 */
244 getDrafter(name, elementType, format, draftParams) {
245 var parsingTable = this.getParsingTable();
246 if (!parsingTable[elementType]) {
247 this.compileModel(name, parsingTable, elementType);
248 }
249 var entry = parsingTable[elementType];
250 if (!Object.prototype.hasOwnProperty.call(entry, 'javascript') || !entry.javascript.draft) {
251 this.compileEntry(entry, elementType, null, draftParams);
252 }
253 if (Object.prototype.hasOwnProperty.call(entry, 'javascript') && entry.javascript.draft) {
254 return entry.javascript.draft;
255 } else {
256 throw new Error('No known parser for type ' + elementType);
257 }
258 }
259}
260module.exports = ParsingTable;
\No newline at end of file