UNPKG

4.42 kBJavaScriptView Raw
1
2//these are the help entries for each command
3export let helpEntries = {};
4let helpEntry = name => helpEntries[name] ? helpEntries[name] : (helpEntries[name] = {name});
5
6//short description
7export function helpText(text){
8 return function(func, name){
9 helpEntry(name).text = text;
10 return func;
11 }
12}
13
14//flag type argument like -f or --file
15export function arg(long, short, desc){
16 return function(func, name){
17 let args = helpEntry(name).args = helpEntry(name).args || [];
18 args.unshift({long, short, desc});
19 return func;
20 }
21}
22
23//normal argument
24export function param(param, desc){
25 return function(func, name){
26 let params = helpEntry(name).params = helpEntry(name).params || [];
27 params.unshift({param, desc});
28 return func;
29 }
30}
31
32//usage string
33export function usage(usage){
34 return function(func, name){
35 usage = usage.replace(/[\[<](\w+)[\]>]/g, chalk`[{blue $1}]`);
36 helpEntry(name).usage = usage;
37 return func;
38 }
39}
40
41export function cachedgetter(target, key, desc){
42 let cachedVal;
43
44 let oldget = desc.get;
45 desc.get = function(){
46 if(cachedVal) return cachedVal;
47 return cachedVal = oldget.call(this);
48 };
49 desc.set = function(val){
50 cachedVal = val;
51 };
52}
53
54function findValueInCache(args, cache){
55 for(let [argsKey, value] of cache){
56 if(args.length !== argsKey.length) continue;
57 for(let i in argsKey){
58 if(args[i] !== argsKey[i]){
59 continue
60 }
61 }
62 return {found: true, value};
63 }
64 return {found: false};
65}
66
67//This decorator takes a function and returns a function that remembers the
68// value returned by given arguments
69export function cached(target, key, desc){
70 let oldFunc = desc.value;
71 let cachedValues = [];
72 function newFunc(...args){
73 let {found, value} = findValueInCache(args, cachedValues);
74 if(!found){
75 //Call the old function to find the value, then store it in the cache
76 value = oldFun(...args);
77 cachedValues.push([args, value]);
78 }
79 return value;
80 }
81 newFunc.clearCache = function(){
82 cachedValues = [];
83 }
84 newFunc.cachePush = function(args, value){
85 cachedValues.push([args, value]);
86 }
87 newFunc.remove = function(...args){
88 let {found, value} = findValueInCache(args, cachedValues);
89 if(found){
90 cachedValues = cachedValues.filter(([arg, item]) => item !== value);
91 }
92 }
93
94 return {
95 ...desc,
96 value: newFunc,
97 };
98}
99
100//Access a deep property of an object: if path is ["a", "b", "c"], then this
101//function retuns obj.a.b.c
102function deepAccess(obj, path){
103 let o = obj;
104 for(let key of path){
105 if(!o) return [];
106 o = o[key];
107 }
108 return o;
109}
110
111//This takes a class as the first argument, then adds a getter/setter pair that
112//corresponds to an object in this.data
113export function defineAssoc(classname, shortname, path){
114 path = path.split(".");
115 let lastKey = path.pop();
116
117 Object.defineProperty(classname.prototype, shortname, {
118 get(){
119 return deepAccess(this, path)[lastKey];
120 },
121 set(val){
122 deepAccess(this, path)[lastKey] = val;
123 },
124 });
125}
126
127import {spawn as cp_spawn} from "child_process";
128import {performance} from "perf_hooks";
129
130//Spawn promise decorator, based on https://gist.github.com/Stuk/6226938
131export function spawn(options, ...args){
132 if(typeof options !== "object"){
133 args.unshift(options);
134 options = {};
135 }
136 //todo options
137 return new Promise((resolve, reject) => {
138 let start = performance.now();
139
140 let stdout = "";
141 let stderr = "";
142 let cp = cp_spawn(...args);
143
144 let write = global.write;
145 if(options.noecho){
146 write = () => {};
147 }
148 if(cp.stdout) cp.stdout.on("data", chunk => {stdout += chunk; write(chunk)});
149 if(cp.stderr) cp.stderr.on("data", chunk => {stderr += chunk; write(chunk)});
150
151 cp.on("error", reject);
152 cp.on("close", code => {
153 let end = performance.now();
154 let time = end - start;
155 let timestr = time > 1000 ? (time/100|0)/10 + "s" : (time|0) + "ms";
156 resolve({stdout, stderr, exitCode: code, time, timestr});
157 });
158 });
159}