Functions for loading, validating, and working with Lightdash project configurations.
This module provides the following functionality:
/**
* Loads Lightdash project configuration from lightdash.yml file
* Validates and parses the configuration with error handling
* @param projectDir - Path to project directory containing lightdash.yml
* @returns Parsed and validated project configuration
* @throws Error if configuration is invalid or file cannot be read
*/
function loadLightdashProjectConfig(projectDir: string): Promise<LightdashProjectConfig>;/**
* Gets the project directory from DBT connection configuration
* @param dbtConnection - Optional DBT project configuration
* @returns Project directory path or undefined
*/
function getProjectDirectory(
dbtConnection?: DbtProjectConfig
): string | undefined;import { loadLightdashProjectConfig } from '@lightdash/common';
// Load project configuration
try {
const config = await loadLightdashProjectConfig('/path/to/dbt/project');
console.log('Project name:', config.name);
console.log('DBT project:', config.dbt_project_dir);
console.log('DBT profiles:', config.dbt_profiles_dir);
// Access model configuration
if (config.models) {
console.log('Model overrides:', Object.keys(config.models));
}
// Access metric overrides
if (config.metrics) {
console.log('Metric overrides:', Object.keys(config.metrics));
}
} catch (error) {
console.error('Failed to load project config:', error.message);
}
// Use in CLI or API
const projectConfig = await loadLightdashProjectConfig(process.cwd());import { getProjectDirectory } from '@lightdash/common';
// Get project directory from DBT connection
const dbtConnection: DbtProjectConfig = {
type: 'dbt_cloud_ide',
target: 'dev',
project_dir: '/home/user/my-dbt-project',
profiles_dir: '/home/user/.dbt',
};
const projectDir = getProjectDirectory(dbtConnection);
console.log('Project directory:', projectDir);
// Output: '/home/user/my-dbt-project'
// Handle missing configuration
const emptyDir = getProjectDirectory();
console.log('Directory:', emptyDir); // undefinedimport { loadLightdashProjectConfig } from '@lightdash/common';
async function validateProjectSetup(projectPath: string): Promise<boolean> {
try {
const config = await loadLightdashProjectConfig(projectPath);
// Verify required fields
if (!config.name) {
console.error('Project name is required');
return false;
}
if (!config.dbt_project_dir) {
console.error('DBT project directory is required');
return false;
}
console.log('Project configuration is valid');
return true;
} catch (error) {
console.error('Invalid configuration:', error.message);
return false;
}
}import { loadLightdashProjectConfig, getProjectDirectory } from '@lightdash/common';
// Node.js built-in (server-side only)
import path from 'path';
async function deployProject(options: { projectDir?: string }) {
// Determine project directory
const projectDir = options.projectDir || process.cwd();
// Load configuration
const config = await loadLightdashProjectConfig(projectDir);
console.log(`Deploying project: ${config.name}`);
// Get DBT project directory
const dbtProjectDir = config.dbt_project_dir || path.join(projectDir, 'dbt');
console.log(`DBT project directory: ${dbtProjectDir}`);
// Use configuration for deployment
await deployToLightdash(config);
}
// Usage
deployProject({ projectDir: '/path/to/project' });import { loadLightdashProjectConfig } from '@lightdash/common';
async function inspectProject(projectPath: string) {
const config = await loadLightdashProjectConfig(projectPath);
console.log('=== Project Configuration ===');
console.log(`Name: ${config.name}`);
console.log(`DBT Project: ${config.dbt_project_dir}`);
console.log(`DBT Profiles: ${config.dbt_profiles_dir}`);
// List model overrides
if (config.models && Object.keys(config.models).length > 0) {
console.log('\nModel Overrides:');
for (const [modelName, modelConfig] of Object.entries(config.models)) {
console.log(` - ${modelName}`);
if (modelConfig.enabled !== undefined) {
console.log(` Enabled: ${modelConfig.enabled}`);
}
}
}
// List metric overrides
if (config.metrics && Object.keys(config.metrics).length > 0) {
console.log('\nMetric Overrides:');
for (const [metricName, metricConfig] of Object.entries(config.metrics)) {
console.log(` - ${metricName}`);
}
}
}import { loadLightdashProjectConfig } from '@lightdash/common';
// Node.js built-in (server-side only)
import fs from 'fs/promises';
async function migrateProjectConfig(oldPath: string, newPath: string) {
// Load old configuration
const config = await loadLightdashProjectConfig(oldPath);
console.log(`Migrating project: ${config.name}`);
// Update paths for new location
const updatedConfig = {
...config,
dbt_project_dir: config.dbt_project_dir?.replace(oldPath, newPath),
dbt_profiles_dir: config.dbt_profiles_dir?.replace(oldPath, newPath),
};
// Save to new location
const yamlContent = YAML.stringify(updatedConfig);
await fs.writeFile(
path.join(newPath, 'lightdash.yml'),
yamlContent
);
console.log('Migration complete');
}import type { LightdashProjectConfig } from '@lightdash/common';
function createProjectConfig(options: {
name: string;
dbtProjectDir: string;
dbtProfilesDir?: string;
}): LightdashProjectConfig {
return {
name: options.name,
dbt_project_dir: options.dbtProjectDir,
dbt_profiles_dir: options.dbtProfilesDir || '~/.dbt',
models: {},
metrics: {},
};
}
// Usage
const config = createProjectConfig({
name: 'my-analytics-project',
dbtProjectDir: './dbt',
});import { loadLightdashProjectConfig } from '@lightdash/common';
// API endpoint to get project configuration
app.get('/api/projects/:id/config', async (req, res) => {
try {
const project = await getProject(req.params.id);
const projectPath = getProjectPath(project);
const config = await loadLightdashProjectConfig(projectPath);
// Return sanitized configuration (without sensitive data)
res.json({
name: config.name,
dbtProjectDir: config.dbt_project_dir,
modelCount: Object.keys(config.models || {}).length,
metricCount: Object.keys(config.metrics || {}).length,
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});import { loadLightdashProjectConfig, getProjectDirectory } from '@lightdash/common';
describe('Project configuration', () => {
it('should load valid configuration', async () => {
const config = await loadLightdashProjectConfig('./test-fixtures/valid-project');
expect(config.name).toBe('Test Project');
expect(config.dbt_project_dir).toBeDefined();
});
it('should throw on invalid configuration', async () => {
await expect(
loadLightdashProjectConfig('./test-fixtures/invalid-project')
).rejects.toThrow();
});
it('should extract project directory', () => {
const dbtConfig = {
type: 'dbt_cloud_ide',
project_dir: '/path/to/project',
};
const dir = getProjectDirectory(dbtConfig);
expect(dir).toBe('/path/to/project');
});
});The lightdash.yml file typically contains:
name: my-project
dbt_project_dir: ./dbt
dbt_profiles_dir: ~/.dbt
models:
my_model:
enabled: true
meta:
lightdash:
label: "My Model"
metrics:
my_metric:
enabled: falseimport { loadLightdashProjectConfig } from '@lightdash/common';
async function safeLoadConfig(projectPath: string) {
try {
return await loadLightdashProjectConfig(projectPath);
} catch (error) {
if (error.code === 'ENOENT') {
console.error('lightdash.yml not found in project directory');
} else if (error.name === 'YAMLException') {
console.error('Invalid YAML syntax in lightdash.yml');
} else {
console.error('Failed to load configuration:', error.message);
}
return null;
}
}