goke 6.4.0 → 6.5.1
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 +261 -59
- package/dist/__test__/index.test.js +80 -0
- package/dist/__test__/just-bash.test.js +128 -0
- package/dist/__test__/types.test-d.js +9 -3
- package/dist/goke-fs.d.ts +25 -0
- package/dist/goke-fs.d.ts.map +1 -0
- package/dist/goke-fs.js +4 -0
- package/dist/goke.d.ts +22 -1
- package/dist/goke.d.ts.map +1 -1
- package/dist/goke.js +25 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/just-bash.d.ts +3 -1
- package/dist/just-bash.d.ts.map +1 -1
- package/dist/just-bash.js +163 -1
- package/dist/picocolors.d.ts +55 -0
- package/dist/picocolors.d.ts.map +1 -0
- package/dist/picocolors.js +78 -0
- package/dist/runtime-browser.d.ts +5 -1
- package/dist/runtime-browser.d.ts.map +1 -1
- package/dist/runtime-browser.js +28 -1
- package/dist/runtime-node.d.ts +3 -1
- package/dist/runtime-node.d.ts.map +1 -1
- package/dist/runtime-node.js +3 -1
- package/package.json +3 -4
- package/src/__test__/index.test.ts +93 -0
- package/src/__test__/just-bash.test.ts +171 -3
- package/src/__test__/types.test-d.ts +9 -3
- package/src/goke-fs.ts +26 -0
- package/src/goke.ts +40 -5
- package/src/index.ts +1 -1
- package/src/just-bash.ts +187 -2
- package/src/picocolors.ts +140 -0
- package/src/runtime-browser.ts +35 -1
- package/src/runtime-node.ts +4 -1
package/src/goke.ts
CHANGED
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
* - Utility functions: string helpers, bracket parsing, dot-prop access
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import pc from 'picocolors'
|
|
13
|
+
import pc from './picocolors.js'
|
|
14
14
|
import mri from "./mri.js"
|
|
15
15
|
import { GokeError, coerceBySchema, extractJsonSchema, extractSchemaMetadata, isStandardSchema } from "./coerce.js"
|
|
16
16
|
import type { StandardJSONSchemaV1 } from "./coerce.js"
|
|
17
17
|
import { createJustBashCommand as createJustBashCommandBridge } from './just-bash.js'
|
|
18
|
-
import {
|
|
18
|
+
import type { GokeFs } from './goke-fs.js'
|
|
19
|
+
import { EventEmitter, fs as runtimeFs, openInBrowser, process } from '#runtime'
|
|
19
20
|
|
|
20
21
|
// ─── Node.js platform constants ───
|
|
21
22
|
|
|
@@ -210,7 +211,8 @@ const getFileName = (input: string) => {
|
|
|
210
211
|
const isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>
|
|
211
212
|
value != null
|
|
212
213
|
&& (typeof value === 'object' || typeof value === 'function')
|
|
213
|
-
&&
|
|
214
|
+
&& 'then' in value
|
|
215
|
+
&& typeof value.then === 'function'
|
|
214
216
|
|
|
215
217
|
const camelcaseOptionName = (name: string) => {
|
|
216
218
|
// Camelcase the option name
|
|
@@ -813,6 +815,9 @@ interface GokeConsole {
|
|
|
813
815
|
|
|
814
816
|
interface GokeProcess {
|
|
815
817
|
argv: string[]
|
|
818
|
+
cwd: string
|
|
819
|
+
env: Record<string, string | undefined>
|
|
820
|
+
stdin: string
|
|
816
821
|
stdout: GokeOutputStream
|
|
817
822
|
stderr: GokeOutputStream
|
|
818
823
|
exit(code: number): never | void
|
|
@@ -820,6 +825,7 @@ interface GokeProcess {
|
|
|
820
825
|
|
|
821
826
|
interface GokeExecutionContext {
|
|
822
827
|
console: GokeConsole
|
|
828
|
+
fs: GokeFs
|
|
823
829
|
process: GokeProcess
|
|
824
830
|
}
|
|
825
831
|
|
|
@@ -837,6 +843,14 @@ class GokeProcessExit extends Error {
|
|
|
837
843
|
* Options for configuring a Goke CLI instance.
|
|
838
844
|
*/
|
|
839
845
|
interface GokeOptions {
|
|
846
|
+
/** Custom cwd value exposed through the injected process context. */
|
|
847
|
+
cwd?: string
|
|
848
|
+
/** Custom environment exposed through the injected process context. */
|
|
849
|
+
env?: Record<string, string | undefined>
|
|
850
|
+
/** Custom fs implementation. Defaults to node:fs/promises in Node runtimes. */
|
|
851
|
+
fs?: GokeFs
|
|
852
|
+
/** Custom stdin content exposed through the injected process context. */
|
|
853
|
+
stdin?: string
|
|
840
854
|
/** Custom stdout stream. Defaults to process.stdout */
|
|
841
855
|
stdout?: GokeOutputStream
|
|
842
856
|
/** Custom stderr stream. Defaults to process.stderr */
|
|
@@ -930,6 +944,14 @@ class Goke<Opts extends Record<string, any> = {}> extends EventEmitter {
|
|
|
930
944
|
showHelpOnExit?: boolean
|
|
931
945
|
showVersionOnExit?: boolean
|
|
932
946
|
|
|
947
|
+
/** Working directory exposed through the injected process context. */
|
|
948
|
+
readonly cwd?: string
|
|
949
|
+
/** Environment exposed through the injected process context. */
|
|
950
|
+
readonly env?: Record<string, string | undefined>
|
|
951
|
+
/** Output stream for normal output (help, version, etc.) */
|
|
952
|
+
readonly fs: GokeFs
|
|
953
|
+
/** Standard input exposed through the injected process context. */
|
|
954
|
+
readonly stdin?: string
|
|
933
955
|
/** Output stream for normal output (help, version, etc.) */
|
|
934
956
|
readonly stdout: GokeOutputStream
|
|
935
957
|
/** Output stream for error output */
|
|
@@ -955,6 +977,10 @@ class Goke<Opts extends Record<string, any> = {}> extends EventEmitter {
|
|
|
955
977
|
this.rawArgs = []
|
|
956
978
|
this.args = []
|
|
957
979
|
this.options = {}
|
|
980
|
+
this.cwd = options?.cwd
|
|
981
|
+
this.env = options?.env
|
|
982
|
+
this.fs = options?.fs ?? runtimeFs
|
|
983
|
+
this.stdin = options?.stdin
|
|
958
984
|
this.stdout = options?.stdout ?? process.stdout
|
|
959
985
|
this.stderr = options?.stderr ?? process.stderr
|
|
960
986
|
this.console = createConsole(this.stdout, this.stderr)
|
|
@@ -967,6 +993,10 @@ class Goke<Opts extends Record<string, any> = {}> extends EventEmitter {
|
|
|
967
993
|
|
|
968
994
|
clone(options?: GokeOptions) {
|
|
969
995
|
const cloned = new Goke<Opts>(this.name, {
|
|
996
|
+
cwd: options?.cwd ?? this.cwd,
|
|
997
|
+
env: options?.env ?? this.env,
|
|
998
|
+
fs: options?.fs ?? this.fs,
|
|
999
|
+
stdin: options?.stdin ?? this.stdin,
|
|
970
1000
|
stdout: options?.stdout ?? this.stdout,
|
|
971
1001
|
stderr: options?.stderr ?? this.stderr,
|
|
972
1002
|
argv: options?.argv ?? this.#defaultArgv,
|
|
@@ -995,8 +1025,12 @@ class Goke<Opts extends Record<string, any> = {}> extends EventEmitter {
|
|
|
995
1025
|
private createExecutionContext(argv = this.rawArgs): GokeExecutionContext {
|
|
996
1026
|
return {
|
|
997
1027
|
console: this.console,
|
|
1028
|
+
fs: this.fs,
|
|
998
1029
|
process: {
|
|
999
1030
|
argv,
|
|
1031
|
+
cwd: this.cwd ?? process.cwd(),
|
|
1032
|
+
env: this.env ?? process.env,
|
|
1033
|
+
stdin: this.stdin ?? '',
|
|
1000
1034
|
stdout: this.stdout,
|
|
1001
1035
|
stderr: this.stderr,
|
|
1002
1036
|
exit: (code: number) => {
|
|
@@ -1045,7 +1079,8 @@ class Goke<Opts extends Record<string, any> = {}> extends EventEmitter {
|
|
|
1045
1079
|
>(rawName: RawName, schema: S): Goke<Opts & OptionEntry<RawName, S>>
|
|
1046
1080
|
option(rawName: string, descriptionOrSchema?: string | StandardJSONSchemaV1): this
|
|
1047
1081
|
option(rawName: string, descriptionOrSchema?: string | StandardJSONSchemaV1): any {
|
|
1048
|
-
|
|
1082
|
+
const option = new Option(rawName, descriptionOrSchema)
|
|
1083
|
+
this.globalCommand.options.push(option)
|
|
1049
1084
|
return this
|
|
1050
1085
|
}
|
|
1051
1086
|
|
|
@@ -1568,6 +1603,6 @@ class Goke<Opts extends Record<string, any> = {}> extends EventEmitter {
|
|
|
1568
1603
|
|
|
1569
1604
|
// ─── Exports ───
|
|
1570
1605
|
|
|
1571
|
-
export type { GokeOutputStream, GokeConsole, GokeOptions, GokeProcess, GokeExecutionContext }
|
|
1606
|
+
export type { GokeOutputStream, GokeConsole, GokeOptions, GokeProcess, GokeExecutionContext, GokeFs }
|
|
1572
1607
|
export { createConsole, Command, GokeProcessExit, openInBrowser }
|
|
1573
1608
|
export default Goke
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,6 @@ const goke = (name = '', options?: GokeOptions) => new Goke(name, options)
|
|
|
11
11
|
export default goke
|
|
12
12
|
export { goke, Goke, Command }
|
|
13
13
|
export { createConsole, GokeProcessExit, openInBrowser } from "./goke.js"
|
|
14
|
-
export type { GokeOutputStream, GokeConsole, GokeExecutionContext, GokeOptions, GokeProcess } from "./goke.js"
|
|
14
|
+
export type { GokeOutputStream, GokeConsole, GokeExecutionContext, GokeFs, GokeOptions, GokeProcess } from "./goke.js"
|
|
15
15
|
export type { StandardTypedV1, StandardJSONSchemaV1, JsonSchema } from "./coerce.js"
|
|
16
16
|
export { GokeError, coerceBySchema, extractJsonSchema, wrapJsonSchema, isStandardSchema, extractSchemaMetadata } from "./coerce.js"
|
package/src/just-bash.ts
CHANGED
|
@@ -6,8 +6,13 @@
|
|
|
6
6
|
* - https://github.com/vercel-labs/just-bash/blob/main/src/types.ts
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { Buffer } from 'node:buffer'
|
|
10
|
+
import { fileURLToPath } from 'node:url'
|
|
11
|
+
import type { PathLike } from 'node:fs'
|
|
12
|
+
import type { CommandContext, IFileSystem } from 'just-bash'
|
|
9
13
|
import Goke, { GokeProcessExit } from './goke.js'
|
|
10
14
|
import type { GokeOutputStream } from './goke.js'
|
|
15
|
+
import type { GokeFs, GokeFsEncodingOption, GokeFsFileContent } from './goke-fs.js'
|
|
11
16
|
|
|
12
17
|
interface JustBashExecResult {
|
|
13
18
|
stdout: string
|
|
@@ -18,9 +23,12 @@ interface JustBashExecResult {
|
|
|
18
23
|
interface JustBashCommand {
|
|
19
24
|
name: string
|
|
20
25
|
trusted: true
|
|
21
|
-
execute(args: string[]): Promise<JustBashExecResult>
|
|
26
|
+
execute(args: string[], context?: JustBashExecutionContext): Promise<JustBashExecResult>
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
type JustBashExecutionContext = Pick<CommandContext, 'cwd' | 'env' | 'fs' | 'stdin'>
|
|
30
|
+
type JustBashEncoding = 'utf8' | 'utf-8' | 'ascii' | 'binary' | 'base64' | 'hex' | 'latin1'
|
|
31
|
+
|
|
24
32
|
function createTextCaptureStream(): GokeOutputStream & { readonly text: string } {
|
|
25
33
|
const chunks: string[] = []
|
|
26
34
|
return {
|
|
@@ -33,6 +41,179 @@ function createTextCaptureStream(): GokeOutputStream & { readonly text: string }
|
|
|
33
41
|
}
|
|
34
42
|
}
|
|
35
43
|
|
|
44
|
+
const resolveJustBashPath = (fs: IFileSystem, cwd: string, path: PathLike) => {
|
|
45
|
+
if (path instanceof URL) {
|
|
46
|
+
return fileURLToPath(path)
|
|
47
|
+
}
|
|
48
|
+
return fs.resolvePath(cwd, path.toString())
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const getEncoding = (options?: GokeFsEncodingOption) => {
|
|
52
|
+
if (typeof options === 'string' || options == null) {
|
|
53
|
+
return options
|
|
54
|
+
}
|
|
55
|
+
return options.encoding
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const toJustBashEncoding = (encoding?: BufferEncoding | null): JustBashEncoding | null | undefined => {
|
|
59
|
+
if (encoding == null) {
|
|
60
|
+
return encoding
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
switch (encoding) {
|
|
64
|
+
case 'utf8':
|
|
65
|
+
case 'utf-8':
|
|
66
|
+
case 'ascii':
|
|
67
|
+
case 'binary':
|
|
68
|
+
case 'base64':
|
|
69
|
+
case 'hex':
|
|
70
|
+
case 'latin1':
|
|
71
|
+
return encoding
|
|
72
|
+
default:
|
|
73
|
+
throw new Error(`Encoding ${encoding} is not supported by the JustBash fs adapter`)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const toJustBashContent = (content: GokeFsFileContent) => {
|
|
78
|
+
if (typeof content === 'string' || content instanceof Uint8Array) {
|
|
79
|
+
return content
|
|
80
|
+
}
|
|
81
|
+
return new Uint8Array(content.buffer, content.byteOffset, content.byteLength)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const toDate = (value: Date | string | number) => {
|
|
85
|
+
const date = value instanceof Date ? value : new Date(value)
|
|
86
|
+
if (Number.isNaN(date.getTime())) {
|
|
87
|
+
throw new Error(`Invalid time value: ${String(value)}`)
|
|
88
|
+
}
|
|
89
|
+
return date
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function createJustBashEnvProxy(env: Map<string, string>): Record<string, string | undefined> {
|
|
93
|
+
return new Proxy(Object.create(null) as Record<string, string | undefined>, {
|
|
94
|
+
deleteProperty(_target, property) {
|
|
95
|
+
if (typeof property === 'string') {
|
|
96
|
+
env.delete(property)
|
|
97
|
+
}
|
|
98
|
+
return true
|
|
99
|
+
},
|
|
100
|
+
get(_target, property) {
|
|
101
|
+
if (typeof property !== 'string') return undefined
|
|
102
|
+
return env.get(property)
|
|
103
|
+
},
|
|
104
|
+
getOwnPropertyDescriptor(_target, property) {
|
|
105
|
+
if (typeof property !== 'string') return undefined
|
|
106
|
+
const value = env.get(property)
|
|
107
|
+
if (value === undefined) return undefined
|
|
108
|
+
return {
|
|
109
|
+
configurable: true,
|
|
110
|
+
enumerable: true,
|
|
111
|
+
value,
|
|
112
|
+
writable: true,
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
has(_target, property) {
|
|
116
|
+
return typeof property === 'string' && env.has(property)
|
|
117
|
+
},
|
|
118
|
+
ownKeys() {
|
|
119
|
+
return [...env.keys()]
|
|
120
|
+
},
|
|
121
|
+
set(_target, property, value) {
|
|
122
|
+
if (typeof property === 'string') {
|
|
123
|
+
if (value === undefined) {
|
|
124
|
+
env.delete(property)
|
|
125
|
+
} else {
|
|
126
|
+
env.set(property, String(value))
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return true
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function createJustBashFs(fs: IFileSystem, cwd: string): GokeFs {
|
|
135
|
+
const readFile: GokeFs['readFile'] = async (path, options) => {
|
|
136
|
+
const resolvedPath = resolveJustBashPath(fs, cwd, path)
|
|
137
|
+
const encoding = toJustBashEncoding(getEncoding(options))
|
|
138
|
+
if (encoding == null) {
|
|
139
|
+
return Buffer.from(await fs.readFileBuffer(resolvedPath))
|
|
140
|
+
}
|
|
141
|
+
return fs.readFile(resolvedPath, encoding)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const writeFile: GokeFs['writeFile'] = async (path, content, options) => {
|
|
145
|
+
const resolvedPath = resolveJustBashPath(fs, cwd, path)
|
|
146
|
+
const encoding = toJustBashEncoding(getEncoding(options)) ?? undefined
|
|
147
|
+
await fs.writeFile(resolvedPath, toJustBashContent(content), encoding)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const appendFile: GokeFs['appendFile'] = async (path, content, options) => {
|
|
151
|
+
const resolvedPath = resolveJustBashPath(fs, cwd, path)
|
|
152
|
+
const encoding = toJustBashEncoding(getEncoding(options)) ?? undefined
|
|
153
|
+
await fs.appendFile(resolvedPath, toJustBashContent(content), encoding)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const mkdir: GokeFs['mkdir'] = async (path, options) => {
|
|
157
|
+
await fs.mkdir(resolveJustBashPath(fs, cwd, path), { recursive: typeof options === 'object' ? options.recursive : undefined })
|
|
158
|
+
return undefined
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const rm: GokeFs['rm'] = async (path, options) => {
|
|
162
|
+
await fs.rm(resolveJustBashPath(fs, cwd, path), {
|
|
163
|
+
recursive: options?.recursive,
|
|
164
|
+
force: options?.force,
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const rename: GokeFs['rename'] = async (oldPath, newPath) => {
|
|
169
|
+
await fs.mv(resolveJustBashPath(fs, cwd, oldPath), resolveJustBashPath(fs, cwd, newPath))
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const copyFile: GokeFs['copyFile'] = async (src, dest) => {
|
|
173
|
+
await fs.cp(resolveJustBashPath(fs, cwd, src), resolveJustBashPath(fs, cwd, dest))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const chmod: GokeFs['chmod'] = async (path, mode) => {
|
|
177
|
+
await fs.chmod(resolveJustBashPath(fs, cwd, path), Number(mode))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const link: GokeFs['link'] = async (existingPath, newPath) => {
|
|
181
|
+
await fs.link(resolveJustBashPath(fs, cwd, existingPath), resolveJustBashPath(fs, cwd, newPath))
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const readlink: GokeFs['readlink'] = async (path) => {
|
|
185
|
+
return fs.readlink(resolveJustBashPath(fs, cwd, path))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const realpath: GokeFs['realpath'] = async (path) => {
|
|
189
|
+
return fs.realpath(resolveJustBashPath(fs, cwd, path))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const symlink: GokeFs['symlink'] = async (target, path) => {
|
|
193
|
+
await fs.symlink(target.toString(), resolveJustBashPath(fs, cwd, path))
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const utimes: GokeFs['utimes'] = async (path, atime, mtime) => {
|
|
197
|
+
await fs.utimes(resolveJustBashPath(fs, cwd, path), toDate(atime), toDate(mtime))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
appendFile,
|
|
202
|
+
chmod,
|
|
203
|
+
copyFile,
|
|
204
|
+
link,
|
|
205
|
+
mkdir,
|
|
206
|
+
readFile,
|
|
207
|
+
readlink,
|
|
208
|
+
realpath,
|
|
209
|
+
rename,
|
|
210
|
+
rm,
|
|
211
|
+
symlink,
|
|
212
|
+
utimes,
|
|
213
|
+
writeFile,
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
36
217
|
export function createJustBashCommand(
|
|
37
218
|
cli: Goke<any>,
|
|
38
219
|
options?: { name?: string }
|
|
@@ -50,11 +231,15 @@ export function createJustBashCommand(
|
|
|
50
231
|
return {
|
|
51
232
|
name,
|
|
52
233
|
trusted: true,
|
|
53
|
-
async execute(args: string[]) {
|
|
234
|
+
async execute(args: string[], context?: JustBashExecutionContext) {
|
|
54
235
|
const stdout = createTextCaptureStream()
|
|
55
236
|
const stderr = createTextCaptureStream()
|
|
56
237
|
const argv = ['node', name, ...args]
|
|
57
238
|
const cloned = cli.clone({
|
|
239
|
+
cwd: context?.cwd,
|
|
240
|
+
env: context ? createJustBashEnvProxy(context.env) : cli.env,
|
|
241
|
+
fs: context ? createJustBashFs(context.fs, context.cwd) : cli.fs,
|
|
242
|
+
stdin: context?.stdin,
|
|
58
243
|
stdout,
|
|
59
244
|
stderr,
|
|
60
245
|
argv,
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendored from picocolors by Alexey Raspopov (MIT license).
|
|
3
|
+
* Source: https://github.com/alexeyraspopov/picocolors/blob/main/picocolors.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { process } from '#runtime'
|
|
7
|
+
|
|
8
|
+
type Formatter = (input: unknown) => string
|
|
9
|
+
|
|
10
|
+
interface PicoColors {
|
|
11
|
+
isColorSupported: boolean
|
|
12
|
+
reset: Formatter
|
|
13
|
+
bold: Formatter
|
|
14
|
+
dim: Formatter
|
|
15
|
+
italic: Formatter
|
|
16
|
+
underline: Formatter
|
|
17
|
+
inverse: Formatter
|
|
18
|
+
hidden: Formatter
|
|
19
|
+
strikethrough: Formatter
|
|
20
|
+
black: Formatter
|
|
21
|
+
red: Formatter
|
|
22
|
+
green: Formatter
|
|
23
|
+
yellow: Formatter
|
|
24
|
+
blue: Formatter
|
|
25
|
+
magenta: Formatter
|
|
26
|
+
cyan: Formatter
|
|
27
|
+
white: Formatter
|
|
28
|
+
gray: Formatter
|
|
29
|
+
bgBlack: Formatter
|
|
30
|
+
bgRed: Formatter
|
|
31
|
+
bgGreen: Formatter
|
|
32
|
+
bgYellow: Formatter
|
|
33
|
+
bgBlue: Formatter
|
|
34
|
+
bgMagenta: Formatter
|
|
35
|
+
bgCyan: Formatter
|
|
36
|
+
bgWhite: Formatter
|
|
37
|
+
blackBright: Formatter
|
|
38
|
+
redBright: Formatter
|
|
39
|
+
greenBright: Formatter
|
|
40
|
+
yellowBright: Formatter
|
|
41
|
+
blueBright: Formatter
|
|
42
|
+
magentaBright: Formatter
|
|
43
|
+
cyanBright: Formatter
|
|
44
|
+
whiteBright: Formatter
|
|
45
|
+
bgBlackBright: Formatter
|
|
46
|
+
bgRedBright: Formatter
|
|
47
|
+
bgGreenBright: Formatter
|
|
48
|
+
bgYellowBright: Formatter
|
|
49
|
+
bgBlueBright: Formatter
|
|
50
|
+
bgMagentaBright: Formatter
|
|
51
|
+
bgCyanBright: Formatter
|
|
52
|
+
bgWhiteBright: Formatter
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const argv = process.argv || []
|
|
56
|
+
const env = process.env || {}
|
|
57
|
+
const isColorSupported =
|
|
58
|
+
!(!!env.NO_COLOR || argv.includes('--no-color'))
|
|
59
|
+
&& (
|
|
60
|
+
!!env.FORCE_COLOR
|
|
61
|
+
|| argv.includes('--color')
|
|
62
|
+
|| process.platform === 'win32'
|
|
63
|
+
|| (process.stdout.isTTY && env.TERM !== 'dumb')
|
|
64
|
+
|| !!env.CI
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
const replaceClose = (string: string, close: string, replace: string, index: number) => {
|
|
68
|
+
let result = ''
|
|
69
|
+
let cursor = 0
|
|
70
|
+
|
|
71
|
+
do {
|
|
72
|
+
result += string.substring(cursor, index) + replace
|
|
73
|
+
cursor = index + close.length
|
|
74
|
+
index = string.indexOf(close, cursor)
|
|
75
|
+
} while (~index)
|
|
76
|
+
|
|
77
|
+
return result + string.substring(cursor)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const formatter = (open: string, close: string, replace = open): Formatter =>
|
|
81
|
+
(input) => {
|
|
82
|
+
const string = String(input)
|
|
83
|
+
const index = string.indexOf(close, open.length)
|
|
84
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const createColors = (enabled = isColorSupported): PicoColors => {
|
|
88
|
+
const f = enabled ? formatter : () => String
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
isColorSupported: enabled,
|
|
92
|
+
reset: f('\x1b[0m', '\x1b[0m'),
|
|
93
|
+
bold: f('\x1b[1m', '\x1b[22m', '\x1b[22m\x1b[1m'),
|
|
94
|
+
dim: f('\x1b[2m', '\x1b[22m', '\x1b[22m\x1b[2m'),
|
|
95
|
+
italic: f('\x1b[3m', '\x1b[23m'),
|
|
96
|
+
underline: f('\x1b[4m', '\x1b[24m'),
|
|
97
|
+
inverse: f('\x1b[7m', '\x1b[27m'),
|
|
98
|
+
hidden: f('\x1b[8m', '\x1b[28m'),
|
|
99
|
+
strikethrough: f('\x1b[9m', '\x1b[29m'),
|
|
100
|
+
black: f('\x1b[30m', '\x1b[39m'),
|
|
101
|
+
red: f('\x1b[31m', '\x1b[39m'),
|
|
102
|
+
green: f('\x1b[32m', '\x1b[39m'),
|
|
103
|
+
yellow: f('\x1b[33m', '\x1b[39m'),
|
|
104
|
+
blue: f('\x1b[34m', '\x1b[39m'),
|
|
105
|
+
magenta: f('\x1b[35m', '\x1b[39m'),
|
|
106
|
+
cyan: f('\x1b[36m', '\x1b[39m'),
|
|
107
|
+
white: f('\x1b[37m', '\x1b[39m'),
|
|
108
|
+
gray: f('\x1b[90m', '\x1b[39m'),
|
|
109
|
+
bgBlack: f('\x1b[40m', '\x1b[49m'),
|
|
110
|
+
bgRed: f('\x1b[41m', '\x1b[49m'),
|
|
111
|
+
bgGreen: f('\x1b[42m', '\x1b[49m'),
|
|
112
|
+
bgYellow: f('\x1b[43m', '\x1b[49m'),
|
|
113
|
+
bgBlue: f('\x1b[44m', '\x1b[49m'),
|
|
114
|
+
bgMagenta: f('\x1b[45m', '\x1b[49m'),
|
|
115
|
+
bgCyan: f('\x1b[46m', '\x1b[49m'),
|
|
116
|
+
bgWhite: f('\x1b[47m', '\x1b[49m'),
|
|
117
|
+
blackBright: f('\x1b[90m', '\x1b[39m'),
|
|
118
|
+
redBright: f('\x1b[91m', '\x1b[39m'),
|
|
119
|
+
greenBright: f('\x1b[92m', '\x1b[39m'),
|
|
120
|
+
yellowBright: f('\x1b[93m', '\x1b[39m'),
|
|
121
|
+
blueBright: f('\x1b[94m', '\x1b[39m'),
|
|
122
|
+
magentaBright: f('\x1b[95m', '\x1b[39m'),
|
|
123
|
+
cyanBright: f('\x1b[96m', '\x1b[39m'),
|
|
124
|
+
whiteBright: f('\x1b[97m', '\x1b[39m'),
|
|
125
|
+
bgBlackBright: f('\x1b[100m', '\x1b[49m'),
|
|
126
|
+
bgRedBright: f('\x1b[101m', '\x1b[49m'),
|
|
127
|
+
bgGreenBright: f('\x1b[102m', '\x1b[49m'),
|
|
128
|
+
bgYellowBright: f('\x1b[103m', '\x1b[49m'),
|
|
129
|
+
bgBlueBright: f('\x1b[104m', '\x1b[49m'),
|
|
130
|
+
bgMagentaBright: f('\x1b[105m', '\x1b[49m'),
|
|
131
|
+
bgCyanBright: f('\x1b[106m', '\x1b[49m'),
|
|
132
|
+
bgWhiteBright: f('\x1b[107m', '\x1b[49m'),
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const pc = createColors()
|
|
137
|
+
|
|
138
|
+
export { createColors }
|
|
139
|
+
export type { PicoColors }
|
|
140
|
+
export default pc
|
package/src/runtime-browser.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Browser-safe runtime stubs for goke core.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { GokeFs } from './goke-fs.js'
|
|
6
|
+
|
|
5
7
|
type Listener = (...args: any[]) => void
|
|
6
8
|
|
|
7
9
|
class EventEmitter {
|
|
@@ -41,6 +43,10 @@ const createOutputStream = () => ({
|
|
|
41
43
|
const process = {
|
|
42
44
|
argv: [] as string[],
|
|
43
45
|
arch: 'browser',
|
|
46
|
+
cwd() {
|
|
47
|
+
return '/'
|
|
48
|
+
},
|
|
49
|
+
env: Object.create(null) as Record<string, string | undefined>,
|
|
44
50
|
platform: 'browser',
|
|
45
51
|
version: 'browser',
|
|
46
52
|
stdout: createOutputStream(),
|
|
@@ -52,8 +58,36 @@ const process = {
|
|
|
52
58
|
},
|
|
53
59
|
}
|
|
54
60
|
|
|
61
|
+
function createBrowserFsError(methodName: string) {
|
|
62
|
+
return new Error(
|
|
63
|
+
`fs.${methodName}() is not available in the browser runtime. Pass a custom fs implementation to goke(...).`
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function createUnsupportedFsMethod<T>(methodName: string): T {
|
|
68
|
+
return (async () => {
|
|
69
|
+
throw createBrowserFsError(methodName)
|
|
70
|
+
}) as T
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const fs: GokeFs = {
|
|
74
|
+
appendFile: createUnsupportedFsMethod<GokeFs['appendFile']>('appendFile'),
|
|
75
|
+
chmod: createUnsupportedFsMethod<GokeFs['chmod']>('chmod'),
|
|
76
|
+
copyFile: createUnsupportedFsMethod<GokeFs['copyFile']>('copyFile'),
|
|
77
|
+
link: createUnsupportedFsMethod<GokeFs['link']>('link'),
|
|
78
|
+
mkdir: createUnsupportedFsMethod<GokeFs['mkdir']>('mkdir'),
|
|
79
|
+
readFile: createUnsupportedFsMethod<GokeFs['readFile']>('readFile'),
|
|
80
|
+
readlink: createUnsupportedFsMethod<GokeFs['readlink']>('readlink'),
|
|
81
|
+
realpath: createUnsupportedFsMethod<GokeFs['realpath']>('realpath'),
|
|
82
|
+
rename: createUnsupportedFsMethod<GokeFs['rename']>('rename'),
|
|
83
|
+
rm: createUnsupportedFsMethod<GokeFs['rm']>('rm'),
|
|
84
|
+
symlink: createUnsupportedFsMethod<GokeFs['symlink']>('symlink'),
|
|
85
|
+
utimes: createUnsupportedFsMethod<GokeFs['utimes']>('utimes'),
|
|
86
|
+
writeFile: createUnsupportedFsMethod<GokeFs['writeFile']>('writeFile'),
|
|
87
|
+
}
|
|
88
|
+
|
|
55
89
|
function openInBrowser(_url: string): void {
|
|
56
90
|
// Browser builds should decide how to surface URLs themselves.
|
|
57
91
|
}
|
|
58
92
|
|
|
59
|
-
export { EventEmitter, openInBrowser, process }
|
|
93
|
+
export { EventEmitter, fs, openInBrowser, process }
|
package/src/runtime-node.ts
CHANGED
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
import { execSync } from 'child_process'
|
|
6
6
|
import { EventEmitter } from 'events'
|
|
7
|
+
import * as nodeFs from 'node:fs/promises'
|
|
8
|
+
import type { GokeFs } from './goke-fs.js'
|
|
7
9
|
|
|
8
10
|
const process = globalThis.process
|
|
11
|
+
const fs: GokeFs = nodeFs
|
|
9
12
|
|
|
10
13
|
function openInBrowser(url: string): void {
|
|
11
14
|
if (!process.stdout.isTTY) {
|
|
@@ -26,4 +29,4 @@ function openInBrowser(url: string): void {
|
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
export { EventEmitter, openInBrowser, process }
|
|
32
|
+
export { EventEmitter, fs, openInBrowser, process }
|