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