UNPKG

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