@lowlighter/run 2.0.5 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -13
- package/command.d.ts +138 -0
- package/command.js +332 -0
- package/mod.d.ts +1 -0
- package/mod.js +2 -0
- package/package.json +20 -20
- package/command.mjs +0 -1
- package/command.ts +0 -324
- package/command_test.ts +0 -127
- package/deno.jsonc +0 -82
- package/deno.lock +0 -77
- package/mod.mjs +0 -1
- package/mod.ts +0 -1
- package/mod_test.ts +0 -1
package/command.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=class e{constructor({level:t,format:r,output:n,tags:o,...i}={}){"granted"===globalThis.Deno?.permissions.querySync?.({name:"env",variable:"LOG_LEVEL"}).state&&(t??=globalThis.Deno?.env.get("LOG_LEVEL")),this.#e=n||null===n?n:console,this.#t=e.level.log,this.#r=e.format.text,this.#n={date:!1,time:!1,delta:!0,caller:{file:!1,name:!1,line:!1,fileformat:null}},this.level(t).format(r).options(i),this.tags=o??{}}#e;#n;options(e){if(!e)return structuredClone(this.#n);if("date"in e&&(this.#n.date=e.date),"time"in e&&(this.#n.time=e.time),"delta"in e&&(this.#n.delta=e.delta),"caller"in e)switch(!0){case!0===e.caller:this.#n.caller={file:!0,name:!0,line:!0,fileformat:this.#n.caller.fileformat};break;case!1===e.caller:this.#n.caller={file:!1,name:!1,line:!1,fileformat:this.#n.caller.fileformat};break;case"object"==typeof e.caller:"file"in e.caller&&(this.#n.caller.file=e.caller.file),"name"in e.caller&&(this.#n.caller.name=e.caller.name),"line"in e.caller&&(this.#n.caller.line=e.caller.line),"fileformat"in e.caller&&void 0!==e.caller.fileformat&&(this.#n.caller.fileformat=e.caller.fileformat)}return this}#t;level(t){return arguments.length?(Number.isNaN(Number.parseInt(`${t}`))||(t=Number.parseInt(`${t}`)),"string"==typeof t&&t in e.level&&(t=e.level[t]),"number"==typeof t&&(this.#t=!Number.isNaN(t)&&t>=0?t:-1),this):this.#t>=0?this.#t:NaN}static level=Object.freeze({disabled:NaN,error:0,warn:1,info:2,ok:2,log:3,debug:4,wdebug:4,trace:5,probe:NaN,always:1/0});error(...t){return this.#t>=e.level.error&&this.#e?.error(...this.#r(this,{level:"error",content:t,options:this.#n})),this}warn(...t){return this.#t>=e.level.warn&&this.#e?.warn(...this.#r(this,{level:"warn",content:t,options:this.#n})),this}info(...t){return this.#t>=e.level.info&&this.#e?.info(...this.#r(this,{level:"info",content:t,options:this.#n})),this}ok(...t){return this.#t>=e.level.info&&this.#e?.info(...this.#r(this,{level:"ok",content:t,options:this.#n})),this}log(...t){return this.#t>=e.level.log&&this.#e?.log(...this.#r(this,{level:"log",content:t,options:this.#n})),this}debug(...t){return this.#t>=e.level.debug&&this.#e?.debug(...this.#r(this,{level:"debug",content:t,options:this.#n})),this}wdebug(...t){return this.#t>=e.level.debug&&this.#e?.debug(...this.#r(this,{level:"wdebug",content:t,options:this.#n})),this}trace(...t){return this.#t>=e.level.trace&&this.#e?.debug(...this.#r(this,{level:"trace",content:t,options:this.#n})),this}probe(...e){return this.#e?.debug(...this.#r(this,{level:"probe",content:e,options:this.#n})),this}tags;with(t={}){return new e({level:this.#t,format:this.#r,output:this.#e,...this.#n,tags:{...this.tags,...t}})}#o(e=3){const t=Error,r=t.prepareStackTrace;t.prepareStackTrace=(e,t)=>t;const{stack:n}=new Error;t.prepareStackTrace=r;return n.map((e=>({file:e.getFileName(),name:e.getFunctionName(),line:e.getLineNumber(),column:e.getColumnNumber()})))[e]}static inspect(e){return globalThis.Deno?.inspect(e,{colors:!0,depth:1/0,strAbbreviateSize:1/0})??e}#r;format(t){return this.#r=("string"==typeof t?e.format[t]:t)??e.format.text,this}static format={text(t,{level:r,content:n,options:o}){const i={error:"red",warn:"orange",info:"cyan",ok:"green",log:"white",debug:"gray",wdebug:"yellow",trace:"gray",probe:"magenta"}[r],s=[`%c ${r.replace("wdebug","debug").toLocaleUpperCase().padEnd(5)} │%c`],l=[`color: black; background-color: ${i}`,""];if(o.date||o.time||o.delta){const e=(new Date).toISOString(),t=[];if(o.delta){const e=performance.now()/1e3;let r=e.toPrecision(4);e<1&&(r=e.toPrecision(2)),t.push(`+${r}`)}o.date&&o.time?t.push(e):o.date?t.push(e.slice(0,e.indexOf("T"))):o.time&&t.push(e.slice(e.indexOf("T")+1,-1)),s.push(`%c ${t.join(" ¦ ").trim()} %c`),l.push(`color: black; background-color: ${i}`,"")}if(o.caller.file||o.caller.name||o.caller.line){const e=t.#o();if(e){const t=[];if(o.caller.file){let r=`${e.file}`;Array.isArray(o.caller.fileformat)&&(r=r.replace(o.caller.fileformat[0],o.caller.fileformat[1])),t.push(r)}o.caller.name&&e.name&&t.push(e.name),o.caller.line&&t.push(e.line,e.column),s.push(`%c ${t.join(":").trim()} %c`),l.push("color: black; background-color: gray","")}}const a=[];for(const[r,n]of Object.entries(t.tags))a.push(`${r}:${e.inspect(n)}`);return s.push(`%c ${a.join(" ").trim()} %c`),l.push("background-color: black",""),[s.join(""),...l,...n.map(e.inspect)]},json(e,{level:t,content:r,options:n}){const o={level:t,timestamp:Date.now(),tags:e.tags,content:r},i={};if(n.date||n.time){const e=new Date(o.timestamp).toISOString();n.date&&(i.date=e.slice(0,e.indexOf("T"))),n.time&&(i.time=e.slice(e.indexOf("T")+1,-1))}if(n.delta&&(i.delta=performance.now()/1e3),n.caller.file||n.caller.name||n.caller.line){const t=e.#o();if(t){if(i.caller={},n.caller.file){let e=`${t.file}`;Array.isArray(n.caller.fileformat)&&(e=e.replace(n.caller.fileformat[0],n.caller.fileformat[1])),i.caller.file=e}n.caller.name&&t.name&&(i.caller.name=t.name),n.caller.line&&(i.caller.line=[t.line,t.column])}}return[JSON.stringify({...o,...i})]}}};TransformStream;function t(e){let t=0;for(const r of e)t+=r.length;const r=new Uint8Array(t);let n=0;for(const t of e)r.set(t,n),n+=t.length;return r}function r(e){const t=e.length,r=new Uint8Array(t);r[0]=0;let n=0,o=1;for(;o<t;)e[o]===e[n]?(n++,r[o]=n,o++):0===n?(r[o]=0,o++):n=r[n-1];return r}TransformStream,TransformStream,TransformStream,TransformStream,TransformStream;var n=class extends TransformStream{#i="";constructor(e={allowCR:!1}){super({transform:(t,r)=>{for(t=this.#i+t;;){const n=t.indexOf("\n"),o=e.allowCR?t.indexOf("\r"):-1;if(-1!==o&&o!==t.length-1&&(-1===n||n-1>o)){r.enqueue(t.slice(0,o)),t=t.slice(o+1);continue}if(-1===n)break;const i="\r"===t[n-1]?n-1:n;r.enqueue(t.slice(0,i)),t=t.slice(n+1)}this.#i=t},flush:t=>{if(""===this.#i)return;const r=e.allowCR&&this.#i.endsWith("\r")?this.#i.slice(0,-1):this.#i;t.enqueue(r)}})}};var o=new TextEncoder,i=new TextDecoder;function s(t,r,{logger:s=new e,stdin:a=null,stdout:c="debug",stderr:u="error",env:d,cwd:h,raw:f,callback:p,buffering:m,sync:g,throw:w,dryrun:b,winext:v="",os:y=Deno.build.os}={}){"windows"===y&&(t=`${t}${v}`),s=s.with({bin:t}),p&&"piped"!==l(a)&&(a="piped");const T=new Deno.Command(t,{args:r,stdin:g?"null":l(a),stdout:l(c),stderr:l(u),env:d,cwd:h,windowsRawArguments:f});if(b){s.wdebug(`dryrun: ${t} not executed`);const e={success:!0,code:0,stdio:[],stdin:"",stdout:"",stderr:""};return g?e:Promise.resolve(e)}return g?function(e,{bin:t,log:r,throw:n,stdout:o,stderr:s}){const a=Date.now(),c=e.outputSync(),{success:u,code:d}=c,h=Date.now()-a,f={get stdio(){return[[h,1,this.stdout],[h,2,this.stderr]]},stdin:"",stdout:"piped"===l(o)?i.decode(c.stdout):"",stderr:"piped"===l(s)?i.decode(c.stderr):""};for(const{channel:e,mode:t}of[{channel:"stdout",mode:o},{channel:"stderr",mode:s}])"piped"===l(t)&&f[e]&&r.with({t:h,channel:e})[t]?.(f[e]);if(!u&&n)throw new EvalError(`${t} exited with non-zero code ${d}:\n${f.stdout}\n${f.stderr}`);return{success:u,code:d,...f}}(T,{bin:t,log:s,throw:w,stdout:c,stderr:u}):async function(e,{bin:t,log:r,callback:i=({close:e})=>e?.(),buffering:s=250,throw:a,...c}){const u=e.spawn(),d=Date.now(),h={stdio:[],get stdin(){return this.stdio.filter((([e,t])=>0===t)).map((([e,t,r])=>r)).join("\n")},get stdout(){return this.stdio.filter((([e,t])=>1===t)).map((([e,t,r])=>r)).join("\n")},get stderr(){return this.stdio.filter((([e,t])=>2===t)).map((([e,t,r])=>r)).join("\n")}},f={};let p="";const m=function(e,t){let r=null,n=null;const o=(...i)=>{o.clear(),n=()=>{o.clear(),e.call(o,...i)},r=Number(setTimeout(n,t))};return o.clear=()=>{"number"==typeof r&&(clearTimeout(r),r=null,n=null)},o.flush=()=>{n?.()},Object.defineProperty(o,"pending",{get:()=>"number"==typeof r}),o}((async e=>{r.with({t:e}).trace("debounced"),p="",await i({stdio:h,i:h.stdin.length,...f})}),s);if("piped"===l(c.stdin)){const e=u.stdin.getWriter();Object.assign(f,{async write(t,n=!0){const i=Date.now()-d;c.stdin&&r.with({t:i,channel:"stdin"})[c.stdin]?.(t),h.stdio.push([i,0,t]),n&&!t.endsWith("\n")&&(t+="\n"),await e.write(o.encode(t)),p="stdin",e.releaseLock()},async close(){try{e.releaseLock(),await u.stdin.close(),r.with({t:Date.now()-d,closed:"stdin"}).trace()}catch{}},async wait(e=1e3){const t=Date.now()-d;r.with({t:t,waiting:e}).trace(),await function(e,t={}){const{signal:r,persistent:n=!0}=t;return r?.aborted?Promise.reject(r.reason):new Promise(((t,o)=>{const i=()=>{clearTimeout(s),o(r?.reason)},s=setTimeout((()=>{r?.removeEventListener("abort",i),t()}),e);if(r?.addEventListener("abort",i,{once:!0}),!1===n)try{Deno.unrefTimer(s)}catch(e){if(!(e instanceof ReferenceError))throw e;console.error("`persistent` option is only available in Deno")}}))}(e),m(t)}}),m(Date.now()-d)}await Promise.all(["stdout","stderr"].filter((e=>"piped"===l(c[e]))).map((async e=>{for await(const t of u[e].pipeThrough(new TextDecoderStream).pipeThrough(new n)){const n=Date.now()-d,o={stdout:1,stderr:2}[e];if(c[e]&&r.with({t:n,channel:e})[c[e]]?.(t),h.stdio.length&&p===e){const e=h.stdio.at(-1);e[1]===o&&(e[2]+=`\n${t}`)}else h.stdio.push([n,o,t]);p=e,m(n)}}))),m.flush();const{success:g,code:w}=await u.status;if(!g&&a)throw new EvalError(`${t} exited with non-zero code ${w}:\n${h.stdout}\n${h.stderr}`);return{success:g,code:w,...h}}(T,{bin:t,log:s,callback:p,buffering:m,throw:w,stdin:"piped"===l(a)?a:null,stdout:"piped"===l(c)?c:null,stderr:"piped"===l(u)?u:null})}function l(e){return["inherit","null"].includes(`${e}`)?`${e}`:"piped"}export{s as command};
|
package/command.ts
DELETED
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
// Imports
|
|
2
|
-
import type { Arg, Nullable, Promisable } from "@libs/typing"
|
|
3
|
-
import { Logger, type loglevel } from "@libs/logger"
|
|
4
|
-
import { TextLineStream } from "@std/streams"
|
|
5
|
-
import { debounce } from "@std/async/debounce"
|
|
6
|
-
import { delay } from "@std/async/delay"
|
|
7
|
-
export type { Logger, loglevel, Promisable }
|
|
8
|
-
|
|
9
|
-
/** Run options. */
|
|
10
|
-
export type options = {
|
|
11
|
-
/** Logger instance. */
|
|
12
|
-
logger?: Logger
|
|
13
|
-
/** Environment variables. */
|
|
14
|
-
env?: Deno.CommandOptions["env"]
|
|
15
|
-
/** Current working directory. */
|
|
16
|
-
cwd?: Deno.CommandOptions["cwd"]
|
|
17
|
-
/** Raw arguments (Windows only). */
|
|
18
|
-
raw?: boolean
|
|
19
|
-
/** Handling of stdin. When using a loglevel, channel will be piped and logged to specified log level. */
|
|
20
|
-
stdin?: loglevel | "piped" | "inherit" | null
|
|
21
|
-
/** Handling of stdout. When using a loglevel, channel will be piped and logged to specified log level. */
|
|
22
|
-
stdout?: loglevel | "piped" | "inherit" | null
|
|
23
|
-
/** Handling of stderr. When using a loglevel, channel will be piped and logged to specified log level. */
|
|
24
|
-
stderr?: loglevel | "piped" | "inherit" | null
|
|
25
|
-
/**
|
|
26
|
-
* Stdin interaction callback.
|
|
27
|
-
* Each time data is received on either stdin or stdout, this will be called after input buffering.
|
|
28
|
-
* You can then read stdio content, write to stdin, close stdin or retry later (for polling).
|
|
29
|
-
* Passing this option will automatically set stdin to "piped" if it is "inherit" or "null".
|
|
30
|
-
*/
|
|
31
|
-
callback?: callback
|
|
32
|
-
/**
|
|
33
|
-
* Stdio buffering.
|
|
34
|
-
* This is used to merge messages that are received relatively closely.
|
|
35
|
-
* Buffering is skipped when a different channel is used in-between.
|
|
36
|
-
*/
|
|
37
|
-
buffering?: number
|
|
38
|
-
/**
|
|
39
|
-
* Execute process synchronously.
|
|
40
|
-
* Note that stdin is not usable in sync mode.
|
|
41
|
-
*/
|
|
42
|
-
sync?: boolean
|
|
43
|
-
/** Process extension on Windows. */
|
|
44
|
-
winext?: string
|
|
45
|
-
/** Operating system. */
|
|
46
|
-
os?: typeof Deno.build.os
|
|
47
|
-
/** Throw an error if exit code is non-zero rather than returning a result. */
|
|
48
|
-
throw?: boolean
|
|
49
|
-
/**
|
|
50
|
-
* Do not actually execute the command.
|
|
51
|
-
* In this case you will instead receive an empty successful result object.
|
|
52
|
-
*/
|
|
53
|
-
dryrun?: boolean
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Run result. */
|
|
57
|
-
export type result = {
|
|
58
|
-
/** Whether the process exited with a zero-code. */
|
|
59
|
-
success: Deno.CommandStatus["success"]
|
|
60
|
-
/** Process exit code. */
|
|
61
|
-
code: Deno.CommandStatus["code"]
|
|
62
|
-
/**
|
|
63
|
-
* Process stdio content.
|
|
64
|
-
* First element is the delta timestamp since process start, second element is the channel (0:stdin, 1:stdout, 2:stderr), third element is the content.
|
|
65
|
-
*/
|
|
66
|
-
stdio: Array<[number, 0 | 1 | 2, string]>
|
|
67
|
-
/** Process stdin content. */
|
|
68
|
-
stdin: string
|
|
69
|
-
/** Process stdout content. */
|
|
70
|
-
stdout: string
|
|
71
|
-
/** Process stderr content. */
|
|
72
|
-
stderr: string
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** Stdin interaction callback. */
|
|
76
|
-
export type callback = (options: { stdio: Pick<result, "stdin" | "stdout" | "stderr">; i: number; write: (content: string) => Promise<void>; close: () => Promise<void>; wait: (dt: number) => Promise<void> }) => Promisable<void>
|
|
77
|
-
|
|
78
|
-
/** Text encoder */
|
|
79
|
-
const encoder = new TextEncoder()
|
|
80
|
-
|
|
81
|
-
/** Text decoder */
|
|
82
|
-
const decoder = new TextDecoder()
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Asynchronous version of {@link command}.
|
|
86
|
-
*
|
|
87
|
-
* Note that stdin is not usable in sync mode and will always be empty.
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* ```ts
|
|
91
|
-
* import { command } from "./command.ts"
|
|
92
|
-
* command("deno", ["version"], { sync: true })
|
|
93
|
-
* ```
|
|
94
|
-
* @example
|
|
95
|
-
* ```
|
|
96
|
-
* import { command } from "./command.ts"
|
|
97
|
-
* try {
|
|
98
|
-
* command("deno", ["eval", "Deno.exit(1)"], { sync: true, throw: true })
|
|
99
|
-
* }
|
|
100
|
-
* catch (error) {
|
|
101
|
-
* console.log(error)
|
|
102
|
-
* }
|
|
103
|
-
* ```
|
|
104
|
-
*/
|
|
105
|
-
export function command(bin: string, args: string[], options?: options & { sync?: false }): Promise<result>
|
|
106
|
-
/**
|
|
107
|
-
* Synchronous version of {@link command}.
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```
|
|
111
|
-
* import { command } from "./command.ts"
|
|
112
|
-
* try {
|
|
113
|
-
* await command("deno", ["eval", "Deno.exit(1)"], { throw: true })
|
|
114
|
-
* }
|
|
115
|
-
* catch (error) {
|
|
116
|
-
* console.log(error)
|
|
117
|
-
* }
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
export function command(bin: string, args: string[], options?: options & { sync: true }): result
|
|
121
|
-
/**
|
|
122
|
-
* Run a command.
|
|
123
|
-
*
|
|
124
|
-
* This is a wrapper around {@link https://docs.deno.com/api/deno/~/Deno.Command | Deno.command} that provides a better handling of stdio for interactive processes.
|
|
125
|
-
*
|
|
126
|
-
* Like `Deno.command`, the `env`, `cwd`, and `raw` (alias for `windowsRawArguments`) options are supported.
|
|
127
|
-
*
|
|
128
|
-
* The `stdin`, `stdout` and `stderr` options can be either set to an allowed {@link https://docs.deno.com/api/deno/~/Deno.Command | Deno.command} values (`"inherit"`, `"null"`, `"piped"`), or either to a supported log level of {@link Logger}.
|
|
129
|
-
* In the later case, the content will be always be "piped" and logged to the specified level of the provided {@link Logger} instance.
|
|
130
|
-
*
|
|
131
|
-
* Set `winext` option to automatically append an extension to the binary path on Windows (like `.cmd` or `.exe`).
|
|
132
|
-
* This is useful when the binary path isn't automatically resolved on Windows.
|
|
133
|
-
*
|
|
134
|
-
* Pass a `callback` option to interact with the process stdin and stdout.
|
|
135
|
-
* It is called each time data is received on of the piped channels, after input buffering.
|
|
136
|
-
* It will receive an object with the current stdio content, the current command index (based on the content written to stdin), along with a few additional functions:
|
|
137
|
-
* - `write(content: string, newline?: boolean): Promise<void>` encodes and writes content to stdin.
|
|
138
|
-
* - A newline is automatically appended by default but can be toggled off by passing `false` as second argument.
|
|
139
|
-
* - `close(): Promise<void>` closes stdin.
|
|
140
|
-
* - Note that you **need** to eventually call this method to prevent most processes from hanging as they're waiting for more input.
|
|
141
|
-
* - `wait(dt: number): Promise<void>` waits for a given amount of time before calling the callback again.
|
|
142
|
-
* - It is especially useful for polling, like checking if a specific line has been written to stdio or not.
|
|
143
|
-
*
|
|
144
|
-
* The `buffering` option is used to merge messages that are received relatively closely.
|
|
145
|
-
* Setting this option to a low value will also increase the rate at which the `callback` is called.
|
|
146
|
-
*
|
|
147
|
-
* Resulting object contains the same properties as {@link https://docs.deno.com/api/deno/~/Deno.CommandStatus | Deno.CommandStatus}
|
|
148
|
-
* with an additional `stdio` property that contains an array of ordered tuples with the delta timestamp since process start, the channel idenfitier (0:stdin, 1:stdout, 2:stderr) and the content.
|
|
149
|
-
* This offers a proper history of exchanged content.
|
|
150
|
-
*
|
|
151
|
-
* @example
|
|
152
|
-
* ```ts
|
|
153
|
-
* import { command } from "./command.ts"
|
|
154
|
-
* import { Logger } from "jsr:@libs/logger"
|
|
155
|
-
* await command("deno", ["version"], { env: { NO_COLOR: "true" }, cwd: "/tmp", raw: true })
|
|
156
|
-
* await command("deno", ["version"], { stdout: "piped" })
|
|
157
|
-
* await command("deno", ["version"], { logger: new Logger(), stdout: "debug" })
|
|
158
|
-
* await command("deno", ["version"], { winext: ".exe" })
|
|
159
|
-
* ```
|
|
160
|
-
*
|
|
161
|
-
* @example
|
|
162
|
-
* ```ts
|
|
163
|
-
* import { command } from "./command.ts"
|
|
164
|
-
*
|
|
165
|
-
* const { stdout } = await command("deno", ["repl"], {
|
|
166
|
-
* env: { NO_COLOR: "true" },
|
|
167
|
-
* // Passing a callback will automatically set `stdin` to `"piped"`
|
|
168
|
-
* // You can then write to the process using utility functions
|
|
169
|
-
* callback: async ({ i, stdio, write, close, wait }) => {
|
|
170
|
-
* if ((!stdio.stdout.includes("exit using")) || (i))
|
|
171
|
-
* return
|
|
172
|
-
* await write("console.log('hello')")
|
|
173
|
-
* await wait(1000)
|
|
174
|
-
* close()
|
|
175
|
-
* },
|
|
176
|
-
* })
|
|
177
|
-
* console.assert(stdout.includes("hello"))
|
|
178
|
-
* ```
|
|
179
|
-
*
|
|
180
|
-
* @author Simon Lecoq (lowlighter)
|
|
181
|
-
* @license MIT
|
|
182
|
-
* @module
|
|
183
|
-
*/
|
|
184
|
-
export function command(bin: string, args: string[], { logger: log = new Logger(), stdin = null, stdout = "debug", stderr = "error", env, cwd, raw, callback, buffering, sync, throw: _throw, dryrun, winext = "", os = Deno.build.os } = {} as options): Promisable<result> {
|
|
185
|
-
if (os === "windows") {
|
|
186
|
-
bin = `${bin}${winext}`
|
|
187
|
-
}
|
|
188
|
-
log = log.with({ bin })
|
|
189
|
-
if (callback && (handle(stdin) !== "piped")) {
|
|
190
|
-
stdin = "piped"
|
|
191
|
-
}
|
|
192
|
-
const command = new Deno.Command(bin, { args, stdin: !sync ? handle(stdin) : "null", stdout: handle(stdout), stderr: handle(stderr), env, cwd, windowsRawArguments: raw })
|
|
193
|
-
if (dryrun) {
|
|
194
|
-
log.wdebug(`dryrun: ${bin} not executed`)
|
|
195
|
-
const result = { success: true, code: 0, stdio: [], stdin: "", stdout: "", stderr: "" }
|
|
196
|
-
return sync ? result : Promise.resolve(result)
|
|
197
|
-
}
|
|
198
|
-
if (sync) {
|
|
199
|
-
return exec(command, { bin, log, throw: _throw, stdout, stderr })
|
|
200
|
-
}
|
|
201
|
-
return spawn(command, { bin, log, callback, buffering, throw: _throw, stdin: handle(stdin) === "piped" ? stdin as loglevel : null, stdout: handle(stdout) === "piped" ? stdout as loglevel : null, stderr: handle(stderr) === "piped" ? stderr as loglevel : null })
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/** Returns the handle type for a given mode. */
|
|
205
|
-
function handle(mode: Nullable<string>) {
|
|
206
|
-
return ["inherit", "null"].includes(`${mode}`) ? `${mode}` as "inherit" | "null" : "piped"
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/** Execute a command synchronously. */
|
|
210
|
-
function exec(command: Deno.Command, { bin, log, throw: _throw, stdout, stderr }: { bin: string; log: Logger; throw?: boolean; stdout: Nullable<string>; stderr: Nullable<string> }) {
|
|
211
|
-
const start = Date.now()
|
|
212
|
-
const output = command.outputSync()
|
|
213
|
-
const { success, code } = output // Do not access stdout or stderr before "piped" status check
|
|
214
|
-
const t = Date.now() - start
|
|
215
|
-
const stdio = {
|
|
216
|
-
get stdio() {
|
|
217
|
-
return [[t, 1, this.stdout], [t, 2, this.stderr]]
|
|
218
|
-
},
|
|
219
|
-
stdin: "",
|
|
220
|
-
stdout: handle(stdout) === "piped" ? decoder.decode(output.stdout) : "",
|
|
221
|
-
stderr: handle(stderr) === "piped" ? decoder.decode(output.stderr) : "",
|
|
222
|
-
} as Pick<result, "stdio" | "stdin" | "stdout" | "stderr">
|
|
223
|
-
for (const { channel, mode } of [{ channel: "stdout", mode: stdout }, { channel: "stderr", mode: stderr }] as const) {
|
|
224
|
-
if ((handle(mode) === "piped") && (stdio[channel])) {
|
|
225
|
-
log.with({ t, channel })[mode as loglevel]?.(stdio[channel])
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
if ((!success) && _throw) {
|
|
229
|
-
throw new EvalError(`${bin} exited with non-zero code ${code}:\n${stdio.stdout}\n${stdio.stderr}`)
|
|
230
|
-
}
|
|
231
|
-
return { success, code, ...stdio }
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/** Spawn a command asynchronously. */
|
|
235
|
-
async function spawn(
|
|
236
|
-
command: Deno.Command,
|
|
237
|
-
{ bin, log, callback = ({ close }) => close?.(), buffering = 250, throw: _throw, ...channels }: { bin: string; log: Logger; callback?: callback; buffering?: number; throw?: boolean; stdin: Nullable<loglevel>; stdout: Nullable<loglevel>; stderr: Nullable<loglevel> },
|
|
238
|
-
) {
|
|
239
|
-
const process = command.spawn()
|
|
240
|
-
const start = Date.now()
|
|
241
|
-
const stdio = {
|
|
242
|
-
stdio: [],
|
|
243
|
-
get stdin() {
|
|
244
|
-
return this.stdio.filter(([_, i]) => i === 0).map(([_, __, content]) => content).join("\n")
|
|
245
|
-
},
|
|
246
|
-
get stdout() {
|
|
247
|
-
return this.stdio.filter(([_, i]) => i === 1).map(([_, __, content]) => content).join("\n")
|
|
248
|
-
},
|
|
249
|
-
get stderr() {
|
|
250
|
-
return this.stdio.filter(([_, i]) => i === 2).map(([_, __, content]) => content).join("\n")
|
|
251
|
-
},
|
|
252
|
-
} as Pick<result, "stdio" | "stdin" | "stdout" | "stderr">
|
|
253
|
-
const options = {} as Pick<Arg<callback>, "write" | "close" | "wait">
|
|
254
|
-
let last = ""
|
|
255
|
-
const debounced = debounce(async (t: number) => {
|
|
256
|
-
log.with({ t }).trace("debounced")
|
|
257
|
-
last = ""
|
|
258
|
-
await callback({ stdio, i: stdio.stdin.length, ...options })
|
|
259
|
-
}, buffering)
|
|
260
|
-
// Prepare stdin handlers if channel is piped
|
|
261
|
-
if (handle(channels.stdin) === "piped") {
|
|
262
|
-
const writer = process.stdin.getWriter()
|
|
263
|
-
Object.assign(options, {
|
|
264
|
-
async write(content: string, newline = true) {
|
|
265
|
-
const t = Date.now() - start
|
|
266
|
-
if (channels.stdin) {
|
|
267
|
-
log.with({ t, channel: "stdin" })[channels.stdin]?.(content)
|
|
268
|
-
}
|
|
269
|
-
stdio.stdio.push([t, 0, content])
|
|
270
|
-
if (newline && (!content.endsWith("\n"))) {
|
|
271
|
-
content += "\n"
|
|
272
|
-
}
|
|
273
|
-
await writer.write(encoder.encode(content))
|
|
274
|
-
last = "stdin"
|
|
275
|
-
writer.releaseLock()
|
|
276
|
-
},
|
|
277
|
-
async close() {
|
|
278
|
-
try {
|
|
279
|
-
writer.releaseLock()
|
|
280
|
-
await process.stdin.close()
|
|
281
|
-
log.with({ t: Date.now() - start, closed: "stdin" }).trace()
|
|
282
|
-
} catch {
|
|
283
|
-
// Ignore
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
async wait(dt = 1000) {
|
|
287
|
-
const t = Date.now() - start
|
|
288
|
-
log.with({ t, waiting: dt }).trace()
|
|
289
|
-
await delay(dt)
|
|
290
|
-
debounced(t)
|
|
291
|
-
},
|
|
292
|
-
})
|
|
293
|
-
debounced(Date.now() - start)
|
|
294
|
-
}
|
|
295
|
-
// Buffer output and debounce interaction callback
|
|
296
|
-
await Promise.all(
|
|
297
|
-
(["stdout", "stderr"] as const).filter((channel) => handle(channels[channel]) === "piped").map(async (channel) => {
|
|
298
|
-
for await (const line of process[channel].pipeThrough(new TextDecoderStream()).pipeThrough(new TextLineStream())) {
|
|
299
|
-
const t = Date.now() - start
|
|
300
|
-
const stdi = { stdout: 1, stderr: 2 }[channel] as 1 | 2
|
|
301
|
-
if (channels[channel]) {
|
|
302
|
-
log.with({ t, channel })[channels[channel]!]?.(line)
|
|
303
|
-
}
|
|
304
|
-
if ((stdio.stdio.length) && (last === channel)) {
|
|
305
|
-
const previous = stdio.stdio.at(-1)!
|
|
306
|
-
if (previous[1] === stdi) {
|
|
307
|
-
previous[2] += `\n${line}`
|
|
308
|
-
}
|
|
309
|
-
} else {
|
|
310
|
-
stdio.stdio.push([t, stdi, line])
|
|
311
|
-
}
|
|
312
|
-
last = channel
|
|
313
|
-
debounced(t)
|
|
314
|
-
}
|
|
315
|
-
}),
|
|
316
|
-
)
|
|
317
|
-
debounced.flush()
|
|
318
|
-
// Result
|
|
319
|
-
const { success, code } = await process.status
|
|
320
|
-
if ((!success) && _throw) {
|
|
321
|
-
throw new EvalError(`${bin} exited with non-zero code ${code}:\n${stdio.stdout}\n${stdio.stderr}`)
|
|
322
|
-
}
|
|
323
|
-
return { success, code, ...stdio }
|
|
324
|
-
}
|
package/command_test.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { Logger } from "@libs/logger"
|
|
2
|
-
import { command } from "./command.ts"
|
|
3
|
-
import { expect, test, type testing } from "@libs/testing"
|
|
4
|
-
|
|
5
|
-
test("deno")("command() can spawn subprocesses asynchronously", async () => {
|
|
6
|
-
let result = command("deno", ["--version"], { env: { NO_COLOR: "true" } }) as testing
|
|
7
|
-
expect(result).toBeInstanceOf(Promise)
|
|
8
|
-
result = await result
|
|
9
|
-
expect(result).toMatchObject({ success: true, code: 0, stdin: "", stderr: "" })
|
|
10
|
-
expect(result.stdio).toBeInstanceOf(Array)
|
|
11
|
-
expect(result.stdout).toMatch(/deno/)
|
|
12
|
-
}, { permissions: { run: ["deno"] } })
|
|
13
|
-
|
|
14
|
-
test("deno")("command() can spawn subprocesses synchronously", () => {
|
|
15
|
-
const result = command("deno", ["--version"], { env: { NO_COLOR: "true" }, sync: true })
|
|
16
|
-
expect(result).not.toBeInstanceOf(Promise)
|
|
17
|
-
expect(result).toMatchObject({ success: true, code: 0, stdin: "", stderr: "" })
|
|
18
|
-
expect(result.stdio).toBeInstanceOf(Array)
|
|
19
|
-
expect(result.stdout).toMatch(/deno/)
|
|
20
|
-
}, { permissions: { run: ["deno"] } })
|
|
21
|
-
|
|
22
|
-
test("deno")("command() handles callback<write()> and callback<close()> calls", async () => {
|
|
23
|
-
const result = await command("deno", ["repl"], { stdin: "debug", env: { NO_COLOR: "true" }, callback: ({ i, write, close }) => i === 0 ? write("console.log('hello')") : close() })
|
|
24
|
-
expect(result).toMatchObject({ success: true, code: 0, stdin: "console.log('hello')" })
|
|
25
|
-
expect(result.stdout).toMatch(/hello/)
|
|
26
|
-
}, { permissions: { run: ["deno"] } })
|
|
27
|
-
|
|
28
|
-
test("deno")("command() handles multiple callback<close()> calls", async () => {
|
|
29
|
-
const result = await command("deno", ["repl"], {
|
|
30
|
-
env: { NO_COLOR: "true" },
|
|
31
|
-
callback: async ({ close }) => {
|
|
32
|
-
await close()
|
|
33
|
-
await close()
|
|
34
|
-
},
|
|
35
|
-
})
|
|
36
|
-
expect(result).toMatchObject({ success: true, code: 0 })
|
|
37
|
-
}, { permissions: { run: ["deno"] } })
|
|
38
|
-
|
|
39
|
-
test("deno")("command() handles callback<wait()> calls", async () => {
|
|
40
|
-
let waited = false
|
|
41
|
-
const result = await command("deno", ["repl"], {
|
|
42
|
-
env: { NO_COLOR: "true" },
|
|
43
|
-
callback: ({ wait, close }) => waited ? close() : (waited = true, wait(250)),
|
|
44
|
-
})
|
|
45
|
-
expect(result).toMatchObject({ success: true, code: 0 })
|
|
46
|
-
}, { permissions: { run: ["deno"] } })
|
|
47
|
-
|
|
48
|
-
for (const sync of [false, true]) {
|
|
49
|
-
for (const mode of ["inherit", "piped", null, "debug", "log", "info", "warn", "error"] as const) {
|
|
50
|
-
test("deno")(`command() supports stdio set to "${mode}" in "${sync ? "sync" : "async"}" mode`, async () => {
|
|
51
|
-
const result = await command("deno", ["eval", "null"], {
|
|
52
|
-
logger: new Logger({ level: "disabled" }),
|
|
53
|
-
env: { NO_COLOR: "true" },
|
|
54
|
-
stdin: mode,
|
|
55
|
-
stdout: mode,
|
|
56
|
-
stderr: mode,
|
|
57
|
-
sync: sync as testing,
|
|
58
|
-
})
|
|
59
|
-
expect(result).toMatchObject({ success: true, code: 0 })
|
|
60
|
-
}, { permissions: { run: ["deno"] } })
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
test("deno")("command() handles both stdout and stderr channels", async () => {
|
|
65
|
-
const result = await command("deno", ["eval", "await Deno.stdout.write(new TextEncoder().encode(`foo\n`));await Deno.stderr.write(new TextEncoder().encode(`bar\n`))"], {
|
|
66
|
-
env: { NO_COLOR: "true" },
|
|
67
|
-
stdout: "piped",
|
|
68
|
-
stderr: "piped",
|
|
69
|
-
})
|
|
70
|
-
expect(result).toMatchObject({ success: true, code: 0, stdout: "foo", stderr: "bar" })
|
|
71
|
-
}, { permissions: { run: ["deno"] } })
|
|
72
|
-
|
|
73
|
-
test("deno")("command() supports buffering", async () => {
|
|
74
|
-
// Combined entries if buffering is greater than the time between writes
|
|
75
|
-
{
|
|
76
|
-
const result = await command("deno", ["eval", "console.log(`foo`);await new Promise(resolve => setTimeout(resolve, 100));console.log(`bar`)"], {
|
|
77
|
-
env: { NO_COLOR: "true" },
|
|
78
|
-
buffering: 150,
|
|
79
|
-
})
|
|
80
|
-
expect(result.stdio).toHaveLength(1)
|
|
81
|
-
expect(result.stdio[0][2]).toBe("foo\nbar")
|
|
82
|
-
expect(result.stdout).toBe("foo\nbar")
|
|
83
|
-
}
|
|
84
|
-
// Separated entries if buffering is less than the time between writes
|
|
85
|
-
{
|
|
86
|
-
const result = await command("deno", ["eval", "console.log(`foo`);await new Promise(resolve => setTimeout(resolve, 100));console.log(`bar`)"], {
|
|
87
|
-
env: { NO_COLOR: "true" },
|
|
88
|
-
buffering: 50,
|
|
89
|
-
})
|
|
90
|
-
expect(result.stdio).toHaveLength(2)
|
|
91
|
-
expect(result.stdio[0][2]).toBe("foo")
|
|
92
|
-
expect(result.stdio[1][2]).toBe("bar")
|
|
93
|
-
expect(result.stdout).toBe("foo\nbar")
|
|
94
|
-
}
|
|
95
|
-
// Separated entries even if buffering is active but channel was changed in-between
|
|
96
|
-
{
|
|
97
|
-
const result = await command("deno", [
|
|
98
|
-
"eval",
|
|
99
|
-
"await Deno.stdout.write(new TextEncoder().encode(`foo\n`));await Deno.stderr.write(new TextEncoder().encode(`baz\n`));await Deno.stdout.write(new TextEncoder().encode(`bar\n`))",
|
|
100
|
-
], {
|
|
101
|
-
stdout: "piped",
|
|
102
|
-
stderr: "piped",
|
|
103
|
-
env: { NO_COLOR: "true" },
|
|
104
|
-
buffering: 200,
|
|
105
|
-
})
|
|
106
|
-
expect(result.stdio).toHaveLength(3)
|
|
107
|
-
expect(result.stdio[0][2]).toBe("foo")
|
|
108
|
-
expect(result.stdio[1][2]).toBe("baz")
|
|
109
|
-
expect(result.stdio[2][2]).toBe("bar")
|
|
110
|
-
expect(result.stdout).toBe("foo\nbar")
|
|
111
|
-
expect(result.stderr).toBe("baz")
|
|
112
|
-
}
|
|
113
|
-
}, { permissions: { run: ["deno"] } })
|
|
114
|
-
|
|
115
|
-
test("deno")("command() throws an error when `throw` option is enabled and exit code is non-zero", async () => {
|
|
116
|
-
expect(() => command("deno", ["eval", "Deno.exit(1)"], { env: { NO_COLOR: "true" }, throw: true, sync: true })).toThrow(EvalError)
|
|
117
|
-
await expect(command("deno", ["eval", "Deno.exit(1)"], { env: { NO_COLOR: "true" }, throw: true })).rejects.toThrow(EvalError)
|
|
118
|
-
}, { permissions: { run: ["deno"] } })
|
|
119
|
-
|
|
120
|
-
test("deno")("command() does nothing in dryrun", async () => {
|
|
121
|
-
expect(command("deno", ["--version"], { dryrun: true, sync: true })).toMatchObject({ success: true, code: 0, stdio: [], stdin: "", stderr: "", stdout: "" })
|
|
122
|
-
await expect(command("deno", ["--version"], { dryrun: true })).resolves.toMatchObject({ success: true, code: 0, stdio: [], stdin: "", stderr: "", stdout: "" })
|
|
123
|
-
}, { permissions: { run: ["deno"] } })
|
|
124
|
-
|
|
125
|
-
test("deno")("command() appends windows extension when os platform is windows", () => {
|
|
126
|
-
expect(command("", ["--version"], { logger: new Logger({ level: "disabled" }), sync: true, winext: "deno", os: "windows" })).toMatchObject({ success: true, code: 0 })
|
|
127
|
-
}, { permissions: { run: ["deno"] } })
|
package/deno.jsonc
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"icon": "⏯️",
|
|
3
|
-
"name": "@libs/run",
|
|
4
|
-
"version": "2.0.5",
|
|
5
|
-
"description": "Utilities to run subprocess.",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"subprocess",
|
|
8
|
-
"esm"
|
|
9
|
-
],
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"author": "lowlighter (Simon Lecoq)",
|
|
12
|
-
"funding": "https://github.com/sponsors/lowlighter",
|
|
13
|
-
"homepage": "https://github.com/lowlighter/libs",
|
|
14
|
-
"playground": "https://libs.lecoq.io/run",
|
|
15
|
-
"supported": [
|
|
16
|
-
"deno"
|
|
17
|
-
],
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "git+https://github.com/lowlighter/libs.git"
|
|
21
|
-
},
|
|
22
|
-
"npm": true,
|
|
23
|
-
"exports": {
|
|
24
|
-
".": "./mod.ts",
|
|
25
|
-
"./command": "./command.ts"
|
|
26
|
-
},
|
|
27
|
-
"imports": {
|
|
28
|
-
"@std/async/delay": "jsr:@std/async@1/delay",
|
|
29
|
-
"@std/async/debounce": "jsr:@std/async@1/debounce",
|
|
30
|
-
"@std/streams": "jsr:@std/streams@1",
|
|
31
|
-
"@libs/logger": "jsr:@libs/logger@2",
|
|
32
|
-
"@libs/testing": "jsr:@libs/testing@2",
|
|
33
|
-
"@libs/typing": "jsr:@libs/typing@2"
|
|
34
|
-
},
|
|
35
|
-
"test:permissions": {
|
|
36
|
-
"run": [
|
|
37
|
-
"deno",
|
|
38
|
-
"node",
|
|
39
|
-
"bun",
|
|
40
|
-
"npx"
|
|
41
|
-
]
|
|
42
|
-
},
|
|
43
|
-
"tasks": {
|
|
44
|
-
"test": "deno test --allow-run=deno,node,bun,npx --no-prompt --coverage --clean --trace-leaks --doc",
|
|
45
|
-
"dev": "deno fmt && deno task test --filter='/^\\[deno\\]/' && deno coverage --exclude=.js --detailed && deno task lint",
|
|
46
|
-
"test:deno": "deno task clean:deno && deno fmt --check && deno task test --filter='/^\\[deno\\]/' --quiet && deno coverage --exclude=.js && deno lint",
|
|
47
|
-
"test:deno-future": "deno task clean:deno && DENO_FUTURE=1 && deno task test:deno",
|
|
48
|
-
"test:others": "deno task clean:others && deno fmt --check && deno task test --filter='/^\\[node|bun \\]/' --quiet && deno coverage --exclude=.js && deno lint",
|
|
49
|
-
"coverage:html": "deno task test --filter='/^\\[deno\\]/' --quiet && deno coverage --exclude=.js --html && sleep 1",
|
|
50
|
-
"lint": "deno fmt --check && deno lint && deno doc --lint mod.ts && deno publish --dry-run --quiet --allow-dirty",
|
|
51
|
-
"clean:deno": "rm -rf node_modules .npmrc deno.lock",
|
|
52
|
-
"clean:others": "rm -rf node_modules .npmrc deno.lock package.json package-lock.json bun.lockb"
|
|
53
|
-
},
|
|
54
|
-
"lint": {
|
|
55
|
-
"rules": {
|
|
56
|
-
"include": [
|
|
57
|
-
"no-throw-literal",
|
|
58
|
-
"no-eval",
|
|
59
|
-
"eqeqeq",
|
|
60
|
-
"ban-untagged-todo"
|
|
61
|
-
]
|
|
62
|
-
},
|
|
63
|
-
"exclude": [
|
|
64
|
-
"**/wasm_*",
|
|
65
|
-
"**/*.mjs"
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
"fmt": {
|
|
69
|
-
"lineWidth": 280,
|
|
70
|
-
"semiColons": false,
|
|
71
|
-
"exclude": [
|
|
72
|
-
"coverage",
|
|
73
|
-
"**/coverage",
|
|
74
|
-
"**/node_modules",
|
|
75
|
-
"**/package.json",
|
|
76
|
-
"**/package-lock.json",
|
|
77
|
-
"**/wasm_*",
|
|
78
|
-
"**/*.mjs"
|
|
79
|
-
],
|
|
80
|
-
"proseWrap": "preserve"
|
|
81
|
-
}
|
|
82
|
-
}
|
package/deno.lock
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "3",
|
|
3
|
-
"packages": {
|
|
4
|
-
"specifiers": {
|
|
5
|
-
"jsr:@libs/logger": "jsr:@libs/logger@2.1.2",
|
|
6
|
-
"jsr:@libs/logger@2": "jsr:@libs/logger@2.1.2",
|
|
7
|
-
"jsr:@libs/testing@2": "jsr:@libs/testing@2.2.4",
|
|
8
|
-
"jsr:@libs/typing@2": "jsr:@libs/typing@2.8.2",
|
|
9
|
-
"jsr:@std/assert@1": "jsr:@std/assert@1.0.3",
|
|
10
|
-
"jsr:@std/assert@^1.0.3": "jsr:@std/assert@1.0.3",
|
|
11
|
-
"jsr:@std/async@1": "jsr:@std/async@1.0.4",
|
|
12
|
-
"jsr:@std/bytes@^1.0.2": "jsr:@std/bytes@1.0.2",
|
|
13
|
-
"jsr:@std/expect@1": "jsr:@std/expect@1.0.1",
|
|
14
|
-
"jsr:@std/http@1": "jsr:@std/http@1.0.4",
|
|
15
|
-
"jsr:@std/internal@^1.0.2": "jsr:@std/internal@1.0.2",
|
|
16
|
-
"jsr:@std/streams@1": "jsr:@std/streams@1.0.3"
|
|
17
|
-
},
|
|
18
|
-
"jsr": {
|
|
19
|
-
"@libs/logger@2.1.2": {
|
|
20
|
-
"integrity": "2a5f4b148fd8d6b1221ff89cff73367ca0511137f4d6548c532b6e220ed22bcc"
|
|
21
|
-
},
|
|
22
|
-
"@libs/testing@2.2.4": {
|
|
23
|
-
"integrity": "3ef407b62cf18424b3e2e604eef5df81d3c07cf8adb4b78ab4cf40db2a029f2c",
|
|
24
|
-
"dependencies": [
|
|
25
|
-
"jsr:@libs/typing@2",
|
|
26
|
-
"jsr:@std/assert@1",
|
|
27
|
-
"jsr:@std/expect@1",
|
|
28
|
-
"jsr:@std/http@1"
|
|
29
|
-
]
|
|
30
|
-
},
|
|
31
|
-
"@libs/typing@2.8.2": {
|
|
32
|
-
"integrity": "c53f8aad9b01621de893aeac5d6cd592ec2ce783f8e89b677dcd81490a3be0a0"
|
|
33
|
-
},
|
|
34
|
-
"@std/assert@1.0.3": {
|
|
35
|
-
"integrity": "b0d03ce1ced880df67132eea140623010d415848df66f6aa5df76507ca7c26d8",
|
|
36
|
-
"dependencies": [
|
|
37
|
-
"jsr:@std/internal@^1.0.2"
|
|
38
|
-
]
|
|
39
|
-
},
|
|
40
|
-
"@std/async@1.0.4": {
|
|
41
|
-
"integrity": "373f5168a01b46ecaabc785d4e0f9ef18a010ab867af069fb905d93a9129ae5b"
|
|
42
|
-
},
|
|
43
|
-
"@std/bytes@1.0.2": {
|
|
44
|
-
"integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57"
|
|
45
|
-
},
|
|
46
|
-
"@std/expect@1.0.1": {
|
|
47
|
-
"integrity": "44075d9c2cb701ddfc4d5a260da2fb26ba3cfd94c45d3a0359f63cabbf85a058",
|
|
48
|
-
"dependencies": [
|
|
49
|
-
"jsr:@std/assert@^1.0.3",
|
|
50
|
-
"jsr:@std/internal@^1.0.2"
|
|
51
|
-
]
|
|
52
|
-
},
|
|
53
|
-
"@std/http@1.0.4": {
|
|
54
|
-
"integrity": "1a8142217907d49c4687f90ef3d257e7df2baf344c5122c322d7316df09df453"
|
|
55
|
-
},
|
|
56
|
-
"@std/internal@1.0.2": {
|
|
57
|
-
"integrity": "f4cabe2021352e8bfc24e6569700df87bf070914fc38d4b23eddd20108ac4495"
|
|
58
|
-
},
|
|
59
|
-
"@std/streams@1.0.3": {
|
|
60
|
-
"integrity": "d62e645ab981cee2c3d03040eb03cf387fc6bceef6d4564f3ed485a43741a81f",
|
|
61
|
-
"dependencies": [
|
|
62
|
-
"jsr:@std/bytes@^1.0.2"
|
|
63
|
-
]
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
"remote": {},
|
|
68
|
-
"workspace": {
|
|
69
|
-
"dependencies": [
|
|
70
|
-
"jsr:@libs/logger@2",
|
|
71
|
-
"jsr:@libs/testing@2",
|
|
72
|
-
"jsr:@libs/typing@2",
|
|
73
|
-
"jsr:@std/async@1",
|
|
74
|
-
"jsr:@std/streams@1"
|
|
75
|
-
]
|
|
76
|
-
}
|
|
77
|
-
}
|
package/mod.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=class e{constructor({level:t,format:r,output:n,tags:o,...i}={}){"granted"===globalThis.Deno?.permissions.querySync?.({name:"env",variable:"LOG_LEVEL"}).state&&(t??=globalThis.Deno?.env.get("LOG_LEVEL")),this.#e=n||null===n?n:console,this.#t=e.level.log,this.#r=e.format.text,this.#n={date:!1,time:!1,delta:!0,caller:{file:!1,name:!1,line:!1,fileformat:null}},this.level(t).format(r).options(i),this.tags=o??{}}#e;#n;options(e){if(!e)return structuredClone(this.#n);if("date"in e&&(this.#n.date=e.date),"time"in e&&(this.#n.time=e.time),"delta"in e&&(this.#n.delta=e.delta),"caller"in e)switch(!0){case!0===e.caller:this.#n.caller={file:!0,name:!0,line:!0,fileformat:this.#n.caller.fileformat};break;case!1===e.caller:this.#n.caller={file:!1,name:!1,line:!1,fileformat:this.#n.caller.fileformat};break;case"object"==typeof e.caller:"file"in e.caller&&(this.#n.caller.file=e.caller.file),"name"in e.caller&&(this.#n.caller.name=e.caller.name),"line"in e.caller&&(this.#n.caller.line=e.caller.line),"fileformat"in e.caller&&void 0!==e.caller.fileformat&&(this.#n.caller.fileformat=e.caller.fileformat)}return this}#t;level(t){return arguments.length?(Number.isNaN(Number.parseInt(`${t}`))||(t=Number.parseInt(`${t}`)),"string"==typeof t&&t in e.level&&(t=e.level[t]),"number"==typeof t&&(this.#t=!Number.isNaN(t)&&t>=0?t:-1),this):this.#t>=0?this.#t:NaN}static level=Object.freeze({disabled:NaN,error:0,warn:1,info:2,ok:2,log:3,debug:4,wdebug:4,trace:5,probe:NaN,always:1/0});error(...t){return this.#t>=e.level.error&&this.#e?.error(...this.#r(this,{level:"error",content:t,options:this.#n})),this}warn(...t){return this.#t>=e.level.warn&&this.#e?.warn(...this.#r(this,{level:"warn",content:t,options:this.#n})),this}info(...t){return this.#t>=e.level.info&&this.#e?.info(...this.#r(this,{level:"info",content:t,options:this.#n})),this}ok(...t){return this.#t>=e.level.info&&this.#e?.info(...this.#r(this,{level:"ok",content:t,options:this.#n})),this}log(...t){return this.#t>=e.level.log&&this.#e?.log(...this.#r(this,{level:"log",content:t,options:this.#n})),this}debug(...t){return this.#t>=e.level.debug&&this.#e?.debug(...this.#r(this,{level:"debug",content:t,options:this.#n})),this}wdebug(...t){return this.#t>=e.level.debug&&this.#e?.debug(...this.#r(this,{level:"wdebug",content:t,options:this.#n})),this}trace(...t){return this.#t>=e.level.trace&&this.#e?.debug(...this.#r(this,{level:"trace",content:t,options:this.#n})),this}probe(...e){return this.#e?.debug(...this.#r(this,{level:"probe",content:e,options:this.#n})),this}tags;with(t={}){return new e({level:this.#t,format:this.#r,output:this.#e,...this.#n,tags:{...this.tags,...t}})}#o(e=3){const t=Error,r=t.prepareStackTrace;t.prepareStackTrace=(e,t)=>t;const{stack:n}=new Error;t.prepareStackTrace=r;return n.map((e=>({file:e.getFileName(),name:e.getFunctionName(),line:e.getLineNumber(),column:e.getColumnNumber()})))[e]}static inspect(e){return globalThis.Deno?.inspect(e,{colors:!0,depth:1/0,strAbbreviateSize:1/0})??e}#r;format(t){return this.#r=("string"==typeof t?e.format[t]:t)??e.format.text,this}static format={text(t,{level:r,content:n,options:o}){const i={error:"red",warn:"orange",info:"cyan",ok:"green",log:"white",debug:"gray",wdebug:"yellow",trace:"gray",probe:"magenta"}[r],s=[`%c ${r.replace("wdebug","debug").toLocaleUpperCase().padEnd(5)} │%c`],l=[`color: black; background-color: ${i}`,""];if(o.date||o.time||o.delta){const e=(new Date).toISOString(),t=[];if(o.delta){const e=performance.now()/1e3;let r=e.toPrecision(4);e<1&&(r=e.toPrecision(2)),t.push(`+${r}`)}o.date&&o.time?t.push(e):o.date?t.push(e.slice(0,e.indexOf("T"))):o.time&&t.push(e.slice(e.indexOf("T")+1,-1)),s.push(`%c ${t.join(" ¦ ").trim()} %c`),l.push(`color: black; background-color: ${i}`,"")}if(o.caller.file||o.caller.name||o.caller.line){const e=t.#o();if(e){const t=[];if(o.caller.file){let r=`${e.file}`;Array.isArray(o.caller.fileformat)&&(r=r.replace(o.caller.fileformat[0],o.caller.fileformat[1])),t.push(r)}o.caller.name&&e.name&&t.push(e.name),o.caller.line&&t.push(e.line,e.column),s.push(`%c ${t.join(":").trim()} %c`),l.push("color: black; background-color: gray","")}}const a=[];for(const[r,n]of Object.entries(t.tags))a.push(`${r}:${e.inspect(n)}`);return s.push(`%c ${a.join(" ").trim()} %c`),l.push("background-color: black",""),[s.join(""),...l,...n.map(e.inspect)]},json(e,{level:t,content:r,options:n}){const o={level:t,timestamp:Date.now(),tags:e.tags,content:r},i={};if(n.date||n.time){const e=new Date(o.timestamp).toISOString();n.date&&(i.date=e.slice(0,e.indexOf("T"))),n.time&&(i.time=e.slice(e.indexOf("T")+1,-1))}if(n.delta&&(i.delta=performance.now()/1e3),n.caller.file||n.caller.name||n.caller.line){const t=e.#o();if(t){if(i.caller={},n.caller.file){let e=`${t.file}`;Array.isArray(n.caller.fileformat)&&(e=e.replace(n.caller.fileformat[0],n.caller.fileformat[1])),i.caller.file=e}n.caller.name&&t.name&&(i.caller.name=t.name),n.caller.line&&(i.caller.line=[t.line,t.column])}}return[JSON.stringify({...o,...i})]}}};TransformStream;function t(e){let t=0;for(const r of e)t+=r.length;const r=new Uint8Array(t);let n=0;for(const t of e)r.set(t,n),n+=t.length;return r}function r(e){const t=e.length,r=new Uint8Array(t);r[0]=0;let n=0,o=1;for(;o<t;)e[o]===e[n]?(n++,r[o]=n,o++):0===n?(r[o]=0,o++):n=r[n-1];return r}TransformStream,TransformStream,TransformStream,TransformStream,TransformStream;var n=class extends TransformStream{#i="";constructor(e={allowCR:!1}){super({transform:(t,r)=>{for(t=this.#i+t;;){const n=t.indexOf("\n"),o=e.allowCR?t.indexOf("\r"):-1;if(-1!==o&&o!==t.length-1&&(-1===n||n-1>o)){r.enqueue(t.slice(0,o)),t=t.slice(o+1);continue}if(-1===n)break;const i="\r"===t[n-1]?n-1:n;r.enqueue(t.slice(0,i)),t=t.slice(n+1)}this.#i=t},flush:t=>{if(""===this.#i)return;const r=e.allowCR&&this.#i.endsWith("\r")?this.#i.slice(0,-1):this.#i;t.enqueue(r)}})}};var o=new TextEncoder,i=new TextDecoder;function s(t,r,{logger:s=new e,stdin:a=null,stdout:c="debug",stderr:u="error",env:d,cwd:h,raw:f,callback:p,buffering:m,sync:g,throw:w,dryrun:b,winext:v="",os:y=Deno.build.os}={}){"windows"===y&&(t=`${t}${v}`),s=s.with({bin:t}),p&&"piped"!==l(a)&&(a="piped");const T=new Deno.Command(t,{args:r,stdin:g?"null":l(a),stdout:l(c),stderr:l(u),env:d,cwd:h,windowsRawArguments:f});if(b){s.wdebug(`dryrun: ${t} not executed`);const e={success:!0,code:0,stdio:[],stdin:"",stdout:"",stderr:""};return g?e:Promise.resolve(e)}return g?function(e,{bin:t,log:r,throw:n,stdout:o,stderr:s}){const a=Date.now(),c=e.outputSync(),{success:u,code:d}=c,h=Date.now()-a,f={get stdio(){return[[h,1,this.stdout],[h,2,this.stderr]]},stdin:"",stdout:"piped"===l(o)?i.decode(c.stdout):"",stderr:"piped"===l(s)?i.decode(c.stderr):""};for(const{channel:e,mode:t}of[{channel:"stdout",mode:o},{channel:"stderr",mode:s}])"piped"===l(t)&&f[e]&&r.with({t:h,channel:e})[t]?.(f[e]);if(!u&&n)throw new EvalError(`${t} exited with non-zero code ${d}:\n${f.stdout}\n${f.stderr}`);return{success:u,code:d,...f}}(T,{bin:t,log:s,throw:w,stdout:c,stderr:u}):async function(e,{bin:t,log:r,callback:i=({close:e})=>e?.(),buffering:s=250,throw:a,...c}){const u=e.spawn(),d=Date.now(),h={stdio:[],get stdin(){return this.stdio.filter((([e,t])=>0===t)).map((([e,t,r])=>r)).join("\n")},get stdout(){return this.stdio.filter((([e,t])=>1===t)).map((([e,t,r])=>r)).join("\n")},get stderr(){return this.stdio.filter((([e,t])=>2===t)).map((([e,t,r])=>r)).join("\n")}},f={};let p="";const m=function(e,t){let r=null,n=null;const o=(...i)=>{o.clear(),n=()=>{o.clear(),e.call(o,...i)},r=Number(setTimeout(n,t))};return o.clear=()=>{"number"==typeof r&&(clearTimeout(r),r=null,n=null)},o.flush=()=>{n?.()},Object.defineProperty(o,"pending",{get:()=>"number"==typeof r}),o}((async e=>{r.with({t:e}).trace("debounced"),p="",await i({stdio:h,i:h.stdin.length,...f})}),s);if("piped"===l(c.stdin)){const e=u.stdin.getWriter();Object.assign(f,{async write(t,n=!0){const i=Date.now()-d;c.stdin&&r.with({t:i,channel:"stdin"})[c.stdin]?.(t),h.stdio.push([i,0,t]),n&&!t.endsWith("\n")&&(t+="\n"),await e.write(o.encode(t)),p="stdin",e.releaseLock()},async close(){try{e.releaseLock(),await u.stdin.close(),r.with({t:Date.now()-d,closed:"stdin"}).trace()}catch{}},async wait(e=1e3){const t=Date.now()-d;r.with({t:t,waiting:e}).trace(),await function(e,t={}){const{signal:r,persistent:n=!0}=t;return r?.aborted?Promise.reject(r.reason):new Promise(((t,o)=>{const i=()=>{clearTimeout(s),o(r?.reason)},s=setTimeout((()=>{r?.removeEventListener("abort",i),t()}),e);if(r?.addEventListener("abort",i,{once:!0}),!1===n)try{Deno.unrefTimer(s)}catch(e){if(!(e instanceof ReferenceError))throw e;console.error("`persistent` option is only available in Deno")}}))}(e),m(t)}}),m(Date.now()-d)}await Promise.all(["stdout","stderr"].filter((e=>"piped"===l(c[e]))).map((async e=>{for await(const t of u[e].pipeThrough(new TextDecoderStream).pipeThrough(new n)){const n=Date.now()-d,o={stdout:1,stderr:2}[e];if(c[e]&&r.with({t:n,channel:e})[c[e]]?.(t),h.stdio.length&&p===e){const e=h.stdio.at(-1);e[1]===o&&(e[2]+=`\n${t}`)}else h.stdio.push([n,o,t]);p=e,m(n)}}))),m.flush();const{success:g,code:w}=await u.status;if(!g&&a)throw new EvalError(`${t} exited with non-zero code ${w}:\n${h.stdout}\n${h.stderr}`);return{success:g,code:w,...h}}(T,{bin:t,log:s,callback:p,buffering:m,throw:w,stdin:"piped"===l(a)?a:null,stdout:"piped"===l(c)?c:null,stderr:"piped"===l(u)?u:null})}function l(e){return["inherit","null"].includes(`${e}`)?`${e}`:"piped"}export{s as command};
|
package/mod.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./command.ts"
|
package/mod_test.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import "./mod.ts"
|