UNPKG

angular-translation-checker

Version:

A comprehensive tool for analyzing translation keys in Angular projects using ngx-translate

283 lines 11.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.ConfigurationManager = exports.DEFAULT_CONFIG = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const types_1 = require("../types"); exports.DEFAULT_CONFIG = { localesPath: './src/assets/i18n', srcPath: './src', patterns: { typescript: ['**/*.ts', '**/*.tsx'], html: ['**/*.html'], javascript: ['**/*.js', '**/*.jsx'] }, ignoreKeys: [], ignoreDynamicKeys: false, languages: [], excludeDirs: ['node_modules', 'dist', '.git', '.angular', 'coverage'], outputFormat: 'console', outputSections: ['summary', 'dynamicPatterns', 'ignored', 'unused', 'missing'], exitOnIssues: false, verbose: false, plugins: [] }; class ConfigurationManager { constructor(logger) { this.logger = logger; } /** * Load configuration from file and merge with defaults */ async loadConfig(configPath) { const config = { ...exports.DEFAULT_CONFIG }; if (configPath) { const fileConfig = await this.loadConfigFile(configPath); return this.mergeConfigs(config, fileConfig); } // Try to find config file automatically const autoConfigPath = await this.findConfigFile(); if (autoConfigPath) { this.logger.debug(`Found configuration file: ${autoConfigPath}`); const fileConfig = await this.loadConfigFile(autoConfigPath); return this.mergeConfigs(config, fileConfig); } this.logger.debug('No configuration file found, using defaults'); return config; } /** * Load configuration from a specific file */ async loadConfigFile(filePath) { const resolvedPath = path.resolve(filePath); try { if (!fs.existsSync(resolvedPath)) { throw new types_1.ConfigurationError(`Configuration file not found: ${resolvedPath}`); } const content = fs.readFileSync(resolvedPath, 'utf8'); const config = JSON.parse(content); this.validateConfig(config); return config; } catch (error) { if (error instanceof types_1.ConfigurationError) { throw error; } throw new types_1.ConfigurationError(`Failed to load configuration from ${resolvedPath}: ${error}`, { filePath: resolvedPath, originalError: error }); } } /** * Find configuration file automatically */ async findConfigFile() { const possiblePaths = [ './angular-translation-checker.config.json', './i18n-checker.config.json', './translation-checker.config.json', './package.json' ]; for (const configPath of possiblePaths) { const resolvedPath = path.resolve(configPath); if (fs.existsSync(resolvedPath)) { if (configPath.endsWith('package.json')) { // Check if package.json has angular-translation-checker config try { const packageJson = JSON.parse(fs.readFileSync(resolvedPath, 'utf8')); if (packageJson['angular-translation-checker']) { return resolvedPath; } } catch { continue; } } else { return resolvedPath; } } } return null; } /** * Merge configurations with deep merge logic */ mergeConfigs(base, override) { const result = { ...base }; for (const [key, value] of Object.entries(override)) { if (value === undefined || value === null) { continue; } const typedKey = key; if (typeof value === 'object' && !Array.isArray(value) && base[typedKey]) { // Deep merge for nested objects result[typedKey] = { ...base[typedKey], ...value }; } else { // Direct assignment for primitives and arrays result[typedKey] = value; } } return result; } /** * Validate configuration object */ validateConfig(config) { if (typeof config !== 'object' || config === null) { throw new types_1.ConfigurationError('Configuration must be an object'); } // Validate required paths if (config.localesPath && typeof config.localesPath !== 'string') { throw new types_1.ConfigurationError('localesPath must be a string'); } if (config.srcPath && typeof config.srcPath !== 'string') { throw new types_1.ConfigurationError('srcPath must be a string'); } // Validate arrays const arrayFields = ['ignoreKeys', 'languages', 'excludeDirs', 'outputSections']; for (const field of arrayFields) { if (config[field] && !Array.isArray(config[field])) { throw new types_1.ConfigurationError(`${field} must be an array`); } } // Validate output format if (config.outputFormat) { const validFormats = ['console', 'json', 'csv', 'xml', 'html']; if (!validFormats.includes(config.outputFormat)) { throw new types_1.ConfigurationError(`Invalid outputFormat '${config.outputFormat}'. Valid options: ${validFormats.join(', ')}`); } } // Validate output sections if (config.outputSections) { const validSections = [ 'summary', 'dynamicPatterns', 'ignored', 'unused', 'missing', 'usedKeys', 'translationKeys', 'config' ]; for (const section of config.outputSections) { if (!validSections.includes(section)) { throw new types_1.ConfigurationError(`Invalid output section '${section}'. Valid options: ${validSections.join(', ')}`); } } } // Validate patterns if (config.patterns) { if (typeof config.patterns !== 'object') { throw new types_1.ConfigurationError('patterns must be an object'); } for (const [key, patterns] of Object.entries(config.patterns)) { if (!Array.isArray(patterns)) { throw new types_1.ConfigurationError(`patterns.${key} must be an array`); } for (const pattern of patterns) { if (typeof pattern !== 'string') { throw new types_1.ConfigurationError(`All patterns in patterns.${key} must be strings`); } } } } // Validate plugins if (config.plugins) { if (!Array.isArray(config.plugins)) { throw new types_1.ConfigurationError('plugins must be an array'); } for (const plugin of config.plugins) { if (typeof plugin !== 'object' || !plugin.name) { throw new types_1.ConfigurationError('Each plugin must be an object with a name property'); } } } } /** * Generate a default configuration file */ async generateConfigFile(outputPath = './angular-translation-checker.config.json') { const configTemplate = { ...exports.DEFAULT_CONFIG, // Add comments as properties (will be filtered out) $schema: 'Configuration schema for Angular Translation Checker', $description: { localesPath: 'Path to translation files directory', srcPath: 'Path to source code directory', patterns: 'File patterns to analyze by file type', ignoreKeys: 'Translation keys to ignore (supports wildcards)', ignoreDynamicKeys: 'Whether to ignore dynamically constructed keys', languages: 'Specific languages to analyze (empty = auto-detect)', excludeDirs: 'Directories to exclude from analysis', outputFormat: 'Output format: console, json, csv, xml, html', outputSections: 'Sections to include in output', exitOnIssues: 'Exit with error code if issues found', verbose: 'Enable verbose logging', plugins: 'Plugin configurations' } }; try { const content = JSON.stringify(configTemplate, null, 2); fs.writeFileSync(outputPath, content, 'utf8'); this.logger.info(`Configuration file generated: ${outputPath}`); } catch (error) { throw new types_1.ConfigurationError(`Failed to generate configuration file: ${error}`, { outputPath, originalError: error }); } } /** * Validate paths exist */ async validatePaths(config) { const errors = []; // Check locales path if (!fs.existsSync(config.localesPath)) { errors.push(`Locales path does not exist: ${config.localesPath}`); } else if (!fs.statSync(config.localesPath).isDirectory()) { errors.push(`Locales path is not a directory: ${config.localesPath}`); } // Check source path if (!fs.existsSync(config.srcPath)) { errors.push(`Source path does not exist: ${config.srcPath}`); } else if (!fs.statSync(config.srcPath).isDirectory()) { errors.push(`Source path is not a directory: ${config.srcPath}`); } if (errors.length > 0) { throw new types_1.ConfigurationError(`Configuration validation failed:\n${errors.join('\n')}`, { errors }); } } } exports.ConfigurationManager = ConfigurationManager; //# sourceMappingURL=config-manager.js.map