hekireki 0.4.2 โ 0.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 +200 -47
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.js +164 -0
- package/dist/fsp-FOfmtPYd.js +68 -0
- package/dist/generator/arktype/index.d.ts +6 -0
- package/dist/generator/arktype/index.js +121 -0
- package/dist/generator/dbml/index.d.ts +9 -0
- package/dist/generator/dbml/index.js +221 -0
- package/dist/generator/docs/index.d.ts +1 -0
- package/dist/generator/docs/index.js +1103 -0
- package/dist/generator/ecto/index.d.ts +6 -3
- package/dist/generator/ecto/index.js +150 -13
- package/dist/generator/effect/index.d.ts +6 -0
- package/dist/generator/effect/index.js +121 -0
- package/dist/generator/mermaid-er/index.d.ts +6 -3
- package/dist/generator/mermaid-er/index.js +136 -21
- package/dist/generator/valibot/index.d.ts +6 -3
- package/dist/generator/valibot/index.js +90 -45
- package/dist/generator/zod/index.d.ts +6 -3
- package/dist/generator/zod/index.js +97 -56
- package/dist/utils-BHGDO4qk.js +145 -0
- package/package.json +34 -17
- package/dist/generator/ecto/generator/ecto.d.ts +0 -3
- package/dist/generator/ecto/generator/ecto.js +0 -131
- package/dist/generator/ecto/utils/index.d.ts +0 -1
- package/dist/generator/ecto/utils/index.js +0 -1
- package/dist/generator/ecto/utils/prisma-type-to-ecto-type.d.ts +0 -1
- package/dist/generator/ecto/utils/prisma-type-to-ecto-type.js +0 -11
- package/dist/generator/mermaid-er/generator/er-content.d.ts +0 -8
- package/dist/generator/mermaid-er/generator/er-content.js +0 -23
- package/dist/generator/mermaid-er/generator/index.d.ts +0 -4
- package/dist/generator/mermaid-er/generator/index.js +0 -4
- package/dist/generator/mermaid-er/generator/model-fields.d.ts +0 -8
- package/dist/generator/mermaid-er/generator/model-fields.js +0 -25
- package/dist/generator/mermaid-er/generator/model-info.d.ts +0 -8
- package/dist/generator/mermaid-er/generator/model-info.js +0 -10
- package/dist/generator/mermaid-er/generator/relation-line.d.ts +0 -13
- package/dist/generator/mermaid-er/generator/relation-line.js +0 -14
- package/dist/generator/mermaid-er/helper/build-relation-line.d.ts +0 -9
- package/dist/generator/mermaid-er/helper/build-relation-line.js +0 -37
- package/dist/generator/mermaid-er/helper/extract-relations.d.ts +0 -8
- package/dist/generator/mermaid-er/helper/extract-relations.js +0 -22
- package/dist/generator/mermaid-er/utils/index.d.ts +0 -34
- package/dist/generator/mermaid-er/utils/index.js +0 -48
- package/dist/generator/valibot/generator/index.d.ts +0 -3
- package/dist/generator/valibot/generator/index.js +0 -3
- package/dist/generator/valibot/generator/schema.d.ts +0 -16
- package/dist/generator/valibot/generator/schema.js +0 -51
- package/dist/generator/valibot/generator/schemas.d.ts +0 -13
- package/dist/generator/valibot/generator/schemas.js +0 -17
- package/dist/generator/valibot/generator/valibot.d.ts +0 -9
- package/dist/generator/valibot/generator/valibot.js +0 -42
- package/dist/generator/valibot/utils/index.d.ts +0 -44
- package/dist/generator/valibot/utils/index.js +0 -75
- package/dist/generator/zod/generator/index.d.ts +0 -3
- package/dist/generator/zod/generator/index.js +0 -3
- package/dist/generator/zod/generator/schema.d.ts +0 -17
- package/dist/generator/zod/generator/schema.js +0 -38
- package/dist/generator/zod/generator/schemas.d.ts +0 -13
- package/dist/generator/zod/generator/schemas.js +0 -17
- package/dist/generator/zod/generator/zod.d.ts +0 -9
- package/dist/generator/zod/generator/zod.js +0 -47
- package/dist/generator/zod/utils/index.d.ts +0 -46
- package/dist/generator/zod/utils/index.js +0 -75
- package/dist/shared/format/index.d.ts +0 -1
- package/dist/shared/format/index.js +0 -9
- package/dist/shared/generator/index.d.ts +0 -11
- package/dist/shared/generator/index.js +0 -23
- package/dist/shared/helper/relations.d.ts +0 -7
- package/dist/shared/helper/relations.js +0 -5
- package/dist/shared/utils/index.d.ts +0 -61
- package/dist/shared/utils/index.js +0 -63
package/README.md
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# Hekireki
|
|
2
2
|
|
|
3
|
-
**[Hekireki](https://www.npmjs.com/package/hekireki)** is a tool that generates validation schemas for Zod and
|
|
3
|
+
**[Hekireki](https://www.npmjs.com/package/hekireki)** is a tool that generates validation schemas for Zod, Valibot, ArkType, and Effect Schema, as well as ER diagrams, from [Prisma](https://www.prisma.io/) schemas annotated with comments.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- ๐ Automatically generates [Zod](https://zod.dev/) schemas from your Prisma schema
|
|
8
8
|
- ๐ค Automatically generates [Valibot](https://valibot.dev/) schemas from your Prisma schema
|
|
9
|
-
-
|
|
9
|
+
- ๐น Automatically generates [ArkType](https://arktype.io/) schemas from your Prisma schema
|
|
10
|
+
- โก Automatically generates [Effect Schema](https://effect.website/docs/schema/introduction/) from your Prisma schema
|
|
11
|
+
- ๐ Creates [Mermaid](https://mermaid.js.org/) ER diagrams with PK/FK markers
|
|
12
|
+
- ๐ Generates [DBML](https://dbml.dbdiagram.io/) (Database Markup Language) files
|
|
13
|
+
- ๐ผ๏ธ Outputs ER diagrams as **PNG/SVG** images using [dbml-renderer](https://github.com/softwaretechnik-berlin/dbml-renderer)
|
|
10
14
|
- ๐งช Generates [Ecto](https://hexdocs.pm/ecto/Ecto.Schema.html) schemas for Elixir projects
|
|
11
15
|
โ ๏ธ Foreign key constraints are **not** included โ manage relationships in your application logic
|
|
12
16
|
|
|
@@ -21,13 +25,8 @@ npm install -D hekireki
|
|
|
21
25
|
Prepare `schema.prisma`:
|
|
22
26
|
|
|
23
27
|
```prisma
|
|
24
|
-
generator client {
|
|
25
|
-
provider = "prisma-client-js"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
28
|
datasource db {
|
|
29
29
|
provider = "sqlite"
|
|
30
|
-
url = env("DATABASE_URL")
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
generator Hekireki-ER {
|
|
@@ -48,42 +47,75 @@ generator Hekireki-Valibot {
|
|
|
48
47
|
relation = true
|
|
49
48
|
}
|
|
50
49
|
|
|
50
|
+
generator Hekireki-ArkType {
|
|
51
|
+
provider = "hekireki-arktype"
|
|
52
|
+
type = true
|
|
53
|
+
comment = true
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
generator Hekireki-Effect {
|
|
57
|
+
provider = "hekireki-effect"
|
|
58
|
+
type = true
|
|
59
|
+
comment = true
|
|
60
|
+
}
|
|
61
|
+
|
|
51
62
|
generator Hekireki-Ecto {
|
|
52
63
|
provider = "hekireki-ecto"
|
|
53
64
|
output = "schema"
|
|
54
65
|
app = "DBSchema"
|
|
55
66
|
}
|
|
56
67
|
|
|
68
|
+
generator Hekireki-DBML {
|
|
69
|
+
provider = "hekireki-dbml"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
generator Hekireki-SVG {
|
|
73
|
+
provider = "hekireki-svg"
|
|
74
|
+
output = "docs"
|
|
75
|
+
format = "png"
|
|
76
|
+
}
|
|
77
|
+
|
|
57
78
|
model User {
|
|
58
79
|
/// Primary key
|
|
59
80
|
/// @z.uuid()
|
|
60
81
|
/// @v.pipe(v.string(), v.uuid())
|
|
82
|
+
/// @a."string.uuid"
|
|
83
|
+
/// @e.Schema.UUID
|
|
61
84
|
id String @id @default(uuid())
|
|
62
85
|
/// Display name
|
|
63
86
|
/// @z.string().min(1).max(50)
|
|
64
87
|
/// @v.pipe(v.string(), v.minLength(1), v.maxLength(50))
|
|
88
|
+
/// @a."1 <= string <= 50"
|
|
89
|
+
/// @e.Schema.String.pipe(Schema.minLength(1), Schema.maxLength(50))
|
|
65
90
|
name String
|
|
66
91
|
/// One-to-many relation to Post
|
|
67
92
|
posts Post[]
|
|
68
93
|
}
|
|
69
94
|
|
|
70
|
-
/// @relation User.id Post.userId one-to-many
|
|
71
95
|
model Post {
|
|
72
96
|
/// Primary key
|
|
73
97
|
/// @z.uuid()
|
|
74
98
|
/// @v.pipe(v.string(), v.uuid())
|
|
99
|
+
/// @a."string.uuid"
|
|
100
|
+
/// @e.Schema.UUID
|
|
75
101
|
id String @id @default(uuid())
|
|
76
102
|
/// Article title
|
|
77
103
|
/// @z.string().min(1).max(100)
|
|
78
104
|
/// @v.pipe(v.string(), v.minLength(1), v.maxLength(100))
|
|
105
|
+
/// @a."1 <= string <= 100"
|
|
106
|
+
/// @e.Schema.String.pipe(Schema.minLength(1), Schema.maxLength(100))
|
|
79
107
|
title String
|
|
80
108
|
/// Body content (no length limit)
|
|
81
109
|
/// @z.string()
|
|
82
110
|
/// @v.string()
|
|
111
|
+
/// @a."string"
|
|
112
|
+
/// @e.Schema.String
|
|
83
113
|
content String
|
|
84
114
|
/// Foreign key referencing User.id
|
|
85
115
|
/// @z.uuid()
|
|
86
116
|
/// @v.pipe(v.string(), v.uuid())
|
|
117
|
+
/// @a."string.uuid"
|
|
118
|
+
/// @e.Schema.UUID
|
|
87
119
|
userId String
|
|
88
120
|
/// Prisma relation definition
|
|
89
121
|
user User @relation(fields: [userId], references: [id])
|
|
@@ -147,6 +179,7 @@ export type PostRelations = z.infer<typeof PostRelationsSchema>
|
|
|
147
179
|
```
|
|
148
180
|
|
|
149
181
|
## Valibot
|
|
182
|
+
|
|
150
183
|
```ts
|
|
151
184
|
import * as v from 'valibot'
|
|
152
185
|
|
|
@@ -184,29 +217,91 @@ export const PostSchema = v.object({
|
|
|
184
217
|
|
|
185
218
|
export type Post = v.InferInput<typeof PostSchema>
|
|
186
219
|
|
|
187
|
-
export const UserRelationsSchema = v.object({
|
|
220
|
+
export const UserRelationsSchema = v.object({
|
|
221
|
+
...UserSchema.entries,
|
|
222
|
+
posts: v.array(PostSchema),
|
|
223
|
+
})
|
|
188
224
|
|
|
189
225
|
export type UserRelations = v.InferInput<typeof UserRelationsSchema>
|
|
190
226
|
|
|
191
|
-
export const PostRelationsSchema = v.object({
|
|
227
|
+
export const PostRelationsSchema = v.object({
|
|
228
|
+
...PostSchema.entries,
|
|
229
|
+
user: UserSchema,
|
|
230
|
+
})
|
|
192
231
|
|
|
193
232
|
export type PostRelations = v.InferInput<typeof PostRelationsSchema>
|
|
194
233
|
```
|
|
195
234
|
|
|
235
|
+
## ArkType
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
import { type } from 'arktype'
|
|
239
|
+
|
|
240
|
+
export const UserSchema = type({
|
|
241
|
+
/** Primary key */
|
|
242
|
+
id: 'string.uuid',
|
|
243
|
+
/** Display name */
|
|
244
|
+
name: '1 <= string <= 50',
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
export type User = typeof UserSchema.infer
|
|
248
|
+
|
|
249
|
+
export const PostSchema = type({
|
|
250
|
+
/** Primary key */
|
|
251
|
+
id: 'string.uuid',
|
|
252
|
+
/** Article title */
|
|
253
|
+
title: '1 <= string <= 100',
|
|
254
|
+
/** Body content (no length limit) */
|
|
255
|
+
content: 'string',
|
|
256
|
+
/** Foreign key referencing User.id */
|
|
257
|
+
userId: 'string.uuid',
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
export type Post = typeof PostSchema.infer
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Effect Schema
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
import { Schema } from 'effect'
|
|
267
|
+
|
|
268
|
+
export const UserSchema = Schema.Struct({
|
|
269
|
+
/** Primary key */
|
|
270
|
+
id: Schema.UUID,
|
|
271
|
+
/** Display name */
|
|
272
|
+
name: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(50)),
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
export type User = Schema.Schema.Type<typeof UserSchema>
|
|
276
|
+
|
|
277
|
+
export const PostSchema = Schema.Struct({
|
|
278
|
+
/** Primary key */
|
|
279
|
+
id: Schema.UUID,
|
|
280
|
+
/** Article title */
|
|
281
|
+
title: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(100)),
|
|
282
|
+
/** Body content (no length limit) */
|
|
283
|
+
content: Schema.String,
|
|
284
|
+
/** Foreign key referencing User.id */
|
|
285
|
+
userId: Schema.UUID,
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
export type Post = Schema.Schema.Type<typeof PostSchema>
|
|
289
|
+
```
|
|
290
|
+
|
|
196
291
|
## Mermaid
|
|
197
292
|
|
|
198
293
|
```mermaid
|
|
199
294
|
erDiagram
|
|
200
295
|
User ||--}| Post : "(id) - (userId)"
|
|
201
296
|
User {
|
|
202
|
-
|
|
203
|
-
|
|
297
|
+
string id PK "Primary key"
|
|
298
|
+
string name "Display name"
|
|
204
299
|
}
|
|
205
300
|
Post {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
301
|
+
string id PK "Primary key"
|
|
302
|
+
string title "Article title"
|
|
303
|
+
string content "Body content (no length limit)"
|
|
304
|
+
string userId FK "Foreign key referencing User.id"
|
|
210
305
|
}
|
|
211
306
|
```
|
|
212
307
|
|
|
@@ -250,48 +345,106 @@ defmodule DBSchema.Post do
|
|
|
250
345
|
end
|
|
251
346
|
```
|
|
252
347
|
|
|
253
|
-
##
|
|
348
|
+
## DBML
|
|
349
|
+
|
|
350
|
+
```dbml
|
|
351
|
+
Table User {
|
|
352
|
+
id String [pk, note: 'Primary key']
|
|
353
|
+
name String [not null, note: 'Display name']
|
|
354
|
+
posts Post [not null, note: 'One-to-many relation to Post']
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
Table Post {
|
|
358
|
+
id String [pk, note: 'Primary key']
|
|
359
|
+
title String [not null, note: 'Article title']
|
|
360
|
+
content String [not null, note: 'Body content (no length limit)']
|
|
361
|
+
userId String [not null, note: 'Foreign key referencing User.id']
|
|
362
|
+
user User [not null, note: 'Prisma relation definition']
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
Ref Post_userId_fk: Post.userId > User.id
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## PNG/SVG
|
|
254
369
|
|
|
255
|
-
|
|
370
|
+
The `hekireki-svg` generator outputs ER diagrams as PNG or SVG images using [dbml-renderer](https://github.com/softwaretechnik-berlin/dbml-renderer).
|
|
256
371
|
|
|
257
|
-
|
|
258
|
-
|--------------|-----------|-------------------------------------|--------------------------------------------------|
|
|
259
|
-
| `output` | `string` | `./zod` | Output directory |
|
|
260
|
-
| `file` | `string` | `index.ts` | File Name |
|
|
261
|
-
| `type` | `boolean` | `false` | Generate TypeScript types |
|
|
262
|
-
| `comment` | `boolean` | `false` | Include schema documentation |
|
|
263
|
-
| `zod` | `string` | `'v4'` | Zod import version (`'mini'`, `'@hono/zod-openapi'`, or default `'v4'`) |
|
|
264
|
-
| `relation` | `boolean` | `false` | Generate relation schemas |
|
|
372
|
+
Output: `docs/er-diagram.png`
|
|
265
373
|
|
|
266
|
-
|
|
374
|
+
## Configuration
|
|
375
|
+
|
|
376
|
+
Configure each generator directly in your `schema.prisma` file:
|
|
267
377
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
378
|
+
```prisma
|
|
379
|
+
// Zod Generator
|
|
380
|
+
generator Hekireki-Zod {
|
|
381
|
+
provider = "hekireki-zod"
|
|
382
|
+
output = "./zod" // Output directory (default: ./zod)
|
|
383
|
+
file = "index.ts" // File name (default: index.ts)
|
|
384
|
+
type = true // Generate TypeScript types (default: false)
|
|
385
|
+
comment = true // Include schema documentation (default: false)
|
|
386
|
+
zod = "v4" // Zod import: "v4", "mini", or "@hono/zod-openapi" (default: v4)
|
|
387
|
+
relation = true // Generate relation schemas (default: false)
|
|
388
|
+
}
|
|
275
389
|
|
|
276
|
-
|
|
390
|
+
// Valibot Generator
|
|
391
|
+
generator Hekireki-Valibot {
|
|
392
|
+
provider = "hekireki-valibot"
|
|
393
|
+
output = "./valibot" // Output directory (default: ./valibot)
|
|
394
|
+
file = "index.ts" // File name (default: index.ts)
|
|
395
|
+
type = true // Generate TypeScript types (default: false)
|
|
396
|
+
comment = true // Include schema documentation (default: false)
|
|
397
|
+
relation = true // Generate relation schemas (default: false)
|
|
398
|
+
}
|
|
277
399
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
400
|
+
// ArkType Generator
|
|
401
|
+
generator Hekireki-ArkType {
|
|
402
|
+
provider = "hekireki-arktype"
|
|
403
|
+
output = "./arktype" // Output directory (default: ./arktype)
|
|
404
|
+
file = "index.ts" // File name (default: index.ts)
|
|
405
|
+
type = true // Generate TypeScript types (default: false)
|
|
406
|
+
comment = true // Include schema documentation (default: false)
|
|
407
|
+
}
|
|
282
408
|
|
|
283
|
-
|
|
409
|
+
// Effect Schema Generator
|
|
410
|
+
generator Hekireki-Effect {
|
|
411
|
+
provider = "hekireki-effect"
|
|
412
|
+
output = "./effect" // Output directory (default: ./effect)
|
|
413
|
+
file = "index.ts" // File name (default: index.ts)
|
|
414
|
+
type = true // Generate TypeScript types (default: false)
|
|
415
|
+
comment = true // Include schema documentation (default: false)
|
|
416
|
+
}
|
|
284
417
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
418
|
+
// Mermaid ER Generator
|
|
419
|
+
generator Hekireki-ER {
|
|
420
|
+
provider = "hekireki-mermaid-er"
|
|
421
|
+
output = "./mermaid-er" // Output directory (default: ./mermaid-er)
|
|
422
|
+
file = "ER.md" // File name (default: ER.md)
|
|
423
|
+
}
|
|
289
424
|
|
|
290
|
-
|
|
425
|
+
// Ecto Generator
|
|
426
|
+
generator Hekireki-Ecto {
|
|
427
|
+
provider = "hekireki-ecto"
|
|
428
|
+
output = "./ecto" // Output directory (default: ./ecto)
|
|
429
|
+
app = "MyApp" // App name (default: MyApp)
|
|
430
|
+
}
|
|
291
431
|
|
|
292
|
-
|
|
432
|
+
// DBML Generator
|
|
433
|
+
generator Hekireki-DBML {
|
|
434
|
+
provider = "hekireki-dbml"
|
|
435
|
+
output = "./dbml" // Output directory (default: ./dbml)
|
|
436
|
+
file = "schema.dbml" // File name (default: schema.dbml)
|
|
437
|
+
}
|
|
293
438
|
|
|
439
|
+
// SVG/PNG Generator
|
|
440
|
+
generator Hekireki-SVG {
|
|
441
|
+
provider = "hekireki-svg"
|
|
442
|
+
output = "./docs" // Output directory (default: ./docs)
|
|
443
|
+
file = "er-diagram" // File name without extension (default: er-diagram)
|
|
444
|
+
format = "png" // Output format: "png", "svg", or "dot" (default: png)
|
|
445
|
+
}
|
|
446
|
+
```
|
|
294
447
|
|
|
295
448
|
## License
|
|
296
449
|
|
|
297
|
-
Distributed under the MIT License. See [LICENSE](https://github.com/nakita628/hekireki?tab=MIT-1-ov-file) for more information.
|
|
450
|
+
Distributed under the MIT License. See [LICENSE](https://github.com/nakita628/hekireki?tab=MIT-1-ov-file) for more information.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/cli/index.d.ts
|
|
2
|
+
type Result<T> = {
|
|
3
|
+
readonly ok: true;
|
|
4
|
+
readonly value: T;
|
|
5
|
+
} | {
|
|
6
|
+
readonly ok: false;
|
|
7
|
+
readonly error: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Main CLI entry point for hekireki.
|
|
11
|
+
*/
|
|
12
|
+
declare const hekireki: () => Result<string>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { hekireki };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { serve } from "@hono/node-server";
|
|
5
|
+
import { serveStatic } from "@hono/node-server/serve-static";
|
|
6
|
+
import { Hono } from "hono";
|
|
7
|
+
|
|
8
|
+
//#region src/cli/index.ts
|
|
9
|
+
/**
|
|
10
|
+
* CLI module for hekireki.
|
|
11
|
+
*
|
|
12
|
+
* Provides the main entry point for the hekireki CLI tool.
|
|
13
|
+
*
|
|
14
|
+
* @module cli
|
|
15
|
+
*/
|
|
16
|
+
const HELP_TEXT = `โก๏ธ hekireki - Prisma schema tools
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
hekireki <command> [options]
|
|
20
|
+
|
|
21
|
+
Commands:
|
|
22
|
+
docs serve Start a local server to view the documentation
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
-p, --port <port> Specify the port (default: 5858)
|
|
26
|
+
-h, --help Show help
|
|
27
|
+
|
|
28
|
+
Examples:
|
|
29
|
+
hekireki docs serve
|
|
30
|
+
hekireki docs serve -p 3000`;
|
|
31
|
+
const DOCS_HELP_TEXT = `โก๏ธ hekireki docs - Documentation tools
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
hekireki docs serve [options]
|
|
35
|
+
|
|
36
|
+
Commands:
|
|
37
|
+
serve Start a local server to view the documentation
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
-p, --port <port> Specify the port (default: 5858)
|
|
41
|
+
-h, --help Show help
|
|
42
|
+
|
|
43
|
+
Examples:
|
|
44
|
+
hekireki docs serve
|
|
45
|
+
hekireki docs serve -p 3000`;
|
|
46
|
+
/**
|
|
47
|
+
* Parse port from CLI arguments.
|
|
48
|
+
*/
|
|
49
|
+
const parsePort = (args) => {
|
|
50
|
+
const portIndex = args.findIndex((arg) => arg === "-p" || arg === "--port");
|
|
51
|
+
if (portIndex === -1) return {
|
|
52
|
+
ok: true,
|
|
53
|
+
value: 5858
|
|
54
|
+
};
|
|
55
|
+
const portStr = args[portIndex + 1];
|
|
56
|
+
if (!portStr || portStr.startsWith("-")) return {
|
|
57
|
+
ok: false,
|
|
58
|
+
error: "โ Error: --port requires a number"
|
|
59
|
+
};
|
|
60
|
+
const port = parseInt(portStr, 10);
|
|
61
|
+
if (isNaN(port)) return {
|
|
62
|
+
ok: false,
|
|
63
|
+
error: `โ Error: Invalid port number: ${portStr}`
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
ok: true,
|
|
67
|
+
value: port
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Parse CLI arguments for docs serve command.
|
|
72
|
+
*/
|
|
73
|
+
const parseDocsServeArgs = (args) => {
|
|
74
|
+
const portResult = parsePort(args);
|
|
75
|
+
if (!portResult.ok) return portResult;
|
|
76
|
+
return {
|
|
77
|
+
ok: true,
|
|
78
|
+
value: { port: portResult.value }
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Start the documentation server.
|
|
83
|
+
*/
|
|
84
|
+
const startDocsServer = (options) => {
|
|
85
|
+
const absolutePath = path.resolve("./docs");
|
|
86
|
+
if (!fs.existsSync(absolutePath)) return {
|
|
87
|
+
ok: false,
|
|
88
|
+
error: `โ Error: Directory not found: ${absolutePath}\n Run "prisma generate" first to generate the documentation.`
|
|
89
|
+
};
|
|
90
|
+
const indexPath = path.join(absolutePath, "index.html");
|
|
91
|
+
if (!fs.existsSync(indexPath)) return {
|
|
92
|
+
ok: false,
|
|
93
|
+
error: `โ Error: index.html not found in ${absolutePath}\n Run "prisma generate" first to generate the documentation.`
|
|
94
|
+
};
|
|
95
|
+
const app = new Hono();
|
|
96
|
+
app.get("/", (c) => {
|
|
97
|
+
const html = fs.readFileSync(indexPath, "utf-8");
|
|
98
|
+
return c.html(html);
|
|
99
|
+
});
|
|
100
|
+
app.use("/*", serveStatic({ root: absolutePath }));
|
|
101
|
+
const server = serve({
|
|
102
|
+
fetch: app.fetch,
|
|
103
|
+
port: options.port
|
|
104
|
+
});
|
|
105
|
+
process.on("SIGTERM", () => {
|
|
106
|
+
server.close();
|
|
107
|
+
process.exit(0);
|
|
108
|
+
});
|
|
109
|
+
process.on("SIGINT", () => {
|
|
110
|
+
server.close();
|
|
111
|
+
process.exit(0);
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
ok: true,
|
|
115
|
+
value: `โก๏ธ Hekireki Docs Server started at http://localhost:${options.port}\n๐ Serving documentation from: ${absolutePath}`
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Handle docs subcommand.
|
|
120
|
+
*/
|
|
121
|
+
const handleDocs = (args) => {
|
|
122
|
+
const subcommand = args[0];
|
|
123
|
+
if (!subcommand || subcommand === "-h" || subcommand === "--help") return {
|
|
124
|
+
ok: true,
|
|
125
|
+
value: DOCS_HELP_TEXT
|
|
126
|
+
};
|
|
127
|
+
if (subcommand !== "serve") return {
|
|
128
|
+
ok: false,
|
|
129
|
+
error: `โ Unknown command: docs ${subcommand}\n\n${DOCS_HELP_TEXT}`
|
|
130
|
+
};
|
|
131
|
+
const parseResult = parseDocsServeArgs(args.slice(1));
|
|
132
|
+
if (!parseResult.ok) return parseResult;
|
|
133
|
+
return startDocsServer(parseResult.value);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Command handlers map.
|
|
137
|
+
*/
|
|
138
|
+
const commands = { docs: handleDocs };
|
|
139
|
+
/**
|
|
140
|
+
* Main CLI entry point for hekireki.
|
|
141
|
+
*/
|
|
142
|
+
const hekireki = () => {
|
|
143
|
+
const args = process.argv.slice(2);
|
|
144
|
+
const command = args[0];
|
|
145
|
+
if (!command || command === "-h" || command === "--help") return {
|
|
146
|
+
ok: true,
|
|
147
|
+
value: HELP_TEXT
|
|
148
|
+
};
|
|
149
|
+
const handler = commands[command];
|
|
150
|
+
if (!handler) return {
|
|
151
|
+
ok: false,
|
|
152
|
+
error: `โ Unknown command: ${command}\n\n${HELP_TEXT}`
|
|
153
|
+
};
|
|
154
|
+
return handler(args.slice(1));
|
|
155
|
+
};
|
|
156
|
+
const result = hekireki();
|
|
157
|
+
if (result.ok) console.log(result.value);
|
|
158
|
+
else {
|
|
159
|
+
console.error(result.error);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
//#endregion
|
|
164
|
+
export { hekireki };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
//#region src/shared/fsp/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates a directory if it does not already exist.
|
|
6
|
+
*
|
|
7
|
+
* @param dir - Directory path to create.
|
|
8
|
+
* @returns A `Result` that is `ok` on success, otherwise an error message.
|
|
9
|
+
*/
|
|
10
|
+
async function mkdir(dir) {
|
|
11
|
+
try {
|
|
12
|
+
await fs.mkdir(dir, { recursive: true });
|
|
13
|
+
return {
|
|
14
|
+
ok: true,
|
|
15
|
+
value: void 0
|
|
16
|
+
};
|
|
17
|
+
} catch (e) {
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
error: e instanceof Error ? e.message : String(e)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Writes UTF-8 text to a file, creating it if necessary.
|
|
26
|
+
*
|
|
27
|
+
* @param path - File path to write.
|
|
28
|
+
* @param data - Text data to write.
|
|
29
|
+
* @returns A `Result` that is `ok` on success, otherwise an error message.
|
|
30
|
+
*/
|
|
31
|
+
async function writeFile(path, data) {
|
|
32
|
+
try {
|
|
33
|
+
await fs.writeFile(path, data, "utf-8");
|
|
34
|
+
return {
|
|
35
|
+
ok: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
};
|
|
38
|
+
} catch (e) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
error: e instanceof Error ? e.message : String(e)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Writes binary data to a file, creating it if necessary.
|
|
47
|
+
*
|
|
48
|
+
* @param path - File path to write.
|
|
49
|
+
* @param data - Binary data to write.
|
|
50
|
+
* @returns A `Result` that is `ok` on success, otherwise an error message.
|
|
51
|
+
*/
|
|
52
|
+
async function writeFileBinary(path, data) {
|
|
53
|
+
try {
|
|
54
|
+
await fs.writeFile(path, data);
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
value: void 0
|
|
58
|
+
};
|
|
59
|
+
} catch (e) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
error: e instanceof Error ? e.message : String(e)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { writeFile as n, writeFileBinary as r, mkdir as t };
|