Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81159 views
1
var assert = require("assert");
2
var path = require("path");
3
var Q = require("q");
4
var util = require("./util");
5
var spawn = require("child_process").spawn;
6
var ReadFileCache = require("./cache").ReadFileCache;
7
var grepP = require("./grep");
8
var glob = require("glob");
9
var env = process.env;
10
11
function BuildContext(options, readFileCache) {
12
var self = this;
13
assert.ok(self instanceof BuildContext);
14
assert.ok(readFileCache instanceof ReadFileCache);
15
16
if (options) {
17
assert.strictEqual(typeof options, "object");
18
} else {
19
options = {};
20
}
21
22
Object.freeze(options);
23
24
Object.defineProperties(self, {
25
readFileCache: { value: readFileCache },
26
config: { value: options.config },
27
options: { value: options },
28
optionsHash: { value: util.deepHash(options) }
29
});
30
}
31
32
var BCp = BuildContext.prototype;
33
34
BCp.makePromise = function(callback, context) {
35
return util.makePromise(callback, context);
36
};
37
38
BCp.spawnP = function(command, args, kwargs) {
39
args = args || [];
40
kwargs = kwargs || {};
41
42
var deferred = Q.defer();
43
44
var outs = [];
45
var errs = [];
46
47
var options = {
48
stdio: "pipe",
49
env: env
50
};
51
52
if (kwargs.cwd) {
53
options.cwd = kwargs.cwd;
54
}
55
56
var child = spawn(command, args, options);
57
58
child.stdout.on("data", function(data) {
59
outs.push(data);
60
});
61
62
child.stderr.on("data", function(data) {
63
errs.push(data);
64
});
65
66
child.on("close", function(code) {
67
if (errs.length > 0 || code !== 0) {
68
var err = {
69
code: code,
70
text: errs.join("")
71
};
72
}
73
74
deferred.resolve([err, outs.join("")]);
75
});
76
77
var stdin = kwargs && kwargs.stdin;
78
if (stdin) {
79
child.stdin.end(stdin);
80
}
81
82
return deferred.promise;
83
};
84
85
BCp.setIgnoreDependencies = function(value) {
86
Object.defineProperty(this, "ignoreDependencies", {
87
value: !!value
88
});
89
};
90
91
// This default can be overridden by individual BuildContext instances.
92
BCp.setIgnoreDependencies(false);
93
94
BCp.setRelativize = function(value) {
95
Object.defineProperty(this, "relativize", {
96
value: !!value
97
});
98
};
99
100
// This default can be overridden by individual BuildContext instances.
101
BCp.setRelativize(false);
102
103
BCp.setUseProvidesModule = function(value) {
104
Object.defineProperty(this, "useProvidesModule", {
105
value: !!value
106
});
107
};
108
109
// This default can be overridden by individual BuildContext instances.
110
BCp.setUseProvidesModule(false);
111
112
BCp.setCacheDirectory = function(dir) {
113
if (!dir) {
114
// Disable the cache directory.
115
} else {
116
assert.strictEqual(typeof dir, "string");
117
}
118
119
Object.defineProperty(this, "cacheDir", {
120
value: dir || null
121
});
122
};
123
124
// This default can be overridden by individual BuildContext instances.
125
BCp.setCacheDirectory(null);
126
127
function PreferredFileExtension(ext) {
128
assert.strictEqual(typeof ext, "string");
129
assert.ok(this instanceof PreferredFileExtension);
130
Object.defineProperty(this, "extension", {
131
value: ext.toLowerCase()
132
});
133
}
134
135
var PFEp = PreferredFileExtension.prototype;
136
137
PFEp.check = function(file) {
138
return file.split(".").pop().toLowerCase() === this.extension;
139
};
140
141
PFEp.trim = function(file) {
142
if (this.check(file)) {
143
var len = file.length;
144
var extLen = 1 + this.extension.length;
145
file = file.slice(0, len - extLen);
146
}
147
return file;
148
};
149
150
PFEp.glob = function() {
151
return "**/*." + this.extension;
152
};
153
154
exports.PreferredFileExtension = PreferredFileExtension;
155
156
BCp.setPreferredFileExtension = function(pfe) {
157
assert.ok(pfe instanceof PreferredFileExtension);
158
Object.defineProperty(this, "preferredFileExtension", { value: pfe });
159
};
160
161
BCp.setPreferredFileExtension(new PreferredFileExtension("js"));
162
163
BCp.expandIdsOrGlobsP = function(idsOrGlobs) {
164
var context = this;
165
166
return Q.all(
167
idsOrGlobs.map(this.expandSingleIdOrGlobP, this)
168
).then(function(listOfListsOfIDs) {
169
var result = [];
170
var seen = {};
171
172
util.flatten(listOfListsOfIDs).forEach(function(id) {
173
if (!seen.hasOwnProperty(id)) {
174
seen[id] = true;
175
if (util.isValidModuleId(id))
176
result.push(id);
177
}
178
});
179
180
return result;
181
});
182
};
183
184
BCp.expandSingleIdOrGlobP = function(idOrGlob) {
185
var context = this;
186
187
return util.makePromise(function(callback) {
188
// If idOrGlob already looks like an acceptable identifier, don't
189
// try to expand it.
190
if (util.isValidModuleId(idOrGlob)) {
191
callback(null, [idOrGlob]);
192
return;
193
}
194
195
glob(idOrGlob, {
196
cwd: context.readFileCache.sourceDir
197
}, function(err, files) {
198
if (err) {
199
callback(err);
200
} else {
201
callback(null, files.filter(function(file) {
202
return !context.isHiddenFile(file);
203
}).map(function(file) {
204
return context.preferredFileExtension.trim(file);
205
}));
206
}
207
});
208
});
209
};
210
211
BCp.readModuleP = function(id) {
212
return this.readFileCache.readFileP(
213
id + "." + this.preferredFileExtension.extension
214
);
215
};
216
217
BCp.readFileP = function(file) {
218
return this.readFileCache.readFileP(file);
219
};
220
221
// Text editors such as VIM and Emacs often create temporary swap files
222
// that should be ignored.
223
var hiddenExp = /^\.|~$/;
224
BCp.isHiddenFile = function(file) {
225
return hiddenExp.test(path.basename(file));
226
};
227
228
BCp.getProvidedP = util.cachedMethod(function() {
229
var context = this;
230
var pattern = "@providesModule\\s+\\S+";
231
232
return grepP(
233
pattern,
234
context.readFileCache.sourceDir
235
).then(function(pathToMatch) {
236
var idToPath = {};
237
238
Object.keys(pathToMatch).sort().forEach(function(path) {
239
if (context.isHiddenFile(path))
240
return;
241
242
var id = pathToMatch[path].split(/\s+/).pop();
243
244
// If we're about to overwrite an existing module identifier,
245
// make sure the corresponding path ends with the preferred
246
// file extension. This allows @providesModule directives in
247
// .coffee files, for example, but prevents .js~ temporary
248
// files from taking precedence over actual .js files.
249
if (!idToPath.hasOwnProperty(id) ||
250
context.preferredFileExtension.check(path))
251
idToPath[id] = path;
252
});
253
254
return idToPath;
255
});
256
});
257
258
var providesExp = /@providesModule[ ]+(\S+)/;
259
260
BCp.getProvidedId = function(source) {
261
var match = providesExp.exec(source);
262
return match && match[1];
263
};
264
265
exports.BuildContext = BuildContext;
266
267