This repository has been archived by the owner on Jun 7, 2019. It is now read-only.
forked from devongovett/node-wkhtmltopdf
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
134 lines (110 loc) · 4.39 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
var spawn = require('child_process').spawn;
var slang = require('slang');
function quote(val) {
// escape and quote the value if it is a string and this isn't windows
if (typeof val === 'string' && process.platform !== 'win32')
val = '"' + val.replace(/(["\\$`])/g, '\\$1') + '"';
return val;
}
function formatKey(key) {
if (key !== 'toc' && key !== 'cover' && key !== 'page')
return key.length === 1 ? '-' + key : '--' + slang.dasherize(key);
}
function optionToArgArray(key, val) {
if (typeof val == 'boolean')
return val ? [formatKey(key)] : [];
else
return [formatKey(key), quote(val)];
}
function wkhtmlto(commandStr) { return function(input, options, callback) {
// In older releases, a user could set alternative command using the
// module.exports.command variable. The following line is to ensure backward
// compatability. However, this is considered deprecated and the user is
// strongly encouraged to use module.exports.image for wkhtmltoimage. If a
// custom command is needed, the user is encouraged to use
// module.exports.customCommand('/my/custom/path/to/wkhtmltopdf')
// which accepts a command string as its first parameter.
command = module.exports.command ? module.exports.command : commandStr;
if (!options) {
options = {};
} else if (typeof options == 'function') {
callback = options;
options = {};
}
var output = options.output;
delete options.output;
// make sure the special keys are last
var extraKeys = [];
var keys = Object.keys(options).filter(function(key) {
if (key === 'toc' || key === 'cover' || key === 'page') {
extraKeys.push(key);
return false;
}
return true;
}).concat(extraKeys);
var args = [command, '--quiet'];
keys.forEach(function(optKey) {
var optVal = options[optKey];
if (Array.isArray(optVal)) {
// when optVal is an array we handle the array as a repeatable option.
// i.e. { allow: ['c', 'd'] } becomes --allow "c" --allow "d"
optVal.forEach(function(val) {
args = args.concat(optionToArgArray(optKey, val));
});
} else if (typeof optVal == 'object') {
// when optVal is an object we handle each property as argument pairs
// when more than one property exists we handle the properties as a
// repeatable option
// i.e. {cookie: { 'a': 'apple', 'b': 'banana'}} becomes
// --cookie "a" "apple" --cookie "b" "banana"
Object.keys(optVal).forEach(function(key) {
var val = optVal[key];
args = args.concat([formatKey(optKey), quote(key), quote(val)]);
});
} else {
//otherwise, optVal is a single value.
args = args.concat(optionToArgArray(optKey, optVal));
}
});
var isUrl = /^(https?|file):\/\//.test(input);
args.push(isUrl ? quote(input) : '-'); // stdin if HTML given directly
args.push(output ? quote(output) : '-'); // stdout if no output file
if (process.platform === 'win32') {
var child = spawn(args[0], args.slice(1));
} else {
// this nasty business prevents piping problems on linux
var child = spawn('/bin/sh', ['-c', args.join(' ') + ' | cat']);
}
// call the callback with null error when the process exits successfully
if (callback)
child.on('exit', function() { callback(null); });
// setup error handling
var stream = child.stdout;
function handleError(err) {
child.removeAllListeners('exit');
child.kill();
// call the callback if there is one
if (callback)
callback(err);
// if not, or there are listeners for errors, emit the error event
if (!callback || stream.listeners('error').length > 0)
stream.emit('error', err);
}
child.once('error', handleError);
child.stderr.once('data', function(err) {
handleError(new Error((err || '').toString().trim()));
});
// write input to stdin if it isn't a url
if (!isUrl)
child.stdin.end(input);
// return stdout stream so we can pipe
return stream;
}; }
// For backwards compatability we make sure that the object returned is a
// function that produces pdfs (deprecated)
module.exports = wkhtmlto('wkhtmltopdf');
// And the preferred interface is to call .pdf or .image
module.exports.pdf = wkhtmlto('wkhtmltopdf');
module.exports.image = wkhtmlto('wkhtmltoimage');
// Support custom commands other than wkhtmltopdf and wkhtmltoimage
module.exports.customCommand = wkhtmlto