From 223f2565b668dca9ea94f9d87ce89ba84a630f91 Mon Sep 17 00:00:00 2001 From: romanlavrinjuk Date: Wed, 30 Oct 2024 13:03:13 +0100 Subject: [PATCH] feat: Fix Option for Removing Zombies Close #153 --- README.md | 5 +++ src/cli/cli.ts | 7 +++- src/cli/dictionaries/CliOptions.ts | 9 ++++ src/cli/enums/OptionsNames.ts | 2 + src/cli/utils/index.ts | 1 - src/core/client.ts | 48 +++++++++++++++++----- src/core/config.ts | 3 +- src/core/interface/IAppConfig.ts | 1 + src/{cli => core}/utils/file.ts | 12 ++++-- src/core/utils/index.ts | 1 + test/integration/config/custom.config.json | 2 +- 11 files changed, 73 insertions(+), 18 deletions(-) delete mode 100644 src/cli/utils/index.ts rename src/{cli => core}/utils/file.ts (71%) diff --git a/README.md b/README.md index 2217388..06c8b0e 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,9 @@ Options: (default: "0.9") -c, --config [path] Path to the config file. + -fz, --fixZombiesKeys [boolean] + Auto fix zombies keys on languages files + (default: "false") -V, --version output the version number @@ -127,6 +130,7 @@ Default Config is: "ignoredMisprintKeys": [], "customRegExpToFindKeys": [ "(?<=marker\\(['\"])([A-Za-z0-9_\\-.]+)(?=['\"]\\))"], // to find: marker('TRSNLATE.KEY'); }, + "fixZombiesKeys": false, "project": "./src/app/**/*.{html,ts}", "languages": "./src/assets/i18n/*.json" } @@ -180,6 +184,7 @@ const ruleConfig: IRulesConfig = { emptyKeys: ErrorTypes.warning, maxWarning: 0, misprintCoefficient: 0.9, + fixZombiesKeys: false, ignoredKeys: [ 'EXAMPLE.KEY', 'IGNORED.KEY.(.*)' ], // can be string or RegExp ignoredMisprintKeys: [], customRegExpToFindKeys: [ "(?<=marker\\(['\"])([A-Za-z0-9_\\-.]+)(?=['\"]\\))" ] // to find: marker('TRSNLATE.KEY'); diff --git a/src/cli/cli.ts b/src/cli/cli.ts index f7047b5..2c4206b 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -10,13 +10,14 @@ import { ResultCliModel, ResultModel, StatusCodes, - ToggleRule + ToggleRule, + parseJsonFile, + getPackageJsonPath, } from "./../core"; import { config } from './../core/config'; import { OptionsLongNames, OptionsShortNames } from './enums'; import chalk from 'chalk'; -import { parseJsonFile, getPackageJsonPath } from './utils'; import { defaultConfig } from 'sinon'; const name: string = 'ngx-translate-lint'; @@ -81,6 +82,7 @@ class Cli { const projectPath: string = this.cliClient.project !== config.defaultValues.projectPath ? this.cliClient.project : options.project; const languagePath: string = this.cliClient.languages !== config.defaultValues.languagesPath? this.cliClient.languages : options.languages; + const fixZombiesKeys: boolean = this.cliClient.fixZombiesKeys !== config.defaultValues.fixZombiesKeys ? this.cliClient.fixZombiesKeys : options.fixZombiesKeys; const tsConfigPath: string = options.tsConfigPath; @@ -180,6 +182,7 @@ class Cli { ignoredMisprintKeys: string[] = [], customRegExpToFindKeys: string[] | RegExp[] = [], tsConfigPath?: string, + fixZombiesKeys?: boolean, ): void { const errorConfig: IRulesConfig = { misprintKeys: misprint || ErrorTypes.disable, diff --git a/src/cli/dictionaries/CliOptions.ts b/src/cli/dictionaries/CliOptions.ts index 50946d0..6ffdc17 100644 --- a/src/cli/dictionaries/CliOptions.ts +++ b/src/cli/dictionaries/CliOptions.ts @@ -146,6 +146,15 @@ const cliOptions: OptionModel[] = [ OptionsPath.absolute ] }), + new OptionModel({ + longName: OptionsLongNames.fixZombiesKeys, + shortName: OptionsShortNames.fixZombiesKeys, + required: false, + type: ArgumentTypes.boolean, + description: `Auto fix zombies keys on languages files`, + additionalDescription: ``, + default: config.defaultValues.fixZombiesKeys?.toString() || 'false', + }), new OptionModel({ longName: OptionsLongNames.version, shortName: OptionsShortNames.version, diff --git a/src/cli/enums/OptionsNames.ts b/src/cli/enums/OptionsNames.ts index 2f4a216..d081a05 100644 --- a/src/cli/enums/OptionsNames.ts +++ b/src/cli/enums/OptionsNames.ts @@ -11,6 +11,7 @@ enum OptionsLongNames { zombieKeys = 'zombieKeys', keysOnViews = 'keysOnViews', misprintKeys = 'misprintKeys', + fixZombiesKeys = 'fixZombiesKeys', misprintCoefficient = 'misprintCoefficient', } @@ -25,6 +26,7 @@ enum OptionsShortNames { zombieKeys = 'zk', keysOnViews = 'kv', misprintKeys = 'mk', + fixZombiesKeys = 'fz', misprintCoefficient = 'mc', } diff --git a/src/cli/utils/index.ts b/src/cli/utils/index.ts deleted file mode 100644 index 706b0d2..0000000 --- a/src/cli/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './file'; diff --git a/src/core/client.ts b/src/core/client.ts index 6e25608..629e084 100644 --- a/src/core/client.ts +++ b/src/core/client.ts @@ -1,21 +1,22 @@ -import { flatMap } from 'lodash'; +import { flatMap, omit } from 'lodash'; import * as path from 'path'; import { config } from './config'; -import { ErrorTypes } from './enums'; +import { ErrorFlow, ErrorTypes } from './enums'; import { IRulesConfig } from './interface'; -import { KeysUtils } from './utils'; +import { getPackageJsonPath, KeysUtils, parseJsonFile, saveJsonFile } from './utils'; import { FileLanguageModel, FileViewModel, KeyModel, LanguagesModel, ResultCliModel, ResultErrorModel } from './models'; -import { AbsentViewKeysRule, MisprintRule, ZombieRule, EmptyKeysRule } from './rules'; +import { AbsentViewKeysRule, EmptyKeysRule, MisprintRule, ZombieRule } from './rules'; import { KeyModelWithLanguages, LanguagesModelWithKey, ViewModelWithKey } from './models/KeyModelWithLanguages'; + class NgxTranslateLint { public rules: IRulesConfig; + public ignore?: string; public projectPath: string; - public languagesPath: string; public tsConfigPath: string | undefined; - - public ignore?: string; + public languagesPath: string; + public fixZombiesKeys: boolean | undefined; constructor ( projectPath: string = config.defaultValues.projectPath, @@ -23,12 +24,14 @@ class NgxTranslateLint { ignore?: string, rulesConfig: IRulesConfig = config.defaultValues.rules, tsConfigPath?: string, + fixZombiesKeys?: boolean, ) { - this.languagesPath = languagesPath; - this.projectPath = projectPath; this.ignore = ignore; this.rules = rulesConfig; + this.projectPath = projectPath; this.tsConfigPath = tsConfigPath; + this.languagesPath = languagesPath; + this.fixZombiesKeys = fixZombiesKeys; } public lint(maxWarning?: number): ResultCliModel { @@ -189,9 +192,34 @@ class NgxTranslateLint { result.push(...ruleResult); } + if (!!this.fixZombiesKeys) { + const allZombiesKeys: ResultErrorModel[] = result.filter((error) => { + return error.errorFlow === ErrorFlow.zombieKeys; + }); + + const filesAndKeys: FileLanguageModel[] = allZombiesKeys.reduce((acum: FileLanguageModel[], item: ResultErrorModel) => { + const existingFileLanguage: FileLanguageModel | undefined = acum.find((x) => x.path === item.currentPath) ; + if (!!existingFileLanguage) { + existingFileLanguage.keys.push(new KeyModel(item.value)); + } else { + const newFileLanguage: FileLanguageModel = new FileLanguageModel(item.currentPath, [], [new KeyModel(item.value)]); + acum.push(newFileLanguage); + } + return acum; + }, []); + + filesAndKeys.forEach((languageFile: FileLanguageModel) => { + // tslint:disable-next-line:no-any + const jsonData: any = parseJsonFile(languageFile.path); + const keysArray: string[] = languageFile.keys.map((x) => x.name); + // tslint:disable-next-line:no-any + const resultData: any = omit(jsonData, keysArray); + saveJsonFile(resultData, languageFile.path); + }); + } + return result; } } - export { NgxTranslateLint }; diff --git a/src/core/config.ts b/src/core/config.ts index d2aa0fc..96c91f7 100644 --- a/src/core/config.ts +++ b/src/core/config.ts @@ -16,7 +16,8 @@ const config: IAppConfig = { customRegExpToFindKeys: [] }, projectPath: './src/app/**/*.{html,ts,resx}', - languagesPath: './src/assets/i18n/*.json' + languagesPath: './src/assets/i18n/*.json', + fixZombiesKeys: false, } }; diff --git a/src/core/interface/IAppConfig.ts b/src/core/interface/IAppConfig.ts index f38b2fd..67b9b2c 100644 --- a/src/core/interface/IAppConfig.ts +++ b/src/core/interface/IAppConfig.ts @@ -4,6 +4,7 @@ interface IDefaultValues { rules: IRulesConfig; projectPath: string; languagesPath: string; + fixZombiesKeys?: boolean; } interface IAppConfig { defaultValues: IDefaultValues; diff --git a/src/cli/utils/file.ts b/src/core/utils/file.ts similarity index 71% rename from src/cli/utils/file.ts rename to src/core/utils/file.ts index 1d7e95e..f9f42cd 100644 --- a/src/cli/utils/file.ts +++ b/src/core/utils/file.ts @@ -2,8 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import chalk from 'chalk'; - -import { FatalErrorModel } from '../../core'; +import { FatalErrorModel } from './../models'; const packageJsonPath: string = './package.json'; @@ -23,7 +22,14 @@ function getPackageJsonPath(): string { return result; } +// tslint:disable-next-line:typedef no-any +function saveJsonFile(data: any, path: string) { + const jsonSpaces: number = 4; + fs.writeFileSync(path, JSON.stringify(data, null, jsonSpaces)); +} + export { getPackageJsonPath, - parseJsonFile + parseJsonFile, + saveJsonFile, }; diff --git a/src/core/utils/index.ts b/src/core/utils/index.ts index fe6a464..69f2592 100644 --- a/src/core/utils/index.ts +++ b/src/core/utils/index.ts @@ -1,4 +1,5 @@ export * from './keys'; +export * from './file'; export * from './path'; export * from './logger'; export * from './shared'; diff --git a/test/integration/config/custom.config.json b/test/integration/config/custom.config.json index 065533a..18bffd3 100644 --- a/test/integration/config/custom.config.json +++ b/test/integration/config/custom.config.json @@ -1,6 +1,6 @@ { "rules": { - "keysOnViews": "warning", + "keysOnViews": "warning ", "zombieKeys": "disable", "misprintKeys": "disable", "deepSearch": "disable",