baseline-lint
Version:
Check web features for Baseline compatibility
309 lines (264 loc) • 7.35 kB
JavaScript
// src/config/config.js
// Configuration management for baseline-lint
import fs from 'fs/promises';
import path from 'path';
import { ValidationError } from '../utils/error-handler.js';
/**
* Default configuration
*/
export const DEFAULT_CONFIG = {
// Baseline level requirements
requiredLevel: 'low', // 'low' (newly) or 'high' (widely)
// Output formatting
format: 'text', // 'text', 'json', 'markdown'
// Filtering options
noWarnings: false,
failOnError: false,
// File processing
cssOnly: false,
jsOnly: false,
// Cache settings
cache: {
enabled: true,
bcdCacheSize: 5000,
featureCacheSize: 1000,
ttl: 3600000 // 1 hour in milliseconds
},
// File patterns
patterns: {
css: ['**/*.css'],
js: ['**/*.{js,jsx,ts,tsx}'],
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**']
},
// Analysis options
analysis: {
includeComments: false,
strictMode: false,
maxFileSize: 50 * 1024 * 1024, // 50MB
timeout: 30000 // 30 seconds
},
// Dashboard settings
dashboard: {
port: 3000,
host: 'localhost',
cors: {
enabled: true,
origins: ['http://localhost:3000', 'http://127.0.0.1:3000']
},
rateLimit: {
enabled: true,
maxRequests: 100,
windowMs: 60000 // 1 minute
}
},
// CI/CD settings
ci: {
commentOnPR: true,
failOnError: true,
reportFormat: 'markdown'
}
};
/**
* Configuration file names to look for
*/
const CONFIG_FILES = [
'baseline-lint.json',
'baseline-lint.config.js',
'.baseline-lintrc',
'.baseline-lintrc.json',
'package.json'
];
/**
* Load configuration from file
*/
export async function loadConfig(configPath = null) {
let config = { ...DEFAULT_CONFIG };
if (configPath) {
// Load from specific path
try {
const fileConfig = await loadConfigFile(configPath);
config = mergeConfigs(config, fileConfig);
} catch (error) {
throw new ValidationError(`Failed to load config from ${configPath}: ${error.message}`);
}
} else {
// Auto-discover config file
const discoveredConfig = await discoverConfig();
if (discoveredConfig) {
config = mergeConfigs(config, discoveredConfig);
}
}
// Validate configuration
validateConfig(config);
return config;
}
/**
* Load configuration from a specific file
*/
async function loadConfigFile(filePath) {
const ext = path.extname(filePath).toLowerCase();
if (ext === '.js') {
// Dynamic import for .js config files
const configModule = await import(path.resolve(filePath));
return configModule.default || configModule;
} else if (ext === '.json' || filePath.endsWith('.baseline-lintrc')) {
const content = await fs.readFile(filePath, 'utf-8');
return JSON.parse(content);
} else {
throw new ValidationError(`Unsupported config file format: ${ext}`);
}
}
/**
* Auto-discover configuration file
*/
async function discoverConfig() {
const cwd = process.cwd();
for (const configFile of CONFIG_FILES) {
const configPath = path.join(cwd, configFile);
try {
await fs.access(configPath);
if (configFile === 'package.json') {
// Extract baseline-lint config from package.json
const pkg = JSON.parse(await fs.readFile(configPath, 'utf-8'));
return pkg['baseline-lint'] || null;
} else {
return await loadConfigFile(configPath);
}
} catch (error) {
// File doesn't exist, continue
continue;
}
}
return null;
}
/**
* Merge two configuration objects
*/
function mergeConfigs(base, override) {
const merged = { ...base };
for (const [key, value] of Object.entries(override)) {
if (value && typeof value === 'object' && !Array.isArray(value)) {
merged[key] = mergeConfigs(merged[key] || {}, value);
} else {
merged[key] = value;
}
}
return merged;
}
/**
* Validate configuration
*/
function validateConfig(config) {
// Validate required level
if (!['low', 'high'].includes(config.requiredLevel)) {
throw new ValidationError('requiredLevel must be "low" or "high"');
}
// Validate format
if (!['text', 'json', 'markdown'].includes(config.format)) {
throw new ValidationError('format must be "text", "json", or "markdown"');
}
// Validate cache settings
if (config.cache.enabled && typeof config.cache.bcdCacheSize !== 'number') {
throw new ValidationError('cache.bcdCacheSize must be a number');
}
if (config.cache.enabled && typeof config.cache.featureCacheSize !== 'number') {
throw new ValidationError('cache.featureCacheSize must be a number');
}
// Validate analysis settings
if (config.analysis.maxFileSize <= 0) {
throw new ValidationError('analysis.maxFileSize must be positive');
}
if (config.analysis.timeout <= 0) {
throw new ValidationError('analysis.timeout must be positive');
}
// Validate dashboard settings
if (config.dashboard.port < 1 || config.dashboard.port > 65535) {
throw new ValidationError('dashboard.port must be between 1 and 65535');
}
if (config.dashboard.rateLimit.enabled && config.dashboard.rateLimit.maxRequests <= 0) {
throw new ValidationError('dashboard.rateLimit.maxRequests must be positive');
}
}
/**
* Create a sample configuration file
*/
export async function createSampleConfig(filePath = 'baseline-lint.json') {
const sampleConfig = {
"$schema": "https://raw.githubusercontent.com/yourusername/baseline-lint/main/schema.json",
"requiredLevel": "low",
"format": "text",
"noWarnings": false,
"failOnError": false,
"cssOnly": false,
"jsOnly": false,
"cache": {
"enabled": true,
"bcdCacheSize": 5000,
"featureCacheSize": 1000
},
"patterns": {
"css": ["**/*.css"],
"js": ["**/*.{js,jsx,ts,tsx}"],
"ignore": ["**/node_modules/**", "**/dist/**", "**/build/**"]
},
"analysis": {
"includeComments": false,
"strictMode": false,
"maxFileSize": 52428800,
"timeout": 30000
},
"dashboard": {
"port": 3000,
"host": "localhost",
"cors": {
"enabled": true,
"origins": ["http://localhost:3000"]
},
"rateLimit": {
"enabled": true,
"maxRequests": 100,
"windowMs": 60000
}
},
"ci": {
"commentOnPR": true,
"failOnError": true,
"reportFormat": "markdown"
}
};
await fs.writeFile(filePath, JSON.stringify(sampleConfig, null, 2));
return filePath;
}
/**
* Get configuration for specific command
*/
export function getCommandConfig(command, options = {}) {
const config = { ...DEFAULT_CONFIG };
// Override with command-specific options
if (options.level) {
config.requiredLevel = options.level === 'widely' ? 'high' : 'low';
}
if (options.format) {
config.format = options.format;
}
if (options.noWarnings) {
config.noWarnings = true;
}
if (options.failOnError) {
config.failOnError = true;
}
if (options.cssOnly) {
config.cssOnly = true;
}
if (options.jsOnly) {
config.jsOnly = true;
}
return config;
}
/**
* Export configuration utilities
*/
export {
CONFIG_FILES,
DEFAULT_CONFIG as defaultConfig
};