-
Notifications
You must be signed in to change notification settings - Fork 380
Expand file tree
/
Copy pathconfig.ts
More file actions
146 lines (131 loc) · 4.28 KB
/
config.ts
File metadata and controls
146 lines (131 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { workspace, WorkspaceFolder } from 'vscode'
import path from 'path'
import fs from 'fs'
import { Result, err, isErr, ok } from '@bus/result'
import { traceVerbose, traceInfo } from './common/log'
import { parse } from 'shell-quote'
import { z } from 'zod'
const sqlmeshConfigurationSchema = z.object({
projectPaths: z.array(z.string()),
lspEntryPoint: z.string(),
})
export type SqlmeshConfiguration = z.infer<typeof sqlmeshConfigurationSchema>
/**
* Get the SQLMesh configuration from VS Code settings.
*
* @returns The SQLMesh configuration
*/
function getSqlmeshConfiguration(): SqlmeshConfiguration {
const config = workspace.getConfiguration('sqlmesh')
const projectPaths = config.get<string[]>('projectPaths', [])
const lspEntryPoint = config.get<string>('lspEntrypoint', '')
const parsed = sqlmeshConfigurationSchema.safeParse({
projectPaths,
lspEntryPoint,
})
if (!parsed.success) {
throw new Error(
`Invalid SQLMesh configuration: ${JSON.stringify(parsed.error)}`,
)
}
return parsed.data
}
const stringsArray = z.array(z.string())
/**
* Get the SQLMesh LSP entry point from VS Code settings. undefined if not set
* it's expected to be a string in the format "command arg1 arg2 ...".
*/
export function getSqlmeshLspEntryPoint():
| {
entrypoint: string
args: string[]
}
| undefined {
const config = getSqlmeshConfiguration()
if (config.lspEntryPoint === '') {
return undefined
}
// Split the entry point into command and arguments
const parts = parse(config.lspEntryPoint)
const parsed = stringsArray.safeParse(parts)
if (!parsed.success) {
throw new Error(
`Invalid lspEntrypoint configuration: ${config.lspEntryPoint}. Expected a
string in the format "command arg1 arg2 ...".`,
)
}
const entrypoint = parsed.data[0]
const args = parsed.data.slice(1)
return { entrypoint, args }
}
/**
* Validate and resolve the project paths from configuration.
* If no project path is configured, use the workspace folder.
* If the project path is configured, it must be a directory that contains a SQLMesh project.
*
* @param workspaceFolder The current workspace folder
* @returns A Result containing the resolved project paths or an error
*/
export function resolveProjectPath(workspaceFolder: WorkspaceFolder): Result<
{
projectPaths: string[] | undefined
workspaceFolder: string
},
string
> {
const config = getSqlmeshConfiguration()
if (config.projectPaths.length === 0) {
// If no project path is configured, use the workspace folder
traceVerbose('No project path configured, using workspace folder')
return ok({
workspaceFolder: workspaceFolder.uri.fsPath,
projectPaths: undefined,
})
}
const resolvedPaths: string[] = []
for (const projectPath of config.projectPaths) {
const result = resolveSingleProjectPath(workspaceFolder, projectPath)
if (isErr(result)) {
return result
}
resolvedPaths.push(result.value)
}
return ok({
projectPaths: resolvedPaths,
workspaceFolder: workspaceFolder.uri.fsPath,
})
}
function resolveSingleProjectPath(
workspaceFolder: WorkspaceFolder,
projectPath: string,
): Result<string, string> {
let resolvedPath: string
// Check if the path is absolute
if (path.isAbsolute(projectPath)) {
resolvedPath = projectPath
} else {
// Resolve relative path from workspace root
resolvedPath = path.join(workspaceFolder.uri.fsPath, projectPath)
}
// Normalize the path
resolvedPath = path.normalize(resolvedPath)
// Validate that the path exists
if (!fs.existsSync(resolvedPath)) {
return err(`Configured project path does not exist: ${resolvedPath}`)
}
// Validate that it's a directory
const stats = fs.statSync(resolvedPath)
if (!stats.isDirectory()) {
return err(`Configured project path is not a directory: ${resolvedPath}`)
}
// Check if it contains SQLMesh project files (config.yaml, config.yml, or config.py)
const configFiles = ['config.yaml', 'config.yml', 'config.py']
const hasConfigFile = configFiles.some(file =>
fs.existsSync(path.join(resolvedPath, file)),
)
if (!hasConfigFile) {
traceInfo(`Warning: No SQLMesh configuration file found in ${resolvedPath}`)
}
traceVerbose(`Using project path: ${resolvedPath}`)
return ok(resolvedPath)
}