UNPKG

7.43 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'use strict';
15/**
16 * Unquote strings
17 * @param {string} value - the string
18 * @return {string} the unquoted string
19 */
20
21function unquoteString(value) {
22 return value.substring(1, value.length - 1);
23}
24/**
25 * Converts a CiceroMark DOM to a PDF Make JSON.
26 * http://pdfmake.org/playground.html
27 */
28
29
30class ToPdfMakeVisitor {
31 /**
32 * Construct the visitor
33 * @param {*} [options] configuration options
34 */
35 constructor(options) {
36 this.options = options;
37 }
38 /**
39 * Apply marks to a leaf node
40 * @param {*} leafNode the leaf node
41 * @param {*} parameters the parameters
42 */
43
44
45 static applyMarks(leafNode, parameters) {
46 if (parameters.emph) {
47 leafNode.style = 'Emph';
48 leafNode.italics = true;
49 }
50
51 if (parameters.strong) {
52 leafNode.style = 'Strong';
53 leafNode.bold = true;
54 }
55
56 if (parameters.code) {
57 leafNode.style = 'Code';
58 }
59 }
60 /**
61 * Converts a formatted text node to a slate text node with marks
62 * @param {*} thing a concerto Strong, Emph or Text node
63 * @param {*} parameters the parameters
64 * @returns {*} the slate text node with marks
65 */
66
67
68 static handleFormattedText(thing, parameters) {
69 const textNode = {
70 text: ToPdfMakeVisitor.getText(thing)
71 };
72 this.applyMarks(textNode, parameters);
73 return textNode;
74 }
75 /**
76 * Gets the text value from a formatted sub-tree
77 * @param {*} thing a concerto Strong, Emph or Text node
78 * @returns {string} the 'text' property of the formatted sub-tree
79 */
80
81
82 static getText(thing) {
83 if (thing.getType() === 'Text') {
84 return thing.text;
85 } else {
86 if (thing.nodes && thing.nodes.length > 0) {
87 return ToPdfMakeVisitor.getText(thing.nodes[0]);
88 } else {
89 return '';
90 }
91 }
92 }
93 /**
94 * Converts a heading level to a heading style name
95 * @param {*} thing concert heading node
96 * @returns {string} the heading type
97 */
98
99
100 static getHeadingType(thing) {
101 switch (thing.level) {
102 case '1':
103 return 'heading_one';
104
105 case '2':
106 return 'heading_two';
107
108 case '3':
109 return 'heading_three';
110
111 case '4':
112 return 'heading_four';
113
114 case '5':
115 return 'heading_five';
116
117 case '6':
118 return 'heading_six';
119
120 default:
121 return 'heading_one';
122 }
123 }
124 /**
125 * Returns the processed children
126 * @param {*} thing a concerto ast node
127 * @param {string} fieldName name of the field containing the children
128 * @param {*} parameters the parameters
129 * @returns {*} an array of slate nodes
130 */
131
132
133 processChildren(thing, fieldName, parameters) {
134 const result = [];
135 const nodes = thing[fieldName] ? thing[fieldName] : [];
136 nodes.forEach(node => {
137 //console.log(`Processing ${thing.getType()} > ${node.getType()}`);
138 const newParameters = {
139 strong: parameters.strong,
140 emph: parameters.emph,
141 code: parameters.code
142 };
143 node.accept(this, newParameters);
144
145 if (Array.isArray(newParameters.result)) {
146 Array.prototype.push.apply(result, newParameters.result);
147 } else {
148 result.push(newParameters.result);
149 }
150 });
151 return result;
152 }
153 /**
154 * Returns the processed child nodes
155 * @param {*} thing a concerto ast node
156 * @param {*} parameters the parameters
157 * @returns {*} an array of slate nodes
158 */
159
160
161 processChildNodes(thing, parameters) {
162 return this.processChildren(thing, 'nodes', parameters);
163 }
164 /**
165 * Visit a concerto ast node and return the corresponding slate node
166 * @param {*} thing the object being visited
167 * @param {*} parameters the parameters
168 */
169
170
171 visit(thing, parameters) {
172 let result = {
173 style: thing.getType()
174 };
175
176 switch (thing.getType()) {
177 case 'Emph':
178 {
179 parameters.emph = true;
180 result.text = this.processChildNodes(thing, parameters);
181 result.italics = true;
182 }
183 break;
184
185 case 'Strong':
186 {
187 parameters.strong = true;
188 result.text = this.processChildNodes(thing, parameters);
189 result.bold = true;
190 }
191 break;
192
193 case 'BlockQuote':
194 case 'Item':
195 case 'Clause':
196 {
197 result.stack = this.processChildNodes(thing, parameters);
198 }
199 break;
200
201 case 'Link':
202 {
203 result.text = thing.nodes[0].text;
204 result.link = thing.destination;
205 }
206 break;
207
208 case 'Image':
209 {
210 result.image = thing.destination;
211 }
212 break;
213
214 case 'Paragraph':
215 {
216 const child = this.processChildNodes(thing, parameters);
217
218 if (child[0] && child[0].style === 'Image') {
219 // PDFMake can't render images inline
220 result.stack = child;
221 } else {
222 result.text = child;
223 result.margin = [0, 5];
224 }
225 }
226 break;
227
228 case 'EnumVariable':
229 case 'FormattedVariable':
230 case 'Formula':
231 case 'Variable':
232 {
233 const fixedText = thing.elementType === 'String' || thing.identifiedBy ? unquoteString(thing.value) : thing.value;
234 result.text = fixedText;
235 }
236 break;
237
238 case 'Optional':
239 case 'Conditional':
240 {
241 const child = this.processChildNodes(thing, parameters);
242 result.stack = child;
243 }
244 break;
245
246 case 'HtmlInline':
247 case 'HtmlBlock':
248 case 'CodeBlock':
249 case 'Code':
250 {
251 result.text = thing.text;
252 }
253 break;
254
255 case 'Text':
256 {
257 result = ToPdfMakeVisitor.handleFormattedText(thing, parameters);
258 }
259 break;
260
261 case 'Heading':
262 {
263 const child = this.processChildNodes(thing, parameters);
264 const text = child && child[0] && child[0].text ? child[0].text : '';
265 result.style = ToPdfMakeVisitor.getHeadingType(thing);
266 result.text = "\n".concat(text, "\n");
267 result.tocItem = text.length > 0 ? true : false;
268 }
269 break;
270
271 case 'ThematicBreak':
272 {
273 result.text = '';
274 result.pageBreak = 'after';
275 }
276 break;
277
278 case 'Linebreak':
279 {
280 result.text = '\n';
281 }
282 break;
283
284 case 'Softbreak':
285 {
286 result.text = ' ';
287 }
288 break;
289
290 case 'ListBlock':
291 case 'List':
292 {
293 result[thing.type === 'ordered' ? 'ol' : 'ul'] = this.processChildNodes(thing, parameters);
294 }
295 break;
296
297 case 'Document':
298 {
299 result.content = this.processChildNodes(thing, parameters);
300 }
301 break;
302
303 default:
304 throw new Error("Unhandled type ".concat(thing.getType()));
305 }
306
307 parameters.result = result;
308 }
309
310}
311
312module.exports = ToPdfMakeVisitor;
\No newline at end of file