galbe 0.14.0 → 0.15.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/bin/commands/build.ts +10 -8
- package/bin/commands/generate/cli/index.ts +22 -15
- package/bin/commands/generate/cli/targets/cac.ts +189 -64
- package/bin/commands/generate/client.ts +520 -110
- package/bin/commands/generate/code.ts +11 -3
- package/bin/commands/generate/model.ts +2 -2
- package/bin/res/client.runtime.ts +184 -0
- package/bin/res/client.template.ts +1 -1
- package/package.json +2 -3
- package/src/extras.ts +1 -1
- package/src/index.ts +10 -10
- package/src/server.ts +1 -1
- package/src/types.ts +28 -4
- package/scripts/hooks/prepare-commit-msg +0 -10
- package/scripts/postinstall.ts +0 -9
|
@@ -2,7 +2,8 @@ import { $ } from 'bun'
|
|
|
2
2
|
import { devNull } from 'os'
|
|
3
3
|
import { Command, Option } from 'commander'
|
|
4
4
|
import { resolve, relative, extname } from 'path'
|
|
5
|
-
import {
|
|
5
|
+
import { readFile } from 'fs/promises'
|
|
6
|
+
import { existsSync } from 'fs'
|
|
6
7
|
|
|
7
8
|
import { CWD, fmtList, fmtVal } from '../../util'
|
|
8
9
|
import { applyPlan, planFromOapi, type GenerationPlan } from './code/openapi.parser'
|
|
@@ -114,10 +115,17 @@ export default (cmd: Command) => {
|
|
|
114
115
|
const outDir = resolve(CWD, out)
|
|
115
116
|
|
|
116
117
|
// Compute per-scope merge result.
|
|
117
|
-
const mergeResults: {
|
|
118
|
+
const mergeResults: {
|
|
119
|
+
scopeKey: string
|
|
120
|
+
content: string
|
|
121
|
+
added: RouteId[]
|
|
122
|
+
updated: RouteId[]
|
|
123
|
+
removed: RouteId[]
|
|
124
|
+
stale: RouteId[]
|
|
125
|
+
}[] = []
|
|
118
126
|
for (const scope of plan.scopes) {
|
|
119
127
|
const routePath = resolve(outDir, `${scope.routeFile}.${target}`)
|
|
120
|
-
const existing = (
|
|
128
|
+
const existing = existsSync(routePath) ? await readFile(routePath, 'utf-8') : null
|
|
121
129
|
const r = mergeRouteFile(existing, scope, mergeOpts)
|
|
122
130
|
mergeResults.push({ scopeKey: scope.scopeKey, ...r })
|
|
123
131
|
}
|
|
@@ -125,7 +125,7 @@ export default (cmd: Command) => {
|
|
|
125
125
|
FROM information_schema.tables
|
|
126
126
|
WHERE table_schema = '${schema}'
|
|
127
127
|
AND table_type = 'BASE TABLE'`)
|
|
128
|
-
tables = r.map(r => r.table_name)
|
|
128
|
+
tables = r.map((r: Record<string, string>) => r.table_name)
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
for (const tableName of tables) {
|
|
@@ -133,7 +133,7 @@ export default (cmd: Command) => {
|
|
|
133
133
|
FROM information_schema.columns
|
|
134
134
|
WHERE table_schema = '${schema}' AND table_name = '${tableName}'`)
|
|
135
135
|
types[tableName] = `type ${toPascalCase(tableName)} = {\n${t
|
|
136
|
-
.map(r => ` ${r.column_name}: ${TYPE_MAP?.[r.data_type] ?? 'any'}${r.is_nullable ? ' | null' : ''}`)
|
|
136
|
+
.map((r: Record<string, string>) => ` ${r.column_name}: ${TYPE_MAP?.[r.data_type] ?? 'any'}${r.is_nullable ? ' | null' : ''}`)
|
|
137
137
|
.join(';\n')}\n}`
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Inlined into the generated client — no exports
|
|
2
|
+
import type { BodyInit } from 'bun'
|
|
3
|
+
|
|
4
|
+
type GalbeClientConfig = {
|
|
5
|
+
server?: { url?: string }
|
|
6
|
+
headers?: Record<string, string>
|
|
7
|
+
fetch?: (req: Request) => Promise<Response>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class GalbeClientError extends Error {
|
|
11
|
+
readonly status: number
|
|
12
|
+
readonly headers: Headers
|
|
13
|
+
readonly body: string
|
|
14
|
+
constructor(status: number, headers: Headers, body: string) {
|
|
15
|
+
super(`HTTP ${status}`)
|
|
16
|
+
this.name = 'GalbeClientError'
|
|
17
|
+
this.status = status
|
|
18
|
+
this.headers = headers
|
|
19
|
+
this.body = body
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const _parseResponse = async (res: Response): Promise<any> => {
|
|
24
|
+
const ct = res.headers.get('content-type') ?? ''
|
|
25
|
+
if (ct.includes('application/json')) return res.json()
|
|
26
|
+
if (ct.includes('application/octet-stream')) return new Uint8Array(await res.arrayBuffer())
|
|
27
|
+
return res.text()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const _buildUrl = (base: string | undefined, path: string, query?: Record<string, any>): string => {
|
|
31
|
+
let url = `${base ?? ''}${path}`
|
|
32
|
+
if (query) {
|
|
33
|
+
const params = new URLSearchParams()
|
|
34
|
+
for (const [k, v] of Object.entries(query)) {
|
|
35
|
+
if (v === undefined || v === null) continue
|
|
36
|
+
if (Array.isArray(v)) for (const item of v) params.append(k, String(item))
|
|
37
|
+
else params.set(k, String(v))
|
|
38
|
+
}
|
|
39
|
+
const qs = params.toString()
|
|
40
|
+
if (qs) url += `?${qs}`
|
|
41
|
+
}
|
|
42
|
+
return url
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const _formdata = (data: Record<string, string | string[] | Blob>): FormData => {
|
|
46
|
+
const form = new FormData()
|
|
47
|
+
for (const [k, v] of Object.entries(data)) {
|
|
48
|
+
if (Array.isArray(v)) for (const item of v) form.append(k, String(item))
|
|
49
|
+
else form.append(k, v instanceof Blob ? v : String(v))
|
|
50
|
+
}
|
|
51
|
+
return form
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type _RequestOptions = {
|
|
55
|
+
query?: Record<string, any>
|
|
56
|
+
headers?: Record<string, string>
|
|
57
|
+
contentType?: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const _doFetch = (
|
|
61
|
+
config: GalbeClientConfig,
|
|
62
|
+
method: string,
|
|
63
|
+
path: string,
|
|
64
|
+
body?: any,
|
|
65
|
+
options?: _RequestOptions
|
|
66
|
+
): Promise<Response> => {
|
|
67
|
+
const url = _buildUrl(config.server?.url, path, options?.query)
|
|
68
|
+
let bodyInit: BodyInit | undefined
|
|
69
|
+
const bodyHeaders: Record<string, string> = {}
|
|
70
|
+
|
|
71
|
+
if (body !== undefined && body !== null) {
|
|
72
|
+
const ct = options?.contentType
|
|
73
|
+
if (ct === 'urlForm') {
|
|
74
|
+
bodyInit = new URLSearchParams(body).toString()
|
|
75
|
+
bodyHeaders['content-type'] = 'application/x-www-form-urlencoded'
|
|
76
|
+
} else if (ct === 'multipart') {
|
|
77
|
+
bodyInit = _formdata(body)
|
|
78
|
+
} else if (ct === 'byteArray' || body instanceof Uint8Array) {
|
|
79
|
+
bodyInit = body
|
|
80
|
+
bodyHeaders['content-type'] = 'application/octet-stream'
|
|
81
|
+
} else if (ct === 'text') {
|
|
82
|
+
bodyInit = String(body)
|
|
83
|
+
bodyHeaders['content-type'] = 'text/plain'
|
|
84
|
+
} else {
|
|
85
|
+
bodyInit = JSON.stringify(body)
|
|
86
|
+
bodyHeaders['content-type'] = 'application/json'
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const req = new Request(url, {
|
|
91
|
+
method,
|
|
92
|
+
headers: { ...config.headers, ...bodyHeaders, ...options?.headers },
|
|
93
|
+
...(bodyInit !== undefined ? { body: bodyInit } : {}),
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
return (config.fetch ?? fetch)(req)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
class GalbeRequest<T, E = any> {
|
|
100
|
+
#promise: Promise<[Response, Response]>
|
|
101
|
+
#main?: Promise<T>
|
|
102
|
+
|
|
103
|
+
constructor(fetchPromise: Promise<Response>) {
|
|
104
|
+
this.#promise = fetchPromise.then(res => [res, res.clone()] as [Response, Response])
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#getMain(): Promise<T> {
|
|
108
|
+
if (!this.#main) {
|
|
109
|
+
this.#main = this.#promise.then(async ([res]) => {
|
|
110
|
+
if (!res.ok) throw new GalbeClientError(res.status, res.headers, await res.text())
|
|
111
|
+
return _parseResponse(res) as T
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
return this.#main
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
then<R1 = T, R2 = never>(
|
|
118
|
+
onfulfilled?: ((value: T) => R1 | PromiseLike<R1>) | null,
|
|
119
|
+
onrejected?: ((reason: any) => R2 | PromiseLike<R2>) | null
|
|
120
|
+
): Promise<R1 | R2> {
|
|
121
|
+
return this.#getMain().then(onfulfilled, onrejected)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
catch<R = never>(onrejected?: ((reason: any) => R | PromiseLike<R>) | null): Promise<T | R> {
|
|
125
|
+
return this.#getMain().then(undefined, onrejected)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
finally(onfinally?: (() => void) | null): Promise<T> {
|
|
129
|
+
return this.#getMain().finally(onfinally)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async safe(): Promise<{ ok: true; data: T } | { ok: false; error: E }> {
|
|
133
|
+
const [mainRes, cloneRes] = await this.#promise
|
|
134
|
+
if (mainRes.ok) {
|
|
135
|
+
return { ok: true, data: (await _parseResponse(cloneRes)) as T }
|
|
136
|
+
} else {
|
|
137
|
+
const body = await _parseResponse(cloneRes)
|
|
138
|
+
return { ok: false, error: { status: mainRes.status, headers: mainRes.headers, body } as E }
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const _createRequest = <T, E = any>(
|
|
144
|
+
config: GalbeClientConfig,
|
|
145
|
+
method: string,
|
|
146
|
+
path: string,
|
|
147
|
+
body?: any,
|
|
148
|
+
options?: _RequestOptions
|
|
149
|
+
): GalbeRequest<T, E> => new GalbeRequest<T, E>(_doFetch(config, method, path, body, options))
|
|
150
|
+
|
|
151
|
+
const _createRawRequest = async (
|
|
152
|
+
config: GalbeClientConfig,
|
|
153
|
+
method: string,
|
|
154
|
+
path: string,
|
|
155
|
+
body?: any,
|
|
156
|
+
options?: _RequestOptions
|
|
157
|
+
): Promise<any> => {
|
|
158
|
+
const res = await _doFetch(config, method, path, body, options)
|
|
159
|
+
return {
|
|
160
|
+
status: res.status,
|
|
161
|
+
ok: res.ok,
|
|
162
|
+
redirected: res.redirected,
|
|
163
|
+
statusText: res.statusText,
|
|
164
|
+
type: res.type,
|
|
165
|
+
url: res.url,
|
|
166
|
+
headers: res.headers,
|
|
167
|
+
body: {
|
|
168
|
+
json: () => res.json(),
|
|
169
|
+
text: () => res.text(),
|
|
170
|
+
byteArray: () => res.arrayBuffer().then((b: ArrayBuffer) => new Uint8Array(b)),
|
|
171
|
+
stream: (): AsyncGenerator<Uint8Array, void, unknown> => {
|
|
172
|
+
const reader = res.body?.getReader()
|
|
173
|
+
return (async function* () {
|
|
174
|
+
if (!reader) return
|
|
175
|
+
while (true) {
|
|
176
|
+
const { value, done } = await reader.read()
|
|
177
|
+
if (done) break
|
|
178
|
+
yield value!
|
|
179
|
+
}
|
|
180
|
+
})()
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -110,7 +110,7 @@ export default class GalbeClient {
|
|
|
110
110
|
text: 'text/plain',
|
|
111
111
|
json: 'application/json',
|
|
112
112
|
urlForm: 'application/x-www-form-urlencoded',
|
|
113
|
-
}[options.contentType],
|
|
113
|
+
}[options.contentType as 'byteArray' | 'text' | 'json' | 'urlForm'],
|
|
114
114
|
}
|
|
115
115
|
: {}),
|
|
116
116
|
...(options?.headers || {}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "galbe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "Fast, lightweight and highly customizable JavaScript web framework based on Bun",
|
|
5
5
|
"author": "Pierre Caillaud M (https://github.com/pierre-cm)",
|
|
6
6
|
"type": "module",
|
|
@@ -35,11 +35,10 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"test": "bun test",
|
|
37
37
|
"typecheck": "tsc --noEmit --emitDeclarationOnly false",
|
|
38
|
-
"postinstall": "bun run ./scripts/postinstall.ts",
|
|
39
38
|
"release": "release-it"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
42
|
-
"@types/bun": "
|
|
41
|
+
"@types/bun": "latest",
|
|
43
42
|
"openapi-types": "^12.1.3",
|
|
44
43
|
"release-it": "^17.1.1"
|
|
45
44
|
},
|
package/src/extras.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { OpenAPISerializer } from './extras/spec/openapi.serializer'
|
|
2
|
-
export type { GalbeCLICommand, GalbeCLIOptions } from './types'
|
|
2
|
+
export type { GalbeCLICommand, GalbeCLIOptions, GalbeClientRoute, GalbeClientOptions } from './types'
|
package/src/index.ts
CHANGED
|
@@ -35,7 +35,7 @@ const overloadDiscriminer = <
|
|
|
35
35
|
P extends Partial<STParams<Path>>,
|
|
36
36
|
Q extends STQuery,
|
|
37
37
|
B extends STBody,
|
|
38
|
-
R extends STResponse
|
|
38
|
+
R extends STResponse,
|
|
39
39
|
>(
|
|
40
40
|
galbe: Galbe,
|
|
41
41
|
method: M,
|
|
@@ -69,7 +69,7 @@ const galbeMethod = <
|
|
|
69
69
|
P extends Partial<STParams<Path>>,
|
|
70
70
|
Q extends STQuery,
|
|
71
71
|
B extends STBody,
|
|
72
|
-
R extends STResponse
|
|
72
|
+
R extends STResponse,
|
|
73
73
|
>(
|
|
74
74
|
_galbe: Galbe,
|
|
75
75
|
method: M,
|
|
@@ -130,7 +130,7 @@ export class Galbe {
|
|
|
130
130
|
stopCb: (() => void)[] = []
|
|
131
131
|
errorCb: ErrorHandler[] = []
|
|
132
132
|
listening: boolean = false
|
|
133
|
-
server?: Server
|
|
133
|
+
server?: Server<any>
|
|
134
134
|
plugins: GalbePlugin[] = []
|
|
135
135
|
constructor(config?: GalbeConfig) {
|
|
136
136
|
this.config = config ?? {}
|
|
@@ -186,7 +186,7 @@ export class Galbe {
|
|
|
186
186
|
H extends STHeaders,
|
|
187
187
|
Q extends STQuery,
|
|
188
188
|
B extends STBody,
|
|
189
|
-
R extends STResponse
|
|
189
|
+
R extends STResponse,
|
|
190
190
|
>(
|
|
191
191
|
path: Path,
|
|
192
192
|
arg2:
|
|
@@ -205,7 +205,7 @@ export class Galbe {
|
|
|
205
205
|
H extends STHeaders,
|
|
206
206
|
Q extends STQuery,
|
|
207
207
|
B extends STBody,
|
|
208
|
-
R extends STResponse
|
|
208
|
+
R extends STResponse,
|
|
209
209
|
>(
|
|
210
210
|
path: Path,
|
|
211
211
|
arg2:
|
|
@@ -223,7 +223,7 @@ export class Galbe {
|
|
|
223
223
|
H extends STHeaders,
|
|
224
224
|
Q extends STQuery,
|
|
225
225
|
B extends STBody,
|
|
226
|
-
R extends STResponse
|
|
226
|
+
R extends STResponse,
|
|
227
227
|
>(
|
|
228
228
|
path: Path,
|
|
229
229
|
arg2:
|
|
@@ -241,7 +241,7 @@ export class Galbe {
|
|
|
241
241
|
H extends STHeaders,
|
|
242
242
|
Q extends STQuery,
|
|
243
243
|
B extends STBody,
|
|
244
|
-
R extends STResponse
|
|
244
|
+
R extends STResponse,
|
|
245
245
|
>(
|
|
246
246
|
path: Path,
|
|
247
247
|
arg2:
|
|
@@ -259,7 +259,7 @@ export class Galbe {
|
|
|
259
259
|
H extends STHeaders,
|
|
260
260
|
Q extends STQuery,
|
|
261
261
|
B extends STBody,
|
|
262
|
-
R extends STResponse
|
|
262
|
+
R extends STResponse,
|
|
263
263
|
>(
|
|
264
264
|
path: Path,
|
|
265
265
|
arg2:
|
|
@@ -277,7 +277,7 @@ export class Galbe {
|
|
|
277
277
|
H extends STHeaders,
|
|
278
278
|
Q extends STQuery,
|
|
279
279
|
B extends STBody,
|
|
280
|
-
R extends STResponse
|
|
280
|
+
R extends STResponse,
|
|
281
281
|
>(
|
|
282
282
|
path: Path,
|
|
283
283
|
arg2:
|
|
@@ -295,7 +295,7 @@ export class Galbe {
|
|
|
295
295
|
H extends STHeaders,
|
|
296
296
|
Q extends STQuery,
|
|
297
297
|
B extends STBody,
|
|
298
|
-
R extends STResponse
|
|
298
|
+
R extends STResponse,
|
|
299
299
|
>(
|
|
300
300
|
path: Path,
|
|
301
301
|
arg2:
|
package/src/server.ts
CHANGED
|
@@ -171,7 +171,7 @@ export default async (galbe: Galbe, port?: number, hostname?: string) => {
|
|
|
171
171
|
|
|
172
172
|
const parsedResponse = responseParser(response, context as Context, cookies, schema.response)
|
|
173
173
|
|
|
174
|
-
if (galbe.config?.responseValidator?.enabled !== false && schema.response)
|
|
174
|
+
if (galbe.config?.responseValidator?.enabled !== false && schema.response && !(response instanceof Response))
|
|
175
175
|
validateResponse(response, schema.response, parsedResponse.status || 200)
|
|
176
176
|
|
|
177
177
|
for (const p of pluginsCb.afterHandle) {
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Serve, SocketAddress, TLSOptions } from 'bun'
|
|
2
2
|
import type {
|
|
3
3
|
STAny,
|
|
4
4
|
STArray,
|
|
@@ -140,7 +140,7 @@ export type GalbeConfig = {
|
|
|
140
140
|
basePath?: string
|
|
141
141
|
/** Enable or disable TLS support. */
|
|
142
142
|
tls?: TLSOptions
|
|
143
|
-
server?: Exclude<
|
|
143
|
+
server?: Exclude<Serve.Options<any>, 'port'> | TLSOptions
|
|
144
144
|
/** A Glob Pattern or a list of Glob patterns defining the route files to be analyzed by the Automatic Route Analyzer. */
|
|
145
145
|
routes?: boolean | string | string[]
|
|
146
146
|
router?: { cacheEnabled: boolean }
|
|
@@ -343,7 +343,7 @@ export class RequestError extends Error {
|
|
|
343
343
|
const message =
|
|
344
344
|
typeof options.payload === 'string'
|
|
345
345
|
? options.payload
|
|
346
|
-
: HttpStatus[status as keyof typeof HttpStatus] ?? 'Request Error'
|
|
346
|
+
: (HttpStatus[status as keyof typeof HttpStatus] ?? 'Request Error')
|
|
347
347
|
super(message)
|
|
348
348
|
this.name = new.target?.name ?? 'RequestError'
|
|
349
349
|
this.status = status
|
|
@@ -484,5 +484,29 @@ export type GalbeCLIOptions = {
|
|
|
484
484
|
args: Record<string, string>,
|
|
485
485
|
options: Record<string, any>
|
|
486
486
|
) => MaybePromise<Request>
|
|
487
|
-
responseFormatter?: (
|
|
487
|
+
responseFormatter?: (
|
|
488
|
+
res: Response,
|
|
489
|
+
command: GalbeCLICommand,
|
|
490
|
+
args: Record<string, string>,
|
|
491
|
+
options: Record<string, any>
|
|
492
|
+
) => MaybePromise<string>
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export type GalbeClientRoute = {
|
|
496
|
+
method: string
|
|
497
|
+
path: string
|
|
498
|
+
operationId: string
|
|
499
|
+
autoDerived: boolean
|
|
500
|
+
params: Record<string, { type: string; description?: string }>
|
|
501
|
+
query: Record<string, { type: string; optional: boolean; description?: string }>
|
|
502
|
+
headers: Record<string, { type: string; optional: boolean; description?: string }>
|
|
503
|
+
body: Record<string, STSchema> | null
|
|
504
|
+
response: STResponse | null
|
|
505
|
+
summary?: string
|
|
506
|
+
description?: string
|
|
507
|
+
tags: string[]
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export type GalbeClientOptions = {
|
|
511
|
+
className?: string
|
|
488
512
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
const COMMIT_MSG = await Bun.file(Bun.argv[2]).text()
|
|
4
|
-
const COMMIT_EMOJI = { feat: '✨', fix: '🔧', doc: '📚', chore: '🧹' }
|
|
5
|
-
|
|
6
|
-
const newCommitMsg = COMMIT_MSG.replace(/^(feat|fix|doc|chore):(.*)/, (_, type, msg) => {
|
|
7
|
-
return `${COMMIT_EMOJI[type]} ${type}:${msg}`
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
await Bun.write(Bun.argv[2], newCommitMsg)
|
package/scripts/postinstall.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { $ } from 'bun'
|
|
2
|
-
import { existsSync } from 'fs'
|
|
3
|
-
|
|
4
|
-
if (existsSync('.git')) {
|
|
5
|
-
console.log('Setting up dev environment')
|
|
6
|
-
Bun.write('.git/hooks/prepare-commit-msg', Bun.file('scripts/hooks/prepare-commit-msg'))
|
|
7
|
-
await $`chmod +x .git/hooks/prepare-commit-msg`
|
|
8
|
-
console.log('done')
|
|
9
|
-
}
|