docgen-tool 2.1.3 → 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 +896 -776
- 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 -63
- 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 -148
- 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,868 +1,988 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var imageSizeOf = require('image-size');
|
|
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');
|
|
14
13
|
|
|
15
14
|
//Allow CommonMark links that use other protocols, such as file:///
|
|
16
15
|
//The markdown-it implementation is more restrictive than the CommonMark spec
|
|
17
16
|
//See https://github.com/markdown-it/markdown-it/issues/108
|
|
18
|
-
markdown.validateLink =
|
|
17
|
+
markdown.validateLink = () => {
|
|
18
|
+
return true;
|
|
19
|
+
};
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
|
-
* DocGen class
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
function DocGen
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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 + '/');
|
|
37
47
|
}
|
|
38
48
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (options.input) {
|
|
43
|
-
options.input = path.normalize(options.input+'/');
|
|
44
|
-
}
|
|
45
|
-
if (options.output) {
|
|
46
|
-
options.output = path.normalize(options.output+'/');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
//wkhtmltopdf path does not need a trailing slash
|
|
50
|
-
if (options.wkhtmltopdfPath && options.wkhtmltopdfPath !== '') {
|
|
51
|
-
options.wkhtmltopdfPath = path.normalize(options.wkhtmltopdfPath);
|
|
52
|
-
}
|
|
49
|
+
//wkhtmltopdf path does not need a trailing slash
|
|
50
|
+
if (options.wkhtmltopdfPath && options.wkhtmltopdfPath !== '') {
|
|
51
|
+
options.wkhtmltopdfPath = path.normalize(options.wkhtmltopdfPath);
|
|
53
52
|
}
|
|
53
|
+
};
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
/*
|
|
56
|
+
copy the example source files (template) to any directory, when scaffold command is invoked
|
|
57
|
+
*/
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
this.scaffold = () => {
|
|
60
|
+
console.log(chalk.green('Creating scaffold template directory'));
|
|
61
|
+
copyDirSync(__dirname + '/example', options.output);
|
|
62
|
+
};
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
+
};
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
/*
|
|
72
72
|
read any file (async)
|
|
73
73
|
*/
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
+
};
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
/*
|
|
90
90
|
write any file (async)
|
|
91
91
|
*/
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
+
};
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
/*
|
|
107
107
|
copy any directory (sync)
|
|
108
108
|
*/
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
+
}
|
|
120
121
|
}
|
|
122
|
+
};
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
/*
|
|
123
125
|
remake a directory (sync) ... remove and then mkdir in one operation
|
|
124
126
|
*/
|
|
125
127
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
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
|
+
}
|
|
137
138
|
}
|
|
139
|
+
};
|
|
138
140
|
|
|
139
|
-
|
|
141
|
+
/*
|
|
140
142
|
remove any directory (sync)
|
|
141
143
|
*/
|
|
142
144
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
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
|
+
}
|
|
153
154
|
}
|
|
155
|
+
};
|
|
154
156
|
|
|
155
|
-
|
|
157
|
+
/*
|
|
156
158
|
load all HTML template files
|
|
157
159
|
*/
|
|
158
160
|
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
items: { oneOf: [ {
|
|
243
|
-
type: "object",
|
|
244
|
-
required: [ "name", "url"],
|
|
245
|
-
properties: {
|
|
246
|
-
name: { type: "string" },
|
|
247
|
-
url: { type: "string" },
|
|
248
|
-
}
|
|
249
|
-
}]}
|
|
250
|
-
},
|
|
251
|
-
website: {
|
|
252
|
-
type : "object",
|
|
253
|
-
required: [ "name", "url"],
|
|
254
|
-
properties: {
|
|
255
|
-
name: { type: "string" },
|
|
256
|
-
url: { type: "string" },
|
|
257
|
-
}
|
|
258
|
-
},
|
|
259
|
-
backlink: {
|
|
260
|
-
type : "object",
|
|
261
|
-
required: [ "name", "url"],
|
|
262
|
-
properties: {
|
|
263
|
-
name: { type: "string" },
|
|
264
|
-
url: { type: "string" },
|
|
265
|
-
}
|
|
266
|
-
},
|
|
267
|
-
module: { type: "string" },
|
|
268
|
-
id: { type: "string" },
|
|
269
|
-
summary: { type: "string" },
|
|
270
|
-
marking: { type: "string" },
|
|
271
|
-
legalese: { type: "string" },
|
|
272
|
-
}
|
|
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
|
+
},
|
|
273
244
|
},
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
245
|
+
contributors: {
|
|
246
|
+
type: 'array',
|
|
247
|
+
items: {
|
|
248
|
+
oneOf: [
|
|
249
|
+
{
|
|
250
|
+
type: 'object',
|
|
251
|
+
required: ['name', 'url'],
|
|
280
252
|
properties: {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
+
},
|
|
294
306
|
},
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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'),
|
|
298
345
|
};
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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);
|
|
308
371
|
}
|
|
372
|
+
}
|
|
309
373
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
*/
|
|
316
|
-
|
|
317
|
-
var loadMeta = function () {
|
|
318
|
-
console.log(chalk.green('Loading required JSON metadata files'));
|
|
319
|
-
var files = {
|
|
320
|
-
parameters: readFile(options.input+'/parameters.json'),
|
|
321
|
-
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' }],
|
|
322
379
|
};
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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;
|
|
341
422
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
pages: [
|
|
347
|
-
{ title: 'Release notes', source: 'release-notes.txt' }
|
|
348
|
-
]
|
|
349
|
-
};
|
|
350
|
-
meta.contents.push(extra);
|
|
351
|
-
loadMarkdown();
|
|
352
|
-
}).catch(function(error) {
|
|
353
|
-
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
|
+
);
|
|
354
427
|
if (options.verbose === true) {
|
|
355
|
-
|
|
428
|
+
console.log(chalk.red(error));
|
|
356
429
|
}
|
|
357
430
|
mainProcess.exit(1);
|
|
431
|
+
}
|
|
358
432
|
});
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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>';
|
|
395
481
|
});
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
mainProcess.exit(1);
|
|
403
|
-
});
|
|
482
|
+
html[++i] = '</li></ul>';
|
|
483
|
+
});
|
|
484
|
+
html[++i] = '</td>';
|
|
485
|
+
}
|
|
486
|
+
}
|
|
404
487
|
}
|
|
405
488
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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>';
|
|
416
504
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
html[++i] = '</li></ul>';
|
|
441
|
-
});
|
|
442
|
-
html[++i] = '</td>';
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
//fixed-width column at end
|
|
448
|
-
html[++i] = '<td class="dg-tocGroup" id="dg-tocFixedColumn"><ul>';
|
|
449
|
-
html[++i] = '<li><span class="w-icon dg-tocIcon" data-name="person_group" title="archive"></span><a href="ownership.html">Ownership</a></li>';
|
|
450
|
-
html[++i] = '<li><span class="w-icon dg-tocIcon" data-name="refresh" title="archive"></span><a href="release-notes.html">Release Notes</a></li>';
|
|
451
|
-
html[++i] = '</ul><div>';
|
|
452
|
-
if (options.pdf) {
|
|
453
|
-
html[++i] = '<button class="w-icon-button" onclick="window.location=\''+pdfName+'\';">';
|
|
454
|
-
html[++i] = '<span class="w-icon" data-name="document"></span>';
|
|
455
|
-
html[++i] = '<span>PDF copy</span>';
|
|
456
|
-
html[++i] = '</button>';
|
|
457
|
-
}
|
|
458
|
-
html[++i] = '</div></td>';
|
|
459
|
-
html[++i] = '</tr></table></div>';
|
|
460
|
-
$('#dg-toc').html(html.join(''));
|
|
461
|
-
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
|
|
462
528
|
}
|
|
463
529
|
|
|
464
|
-
|
|
465
|
-
insert the parameters into all templates
|
|
466
|
-
*/
|
|
530
|
+
//------------------------------------------------------------------------------------------------------
|
|
467
531
|
|
|
468
|
-
|
|
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';
|
|
469
536
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
try {
|
|
476
|
-
var logo = imageSizeOf(options.input+'/files/images/logo.png');
|
|
477
|
-
logoWidth = logo.width;
|
|
478
|
-
logoHeight = logo.height;
|
|
479
|
-
hasLogo = true;
|
|
480
|
-
} catch (error) {
|
|
481
|
-
//do nothing. If logo file cannot be read, logo is simply not shown
|
|
482
|
-
}
|
|
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 + '.';
|
|
483
542
|
|
|
484
|
-
|
|
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
|
+
}
|
|
485
551
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
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
|
+
}
|
|
489
563
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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
|
+
}
|
|
494
575
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
+
}
|
|
503
587
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
+
}
|
|
510
599
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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
|
+
}
|
|
517
611
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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');
|
|
521
640
|
} else {
|
|
522
|
-
|
|
641
|
+
$('#dg-logo').css('padding-left', '0');
|
|
523
642
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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>');
|
|
528
705
|
} else {
|
|
529
|
-
|
|
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
|
+
);
|
|
530
710
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
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">';
|
|
537
720
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
} else {
|
|
544
|
-
contributors += contributor.name+', ';
|
|
545
|
-
}
|
|
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>';
|
|
546
726
|
});
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
var copyright = '© '+year+' '+organization;
|
|
550
|
-
|
|
551
|
-
var webTitle = meta.parameters.title
|
|
552
|
-
|
|
553
|
-
var webFooter = 'Version '+releaseVersion+' released on '+releaseDate+'.';
|
|
554
|
-
|
|
555
|
-
for (var key in templates) {
|
|
556
|
-
if (templates.hasOwnProperty(key)) {
|
|
557
|
-
$ = templates[key];
|
|
558
|
-
//logo
|
|
559
|
-
if (hasLogo === true) {
|
|
560
|
-
var logoUrl = 'files/images/logo.png';
|
|
561
|
-
$('#dg-logo').css('background-image', 'url(' + logoUrl + ')');
|
|
562
|
-
$('#dg-logo').css('height', logoHeight+'px');
|
|
563
|
-
$('#dg-logo').css('line-height', logoHeight+'px');
|
|
564
|
-
$('#dg-logo').css('padding-left', (logoWidth+25)+'px');
|
|
565
|
-
} else {
|
|
566
|
-
$('#dg-logo').css('padding-left', '0');
|
|
567
|
-
}
|
|
568
|
-
//parameters
|
|
569
|
-
$('title').text(meta.parameters.title);
|
|
570
|
-
$('#dg-homelink').attr('href', homelink);
|
|
571
|
-
$('#dg-title').text(meta.parameters.title);
|
|
572
|
-
$('#dg-owner').html(owner);
|
|
573
|
-
$('#dg-version').text(releaseVersion);
|
|
574
|
-
$('#dg-web-title-version').text('('+releaseVersion+')');
|
|
575
|
-
$('#dg-release-date').text(releaseDate);
|
|
576
|
-
$('#dg-web-footer').text(webFooter);
|
|
577
|
-
$('#dg-author').html(author);
|
|
578
|
-
$('#dg-contributors').html(contributors);
|
|
579
|
-
$('#dg-module').text(meta.parameters.module);
|
|
580
|
-
$('#dg-id').html(meta.parameters.id);
|
|
581
|
-
$('#dg-website').html(website);
|
|
582
|
-
$('#dg-backlink').html(backlink);
|
|
583
|
-
$('#dg-summary').text(meta.parameters.summary);
|
|
584
|
-
$('#dg-copyright').html(copyright);
|
|
585
|
-
$('#dg-marking').text(meta.parameters.marking);
|
|
586
|
-
$('#dg-legalese').text(meta.parameters.legalese);
|
|
587
|
-
$('#dg-attribution').text(attribution);
|
|
588
|
-
}
|
|
727
|
+
if (headings.length > 0) {
|
|
728
|
+
html[++i] = '</ul>';
|
|
589
729
|
}
|
|
590
|
-
if (options.
|
|
591
|
-
|
|
592
|
-
//support for KaTeX (bundled with DocGen)
|
|
593
|
-
$('head').append('<link rel="stylesheet" href="require/katex/katex.min.css" type="text/css">');
|
|
594
|
-
$('head').append('<script type="text/javascript" src="require/katex/katex.min.js"></script>');
|
|
595
|
-
$('head').append('<script type="text/javascript" src="require/katexInjector.js"></script>');
|
|
596
|
-
|
|
730
|
+
if (options.pageToc === true && page.html !== true) {
|
|
731
|
+
$('#dg-innerContent').prepend(html.join(''));
|
|
597
732
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
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');
|
|
603
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
|
+
);
|
|
604
794
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
section.pages.forEach( function (page) {
|
|
616
|
-
var $ = cheerio.load(templates.main.html()); //clone
|
|
617
|
-
var key = page.source;
|
|
618
|
-
var content = pages[key];
|
|
619
|
-
//add relevant container
|
|
620
|
-
if (page.html === true) { //raw HTML pages should not be confined to the fixed width
|
|
621
|
-
$('#dg-content').html('<div id="dg-innerContent"></div>');
|
|
622
|
-
} else { //Markdown pages should be confined to the fixed width
|
|
623
|
-
$('#dg-content').html('<div class="w-fixed-width"><div id="dg-innerContent"></div></div>');
|
|
624
|
-
}
|
|
625
|
-
$('#dg-innerContent').html(content);
|
|
626
|
-
//------------------------------------------------------------------------------------------------------
|
|
627
|
-
//insert permalinks for every page heading
|
|
628
|
-
//when pageToc is enabled, also insert a page-level table of contents
|
|
629
|
-
var html = [], i = -1;
|
|
630
|
-
var headings = $('h1, h2, h3, h4, h5, h6');
|
|
631
|
-
if (headings.length > 0) {
|
|
632
|
-
html[++i] = '<ul class="dg-pageToc">';
|
|
633
|
-
}
|
|
634
|
-
headings.each(function( index ) {
|
|
635
|
-
var label = $(this).text();
|
|
636
|
-
var anchor = label.toLowerCase().replace(/\s+/g, "-");
|
|
637
|
-
$(this).attr('id', anchor);
|
|
638
|
-
html[++i] = '<li><a href="#'+anchor+'">'+label+'</a></li>';
|
|
639
|
-
});
|
|
640
|
-
if (headings.length > 0) {
|
|
641
|
-
html[++i] = '</ul>';
|
|
642
|
-
}
|
|
643
|
-
if (options.pageToc === true && page.html !== true) {
|
|
644
|
-
$('#dg-innerContent').prepend(html.join(''));
|
|
645
|
-
}
|
|
646
|
-
//------------------------------------------------------------------------------------------------------
|
|
647
|
-
//prepend the auto heading (which makes the PDF table of contents match the web TOC)
|
|
648
|
-
$('#dg-innerContent').prepend('<h1 id="dg-autoTitle">'+page.title+'</h1>');
|
|
649
|
-
if (page.html === true) {
|
|
650
|
-
$('#dg-autoTitle').addClass('dg-hiddenTitle');
|
|
651
|
-
}
|
|
652
|
-
//------------------------------------------------------------------------------------------------------
|
|
653
|
-
//apply the w-table class
|
|
654
|
-
$('table:not(.unstyled)').addClass('w-table w-fixed w-stripe');
|
|
655
|
-
//------------------------------------------------------------------------------------------------------
|
|
656
|
-
pages[key] = $;
|
|
657
|
-
});
|
|
658
|
-
});
|
|
659
|
-
//add web ownership page
|
|
660
|
-
var $ = cheerio.load(templates.main.html()); //clone
|
|
661
|
-
$('#dg-content').html('<div class="w-fixed-width"><div id="dg-innerContent"></div></div>');
|
|
662
|
-
$('#dg-innerContent').html(templates.webCover.html());
|
|
663
|
-
templates.webCover = $;
|
|
664
|
-
writePages();
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/*
|
|
668
|
-
write each html page
|
|
669
|
-
*/
|
|
670
|
-
|
|
671
|
-
var writePages = function () {
|
|
672
|
-
console.log(chalk.green('Writing the web page files'));
|
|
673
|
-
var promises = {};
|
|
674
|
-
meta.contents.forEach( function (section) {
|
|
675
|
-
section.pages.forEach( function (page) {
|
|
676
|
-
var key = page.source;
|
|
677
|
-
var name = key.substr(0, page.source.lastIndexOf('.'));
|
|
678
|
-
var path = options.output+name+'.html';
|
|
679
|
-
var html = pages[key].html();
|
|
680
|
-
promises[key] = writeFile(path, html);
|
|
681
|
-
});
|
|
682
|
-
});
|
|
683
|
-
//add extra files
|
|
684
|
-
promises['ownership'] = writeFile(options.output+'ownership.html', templates.webCover.html());
|
|
685
|
-
if (options.pdf === true) {
|
|
686
|
-
var pdfTempDir = options.output+'temp/';
|
|
687
|
-
fs.mkdirsSync(pdfTempDir);
|
|
688
|
-
promises['docgenPdfCover'] = writeFile(pdfTempDir+'pdfCover.html', templates.pdfCover.html());
|
|
689
|
-
promises['docgenPdfHeader'] = writeFile(pdfTempDir+'pdfHeader.html', templates.pdfHeader.html());
|
|
690
|
-
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
|
+
);
|
|
691
805
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
checkPdfVersion();
|
|
699
|
-
}).catch(function(error) {
|
|
700
|
-
console.log(chalk.red('Error writing the web page files'));
|
|
701
|
-
if (options.verbose === true) {
|
|
702
|
-
console.log(chalk.red(error));
|
|
703
|
-
}
|
|
704
|
-
mainProcess.exit(1);
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
/*
|
|
709
|
-
wkthmltopdf options
|
|
710
|
-
*/
|
|
711
|
-
|
|
712
|
-
var pdfOptions = [
|
|
713
|
-
' --zoom 1.0',
|
|
714
|
-
' --image-quality 100',
|
|
715
|
-
' --print-media-type',
|
|
716
|
-
' --orientation portrait',
|
|
717
|
-
' --page-size A4',
|
|
718
|
-
' --margin-top 25',
|
|
719
|
-
' --margin-right 15',
|
|
720
|
-
' --margin-bottom 16',
|
|
721
|
-
' --margin-left 15',
|
|
722
|
-
' --header-spacing 5',
|
|
723
|
-
' --footer-spacing 5',
|
|
724
|
-
' --no-stop-slow-scripts',
|
|
725
|
-
];
|
|
726
|
-
|
|
727
|
-
var getPdfArguments = function () {
|
|
728
|
-
var pdfName = meta.parameters.name.toLowerCase()+'.pdf';
|
|
729
|
-
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?)
|
|
730
|
-
pdfOptions.push(' --user-style-sheet '+__dirname+'/pdf-stylesheet.css');
|
|
731
|
-
pdfOptions.push(' --header-html '+options.output+'temp/pdfHeader.html');
|
|
732
|
-
pdfOptions.push(' --footer-html '+options.output+'temp/pdfFooter.html');
|
|
733
|
-
pdfOptions.push(' cover '+options.output+'temp/pdfCover.html');
|
|
734
|
-
pdfOptions.push(' toc --xsl-style-sheet '+__dirname+'/pdf-contents.xsl');
|
|
735
|
-
var allPages = '';
|
|
736
|
-
for (var key in sortedPages) {
|
|
737
|
-
if (sortedPages.hasOwnProperty(key)) {
|
|
738
|
-
sortedPages[key].forEach( function (section) {
|
|
739
|
-
section.pages.forEach( function (page) {
|
|
740
|
-
var key = page.source;
|
|
741
|
-
var name = key.substr(0, page.source.lastIndexOf('.'));
|
|
742
|
-
var path = options.output+name+'.html';
|
|
743
|
-
allPages += ' '+path;
|
|
744
|
-
});
|
|
745
|
-
});
|
|
746
|
-
}
|
|
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));
|
|
747
812
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
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
|
+
}
|
|
752
859
|
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
console.log(chalk.yellow(detectedVersion));
|
|
774
|
-
}
|
|
775
|
-
generatePdf();
|
|
776
|
-
}
|
|
777
|
-
});
|
|
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);
|
|
778
880
|
} else {
|
|
779
|
-
|
|
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();
|
|
780
894
|
}
|
|
895
|
+
});
|
|
896
|
+
} else {
|
|
897
|
+
cleanUp();
|
|
781
898
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
wkhtmltopdf.stdout.on('data', function (data) {
|
|
811
|
-
//do nothing
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
wkhtmltopdf.stderr.on('data', function (data) {
|
|
815
|
-
//do nothing
|
|
816
|
-
});
|
|
817
|
-
|
|
818
|
-
wkhtmltopdf.on('close', function (code) {
|
|
819
|
-
if (options.verbose !== true) {
|
|
820
|
-
spinner.stop();
|
|
821
|
-
console.log(''); //newline after spinner stops
|
|
822
|
-
}
|
|
823
|
-
if (code !== 0) {
|
|
824
|
-
var warning = 'wkhtmltopdf exited with a warning or error: try the -v option for details';
|
|
825
|
-
console.log(chalk.yellow(warning));
|
|
826
|
-
}
|
|
827
|
-
cleanUp();
|
|
828
|
-
});
|
|
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);
|
|
829
926
|
}
|
|
830
927
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
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));
|
|
851
968
|
}
|
|
969
|
+
//don't exit because redirect error is not a fatal error
|
|
970
|
+
}
|
|
852
971
|
}
|
|
972
|
+
};
|
|
853
973
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
974
|
+
/*
|
|
975
|
+
cleanup
|
|
976
|
+
*/
|
|
857
977
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
}
|
|
864
|
-
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');
|
|
865
983
|
}
|
|
984
|
+
console.log(chalk.green.bold('Done!'));
|
|
985
|
+
};
|
|
866
986
|
}
|
|
867
987
|
|
|
868
988
|
module.exports = DocGen;
|