UNPKG

7.64 kBJavaScriptView Raw
1#!/usr/bin/env node
2//-
3//- Usage
4//- lj [init|bench|build|help|test]
5//-
6//- build options
7//- --banner, -b Add comment banner to output
8//- --input, -i Input file
9//- --output, -o Output file
10//- --readme, -r Replase readme tags in file
11//-
12//- Examples
13//- lj b -r README.md -i ui/dev.html -o ui/index.html
14//- lj r
15//-
16
17require("./cli/patch-node.js")
18
19var fs = require("fs")
20, child = require("child_process")
21, path = require("path")
22, now = new Date()
23, cli = Object.assign(exports, require("./package.json"), {
24 cols: +process.env.COLUMNS || process.stdout.columns || 80,
25 rows: +process.env.ROWS || process.stdout.rows || 24,
26 command: command,
27 conf: {
28 date: now.toISOString().split("T")[0]
29 },
30 cp: cp,
31 debounce: debounce,
32 hold: hold,
33 ls: ls,
34 mkdirp: mkdirp,
35 readFile: readFile,
36 rmrf: rmrf,
37 wait: wait,
38 watch: watch,
39 writeFile: writeFile,
40 writePackage: writePackage
41})
42, defaults = {
43 "bench": "lj bench ./test/bench/*.js",
44 "build": "lj build --out=ui/index.html ui/dev.html",
45 "commit": true,
46 "launch": "node",
47 "lcov": true,
48 "sources": "./*.js",
49 "status": 1,
50 "tag": true,
51 "template": "default",
52 "test": "lj test ./test/index.js",
53 "threads": 0,
54 "update": true
55}
56, shortcut = {
57 b: "build",
58 h: "help",
59 r: "release",
60 t: "test"
61}
62, commands = {
63 build: 1,
64 init: 1,
65 bench: 1,
66 release: 1,
67 test: 1
68}
69, hasOwn = commands.hasOwnProperty
70, intArgs = /^(samples|sample-time|warmup)$/
71, nodeArgs = /^(allow-natives-syntax)$/
72
73try {
74 var userPackage = require(path.resolve("package.json"))
75 Object.assign(cli.conf, userPackage)
76 Object.assign(defaults, userPackage.litejs)
77} catch(e) {}
78
79function getopts(argv) {
80 var opts = Object.assign({}, defaults, {args: argv, opts: [], nodeArgs: []})
81 for (var arg, i = argv.length; i; ) {
82 arg = argv[--i].split(/^--(no-)?|=/)
83 if (arg[0] === "") {
84 opts[nodeArgs.test(arg[2]) ? "nodeArgs" : "opts"].push(argv[i])
85 opts[arg[2]] = intArgs.test(opts[arg[2]]) ? 0|(arg[4] || !arg[1]) : arg[4] || !arg[1]
86 argv.splice(i, 1)
87 }
88 }
89 opts.cmd = argv.shift()
90 return opts
91}
92
93if (!module.parent) {
94 execute(getopts(process.argv.slice(2)))
95}
96
97function run(opt, cmd, addOpts) {
98 if (cmd) try {
99 ;(Array.isArray(cmd) ? cmd : [cmd]).forEach(function(cmd) {
100 cmd += addOpts ? " " + addOpts : ""
101 child.execSync(replaceVersion(cmd), { stdio: "inherit" })
102 })
103 } catch (e) {
104 console.error("\n%s\nIgnore with --no-%s option.", e.message, opt)
105 process.exit(1)
106 }
107}
108function replaceVersion(cmd) {
109 var re = /{v(\d)}/g
110 , ver = (cli.conf.version || "0.0.0").split(".")
111 return cmd.replace(re, function(all, num) {
112 return ver[num]
113 })
114}
115
116function execute(opts) {
117 var sub
118 , cmd = shortcut[opts.cmd] || opts.cmd
119 , helpFile = module.filename
120
121 if (opts.version) console.log("%s v%s", cli.name, cli.version)
122
123 if (!opts.version || cmd) switch (cmd) {
124 case "bench":
125 case "build":
126 case "test":
127 if (opts.args.length < 1) {
128 return run(cmd, opts[cmd], opts.opts.join(" "))
129 }
130 /* falls through */
131 case "init":
132 case "release":
133 require("./cli/" + cmd)(opts)
134 break;
135 case "lint":
136 run(cmd, opts[cmd])
137 break;
138 case "help":
139 sub = shortcut[opts.args[0]] || opts.args[0]
140 if (hasOwn.call(commands, sub)) {
141 helpFile = path.join(path.dirname(module.filename), "cli", sub + ".js")
142 }
143 /* falls through */
144 default:
145 console.log(readFile(helpFile).match(/^\/\/-.*/gm).join("\n").replace(/^.../gm, ""))
146 }
147}
148
149function command(name) {
150 try {
151 return !!child.execSync((process.platform === "win32" ? "where " : "command -v ") + name)
152 } catch (e) {}
153}
154
155function cp(src, dest) {
156 if (fs.statSync(src).isDirectory()) {
157 mkdirp(dest)
158 fs.readdirSync(src).forEach(function(file) {
159 cp(path.join(src, file), path.join(dest, file))
160 })
161 } else {
162 console.error("cp", src, dest)
163 fs.copyFileSync(src, dest)
164 }
165}
166
167function debounce(fn, time) {
168 var timer
169 return function() {
170 clearTimeout(timer)
171 timer = setTimeout(exec, time || 300, this, arguments)
172 }
173 function exec(scope, args) {
174 fn.apply(scope, args)
175 }
176}
177
178function flat(arr) {
179 var out = []
180 return out.concat.apply(out, arr)
181}
182
183function ls() {
184 var key, dirRe, outRe, tmp, tmp2
185 , arr = flat(arguments)
186 , i = arr.length
187 , out = []
188 , paths = {}
189 , reEscRe = /[*.+^=:${}()|\/\\]/g
190 for (; i > 0; ) {
191 key = arr[--i]
192 if (typeof key !== "string") continue
193 tmp = path.resolve(tmp2 = key.replace(/[^\/]*\*.*/, ""))
194 tmp = paths[tmp] || (paths[tmp] = [])
195 if (key !== tmp2) tmp.push(key.slice(tmp2.length))
196 }
197 for (key in paths) {
198 outRe = RegExp("^" + esc(key) + (
199 paths[key][0] ? "\\/(" + paths[key].map(esc).join("|") + ")$" : "$"
200 ))
201 tmp = paths[key].map(dirname).filter(Boolean)
202 dirRe = RegExp("^" + esc(key) + (
203 tmp[0] ? "(?:\\/(" + tmp.map(esc).join("|") + ")|)$" : "$"
204 ))
205 scan(key)
206 }
207 return out.sort()
208 function scan(name) {
209 if (outRe.test(name)) {
210 out.push(path.relative(process.cwd(), name))
211 } else if (dirRe.test(name)) try {
212 var stat = fs.statSync(name)
213 if (stat.isDirectory()) {
214 fs.readdirSync(name).forEach(function(file) {
215 scan(path.resolve(name, file))
216 })
217 }
218 } catch(e) {}
219 }
220 function dirname(s) {
221 return s.indexOf("/") > -1 && path.dirname(s)
222 }
223 function esc(s) {
224 return (s.charAt(0) === "." ? "" : "(?!\\.)") +
225 s
226 .replace(reEscRe, "\\$&")
227 .replace(/\?/g, "[^\/]")
228 .replace(/\\\*\\\*(\\\/)?/g, "(.+$1)?")
229 .replace(/\\(?=\*)/g, "[^\/]")
230 }
231}
232
233function mkdirp(dir) {
234 try {
235 fs.statSync(dir)
236 } catch (e) {
237 mkdirp(path.dirname(dir))
238 console.error("mkdir", dir)
239 fs.mkdirSync(dir)
240 }
241}
242
243function readFile(fileName) {
244 return fs.readFileSync(path.resolve(fileName.split("?")[0]), "utf8")
245}
246
247function rmrf(dir) {
248 if (dir === "/") throw Error("Can not remove root")
249 fs.rmSync(dir, { force: true, recursive: true })
250}
251
252function writeFile(fileName, content) {
253 var name = path.resolve(fileName.split("?")[0])
254 mkdirp(path.dirname(name))
255 fs.writeFileSync(name, content, "utf8")
256}
257
258function writePackage(obj) {
259 var undef
260 obj.litejs = Object.assign(obj.litejs || {}, { cmd:undef, name:undef })
261 writeFile("package.json", JSON.stringify(obj, null, " ") + "\n")
262}
263
264
265function wait(fn) {
266 var pending = 1
267 function resume() {
268 if (!--pending && fn) fn.call(this)
269 }
270 resume.wait = function() {
271 pending++
272 return resume
273 }
274 return resume
275}
276
277function watch(paths, cb, delay) {
278 var watchers = {}
279 , changed = []
280 , fn = debounce(function() {
281 add(changed)
282 changed.length = 0
283 cb()
284 }, delay)
285
286 add(paths)
287
288 return {
289 add: add
290 }
291 function add(paths) {
292 paths.forEach(watch)
293 }
294 function watch(file) {
295 if (watchers[file]) return
296 try {
297 watchers[file] = fs.watch(file, function() {
298 if (watchers[file]) {
299 changed.push(file)
300 watchers[file].close()
301 watchers[file] = null
302 }
303 fn()
304 })
305 } catch (e) {}
306 }
307}
308
309function hold(ignore) {
310 var k
311 , obj = this
312 , hooks = []
313 , hooked = []
314 , _resume = wait(resume)
315 ignore = ignore || obj.syncMethods || []
316
317 for (k in obj) if (typeof obj[k] == "function" && ignore.indexOf(k) < 0) swap(k)
318 function swap(k) {
319 hooked.push(k, hasOwn.call(obj, k) && obj[k])
320 obj[k] = function() {
321 hooks.push(k, arguments)
322 return obj
323 }
324 }
325
326 /**
327 * `wait` is already in hooked array,
328 * so override hooked method
329 * that will be cleared on resume.
330 */
331 obj.wait = _resume.wait
332
333 return _resume
334
335 function resume() {
336 for (var v, scope = obj, i = hooked.length; i--; i--) {
337 if (hooked[i]) obj[hooked[i-1]] = hooked[i]
338 else delete obj[hooked[i-1]]
339 }
340 // i == -1 from previous loop
341 for (; (v = hooks[++i]); ) {
342 scope = scope[v].apply(scope, hooks[++i]) || scope
343 }
344 hooks = hooked = null
345 }
346}
347