@duckcodeailabs/dql-core 0.1.4 → 0.3.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.
Files changed (42) hide show
  1. package/LICENSE +123 -0
  2. package/dist/semantic/index.d.ts +5 -0
  3. package/dist/semantic/index.d.ts.map +1 -1
  4. package/dist/semantic/index.js +3 -0
  5. package/dist/semantic/index.js.map +1 -1
  6. package/dist/semantic/providers/cubejs-provider.d.ts +11 -0
  7. package/dist/semantic/providers/cubejs-provider.d.ts.map +1 -0
  8. package/dist/semantic/providers/cubejs-provider.js +190 -0
  9. package/dist/semantic/providers/cubejs-provider.js.map +1 -0
  10. package/dist/semantic/providers/dbt-provider.d.ts +12 -0
  11. package/dist/semantic/providers/dbt-provider.d.ts.map +1 -0
  12. package/dist/semantic/providers/dbt-provider.js +233 -0
  13. package/dist/semantic/providers/dbt-provider.js.map +1 -0
  14. package/dist/semantic/providers/dql-provider.d.ts +11 -0
  15. package/dist/semantic/providers/dql-provider.d.ts.map +1 -0
  16. package/dist/semantic/providers/dql-provider.js +16 -0
  17. package/dist/semantic/providers/dql-provider.js.map +1 -0
  18. package/dist/semantic/providers/index.d.ts +3 -0
  19. package/dist/semantic/providers/index.d.ts.map +1 -0
  20. package/dist/semantic/providers/index.js +2 -0
  21. package/dist/semantic/providers/index.js.map +1 -0
  22. package/dist/semantic/providers/provider.d.ts +14 -0
  23. package/dist/semantic/providers/provider.d.ts.map +1 -0
  24. package/dist/semantic/providers/provider.js +2 -0
  25. package/dist/semantic/providers/provider.js.map +1 -0
  26. package/dist/semantic/providers/registry.d.ts +15 -0
  27. package/dist/semantic/providers/registry.d.ts.map +1 -0
  28. package/dist/semantic/providers/registry.js +51 -0
  29. package/dist/semantic/providers/registry.js.map +1 -0
  30. package/dist/semantic/semantic-layer.d.ts +5 -0
  31. package/dist/semantic/semantic-layer.d.ts.map +1 -1
  32. package/dist/semantic/semantic-layer.js +8 -14
  33. package/dist/semantic/semantic-layer.js.map +1 -1
  34. package/dist/semantic/sql-dialect.d.ts +37 -0
  35. package/dist/semantic/sql-dialect.d.ts.map +1 -0
  36. package/dist/semantic/sql-dialect.js +350 -0
  37. package/dist/semantic/sql-dialect.js.map +1 -0
  38. package/dist/semantic/yaml-loader.d.ts +26 -0
  39. package/dist/semantic/yaml-loader.d.ts.map +1 -0
  40. package/dist/semantic/yaml-loader.js +80 -0
  41. package/dist/semantic/yaml-loader.js.map +1 -0
  42. package/package.json +14 -11
@@ -0,0 +1,350 @@
1
+ /**
2
+ * SQL Dialect abstraction for cross-database semantic query generation.
3
+ *
4
+ * Each database has different syntax for date truncation, identifier quoting,
5
+ * type casting, etc. This module provides a uniform interface so that
6
+ * SemanticLayer.composeQuery() generates portable SQL.
7
+ */
8
+ // ── PostgreSQL / Redshift ────────────────────────────────────────────────────
9
+ class PostgreSQLDialect {
10
+ name = 'postgresql';
11
+ limitAtEnd = true;
12
+ dateTrunc(granularity, columnSql) {
13
+ return `DATE_TRUNC('${granularity}', ${columnSql})`;
14
+ }
15
+ quoteIdentifier(name) {
16
+ return `"${name.replace(/"/g, '""')}"`;
17
+ }
18
+ currentTimestamp() {
19
+ return 'CURRENT_TIMESTAMP';
20
+ }
21
+ castToDate(expr) {
22
+ return `(${expr})::DATE`;
23
+ }
24
+ limitClause(n) {
25
+ return `LIMIT ${n}`;
26
+ }
27
+ concat(a, b) {
28
+ return `${a} || ${b}`;
29
+ }
30
+ ilike(column, pattern) {
31
+ return `${column} ILIKE ${pattern}`;
32
+ }
33
+ }
34
+ // ── DuckDB / File ────────────────────────────────────────────────────────────
35
+ class DuckDBDialect {
36
+ name = 'duckdb';
37
+ limitAtEnd = true;
38
+ dateTrunc(granularity, columnSql) {
39
+ return `DATE_TRUNC('${granularity}', ${columnSql})`;
40
+ }
41
+ quoteIdentifier(name) {
42
+ return `"${name.replace(/"/g, '""')}"`;
43
+ }
44
+ currentTimestamp() {
45
+ return 'CURRENT_TIMESTAMP';
46
+ }
47
+ castToDate(expr) {
48
+ return `CAST(${expr} AS DATE)`;
49
+ }
50
+ limitClause(n) {
51
+ return `LIMIT ${n}`;
52
+ }
53
+ concat(a, b) {
54
+ return `${a} || ${b}`;
55
+ }
56
+ ilike(column, pattern) {
57
+ return `${column} ILIKE ${pattern}`;
58
+ }
59
+ }
60
+ // ── Snowflake ────────────────────────────────────────────────────────────────
61
+ class SnowflakeDialect {
62
+ name = 'snowflake';
63
+ limitAtEnd = true;
64
+ dateTrunc(granularity, columnSql) {
65
+ return `DATE_TRUNC('${granularity}', ${columnSql})`;
66
+ }
67
+ quoteIdentifier(name) {
68
+ return `"${name.replace(/"/g, '""')}"`;
69
+ }
70
+ currentTimestamp() {
71
+ return 'CURRENT_TIMESTAMP()';
72
+ }
73
+ castToDate(expr) {
74
+ return `TO_DATE(${expr})`;
75
+ }
76
+ limitClause(n) {
77
+ return `LIMIT ${n}`;
78
+ }
79
+ concat(a, b) {
80
+ return `${a} || ${b}`;
81
+ }
82
+ ilike(column, pattern) {
83
+ return `${column} ILIKE ${pattern}`;
84
+ }
85
+ }
86
+ // ── BigQuery ─────────────────────────────────────────────────────────────────
87
+ class BigQueryDialect {
88
+ name = 'bigquery';
89
+ limitAtEnd = true;
90
+ dateTrunc(granularity, columnSql) {
91
+ // BigQuery: DATE_TRUNC(column, MONTH) — note reversed arg order, granularity is keyword not string
92
+ const grain = granularity.toUpperCase();
93
+ return `DATE_TRUNC(${columnSql}, ${grain})`;
94
+ }
95
+ quoteIdentifier(name) {
96
+ return `\`${name.replace(/`/g, '\\`')}\``;
97
+ }
98
+ currentTimestamp() {
99
+ return 'CURRENT_TIMESTAMP()';
100
+ }
101
+ castToDate(expr) {
102
+ return `DATE(${expr})`;
103
+ }
104
+ limitClause(n) {
105
+ return `LIMIT ${n}`;
106
+ }
107
+ concat(a, b) {
108
+ return `CONCAT(${a}, ${b})`;
109
+ }
110
+ ilike(column, pattern) {
111
+ return `LOWER(${column}) LIKE LOWER(${pattern})`;
112
+ }
113
+ }
114
+ // ── MySQL ────────────────────────────────────────────────────────────────────
115
+ class MySQLDialect {
116
+ name = 'mysql';
117
+ limitAtEnd = true;
118
+ dateTrunc(granularity, columnSql) {
119
+ // MySQL doesn't have DATE_TRUNC — use DATE_FORMAT or equivalent
120
+ switch (granularity) {
121
+ case 'day':
122
+ return `DATE(${columnSql})`;
123
+ case 'week':
124
+ return `DATE(DATE_SUB(${columnSql}, INTERVAL WEEKDAY(${columnSql}) DAY))`;
125
+ case 'month':
126
+ return `DATE_FORMAT(${columnSql}, '%Y-%m-01')`;
127
+ case 'quarter':
128
+ return `MAKEDATE(YEAR(${columnSql}), 1) + INTERVAL (QUARTER(${columnSql}) - 1) QUARTER`;
129
+ case 'year':
130
+ return `DATE_FORMAT(${columnSql}, '%Y-01-01')`;
131
+ default:
132
+ return `DATE(${columnSql})`;
133
+ }
134
+ }
135
+ quoteIdentifier(name) {
136
+ return `\`${name.replace(/`/g, '``')}\``;
137
+ }
138
+ currentTimestamp() {
139
+ return 'NOW()';
140
+ }
141
+ castToDate(expr) {
142
+ return `DATE(${expr})`;
143
+ }
144
+ limitClause(n) {
145
+ return `LIMIT ${n}`;
146
+ }
147
+ concat(a, b) {
148
+ return `CONCAT(${a}, ${b})`;
149
+ }
150
+ ilike(column, pattern) {
151
+ // MySQL LIKE is case-insensitive by default with utf8 collation
152
+ return `${column} LIKE ${pattern}`;
153
+ }
154
+ }
155
+ // ── SQLite ───────────────────────────────────────────────────────────────────
156
+ class SQLiteDialect {
157
+ name = 'sqlite';
158
+ limitAtEnd = true;
159
+ dateTrunc(granularity, columnSql) {
160
+ switch (granularity) {
161
+ case 'day':
162
+ return `DATE(${columnSql})`;
163
+ case 'week':
164
+ return `DATE(${columnSql}, 'weekday 0', '-6 days')`;
165
+ case 'month':
166
+ return `STRFTIME('%Y-%m-01', ${columnSql})`;
167
+ case 'quarter':
168
+ return `STRFTIME('%Y-', ${columnSql}) || CASE ((CAST(STRFTIME('%m', ${columnSql}) AS INTEGER) - 1) / 3) WHEN 0 THEN '01-01' WHEN 1 THEN '04-01' WHEN 2 THEN '07-01' ELSE '10-01' END`;
169
+ case 'year':
170
+ return `STRFTIME('%Y-01-01', ${columnSql})`;
171
+ default:
172
+ return `DATE(${columnSql})`;
173
+ }
174
+ }
175
+ quoteIdentifier(name) {
176
+ return `"${name.replace(/"/g, '""')}"`;
177
+ }
178
+ currentTimestamp() {
179
+ return "DATETIME('now')";
180
+ }
181
+ castToDate(expr) {
182
+ return `DATE(${expr})`;
183
+ }
184
+ limitClause(n) {
185
+ return `LIMIT ${n}`;
186
+ }
187
+ concat(a, b) {
188
+ return `${a} || ${b}`;
189
+ }
190
+ ilike(column, pattern) {
191
+ return `${column} LIKE ${pattern}`;
192
+ }
193
+ }
194
+ // ── MSSQL / Fabric ───────────────────────────────────────────────────────────
195
+ class MSSQLDialect {
196
+ name = 'mssql';
197
+ limitAtEnd = false;
198
+ dateTrunc(granularity, columnSql) {
199
+ // SQL Server 2022+ supports DATETRUNC, older versions need DATEADD/DATEDIFF
200
+ // Using DATETRUNC for modern compat (Azure SQL, Fabric always support it)
201
+ const grain = granularity.toLowerCase();
202
+ return `DATETRUNC(${grain}, ${columnSql})`;
203
+ }
204
+ quoteIdentifier(name) {
205
+ return `[${name.replace(/\]/g, ']]')}]`;
206
+ }
207
+ currentTimestamp() {
208
+ return 'GETDATE()';
209
+ }
210
+ castToDate(expr) {
211
+ return `CAST(${expr} AS DATE)`;
212
+ }
213
+ limitClause(n) {
214
+ // MSSQL uses TOP N in SELECT, but for composed queries OFFSET/FETCH is cleaner
215
+ return `OFFSET 0 ROWS FETCH NEXT ${n} ROWS ONLY`;
216
+ }
217
+ concat(a, b) {
218
+ return `CONCAT(${a}, ${b})`;
219
+ }
220
+ ilike(column, pattern) {
221
+ // MSSQL LIKE is case-insensitive by default
222
+ return `${column} LIKE ${pattern}`;
223
+ }
224
+ }
225
+ // ── ClickHouse ───────────────────────────────────────────────────────────────
226
+ class ClickHouseDialect {
227
+ name = 'clickhouse';
228
+ limitAtEnd = true;
229
+ dateTrunc(granularity, columnSql) {
230
+ switch (granularity) {
231
+ case 'day':
232
+ return `toDate(${columnSql})`;
233
+ case 'week':
234
+ return `toMonday(${columnSql})`;
235
+ case 'month':
236
+ return `toStartOfMonth(${columnSql})`;
237
+ case 'quarter':
238
+ return `toStartOfQuarter(${columnSql})`;
239
+ case 'year':
240
+ return `toStartOfYear(${columnSql})`;
241
+ default:
242
+ return `toDate(${columnSql})`;
243
+ }
244
+ }
245
+ quoteIdentifier(name) {
246
+ return `"${name.replace(/"/g, '""')}"`;
247
+ }
248
+ currentTimestamp() {
249
+ return 'now()';
250
+ }
251
+ castToDate(expr) {
252
+ return `toDate(${expr})`;
253
+ }
254
+ limitClause(n) {
255
+ return `LIMIT ${n}`;
256
+ }
257
+ concat(a, b) {
258
+ return `concat(${a}, ${b})`;
259
+ }
260
+ ilike(column, pattern) {
261
+ return `${column} ILIKE ${pattern}`;
262
+ }
263
+ }
264
+ // ── Databricks ───────────────────────────────────────────────────────────────
265
+ class DatabricksDialect {
266
+ name = 'databricks';
267
+ limitAtEnd = true;
268
+ dateTrunc(granularity, columnSql) {
269
+ return `DATE_TRUNC('${granularity}', ${columnSql})`;
270
+ }
271
+ quoteIdentifier(name) {
272
+ return `\`${name.replace(/`/g, '``')}\``;
273
+ }
274
+ currentTimestamp() {
275
+ return 'CURRENT_TIMESTAMP()';
276
+ }
277
+ castToDate(expr) {
278
+ return `CAST(${expr} AS DATE)`;
279
+ }
280
+ limitClause(n) {
281
+ return `LIMIT ${n}`;
282
+ }
283
+ concat(a, b) {
284
+ return `CONCAT(${a}, ${b})`;
285
+ }
286
+ ilike(column, pattern) {
287
+ return `${column} ILIKE ${pattern}`;
288
+ }
289
+ }
290
+ // ── Trino / Athena (Presto family) ───────────────────────────────────────────
291
+ class TrinoDialect {
292
+ name = 'trino';
293
+ limitAtEnd = true;
294
+ dateTrunc(granularity, columnSql) {
295
+ return `DATE_TRUNC('${granularity}', ${columnSql})`;
296
+ }
297
+ quoteIdentifier(name) {
298
+ return `"${name.replace(/"/g, '""')}"`;
299
+ }
300
+ currentTimestamp() {
301
+ return 'CURRENT_TIMESTAMP';
302
+ }
303
+ castToDate(expr) {
304
+ return `CAST(${expr} AS DATE)`;
305
+ }
306
+ limitClause(n) {
307
+ return `LIMIT ${n}`;
308
+ }
309
+ concat(a, b) {
310
+ return `${a} || ${b}`;
311
+ }
312
+ ilike(column, pattern) {
313
+ return `LOWER(${column}) LIKE LOWER(${pattern})`;
314
+ }
315
+ }
316
+ // ── Dialect Registry ─────────────────────────────────────────────────────────
317
+ const DIALECT_MAP = {
318
+ postgresql: new PostgreSQLDialect(),
319
+ redshift: new PostgreSQLDialect(),
320
+ duckdb: new DuckDBDialect(),
321
+ file: new DuckDBDialect(),
322
+ snowflake: new SnowflakeDialect(),
323
+ bigquery: new BigQueryDialect(),
324
+ mysql: new MySQLDialect(),
325
+ sqlite: new SQLiteDialect(),
326
+ mssql: new MSSQLDialect(),
327
+ fabric: new MSSQLDialect(),
328
+ clickhouse: new ClickHouseDialect(),
329
+ databricks: new DatabricksDialect(),
330
+ trino: new TrinoDialect(),
331
+ athena: new TrinoDialect(),
332
+ };
333
+ /** Default dialect (DuckDB) used when no driver is specified. */
334
+ const DEFAULT_DIALECT = DIALECT_MAP['duckdb'];
335
+ /**
336
+ * Get the SQL dialect for a given driver name.
337
+ * Falls back to DuckDB dialect if the driver is unknown.
338
+ */
339
+ export function getDialect(driver) {
340
+ if (!driver)
341
+ return DEFAULT_DIALECT;
342
+ return DIALECT_MAP[driver] ?? DEFAULT_DIALECT;
343
+ }
344
+ /**
345
+ * List all supported dialect driver names.
346
+ */
347
+ export function listDialectDrivers() {
348
+ return Object.keys(DIALECT_MAP);
349
+ }
350
+ //# sourceMappingURL=sql-dialect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql-dialect.js","sourceRoot":"","sources":["../../src/semantic/sql-dialect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * YAML-based semantic layer loader.
3
+ * Reads metric, dimension, hierarchy, cube, and block-companion YAML files
4
+ * from a project's semantic-layer/ directory and returns a populated SemanticLayer.
5
+ */
6
+ import { SemanticLayer } from './semantic-layer.js';
7
+ /**
8
+ * Load a SemanticLayer from a directory on disk.
9
+ * Expected structure:
10
+ * semanticLayerDir/
11
+ * metrics/ → *.yaml metric definitions
12
+ * dimensions/ → *.yaml dimension definitions
13
+ * hierarchies/ → *.yaml hierarchy definitions
14
+ * cubes/ → *.yaml cube definitions
15
+ * blocks/ → *.yaml block companion definitions (metadata only, not loaded into layer)
16
+ */
17
+ export declare function loadSemanticLayerFromDir(semanticLayerDir: string): SemanticLayer;
18
+ /**
19
+ * Load a SemanticLayer from pre-read file contents (no filesystem access needed).
20
+ * Useful for browser contexts or when files are already loaded.
21
+ */
22
+ export declare function loadSemanticLayerFromConfig(files: Array<{
23
+ path: string;
24
+ content: string;
25
+ }>): SemanticLayer;
26
+ //# sourceMappingURL=yaml-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-loader.d.ts","sourceRoot":"","sources":["../../src/semantic/yaml-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,aAAa,EAKd,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,gBAAgB,EAAE,MAAM,GAAG,aAAa,CA4BhF;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9C,aAAa,CAwBf"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * YAML-based semantic layer loader.
3
+ * Reads metric, dimension, hierarchy, cube, and block-companion YAML files
4
+ * from a project's semantic-layer/ directory and returns a populated SemanticLayer.
5
+ */
6
+ import { readFileSync, readdirSync, existsSync } from 'node:fs';
7
+ import { join, extname } from 'node:path';
8
+ import * as yaml from 'js-yaml';
9
+ import { SemanticLayer, parseMetricDefinition, parseDimensionDefinition, parseHierarchyDefinition, parseCubeDefinition, } from './semantic-layer.js';
10
+ /**
11
+ * Load a SemanticLayer from a directory on disk.
12
+ * Expected structure:
13
+ * semanticLayerDir/
14
+ * metrics/ → *.yaml metric definitions
15
+ * dimensions/ → *.yaml dimension definitions
16
+ * hierarchies/ → *.yaml hierarchy definitions
17
+ * cubes/ → *.yaml cube definitions
18
+ * blocks/ → *.yaml block companion definitions (metadata only, not loaded into layer)
19
+ */
20
+ export function loadSemanticLayerFromDir(semanticLayerDir) {
21
+ const layer = new SemanticLayer();
22
+ const subdirs = [
23
+ { folder: 'metrics', loader: (raw) => layer.addMetric(parseMetricDefinition(raw)) },
24
+ { folder: 'dimensions', loader: (raw) => layer.addDimension(parseDimensionDefinition(raw)) },
25
+ { folder: 'hierarchies', loader: (raw) => layer.addHierarchy(parseHierarchyDefinition(raw)) },
26
+ { folder: 'cubes', loader: (raw) => layer.addCube(parseCubeDefinition(raw)) },
27
+ ];
28
+ for (const { folder, loader } of subdirs) {
29
+ const dir = join(semanticLayerDir, folder);
30
+ if (!existsSync(dir))
31
+ continue;
32
+ for (const file of readdirSync(dir)) {
33
+ if (extname(file) !== '.yaml' && extname(file) !== '.yml')
34
+ continue;
35
+ try {
36
+ const content = readFileSync(join(dir, file), 'utf-8');
37
+ const raw = yaml.load(content);
38
+ if (raw && typeof raw === 'object') {
39
+ loader(raw);
40
+ }
41
+ }
42
+ catch {
43
+ // Skip malformed YAML files
44
+ }
45
+ }
46
+ }
47
+ return layer;
48
+ }
49
+ /**
50
+ * Load a SemanticLayer from pre-read file contents (no filesystem access needed).
51
+ * Useful for browser contexts or when files are already loaded.
52
+ */
53
+ export function loadSemanticLayerFromConfig(files) {
54
+ const layer = new SemanticLayer();
55
+ for (const file of files) {
56
+ try {
57
+ const raw = yaml.load(file.content);
58
+ if (!raw || typeof raw !== 'object')
59
+ continue;
60
+ const pathLower = file.path.toLowerCase();
61
+ if (pathLower.includes('/metrics/') || pathLower.includes('\\metrics\\')) {
62
+ layer.addMetric(parseMetricDefinition(raw));
63
+ }
64
+ else if (pathLower.includes('/dimensions/') || pathLower.includes('\\dimensions\\')) {
65
+ layer.addDimension(parseDimensionDefinition(raw));
66
+ }
67
+ else if (pathLower.includes('/hierarchies/') || pathLower.includes('\\hierarchies\\')) {
68
+ layer.addHierarchy(parseHierarchyDefinition(raw));
69
+ }
70
+ else if (pathLower.includes('/cubes/') || pathLower.includes('\\cubes\\')) {
71
+ layer.addCube(parseCubeDefinition(raw));
72
+ }
73
+ }
74
+ catch {
75
+ // Skip malformed files
76
+ }
77
+ }
78
+ return layer;
79
+ }
80
+ //# sourceMappingURL=yaml-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml-loader.js","sourceRoot":"","sources":["../../src/semantic/yaml-loader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckcodeailabs/dql-core",
3
- "version": "0.1.4",
3
+ "version": "0.3.0",
4
4
  "description": "DQL language core: lexer, parser, AST, semantic analysis",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -12,13 +12,6 @@
12
12
  "import": "./dist/index.js"
13
13
  }
14
14
  },
15
- "scripts": {
16
- "build": "rm -rf dist tsconfig.tsbuildinfo && tsc",
17
- "test": "vitest run",
18
- "test:watch": "vitest",
19
- "clean": "rm -rf dist tsconfig.tsbuildinfo",
20
- "prepublishOnly": "pnpm run build"
21
- },
22
15
  "files": [
23
16
  "dist"
24
17
  ],
@@ -40,11 +33,21 @@
40
33
  "access": "public"
41
34
  },
42
35
  "devDependencies": {
43
- "vitest": "^3.0.0",
36
+ "@types/js-yaml": "^4.0.9",
37
+ "@types/node": "^22.0.0",
44
38
  "typescript": "^5.7.0",
45
- "@types/node": "^22.0.0"
39
+ "vitest": "^3.0.0"
46
40
  },
47
41
  "engines": {
48
42
  "node": ">=18.0.0"
43
+ },
44
+ "dependencies": {
45
+ "js-yaml": "^4.1.1"
46
+ },
47
+ "scripts": {
48
+ "build": "rm -rf dist tsconfig.tsbuildinfo && tsc",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest",
51
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
49
52
  }
50
- }
53
+ }