angular-translation-checker
Version:
A comprehensive tool for analyzing translation keys in Angular projects using ngx-translate
283 lines • 11.5 kB
JavaScript
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
;