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