{"version":3,"sources":["../../../packages/tools/wac-cli/src/eslint/main.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,oBAAY,WAAW;IACnB,cAAc,mBAAmB;IACjC,iBAAiB,sBAAsB;IACvC,WAAW,gBAAgB;CAC9B;AAED;;GAEG;AACH,oBAAY,sBAAsB;IAC9B,eAAe,0CAA0C;IACzD,iBAAiB,2BAA2B;IAC5C,wBAAwB,+BAA+B;IACvD,2BAA2B,kCAAkC;IAC7D,qBAAqB,4BAA4B;IACjD,qBAAqB,yCAAyC;IAC9D,iBAAiB,6EAA6E;IAC9F,mBAAmB,kCAAkC;IACrD,qBAAqB,sCAAsC;IAC3D,qBAAqB,uCAAuC;IAC5D,kBAAkB,gEAAgE;IAClF,kBAAkB,gEAAgE;IAClF,kBAAkB,uCAAuC;IACzD,eAAe,qCAAqC;IACpD,eAAe,sCAAsC;IACrD,mBAAmB,yMAIlB;IACD,SAAS,uBAAuB;CACnC;AAED;;;GAGG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAwB;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAA+B;IAC1E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAElD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAoB;IACzD,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAEtC;IACF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAwB;IAC1D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAyB;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmB;IACjD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAqC;IAC5E,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAA4B;IACxE,OAAO,CAAC,QAAQ,CAAC,sCAAsC,CAAmD;IAE1G;;;;OAIG;IACU,OAAO,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;;IAwElD,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,kBAAkB;YAOZ,mBAAmB;YAOnB,4BAA4B;YAO5B,4BAA4B;IAO1C;;OAEG;IACU,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;YAkBnC,qBAAqB;YAcrB,mBAAmB;YASnB,eAAe;YAUf,mBAAmB;YA4BnB,SAAS;IAMvB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,UAAU;IAmClB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,KAAK;CAGhB","file":"main.d.ts","sourcesContent":["import fse, { pathExists } from 'fs-extra';\r\nimport { Common } from '../common';\r\nimport { exec } from 'child_process';\r\n\r\n/**\r\n * Represents the type of upgrade that needs to be performed.\r\n */\r\nexport enum UpgradeType {\r\n    WithBaseConfig = 'WithBaseConfig',\r\n    WithoutBaseConfig = 'WithoutBaseConfig',\r\n    NoOperation = 'NoOperation'\r\n}\r\n\r\n/**\r\n * Represents the messages that are displayed during the upgrade process.\r\n */\r\nexport enum EslintUpgraderMessages {\r\n    StartingUpgrade = 'Starting upgrade eslinting process...',\r\n    CheckingFilePaths = 'Checking file paths...',\r\n    UpdateTypeWithBaseConfig = 'UpdateType: WithBaseConfig',\r\n    UpdateTypeWithoutBaseConfig = 'UpdateType: WithoutBaseConfig',\r\n    UpdateTypeWithoutBoth = 'UpdateType: NoOperation',\r\n    ExitWithoutBaseConfig = 'Exiting upgrade eslinting process...',\r\n    RCANoTsConfigFile = 'Please manually create a tsconfig.json file in the root of your project.',\r\n    GettingTsConfigFile = 'Getting tsconfig.json file...',\r\n    UpdateTsConfigContent = 'Updating tsconfig.json content...',\r\n    RevertTsConfigContent = 'Reverting tsconfig.json content...',\r\n    RenameTsBaseConfig = 'Renaming tsconfig.base.json to tsconfig.base.json_backup...',\r\n    RevertTsBaseConfig = 'Renaming tsconfig.base.json_backup to tsconfig.base.json...',\r\n    UpdateEslintConfig = 'Updating .eslintrc.json content...',\r\n    UpdatePolyfills = 'Updating polyfills.ts content...',\r\n    UpdateKarmaFile = 'Updating karma.conf.js content...',\r\n    FinalizeInfoLintFix = `There are eslint violations that needs fix... After fixing the violations, please run the following commands:\\n\r\n        npx eslint . --fix \\n\r\n        gulp lintApp \\n\r\n        gulp build \\n\r\n    `,\r\n    Completed = 'Upgrade completed!'\r\n}\r\n\r\n/**\r\n * This is the main class of the EslintUpgrader tool.\r\n * It is responsible for upgrading the Tslint to Eslint.\r\n */\r\nexport class EslintUpgrader {\r\n    private tsconfigBaseFilePath: string;\r\n    private tsconfigFilePath: string;\r\n    private angularFilePath: string;\r\n\r\n    private debug = false;\r\n    private libUpgrade = false;\r\n\r\n    private readonly tsconfigBaseFileName = 'tsconfig.base.json';\r\n    private readonly tsconfigFileName = 'tsconfig.json';\r\n    private readonly tsconfigBaseFileNameBackUp = 'tsconfig.base.json_backup';\r\n    private readonly angularFileName = 'angular.json';\r\n\r\n    private readonly eslintConfigFileName = '.eslintrc.json';\r\n    private readonly eslintConfigFileContent = {\r\n        \"extends\": \"./node_modules/@microsoft/windows-admin-center-sdk/tools/code-formatter/.eslintrc.base.json\"\r\n    };\r\n    private readonly polifillsFilePath = './src/polyfills.ts';\r\n    private readonly karmaConfigFilePath = './src/karma.conf.js';\r\n    private readonly eslintDisable = 'eslint-disable'\r\n    private readonly targetGulpLintFilePath = '.\\\\gulpfile.ts\\\\common\\\\lint.ts';\r\n    private readonly targetGulpLintIndexFilePath = './gulpfile.ts/index.ts';\r\n    private readonly targetGulpLintUiTestAutomationFilePath = '.\\\\gulpfile.ts\\\\common\\\\ui-test-automation.ts';\r\n\r\n    /**\r\n     * The main upgrade process\r\n     * @param debug - Indicates if the debug mode is enabled.\r\n     * @returns Promise<void> - Returns a promise that resolves when the upgrade process is completed.\r\n     */\r\n    public async upgrade(debug = false): Promise<void> {\r\n        this.debug = !!debug;\r\n\r\n        this.logger(EslintUpgraderMessages.StartingUpgrade);\r\n        this.logger(EslintUpgraderMessages.CheckingFilePaths);\r\n\r\n        const upgradeType = this.checkFileExists();\r\n        this.checkLibUpgrade();\r\n\r\n        switch (upgradeType) {\r\n            case UpgradeType.WithBaseConfig:\r\n                this.logger(EslintUpgraderMessages.UpdateTypeWithBaseConfig);\r\n\r\n                this.updateTsConfigContent();\r\n                this.renameTsBaseConfig();\r\n                await this.addEslintSchematics();\r\n                await this.esLintSchematicsRunModuleApp();\r\n\r\n                if (this.libUpgrade) {\r\n                    await this.esLintSchematicsRunModuleLib();\r\n                }\r\n\r\n                await this.uninstallDependencies();\r\n                await this.installDependencies();\r\n                await this.replaceEslintConfig();\r\n                this.updateTsConfigContent(true);\r\n                this.renameTsBaseConfig(true);\r\n                await this.replaceGulpLintFile();\r\n                this.cleanUpPolyfills();\r\n                this.cleanUpKarmaConfigFile();\r\n                await this.fixEslintErrors();\r\n                await this.gulpBuild();\r\n\r\n                break;\r\n            case UpgradeType.WithoutBaseConfig:\r\n                this.logger(EslintUpgraderMessages.UpdateTypeWithoutBaseConfig);\r\n\r\n                await this.addEslintSchematics();\r\n                await this.esLintSchematicsRunModuleApp();\r\n\r\n                if (this.libUpgrade) {\r\n                    await this.esLintSchematicsRunModuleLib();\r\n                }\r\n\r\n                await this.uninstallDependencies();\r\n                await this.installDependencies();\r\n                await this.replaceEslintConfig();\r\n                await this.replaceGulpLintFile();\r\n                this.cleanUpPolyfills();\r\n                this.cleanUpKarmaConfigFile();\r\n                await this.fixEslintErrors();\r\n                await this.gulpBuild();\r\n\r\n                break;\r\n            case UpgradeType.NoOperation:\r\n                this.logger(EslintUpgraderMessages.UpdateTypeWithoutBoth);\r\n                this.logger(EslintUpgraderMessages.ExitWithoutBaseConfig);\r\n                this.logger(EslintUpgraderMessages.RCANoTsConfigFile);\r\n\r\n                break;\r\n            default:\r\n                break;\r\n        }\r\n\r\n        this.logger(EslintUpgraderMessages.Completed);\r\n    }\r\n\r\n    constructor() {\r\n        Common.rootPath = process.cwd();\r\n        this.updateBasicPaths();\r\n    }\r\n\r\n    private updateBasicPaths(): void {\r\n        this.tsconfigBaseFilePath = Common.rootPath + '\\\\' + this.tsconfigBaseFileName;\r\n        this.tsconfigFilePath = Common.rootPath + '\\\\' + this.tsconfigFileName;\r\n        this.angularFilePath = Common.rootPath + '\\\\' + this.angularFileName;\r\n    }\r\n\r\n    private checkLibUpgrade(): void {\r\n        const angularFilePathExists = pathExists(this.angularFilePath);\r\n        if (!angularFilePathExists) {\r\n            return;\r\n        }\r\n\r\n        const angularFileContent = Common.readFileData(this.angularFilePath);\r\n        this.libUpgrade = !!angularFileContent.includes('module-lib');\r\n    }\r\n\r\n    private checkFileExists(): UpgradeType {\r\n        const tsconfigBaseFilePathExists = pathExists(this.tsconfigBaseFilePath);\r\n        const tsconfigFilePathExists = pathExists(this.tsconfigFilePath);\r\n        if (tsconfigBaseFilePathExists && tsconfigFilePathExists) {\r\n            return UpgradeType.WithBaseConfig;\r\n        } else if (tsconfigFilePathExists) {\r\n            return UpgradeType.WithoutBaseConfig;\r\n        } else {\r\n            return UpgradeType.NoOperation;\r\n        }\r\n    }\r\n\r\n    private updateTsConfigContent(revert = false) {\r\n        revert ? this.logger(EslintUpgraderMessages.RevertTsConfigContent) : this.logger(EslintUpgraderMessages.UpdateTsConfigContent);\r\n\r\n        revert ?\r\n            this.updateFile(this.tsconfigFilePath, `// \"extends\": \"./${this.tsconfigBaseFileName}\"`, `\"extends\": \"./${this.tsconfigBaseFileName}\"`) :\r\n            this.updateFile(this.tsconfigFilePath, `\"extends\": \"./${this.tsconfigBaseFileName}\"`, `// \"extends\": \"./${this.tsconfigBaseFileName}\"`);\r\n    }\r\n\r\n    private updateFile(filePath: string, prev: string, target: string): void {\r\n        this.logger('Updating file...' + filePath + ',' + prev + ',' + target + '...');\r\n\r\n        let fileData = Common.readFileData(filePath);\r\n        fileData = fileData.replace(prev, target);\r\n        fse.writeFileSync(filePath, fileData);\r\n    }\r\n\r\n    private renameTsBaseConfig(revert = false): void {\r\n        revert ? this.logger(EslintUpgraderMessages.RenameTsBaseConfig) : this.logger(EslintUpgraderMessages.RevertTsBaseConfig);\r\n\r\n        const cmd = revert ? `git mv ./${this.tsconfigBaseFileNameBackUp} ./${this.tsconfigBaseFileName}` : `git mv ./${this.tsconfigBaseFileName} ./${this.tsconfigBaseFileNameBackUp}`;\r\n        this.runCommand(cmd);\r\n    }\r\n\r\n    private async addEslintSchematics(): Promise<void> {\r\n        const cmd = 'ng add @angular-eslint/schematics --skip-confirmation';\r\n\r\n        this.logger(cmd);\r\n        await this.runCommand(cmd);\r\n    }\r\n\r\n    private async esLintSchematicsRunModuleApp(): Promise<void> {\r\n        const cmd = 'ng g @angular-eslint/schematics:convert-tslint-to-eslint module-app';\r\n\r\n        this.logger(cmd);\r\n        await this.runCommand(cmd);\r\n    }\r\n\r\n    private async esLintSchematicsRunModuleLib(): Promise<void> {\r\n        const cmd = 'ng g @angular-eslint/schematics:convert-tslint-to-eslint module-lib';\r\n\r\n        this.logger(cmd);\r\n        await this.runCommand(cmd);\r\n    }\r\n\r\n    /**\r\n     * It updates to the eslintrc.json file on the root of the project.\r\n     */\r\n    public async replaceEslintConfig(): Promise<void> {\r\n        const formattedNewContent = JSON.stringify(this.eslintConfigFileContent, null, 2)\r\n            .replace('}', '}\\n')\r\n\r\n        this.logger(EslintUpgraderMessages.UpdateEslintConfig);\r\n\r\n        if (fse.existsSync(`./${this.eslintConfigFileName}`)) {\r\n            this.logger('Updating eslint file');\r\n            Common.writeFileData(`./${this.eslintConfigFileName}`, formattedNewContent);\r\n        } else {\r\n            this.logger('Creating new eslint file');\r\n            Common.writeFile(`./${this.eslintConfigFileName}`, formattedNewContent);\r\n        }\r\n\r\n        // race condition for the eslintrc file not being released by the writeFile function.\r\n        await this.sleep(1000);\r\n    }\r\n\r\n    private async uninstallDependencies(): Promise<void> {\r\n        const cmd = 'npm uninstall codelyzer gulp-tslint rxjs-tslint rxjs-tslint-rules tslint tslint-consistent-codestyle tslint-eslint-rules tslint-microsoft-contrib';\r\n\r\n        this.logger(cmd);\r\n        await this.runCommand(cmd);\r\n\r\n        const removeForRollBackCmd = 'npm uninstall gulp-eslint eslint eslint-plugin-angular eslint-plugin-import eslint-plugin-jsdoc eslint-plugin-jsonc eslint-plugin-prefer-arrow ' +\r\n            '@typescript-eslint/eslint-plugin @typescript-eslint/parser @angular-eslint/builder @angular-eslint/eslint-plugin @angular-eslint/eslint-plugin-template @angular-eslint/schematics ' +\r\n            '@angular-eslint/template-parser'\r\n\r\n        this.logger(removeForRollBackCmd);\r\n        await this.runCommand(removeForRollBackCmd);\r\n    }\r\n\r\n    private async installDependencies(): Promise<void> {\r\n        const cmd = 'npm install gulp-eslint@6.0.0 eslint@7.6.0 eslint-plugin-angular@4.1.0 eslint-plugin-import@2.21.0 eslint-plugin-jsdoc@36.1.1 eslint-plugin-jsonc@2.8.0 eslint-plugin-prefer-arrow@1.2.3 ' +\r\n            '@typescript-eslint/eslint-plugin@4.16.1 @typescript-eslint/parser@4.16.1 @angular-eslint/builder@4.3.1 @angular-eslint/eslint-plugin@4.3.1 @angular-eslint/eslint-plugin-template@4.3.1 ' +\r\n            '@angular-eslint/schematics@4.3.1 @angular-eslint/template-parser@4.3.1 --save-dev';\r\n\r\n        this.logger(cmd);\r\n        await this.runCommand(cmd);\r\n    }\r\n\r\n    private async fixEslintErrors(): Promise<void> {\r\n        const rootFileLinterFix = 'npx eslint . --fix';\r\n        this.logger(rootFileLinterFix);\r\n        await this.runCommand(rootFileLinterFix, true, EslintUpgraderMessages.FinalizeInfoLintFix);\r\n\r\n        const projectLinterFix = 'npx ng lint --fix';\r\n        this.logger(projectLinterFix);\r\n        await this.runCommand(projectLinterFix, true, EslintUpgraderMessages.FinalizeInfoLintFix);\r\n    }\r\n\r\n    private async replaceGulpLintFile(): Promise<void> {\r\n        const cmd = `del ${this.targetGulpLintFilePath}`;\r\n\r\n        this.logger(cmd);\r\n        await this.runCommand(cmd);\r\n\r\n        if (pathExists(this.targetGulpLintIndexFilePath)) {\r\n            this.updateFile(\r\n                this.targetGulpLintIndexFilePath,\r\n                `import { LintModule } from './common/lint'`,\r\n                `import { LintModule } from '../node_modules/@microsoft/windows-admin-center-sdk/tools/code-formatter/lint'`);\r\n        }\r\n\r\n        if (pathExists(this.targetGulpLintUiTestAutomationFilePath)) {\r\n            this.updateFile(\r\n                this.targetGulpLintUiTestAutomationFilePath,\r\n                `import { LintModule } from './lint'`,\r\n                `import { LintModule } from '../../node_modules/@microsoft/windows-admin-center-sdk/tools/code-formatter/lint'`);\r\n\r\n            // The new UI automation framework will remove this line.\r\n            // This is for the repositories that has not yet onboraded to the new frawework.\r\n            this.updateFile(\r\n                this.targetGulpLintUiTestAutomationFilePath,\r\n                `export const uiTestAutomation = series(LintModule.lintUiTestAutomation, buildUiTestAutomation);`,\r\n                `export const uiTestAutomation = series(LintModule.lintUiTestAutomation_legacy, buildUiTestAutomation);`);\r\n        }\r\n    }\r\n\r\n    private async gulpBuild(): Promise<void> {\r\n        const cmd = 'gulp build';\r\n        this.logger(cmd);\r\n        await this.runCommand(cmd);\r\n    }\r\n\r\n    private cleanUpPolyfills(): void {\r\n        this.logger(EslintUpgraderMessages.UpdatePolyfills);\r\n\r\n        const fileDataInLines = Common.readFileData(this.polifillsFilePath).split('\\n');\r\n        const newLines = fileDataInLines.filter(line => !line.includes(this.eslintDisable));\r\n        Common.writeFileData(this.polifillsFilePath, newLines.join('\\n'));\r\n    }\r\n\r\n    private cleanUpKarmaConfigFile(): void {\r\n        this.logger(EslintUpgraderMessages.UpdateKarmaFile);\r\n\r\n        this.updateFile(\r\n            this.karmaConfigFilePath,\r\n            `module.exports = (config) => {`,\r\n            `module.exports = function (config) {`);\r\n    }\r\n\r\n    private runCommand(cmd: string, forceDebug = false, finalizeInfo = undefined): Promise<void> {\r\n        console.log(`Running ${cmd}`);\r\n        return new Promise((resolve) => {\r\n            const child = exec(cmd, (error, stdout, stderr) => {\r\n                if (error) {\r\n                    console.error(`  exec error: ${error}`);\r\n                    return;\r\n                }\r\n\r\n                stdout.split('\\n').filter(line => line.trimEnd()).forEach(line => console.log(line));\r\n                stderr.split('\\n').filter(line => line.trimEnd()).forEach(line => console.error(line));\r\n\r\n                resolve();\r\n            });\r\n\r\n            if (this.debug || forceDebug) {\r\n                child.stdout.on('data', (data) => {\r\n                    data.split('\\n').filter(line => line.trimEnd()).forEach(line => console.log(`  ${line}`));\r\n                });\r\n            }\r\n\r\n            child.stderr.on('data', (data) => {\r\n                data.split('\\n').filter(line => line.trimEnd()).forEach(line => console.error(`  ${line}`));\r\n            });\r\n\r\n            child.on('close', (code) => {\r\n                console.log(`exitCode: ${code}`);\r\n                if (code !== 0 && finalizeInfo) {\r\n                    this.logger(finalizeInfo);\r\n                    this.logger(EslintUpgraderMessages.Completed);\r\n                }\r\n            });\r\n        });\r\n    }\r\n\r\n    private logger(value: EslintUpgraderMessages | string, prefix = 'Main thread') {\r\n        console.log(`${prefix} - ${value}`);\r\n    }\r\n\r\n    private sleep(ms: number): Promise<void> {\r\n        return new Promise(resolve => setTimeout(resolve, ms));\r\n    }\r\n}\r\n"]}