@strav/cli 0.1.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.
@@ -0,0 +1,128 @@
1
+ import { resolve, relative } from 'node:path'
2
+ import type { GeneratedFile } from './model_generator.ts'
3
+
4
+ // ---------------------------------------------------------------------------
5
+ // Types
6
+ // ---------------------------------------------------------------------------
7
+
8
+ export interface GeneratorPaths {
9
+ models: string
10
+ enums: string
11
+ controllers: string
12
+ services: string
13
+ events: string
14
+ validators: string
15
+ policies: string
16
+ resources: string
17
+ routes: string
18
+ tests: string
19
+ docs: string
20
+ // Database paths
21
+ schemas: string
22
+ migrations: string
23
+ }
24
+
25
+ export interface ModelNaming {
26
+ [domain: string]: string | null | undefined
27
+ }
28
+
29
+ export interface GeneratorConfig {
30
+ paths?: Partial<GeneratorPaths>
31
+ modelNaming?: ModelNaming
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Defaults
36
+ // ---------------------------------------------------------------------------
37
+
38
+ const DEFAULT_PATHS: GeneratorPaths = {
39
+ models: 'app/models',
40
+ enums: 'app/enums',
41
+ controllers: 'app/http/controllers',
42
+ services: 'app/services',
43
+ events: 'app/events',
44
+ validators: 'app/validators',
45
+ policies: 'app/policies',
46
+ resources: 'app/resources',
47
+ routes: 'start',
48
+ tests: 'tests/api',
49
+ docs: 'public/_docs',
50
+ // Database paths
51
+ schemas: 'database/schemas',
52
+ migrations: 'database/migrations',
53
+ }
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Helpers
57
+ // ---------------------------------------------------------------------------
58
+
59
+ /** Merge user config with defaults, returning fully resolved paths. */
60
+ export function resolvePaths(config?: GeneratorConfig, scope?: string): GeneratorPaths {
61
+ const basePaths = config?.paths ? { ...DEFAULT_PATHS, ...config.paths } : { ...DEFAULT_PATHS }
62
+
63
+ // If a domain is provided, append it to models and enums paths
64
+ if (scope) {
65
+ return {
66
+ ...basePaths,
67
+ models: `${basePaths.models}/${scope}`,
68
+ enums: `${basePaths.enums}/${scope}`
69
+ }
70
+ }
71
+
72
+ return basePaths
73
+ }
74
+
75
+ /**
76
+ * Compute a relative import path from a file inside `fromDir` to a file
77
+ * inside `toDir`. Returns a path suitable for ES import statements
78
+ * (e.g. `'../../services'`, `'../enums'`).
79
+ */
80
+ export function relativeImport(fromDir: string, toDir: string): string {
81
+ let rel = relative(fromDir, toDir)
82
+ // Normalize Windows separators for import paths
83
+ rel = rel.split('\\').join('/')
84
+ return rel.startsWith('.') ? rel : './' + rel
85
+ }
86
+
87
+ /** Get the model name prefix for a given domain. Returns empty string if no prefix. */
88
+ export function getModelPrefix(config: GeneratorConfig | undefined, domain: string | undefined): string {
89
+ if (!domain) return ''
90
+
91
+ // Public domain has no prefix by default
92
+ if (domain === 'public') {
93
+ return config?.modelNaming?.[domain] ?? ''
94
+ }
95
+
96
+ // For other domains, use configured prefix or default to PascalCase
97
+ if (config?.modelNaming?.[domain] !== undefined) {
98
+ return config.modelNaming[domain] || ''
99
+ }
100
+
101
+ // Default prefix: PascalCase the domain name
102
+ return domain.charAt(0).toUpperCase() + domain.slice(1).toLowerCase()
103
+ }
104
+
105
+ /**
106
+ * Format generated files with Prettier and write them to disk.
107
+ * Resolves the Prettier config from each file's location (so the project's
108
+ * `.prettierrc` is picked up automatically). Falls back to writing
109
+ * unformatted content if Prettier is not installed.
110
+ */
111
+ export async function formatAndWrite(files: GeneratedFile[]): Promise<void> {
112
+ let prettier: typeof import('prettier') | null = null
113
+ try {
114
+ prettier = await import('prettier')
115
+ } catch {
116
+ // Prettier not installed — write unformatted
117
+ }
118
+
119
+ for (const file of files) {
120
+ let content = file.content
121
+ if (prettier) {
122
+ const filePath = resolve(file.path)
123
+ const options = await prettier.resolveConfig(filePath)
124
+ content = await prettier.format(content, { ...options, filepath: filePath })
125
+ }
126
+ await Bun.write(file.path, content)
127
+ }
128
+ }