UNPKG

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