@sqldoc/sqldoc 0.0.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/src/runtime.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Runtime detection for the sqldoc shim.
3
+ * Works on both Node and Bun, compiled and uncompiled.
4
+ */
5
+
6
+ import { execSync } from 'node:child_process'
7
+
8
+ /** Whether we're running as a Bun-compiled binary */
9
+ export function isCompiledBinary(): boolean {
10
+ return process.execPath.includes('sqldoc') && typeof (globalThis as any).Bun !== 'undefined'
11
+ }
12
+
13
+ /**
14
+ * Get the command to run package installs.
15
+ * Compiled binary: uses BUN_BE_BUN to invoke itself as bun.
16
+ * Dev mode: uses the detected package manager.
17
+ */
18
+ export function getPackageManagerCommand(_sqldocDir: string): { cmd: string; env?: Record<string, string> } {
19
+ if (isCompiledBinary()) {
20
+ return {
21
+ cmd: process.execPath,
22
+ env: { BUN_BE_BUN: '1' },
23
+ }
24
+ }
25
+
26
+ // Dev mode — use whatever is available
27
+ try {
28
+ execSync('bun --version', { stdio: 'ignore' })
29
+ return { cmd: 'bun' }
30
+ } catch {}
31
+
32
+ try {
33
+ execSync('pnpm --version', { stdio: 'ignore' })
34
+ return { cmd: 'pnpm' }
35
+ } catch {}
36
+
37
+ return { cmd: 'npm' }
38
+ }
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Scaffolding helpers for `sqldoc init`.
3
+ * Generates sqldoc.config.ts and example.sql based on user choices.
4
+ */
5
+
6
+ type Dialect = 'postgres' | 'mysql' | 'sqlite'
7
+
8
+ interface ScaffoldOptions {
9
+ dialect: Dialect
10
+ namespaces: string[]
11
+ templates: string[]
12
+ }
13
+
14
+ /**
15
+ * Generate sqldoc.config.ts content based on user selections.
16
+ */
17
+ export function scaffoldConfig(opts: ScaffoldOptions): string {
18
+ const lines: string[] = []
19
+
20
+ // Imports
21
+ lines.push(`import type { SqldocConfig } from './.sqldoc/config'`)
22
+ lines.push('')
23
+
24
+ // Config object
25
+ lines.push('const config: SqldocConfig = {')
26
+
27
+ // Dialect (mandatory)
28
+ lines.push(` dialect: '${opts.dialect}',`)
29
+
30
+ // Dev URL hint
31
+ const devUrlHint = devUrlForDialect(opts.dialect)
32
+ lines.push(` // devUrl: '${devUrlHint}',`)
33
+
34
+ // Namespaces
35
+ if (opts.namespaces.length > 0) {
36
+ lines.push(' namespaces: {')
37
+
38
+ for (const ns of opts.namespaces) {
39
+ const nsConfig = namespaceConfigSnippet(ns, opts.templates)
40
+ if (nsConfig) {
41
+ lines.push(` ${ns}: ${nsConfig},`)
42
+ } else {
43
+ lines.push(` ${ns}: {},`)
44
+ }
45
+ }
46
+
47
+ lines.push(' },')
48
+ }
49
+
50
+ lines.push('}')
51
+ lines.push('')
52
+ lines.push('export default config')
53
+ lines.push('')
54
+
55
+ return lines.join('\n')
56
+ }
57
+
58
+ function devUrlForDialect(dialect: Dialect): string {
59
+ switch (dialect) {
60
+ case 'postgres':
61
+ return 'postgres://localhost:5432/mydb?sslmode=disable'
62
+ case 'mysql':
63
+ return 'mysql://localhost:3306/mydb'
64
+ case 'sqlite':
65
+ return 'sqlite://dev.db'
66
+ }
67
+ }
68
+
69
+ function namespaceConfigSnippet(ns: string, templates: string[]): string | null {
70
+ switch (ns) {
71
+ case 'docs':
72
+ return `{\n format: 'html',\n output: 'docs/schema.html',\n title: 'Schema Documentation',\n }`
73
+ case 'codegen': {
74
+ if (templates.length === 0) return null
75
+ const entries = templates.map((t) => {
76
+ const output = templateOutput(t)
77
+ return ` { template: '@sqldoc/templates/${t}', output: '${output}' },`
78
+ })
79
+ return `{\n templates: [\n${entries.join('\n')}\n ],\n }`
80
+ }
81
+ default:
82
+ return null
83
+ }
84
+ }
85
+
86
+ function templateOutput(template: string): string {
87
+ switch (template) {
88
+ case 'typescript':
89
+ return 'generated/types.ts'
90
+ case 'zod':
91
+ return 'generated/schemas.ts'
92
+ case 'drizzle':
93
+ return 'generated/drizzle.ts'
94
+ case 'prisma':
95
+ return 'generated/schema.prisma'
96
+ case 'kysely':
97
+ return 'generated/database.ts'
98
+ case 'go-structs':
99
+ return 'generated/models.go'
100
+ case 'gorm':
101
+ return 'generated/models.go'
102
+ case 'sqlc':
103
+ return 'generated/models.go'
104
+ case 'python-dataclasses':
105
+ return 'generated/models.py'
106
+ case 'pydantic':
107
+ return 'generated/models.py'
108
+ case 'sqlalchemy':
109
+ return 'generated/models.py'
110
+ case 'java-records':
111
+ return 'generated/Models.java'
112
+ case 'jpa':
113
+ return 'generated/Models.java'
114
+ case 'kotlin-data':
115
+ return 'generated/Models.kt'
116
+ case 'rust-structs':
117
+ return 'generated/models.rs'
118
+ case 'diesel':
119
+ return 'generated/models.rs'
120
+ case 'csharp-records':
121
+ return 'generated/Models.cs'
122
+ case 'efcore':
123
+ return 'generated/Models.cs'
124
+ case 'json-schema':
125
+ return 'generated/schema.json'
126
+ case 'protobuf':
127
+ return 'generated/schema.proto'
128
+ default:
129
+ return `generated/${template}`
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Generate example.sql content based on selected namespaces and dialect.
135
+ */
136
+ export function scaffoldExample(opts: ScaffoldOptions): string {
137
+ const lines: string[] = []
138
+
139
+ lines.push(`-- Example SQL file demonstrating sqldoc tags`)
140
+ lines.push(`-- See: https://sqldoc.dev/docs`)
141
+ lines.push('')
142
+
143
+ // Imports for selected namespaces
144
+ for (const ns of opts.namespaces) {
145
+ lines.push(`-- @import ${nsPackage(ns)}`)
146
+ }
147
+ if (opts.namespaces.length > 0) lines.push('')
148
+
149
+ // Table with tags for selected namespaces
150
+ lines.push(tableExample(opts))
151
+
152
+ return lines.join('\n')
153
+ }
154
+
155
+ function nsPackage(ns: string): string {
156
+ return `@sqldoc/ns-${ns}`
157
+ }
158
+
159
+ function tableExample(opts: ScaffoldOptions): string {
160
+ const lines: string[] = []
161
+ const hasNs = (ns: string) => opts.namespaces.includes(ns)
162
+
163
+ // Table-level tags
164
+ const tableTags: string[] = []
165
+ if (hasNs('audit')) tableTags.push('-- @audit')
166
+ if (hasNs('rls')) tableTags.push('-- @rls')
167
+ if (hasNs('docs')) tableTags.push('-- @docs.description("User accounts")')
168
+
169
+ if (tableTags.length > 0) {
170
+ lines.push(tableTags.join('\n'))
171
+ }
172
+
173
+ const idType = opts.dialect === 'mysql' ? 'INT AUTO_INCREMENT' : opts.dialect === 'sqlite' ? 'INTEGER' : 'SERIAL'
174
+ const textType = opts.dialect === 'mysql' ? 'VARCHAR(255)' : 'TEXT'
175
+ const timestampType =
176
+ opts.dialect === 'mysql'
177
+ ? 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP'
178
+ : opts.dialect === 'sqlite'
179
+ ? 'TEXT DEFAULT CURRENT_TIMESTAMP'
180
+ : 'TIMESTAMPTZ DEFAULT now()'
181
+
182
+ lines.push('CREATE TABLE users (')
183
+
184
+ const columns: string[] = []
185
+ columns.push(` id ${idType} PRIMARY KEY`)
186
+
187
+ // Email column with tags
188
+ const emailTags: string[] = []
189
+ if (hasNs('validate')) emailTags.push(' -- @validate.check("email ~* \'^.+@.+$\'")')
190
+ if (hasNs('anon')) emailTags.push(' -- @anon.mask("anon.fake_email()")')
191
+ if (hasNs('codegen')) emailTags.push(' -- @codegen.type("string")')
192
+ if (emailTags.length > 0) columns.push(emailTags.join('\n'))
193
+ columns.push(` email ${textType} NOT NULL`)
194
+
195
+ // Name column
196
+ if (hasNs('anon')) columns.push(' -- @anon.mask("anon.fake_first_name()")')
197
+ columns.push(` name ${textType}`)
198
+
199
+ // Created at
200
+ if (hasNs('docs')) columns.push(' -- @docs.description("When the user signed up")')
201
+ columns.push(` created_at ${timestampType}`)
202
+
203
+ lines.push(columns.join(',\n'))
204
+ lines.push(');')
205
+ lines.push('')
206
+
207
+ // RLS policy example
208
+ if (hasNs('rls') && opts.dialect === 'postgres') {
209
+ lines.push('-- @rls.policy(name: "users_own_data", for: "all", using: "auth.uid() = id")')
210
+ lines.push('')
211
+ }
212
+
213
+ return lines.join('\n')
214
+ }
215
+
216
+ /**
217
+ * List of namespace packages to install for selected namespaces.
218
+ */
219
+ export function namespacesToInstall(namespaces: string[], templates: string[]): string[] {
220
+ const packages: string[] = ['@sqldoc/cli']
221
+
222
+ for (const ns of namespaces) {
223
+ packages.push(`@sqldoc/ns-${ns}`)
224
+ }
225
+
226
+ if (namespaces.includes('codegen') && templates.length > 0) {
227
+ packages.push('@sqldoc/templates')
228
+ }
229
+
230
+ return packages
231
+ }