{"version":3,"sources":["../../../packages/tools/wac-cli/src/upgrade/error-updater.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAInE,qBAAa,YAAY;IACrB;;;;;OAKG;IACU,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAOvF;;;;;OAKG;IACU,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAaxF,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA2BjE,SAAS,CAAC,gBAAgB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;cAQpC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;cAsClH,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmC/I,SAAS,CAAC,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE;IAuD1D,SAAS,CAAC,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE;CA4C/D","file":"error-updater.d.ts","sourcesContent":["import { exec } from 'child_process';\r\nimport fse from 'fs-extra';\r\nimport { Common, ResolveState } from '../common';\r\nimport { UpdaterLookup } from './error-updaters/updater-lookup';\r\nimport { ErrorPosition, ErrorResult } from './models/error-result';\r\nimport { Updater } from './models/updater-interface';\r\nimport { Logger } from '../angular15/utils/logger';\r\n\r\nexport class ErrorUpdater {\r\n    /**\r\n     * Executes 'ng lint' and attempts to fix returned errors.\r\n     * @param {boolean} audit Flag indicating if upgrade is running it audit mode\r\n     * @param {string[]} updateSource Array used to emit logs to file\r\n     * @returns {Promise<number>} Count of unresolved errors.\r\n     */\r\n    public async resolveLintErrors(audit: boolean, updateSource: string[]): Promise<number> {\r\n        const errors = await this.parseLintErrors(audit);\r\n        const unresolvedCount = await this.fixErrors(audit, errors, updateSource);\r\n\r\n        return new Promise((resolve) => resolve(unresolvedCount));\r\n    }\r\n\r\n    /**\r\n     * Executes 'ng build' and attempts to fix returned errors.\r\n     * @param {boolean} audit Flag indicating if upgrade is running it audit mode\r\n     * @param {string[]} updateSource Array used to emit logs to file\r\n     * @returns {Promise<number>} Count of unresolved errors.\r\n     */\r\n    public async resolveBuildErrors(audit: boolean, updateSource: string[]): Promise<number> {\r\n        // If running in audit mode, we don't want to build\r\n        if (audit) {\r\n            return new Promise(resolve => resolve(0));\r\n        }\r\n\r\n        const errors = await this.parseBuildErrors();\r\n        const unresolvedCount = await this.fixErrors(false, errors, updateSource);\r\n\r\n        Logger.log('INFO - unresolvedCount' + unresolvedCount);\r\n        return new Promise((resolve) => resolve(unresolvedCount));\r\n    }\r\n\r\n    protected parseLintErrors(audit: boolean): Promise<ErrorResult[]> {\r\n        // If audit is true, run without --fix flag\r\n        const cmd = audit ? 'ng lint --project module-app --format json' : 'ng lint --project module-app --fix --format json';\r\n\r\n        console.log('Linting, please wait...');\r\n        return new Promise((resolve) => {\r\n            exec(cmd, (_, stdout) => {\r\n                const output = JSON.parse(stdout);\r\n\r\n                const results: ErrorResult[] = [];\r\n                for (const error of output) {\r\n                    if (error.ruleSeverity === 'error') {\r\n                        results.push({\r\n                            filePath: error.name,\r\n                            type: error.ruleName,\r\n                            message: error.failure,\r\n                            position: { line: error.startPosition.line, character: error.startPosition.character },\r\n                            resolved: ResolveState.Unresolved\r\n                        });\r\n                    }\r\n                }\r\n\r\n                resolve(results);\r\n            });\r\n        });\r\n    }\r\n\r\n    protected parseBuildErrors(): Promise<ErrorResult[]> {\r\n        console.log('Building, please wait...');\r\n\r\n        return new Promise((resolve) => exec('ng build', (_error, _stdout, stderr) => {\r\n            resolve(this.parseBuildErrorsCore(stderr));\r\n        }));\r\n    }\r\n\r\n    protected async fixErrors(audit: boolean, errors: ErrorResult[], updateSource: string[], angularVersion?: string): Promise<number> {\r\n        if (!errors || !errors.length) {\r\n            return new Promise(resolve => resolve(0));\r\n        }\r\n\r\n        let unresolvedCount = errors.length;\r\n\r\n        for (const error of errors) {\r\n            let message = `File path: ${error.filePath}`;\r\n            console.log(message);\r\n            updateSource.push(message + '\\n');\r\n\r\n            let fileData = Common.readFileData(error.filePath);\r\n\r\n            if (!fileData) {\r\n                message = `Couldn't retrieve file data for path ${error.filePath}. Please verify this path is valid.`;\r\n                console.log(message);\r\n                updateSource.push(message + '\\n');\r\n                continue;\r\n            }\r\n\r\n            fileData = await this.fixError(audit, fileData, error, updateSource, angularVersion);\r\n\r\n            if (error.resolved === ResolveState.Resolved) {\r\n                unresolvedCount--;\r\n            }\r\n\r\n            if (fileData) {\r\n                fse.writeFileSync(error.filePath, fileData);\r\n            }\r\n\r\n            console.log('');\r\n            updateSource.push('\\n');\r\n        }\r\n\r\n        return new Promise(resolve => resolve(unresolvedCount));\r\n    }\r\n\r\n    protected async fixError(audit: boolean, fileData: string, error: ErrorResult, updateSource: string[], augularVerion?: string): Promise<string> {\r\n        let message = `\\tType: ${error.type}`;\r\n        console.log(message);\r\n        updateSource.push(message + '\\n');\r\n\r\n        message = `\\tLine: ${error?.position?.line}`;\r\n        console.log(message);\r\n        updateSource.push(message + '\\n');\r\n\r\n        message = `\\tChar: ${error?.position?.character}`;\r\n        console.log(message);\r\n        updateSource.push(message + '\\n');\r\n\r\n        message = `\\tMessage: ${error.message}`;\r\n        console.log(message);\r\n        updateSource.push(message + '\\n');\r\n\r\n        if (audit) {\r\n            return fileData;\r\n        }\r\n\r\n        const updaterLookup = UpdaterLookup.initialize(augularVerion);\r\n        const updater: Updater = updaterLookup[error.type];\r\n\r\n        Logger.log(`error.type = ${error.type}`);\r\n        Logger.log(updater ? `Found updater for ${error.type}` : `No updater found for ${error.type}`);\r\n\r\n        const result = updater != null ? await updater.update(fileData, error) : fileData;\r\n\r\n        message = `\\tResolved: ${error.resolved}\\n`;\r\n        console.log(message);\r\n        updateSource.push(message + '\\n');\r\n        return new Promise(resolve => resolve(result));\r\n    }\r\n\r\n    protected parseBuildErrorsCore(log: string): ErrorResult[] {\r\n        const captureAll = /[\\s\\S]+?(?=(Error|Warning):)/g; // Capture array of build error/warning output by file\r\n        const captureFilePath = /(?<=Error: )(.+)(?=:\\d+:\\d+)/g; // Capture file path of individual error\r\n        const captureErrorPosition = /(?<=Error: .+)(\\d+:\\d+)(?= - error)/g; // Capture file position of individual error\r\n        const captureErrorCode = /(?<=Error:.+- error )(TS\\d+)/g; // Capture error code of individual error\r\n        const captureErrorMessage = /(?<=TS\\d+: ).+/g; // Capture error message of individual error\r\n\r\n        log = log + '\\n\\n\\nWarning:';\r\n        const buildOutputByCode = log.match(captureAll);\r\n\r\n        const results: ErrorResult[] = [];\r\n\r\n        if (!buildOutputByCode) {\r\n            return results;\r\n        }\r\n        \r\n        for (const file of buildOutputByCode) {\r\n            const filePath = file.match(captureFilePath);\r\n\r\n            // If no file path found, this match doesn't contain errors\r\n            if (!filePath || filePath.length === 0) {\r\n                continue;\r\n            }\r\n\r\n            const errorPositionString = file.match(captureErrorPosition);\r\n\r\n            // If there isn't a position found this isn't a parsable error, skip to next file\r\n            if (!errorPositionString || errorPositionString.length === 0) {\r\n                continue;\r\n            }\r\n\r\n            const splitValues = errorPositionString[0].split(':');\r\n            const errorPosition: ErrorPosition = { line: parseInt(splitValues[0], null), character: parseInt(splitValues[1], null) };\r\n\r\n            const errorCode = file.match(captureErrorCode);\r\n\r\n            // Couldn't get error code, skip to next file\r\n            if (!errorCode || errorCode.length === 0) {\r\n                continue;\r\n            }\r\n\r\n            const errorMessage = file.match(captureErrorMessage);\r\n\r\n            results.push({\r\n                filePath: filePath[0],\r\n                type: errorCode[0],\r\n                message: errorMessage[0],\r\n                position: errorPosition,\r\n                resolved: ResolveState.Unresolved\r\n            });\r\n        }\r\n\r\n        return results;\r\n    }\r\n\r\n    protected parseBuildWarningsCore(log: string): ErrorResult[] {\r\n        // Capture array of build error/warning output by file\r\n        const captureAll = /[\\s\\S]+?(?=(Error|Warning):)/g;\r\n\r\n        // Capture file path of individual error\r\n        const captureFilePath = /([^\\s\\r\\n].*\\.css)\\s*(?=:)/g;\r\n\r\n        log = log + '\\n\\n\\nWarning:';\r\n        const buildOutputByCode = log.match(captureAll);\r\n\r\n        const results: ErrorResult[] = [];\r\n\r\n        if (!buildOutputByCode) {\r\n            return results;\r\n        }\r\n        \r\n        for (const file of buildOutputByCode) {\r\n            const filePath = file.match(captureFilePath);\r\n\r\n            // If no file path found, this match doesn't contain errors\r\n            if (!filePath || filePath.length === 0) {\r\n                continue;\r\n            }\r\n\r\n            let errorCode;\r\n            if (file.includes('css-syntax-error')) {\r\n                errorCode = ['css-syntax-error'];\r\n            }\r\n\r\n            // Couldn't get error code, skip to next file\r\n            if (!errorCode || errorCode.length === 0) {\r\n                continue;\r\n            }\r\n\r\n            results.push({\r\n                filePath: filePath[0],\r\n                type: errorCode[0],\r\n                message: file,\r\n                resolved: ResolveState.Unresolved\r\n            });\r\n        }\r\n\r\n        return results;\r\n    }\r\n}\r\n"]}