yamchart 0.3.1 → 0.3.3
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/dist/chunk-4P5UHWYK.js +247 -0
- package/dist/chunk-4P5UHWYK.js.map +1 -0
- package/dist/chunk-A24KVXJQ.js +922 -0
- package/dist/chunk-A24KVXJQ.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/chunk-LL3VKMZM.js +1265 -0
- package/dist/chunk-LL3VKMZM.js.map +1 -0
- package/dist/dev-PTVNJI7G.js +13557 -0
- package/dist/dev-PTVNJI7G.js.map +1 -0
- package/dist/dist-JH7OL7U4.js +16 -0
- package/dist/dist-JH7OL7U4.js.map +1 -0
- package/dist/dist-JKJLH3F6.js +56 -0
- package/dist/dist-JKJLH3F6.js.map +1 -0
- package/dist/{generate-RD3LCS73.js → generate-KNER36CB.js} +3 -1
- package/dist/{generate-RD3LCS73.js.map → generate-KNER36CB.js.map} +1 -1
- package/dist/index.js +13 -11
- package/dist/index.js.map +1 -1
- package/dist/{init-6D5VNGSP.js → init-FTSEOTAD.js} +3 -1
- package/dist/{init-6D5VNGSP.js.map → init-FTSEOTAD.js.map} +1 -1
- package/dist/{reset-password-MJ54ICGP.js → reset-password-IZQTDTU7.js} +3 -2
- package/dist/{reset-password-MJ54ICGP.js.map → reset-password-IZQTDTU7.js.map} +1 -1
- package/dist/{sync-dbt-IDDD4X2Z.js → sync-dbt-6WY7HKP7.js} +3 -1
- package/dist/{sync-dbt-IDDD4X2Z.js.map → sync-dbt-6WY7HKP7.js.map} +1 -1
- package/dist/{test-N4KIIKQN.js → test-WYNX4RYZ.js} +11 -10
- package/dist/{test-N4KIIKQN.js.map → test-WYNX4RYZ.js.map} +1 -1
- package/dist/{update-QHLCWS56.js → update-GWPF5AS6.js} +2 -1
- package/dist/{update-QHLCWS56.js.map → update-GWPF5AS6.js.map} +1 -1
- package/package.json +25 -7
- package/dist/chunk-6GDL3DH4.js +0 -354
- package/dist/chunk-6GDL3DH4.js.map +0 -1
- package/dist/dev-HMLMSTA7.js +0 -106
- package/dist/dev-HMLMSTA7.js.map +0 -1
|
@@ -0,0 +1,922 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseModelMetadata
|
|
3
|
+
} from "./chunk-LL3VKMZM.js";
|
|
4
|
+
|
|
5
|
+
// src/commands/validate.ts
|
|
6
|
+
import { readFile, readdir, access } from "fs/promises";
|
|
7
|
+
import { join, extname, relative } from "path";
|
|
8
|
+
import { parse as parseYaml } from "yaml";
|
|
9
|
+
|
|
10
|
+
// ../../packages/schema/dist/connection.js
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
var EnvAuthSchema = z.object({
|
|
13
|
+
type: z.literal("env"),
|
|
14
|
+
user_var: z.string(),
|
|
15
|
+
password_var: z.string()
|
|
16
|
+
});
|
|
17
|
+
var KeyPairAuthSchema = z.object({
|
|
18
|
+
type: z.literal("key_pair"),
|
|
19
|
+
user_var: z.string(),
|
|
20
|
+
private_key_path: z.string()
|
|
21
|
+
});
|
|
22
|
+
var SecretManagerAuthSchema = z.object({
|
|
23
|
+
type: z.literal("secret_manager"),
|
|
24
|
+
provider: z.enum(["aws_secrets_manager", "gcp_secret_manager", "vault"]),
|
|
25
|
+
secret_id: z.string()
|
|
26
|
+
});
|
|
27
|
+
var AuthSchema = z.discriminatedUnion("type", [
|
|
28
|
+
EnvAuthSchema,
|
|
29
|
+
KeyPairAuthSchema,
|
|
30
|
+
SecretManagerAuthSchema
|
|
31
|
+
]);
|
|
32
|
+
var PoolConfigSchema = z.object({
|
|
33
|
+
min_connections: z.number().int().positive().optional(),
|
|
34
|
+
max_connections: z.number().int().positive().optional(),
|
|
35
|
+
idle_timeout: z.number().int().positive().optional()
|
|
36
|
+
});
|
|
37
|
+
var QueryConfigSchema = z.object({
|
|
38
|
+
timeout: z.number().int().positive().optional(),
|
|
39
|
+
max_rows: z.number().int().positive().optional()
|
|
40
|
+
});
|
|
41
|
+
var DuckDBConfigSchema = z.object({
|
|
42
|
+
path: z.string()
|
|
43
|
+
// file path or :memory:
|
|
44
|
+
});
|
|
45
|
+
var PostgresConfigSchema = z.object({
|
|
46
|
+
host: z.string(),
|
|
47
|
+
port: z.number().int().positive().default(5432),
|
|
48
|
+
database: z.string(),
|
|
49
|
+
schema: z.string().optional(),
|
|
50
|
+
ssl: z.boolean().optional()
|
|
51
|
+
});
|
|
52
|
+
var SnowflakeConfigSchema = z.object({
|
|
53
|
+
account: z.string(),
|
|
54
|
+
warehouse: z.string(),
|
|
55
|
+
database: z.string(),
|
|
56
|
+
schema: z.string().optional(),
|
|
57
|
+
role: z.string().optional()
|
|
58
|
+
});
|
|
59
|
+
var MySQLConfigSchema = z.object({
|
|
60
|
+
host: z.string(),
|
|
61
|
+
port: z.number().int().positive().default(3306),
|
|
62
|
+
database: z.string(),
|
|
63
|
+
ssl: z.boolean().optional()
|
|
64
|
+
});
|
|
65
|
+
var SQLiteConfigSchema = z.object({
|
|
66
|
+
path: z.string()
|
|
67
|
+
// file path or :memory:
|
|
68
|
+
});
|
|
69
|
+
var BaseConnectionSchema = z.object({
|
|
70
|
+
name: z.string().min(1),
|
|
71
|
+
description: z.string().optional(),
|
|
72
|
+
pool: PoolConfigSchema.optional(),
|
|
73
|
+
query: QueryConfigSchema.optional()
|
|
74
|
+
});
|
|
75
|
+
var DuckDBConnectionSchema = BaseConnectionSchema.extend({
|
|
76
|
+
type: z.literal("duckdb"),
|
|
77
|
+
config: DuckDBConfigSchema,
|
|
78
|
+
auth: z.undefined().optional()
|
|
79
|
+
});
|
|
80
|
+
var PostgresConnectionSchema = BaseConnectionSchema.extend({
|
|
81
|
+
type: z.literal("postgres"),
|
|
82
|
+
config: PostgresConfigSchema,
|
|
83
|
+
auth: AuthSchema.optional()
|
|
84
|
+
});
|
|
85
|
+
var SnowflakeConnectionSchema = BaseConnectionSchema.extend({
|
|
86
|
+
type: z.literal("snowflake"),
|
|
87
|
+
config: SnowflakeConfigSchema,
|
|
88
|
+
auth: AuthSchema
|
|
89
|
+
});
|
|
90
|
+
var MySQLConnectionSchema = BaseConnectionSchema.extend({
|
|
91
|
+
type: z.literal("mysql"),
|
|
92
|
+
config: MySQLConfigSchema,
|
|
93
|
+
auth: AuthSchema.optional()
|
|
94
|
+
});
|
|
95
|
+
var SQLiteConnectionSchema = BaseConnectionSchema.extend({
|
|
96
|
+
type: z.literal("sqlite"),
|
|
97
|
+
config: SQLiteConfigSchema,
|
|
98
|
+
auth: z.undefined().optional()
|
|
99
|
+
});
|
|
100
|
+
var ConnectionSchema = z.discriminatedUnion("type", [
|
|
101
|
+
DuckDBConnectionSchema,
|
|
102
|
+
PostgresConnectionSchema,
|
|
103
|
+
SnowflakeConnectionSchema,
|
|
104
|
+
MySQLConnectionSchema,
|
|
105
|
+
SQLiteConnectionSchema
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
// ../../packages/schema/dist/chart.js
|
|
109
|
+
import { z as z2 } from "zod";
|
|
110
|
+
var AxisTypeSchema = z2.enum(["temporal", "quantitative", "ordinal", "nominal"]);
|
|
111
|
+
var AxisSchema = z2.object({
|
|
112
|
+
field: z2.string().min(1),
|
|
113
|
+
type: AxisTypeSchema,
|
|
114
|
+
format: z2.string().optional(),
|
|
115
|
+
label: z2.string().optional()
|
|
116
|
+
});
|
|
117
|
+
var ChartTypeSchema = z2.enum([
|
|
118
|
+
"line",
|
|
119
|
+
"bar",
|
|
120
|
+
"area",
|
|
121
|
+
"pie",
|
|
122
|
+
"donut",
|
|
123
|
+
"table",
|
|
124
|
+
"metric",
|
|
125
|
+
"map",
|
|
126
|
+
"heatmap",
|
|
127
|
+
"funnel",
|
|
128
|
+
"sankey",
|
|
129
|
+
"treemap",
|
|
130
|
+
"waterfall",
|
|
131
|
+
"gauge"
|
|
132
|
+
]);
|
|
133
|
+
var GradientSchema = z2.union([
|
|
134
|
+
z2.boolean(),
|
|
135
|
+
z2.object({
|
|
136
|
+
from: z2.string(),
|
|
137
|
+
to: z2.string()
|
|
138
|
+
})
|
|
139
|
+
]);
|
|
140
|
+
var LongFormatSeriesSchema = z2.object({
|
|
141
|
+
field: z2.string().min(1),
|
|
142
|
+
colors: z2.record(z2.string(), z2.string()).optional()
|
|
143
|
+
});
|
|
144
|
+
var WideFormatColumnSchema = z2.object({
|
|
145
|
+
field: z2.string().min(1),
|
|
146
|
+
name: z2.string().optional(),
|
|
147
|
+
type: z2.enum(["line", "bar", "area"]).optional(),
|
|
148
|
+
axis: z2.enum(["left", "right"]).optional(),
|
|
149
|
+
color: z2.string().optional(),
|
|
150
|
+
style: z2.enum(["solid", "dashed", "dotted"]).optional(),
|
|
151
|
+
opacity: z2.number().min(0).max(1).optional(),
|
|
152
|
+
gradient: GradientSchema.optional()
|
|
153
|
+
});
|
|
154
|
+
var WideFormatSeriesSchema = z2.object({
|
|
155
|
+
columns: z2.array(WideFormatColumnSchema).min(1)
|
|
156
|
+
});
|
|
157
|
+
var SeriesConfigSchema = z2.union([
|
|
158
|
+
LongFormatSeriesSchema,
|
|
159
|
+
WideFormatSeriesSchema
|
|
160
|
+
]);
|
|
161
|
+
var ColorConditionSchema = z2.object({
|
|
162
|
+
when: z2.string(),
|
|
163
|
+
color: z2.string()
|
|
164
|
+
});
|
|
165
|
+
var ConditionalColorSchema = z2.object({
|
|
166
|
+
conditions: z2.array(ColorConditionSchema).min(1),
|
|
167
|
+
default: z2.string().optional()
|
|
168
|
+
});
|
|
169
|
+
var ColorSchema = z2.union([
|
|
170
|
+
z2.string(),
|
|
171
|
+
ConditionalColorSchema
|
|
172
|
+
]);
|
|
173
|
+
var LegendSchema = z2.object({
|
|
174
|
+
show: z2.boolean().optional(),
|
|
175
|
+
position: z2.enum(["top", "bottom", "left", "right"]).optional()
|
|
176
|
+
});
|
|
177
|
+
var LineAnnotationSchema = z2.object({
|
|
178
|
+
type: z2.literal("line"),
|
|
179
|
+
value: z2.number(),
|
|
180
|
+
label: z2.string().optional(),
|
|
181
|
+
color: z2.string().optional(),
|
|
182
|
+
style: z2.enum(["solid", "dashed", "dotted"]).optional()
|
|
183
|
+
});
|
|
184
|
+
var BandAnnotationSchema = z2.object({
|
|
185
|
+
type: z2.literal("band"),
|
|
186
|
+
from: z2.number(),
|
|
187
|
+
to: z2.number(),
|
|
188
|
+
label: z2.string().optional(),
|
|
189
|
+
color: z2.string().optional()
|
|
190
|
+
});
|
|
191
|
+
var AnnotationSchema = z2.discriminatedUnion("type", [
|
|
192
|
+
LineAnnotationSchema,
|
|
193
|
+
BandAnnotationSchema
|
|
194
|
+
]);
|
|
195
|
+
var InteractionsSchema = z2.object({
|
|
196
|
+
tooltip: z2.boolean().default(true),
|
|
197
|
+
zoom: z2.boolean().default(false),
|
|
198
|
+
brush: z2.boolean().default(false)
|
|
199
|
+
});
|
|
200
|
+
var KpiFormatSchema = z2.object({
|
|
201
|
+
type: z2.enum(["number", "currency", "percent"]),
|
|
202
|
+
currency: z2.string().optional(),
|
|
203
|
+
// e.g., 'USD', 'EUR'
|
|
204
|
+
decimals: z2.number().optional()
|
|
205
|
+
});
|
|
206
|
+
var KpiComparisonSchema = z2.object({
|
|
207
|
+
enabled: z2.boolean(),
|
|
208
|
+
field: z2.string().min(1),
|
|
209
|
+
label: z2.string().optional(),
|
|
210
|
+
type: z2.enum(["percent_change", "absolute"])
|
|
211
|
+
});
|
|
212
|
+
var KpiValueSchema = z2.object({
|
|
213
|
+
field: z2.string().min(1)
|
|
214
|
+
});
|
|
215
|
+
var KpiConfigSchema = z2.object({
|
|
216
|
+
type: z2.literal("kpi"),
|
|
217
|
+
value: KpiValueSchema,
|
|
218
|
+
format: KpiFormatSchema,
|
|
219
|
+
comparison: KpiComparisonSchema.optional()
|
|
220
|
+
});
|
|
221
|
+
var CenterValueSchema = z2.object({
|
|
222
|
+
field: z2.string().optional(),
|
|
223
|
+
// 'total' for sum, or specific field
|
|
224
|
+
label: z2.string().optional(),
|
|
225
|
+
format: z2.string().optional()
|
|
226
|
+
});
|
|
227
|
+
var StandardChartConfigSchema = z2.object({
|
|
228
|
+
type: ChartTypeSchema,
|
|
229
|
+
x: AxisSchema,
|
|
230
|
+
y: AxisSchema.optional(),
|
|
231
|
+
series: SeriesConfigSchema.optional(),
|
|
232
|
+
stacking: z2.enum(["stacked", "percent"]).optional(),
|
|
233
|
+
color: ColorSchema.optional(),
|
|
234
|
+
gradient: GradientSchema.optional(),
|
|
235
|
+
legend: LegendSchema.optional(),
|
|
236
|
+
annotations: z2.array(AnnotationSchema).optional(),
|
|
237
|
+
interactions: InteractionsSchema.optional(),
|
|
238
|
+
centerValue: CenterValueSchema.optional()
|
|
239
|
+
// For donut charts
|
|
240
|
+
});
|
|
241
|
+
var DualAxesSchema = z2.object({
|
|
242
|
+
left: AxisSchema.optional(),
|
|
243
|
+
right: AxisSchema.optional()
|
|
244
|
+
});
|
|
245
|
+
var ComboChartConfigSchema = z2.object({
|
|
246
|
+
type: z2.literal("combo"),
|
|
247
|
+
x: AxisSchema,
|
|
248
|
+
series: WideFormatSeriesSchema,
|
|
249
|
+
axes: DualAxesSchema,
|
|
250
|
+
legend: LegendSchema.optional(),
|
|
251
|
+
interactions: InteractionsSchema.optional(),
|
|
252
|
+
gradient: GradientSchema.optional()
|
|
253
|
+
});
|
|
254
|
+
var ScatterSizeSchema = z2.object({
|
|
255
|
+
field: z2.string().min(1),
|
|
256
|
+
min: z2.number().optional(),
|
|
257
|
+
max: z2.number().optional(),
|
|
258
|
+
label: z2.string().optional()
|
|
259
|
+
});
|
|
260
|
+
var ScatterGroupSchema = z2.object({
|
|
261
|
+
field: z2.string().min(1)
|
|
262
|
+
});
|
|
263
|
+
var RegressionSchema = z2.object({
|
|
264
|
+
type: z2.literal("linear"),
|
|
265
|
+
show_equation: z2.boolean().optional(),
|
|
266
|
+
show_r_squared: z2.boolean().optional()
|
|
267
|
+
});
|
|
268
|
+
var ScatterChartConfigSchema = z2.object({
|
|
269
|
+
type: z2.literal("scatter"),
|
|
270
|
+
x: AxisSchema,
|
|
271
|
+
y: AxisSchema,
|
|
272
|
+
size: ScatterSizeSchema.optional(),
|
|
273
|
+
group: ScatterGroupSchema.optional(),
|
|
274
|
+
regression: RegressionSchema.optional(),
|
|
275
|
+
color: ColorSchema.optional(),
|
|
276
|
+
legend: LegendSchema.optional(),
|
|
277
|
+
interactions: InteractionsSchema.optional()
|
|
278
|
+
});
|
|
279
|
+
var HeatmapChartConfigSchema = z2.object({
|
|
280
|
+
type: z2.literal("heatmap"),
|
|
281
|
+
x: AxisSchema,
|
|
282
|
+
y: AxisSchema,
|
|
283
|
+
value: z2.object({
|
|
284
|
+
field: z2.string().min(1),
|
|
285
|
+
label: z2.string().optional()
|
|
286
|
+
}),
|
|
287
|
+
color_range: z2.object({
|
|
288
|
+
min: z2.string().optional(),
|
|
289
|
+
max: z2.string().optional()
|
|
290
|
+
}).optional(),
|
|
291
|
+
show_values: z2.boolean().optional()
|
|
292
|
+
});
|
|
293
|
+
var FunnelChartConfigSchema = z2.object({
|
|
294
|
+
type: z2.literal("funnel"),
|
|
295
|
+
stage: z2.object({ field: z2.string().min(1) }),
|
|
296
|
+
value: z2.object({ field: z2.string().min(1) }),
|
|
297
|
+
show_conversion: z2.boolean().optional(),
|
|
298
|
+
color: ColorSchema.optional()
|
|
299
|
+
});
|
|
300
|
+
var WaterfallChartConfigSchema = z2.object({
|
|
301
|
+
type: z2.literal("waterfall"),
|
|
302
|
+
category: z2.object({ field: z2.string().min(1) }),
|
|
303
|
+
value: z2.object({ field: z2.string().min(1) }),
|
|
304
|
+
total_field: z2.string().optional(),
|
|
305
|
+
colors: z2.object({
|
|
306
|
+
increase: z2.string().optional(),
|
|
307
|
+
decrease: z2.string().optional(),
|
|
308
|
+
total: z2.string().optional()
|
|
309
|
+
}).optional()
|
|
310
|
+
});
|
|
311
|
+
var GaugeThresholdSchema = z2.object({
|
|
312
|
+
value: z2.number(),
|
|
313
|
+
color: z2.string()
|
|
314
|
+
});
|
|
315
|
+
var GaugeChartConfigSchema = z2.object({
|
|
316
|
+
type: z2.literal("gauge"),
|
|
317
|
+
value: z2.object({ field: z2.string().min(1) }),
|
|
318
|
+
min: z2.number().optional(),
|
|
319
|
+
max: z2.number().optional(),
|
|
320
|
+
thresholds: z2.array(GaugeThresholdSchema).optional(),
|
|
321
|
+
format: z2.string().optional()
|
|
322
|
+
});
|
|
323
|
+
var ChartConfigSchema = z2.union([
|
|
324
|
+
ScatterChartConfigSchema,
|
|
325
|
+
ComboChartConfigSchema,
|
|
326
|
+
HeatmapChartConfigSchema,
|
|
327
|
+
FunnelChartConfigSchema,
|
|
328
|
+
WaterfallChartConfigSchema,
|
|
329
|
+
GaugeChartConfigSchema,
|
|
330
|
+
StandardChartConfigSchema,
|
|
331
|
+
KpiConfigSchema
|
|
332
|
+
]);
|
|
333
|
+
var ParameterTypeSchema = z2.enum([
|
|
334
|
+
"date_range",
|
|
335
|
+
"select",
|
|
336
|
+
"multi_select",
|
|
337
|
+
"dynamic_select",
|
|
338
|
+
"text",
|
|
339
|
+
"number"
|
|
340
|
+
]);
|
|
341
|
+
var ParameterOptionSchema = z2.union([
|
|
342
|
+
z2.string(),
|
|
343
|
+
z2.object({
|
|
344
|
+
value: z2.string(),
|
|
345
|
+
label: z2.string()
|
|
346
|
+
})
|
|
347
|
+
]);
|
|
348
|
+
var ParameterSourceSchema = z2.object({
|
|
349
|
+
model: z2.string(),
|
|
350
|
+
value_field: z2.string(),
|
|
351
|
+
label_field: z2.string()
|
|
352
|
+
});
|
|
353
|
+
var ParameterSchema = z2.object({
|
|
354
|
+
name: z2.string().min(1),
|
|
355
|
+
type: ParameterTypeSchema,
|
|
356
|
+
label: z2.string().optional(),
|
|
357
|
+
default: z2.union([z2.string(), z2.number(), z2.array(z2.string())]).optional(),
|
|
358
|
+
options: z2.array(ParameterOptionSchema).optional(),
|
|
359
|
+
source: ParameterSourceSchema.optional()
|
|
360
|
+
});
|
|
361
|
+
var SourceSchema = z2.object({
|
|
362
|
+
model: z2.string().optional(),
|
|
363
|
+
sql: z2.string().optional()
|
|
364
|
+
}).refine((data) => data.model !== void 0 || data.sql !== void 0, { message: "Source must specify either model or sql" }).refine((data) => !(data.model !== void 0 && data.sql !== void 0), { message: "Source cannot specify both model and sql" });
|
|
365
|
+
var RefreshSchema = z2.object({
|
|
366
|
+
schedule: z2.string().optional(),
|
|
367
|
+
// cron expression
|
|
368
|
+
timezone: z2.string().optional(),
|
|
369
|
+
cache_ttl: z2.string().optional()
|
|
370
|
+
// e.g., "1h", "30m"
|
|
371
|
+
});
|
|
372
|
+
var DrillDownColumnSchema = z2.object({
|
|
373
|
+
field: z2.string().min(1),
|
|
374
|
+
label: z2.string().optional(),
|
|
375
|
+
format: z2.string().optional()
|
|
376
|
+
});
|
|
377
|
+
var DrillDownConfigSchema = z2.object({
|
|
378
|
+
chart: z2.string().optional(),
|
|
379
|
+
// target chart name (source side)
|
|
380
|
+
field: z2.string().optional(),
|
|
381
|
+
// field to pass as filter, defaults to x-axis field
|
|
382
|
+
columns: z2.array(DrillDownColumnSchema).optional()
|
|
383
|
+
// data table columns (target side)
|
|
384
|
+
});
|
|
385
|
+
var ChartSchema = z2.object({
|
|
386
|
+
// Identity
|
|
387
|
+
name: z2.string().min(1),
|
|
388
|
+
title: z2.string().min(1),
|
|
389
|
+
description: z2.string().optional(),
|
|
390
|
+
// Metadata
|
|
391
|
+
owner: z2.string().optional(),
|
|
392
|
+
tags: z2.array(z2.string()).optional(),
|
|
393
|
+
created: z2.string().optional(),
|
|
394
|
+
updated: z2.string().optional(),
|
|
395
|
+
// Data
|
|
396
|
+
source: SourceSchema,
|
|
397
|
+
parameters: z2.array(ParameterSchema).optional(),
|
|
398
|
+
// Visualization
|
|
399
|
+
chart: ChartConfigSchema,
|
|
400
|
+
// Caching
|
|
401
|
+
refresh: RefreshSchema.optional(),
|
|
402
|
+
// Drill-down navigation
|
|
403
|
+
drillDown: DrillDownConfigSchema.optional()
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// ../../packages/schema/dist/project.js
|
|
407
|
+
import { z as z3 } from "zod";
|
|
408
|
+
var DefaultsSchema = z3.object({
|
|
409
|
+
connection: z3.string().optional(),
|
|
410
|
+
theme: z3.string().optional(),
|
|
411
|
+
timezone: z3.string().optional(),
|
|
412
|
+
cache_ttl: z3.string().optional(),
|
|
413
|
+
base_url: z3.string().url().optional()
|
|
414
|
+
});
|
|
415
|
+
var EnvironmentSchema = z3.object({
|
|
416
|
+
connection: z3.string().optional(),
|
|
417
|
+
base_url: z3.string().url().optional()
|
|
418
|
+
});
|
|
419
|
+
var GitSchema = z3.object({
|
|
420
|
+
provider: z3.enum(["github", "gitlab", "bitbucket"]).optional(),
|
|
421
|
+
repo: z3.string().optional(),
|
|
422
|
+
branch: z3.string().optional(),
|
|
423
|
+
preview_branches: z3.boolean().optional()
|
|
424
|
+
});
|
|
425
|
+
var SSOProviderSchema = z3.object({
|
|
426
|
+
client_id: z3.string(),
|
|
427
|
+
client_secret: z3.string(),
|
|
428
|
+
tenant: z3.string().optional(),
|
|
429
|
+
issuer: z3.string().optional(),
|
|
430
|
+
display_name: z3.string().optional()
|
|
431
|
+
});
|
|
432
|
+
var AuthSchema2 = z3.object({
|
|
433
|
+
enabled: z3.boolean(),
|
|
434
|
+
db_path: z3.string().optional(),
|
|
435
|
+
session_ttl: z3.string().optional(),
|
|
436
|
+
providers: z3.object({
|
|
437
|
+
google: SSOProviderSchema.optional(),
|
|
438
|
+
microsoft: SSOProviderSchema.optional(),
|
|
439
|
+
oidc: SSOProviderSchema.optional()
|
|
440
|
+
}).optional()
|
|
441
|
+
});
|
|
442
|
+
var FeaturesSchema = z3.object({
|
|
443
|
+
enable_sql_editor: z3.boolean().optional(),
|
|
444
|
+
enable_csv_export: z3.boolean().optional(),
|
|
445
|
+
enable_scheduling: z3.boolean().optional()
|
|
446
|
+
});
|
|
447
|
+
var ThemeSchema = z3.object({
|
|
448
|
+
palette: z3.array(z3.string()).optional(),
|
|
449
|
+
gradient: z3.boolean().default(false),
|
|
450
|
+
opacity: z3.number().min(0).max(1).default(1)
|
|
451
|
+
});
|
|
452
|
+
var ProjectSchema = z3.object({
|
|
453
|
+
version: z3.string().min(1),
|
|
454
|
+
name: z3.string().min(1),
|
|
455
|
+
description: z3.string().optional(),
|
|
456
|
+
defaults: DefaultsSchema.optional(),
|
|
457
|
+
environments: z3.record(z3.string(), EnvironmentSchema).optional(),
|
|
458
|
+
git: GitSchema.optional(),
|
|
459
|
+
auth: AuthSchema2.optional(),
|
|
460
|
+
features: FeaturesSchema.optional(),
|
|
461
|
+
theme: ThemeSchema.optional()
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// ../../packages/schema/dist/model.js
|
|
465
|
+
import { z as z4 } from "zod";
|
|
466
|
+
var ParamTypeSchema = z4.enum(["string", "number", "date", "boolean", "string[]", "number[]"]);
|
|
467
|
+
var ModelParamSchema = z4.object({
|
|
468
|
+
name: z4.string().min(1),
|
|
469
|
+
type: ParamTypeSchema,
|
|
470
|
+
default: z4.string().optional(),
|
|
471
|
+
options: z4.array(z4.string()).optional(),
|
|
472
|
+
// For enum-like params
|
|
473
|
+
description: z4.string().optional()
|
|
474
|
+
});
|
|
475
|
+
var ReturnColumnSchema = z4.object({
|
|
476
|
+
name: z4.string().min(1),
|
|
477
|
+
type: z4.string(),
|
|
478
|
+
description: z4.string().optional()
|
|
479
|
+
});
|
|
480
|
+
var ModelMetadataSchema = z4.object({
|
|
481
|
+
name: z4.string().min(1),
|
|
482
|
+
description: z4.string().optional(),
|
|
483
|
+
owner: z4.string().optional(),
|
|
484
|
+
tags: z4.array(z4.string()).optional(),
|
|
485
|
+
params: z4.array(ModelParamSchema).optional(),
|
|
486
|
+
returns: z4.array(ReturnColumnSchema).optional(),
|
|
487
|
+
tests: z4.array(z4.string()).optional()
|
|
488
|
+
// SQL assertions
|
|
489
|
+
});
|
|
490
|
+
var ModelSchema = z4.object({
|
|
491
|
+
metadata: ModelMetadataSchema,
|
|
492
|
+
sql: z4.string().min(1),
|
|
493
|
+
filePath: z4.string().optional()
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
// ../../packages/schema/dist/dashboard.js
|
|
497
|
+
import { z as z5 } from "zod";
|
|
498
|
+
var ChartWidgetSchema = z5.object({
|
|
499
|
+
type: z5.literal("chart"),
|
|
500
|
+
ref: z5.string().min(1),
|
|
501
|
+
cols: z5.number().min(1).max(12)
|
|
502
|
+
});
|
|
503
|
+
var TextWidgetSchema = z5.object({
|
|
504
|
+
type: z5.literal("text"),
|
|
505
|
+
content: z5.string().min(1),
|
|
506
|
+
cols: z5.number().min(1).max(12)
|
|
507
|
+
});
|
|
508
|
+
var WidgetSchema = z5.discriminatedUnion("type", [
|
|
509
|
+
ChartWidgetSchema,
|
|
510
|
+
TextWidgetSchema
|
|
511
|
+
]);
|
|
512
|
+
var RowSchema = z5.object({
|
|
513
|
+
height: z5.number().min(50),
|
|
514
|
+
widgets: z5.array(WidgetSchema).min(1)
|
|
515
|
+
});
|
|
516
|
+
var LayoutSchema = z5.object({
|
|
517
|
+
gap: z5.number().min(0).default(16),
|
|
518
|
+
rows: z5.array(RowSchema).min(1)
|
|
519
|
+
});
|
|
520
|
+
var DashboardSchema = z5.object({
|
|
521
|
+
// Identity
|
|
522
|
+
name: z5.string().min(1),
|
|
523
|
+
title: z5.string().min(1),
|
|
524
|
+
description: z5.string().optional(),
|
|
525
|
+
// Filters inherited by all widgets
|
|
526
|
+
filters: z5.array(ParameterSchema).optional(),
|
|
527
|
+
// Layout definition
|
|
528
|
+
layout: LayoutSchema
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// ../../packages/schema/dist/schedule.js
|
|
532
|
+
import { z as z6 } from "zod";
|
|
533
|
+
var SlackChannelSchema = z6.object({
|
|
534
|
+
webhook_url: z6.string().min(1),
|
|
535
|
+
channel: z6.string().optional()
|
|
536
|
+
});
|
|
537
|
+
var ChannelSchema = z6.object({
|
|
538
|
+
slack: SlackChannelSchema
|
|
539
|
+
});
|
|
540
|
+
var ConditionOperatorSchema = z6.enum(["lt", "gt", "lte", "gte", "eq"]);
|
|
541
|
+
var ConditionSchema = z6.object({
|
|
542
|
+
field: z6.string().min(1),
|
|
543
|
+
operator: ConditionOperatorSchema,
|
|
544
|
+
value: z6.number()
|
|
545
|
+
});
|
|
546
|
+
var ReportScheduleSchema = z6.object({
|
|
547
|
+
name: z6.string().min(1),
|
|
548
|
+
type: z6.literal("report"),
|
|
549
|
+
schedule: z6.string().min(1),
|
|
550
|
+
timezone: z6.string().optional(),
|
|
551
|
+
channel: ChannelSchema,
|
|
552
|
+
charts: z6.array(z6.string().min(1)).min(1),
|
|
553
|
+
params: z6.record(z6.unknown()).optional(),
|
|
554
|
+
message: z6.string().optional(),
|
|
555
|
+
notify_on_error: z6.boolean().optional()
|
|
556
|
+
});
|
|
557
|
+
var AlertScheduleSchema = z6.object({
|
|
558
|
+
name: z6.string().min(1),
|
|
559
|
+
type: z6.literal("alert"),
|
|
560
|
+
schedule: z6.string().min(1),
|
|
561
|
+
timezone: z6.string().optional(),
|
|
562
|
+
channel: ChannelSchema,
|
|
563
|
+
chart: z6.string().min(1),
|
|
564
|
+
params: z6.record(z6.unknown()).optional(),
|
|
565
|
+
condition: ConditionSchema,
|
|
566
|
+
cooldown: z6.string().optional(),
|
|
567
|
+
message: z6.string().optional(),
|
|
568
|
+
notify_on_error: z6.boolean().optional()
|
|
569
|
+
});
|
|
570
|
+
var ScheduleSchema = z6.discriminatedUnion("type", [
|
|
571
|
+
ReportScheduleSchema,
|
|
572
|
+
AlertScheduleSchema
|
|
573
|
+
]);
|
|
574
|
+
|
|
575
|
+
// src/commands/validate.ts
|
|
576
|
+
async function validateProject(projectDir, options) {
|
|
577
|
+
const errors = [];
|
|
578
|
+
const warnings = [];
|
|
579
|
+
let filesChecked = 0;
|
|
580
|
+
let filesPassed = 0;
|
|
581
|
+
const config = {
|
|
582
|
+
project: null,
|
|
583
|
+
connections: /* @__PURE__ */ new Map(),
|
|
584
|
+
models: /* @__PURE__ */ new Map(),
|
|
585
|
+
charts: /* @__PURE__ */ new Map(),
|
|
586
|
+
dashboards: /* @__PURE__ */ new Map(),
|
|
587
|
+
schedules: /* @__PURE__ */ new Map()
|
|
588
|
+
};
|
|
589
|
+
const projectPath = join(projectDir, "yamchart.yaml");
|
|
590
|
+
try {
|
|
591
|
+
await access(projectPath);
|
|
592
|
+
filesChecked++;
|
|
593
|
+
const content = await readFile(projectPath, "utf-8");
|
|
594
|
+
const parsed = parseYaml(content);
|
|
595
|
+
const result = ProjectSchema.safeParse(parsed);
|
|
596
|
+
if (result.success) {
|
|
597
|
+
config.project = result.data;
|
|
598
|
+
filesPassed++;
|
|
599
|
+
} else {
|
|
600
|
+
errors.push({
|
|
601
|
+
file: "yamchart.yaml",
|
|
602
|
+
message: `Invalid schema: ${result.error.errors[0]?.message || "Unknown error"}`
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
} catch {
|
|
606
|
+
errors.push({
|
|
607
|
+
file: "yamchart.yaml",
|
|
608
|
+
message: "yamchart.yaml not found"
|
|
609
|
+
});
|
|
610
|
+
return {
|
|
611
|
+
success: false,
|
|
612
|
+
errors,
|
|
613
|
+
warnings,
|
|
614
|
+
stats: { files: filesChecked, passed: filesPassed, failed: filesChecked - filesPassed }
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const connectionsDir = join(projectDir, "connections");
|
|
618
|
+
try {
|
|
619
|
+
await access(connectionsDir);
|
|
620
|
+
const files = await readdir(connectionsDir);
|
|
621
|
+
for (const file of files) {
|
|
622
|
+
if (extname(file) !== ".yaml" && extname(file) !== ".yml") continue;
|
|
623
|
+
filesChecked++;
|
|
624
|
+
const filePath = join(connectionsDir, file);
|
|
625
|
+
const content = await readFile(filePath, "utf-8");
|
|
626
|
+
const parsed = parseYaml(content);
|
|
627
|
+
const result = ConnectionSchema.safeParse(parsed);
|
|
628
|
+
if (result.success) {
|
|
629
|
+
config.connections.set(result.data.name, result.data);
|
|
630
|
+
filesPassed++;
|
|
631
|
+
} else {
|
|
632
|
+
errors.push({
|
|
633
|
+
file: `connections/${file}`,
|
|
634
|
+
message: `Invalid schema: ${result.error.errors[0]?.message || "Unknown error"}`
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
} catch {
|
|
639
|
+
}
|
|
640
|
+
const modelsDir = join(projectDir, "models");
|
|
641
|
+
const modelStats = { filesChecked: 0, filesPassed: 0 };
|
|
642
|
+
try {
|
|
643
|
+
await access(modelsDir);
|
|
644
|
+
await validateModelsDir(modelsDir, projectDir, config, errors, modelStats);
|
|
645
|
+
filesChecked += modelStats.filesChecked;
|
|
646
|
+
filesPassed += modelStats.filesPassed;
|
|
647
|
+
} catch {
|
|
648
|
+
}
|
|
649
|
+
const chartsDir = join(projectDir, "charts");
|
|
650
|
+
try {
|
|
651
|
+
await access(chartsDir);
|
|
652
|
+
const files = await readdir(chartsDir);
|
|
653
|
+
for (const file of files) {
|
|
654
|
+
if (extname(file) !== ".yaml" && extname(file) !== ".yml") continue;
|
|
655
|
+
filesChecked++;
|
|
656
|
+
const filePath = join(chartsDir, file);
|
|
657
|
+
const content = await readFile(filePath, "utf-8");
|
|
658
|
+
const parsed = parseYaml(content);
|
|
659
|
+
const result = ChartSchema.safeParse(parsed);
|
|
660
|
+
if (result.success) {
|
|
661
|
+
config.charts.set(result.data.name, result.data);
|
|
662
|
+
filesPassed++;
|
|
663
|
+
} else {
|
|
664
|
+
errors.push({
|
|
665
|
+
file: `charts/${file}`,
|
|
666
|
+
message: `Invalid schema: ${result.error.errors[0]?.message || "Unknown error"}`
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
} catch {
|
|
671
|
+
}
|
|
672
|
+
const dashboardsDir = join(projectDir, "dashboards");
|
|
673
|
+
try {
|
|
674
|
+
await access(dashboardsDir);
|
|
675
|
+
const files = await readdir(dashboardsDir);
|
|
676
|
+
for (const file of files) {
|
|
677
|
+
if (extname(file) !== ".yaml" && extname(file) !== ".yml") continue;
|
|
678
|
+
filesChecked++;
|
|
679
|
+
const filePath = join(dashboardsDir, file);
|
|
680
|
+
const content = await readFile(filePath, "utf-8");
|
|
681
|
+
const parsed = parseYaml(content);
|
|
682
|
+
const result = DashboardSchema.safeParse(parsed);
|
|
683
|
+
if (result.success) {
|
|
684
|
+
config.dashboards.set(result.data.name, result.data);
|
|
685
|
+
filesPassed++;
|
|
686
|
+
} else {
|
|
687
|
+
errors.push({
|
|
688
|
+
file: `dashboards/${file}`,
|
|
689
|
+
message: `Invalid schema: ${result.error.errors[0]?.message || "Unknown error"}`
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
} catch {
|
|
694
|
+
}
|
|
695
|
+
const schedulesDir = join(projectDir, "schedules");
|
|
696
|
+
try {
|
|
697
|
+
await access(schedulesDir);
|
|
698
|
+
const files = await readdir(schedulesDir);
|
|
699
|
+
for (const file of files) {
|
|
700
|
+
if (extname(file) !== ".yaml" && extname(file) !== ".yml") continue;
|
|
701
|
+
filesChecked++;
|
|
702
|
+
const filePath = join(schedulesDir, file);
|
|
703
|
+
const content = await readFile(filePath, "utf-8");
|
|
704
|
+
const parsed = parseYaml(content);
|
|
705
|
+
const result = ScheduleSchema.safeParse(parsed);
|
|
706
|
+
if (result.success) {
|
|
707
|
+
config.schedules.set(result.data.name, result.data);
|
|
708
|
+
filesPassed++;
|
|
709
|
+
} else {
|
|
710
|
+
errors.push({
|
|
711
|
+
file: `schedules/${file}`,
|
|
712
|
+
message: `Invalid schema: ${result.error.errors[0]?.message || "Unknown error"}`
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
} catch {
|
|
717
|
+
}
|
|
718
|
+
crossReferenceValidation(config, errors, warnings);
|
|
719
|
+
let dryRunStats;
|
|
720
|
+
if (options.dryRun) {
|
|
721
|
+
dryRunStats = await dryRunValidation(projectDir, config, options.connection, errors);
|
|
722
|
+
}
|
|
723
|
+
return {
|
|
724
|
+
success: errors.length === 0,
|
|
725
|
+
errors,
|
|
726
|
+
warnings,
|
|
727
|
+
stats: {
|
|
728
|
+
files: filesChecked,
|
|
729
|
+
passed: filesPassed,
|
|
730
|
+
failed: filesChecked - filesPassed
|
|
731
|
+
},
|
|
732
|
+
dryRunStats
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
async function validateModelsDir(dir, projectDir, config, errors, stats) {
|
|
736
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
737
|
+
for (const entry of entries) {
|
|
738
|
+
const fullPath = join(dir, entry.name);
|
|
739
|
+
if (entry.isDirectory()) {
|
|
740
|
+
await validateModelsDir(fullPath, projectDir, config, errors, stats);
|
|
741
|
+
} else if (extname(entry.name) === ".sql") {
|
|
742
|
+
stats.filesChecked++;
|
|
743
|
+
const relPath = relative(projectDir, fullPath);
|
|
744
|
+
const content = await readFile(fullPath, "utf-8");
|
|
745
|
+
try {
|
|
746
|
+
const parsed = parseModelMetadata(content);
|
|
747
|
+
config.models.set(parsed.name, { name: parsed.name, sql: parsed.sql });
|
|
748
|
+
stats.filesPassed++;
|
|
749
|
+
} catch (err) {
|
|
750
|
+
errors.push({
|
|
751
|
+
file: relPath,
|
|
752
|
+
message: err instanceof Error ? err.message : "Failed to parse model"
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
function crossReferenceValidation(config, errors, warnings) {
|
|
759
|
+
for (const [chartName, chart] of config.charts) {
|
|
760
|
+
if (chart.source.model && !config.models.has(chart.source.model)) {
|
|
761
|
+
const suggestion = findSimilar(chart.source.model, Array.from(config.models.keys()));
|
|
762
|
+
errors.push({
|
|
763
|
+
file: `charts/${chartName}.yaml`,
|
|
764
|
+
message: `Unknown model reference "${chart.source.model}"`,
|
|
765
|
+
suggestion: suggestion ? `Did you mean "${suggestion}"?` : void 0
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
for (const [scheduleName, schedule] of config.schedules) {
|
|
770
|
+
const chartNames = schedule.type === "report" ? schedule.charts : [schedule.chart];
|
|
771
|
+
for (const chartName of chartNames) {
|
|
772
|
+
if (!config.charts.has(chartName)) {
|
|
773
|
+
const suggestion = findSimilar(chartName, Array.from(config.charts.keys()));
|
|
774
|
+
warnings.push({
|
|
775
|
+
file: `schedules/${scheduleName}.yaml`,
|
|
776
|
+
message: `Unknown chart reference "${chartName}"`,
|
|
777
|
+
suggestion: suggestion ? `Did you mean "${suggestion}"?` : void 0
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
const cronFields = schedule.schedule.trim().split(/\s+/);
|
|
782
|
+
if (cronFields.length < 5 || cronFields.length > 6) {
|
|
783
|
+
errors.push({
|
|
784
|
+
file: `schedules/${scheduleName}.yaml`,
|
|
785
|
+
message: `Invalid cron expression "${schedule.schedule}" (expected 5-6 fields)`
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
if (config.project?.defaults?.connection) {
|
|
790
|
+
const connName = config.project.defaults.connection;
|
|
791
|
+
if (!config.connections.has(connName)) {
|
|
792
|
+
const suggestion = findSimilar(connName, Array.from(config.connections.keys()));
|
|
793
|
+
errors.push({
|
|
794
|
+
file: "yamchart.yaml",
|
|
795
|
+
message: `Default connection "${connName}" not found`,
|
|
796
|
+
suggestion: suggestion ? `Did you mean "${suggestion}"?` : void 0
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
function findSimilar(target, candidates) {
|
|
802
|
+
const threshold = 3;
|
|
803
|
+
for (const candidate of candidates) {
|
|
804
|
+
if (levenshtein(target.toLowerCase(), candidate.toLowerCase()) <= threshold) {
|
|
805
|
+
return candidate;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
function levenshtein(a, b) {
|
|
811
|
+
const matrix = [];
|
|
812
|
+
for (let i = 0; i <= b.length; i++) {
|
|
813
|
+
matrix[i] = [i];
|
|
814
|
+
}
|
|
815
|
+
for (let j = 0; j <= a.length; j++) {
|
|
816
|
+
matrix[0][j] = j;
|
|
817
|
+
}
|
|
818
|
+
for (let i = 1; i <= b.length; i++) {
|
|
819
|
+
for (let j = 1; j <= a.length; j++) {
|
|
820
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
821
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
822
|
+
} else {
|
|
823
|
+
matrix[i][j] = Math.min(
|
|
824
|
+
matrix[i - 1][j - 1] + 1,
|
|
825
|
+
matrix[i][j - 1] + 1,
|
|
826
|
+
matrix[i - 1][j] + 1
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return matrix[b.length][a.length];
|
|
832
|
+
}
|
|
833
|
+
async function dryRunValidation(projectDir, config, connectionName, errors) {
|
|
834
|
+
const { DuckDBConnector } = await import("./dist-JKJLH3F6.js");
|
|
835
|
+
let passed = 0;
|
|
836
|
+
let failed = 0;
|
|
837
|
+
const connName = connectionName || config.project?.defaults?.connection;
|
|
838
|
+
if (!connName) {
|
|
839
|
+
errors.push({
|
|
840
|
+
file: "yamchart.yaml",
|
|
841
|
+
message: "No connection specified for dry-run (use --connection or set defaults.connection)"
|
|
842
|
+
});
|
|
843
|
+
return { passed, failed: 1 };
|
|
844
|
+
}
|
|
845
|
+
const connection = config.connections.get(connName);
|
|
846
|
+
if (!connection) {
|
|
847
|
+
errors.push({
|
|
848
|
+
file: "yamchart.yaml",
|
|
849
|
+
message: `Connection "${connName}" not found`
|
|
850
|
+
});
|
|
851
|
+
return { passed, failed: 1 };
|
|
852
|
+
}
|
|
853
|
+
if (connection.type !== "duckdb") {
|
|
854
|
+
errors.push({
|
|
855
|
+
file: `connections/${connName}.yaml`,
|
|
856
|
+
message: `Dry-run not yet supported for connection type "${connection.type}"`
|
|
857
|
+
});
|
|
858
|
+
return { passed, failed: 1 };
|
|
859
|
+
}
|
|
860
|
+
const connPath = join(projectDir, "connections", `${connName}.yaml`);
|
|
861
|
+
const connContent = await readFile(connPath, "utf-8");
|
|
862
|
+
const connConfig = parseYaml(connContent);
|
|
863
|
+
const dbPath = connConfig.config.path.startsWith("/") ? connConfig.config.path : join(projectDir, connConfig.config.path);
|
|
864
|
+
const connector = new DuckDBConnector({ path: dbPath });
|
|
865
|
+
try {
|
|
866
|
+
await connector.connect();
|
|
867
|
+
for (const [modelName, model] of config.models) {
|
|
868
|
+
const result = await connector.explain(model.sql);
|
|
869
|
+
if (result.valid) {
|
|
870
|
+
passed++;
|
|
871
|
+
} else {
|
|
872
|
+
failed++;
|
|
873
|
+
errors.push({
|
|
874
|
+
file: `models/${modelName}.sql`,
|
|
875
|
+
message: result.error || "Query validation failed"
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
} finally {
|
|
880
|
+
await connector.disconnect();
|
|
881
|
+
}
|
|
882
|
+
return { passed, failed };
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// src/utils/config.ts
|
|
886
|
+
import { access as access2 } from "fs/promises";
|
|
887
|
+
import { join as join2, dirname, resolve } from "path";
|
|
888
|
+
import { config as loadDotenv } from "dotenv";
|
|
889
|
+
async function findProjectRoot(startDir) {
|
|
890
|
+
let currentDir = resolve(startDir);
|
|
891
|
+
const root = dirname(currentDir);
|
|
892
|
+
while (currentDir !== root) {
|
|
893
|
+
const configPath = join2(currentDir, "yamchart.yaml");
|
|
894
|
+
try {
|
|
895
|
+
await access2(configPath);
|
|
896
|
+
return currentDir;
|
|
897
|
+
} catch {
|
|
898
|
+
currentDir = dirname(currentDir);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
try {
|
|
902
|
+
await access2(join2(root, "yamchart.yaml"));
|
|
903
|
+
return root;
|
|
904
|
+
} catch {
|
|
905
|
+
return null;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
function loadEnvFile(projectDir) {
|
|
909
|
+
loadDotenv({ path: join2(projectDir, ".env") });
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
export {
|
|
913
|
+
ConnectionSchema,
|
|
914
|
+
ChartSchema,
|
|
915
|
+
ProjectSchema,
|
|
916
|
+
DashboardSchema,
|
|
917
|
+
ScheduleSchema,
|
|
918
|
+
validateProject,
|
|
919
|
+
findProjectRoot,
|
|
920
|
+
loadEnvFile
|
|
921
|
+
};
|
|
922
|
+
//# sourceMappingURL=chunk-A24KVXJQ.js.map
|