yamchart 0.3.1 → 0.3.4
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/public/assets/index-eDQyKtAA.js +378 -0
- package/dist/public/assets/index-ogBV05Wr.css +1 -0
- package/dist/public/assets/index.es-BMf7uM-9.js +18 -0
- package/dist/public/assets/purify.es-B9ZVCkUG.js +2 -0
- package/dist/public/index.html +13 -0
- 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,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthDatabase,
|
|
3
|
+
generateSessionToken,
|
|
4
|
+
hashPassword,
|
|
5
|
+
parseTtl,
|
|
6
|
+
verifyPassword
|
|
7
|
+
} from "./chunk-4P5UHWYK.js";
|
|
8
|
+
import "./chunk-DGUM43GV.js";
|
|
9
|
+
export {
|
|
10
|
+
AuthDatabase,
|
|
11
|
+
generateSessionToken,
|
|
12
|
+
hashPassword,
|
|
13
|
+
parseTtl,
|
|
14
|
+
verifyPassword
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=dist-JH7OL7U4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DATE_PRESETS,
|
|
3
|
+
DuckDBConnector,
|
|
4
|
+
MySQLConnector,
|
|
5
|
+
PostgresConnector,
|
|
6
|
+
QueryCompiler,
|
|
7
|
+
SQLiteConnector,
|
|
8
|
+
SnowflakeConnector,
|
|
9
|
+
VERSION,
|
|
10
|
+
checkSchema,
|
|
11
|
+
createTemplateContext,
|
|
12
|
+
expandCustomDateRange,
|
|
13
|
+
expandDatePreset,
|
|
14
|
+
expandThis,
|
|
15
|
+
extractTemplateVariables,
|
|
16
|
+
isCustomDateRange,
|
|
17
|
+
isDatePreset,
|
|
18
|
+
parseModelMetadata,
|
|
19
|
+
renderTemplate,
|
|
20
|
+
resolveMySQLAuth,
|
|
21
|
+
resolvePostgresAuth,
|
|
22
|
+
resolveSnowflakeAuth,
|
|
23
|
+
runAll,
|
|
24
|
+
runAssertion,
|
|
25
|
+
runModel,
|
|
26
|
+
templateHasVariable
|
|
27
|
+
} from "./chunk-LL3VKMZM.js";
|
|
28
|
+
import "./chunk-DGUM43GV.js";
|
|
29
|
+
export {
|
|
30
|
+
DATE_PRESETS,
|
|
31
|
+
DuckDBConnector,
|
|
32
|
+
MySQLConnector,
|
|
33
|
+
PostgresConnector,
|
|
34
|
+
QueryCompiler,
|
|
35
|
+
SQLiteConnector,
|
|
36
|
+
SnowflakeConnector,
|
|
37
|
+
VERSION,
|
|
38
|
+
checkSchema,
|
|
39
|
+
createTemplateContext,
|
|
40
|
+
expandCustomDateRange,
|
|
41
|
+
expandDatePreset,
|
|
42
|
+
expandThis,
|
|
43
|
+
extractTemplateVariables,
|
|
44
|
+
isCustomDateRange,
|
|
45
|
+
isDatePreset,
|
|
46
|
+
parseModelMetadata,
|
|
47
|
+
renderTemplate,
|
|
48
|
+
resolveMySQLAuth,
|
|
49
|
+
resolvePostgresAuth,
|
|
50
|
+
resolveSnowflakeAuth,
|
|
51
|
+
runAll,
|
|
52
|
+
runAssertion,
|
|
53
|
+
runModel,
|
|
54
|
+
templateHasVariable
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=dist-JKJLH3F6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import "./chunk-DGUM43GV.js";
|
|
2
|
+
|
|
1
3
|
// src/commands/generate.ts
|
|
2
4
|
import { readFile } from "fs/promises";
|
|
3
5
|
import { join as join2 } from "path";
|
|
@@ -312,4 +314,4 @@ async function generate(projectDir, options) {
|
|
|
312
314
|
export {
|
|
313
315
|
generate
|
|
314
316
|
};
|
|
315
|
-
//# sourceMappingURL=generate-
|
|
317
|
+
//# sourceMappingURL=generate-KNER36CB.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/generate.ts","../src/generate/detector.ts","../src/generate/variants.ts","../src/generate/writer.ts","../src/generate/prompts.ts"],"sourcesContent":["// apps/cli/src/commands/generate.ts\nimport { readFile } from 'fs/promises';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\nimport type { CatalogData, CatalogModel } from '../dbt/catalog.js';\nimport { detectColumnTypes } from '../generate/detector.js';\nimport { generateVariants, type MetricColumn } from '../generate/variants.js';\nimport { writeStub, stubExists } from '../generate/writer.js';\nimport {\n promptDateColumn,\n promptMetrics,\n promptDimensions,\n promptConfirmVariants,\n promptOverwrite,\n} from '../generate/prompts.js';\n\nexport interface GenerateOptions {\n model?: string;\n yolo?: boolean;\n}\n\nexport interface GenerateResult {\n success: boolean;\n error?: string;\n modelsProcessed: number;\n filesCreated: number;\n filesSkipped: number;\n}\n\nasync function loadCatalog(projectDir: string): Promise<CatalogData | null> {\n const catalogPath = join(projectDir, '.yamchart', 'catalog.json');\n if (!existsSync(catalogPath)) return null;\n\n const content = await readFile(catalogPath, 'utf-8');\n return JSON.parse(content);\n}\n\nasync function processModel(\n projectDir: string,\n model: CatalogModel,\n yolo: boolean\n): Promise<{ created: number; skipped: number }> {\n const detected = detectColumnTypes(model.columns);\n\n let dateColumn: string | null;\n let metrics: MetricColumn[];\n let dimensions: string[];\n\n if (yolo) {\n // Use all defaults\n dateColumn = detected.dateColumns[0] || null;\n metrics = detected.metricColumns.map(name => ({ name, aggregation: 'sum' as const }));\n dimensions = detected.dimensionColumns;\n } else {\n // Interactive prompts\n dateColumn = await promptDateColumn(model.name, detected);\n metrics = await promptMetrics(model.name, detected);\n dimensions = await promptDimensions(model.name, detected);\n }\n\n if (metrics.length === 0) {\n return { created: 0, skipped: 0 };\n }\n\n const variants = generateVariants({\n modelName: model.name,\n tableName: model.table || model.name,\n dateColumn,\n metricColumns: metrics,\n dimensionColumns: dimensions,\n });\n\n let confirmedVariants = variants;\n if (!yolo && variants.length > 0) {\n const selected = await promptConfirmVariants(\n model.name,\n variants.map(v => v.name)\n );\n confirmedVariants = variants.filter(v => selected.includes(v.name));\n }\n\n let created = 0;\n let skipped = 0;\n\n for (const variant of confirmedVariants) {\n const exists = await stubExists(projectDir, variant.filename);\n\n if (exists && !yolo) {\n const action = await promptOverwrite(variant.filename);\n if (action === 'skip') {\n skipped++;\n continue;\n }\n if (action === 'rename') {\n variant.filename = variant.filename.replace('.sql', '_new.sql');\n }\n }\n\n await writeStub(projectDir, variant.filename, variant.sql);\n created++;\n }\n\n return { created, skipped };\n}\n\nexport async function generate(\n projectDir: string,\n options: GenerateOptions\n): Promise<GenerateResult> {\n const catalog = await loadCatalog(projectDir);\n\n if (!catalog) {\n return {\n success: false,\n error: 'catalog.json not found. Run `yamchart sync-dbt` first.',\n modelsProcessed: 0,\n filesCreated: 0,\n filesSkipped: 0,\n };\n }\n\n let models = catalog.models;\n\n if (options.model) {\n models = models.filter(m => m.name === options.model);\n if (models.length === 0) {\n return {\n success: false,\n error: `Model '${options.model}' not found in catalog`,\n modelsProcessed: 0,\n filesCreated: 0,\n filesSkipped: 0,\n };\n }\n }\n\n let totalCreated = 0;\n let totalSkipped = 0;\n\n for (const model of models) {\n const { created, skipped } = await processModel(\n projectDir,\n model,\n options.yolo ?? false\n );\n totalCreated += created;\n totalSkipped += skipped;\n }\n\n return {\n success: true,\n modelsProcessed: models.length,\n filesCreated: totalCreated,\n filesSkipped: totalSkipped,\n };\n}\n","import type { DbtColumn } from '../dbt/types.js';\n\nexport interface DetectedColumns {\n dateColumns: string[];\n metricColumns: string[];\n dimensionColumns: string[];\n primaryKeys: string[];\n foreignKeys: string[];\n}\n\nconst DATE_TYPES = ['date', 'timestamp', 'datetime', 'timestamptz', 'timestamp_ntz'];\nconst NUMERIC_TYPES = ['int', 'integer', 'bigint', 'smallint', 'numeric', 'decimal', 'float', 'double', 'real', 'number'];\nconst STRING_TYPES = ['string', 'varchar', 'char', 'text'];\nconst BOOLEAN_TYPES = ['boolean', 'bool', 'bit'];\n\nfunction isDateColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n if (DATE_TYPES.some(t => typeLower.includes(t))) return true;\n\n const nameLower = col.name.toLowerCase();\n return nameLower.endsWith('_at') || nameLower.endsWith('_date') || nameLower.endsWith('_time');\n}\n\nfunction isNumericColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n return NUMERIC_TYPES.some(t => typeLower.includes(t));\n}\n\nfunction isStringColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n return STRING_TYPES.some(t => typeLower.includes(t));\n}\n\nfunction isBooleanColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n return BOOLEAN_TYPES.some(t => typeLower.includes(t));\n}\n\nfunction isPrimaryKey(col: DbtColumn): boolean {\n if (col.hints.includes('primary_key') || col.hints.includes('unique')) return true;\n return col.name === 'id';\n}\n\nfunction isForeignKey(col: DbtColumn): boolean {\n return col.hints.some(h => h.startsWith('fk:'));\n}\n\nexport function detectColumnTypes(columns: DbtColumn[]): DetectedColumns {\n const dateColumns: string[] = [];\n const metricColumns: string[] = [];\n const dimensionColumns: string[] = [];\n const primaryKeys: string[] = [];\n const foreignKeys: string[] = [];\n\n for (const col of columns) {\n if (isPrimaryKey(col)) {\n primaryKeys.push(col.name);\n continue;\n }\n\n if (isForeignKey(col)) {\n foreignKeys.push(col.name);\n continue;\n }\n\n if (isDateColumn(col)) {\n dateColumns.push(col.name);\n } else if (isNumericColumn(col)) {\n metricColumns.push(col.name);\n } else {\n // String, boolean, or unknown types all become dimensions\n dimensionColumns.push(col.name);\n }\n }\n\n return { dateColumns, metricColumns, dimensionColumns, primaryKeys, foreignKeys };\n}\n","// apps/cli/src/generate/variants.ts\n\nexport interface MetricColumn {\n name: string;\n aggregation: 'sum' | 'avg' | 'count' | 'min' | 'max';\n}\n\nexport interface VariantConfig {\n modelName: string;\n tableName: string;\n dateColumn: string | null;\n metricColumns: MetricColumn[];\n dimensionColumns: string[];\n}\n\nexport interface GeneratedVariant {\n name: string;\n filename: string;\n description: string;\n sql: string;\n}\n\nfunction formatDate(): string {\n return new Date().toISOString().split('T')[0];\n}\n\nfunction quoteIdentifier(name: string): string {\n // Double quotes for ANSI SQL standard\n // Escape any existing double quotes by doubling them\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction generateHeader(modelName: string, variantName: string, description: string, tableName: string): string {\n return `-- @generated: from dbt model '${modelName}' on ${formatDate()}\n-- @name: ${variantName}\n-- @description: ${description}\n-- @source: ${tableName}\n\n`;\n}\n\nfunction generateMetricSelects(metrics: MetricColumn[]): string {\n return metrics\n .map(m => ` ${m.aggregation.toUpperCase()}(${quoteIdentifier(m.name)}) AS ${quoteIdentifier(m.aggregation + '_' + m.name)}`)\n .join(',\\n');\n}\n\nexport function generateVariants(config: VariantConfig): GeneratedVariant[] {\n const variants: GeneratedVariant[] = [];\n const { modelName, tableName, dateColumn, metricColumns, dimensionColumns } = config;\n\n // Time series variant\n if (dateColumn && metricColumns.length > 0) {\n const name = `${modelName}_over_time`;\n const description = `${modelName} aggregated over time`;\n const sql = `${generateHeader(modelName, name, description, tableName)}SELECT\n date_trunc('{{ granularity }}', ${quoteIdentifier(dateColumn)}) AS period,\n${generateMetricSelects(metricColumns)}\nFROM ${tableName}\nWHERE ${quoteIdentifier(dateColumn)} >= '{{ start_date }}'\n AND ${quoteIdentifier(dateColumn)} <= '{{ end_date }}'\nGROUP BY 1\nORDER BY 1\n`;\n variants.push({ name, filename: `${name}.sql`, description, sql });\n }\n\n // Dimension variants\n for (const dim of dimensionColumns) {\n const name = `${modelName}_by_${dim}`;\n const description = `${modelName} grouped by ${dim}`;\n let sql = generateHeader(modelName, name, description, tableName);\n sql += `SELECT\n ${quoteIdentifier(dim)},\n${generateMetricSelects(metricColumns)}\nFROM ${tableName}\n`;\n if (dateColumn) {\n sql += `WHERE ${quoteIdentifier(dateColumn)} >= '{{ start_date }}'\n AND ${quoteIdentifier(dateColumn)} <= '{{ end_date }}'\n`;\n }\n sql += `GROUP BY 1\nORDER BY 2 DESC\n`;\n variants.push({ name, filename: `${name}.sql`, description, sql });\n }\n\n // KPI variant\n if (metricColumns.length > 0) {\n const name = `${modelName}_kpi`;\n const description = `${modelName} summary metrics`;\n let sql = generateHeader(modelName, name, description, tableName);\n sql += `SELECT\n${generateMetricSelects(metricColumns)}\nFROM ${tableName}\n`;\n if (dateColumn) {\n sql += `WHERE ${quoteIdentifier(dateColumn)} >= '{{ start_date }}'\n AND ${quoteIdentifier(dateColumn)} <= '{{ end_date }}'\n`;\n }\n variants.push({ name, filename: `${name}.sql`, description, sql });\n }\n\n return variants;\n}\n","// apps/cli/src/generate/writer.ts\nimport { writeFile, mkdir } from 'fs/promises';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\n\nexport async function writeStub(projectDir: string, filename: string, content: string): Promise<void> {\n const modelsDir = join(projectDir, 'models');\n await mkdir(modelsDir, { recursive: true });\n await writeFile(join(modelsDir, filename), content, 'utf-8');\n}\n\nexport async function stubExists(projectDir: string, filename: string): Promise<boolean> {\n return existsSync(join(projectDir, 'models', filename));\n}\n","// apps/cli/src/generate/prompts.ts\nimport { confirm, select, checkbox } from '@inquirer/prompts';\nimport type { DetectedColumns } from './detector.js';\nimport type { MetricColumn } from './variants.js';\n\nexport interface DateColumnChoice {\n name: string;\n value: string | null;\n checked: boolean;\n}\n\nexport interface MetricChoice {\n name: string;\n value: MetricColumn;\n checked: boolean;\n}\n\nexport interface DimensionChoice {\n name: string;\n value: string;\n checked: boolean;\n}\n\nexport function buildDateColumnChoices(detected: DetectedColumns): DateColumnChoice[] {\n const choices: DateColumnChoice[] = detected.dateColumns.map((col, i) => ({\n name: col,\n value: col,\n checked: i === 0,\n }));\n choices.push({ name: 'Skip time series', value: null, checked: false });\n return choices;\n}\n\nexport function buildMetricChoices(detected: DetectedColumns): MetricChoice[] {\n return detected.metricColumns.map(col => ({\n name: `${col} (sum)`,\n value: { name: col, aggregation: 'sum' as const },\n checked: true,\n }));\n}\n\nexport function buildDimensionChoices(detected: DetectedColumns): DimensionChoice[] {\n return detected.dimensionColumns.map(col => ({\n name: col,\n value: col,\n checked: true,\n }));\n}\n\nexport async function promptDateColumn(modelName: string, detected: DetectedColumns): Promise<string | null> {\n if (detected.dateColumns.length === 0) return null;\n\n const defaultCol = detected.dateColumns[0];\n const confirmed = await confirm({\n message: `${modelName}: Use '${defaultCol}' for time series?`,\n default: true,\n });\n\n if (confirmed) return defaultCol;\n\n if (detected.dateColumns.length === 1) return null;\n\n return select({\n message: 'Select date column:',\n choices: buildDateColumnChoices(detected).map(c => ({ name: c.name, value: c.value })),\n });\n}\n\nexport async function promptMetrics(modelName: string, detected: DetectedColumns): Promise<MetricColumn[]> {\n if (detected.metricColumns.length === 0) return [];\n\n const choices = buildMetricChoices(detected);\n const selected = await checkbox({\n message: `${modelName}: Select metrics to aggregate:`,\n choices: choices.map(c => ({ name: c.name, value: c.value, checked: c.checked })),\n });\n\n return selected;\n}\n\nexport async function promptDimensions(modelName: string, detected: DetectedColumns): Promise<string[]> {\n if (detected.dimensionColumns.length === 0) return [];\n\n const choices = buildDimensionChoices(detected);\n const selected = await checkbox({\n message: `${modelName}: Select dimensions for grouping:`,\n choices: choices.map(c => ({ name: c.name, value: c.value, checked: c.checked })),\n });\n\n return selected;\n}\n\nexport async function promptConfirmVariants(modelName: string, variantNames: string[]): Promise<string[]> {\n const choices = variantNames.map(name => ({ name, value: name, checked: true }));\n\n return checkbox({\n message: `${modelName}: Generate these stubs?`,\n choices,\n });\n}\n\nexport async function promptOverwrite(filename: string): Promise<'overwrite' | 'skip' | 'rename'> {\n return select({\n message: `${filename} already exists:`,\n choices: [\n { name: 'Overwrite', value: 'overwrite' as const },\n { name: 'Skip', value: 'skip' as const },\n { name: 'Rename (add suffix)', value: 'rename' as const },\n ],\n });\n}\n"],"mappings":"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","names":["join","existsSync","join","existsSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/commands/generate.ts","../src/generate/detector.ts","../src/generate/variants.ts","../src/generate/writer.ts","../src/generate/prompts.ts"],"sourcesContent":["// apps/cli/src/commands/generate.ts\nimport { readFile } from 'fs/promises';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\nimport type { CatalogData, CatalogModel } from '../dbt/catalog.js';\nimport { detectColumnTypes } from '../generate/detector.js';\nimport { generateVariants, type MetricColumn } from '../generate/variants.js';\nimport { writeStub, stubExists } from '../generate/writer.js';\nimport {\n promptDateColumn,\n promptMetrics,\n promptDimensions,\n promptConfirmVariants,\n promptOverwrite,\n} from '../generate/prompts.js';\n\nexport interface GenerateOptions {\n model?: string;\n yolo?: boolean;\n}\n\nexport interface GenerateResult {\n success: boolean;\n error?: string;\n modelsProcessed: number;\n filesCreated: number;\n filesSkipped: number;\n}\n\nasync function loadCatalog(projectDir: string): Promise<CatalogData | null> {\n const catalogPath = join(projectDir, '.yamchart', 'catalog.json');\n if (!existsSync(catalogPath)) return null;\n\n const content = await readFile(catalogPath, 'utf-8');\n return JSON.parse(content);\n}\n\nasync function processModel(\n projectDir: string,\n model: CatalogModel,\n yolo: boolean\n): Promise<{ created: number; skipped: number }> {\n const detected = detectColumnTypes(model.columns);\n\n let dateColumn: string | null;\n let metrics: MetricColumn[];\n let dimensions: string[];\n\n if (yolo) {\n // Use all defaults\n dateColumn = detected.dateColumns[0] || null;\n metrics = detected.metricColumns.map(name => ({ name, aggregation: 'sum' as const }));\n dimensions = detected.dimensionColumns;\n } else {\n // Interactive prompts\n dateColumn = await promptDateColumn(model.name, detected);\n metrics = await promptMetrics(model.name, detected);\n dimensions = await promptDimensions(model.name, detected);\n }\n\n if (metrics.length === 0) {\n return { created: 0, skipped: 0 };\n }\n\n const variants = generateVariants({\n modelName: model.name,\n tableName: model.table || model.name,\n dateColumn,\n metricColumns: metrics,\n dimensionColumns: dimensions,\n });\n\n let confirmedVariants = variants;\n if (!yolo && variants.length > 0) {\n const selected = await promptConfirmVariants(\n model.name,\n variants.map(v => v.name)\n );\n confirmedVariants = variants.filter(v => selected.includes(v.name));\n }\n\n let created = 0;\n let skipped = 0;\n\n for (const variant of confirmedVariants) {\n const exists = await stubExists(projectDir, variant.filename);\n\n if (exists && !yolo) {\n const action = await promptOverwrite(variant.filename);\n if (action === 'skip') {\n skipped++;\n continue;\n }\n if (action === 'rename') {\n variant.filename = variant.filename.replace('.sql', '_new.sql');\n }\n }\n\n await writeStub(projectDir, variant.filename, variant.sql);\n created++;\n }\n\n return { created, skipped };\n}\n\nexport async function generate(\n projectDir: string,\n options: GenerateOptions\n): Promise<GenerateResult> {\n const catalog = await loadCatalog(projectDir);\n\n if (!catalog) {\n return {\n success: false,\n error: 'catalog.json not found. Run `yamchart sync-dbt` first.',\n modelsProcessed: 0,\n filesCreated: 0,\n filesSkipped: 0,\n };\n }\n\n let models = catalog.models;\n\n if (options.model) {\n models = models.filter(m => m.name === options.model);\n if (models.length === 0) {\n return {\n success: false,\n error: `Model '${options.model}' not found in catalog`,\n modelsProcessed: 0,\n filesCreated: 0,\n filesSkipped: 0,\n };\n }\n }\n\n let totalCreated = 0;\n let totalSkipped = 0;\n\n for (const model of models) {\n const { created, skipped } = await processModel(\n projectDir,\n model,\n options.yolo ?? false\n );\n totalCreated += created;\n totalSkipped += skipped;\n }\n\n return {\n success: true,\n modelsProcessed: models.length,\n filesCreated: totalCreated,\n filesSkipped: totalSkipped,\n };\n}\n","import type { DbtColumn } from '../dbt/types.js';\n\nexport interface DetectedColumns {\n dateColumns: string[];\n metricColumns: string[];\n dimensionColumns: string[];\n primaryKeys: string[];\n foreignKeys: string[];\n}\n\nconst DATE_TYPES = ['date', 'timestamp', 'datetime', 'timestamptz', 'timestamp_ntz'];\nconst NUMERIC_TYPES = ['int', 'integer', 'bigint', 'smallint', 'numeric', 'decimal', 'float', 'double', 'real', 'number'];\nconst STRING_TYPES = ['string', 'varchar', 'char', 'text'];\nconst BOOLEAN_TYPES = ['boolean', 'bool', 'bit'];\n\nfunction isDateColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n if (DATE_TYPES.some(t => typeLower.includes(t))) return true;\n\n const nameLower = col.name.toLowerCase();\n return nameLower.endsWith('_at') || nameLower.endsWith('_date') || nameLower.endsWith('_time');\n}\n\nfunction isNumericColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n return NUMERIC_TYPES.some(t => typeLower.includes(t));\n}\n\nfunction isStringColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n return STRING_TYPES.some(t => typeLower.includes(t));\n}\n\nfunction isBooleanColumn(col: DbtColumn): boolean {\n const typeLower = (col.data_type || '').toLowerCase();\n return BOOLEAN_TYPES.some(t => typeLower.includes(t));\n}\n\nfunction isPrimaryKey(col: DbtColumn): boolean {\n if (col.hints.includes('primary_key') || col.hints.includes('unique')) return true;\n return col.name === 'id';\n}\n\nfunction isForeignKey(col: DbtColumn): boolean {\n return col.hints.some(h => h.startsWith('fk:'));\n}\n\nexport function detectColumnTypes(columns: DbtColumn[]): DetectedColumns {\n const dateColumns: string[] = [];\n const metricColumns: string[] = [];\n const dimensionColumns: string[] = [];\n const primaryKeys: string[] = [];\n const foreignKeys: string[] = [];\n\n for (const col of columns) {\n if (isPrimaryKey(col)) {\n primaryKeys.push(col.name);\n continue;\n }\n\n if (isForeignKey(col)) {\n foreignKeys.push(col.name);\n continue;\n }\n\n if (isDateColumn(col)) {\n dateColumns.push(col.name);\n } else if (isNumericColumn(col)) {\n metricColumns.push(col.name);\n } else {\n // String, boolean, or unknown types all become dimensions\n dimensionColumns.push(col.name);\n }\n }\n\n return { dateColumns, metricColumns, dimensionColumns, primaryKeys, foreignKeys };\n}\n","// apps/cli/src/generate/variants.ts\n\nexport interface MetricColumn {\n name: string;\n aggregation: 'sum' | 'avg' | 'count' | 'min' | 'max';\n}\n\nexport interface VariantConfig {\n modelName: string;\n tableName: string;\n dateColumn: string | null;\n metricColumns: MetricColumn[];\n dimensionColumns: string[];\n}\n\nexport interface GeneratedVariant {\n name: string;\n filename: string;\n description: string;\n sql: string;\n}\n\nfunction formatDate(): string {\n return new Date().toISOString().split('T')[0];\n}\n\nfunction quoteIdentifier(name: string): string {\n // Double quotes for ANSI SQL standard\n // Escape any existing double quotes by doubling them\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction generateHeader(modelName: string, variantName: string, description: string, tableName: string): string {\n return `-- @generated: from dbt model '${modelName}' on ${formatDate()}\n-- @name: ${variantName}\n-- @description: ${description}\n-- @source: ${tableName}\n\n`;\n}\n\nfunction generateMetricSelects(metrics: MetricColumn[]): string {\n return metrics\n .map(m => ` ${m.aggregation.toUpperCase()}(${quoteIdentifier(m.name)}) AS ${quoteIdentifier(m.aggregation + '_' + m.name)}`)\n .join(',\\n');\n}\n\nexport function generateVariants(config: VariantConfig): GeneratedVariant[] {\n const variants: GeneratedVariant[] = [];\n const { modelName, tableName, dateColumn, metricColumns, dimensionColumns } = config;\n\n // Time series variant\n if (dateColumn && metricColumns.length > 0) {\n const name = `${modelName}_over_time`;\n const description = `${modelName} aggregated over time`;\n const sql = `${generateHeader(modelName, name, description, tableName)}SELECT\n date_trunc('{{ granularity }}', ${quoteIdentifier(dateColumn)}) AS period,\n${generateMetricSelects(metricColumns)}\nFROM ${tableName}\nWHERE ${quoteIdentifier(dateColumn)} >= '{{ start_date }}'\n AND ${quoteIdentifier(dateColumn)} <= '{{ end_date }}'\nGROUP BY 1\nORDER BY 1\n`;\n variants.push({ name, filename: `${name}.sql`, description, sql });\n }\n\n // Dimension variants\n for (const dim of dimensionColumns) {\n const name = `${modelName}_by_${dim}`;\n const description = `${modelName} grouped by ${dim}`;\n let sql = generateHeader(modelName, name, description, tableName);\n sql += `SELECT\n ${quoteIdentifier(dim)},\n${generateMetricSelects(metricColumns)}\nFROM ${tableName}\n`;\n if (dateColumn) {\n sql += `WHERE ${quoteIdentifier(dateColumn)} >= '{{ start_date }}'\n AND ${quoteIdentifier(dateColumn)} <= '{{ end_date }}'\n`;\n }\n sql += `GROUP BY 1\nORDER BY 2 DESC\n`;\n variants.push({ name, filename: `${name}.sql`, description, sql });\n }\n\n // KPI variant\n if (metricColumns.length > 0) {\n const name = `${modelName}_kpi`;\n const description = `${modelName} summary metrics`;\n let sql = generateHeader(modelName, name, description, tableName);\n sql += `SELECT\n${generateMetricSelects(metricColumns)}\nFROM ${tableName}\n`;\n if (dateColumn) {\n sql += `WHERE ${quoteIdentifier(dateColumn)} >= '{{ start_date }}'\n AND ${quoteIdentifier(dateColumn)} <= '{{ end_date }}'\n`;\n }\n variants.push({ name, filename: `${name}.sql`, description, sql });\n }\n\n return variants;\n}\n","// apps/cli/src/generate/writer.ts\nimport { writeFile, mkdir } from 'fs/promises';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\n\nexport async function writeStub(projectDir: string, filename: string, content: string): Promise<void> {\n const modelsDir = join(projectDir, 'models');\n await mkdir(modelsDir, { recursive: true });\n await writeFile(join(modelsDir, filename), content, 'utf-8');\n}\n\nexport async function stubExists(projectDir: string, filename: string): Promise<boolean> {\n return existsSync(join(projectDir, 'models', filename));\n}\n","// apps/cli/src/generate/prompts.ts\nimport { confirm, select, checkbox } from '@inquirer/prompts';\nimport type { DetectedColumns } from './detector.js';\nimport type { MetricColumn } from './variants.js';\n\nexport interface DateColumnChoice {\n name: string;\n value: string | null;\n checked: boolean;\n}\n\nexport interface MetricChoice {\n name: string;\n value: MetricColumn;\n checked: boolean;\n}\n\nexport interface DimensionChoice {\n name: string;\n value: string;\n checked: boolean;\n}\n\nexport function buildDateColumnChoices(detected: DetectedColumns): DateColumnChoice[] {\n const choices: DateColumnChoice[] = detected.dateColumns.map((col, i) => ({\n name: col,\n value: col,\n checked: i === 0,\n }));\n choices.push({ name: 'Skip time series', value: null, checked: false });\n return choices;\n}\n\nexport function buildMetricChoices(detected: DetectedColumns): MetricChoice[] {\n return detected.metricColumns.map(col => ({\n name: `${col} (sum)`,\n value: { name: col, aggregation: 'sum' as const },\n checked: true,\n }));\n}\n\nexport function buildDimensionChoices(detected: DetectedColumns): DimensionChoice[] {\n return detected.dimensionColumns.map(col => ({\n name: col,\n value: col,\n checked: true,\n }));\n}\n\nexport async function promptDateColumn(modelName: string, detected: DetectedColumns): Promise<string | null> {\n if (detected.dateColumns.length === 0) return null;\n\n const defaultCol = detected.dateColumns[0];\n const confirmed = await confirm({\n message: `${modelName}: Use '${defaultCol}' for time series?`,\n default: true,\n });\n\n if (confirmed) return defaultCol;\n\n if (detected.dateColumns.length === 1) return null;\n\n return select({\n message: 'Select date column:',\n choices: buildDateColumnChoices(detected).map(c => ({ name: c.name, value: c.value })),\n });\n}\n\nexport async function promptMetrics(modelName: string, detected: DetectedColumns): Promise<MetricColumn[]> {\n if (detected.metricColumns.length === 0) return [];\n\n const choices = buildMetricChoices(detected);\n const selected = await checkbox({\n message: `${modelName}: Select metrics to aggregate:`,\n choices: choices.map(c => ({ name: c.name, value: c.value, checked: c.checked })),\n });\n\n return selected;\n}\n\nexport async function promptDimensions(modelName: string, detected: DetectedColumns): Promise<string[]> {\n if (detected.dimensionColumns.length === 0) return [];\n\n const choices = buildDimensionChoices(detected);\n const selected = await checkbox({\n message: `${modelName}: Select dimensions for grouping:`,\n choices: choices.map(c => ({ name: c.name, value: c.value, checked: c.checked })),\n });\n\n return selected;\n}\n\nexport async function promptConfirmVariants(modelName: string, variantNames: string[]): Promise<string[]> {\n const choices = variantNames.map(name => ({ name, value: name, checked: true }));\n\n return checkbox({\n message: `${modelName}: Generate these stubs?`,\n choices,\n });\n}\n\nexport async function promptOverwrite(filename: string): Promise<'overwrite' | 'skip' | 'rename'> {\n return select({\n message: `${filename} already exists:`,\n choices: [\n { name: 'Overwrite', value: 'overwrite' as const },\n { name: 'Skip', value: 'skip' as const },\n { name: 'Rename (add suffix)', value: 'rename' as const },\n ],\n });\n}\n"],"mappings":"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","names":["join","existsSync","join","existsSync"]}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
checkForUpdate
|
|
4
|
+
} from "./chunk-3CLMQNNR.js";
|
|
2
5
|
import {
|
|
3
6
|
findProjectRoot,
|
|
4
7
|
loadEnvFile,
|
|
5
8
|
validateProject
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
checkForUpdate
|
|
9
|
-
} from "./chunk-3CLMQNNR.js";
|
|
9
|
+
} from "./chunk-A24KVXJQ.js";
|
|
10
10
|
import {
|
|
11
11
|
detail,
|
|
12
12
|
error,
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
success,
|
|
18
18
|
warning
|
|
19
19
|
} from "./chunk-HJVVHYVN.js";
|
|
20
|
+
import "./chunk-LL3VKMZM.js";
|
|
21
|
+
import "./chunk-DGUM43GV.js";
|
|
20
22
|
|
|
21
23
|
// src/index.ts
|
|
22
24
|
import { Command } from "commander";
|
|
@@ -93,7 +95,7 @@ program.command("dev").description("Start development server with hot reload").a
|
|
|
93
95
|
detail("Run this command from a yamchart project directory");
|
|
94
96
|
process.exit(2);
|
|
95
97
|
}
|
|
96
|
-
const { runDevServer } = await import("./dev-
|
|
98
|
+
const { runDevServer } = await import("./dev-PTVNJI7G.js");
|
|
97
99
|
await runDevServer(projectDir, {
|
|
98
100
|
port: parseInt(options.port, 10),
|
|
99
101
|
apiOnly: options.apiOnly ?? false,
|
|
@@ -101,7 +103,7 @@ program.command("dev").description("Start development server with hot reload").a
|
|
|
101
103
|
});
|
|
102
104
|
});
|
|
103
105
|
program.command("init").description("Create a new yamchart project").argument("[directory]", "Target directory", ".").option("--example", "Create full example project with sample database").option("--empty", "Create only yamchart.yaml (no connections, models, or charts)").option("--force", "Overwrite existing files").action(async (directory, options) => {
|
|
104
|
-
const { initProject } = await import("./init-
|
|
106
|
+
const { initProject } = await import("./init-FTSEOTAD.js");
|
|
105
107
|
const targetDir = resolve(directory);
|
|
106
108
|
const result = await initProject(targetDir, options);
|
|
107
109
|
if (!result.success) {
|
|
@@ -120,7 +122,7 @@ program.command("init").description("Create a new yamchart project").argument("[
|
|
|
120
122
|
info(`Run \`cd ${directory === "." ? basename(targetDir) : directory} && yamchart dev\` to start.`);
|
|
121
123
|
});
|
|
122
124
|
program.command("sync-dbt").description("Sync dbt project metadata into AI-readable catalog").option("-s, --source <type>", "Source type: local, github, dbt-cloud", "local").option("-p, --path <dir>", "Path to dbt project (for local source)").option("--repo <repo>", "GitHub repository (for github source)").option("--branch <branch>", "Git branch (for github source)", "main").option("-i, --include <patterns...>", "Include glob patterns").option("-e, --exclude <patterns...>", "Exclude glob patterns").option("-t, --tag <tags...>", "Filter by dbt tags").option("--refresh", "Re-sync using saved configuration").action(async (options) => {
|
|
123
|
-
const { syncDbt, loadSyncConfig } = await import("./sync-dbt-
|
|
125
|
+
const { syncDbt, loadSyncConfig } = await import("./sync-dbt-6WY7HKP7.js");
|
|
124
126
|
const projectDir = await findProjectRoot(process.cwd());
|
|
125
127
|
if (!projectDir) {
|
|
126
128
|
error("yamchart.yaml not found");
|
|
@@ -158,7 +160,7 @@ program.command("sync-dbt").description("Sync dbt project metadata into AI-reada
|
|
|
158
160
|
}
|
|
159
161
|
});
|
|
160
162
|
program.command("generate").description("Generate SQL model stubs from dbt catalog").argument("[model]", "Specific model to generate (optional)").option("--yolo", "Skip all prompts, use defaults for everything").action(async (model, options) => {
|
|
161
|
-
const { generate } = await import("./generate-
|
|
163
|
+
const { generate } = await import("./generate-KNER36CB.js");
|
|
162
164
|
const projectDir = await findProjectRoot(process.cwd());
|
|
163
165
|
if (!projectDir) {
|
|
164
166
|
error("yamchart.yaml not found");
|
|
@@ -192,7 +194,7 @@ program.command("test").description("Run model tests (@returns schema checks and
|
|
|
192
194
|
}
|
|
193
195
|
loadEnvFile(projectDir);
|
|
194
196
|
try {
|
|
195
|
-
const { testProject, formatTestOutput } = await import("./test-
|
|
197
|
+
const { testProject, formatTestOutput } = await import("./test-WYNX4RYZ.js");
|
|
196
198
|
const result = await testProject(projectDir, model, {
|
|
197
199
|
connection: options.connection,
|
|
198
200
|
json: options.json
|
|
@@ -215,7 +217,7 @@ program.command("test").description("Run model tests (@returns schema checks and
|
|
|
215
217
|
}
|
|
216
218
|
});
|
|
217
219
|
program.command("update").description("Check for yamchart updates").action(async () => {
|
|
218
|
-
const { runUpdate } = await import("./update-
|
|
220
|
+
const { runUpdate } = await import("./update-GWPF5AS6.js");
|
|
219
221
|
await runUpdate(pkg.version);
|
|
220
222
|
});
|
|
221
223
|
program.command("reset-password").description("Reset a user password (requires auth to be enabled)").requiredOption("-e, --email <email>", "Email address of the user").action(async (options) => {
|
|
@@ -227,7 +229,7 @@ program.command("reset-password").description("Reset a user password (requires a
|
|
|
227
229
|
process.exit(2);
|
|
228
230
|
}
|
|
229
231
|
loadEnvFile(projectDir);
|
|
230
|
-
const { resetPassword } = await import("./reset-password-
|
|
232
|
+
const { resetPassword } = await import("./reset-password-IZQTDTU7.js");
|
|
231
233
|
await resetPassword(projectDir, options.email);
|
|
232
234
|
});
|
|
233
235
|
program.parse();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { resolve, basename, dirname, join } from 'path';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { validateProject } from './commands/validate.js';\nimport { findProjectRoot, loadEnvFile } from './utils/config.js';\nimport pc from 'picocolors';\nimport * as output from './utils/output.js';\nimport { checkForUpdate } from './utils/update-check.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));\n\nconst program = new Command();\n\nprogram\n .name('yamchart')\n .description('Git-native business intelligence dashboards')\n .version(pkg.version);\n\nprogram\n .command('validate')\n .description('Validate configuration files')\n .argument('[path]', 'Path to yamchart project', '.')\n .option('--dry-run', 'Connect to database and test queries with EXPLAIN')\n .option('-c, --connection <name>', 'Connection to use for dry-run')\n .option('--json', 'Output as JSON')\n .action(async (path: string, options: { dryRun?: boolean; connection?: string; json?: boolean }) => {\n const startPath = resolve(path);\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n if (options.json) {\n console.log(JSON.stringify({ success: false, error: 'yamchart.yaml not found' }));\n } else {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n }\n process.exit(2);\n }\n\n // Load .env file\n loadEnvFile(projectDir);\n\n if (!options.json) {\n output.header('Validating yamchart project...');\n }\n\n const result = await validateProject(projectDir, {\n dryRun: options.dryRun ?? false,\n connection: options.connection,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n // Print results\n for (const error of result.errors) {\n output.error(error.file);\n output.detail(error.message);\n if (error.suggestion) {\n output.detail(error.suggestion);\n }\n }\n\n for (const warning of result.warnings) {\n output.warning(warning.file);\n output.detail(warning.message);\n }\n\n output.newline();\n\n if (result.success) {\n output.success(`Schema: ${result.stats.passed} passed`);\n } else {\n output.error(`Schema: ${result.stats.passed} passed, ${result.stats.failed} failed`);\n }\n\n if (result.dryRunStats) {\n output.newline();\n if (result.dryRunStats.failed === 0) {\n output.success(`Queries: ${result.dryRunStats.passed} passed (EXPLAIN OK)`);\n } else {\n output.error(`Queries: ${result.dryRunStats.passed} passed, ${result.dryRunStats.failed} failed`);\n }\n }\n\n output.newline();\n\n if (result.success) {\n output.success('Validation passed');\n } else {\n output.error(`Validation failed with ${result.errors.length} error(s)`);\n }\n }\n\n process.exit(result.success ? 0 : 1);\n });\n\nprogram\n .command('dev')\n .description('Start development server with hot reload')\n .argument('[path]', 'Path to yamchart project', '.')\n .option('-p, --port <number>', 'Port to listen on', '3001')\n .option('--api-only', 'Only serve API, no web UI')\n .option('--no-open', 'Do not open browser automatically')\n .action(async (path: string, options: { port: string; apiOnly?: boolean; open: boolean }) => {\n const startPath = resolve(path);\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n const { runDevServer } = await import('./commands/dev.js');\n\n await runDevServer(projectDir, {\n port: parseInt(options.port, 10),\n apiOnly: options.apiOnly ?? false,\n open: options.open,\n });\n });\n\nprogram\n .command('init')\n .description('Create a new yamchart project')\n .argument('[directory]', 'Target directory', '.')\n .option('--example', 'Create full example project with sample database')\n .option('--empty', 'Create only yamchart.yaml (no connections, models, or charts)')\n .option('--force', 'Overwrite existing files')\n .action(async (directory: string, options: { example?: boolean; empty?: boolean; force?: boolean }) => {\n const { initProject } = await import('./commands/init.js');\n const targetDir = resolve(directory);\n\n const result = await initProject(targetDir, options);\n\n if (!result.success) {\n output.error(result.error || 'Failed to create project');\n process.exit(1);\n }\n\n output.newline();\n output.success(`Created ${directory === '.' ? basename(targetDir) : directory}/`);\n for (const file of result.files.slice(0, 10)) {\n output.detail(file);\n }\n if (result.files.length > 10) {\n output.detail(`... and ${result.files.length - 10} more files`);\n }\n output.newline();\n output.info(`Run \\`cd ${directory === '.' ? basename(targetDir) : directory} && yamchart dev\\` to start.`);\n });\n\nprogram\n .command('sync-dbt')\n .description('Sync dbt project metadata into AI-readable catalog')\n .option('-s, --source <type>', 'Source type: local, github, dbt-cloud', 'local')\n .option('-p, --path <dir>', 'Path to dbt project (for local source)')\n .option('--repo <repo>', 'GitHub repository (for github source)')\n .option('--branch <branch>', 'Git branch (for github source)', 'main')\n .option('-i, --include <patterns...>', 'Include glob patterns')\n .option('-e, --exclude <patterns...>', 'Exclude glob patterns')\n .option('-t, --tag <tags...>', 'Filter by dbt tags')\n .option('--refresh', 'Re-sync using saved configuration')\n .action(async (options: {\n source: 'local' | 'github' | 'dbt-cloud';\n path?: string;\n repo?: string;\n branch?: string;\n include?: string[];\n exclude?: string[];\n tag?: string[];\n refresh?: boolean;\n }) => {\n const { syncDbt, loadSyncConfig } = await import('./commands/sync-dbt.js');\n\n // Find project root\n const projectDir = await findProjectRoot(process.cwd());\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n // Handle refresh mode\n if (options.refresh) {\n const savedConfig = await loadSyncConfig(projectDir);\n if (!savedConfig) {\n output.error('No saved sync config found');\n output.detail('Run sync-dbt without --refresh first');\n process.exit(1);\n }\n output.info(`Re-syncing from ${savedConfig.source}:${savedConfig.path || savedConfig.repo}`);\n }\n\n const spin = output.spinner('Syncing dbt metadata...');\n\n const result = await syncDbt(projectDir, {\n source: options.source,\n path: options.path,\n repo: options.repo,\n branch: options.branch,\n include: options.include || [],\n exclude: options.exclude || [],\n tags: options.tag || [],\n refresh: options.refresh,\n });\n\n spin.stop();\n\n if (!result.success) {\n output.error(result.error || 'Sync failed');\n process.exit(1);\n }\n\n output.success(`Synced ${result.modelsIncluded} models to .yamchart/catalog.md`);\n if (result.modelsExcluded > 0) {\n output.detail(`${result.modelsExcluded} models filtered out`);\n }\n });\n\nprogram\n .command('generate')\n .description('Generate SQL model stubs from dbt catalog')\n .argument('[model]', 'Specific model to generate (optional)')\n .option('--yolo', 'Skip all prompts, use defaults for everything')\n .action(async (model: string | undefined, options: { yolo?: boolean }) => {\n const { generate } = await import('./commands/generate.js');\n\n const projectDir = await findProjectRoot(process.cwd());\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n const result = await generate(projectDir, {\n model,\n yolo: options.yolo,\n });\n\n if (!result.success) {\n output.error(result.error || 'Generate failed');\n process.exit(1);\n }\n\n output.success(`Generated ${result.filesCreated} model stubs`);\n if (result.filesSkipped > 0) {\n output.detail(`${result.filesSkipped} files skipped`);\n }\n });\n\nprogram\n .command('test')\n .description('Run model tests (@returns schema checks and @tests data assertions)')\n .argument('[model]', 'Specific model to test (optional, tests all if omitted)')\n .option('-c, --connection <name>', 'Connection to use (overrides default)')\n .option('--json', 'Output as JSON')\n .action(async (model: string | undefined, options: { connection?: string; json?: boolean }) => {\n const startPath = resolve('.');\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n if (options.json) {\n console.log(JSON.stringify({ success: false, error: 'yamchart.yaml not found' }));\n } else {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n }\n process.exit(2);\n }\n\n loadEnvFile(projectDir);\n\n try {\n const { testProject, formatTestOutput } = await import('./commands/test.js');\n const result = await testProject(projectDir, model, {\n connection: options.connection,\n json: options.json,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n formatTestOutput(result, result.connectionName);\n }\n\n process.exit(result.success ? 0 : 1);\n } catch (err) {\n if (options.json) {\n console.log(\n JSON.stringify({ success: false, error: err instanceof Error ? err.message : String(err) }),\n );\n } else {\n output.error(err instanceof Error ? err.message : String(err));\n }\n process.exit(2);\n }\n });\n\nprogram\n .command('update')\n .description('Check for yamchart updates')\n .action(async () => {\n const { runUpdate } = await import('./commands/update.js');\n await runUpdate(pkg.version);\n });\n\nprogram\n .command('reset-password')\n .description('Reset a user password (requires auth to be enabled)')\n .requiredOption('-e, --email <email>', 'Email address of the user')\n .action(async (options: { email: string }) => {\n const startPath = resolve('.');\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n loadEnvFile(projectDir);\n\n const { resetPassword } = await import('./commands/reset-password.js');\n await resetPassword(projectDir, options.email);\n });\n\nprogram.parse();\n\n// Passive update check — runs in background, prints on exit if outdated\nlet updateNotification: string | null = null;\n\ncheckForUpdate(pkg.version).then((update) => {\n if (update) {\n updateNotification = `\\n Update available: ${update.current} → ${update.latest}\\n Run: yamchart update\\n`;\n }\n});\n\nprocess.on('exit', () => {\n if (updateNotification) {\n // Use dim styling so it doesn't compete with command output\n console.error(`\\n${pc.dim(updateNotification)}`);\n }\n});\n"],"mappings":"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","names":["error","warning"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { resolve, basename, dirname, join } from 'path';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { validateProject } from './commands/validate.js';\nimport { findProjectRoot, loadEnvFile } from './utils/config.js';\nimport pc from 'picocolors';\nimport * as output from './utils/output.js';\nimport { checkForUpdate } from './utils/update-check.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));\n\nconst program = new Command();\n\nprogram\n .name('yamchart')\n .description('Git-native business intelligence dashboards')\n .version(pkg.version);\n\nprogram\n .command('validate')\n .description('Validate configuration files')\n .argument('[path]', 'Path to yamchart project', '.')\n .option('--dry-run', 'Connect to database and test queries with EXPLAIN')\n .option('-c, --connection <name>', 'Connection to use for dry-run')\n .option('--json', 'Output as JSON')\n .action(async (path: string, options: { dryRun?: boolean; connection?: string; json?: boolean }) => {\n const startPath = resolve(path);\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n if (options.json) {\n console.log(JSON.stringify({ success: false, error: 'yamchart.yaml not found' }));\n } else {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n }\n process.exit(2);\n }\n\n // Load .env file\n loadEnvFile(projectDir);\n\n if (!options.json) {\n output.header('Validating yamchart project...');\n }\n\n const result = await validateProject(projectDir, {\n dryRun: options.dryRun ?? false,\n connection: options.connection,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n // Print results\n for (const error of result.errors) {\n output.error(error.file);\n output.detail(error.message);\n if (error.suggestion) {\n output.detail(error.suggestion);\n }\n }\n\n for (const warning of result.warnings) {\n output.warning(warning.file);\n output.detail(warning.message);\n }\n\n output.newline();\n\n if (result.success) {\n output.success(`Schema: ${result.stats.passed} passed`);\n } else {\n output.error(`Schema: ${result.stats.passed} passed, ${result.stats.failed} failed`);\n }\n\n if (result.dryRunStats) {\n output.newline();\n if (result.dryRunStats.failed === 0) {\n output.success(`Queries: ${result.dryRunStats.passed} passed (EXPLAIN OK)`);\n } else {\n output.error(`Queries: ${result.dryRunStats.passed} passed, ${result.dryRunStats.failed} failed`);\n }\n }\n\n output.newline();\n\n if (result.success) {\n output.success('Validation passed');\n } else {\n output.error(`Validation failed with ${result.errors.length} error(s)`);\n }\n }\n\n process.exit(result.success ? 0 : 1);\n });\n\nprogram\n .command('dev')\n .description('Start development server with hot reload')\n .argument('[path]', 'Path to yamchart project', '.')\n .option('-p, --port <number>', 'Port to listen on', '3001')\n .option('--api-only', 'Only serve API, no web UI')\n .option('--no-open', 'Do not open browser automatically')\n .action(async (path: string, options: { port: string; apiOnly?: boolean; open: boolean }) => {\n const startPath = resolve(path);\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n const { runDevServer } = await import('./commands/dev.js');\n\n await runDevServer(projectDir, {\n port: parseInt(options.port, 10),\n apiOnly: options.apiOnly ?? false,\n open: options.open,\n });\n });\n\nprogram\n .command('init')\n .description('Create a new yamchart project')\n .argument('[directory]', 'Target directory', '.')\n .option('--example', 'Create full example project with sample database')\n .option('--empty', 'Create only yamchart.yaml (no connections, models, or charts)')\n .option('--force', 'Overwrite existing files')\n .action(async (directory: string, options: { example?: boolean; empty?: boolean; force?: boolean }) => {\n const { initProject } = await import('./commands/init.js');\n const targetDir = resolve(directory);\n\n const result = await initProject(targetDir, options);\n\n if (!result.success) {\n output.error(result.error || 'Failed to create project');\n process.exit(1);\n }\n\n output.newline();\n output.success(`Created ${directory === '.' ? basename(targetDir) : directory}/`);\n for (const file of result.files.slice(0, 10)) {\n output.detail(file);\n }\n if (result.files.length > 10) {\n output.detail(`... and ${result.files.length - 10} more files`);\n }\n output.newline();\n output.info(`Run \\`cd ${directory === '.' ? basename(targetDir) : directory} && yamchart dev\\` to start.`);\n });\n\nprogram\n .command('sync-dbt')\n .description('Sync dbt project metadata into AI-readable catalog')\n .option('-s, --source <type>', 'Source type: local, github, dbt-cloud', 'local')\n .option('-p, --path <dir>', 'Path to dbt project (for local source)')\n .option('--repo <repo>', 'GitHub repository (for github source)')\n .option('--branch <branch>', 'Git branch (for github source)', 'main')\n .option('-i, --include <patterns...>', 'Include glob patterns')\n .option('-e, --exclude <patterns...>', 'Exclude glob patterns')\n .option('-t, --tag <tags...>', 'Filter by dbt tags')\n .option('--refresh', 'Re-sync using saved configuration')\n .action(async (options: {\n source: 'local' | 'github' | 'dbt-cloud';\n path?: string;\n repo?: string;\n branch?: string;\n include?: string[];\n exclude?: string[];\n tag?: string[];\n refresh?: boolean;\n }) => {\n const { syncDbt, loadSyncConfig } = await import('./commands/sync-dbt.js');\n\n // Find project root\n const projectDir = await findProjectRoot(process.cwd());\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n // Handle refresh mode\n if (options.refresh) {\n const savedConfig = await loadSyncConfig(projectDir);\n if (!savedConfig) {\n output.error('No saved sync config found');\n output.detail('Run sync-dbt without --refresh first');\n process.exit(1);\n }\n output.info(`Re-syncing from ${savedConfig.source}:${savedConfig.path || savedConfig.repo}`);\n }\n\n const spin = output.spinner('Syncing dbt metadata...');\n\n const result = await syncDbt(projectDir, {\n source: options.source,\n path: options.path,\n repo: options.repo,\n branch: options.branch,\n include: options.include || [],\n exclude: options.exclude || [],\n tags: options.tag || [],\n refresh: options.refresh,\n });\n\n spin.stop();\n\n if (!result.success) {\n output.error(result.error || 'Sync failed');\n process.exit(1);\n }\n\n output.success(`Synced ${result.modelsIncluded} models to .yamchart/catalog.md`);\n if (result.modelsExcluded > 0) {\n output.detail(`${result.modelsExcluded} models filtered out`);\n }\n });\n\nprogram\n .command('generate')\n .description('Generate SQL model stubs from dbt catalog')\n .argument('[model]', 'Specific model to generate (optional)')\n .option('--yolo', 'Skip all prompts, use defaults for everything')\n .action(async (model: string | undefined, options: { yolo?: boolean }) => {\n const { generate } = await import('./commands/generate.js');\n\n const projectDir = await findProjectRoot(process.cwd());\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n const result = await generate(projectDir, {\n model,\n yolo: options.yolo,\n });\n\n if (!result.success) {\n output.error(result.error || 'Generate failed');\n process.exit(1);\n }\n\n output.success(`Generated ${result.filesCreated} model stubs`);\n if (result.filesSkipped > 0) {\n output.detail(`${result.filesSkipped} files skipped`);\n }\n });\n\nprogram\n .command('test')\n .description('Run model tests (@returns schema checks and @tests data assertions)')\n .argument('[model]', 'Specific model to test (optional, tests all if omitted)')\n .option('-c, --connection <name>', 'Connection to use (overrides default)')\n .option('--json', 'Output as JSON')\n .action(async (model: string | undefined, options: { connection?: string; json?: boolean }) => {\n const startPath = resolve('.');\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n if (options.json) {\n console.log(JSON.stringify({ success: false, error: 'yamchart.yaml not found' }));\n } else {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n }\n process.exit(2);\n }\n\n loadEnvFile(projectDir);\n\n try {\n const { testProject, formatTestOutput } = await import('./commands/test.js');\n const result = await testProject(projectDir, model, {\n connection: options.connection,\n json: options.json,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n } else {\n formatTestOutput(result, result.connectionName);\n }\n\n process.exit(result.success ? 0 : 1);\n } catch (err) {\n if (options.json) {\n console.log(\n JSON.stringify({ success: false, error: err instanceof Error ? err.message : String(err) }),\n );\n } else {\n output.error(err instanceof Error ? err.message : String(err));\n }\n process.exit(2);\n }\n });\n\nprogram\n .command('update')\n .description('Check for yamchart updates')\n .action(async () => {\n const { runUpdate } = await import('./commands/update.js');\n await runUpdate(pkg.version);\n });\n\nprogram\n .command('reset-password')\n .description('Reset a user password (requires auth to be enabled)')\n .requiredOption('-e, --email <email>', 'Email address of the user')\n .action(async (options: { email: string }) => {\n const startPath = resolve('.');\n const projectDir = await findProjectRoot(startPath);\n\n if (!projectDir) {\n output.error('yamchart.yaml not found');\n output.detail('Run this command from a yamchart project directory');\n process.exit(2);\n }\n\n loadEnvFile(projectDir);\n\n const { resetPassword } = await import('./commands/reset-password.js');\n await resetPassword(projectDir, options.email);\n });\n\nprogram.parse();\n\n// Passive update check — runs in background, prints on exit if outdated\nlet updateNotification: string | null = null;\n\ncheckForUpdate(pkg.version).then((update) => {\n if (update) {\n updateNotification = `\\n Update available: ${update.current} → ${update.latest}\\n Run: yamchart update\\n`;\n }\n});\n\nprocess.on('exit', () => {\n if (updateNotification) {\n // Use dim styling so it doesn't compete with command output\n console.error(`\\n${pc.dim(updateNotification)}`);\n }\n});\n"],"mappings":"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","names":["error","warning"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import "./chunk-DGUM43GV.js";
|
|
2
|
+
|
|
1
3
|
// src/commands/init.ts
|
|
2
4
|
import { mkdir, readFile, writeFile, access, readdir, copyFile } from "fs/promises";
|
|
3
5
|
import { join, dirname, basename } from "path";
|
|
@@ -115,4 +117,4 @@ async function copyDirectory(srcDir, destDir, files, projectName, basePath = "")
|
|
|
115
117
|
export {
|
|
116
118
|
initProject
|
|
117
119
|
};
|
|
118
|
-
//# sourceMappingURL=init-
|
|
120
|
+
//# sourceMappingURL=init-FTSEOTAD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import { mkdir, readFile, writeFile, access, readdir, copyFile } from 'fs/promises';\nimport { join, dirname, basename } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport interface InitOptions {\n empty?: boolean;\n example?: boolean;\n force?: boolean;\n}\n\nexport interface InitResult {\n success: boolean;\n files: string[];\n error?: string;\n}\n\n/**\n * Check if a directory exists and is accessible.\n */\nasync function directoryExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the templates directory path.\n * Handles both development (src/commands) and production (dist/) contexts.\n */\nasync function getTemplatesDir(): Promise<string> {\n // In production (dist/), templates are at dist/templates\n const distTemplates = join(__dirname, 'templates');\n if (await directoryExists(distTemplates)) {\n return distTemplates;\n }\n\n // In development (src/commands), templates are at src/templates\n const srcTemplates = join(__dirname, '../templates');\n if (await directoryExists(srcTemplates)) {\n return srcTemplates;\n }\n\n throw new Error('Templates not found. Reinstall yamchart or check installation.');\n}\n\n/**\n * Get the examples directory path.\n * Handles both development and production contexts.\n */\nasync function getExamplesDir(): Promise<string> {\n // In production (dist/): dist -> cli -> apps -> yamchart -> examples\n const distExamples = join(__dirname, '../../../examples');\n if (await directoryExists(distExamples)) {\n return distExamples;\n }\n\n // In development (src/commands): src/commands -> src -> cli -> apps -> yamchart -> examples\n const srcExamples = join(__dirname, '../../../../examples');\n if (await directoryExists(srcExamples)) {\n return srcExamples;\n }\n\n throw new Error('Example assets not found. Reinstall yamchart or use default mode.');\n}\n\nexport async function initProject(projectDir: string, options: InitOptions): Promise<InitResult> {\n const projectName = basename(projectDir);\n const files: string[] = [];\n\n // Check if yamchart.yaml already exists\n const yamchartYamlPath = join(projectDir, 'yamchart.yaml');\n try {\n await access(yamchartYamlPath);\n if (!options.force) {\n return {\n success: false,\n files: [],\n error: `${yamchartYamlPath} already exists. Use --force to overwrite.`,\n };\n }\n } catch {\n // File doesn't exist, continue\n }\n\n // Create project directory\n await mkdir(projectDir, { recursive: true });\n\n try {\n if (options.example) {\n // Copy example project\n const examplesDir = await getExamplesDir();\n await copyDirectory(examplesDir, projectDir, files, projectName);\n } else if (options.empty) {\n // Empty mode - only yamchart.yaml\n const templateDir = join(await getTemplatesDir(), 'empty');\n await copyTemplate(templateDir, projectDir, files, projectName);\n } else {\n // Default mode - minimal working project\n const templateDir = join(await getTemplatesDir(), 'default');\n await copyTemplate(templateDir, projectDir, files, projectName);\n }\n } catch (err) {\n return {\n success: false,\n files: [],\n error: err instanceof Error ? err.message : 'Failed to create project',\n };\n }\n\n return { success: true, files };\n}\n\nasync function copyTemplate(\n templateDir: string,\n targetDir: string,\n files: string[],\n projectName: string,\n basePath: string = ''\n): Promise<void> {\n const entries = await readdir(templateDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(templateDir, entry.name);\n const destPath = join(targetDir, entry.name);\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n await mkdir(destPath, { recursive: true });\n await copyTemplate(srcPath, destPath, files, projectName, relativePath);\n } else {\n let content = await readFile(srcPath, 'utf-8');\n content = content.replace(/\\{\\{name\\}\\}/g, projectName);\n await writeFile(destPath, content, 'utf-8');\n files.push(relativePath);\n }\n }\n}\n\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n files: string[],\n projectName: string,\n basePath: string = ''\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n // Skip node_modules, lock files, and hidden files\n if (\n entry.name === 'node_modules' ||\n entry.name === 'pnpm-lock.yaml' ||\n entry.name === 'package-lock.json' ||\n entry.name === 'yarn.lock' ||\n entry.name === 'package.json' ||\n entry.name.startsWith('.')\n ) {\n continue;\n }\n\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n await mkdir(destPath, { recursive: true });\n await copyDirectory(srcPath, destPath, files, projectName, relativePath);\n } else {\n // For binary files (like .duckdb), copy directly\n if (entry.name.endsWith('.duckdb')) {\n await copyFile(srcPath, destPath);\n } else {\n // For text files, replace project name in yamchart.yaml\n let content = await readFile(srcPath, 'utf-8');\n if (entry.name === 'yamchart.yaml') {\n content = content.replace(/^name:\\s*\\S+/m, `name: ${projectName}`);\n }\n await writeFile(destPath, content, 'utf-8');\n }\n files.push(relativePath);\n }\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import { mkdir, readFile, writeFile, access, readdir, copyFile } from 'fs/promises';\nimport { join, dirname, basename } from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport interface InitOptions {\n empty?: boolean;\n example?: boolean;\n force?: boolean;\n}\n\nexport interface InitResult {\n success: boolean;\n files: string[];\n error?: string;\n}\n\n/**\n * Check if a directory exists and is accessible.\n */\nasync function directoryExists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the templates directory path.\n * Handles both development (src/commands) and production (dist/) contexts.\n */\nasync function getTemplatesDir(): Promise<string> {\n // In production (dist/), templates are at dist/templates\n const distTemplates = join(__dirname, 'templates');\n if (await directoryExists(distTemplates)) {\n return distTemplates;\n }\n\n // In development (src/commands), templates are at src/templates\n const srcTemplates = join(__dirname, '../templates');\n if (await directoryExists(srcTemplates)) {\n return srcTemplates;\n }\n\n throw new Error('Templates not found. Reinstall yamchart or check installation.');\n}\n\n/**\n * Get the examples directory path.\n * Handles both development and production contexts.\n */\nasync function getExamplesDir(): Promise<string> {\n // In production (dist/): dist -> cli -> apps -> yamchart -> examples\n const distExamples = join(__dirname, '../../../examples');\n if (await directoryExists(distExamples)) {\n return distExamples;\n }\n\n // In development (src/commands): src/commands -> src -> cli -> apps -> yamchart -> examples\n const srcExamples = join(__dirname, '../../../../examples');\n if (await directoryExists(srcExamples)) {\n return srcExamples;\n }\n\n throw new Error('Example assets not found. Reinstall yamchart or use default mode.');\n}\n\nexport async function initProject(projectDir: string, options: InitOptions): Promise<InitResult> {\n const projectName = basename(projectDir);\n const files: string[] = [];\n\n // Check if yamchart.yaml already exists\n const yamchartYamlPath = join(projectDir, 'yamchart.yaml');\n try {\n await access(yamchartYamlPath);\n if (!options.force) {\n return {\n success: false,\n files: [],\n error: `${yamchartYamlPath} already exists. Use --force to overwrite.`,\n };\n }\n } catch {\n // File doesn't exist, continue\n }\n\n // Create project directory\n await mkdir(projectDir, { recursive: true });\n\n try {\n if (options.example) {\n // Copy example project\n const examplesDir = await getExamplesDir();\n await copyDirectory(examplesDir, projectDir, files, projectName);\n } else if (options.empty) {\n // Empty mode - only yamchart.yaml\n const templateDir = join(await getTemplatesDir(), 'empty');\n await copyTemplate(templateDir, projectDir, files, projectName);\n } else {\n // Default mode - minimal working project\n const templateDir = join(await getTemplatesDir(), 'default');\n await copyTemplate(templateDir, projectDir, files, projectName);\n }\n } catch (err) {\n return {\n success: false,\n files: [],\n error: err instanceof Error ? err.message : 'Failed to create project',\n };\n }\n\n return { success: true, files };\n}\n\nasync function copyTemplate(\n templateDir: string,\n targetDir: string,\n files: string[],\n projectName: string,\n basePath: string = ''\n): Promise<void> {\n const entries = await readdir(templateDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = join(templateDir, entry.name);\n const destPath = join(targetDir, entry.name);\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n await mkdir(destPath, { recursive: true });\n await copyTemplate(srcPath, destPath, files, projectName, relativePath);\n } else {\n let content = await readFile(srcPath, 'utf-8');\n content = content.replace(/\\{\\{name\\}\\}/g, projectName);\n await writeFile(destPath, content, 'utf-8');\n files.push(relativePath);\n }\n }\n}\n\nasync function copyDirectory(\n srcDir: string,\n destDir: string,\n files: string[],\n projectName: string,\n basePath: string = ''\n): Promise<void> {\n const entries = await readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n // Skip node_modules, lock files, and hidden files\n if (\n entry.name === 'node_modules' ||\n entry.name === 'pnpm-lock.yaml' ||\n entry.name === 'package-lock.json' ||\n entry.name === 'yarn.lock' ||\n entry.name === 'package.json' ||\n entry.name.startsWith('.')\n ) {\n continue;\n }\n\n const srcPath = join(srcDir, entry.name);\n const destPath = join(destDir, entry.name);\n const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;\n\n if (entry.isDirectory()) {\n await mkdir(destPath, { recursive: true });\n await copyDirectory(srcPath, destPath, files, projectName, relativePath);\n } else {\n // For binary files (like .duckdb), copy directly\n if (entry.name.endsWith('.duckdb')) {\n await copyFile(srcPath, destPath);\n } else {\n // For text files, replace project name in yamchart.yaml\n let content = await readFile(srcPath, 'utf-8');\n if (entry.name === 'yamchart.yaml') {\n content = content.replace(/^name:\\s*\\S+/m, `name: ${projectName}`);\n }\n await writeFile(destPath, content, 'utf-8');\n }\n files.push(relativePath);\n }\n }\n}\n"],"mappings":"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","names":[]}
|