docgen-tool 3.2.2 → 3.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/docgen/docgen.js +906 -0
  2. package/dist/docgen.js +51 -0
  3. package/dist/include/example/contents.json +12 -0
  4. package/dist/include/example/files/images/logo.png +0 -0
  5. package/dist/include/example/index.txt +4 -0
  6. package/dist/include/example/parameters.json +37 -0
  7. package/dist/include/example/release-notes.txt +1 -0
  8. package/dist/include/optional/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  9. package/dist/include/optional/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  10. package/dist/include/optional/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  11. package/dist/include/optional/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  12. package/dist/include/optional/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  13. package/dist/include/optional/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  14. package/dist/include/optional/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  15. package/dist/include/optional/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  16. package/dist/include/optional/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  17. package/dist/include/optional/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  18. package/dist/include/optional/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  19. package/dist/include/optional/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  20. package/dist/include/optional/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  21. package/dist/include/optional/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  22. package/dist/include/optional/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  23. package/dist/include/optional/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  24. package/dist/include/optional/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  25. package/dist/include/optional/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  26. package/dist/include/optional/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  27. package/dist/include/optional/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  28. package/dist/include/optional/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  29. package/dist/include/optional/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  30. package/dist/include/optional/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  31. package/dist/include/optional/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  32. package/dist/include/optional/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  33. package/dist/include/optional/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  34. package/dist/include/optional/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  35. package/dist/include/optional/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  36. package/dist/include/optional/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  37. package/dist/include/optional/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  38. package/dist/include/optional/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  39. package/dist/include/optional/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  40. package/dist/include/optional/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  41. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  42. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  43. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  44. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  45. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  46. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  47. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  48. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  49. package/dist/include/optional/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  50. package/dist/include/optional/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  51. package/dist/include/optional/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  52. package/dist/include/optional/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  53. package/dist/include/optional/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  54. package/dist/include/optional/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  55. package/dist/include/optional/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  56. package/dist/include/optional/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  57. package/dist/include/optional/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  58. package/dist/include/optional/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  59. package/dist/include/optional/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  60. package/dist/include/optional/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  61. package/dist/include/optional/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  62. package/dist/include/optional/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  63. package/dist/include/optional/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  64. package/dist/include/optional/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  65. package/dist/include/optional/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  66. package/dist/include/optional/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  67. package/dist/include/optional/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  68. package/dist/include/optional/katex/katex.min.css +1105 -0
  69. package/dist/include/optional/katex/katex.min.js +12562 -0
  70. package/dist/include/pdf-contents.xsl +71 -0
  71. package/dist/include/pdf-stylesheet.css +59 -0
  72. package/dist/include/require/docgen.css +136 -0
  73. package/dist/include/require/katexInjector.js +18 -0
  74. package/dist/include/require/print.css +26 -0
  75. package/dist/include/require/styles/fonts/DroidSansMono.woff +0 -0
  76. package/dist/include/require/styles/fonts/Montserrat-Italic.woff +0 -0
  77. package/dist/include/require/styles/fonts/Montserrat-Regular.woff +0 -0
  78. package/dist/include/require/styles/fonts/Montserrat-SemiBold.woff +0 -0
  79. package/dist/include/require/styles/fonts/Montserrat-SemiBoldItalic.woff +0 -0
  80. package/dist/include/require/styles/framework.css +1022 -0
  81. package/dist/include/require/styles/framework.icons.js +143 -0
  82. package/dist/include/require/styles/framework.js +5420 -0
  83. package/dist/include/require/styles/highlight.min.css +153 -0
  84. package/dist/include/require/styles/highlight.min.js +1545 -0
  85. package/dist/include/templates/main.html +95 -0
  86. package/dist/include/templates/pdfCover.html +128 -0
  87. package/dist/include/templates/pdfFooter.html +59 -0
  88. package/dist/include/templates/pdfHeader.html +21 -0
  89. package/dist/include/templates/redirect.html +10 -0
  90. package/dist/include/templates/webCover.html +73 -0
  91. package/package.json +11 -12
@@ -0,0 +1,906 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var rsvp = require('rsvp');
4
+ var fs = require('fs-extra');
5
+ var path = require('path');
6
+ var cheerio = require('cheerio');
7
+ var markdown = require('markdown-it')('commonmark').enable('table');
8
+ var moment = require('moment');
9
+ var child_process_1 = require("child_process");
10
+ var schemaValidator = require('z-schema');
11
+ var chalk = require('chalk');
12
+ var spawnArgs = require('spawn-args');
13
+ var cliSpinner = require('cli-spinner').Spinner;
14
+ var imageSizeOf = require('image-size');
15
+ var package_json_1 = require("../../package.json");
16
+ //Allow CommonMark links that use other protocols, such as file:///
17
+ //The markdown-it implementation is more restrictive than the CommonMark spec
18
+ //See https://github.com/markdown-it/markdown-it/issues/108
19
+ markdown.validateLink = function () {
20
+ return true;
21
+ };
22
+ /**
23
+ * DocGen class
24
+ */
25
+ function DocGen(process) {
26
+ var mainProcess = process;
27
+ var wkhtmltopdfVersion = 'wkhtmltopdf 0.12.6 (with patched qt)'; //output from wkhtmltopdf -V
28
+ var options;
29
+ var templates = {};
30
+ var meta = {};
31
+ var pages = {};
32
+ var sortedPages = {};
33
+ this.getVersion = function () {
34
+ return package_json_1.version;
35
+ };
36
+ this.setOptions = function (userOptions) {
37
+ options = userOptions;
38
+ //all user-specified paths must be normalized
39
+ if (options.input) {
40
+ options.input = path.normalize(options.input + '/');
41
+ }
42
+ if (options.output) {
43
+ options.output = path.normalize(options.output + '/');
44
+ }
45
+ //wkhtmltopdf path does not need a trailing slash
46
+ if (options.wkhtmltopdfPath && options.wkhtmltopdfPath !== '') {
47
+ options.wkhtmltopdfPath = path.normalize(options.wkhtmltopdfPath);
48
+ }
49
+ };
50
+ /*
51
+ copy the example src files (template) to any directory, when scaffold command is invoked
52
+ */
53
+ this.scaffold = function () {
54
+ console.log(chalk.green('Creating scaffold template directory'));
55
+ copyDirSync(__dirname + '/example', options.output);
56
+ };
57
+ this.run = function () {
58
+ console.log(chalk.green.bold('DocGen version ' + package_json_1.version));
59
+ //delete and recreate the output directory
60
+ remakeDirSync(options.output);
61
+ loadTemplates();
62
+ };
63
+ /*
64
+ read any file (async)
65
+ */
66
+ var readFile = function (filePath) {
67
+ var normalized = path.normalize(filePath);
68
+ return new rsvp.Promise(function (resolve, reject) {
69
+ fs.readFile(normalized, 'utf8', function (error, data) {
70
+ if (error) {
71
+ console.log(chalk.red('Error reading file: ' + normalized));
72
+ reject(error);
73
+ }
74
+ else {
75
+ data = data.replace(/^\uFEFF/, ''); //remove the BOM (byte-order-mark) from UTF-8 files, if present
76
+ resolve(data);
77
+ }
78
+ });
79
+ });
80
+ };
81
+ /*
82
+ write any file (async)
83
+ */
84
+ var writeFile = function (path, data) {
85
+ return new rsvp.Promise(function (resolve, reject) {
86
+ fs.writeFile(path, data, function (error) {
87
+ if (error) {
88
+ console.log(chalk.red('Error writing file: ' + path));
89
+ reject(error);
90
+ }
91
+ else {
92
+ resolve(true);
93
+ }
94
+ });
95
+ });
96
+ };
97
+ /*
98
+ copy any directory (sync)
99
+ */
100
+ var copyDirSync = function (source, destination) {
101
+ try {
102
+ fs.copySync(source, destination);
103
+ }
104
+ catch (error) {
105
+ console.log(chalk.red('Error copying directory: ' + source + ' to ' + destination));
106
+ if (options.verbose === true) {
107
+ console.log(chalk.red(error));
108
+ mainProcess.exit(1);
109
+ }
110
+ }
111
+ };
112
+ /*
113
+ remake a directory (sync) ... remove and then mkdir in one operation
114
+ */
115
+ var remakeDirSync = function (path) {
116
+ try {
117
+ fs.removeSync(path);
118
+ fs.mkdirpSync(path);
119
+ }
120
+ catch (error) {
121
+ console.log(chalk.red('Error recreating directory: ' + path));
122
+ if (options.verbose === true) {
123
+ console.log(chalk.red(error));
124
+ mainProcess.exit(1);
125
+ }
126
+ }
127
+ };
128
+ /*
129
+ remove any directory (sync)
130
+ */
131
+ var removeDirSync = function (path) {
132
+ try {
133
+ fs.removeSync(path);
134
+ }
135
+ catch (error) {
136
+ console.log(chalk.red('Error removing directory: ' + path));
137
+ if (options.verbose === true) {
138
+ console.log(chalk.red(error));
139
+ mainProcess.exit(1);
140
+ }
141
+ }
142
+ };
143
+ /*
144
+ load all HTML template files
145
+ */
146
+ var loadTemplates = function () {
147
+ console.log(chalk.green('Loading templates'));
148
+ var files = {
149
+ main: readFile(__dirname + '/../include/templates/main.html'),
150
+ redirect: readFile(__dirname + '/../include/templates/redirect.html'),
151
+ webCover: readFile(__dirname + '/../include/templates/webCover.html'),
152
+ pdfCover: readFile(__dirname + '/../include/templates/pdfCover.html'),
153
+ pdfHeader: readFile(__dirname + '/../include/templates/pdfHeader.html'),
154
+ pdfFooter: readFile(__dirname + '/../include/templates/pdfFooter.html'),
155
+ };
156
+ rsvp
157
+ .hash(files)
158
+ .then(function (files) {
159
+ for (var key in files) {
160
+ if (files.hasOwnProperty(key)) {
161
+ var file = files[key];
162
+ var dom = cheerio.load(file);
163
+ templates[key] = dom;
164
+ }
165
+ }
166
+ loadMeta();
167
+ })
168
+ .catch(function (error) {
169
+ console.log(chalk.red('Error loading templates'));
170
+ if (options.verbose === true) {
171
+ console.log(chalk.red(error));
172
+ }
173
+ mainProcess.exit(1);
174
+ });
175
+ };
176
+ /*
177
+ JSON schema validation
178
+ */
179
+ var schemas = {
180
+ parameters: {
181
+ title: 'DocGen Parameters Schema',
182
+ type: 'object',
183
+ required: [
184
+ 'title',
185
+ 'name',
186
+ 'version',
187
+ 'date',
188
+ 'organization',
189
+ 'author',
190
+ 'owner',
191
+ 'contributors',
192
+ 'website',
193
+ 'module',
194
+ 'id',
195
+ 'summary',
196
+ 'marking',
197
+ 'legalese',
198
+ ],
199
+ properties: {
200
+ title: { type: 'string' },
201
+ name: { type: 'string' },
202
+ version: { type: 'string' },
203
+ date: { type: 'string' },
204
+ organization: {
205
+ type: 'object',
206
+ required: ['name', 'url'],
207
+ properties: {
208
+ name: { type: 'string' },
209
+ url: { type: 'string' },
210
+ },
211
+ },
212
+ author: {
213
+ type: 'object',
214
+ required: ['name', 'url'],
215
+ properties: {
216
+ name: { type: 'string' },
217
+ url: { type: 'string' },
218
+ },
219
+ },
220
+ owner: {
221
+ type: 'object',
222
+ required: ['name', 'url'],
223
+ properties: {
224
+ name: { type: 'string' },
225
+ url: { type: 'string' },
226
+ },
227
+ },
228
+ contributors: {
229
+ type: 'array',
230
+ items: {
231
+ oneOf: [
232
+ {
233
+ type: 'object',
234
+ required: ['name', 'url'],
235
+ properties: {
236
+ name: { type: 'string' },
237
+ url: { type: 'string' },
238
+ },
239
+ },
240
+ ],
241
+ },
242
+ },
243
+ website: {
244
+ type: 'object',
245
+ required: ['name', 'url'],
246
+ properties: {
247
+ name: { type: 'string' },
248
+ url: { type: 'string' },
249
+ },
250
+ },
251
+ backlink: {
252
+ type: 'object',
253
+ required: ['name', 'url'],
254
+ properties: {
255
+ name: { type: 'string' },
256
+ url: { type: 'string' },
257
+ },
258
+ },
259
+ module: { type: 'string' },
260
+ id: { type: 'string' },
261
+ summary: { type: 'string' },
262
+ marking: { type: 'string' },
263
+ legalese: { type: 'string' },
264
+ },
265
+ },
266
+ contents: {
267
+ title: 'DocGen Table of Contents Schema',
268
+ type: 'array',
269
+ items: {
270
+ oneOf: [
271
+ {
272
+ type: 'object',
273
+ required: ['heading', 'column', 'pages'],
274
+ properties: {
275
+ name: { type: 'string' },
276
+ column: { type: 'integer', minimum: 1, maximum: 4 },
277
+ pages: {
278
+ type: 'array',
279
+ items: {
280
+ oneOf: [
281
+ {
282
+ type: 'object',
283
+ required: ['title', 'source'],
284
+ properties: {
285
+ title: { type: 'string' },
286
+ source: { type: 'string' },
287
+ html: { type: 'boolean' },
288
+ },
289
+ },
290
+ ],
291
+ },
292
+ },
293
+ },
294
+ },
295
+ ],
296
+ },
297
+ },
298
+ };
299
+ var validateJSON = function (key, data) {
300
+ var schema = schemas[key];
301
+ var validator = new schemaValidator();
302
+ var valid = validator.validate(data, schema);
303
+ if (!valid) {
304
+ console.log(chalk.red('Error parsing required file: ' +
305
+ key +
306
+ '.json (failed schema validation)'));
307
+ if (options.verbose === true) {
308
+ console.log(chalk.red(validator.getLastError()));
309
+ }
310
+ }
311
+ return valid;
312
+ };
313
+ /*
314
+ load all metadata files (JSON)
315
+ */
316
+ var loadMeta = function () {
317
+ console.log(chalk.green('Loading required JSON metadata files'));
318
+ var files = {
319
+ parameters: readFile(options.input + '/parameters.json'),
320
+ contents: readFile(options.input + '/contents.json'),
321
+ };
322
+ rsvp
323
+ .hash(files)
324
+ .then(function (files) {
325
+ for (var key in files) {
326
+ if (files.hasOwnProperty(key)) {
327
+ //ignore prototype
328
+ try {
329
+ var file = JSON.parse(files[key]);
330
+ if (validateJSON(key, file)) {
331
+ meta[key] = file;
332
+ }
333
+ else {
334
+ mainProcess.exit(1);
335
+ }
336
+ }
337
+ catch (error) {
338
+ console.log(chalk.red('Error parsing required file: ' +
339
+ key +
340
+ '.json (invalid JSON)'));
341
+ if (options.verbose === true) {
342
+ console.log(chalk.red(error));
343
+ }
344
+ mainProcess.exit(1);
345
+ }
346
+ }
347
+ }
348
+ //add the release notes to the contents list
349
+ var extra = {
350
+ heading: 'Extra',
351
+ column: 5,
352
+ pages: [{ title: 'Release notes', source: 'release-notes.txt' }],
353
+ };
354
+ meta.contents.push(extra);
355
+ loadMarkdown();
356
+ })
357
+ .catch(function (error) {
358
+ console.log(chalk.red('Error loading required JSON metadata files'));
359
+ if (options.verbose === true) {
360
+ console.log(chalk.red(error));
361
+ }
362
+ mainProcess.exit(1);
363
+ });
364
+ };
365
+ /*
366
+ load all markdown files (src)
367
+ */
368
+ var loadMarkdown = function () {
369
+ console.log(chalk.green('Loading src files'));
370
+ var keys = [];
371
+ var files = [];
372
+ meta.contents.forEach(function (section) {
373
+ section.pages.forEach(function (page) {
374
+ keys.push(page);
375
+ files.push(options.input + '/' + page.source);
376
+ });
377
+ });
378
+ //add the release notes page
379
+ keys.push('ownership');
380
+ files.push(options.input + '/release-notes.txt');
381
+ rsvp
382
+ .all(files.map(readFile))
383
+ .then(function (files) {
384
+ files.forEach(function (page, index) {
385
+ try {
386
+ var key = keys[index];
387
+ if (key.html === true) {
388
+ //allow raw HTML input pages
389
+ pages[key.source] = page;
390
+ }
391
+ else {
392
+ //otherwise parse input from Markdown into HTML
393
+ var html = markdown.render(page);
394
+ pages[key.source] = html;
395
+ }
396
+ }
397
+ catch (error) {
398
+ console.log(chalk.red('Error parsing Markdown file: ' + file.source));
399
+ if (options.verbose === true) {
400
+ console.log(chalk.red(error));
401
+ }
402
+ mainProcess.exit(1);
403
+ }
404
+ });
405
+ processContent();
406
+ })
407
+ .catch(function (error) {
408
+ console.log(error);
409
+ console.log(chalk.red('Error loading src files'));
410
+ if (options.verbose === true) {
411
+ console.log(chalk.red(error));
412
+ }
413
+ mainProcess.exit(1);
414
+ });
415
+ };
416
+ var sortPages = function () {
417
+ //sort the contents by heading
418
+ var headings = { 1: [], 2: [], 3: [], 4: [], 5: [] };
419
+ meta.contents.forEach(function (section) {
420
+ if (headings.hasOwnProperty(section.column)) {
421
+ headings[section.column].push(section);
422
+ }
423
+ });
424
+ sortedPages = headings;
425
+ };
426
+ /*
427
+ build the HTML for the table of contents
428
+ */
429
+ var webToc = function () {
430
+ sortPages();
431
+ var pdfName = meta.parameters.name.toLowerCase() + '.pdf';
432
+ var $ = templates.main;
433
+ var html = [], i = -1;
434
+ html[++i] = '<div><table class="unstyled"><tr>';
435
+ //build the contents HTML
436
+ for (var key in sortedPages) {
437
+ if (sortedPages.hasOwnProperty(key)) {
438
+ if (key != 5) {
439
+ //skip the extra column
440
+ html[++i] = '<td class="dg-tocGroup">';
441
+ sortedPages[key].forEach(function (section) {
442
+ html[++i] =
443
+ '<ul><li class="dg-tocHeading">' + section.heading + '</li>';
444
+ section.pages.forEach(function (page) {
445
+ var name = page.source.substr(0, page.source.lastIndexOf('.'));
446
+ var path = name + '.html';
447
+ html[++i] =
448
+ '<li><a href="' + path + '">' + page.title + '</a></li>';
449
+ });
450
+ html[++i] = '</li></ul>';
451
+ });
452
+ html[++i] = '</td>';
453
+ }
454
+ }
455
+ }
456
+ //fixed-width column at end
457
+ html[++i] = '<td class="dg-tocGroup" id="dg-tocFixedColumn"><ul>';
458
+ html[++i] =
459
+ '<li><span class="w-icon dg-tocIcon" data-name="person_group" title="archive"></span><a href="ownership.html">Ownership</a></li>';
460
+ html[++i] =
461
+ '<li><span class="w-icon dg-tocIcon" data-name="refresh" title="archive"></span><a href="release-notes.html">Release Notes</a></li>';
462
+ html[++i] = '</ul><div>';
463
+ if (options.pdf) {
464
+ html[++i] =
465
+ '<button class="whiteInverted" onclick="window.location=\'' +
466
+ pdfName +
467
+ '\';">';
468
+ html[++i] = '<span>PDF</span>';
469
+ html[++i] = '</button>';
470
+ }
471
+ html[++i] = '</div></td>';
472
+ html[++i] = '</tr></table></div>';
473
+ $('#dg-toc').html(html.join(''));
474
+ templates.main = $;
475
+ };
476
+ /*
477
+ insert the parameters into all templates
478
+ */
479
+ var insertParameters = function () {
480
+ //------------------------------------------------------------------------------------------------------
481
+ //logo dimensions
482
+ var hasLogo = false;
483
+ var logoWidth = 0;
484
+ var logoHeight = 0;
485
+ var logoPath;
486
+ try {
487
+ logoPath = 'files/images/logo.svg';
488
+ var logo = imageSizeOf("".concat(options.input, "/").concat(logoPath));
489
+ logoWidth = logo.width;
490
+ logoHeight = logo.height;
491
+ hasLogo = true;
492
+ }
493
+ catch (error) {
494
+ //do nothing. If logo file cannot be read, logo is simply not shown
495
+ }
496
+ if (!hasLogo) {
497
+ //PNG fallback
498
+ try {
499
+ logoPath = 'files/images/logo.png';
500
+ var logo = imageSizeOf("".concat(options.input, "/").concat(logoPath));
501
+ logoWidth = logo.width;
502
+ logoHeight = logo.height;
503
+ hasLogo = true;
504
+ }
505
+ catch (error) {
506
+ //do nothing. If logo file cannot be read, logo is simply not shown
507
+ }
508
+ }
509
+ //------------------------------------------------------------------------------------------------------
510
+ //the homepage is the first link in the first heading
511
+ var homelink = meta.contents[0].pages[0];
512
+ homelink =
513
+ homelink.source.substr(0, homelink.source.lastIndexOf('.')) + '.html';
514
+ var date = moment().format('DD/MM/YYYY');
515
+ var time = moment().format('HH:mm:ss');
516
+ var year = moment().format('YYYY');
517
+ var attribution = 'Created by DocGen ' + package_json_1.version + ' on ' + date + ' at ' + time + '.';
518
+ var releaseVersion = meta.parameters.version;
519
+ if (options.setVersion !== false) {
520
+ releaseVersion = options.setVersion;
521
+ }
522
+ var releaseDate = meta.parameters.date;
523
+ if (options.setReleaseDate !== false) {
524
+ releaseDate = options.setReleaseDate;
525
+ }
526
+ var author = '';
527
+ if (meta.parameters.author.url !== '') {
528
+ author +=
529
+ '<a href="' +
530
+ meta.parameters.author.url +
531
+ '">' +
532
+ meta.parameters.author.name +
533
+ '</a>';
534
+ }
535
+ else {
536
+ author += meta.parameters.author.name;
537
+ }
538
+ var owner = '';
539
+ if (meta.parameters.owner.url !== '') {
540
+ owner +=
541
+ '<a href="' +
542
+ meta.parameters.owner.url +
543
+ '">' +
544
+ meta.parameters.owner.name +
545
+ '</a>';
546
+ }
547
+ else {
548
+ owner += meta.parameters.owner.name;
549
+ }
550
+ var organization = '';
551
+ if (meta.parameters.organization.url !== '') {
552
+ organization +=
553
+ '<a href="' +
554
+ meta.parameters.organization.url +
555
+ '">' +
556
+ meta.parameters.organization.name +
557
+ '</a>';
558
+ }
559
+ else {
560
+ organization += meta.parameters.organization.name;
561
+ }
562
+ var website = '';
563
+ if (meta.parameters.website.url !== '') {
564
+ website +=
565
+ '<a href="' +
566
+ meta.parameters.website.url +
567
+ '">' +
568
+ meta.parameters.website.name +
569
+ '</a>';
570
+ }
571
+ else {
572
+ website += meta.parameters.website.name;
573
+ }
574
+ var backlink = '';
575
+ if (meta.parameters.backlink.url !== '') {
576
+ backlink +=
577
+ '<a href="' +
578
+ meta.parameters.backlink.url +
579
+ '">' +
580
+ meta.parameters.backlink.name +
581
+ '</a>';
582
+ }
583
+ else {
584
+ backlink += meta.parameters.backlink.name;
585
+ }
586
+ var contributors = '';
587
+ meta.parameters.contributors.forEach(function (contributor) {
588
+ if (contributor.url !== '') {
589
+ contributors +=
590
+ '<a href="' + contributor.url + '">' + contributor.name + '</a>, ';
591
+ }
592
+ else {
593
+ contributors += contributor.name + ', ';
594
+ }
595
+ });
596
+ contributors = contributors.replace(/,\s*$/, ''); //remove trailing commas
597
+ var copyright = '&copy; ' + year + ' ' + organization;
598
+ var webTitle = meta.parameters.title;
599
+ var webFooter = 'Version ' + releaseVersion + ' released on ' + releaseDate + '.';
600
+ for (var key in templates) {
601
+ if (templates.hasOwnProperty(key)) {
602
+ var $ = templates[key];
603
+ //logo
604
+ if (hasLogo === true) {
605
+ var logoUrl = logoPath;
606
+ $('#dg-logo').css('background-image', 'url(' + logoUrl + ')');
607
+ $('#dg-logo').css('height', logoHeight + 'px');
608
+ $('#dg-logo').css('line-height', logoHeight + 'px');
609
+ $('#dg-logo').css('padding-left', logoWidth + 25 + 'px');
610
+ }
611
+ else {
612
+ $('#dg-logo').css('padding-left', '0');
613
+ }
614
+ //parameters
615
+ $('title').text(meta.parameters.title);
616
+ $('#dg-homelink').attr('href', homelink);
617
+ $('#dg-title').text(meta.parameters.title);
618
+ $('#dg-owner').html(owner);
619
+ $('#dg-version').text(releaseVersion);
620
+ $('#dg-web-title-version').text('(' + releaseVersion + ')');
621
+ $('#dg-release-date').text(releaseDate);
622
+ $('#dg-web-footer').text(webFooter);
623
+ $('#dg-author').html(author);
624
+ $('#dg-contributors').html(contributors);
625
+ $('#dg-module').text(meta.parameters.module);
626
+ $('#dg-id').html(meta.parameters.id);
627
+ $('#dg-website').html(website);
628
+ $('#dg-backlink').html(backlink);
629
+ $('#dg-summary').text(meta.parameters.summary);
630
+ $('#dg-copyright').html(copyright);
631
+ $('#dg-marking').text(meta.parameters.marking);
632
+ $('#dg-legalese').text(meta.parameters.legalese);
633
+ $('#dg-attribution').text(attribution);
634
+ }
635
+ }
636
+ if (options.mathKatex === true) {
637
+ var $ = templates.main;
638
+ //support for KaTeX (bundled with DocGen)
639
+ $('head').append('<link rel="stylesheet" href="require/katex/katex.min.css" type="text/css">');
640
+ $('head').append('<script type="text/javascript" src="require/katex/katex.min.js"></script>');
641
+ $('head').append('<script type="text/javascript" src="require/katexInjector.js"></script>');
642
+ }
643
+ if (options.mathMathjax === true) {
644
+ //support for MathJax (only supported via CDN due to very large size)
645
+ //MathJax configuration is the same as used by math.stackexchange.com
646
+ //Note - wkhtmlpdf //cdn urls - see https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1634
647
+ $('head').append('<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML-full"></script>');
648
+ }
649
+ };
650
+ /*
651
+ process each input into an output
652
+ */
653
+ var processContent = function () {
654
+ console.log(chalk.green('Generating the static web content'));
655
+ webToc();
656
+ insertParameters();
657
+ meta.contents.forEach(function (section) {
658
+ section.pages.forEach(function (page) {
659
+ var $ = cheerio.load(templates.main.html()); //clone
660
+ var key = page.source;
661
+ var content = pages[key];
662
+ //add relevant container
663
+ if (page.html === true) {
664
+ //raw HTML pages should not be confined to the fixed width
665
+ $('#dg-content').html('<div id="dg-innerContent"></div>');
666
+ }
667
+ else {
668
+ //Markdown pages should be confined to the fixed width
669
+ $('#dg-content').html('<div class="w-fixed-width"><div id="dg-innerContent"></div></div>');
670
+ }
671
+ $('#dg-innerContent').html(content);
672
+ //------------------------------------------------------------------------------------------------------
673
+ //insert permalinks for every page heading
674
+ //when pageToc is enabled, also insert a page-level table of contents
675
+ var html = [], i = -1;
676
+ var headings = $('h1, h2, h3, h4, h5, h6');
677
+ if (headings.length > 0) {
678
+ html[++i] = '<ul class="dg-pageToc">';
679
+ }
680
+ headings.each(function () {
681
+ var label = $(this).text();
682
+ var anchor = label.toLowerCase().replace(/\s+/g, '-');
683
+ $(this).attr('id', anchor);
684
+ html[++i] = '<li><a href="#' + anchor + '">' + label + '</a></li>';
685
+ });
686
+ if (headings.length > 0) {
687
+ html[++i] = '</ul>';
688
+ }
689
+ if (options.pageToc === true && page.html !== true) {
690
+ $('#dg-innerContent').prepend(html.join(''));
691
+ }
692
+ //------------------------------------------------------------------------------------------------------
693
+ //prepend the auto heading (which makes the PDF table of contents match the web TOC)
694
+ $('#dg-innerContent').prepend('<h1 id="dg-autoTitle">' + page.title + '</h1>');
695
+ if (page.html === true) {
696
+ $('#dg-autoTitle').addClass('dg-hiddenTitle');
697
+ }
698
+ //------------------------------------------------------------------------------------------------------
699
+ //apply the w-table class
700
+ $('table:not(.unstyled)').addClass('w-table w-fixed w-stripe');
701
+ //------------------------------------------------------------------------------------------------------
702
+ pages[key] = $;
703
+ });
704
+ });
705
+ //add web ownership page
706
+ var $ = cheerio.load(templates.main.html()); //clone
707
+ $('#dg-content').html('<div class="w-fixed-width"><div id="dg-innerContent"></div></div>');
708
+ $('#dg-innerContent').html(templates.webCover.html());
709
+ templates.webCover = $;
710
+ writePages();
711
+ };
712
+ /*
713
+ write each html page
714
+ */
715
+ var writePages = function () {
716
+ console.log(chalk.green('Writing the web page files'));
717
+ var promises = {};
718
+ meta.contents.forEach(function (section) {
719
+ section.pages.forEach(function (page) {
720
+ var key = page.source;
721
+ var name = key.substr(0, page.source.lastIndexOf('.'));
722
+ var path = options.output + name + '.html';
723
+ var html = pages[key].html();
724
+ promises[key] = writeFile(path, html);
725
+ });
726
+ });
727
+ //add extra files
728
+ promises['ownership'] = writeFile(options.output + 'ownership.html', templates.webCover.html());
729
+ if (options.pdf === true) {
730
+ var pdfTempDir = options.output + 'temp/';
731
+ fs.mkdirsSync(pdfTempDir);
732
+ promises['docgenPdfCover'] = writeFile(pdfTempDir + 'pdfCover.html', templates.pdfCover.html());
733
+ promises['docgenPdfHeader'] = writeFile(pdfTempDir + 'pdfHeader.html', templates.pdfHeader.html());
734
+ promises['docgenPdfFooter'] = writeFile(pdfTempDir + 'pdfFooter.html', templates.pdfFooter.html());
735
+ }
736
+ rsvp
737
+ .hash(promises)
738
+ .then(function () {
739
+ copyDirSync(__dirname + '/../include/require', options.output + 'require'); //CSS, JavaScript
740
+ copyDirSync(options.input + '/files', options.output + 'files'); //user-attached files and images
741
+ if (options.mathKatex === true) {
742
+ copyDirSync(__dirname + '/../include/optional/katex', options.output + 'require/katex');
743
+ }
744
+ checkPdfVersion();
745
+ })
746
+ .catch(function (error) {
747
+ console.log(chalk.red('Error writing the web page files'));
748
+ if (options.verbose === true) {
749
+ console.log(chalk.red(error));
750
+ }
751
+ mainProcess.exit(1);
752
+ });
753
+ };
754
+ /*
755
+ wkthmltopdf options
756
+ */
757
+ var pdfOptions = [
758
+ ' --zoom 1.0',
759
+ ' --image-quality 100',
760
+ ' --print-media-type',
761
+ ' --orientation portrait',
762
+ ' --page-size A4',
763
+ ' --margin-top 25',
764
+ ' --margin-right 15',
765
+ ' --margin-bottom 16',
766
+ ' --margin-left 15',
767
+ ' --header-spacing 5',
768
+ ' --footer-spacing 5',
769
+ ' --no-stop-slow-scripts',
770
+ ];
771
+ var getPdfArguments = function () {
772
+ var pdfName = meta.parameters.name.toLowerCase() + '.pdf';
773
+ pdfOptions.push(' --enable-local-file-access');
774
+ pdfOptions.push(' --javascript-delay ' + options.pdfDelay); //code syntax highlight in wkhtmltopdf 0.12.2.1 fails without a delay (but why doesn't --no-stop-slow-scripts work?)
775
+ pdfOptions.push(' --user-style-sheet ' + __dirname + '/../include/pdf-stylesheet.css');
776
+ pdfOptions.push(' --header-html ' + options.output + 'temp/pdfHeader.html');
777
+ pdfOptions.push(' --footer-html ' + options.output + 'temp/pdfFooter.html');
778
+ pdfOptions.push(' cover ' + options.output + 'temp/pdfCover.html');
779
+ pdfOptions.push(' toc --xsl-style-sheet ' + __dirname + '/../include/pdf-contents.xsl');
780
+ var allPages = '';
781
+ for (var key in sortedPages) {
782
+ if (sortedPages.hasOwnProperty(key)) {
783
+ sortedPages[key].forEach(function (section) {
784
+ section.pages.forEach(function (page) {
785
+ var key = page.source;
786
+ var name = key.substr(0, page.source.lastIndexOf('.'));
787
+ var path = options.output + name + '.html';
788
+ allPages += ' ' + path;
789
+ });
790
+ });
791
+ }
792
+ }
793
+ var args = pdfOptions.join('');
794
+ args += allPages;
795
+ args += ' ' + options.output + pdfName;
796
+ return spawnArgs(args);
797
+ };
798
+ var checkPdfVersion = function () {
799
+ if (options.pdf === true) {
800
+ //first check that wkhtmltopdf is installed
801
+ (0, child_process_1.exec)(options.wkhtmltopdfPath + ' -V', function (error, stdout, stderr) {
802
+ if (error) {
803
+ console.log(chalk.red('Unable to call wkhtmltopdf. Is it installed and in path? See http://wkhtmltopdf.org'));
804
+ if (options.verbose === true) {
805
+ console.log(chalk.red(error));
806
+ }
807
+ mainProcess.exit(1);
808
+ }
809
+ else {
810
+ //warn if the version of wkhtmltopdf is not an expected version
811
+ var actualWkhtmltopdfVersion = stdout.trim();
812
+ if (actualWkhtmltopdfVersion !== wkhtmltopdfVersion) {
813
+ var warning = 'Warning: unexpected version of wkhtmltopdf, which may work but is not tested or supported';
814
+ var expectedVersion = ' expected version: ' + wkhtmltopdfVersion;
815
+ var detectedVersion = ' detected version: ' + actualWkhtmltopdfVersion;
816
+ console.log(chalk.yellow(warning));
817
+ console.log(chalk.yellow(expectedVersion));
818
+ console.log(chalk.yellow(detectedVersion));
819
+ }
820
+ generatePdf();
821
+ }
822
+ });
823
+ }
824
+ else {
825
+ cleanUp();
826
+ }
827
+ };
828
+ /*
829
+ call wkhtmltopdf as an external executable
830
+ */
831
+ var generatePdf = function () {
832
+ console.log(chalk.green('Creating the PDF copy (may take some time)'));
833
+ var args = getPdfArguments();
834
+ var wkhtmltopdf = (0, child_process_1.spawn)(options.wkhtmltopdfPath, args);
835
+ var spinner = new cliSpinner(chalk.green(' Processing... %s'));
836
+ spinner.setSpinnerString('|/-\\');
837
+ wkhtmltopdf.on('error', function (error) {
838
+ console.log(chalk.red('Error calling wkhtmltopdf to generate the PDF'));
839
+ if (options.verbose === true) {
840
+ console.log(chalk.red(error));
841
+ }
842
+ });
843
+ if (options.verbose !== true) {
844
+ spinner.start(); //only show spinner when verbose is off (otherwise show raw wkhtmltopdf output)
845
+ }
846
+ else {
847
+ //pipe the output from wkhtmltopdf back to stdout
848
+ //however, wkhtmltpdf outputs to stderr, not stdout. See:
849
+ //https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1980
850
+ wkhtmltopdf.stderr.pipe(mainProcess.stdout);
851
+ }
852
+ wkhtmltopdf.stdout.on('data', function (data) {
853
+ //do nothing
854
+ });
855
+ wkhtmltopdf.stderr.on('data', function (data) {
856
+ //do nothing
857
+ });
858
+ wkhtmltopdf.on('close', function (code) {
859
+ if (options.verbose !== true) {
860
+ spinner.stop();
861
+ console.log(''); //newline after spinner stops
862
+ }
863
+ if (code !== 0) {
864
+ var warning = 'wkhtmltopdf exited with a warning or error: try the -v option for details';
865
+ console.log(chalk.yellow(warning));
866
+ }
867
+ cleanUp();
868
+ });
869
+ };
870
+ var createRedirect = function () {
871
+ if (options.redirect) {
872
+ var parent_1 = options.output.replace(/\/$/, ''); //trim any trailing slash
873
+ parent_1 = parent_1.split(path.sep).slice(-1).pop(); //get name of final directory in the path
874
+ var homepage = meta.contents[0].pages[0];
875
+ homepage =
876
+ homepage.source.substr(0, homepage.source.lastIndexOf('.')) + '.html';
877
+ var redirectLink = parent_1 + '/' + homepage;
878
+ var $ = templates.redirect;
879
+ $('a').attr('href', redirectLink);
880
+ $('meta[http-equiv=REFRESH]').attr('content', '0;url=' + redirectLink);
881
+ var file = options.output + '../' + 'index.html';
882
+ try {
883
+ fs.outputFileSync(file, $.html(), 'utf-8');
884
+ }
885
+ catch (error) {
886
+ console.log(chalk.red('Error writing redirect file: ' + file));
887
+ if (options.verbose === true) {
888
+ console.log(chalk.red(error));
889
+ }
890
+ //don't exit because redirect error is not a fatal error
891
+ }
892
+ }
893
+ };
894
+ /*
895
+ cleanup
896
+ */
897
+ var cleanUp = function () {
898
+ createRedirect();
899
+ //remove temp files
900
+ if (options.pdf === true) {
901
+ removeDirSync(options.output + 'temp');
902
+ }
903
+ console.log(chalk.green.bold('Done!'));
904
+ };
905
+ }
906
+ module.exports = DocGen;