This repository was archived by the owner on Sep 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathpandoc.js
More file actions
169 lines (138 loc) · 4.16 KB
/
pandoc.js
File metadata and controls
169 lines (138 loc) · 4.16 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
* node-pandoc
*
* This is the main, and currently only, file. It wraps the `pandoc` command
* using node's child_process module. Since we still have to support node 0.4.x
* (latest stable) we have to use spawn instead of fork().
*/
var childProcess = require('child_process');
var spawn = childProcess.spawn;
var exec = childProcess.exec;
// The global command line args for pandocs.
var globalArgs = {
//what the user provided
provided: null,
//whether to persist between convert() calls
persist: false,
//resets back to defaults
reset: function() {
this.provided = null;
this.persist = false;
}
};
/*
* type is the input markup's type
*
* input is the input markup
*
* types is an array of markup types to convert to or a single type as a string
*
* callback will be passed an object mapping markup type to markup, unless
* there was an error in which case it gets passed (null, statusCode)
*/
exports.convert = function(type, input, types, callback) {
var res = {};
var numResponses = 0;
var targetResponses;
var pandoc;
var args;
var i;
if(!type || typeof type !== 'string') {
throw 'Invalid source markup type: must be a string.';
}
if(!input || typeof input !== 'string') {
throw 'Invalid markup type: must be a string.';
}
if(typeof types !== 'string' && !Array.isArray(types)) {
throw 'Invalid destination types: must be a string or an array of strings.';
}
if(types.length <= 0) {
throw 'No destination types provided (empty array).';
}
if(typeof callback !== 'function') {
if(callback) {
throw 'Invalid callback provided: must be a function.';
}
else {
throw 'No callback provided: must be a function.';
}
}
//what we're going to send to the callback if there are no pandoc errors
res[type] = input;
if(typeof types === 'string') {
types = [ types ];
}
targetResponses = types.length;
exec('which pandoc', function(err, stdout) {
var pandocPath;
if(err) {
throw err;
}
if(!stdout) {
throw new Error('Cannot find pandoc - is it installed?');
}
//strip the newline
pandocPath = stdout.substr(0, stdout.length - 1);
for(i in types) {
if(types.hasOwnProperty(i)) {
if(typeof types[i] !== 'string') {
throw 'Invalid destination type provided: non-string value found in array.';
}
/*
* This if-block filters out the target markup type because we already set
* it on the res object.
*/
if(!res[types[i]]) {
args = globalArgs.provided || [];
args.push('-f', type, '-t', types[i]);
pandoc = spawn(pandocPath, args);
//so that we have the target type in scope on('data') - love ya some asynch
pandoc.stdout.targetType = types[i];
pandoc.stdout.on('data', function(data) {
//data will be a binary stream if you don't cast it to a string
res[this.targetType] = data + '';
});
pandoc.on('error', function(err) {
callback(null, err);
});
pandoc.on('exit', function(code, signal) {
numResponses++;
if(code !== 0) {
callback(null, code);
}
else if(numResponses === targetResponses) {
callback(res);
}
});
//pipe them the input
pandoc.stdin.write(input, 'utf8');
pandoc.stdin.end();
if(!globalArgs.persist) {
globalArgs.reset();
}
}
}
}
});
};
/*
* args is an array of command line arguments that should be passed to pandoc
* on the next call. If set to a non-array value, then default args will be
* used. The default behavior is that they will be thrown away before the next
* call.
*
* persist is a boolean that when set to true will persist the provided args
* for future calls.
*
* Returns this module so you can chain this funciton with convert().
*/
exports.args = function(args, persist) {
if(Array.isArray(args)) {
globalArgs.provided = args;
globalArgs.persist = persist;
}
else {
globalArgs.reset();
}
return exports;
};