1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | var undef, conf
|
17 | , PAC = require("../../package.json")
|
18 | , fs = require("fs")
|
19 | , child = require("child_process")
|
20 | , spawn = child.spawn
|
21 | , now = new Date()
|
22 | , path = require("../path")
|
23 | , events = require("../events")
|
24 | , cli = require("./")
|
25 | , Fn = require("../fn.js").Fn
|
26 | , files = {}
|
27 | , fileHashes = {}
|
28 | , hasOwn = files.hasOwnProperty
|
29 | , adapters = File.adapters = {
|
30 | css: {
|
31 | split: cssSplit, min: cssMin, banner: "/*! {0} */\n"
|
32 | },
|
33 | html: {
|
34 | split: htmlSplit, sep: "", banner: "<!-- {0} -->\n",
|
35 | transpilers: {
|
36 | js: jsToHtml, css: cssToHtml
|
37 | }
|
38 | },
|
39 | js: {
|
40 | min: jsMin, banner: "/*! {0} */\n",
|
41 | transpilers: {
|
42 | tpl: tplToJs, view: tplToJs
|
43 | }
|
44 | },
|
45 | tpl: {
|
46 | min: tplMin, banner: "/{0}\n"
|
47 | }
|
48 | }
|
49 | , translate = {
|
50 |
|
51 | stability: "0 - Deprecated,1 - Experimental,2 - Unstable,3 - Stable,4 - API Frozen,5 - Locked".split(","),
|
52 | date: now.toISOString().split("T")[0]
|
53 | }
|
54 | , linked = __dirname.indexOf(process.cwd()) !== 0
|
55 |
|
56 | adapters.view = adapters.tpl
|
57 |
|
58 | try {
|
59 | conf = require(path.resolve("package.json"))
|
60 | console.log("# Build %s@%s with %s@%s", conf.name, conf.version, PAC.name, PAC.version)
|
61 | } catch(e) {
|
62 | console.error(e)
|
63 | conf = {}
|
64 | }
|
65 |
|
66 | if (linked) {
|
67 | module.paths = require("module")._nodeModulePaths(process.cwd())
|
68 |
|
69 |
|
70 | }
|
71 |
|
72 | function File(_name, _opts) {
|
73 | var file = this
|
74 | , name = _name === "-" ? _name : path.resolve(_name.split("?")[0])
|
75 |
|
76 | if (_name && files[name]) {
|
77 | return files[name]
|
78 | }
|
79 | if (!(file instanceof File)) {
|
80 | return new File(_name, _opts)
|
81 | }
|
82 |
|
83 | var opts = file.opts = _opts || {}
|
84 | , ext = file.ext = opts.ext || (
|
85 | name === "-" ?
|
86 | "" + opts.input :
|
87 | name
|
88 | ).split(".").pop()
|
89 |
|
90 | files[name] = file
|
91 | file._depends = []
|
92 | file.write = file.write.bind(file)
|
93 |
|
94 | if (!("root" in opts)) {
|
95 | opts.root = name.replace(/[^\/]*$/, "")
|
96 | }
|
97 | file.name = opts.name = name
|
98 |
|
99 | if (typeof opts.input == "string") {
|
100 | opts.input = [ opts.input ]
|
101 | }
|
102 | if (!opts.warnings) opts.warnings = []
|
103 |
|
104 | if (opts.sourceMap === true) {
|
105 | opts.sourceMap = name.replace(/\?|$/, ".map$&").slice(opts.root.length)
|
106 | }
|
107 | if (opts.drop) {
|
108 | if (!opts.replace) {
|
109 | opts.replace = []
|
110 | }
|
111 | opts.replace.push(
|
112 | [ new RegExp("\\/\\/(?=\\*\\*\\s+(?:" + opts.drop.replace(/[\s,]+/g, "|") + "))", "g"), "/"],
|
113 | [ new RegExp("\\/(\\*{2,})\\s+(?:" + opts.drop.replace(/[^\w]+/g, "|") + ")\\s+\\1\\/", "g"), "$&/*"]
|
114 | )
|
115 | }
|
116 |
|
117 | file.reset()
|
118 |
|
119 | setImmediate(file.wait())
|
120 |
|
121 | file.build()
|
122 |
|
123 | return file
|
124 | }
|
125 |
|
126 | File.prototype = {
|
127 | wait: Fn.hold,
|
128 | syncMethods: ["on", "toString"],
|
129 | depends: function(child) {
|
130 | var file = this
|
131 | child.on("change", file.write)
|
132 | },
|
133 | reset: function() {
|
134 | var file = this
|
135 |
|
136 | file._depends.forEach(function() {
|
137 | child.off("change", file.write)
|
138 | })
|
139 | file._depends.length = 0
|
140 | file.content = []
|
141 | },
|
142 | build: function() {
|
143 | var file = this
|
144 | , opts = file.opts
|
145 | , resume = file.wait()
|
146 | , adapter = adapters[file.ext] || {}
|
147 | , buildResume = Fn.wait(min)
|
148 |
|
149 | if (opts.input) {
|
150 | file.content = opts.input.map(function(fileName, i, arr) {
|
151 | var child = fileName
|
152 | if (!(fileName instanceof File)) {
|
153 | if (!fs.existsSync(path.resolve(fileName))) {
|
154 | fileName = arr[i] = require.resolve(fileName)
|
155 | }
|
156 | child = File(fileName, {
|
157 | root: opts.root,
|
158 | warnings: opts.warnings
|
159 | })
|
160 | }
|
161 | child.then(buildResume.wait())
|
162 | file.depends(child)
|
163 | return child
|
164 | })
|
165 | file.write()
|
166 | } else {
|
167 | if (!opts.mem) {
|
168 | var source = cli.readFile(file.name)
|
169 | file.content = adapter.split ? adapter.split(source, opts) : [ source ]
|
170 | }
|
171 | file.content.forEach(function(junk, i, arr) {
|
172 | if (junk instanceof File) {
|
173 | file.depends(junk)
|
174 | junk.then(buildResume.wait())
|
175 | }
|
176 | })
|
177 | }
|
178 |
|
179 | setImmediate(buildResume)
|
180 |
|
181 | function min() {
|
182 | file.src = file.content
|
183 | .filter(Boolean)
|
184 | .map(function(f) {
|
185 | if (
|
186 | typeof f === "string" ||
|
187 | adapters[file.ext] === adapters[f.ext] ||
|
188 | !adapters[file.ext].transpilers ||
|
189 | !adapters[file.ext].transpilers[f.ext]
|
190 | ) return f
|
191 | return adapters[file.ext].transpilers[f.ext](f.toString())
|
192 | })
|
193 | .join("sep" in adapter ? adapter.sep : "\n")
|
194 |
|
195 | if (opts.replace) {
|
196 | opts.replace.forEach(function(arr) {
|
197 | file.src = file.src.replace(arr[0], arr[1] || "")
|
198 | })
|
199 | }
|
200 |
|
201 | if (adapter.min && opts.min) {
|
202 | var map = file.content.reduce(function(map, f) {
|
203 | var str = f instanceof File ? f.src : f
|
204 | if (opts.replace) opts.replace.forEach(function(arr) {
|
205 | str = str.replace(arr[0], arr[1])
|
206 | })
|
207 | map[f.name] = (
|
208 | typeof f !== "string" &&
|
209 | adapters[file.ext] !== adapters[f.ext] &&
|
210 | adapters[file.ext].transpilers &&
|
211 | adapters[file.ext].transpilers[f.ext] ?
|
212 | adapters[file.ext].transpilers[f.ext](f.toString()) :
|
213 | str
|
214 | )
|
215 | return map
|
216 | }, {})
|
217 | adapter.min(map, opts, function(err, res) {
|
218 | file.min = res
|
219 | resume()
|
220 | })
|
221 | } else {
|
222 | resume()
|
223 | }
|
224 | }
|
225 | },
|
226 | write: function(by) {
|
227 | var file = this
|
228 | if (file.name === "-") {
|
229 | process.stdout.write(file.toString())
|
230 | } else if (!file.opts.mem) {
|
231 | cli.writeFile(file.name, file.toString())
|
232 | if (fileHashes[file.name]) {
|
233 |
|
234 | var fullHash = child.execSync("git hash-object " + file.name).toString("utf8")
|
235 | fileHashes[file.name] = child.execSync("git rev-parse --short=4 " + fullHash).toString("utf8")
|
236 | }
|
237 | }
|
238 | if (file.opts.warnings.length) {
|
239 | console.error("WARNINGS:\n - " + file.opts.warnings.join("\n - "))
|
240 | }
|
241 | },
|
242 | then: function(next, scope) {
|
243 | if (typeof next == "function") {
|
244 | next.call(scope || this)
|
245 | }
|
246 | return this
|
247 | },
|
248 | toString: function() {
|
249 | var file = this
|
250 | , opts = file.opts
|
251 | , adapter = adapters[file.ext] || {}
|
252 | , banner = opts.banner && adapter.banner && adapter.banner.replace(/\{0\}/g, opts.banner)
|
253 | , str = adapter.min && opts.min ? file.min : format(file.src)
|
254 | , out = (
|
255 | (banner ? format(banner) : "") +
|
256 | str.trim() +
|
257 | (opts.sourceMap ? "\n//# sourceMappingURL=" + opts.sourceMap + "\n" : "")
|
258 | )
|
259 |
|
260 | if (opts.outPrefix) {
|
261 | out = opts.outPrefix + out.split("\n").join("\n" + opts.outPrefix)
|
262 | }
|
263 |
|
264 | return out
|
265 | }
|
266 | }
|
267 |
|
268 | events.asEmitter(File.prototype)
|
269 |
|
270 | function defMap(str) {
|
271 | var chr = str.charAt(0)
|
272 | , slice = str.slice(1)
|
273 | return chr == "+" ? lastStr + slice :
|
274 | chr == "%" ? ((chr = lastStr.lastIndexOf(slice.charAt(0))), (chr > 0 ? lastStr.slice(0, chr) : lastStr)) + slice :
|
275 | (chr == "." && this.root ? this.root : "") + (lastStr = str)
|
276 | }
|
277 |
|
278 | function htmlQuote(val) {
|
279 |
|
280 |
|
281 | return (
|
282 | /^[^\s'"`<>=]+$/.test(val) ? '"' + val + '"' :
|
283 | val
|
284 | )
|
285 | }
|
286 |
|
287 | function htmlSplit(str, opts) {
|
288 | var newOpts, pos, file, ext, file2, match, match2, match3, out, min, replace, tmp, haveInlineJS
|
289 | , mined = []
|
290 | , lastIndex = 0
|
291 | , re = /<link[^>]+href="([^"]*?)"[^>]*?>|<(script)[^>]+src="([^>]*?)"[^>]*><\/\2>/ig
|
292 | , banner, bannerRe = /\sbanner=(("|')([^]+?)\2|[^\s]+)/i
|
293 | , inline, inlineRe = /\sinline\b/i
|
294 | , drop, dropRe = /\sdrop=(("|')([^]*?)\2|[^\s]+)/i
|
295 | , minRe = /\smin\b(?:=["']?(.+?)["'])?/i
|
296 | , requireRe = /\srequire=(("|')([^]*?)\2|[^\s]+)/i
|
297 | , excludeRe = /\sexclude\b/i
|
298 | , loadFiles = []
|
299 | , hashes = {}
|
300 |
|
301 | str = str
|
302 | .replace(/<!--(?!\[if)[^]*?-->/g, "")
|
303 |
|
304 | for (out = [ str ]; match = re.exec(str); ) {
|
305 | file = opts.root + (match[1] || match[3])
|
306 | ext = file.split(".").pop()
|
307 | pos = out.length
|
308 | out.splice(-1, 1,
|
309 | str.slice(lastIndex, match.index), "",
|
310 | str.slice(lastIndex = re.lastIndex)
|
311 | )
|
312 |
|
313 | banner = bannerRe.exec(match[0])
|
314 | inline = inlineRe.test(match[0])
|
315 | drop = dropRe.exec(match[0])
|
316 |
|
317 | if (match2 = requireRe.exec(match[0])) {
|
318 | lastStr = opts.root
|
319 | tmp = (match2[2] ? match2[3] : match2[1]).match(/[^,\s]+/g)
|
320 | match2 = File(file, {
|
321 | input: tmp ? tmp.map(defMap, opts) : [],
|
322 | drop: drop ? drop[3] || drop[1] : ""
|
323 | })
|
324 | if (!tmp) {
|
325 | match2._requireNext = true
|
326 | }
|
327 | }
|
328 |
|
329 | if (excludeRe.test(match[0])) {
|
330 | continue
|
331 | }
|
332 |
|
333 | newOpts = {
|
334 | min: 1,
|
335 | replace: inline && [
|
336 | ["/*!{loadFiles}*/", loadFiles],
|
337 | ["/*!{loadHashes}*/", JSON.stringify(hashes).slice(1, -1)]
|
338 | ],
|
339 | banner: banner ? banner[3] || banner[1] : "",
|
340 | drop: drop ? drop[3] || drop[1] : ""
|
341 | }
|
342 |
|
343 | if (match3 = minRe.exec(match[0])) {
|
344 | lastStr = file.slice(opts.root.length)
|
345 | file2 = (
|
346 | match3[1] ? path.resolve(opts.root, defMap.call(opts, match3[1])) :
|
347 | min && (
|
348 | adapters[min.ext] === adapters[ext] ||
|
349 | (adapters[min.ext].transpilers||[])[ext]
|
350 | ) ? min.name :
|
351 | opts.root + mined.length.toString(32) + "." + ext
|
352 | )
|
353 | if (!min || min.name !== file2) {
|
354 | newOpts.input = []
|
355 | min = File(file2, newOpts)
|
356 | mined.push(min.wait())
|
357 | }
|
358 | min.opts.input.push(match2 || file.replace(/\?.*/, ""))
|
359 | if (match2 && match2._requireNext) {
|
360 | min = match2
|
361 | }
|
362 | if (min.isLoaded) {
|
363 | continue
|
364 | }
|
365 | min.isLoaded = 1
|
366 | file = file2
|
367 | }
|
368 | var dataIf = /\sif="([^"?]+)/.exec(match[0])
|
369 | if (inline) {
|
370 | if (match2 && !match3) {
|
371 | newOpts.input = [match2]
|
372 | newOpts.mem = true
|
373 | file = "mem:" + file
|
374 | }
|
375 | tmp = File(file, newOpts)
|
376 | if (match[2]) haveInlineJS = true
|
377 | mined.push(tmp.wait())
|
378 | out[pos] = tmp
|
379 | } else if ((haveInlineJS && match[2]) || dataIf) {
|
380 | loadFiles.push(
|
381 | (dataIf ? "(" + dataIf[1] + ")&&'" : "'") +
|
382 | replacePath(path.relative(opts.root, file), opts) + "'"
|
383 | )
|
384 | } else {
|
385 | tmp = match[0]
|
386 | if (match3) {
|
387 | tmp = tmp
|
388 | .replace(minRe, "")
|
389 | .replace(requireRe, "")
|
390 | .replace(bannerRe, "")
|
391 | .replace(match[1] || match[3], path.relative(opts.root, file))
|
392 | }
|
393 | out[pos] = tmp
|
394 | }
|
395 | }
|
396 | mined.forEach(function(fn) { fn() })
|
397 | return out.filter(Boolean).map(htmlMin, opts)
|
398 | }
|
399 |
|
400 | function htmlMin(str) {
|
401 | var opts = this
|
402 | return typeof str !== "string" ? str : str
|
403 | .replace(/[\r\n][\r\n\s]*[\r\n]/g, "\n")
|
404 | .replace(/\t/g, " ")
|
405 | .replace(/\s+(?=<|\/?>|$)/g, "")
|
406 | .replace(/\b(href|src)="(?!data:)(.+?)"/gi, function(_, tag, file) {
|
407 | return tag + '="' + replacePath(file, opts) + '"'
|
408 | })
|
409 | }
|
410 |
|
411 | function jsToHtml(str) {
|
412 | return '<script>' + str + '</script>'
|
413 |
|
414 | }
|
415 | function cssToHtml(str) {
|
416 | return '<style>' + str + '</style>'
|
417 | }
|
418 |
|
419 | function cssSplit(str, opts) {
|
420 | var match, out
|
421 | , lastIndex = 0
|
422 | , re = /@import\s+url\((['"]?)(?!data:)(.+?)\1\);*/ig
|
423 |
|
424 | if (opts.root !== opts.name.replace(/[^\/]*$/, "")) {
|
425 | str = str.replace(/\/\*(?!!)[^]*?\*\/|url\((['"]?)(?!data:)(.+?)\1\)/ig, function(_, q, name) {
|
426 | return name ?
|
427 | 'url("' + replacePath(path.relative(opts.root, path.resolve(opts.name.replace(/[^\/]*$/, name))), opts) + '")' :
|
428 | _
|
429 | })
|
430 | }
|
431 |
|
432 | for (out = [ str ]; match = re.exec(str); ) {
|
433 | out.splice(-1, 1,
|
434 | str.slice(lastIndex, match.index),
|
435 | File(path.resolve(opts.root, match[2]), opts),
|
436 | str.slice(lastIndex = re.lastIndex)
|
437 | )
|
438 | }
|
439 | return out.filter(Boolean)
|
440 | }
|
441 |
|
442 | function cssMin(map, opts, next) {
|
443 | var name
|
444 | , out = ""
|
445 | for (name in map) if (hasOwn.call(map, name)) {
|
446 | out += typeof map[name] !== "string" ? map[name] : map[name]
|
447 | .replace(/\/\*(?!!)[^]*?\*\//g, "")
|
448 | .replace(/[\r\n]+/g, "\n")
|
449 |
|
450 | .replace(/(.*)\/\*!\s*([\w-]+)\s*([\w-.]*)\s*\*\//g, function(_, line, cmd, param) {
|
451 | switch (cmd) {
|
452 | case "data-uri":
|
453 | line = line.replace(/url\((['"]?)(.+?)\1\)/g, function(_, quote, fileName) {
|
454 | var str = fs.readFileSync(path.resolve(opts.root + fileName), "base64")
|
455 | return 'url("data:image/' + fileName.split(".").pop() + ";base64," + str + '")'
|
456 | })
|
457 | break;
|
458 | }
|
459 | return line
|
460 | })
|
461 |
|
462 |
|
463 | .replace(/(["'])((?:\\?.)*?)\1|[^"']+/g, function(_, q, str) {
|
464 | if (q) return q == "'" && str.indexOf('"') == -1 ? '"' + str + '"' : _
|
465 | return _.replace(/[\t\n]/g, " ")
|
466 | .replace(/ *([,;{}>~+]) */g, "$1")
|
467 | .replace(/^ +|;(?=})/g, "")
|
468 | .replace(/: +/g, ":")
|
469 | .replace(/ and\(/g, " and (")
|
470 | .replace(/}(?!})/g, "}\n")
|
471 | })
|
472 |
|
473 |
|
474 |
|
475 |
|
476 | .replace(/url\("([\w\/_.-]*)"\)/g, "url($1)")
|
477 | .replace(/([ :,])0\.([0-9]+)/g, "$1.$2")
|
478 | }
|
479 | next(null, out)
|
480 | }
|
481 |
|
482 | var npmChild
|
483 |
|
484 | function jsMin(map, opts, next) {
|
485 | if (!cli.command("uglifyjs")) {
|
486 | console.error("Error: uglify-js not found, run: npm i -g uglify-js\n")
|
487 | process.exit(1)
|
488 | }
|
489 | var name
|
490 | , result = ""
|
491 | , child = spawn("uglifyjs", [
|
492 | "--warn",
|
493 | "--ie8",
|
494 | "--compress", "evaluate=false,properties=false",
|
495 | "--mangle", "eval",
|
496 | "--comments", "/^[@!]/",
|
497 | "--beautify", "beautify=false,semicolons=false,keep_quoted_props=true"
|
498 | ])
|
499 |
|
500 | child.stderr.on("data", function onError(data) {
|
501 | data = data.toString().trim()
|
502 | if (data !== "") opts.warnings.push(data)
|
503 | })
|
504 | child.stdout.on("data", function(data) {
|
505 | result += data.toString()
|
506 | })
|
507 | child.on("close", function(code) {
|
508 | if (code !== 0) {
|
509 | console.error(opts.warnings)
|
510 | throw Error("uglifyjs exited with " + code)
|
511 | }
|
512 | result = result
|
513 | .replace(/\/\*!cc_on\*\//g, "/*@cc_on")
|
514 | .replace(/\/\*!cc_off\*\//g, "@*/")
|
515 | next(null, result)
|
516 | })
|
517 | for (name in map) if (hasOwn.call(map, name)) {
|
518 | child.stdin.write(map[name])
|
519 | }
|
520 | child.stdin.end()
|
521 | }
|
522 |
|
523 | function tplMin(map, opts, next) {
|
524 | var out = Object.keys(map)
|
525 | , pos = 0
|
526 |
|
527 | min()
|
528 |
|
529 | function min() {
|
530 | var i = pos++
|
531 | if (i < out.length) {
|
532 | _tplSplit(map[out[i]], opts, function(err, str) {
|
533 | out[i] = str
|
534 | min()
|
535 | })
|
536 | } else {
|
537 | next(null, out.join("\n"))
|
538 | }
|
539 | }
|
540 | }
|
541 |
|
542 | function _tplSplit(str, opts, next) {
|
543 | var templateRe = /^([ \t]*)(%?)((?:("|')(?:\\?.)*?\4|[-\w:.#[\]=])*)[ \t]*(([\])}]?).*?([[({]?))$/gm
|
544 | , out = [""]
|
545 | , parent = 0
|
546 | , stack = [-1]
|
547 | , resume = Fn.wait(function() {
|
548 | next(null, out.join("\n"))
|
549 | })
|
550 |
|
551 | str.replace(templateRe, work)
|
552 |
|
553 | resume()
|
554 |
|
555 | function work(all, indent, plugin, name, q, text, mapEnd, mapStart, offset) {
|
556 | if (offset && all === indent) return
|
557 |
|
558 | for (q = indent.length; q <= stack[0]; ) {
|
559 | if (typeof out[parent] !== "string") {
|
560 | parent = out.push("") - 1
|
561 | }
|
562 | stack.shift()
|
563 | }
|
564 |
|
565 | if (typeof out[parent] !== "string") {
|
566 | if (!out[parent].content.length) out[parent].content.push(all)
|
567 | else out[parent].content[0] += all + "\n"
|
568 | } else if (plugin && (name === "js" || name === "css")) {
|
569 | out[parent] += all
|
570 | parent = out.push(
|
571 | File("", {mem:1, min:1, ext:name, outPrefix: indent + " "}).then(resume.wait())
|
572 | ) - 1
|
573 | stack.unshift(q)
|
574 | } else {
|
575 | if (text && text.charAt(0) === "/") return
|
576 | out[parent] += all + "\n"
|
577 | }
|
578 | }
|
579 | }
|
580 |
|
581 | function tplToJs(input) {
|
582 | var i = input.length
|
583 | , singles = 0
|
584 | , doubles = 0
|
585 | for (; i--; ) {
|
586 | if (input.charCodeAt(i) === 34) doubles++
|
587 | else if (input.charCodeAt(i) === 39) singles++
|
588 | }
|
589 | input = input.replace(/\n+/g, "\\n")
|
590 | return(
|
591 | singles > doubles ?
|
592 | 'El.tpl("' + input.replace(/"/g, '\\"') + '")' :
|
593 | "El.tpl('" + input.replace(/'/g, "\\'") + "')"
|
594 | )
|
595 | }
|
596 |
|
597 | function readFileHashes(next) {
|
598 | var leftover = ""
|
599 | , cwd = process.cwd() + "/"
|
600 | , git = spawn("git", ["ls-files", "-sz", "--abbrev=1"])
|
601 |
|
602 | git.stdout.on("data", onData).on("end", onEnd)
|
603 | git.stderr.pipe(process.stderr)
|
604 |
|
605 | function onData(data) {
|
606 | var lines = (leftover + data).split("\0")
|
607 |
|
608 | leftover = lines.pop()
|
609 | lines.forEach(onLine)
|
610 | }
|
611 |
|
612 | function onEnd() {
|
613 | onLine(leftover)
|
614 | next()
|
615 | }
|
616 |
|
617 | function onLine(line) {
|
618 | if (line !== "") {
|
619 | fileHashes[cwd + line.slice(1 + line.indexOf("\t"))] = line.split(" ")[1]
|
620 | }
|
621 | }
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 | }
|
628 |
|
629 | function execute(args, i) {
|
630 | var arg, banner, input, output
|
631 |
|
632 | for (; arg = args[i++]; ) {
|
633 | switch (arg) {
|
634 | case "-b":
|
635 | case "--banner":
|
636 | banner = args[i++]
|
637 | break;
|
638 | case "-i":
|
639 | case "--input":
|
640 | if (!input) input = []
|
641 | input.push(args[i++])
|
642 | break;
|
643 | case "-o":
|
644 | case "--output":
|
645 | output = args[i++]
|
646 | break;
|
647 | case "-w":
|
648 | case "--worker":
|
649 | var opts = { warnings: [] }
|
650 | updateWorker(args[i++], opts, {})
|
651 | break;
|
652 | case "-r":
|
653 | case "--readme":
|
654 | updateReadme(args[i++])
|
655 | break;
|
656 | case "-v":
|
657 | case "--version":
|
658 | var opts = { warnings: [] }
|
659 | updateVersion(args[i++])
|
660 | break;
|
661 | default:
|
662 | if (arg.charAt(0) == "-") {
|
663 | args.splice.apply(
|
664 | args,
|
665 | [i, 0].concat(arg.replace(/\w(?!$)/g,"$& " + args[i] + " -").split(" "))
|
666 | )
|
667 | }
|
668 | }
|
669 | if (input && output) {
|
670 | File(output, {
|
671 | banner: banner,
|
672 | input: input,
|
673 | min: 1
|
674 | })
|
675 | banner = input = output = ""
|
676 | }
|
677 | }
|
678 | }
|
679 |
|
680 | if (module.parent) {
|
681 |
|
682 | exports.File = File
|
683 | exports.updateReadme = updateReadme
|
684 | exports.execute = function(args, i) {
|
685 | readFileHashes(function() {
|
686 | exports.execute = execute
|
687 | if (args.length > i) execute(args, i)
|
688 | else if (conf.litejs && Array.isArray(conf.litejs.build)) {
|
689 | conf.litejs.build.forEach(function(row) {
|
690 | execute(row.split(/\s+/), 0)
|
691 | })
|
692 | }
|
693 | })
|
694 | }
|
695 | }
|
696 |
|
697 | function replacePath(_p, opts) {
|
698 | var p = path.normalize(_p)
|
699 | if (p.indexOf("{hash}") > -1) {
|
700 | var full = path.resolve(opts.root, p.split("?")[0])
|
701 | p = p.replace(/{hash}/g, fileHashes[full] || +now)
|
702 | if (!fileHashes[full]) {
|
703 | opts.warnings.pushUniq("'" + full + "' not commited?")
|
704 | }
|
705 | }
|
706 | return p
|
707 | }
|
708 |
|
709 | function format(str) {
|
710 | return str.replace(/([\s\*\/]*@(version|date|author|stability)\s+).*/g, function(all, match, tag) {
|
711 | tag = translate[tag] ? translate[tag][conf[tag]] || translate[tag] : conf[tag]
|
712 | return tag ? match + tag : all
|
713 | })
|
714 | }
|
715 |
|
716 | function updateReadme(file) {
|
717 | var current = cli.readFile(file)
|
718 | , updated = format(current)
|
719 |
|
720 | if (current != updated) {
|
721 | console.error("# Update readme: " + file)
|
722 | cli.writeFile(file, updated)
|
723 | }
|
724 | }
|
725 |
|
726 | function updateVersion(file) {
|
727 | var re = /(\s+VERSION\s*=\s*)("|').*?\2/
|
728 | , current = cli.readFile(file)
|
729 | , updated = current.replace(re, function(_, a, q) {
|
730 | return a + q + now.toISOString() + q
|
731 | })
|
732 | if (current !== updated) {
|
733 | console.error("# Update version: " + file)
|
734 | cli.writeFile(file, updated)
|
735 | }
|
736 | }
|
737 |
|
738 | function updateWorker(file, opts, hashes) {
|
739 | var root = file.replace(/[^\/]+$/, "")
|
740 | , re = /(\s+VERSION\s*=\s*)("|').*?\2/
|
741 | , current = cli.readFile(file)
|
742 | , updated = current
|
743 | .replace(re, function(_, a, q) {
|
744 | return a + q + now.toISOString() + q
|
745 | })
|
746 | .replace(/ FILES = (\[[^\]]+?\])/, function(all, files) {
|
747 | files = JSON.parse(files)
|
748 | .map(function(line) {
|
749 | var name = line.replace(/\?.*/, "")
|
750 | , full = path.resolve(root, name)
|
751 | if (!fileHashes[full]) {
|
752 | opts.warnings.pushUniq("'" + full + "' not commited?")
|
753 | } else if (name !== line) {
|
754 | hashes[name] = fileHashes[full]
|
755 | return name + "?" + fileHashes[full]
|
756 | }
|
757 | return line
|
758 | })
|
759 | return " FILES = " + JSON.stringify(files, null, "\t")
|
760 | })
|
761 |
|
762 | if (current != updated) {
|
763 | console.error("# Update worker: " + file)
|
764 | cli.writeFile(file, updated)
|
765 | }
|
766 | }
|
767 |
|
768 |
|