import { FileInfo, API, Expression } from 'jscodeshift'; import get from 'lodash.get'; import { APIRule, Location, Parse, Parser, TransformError, ValidateReport, Warning } from '../../types/runner'; import { saveTempData } from '../../utils/file'; import { getDOMWarnings } from '../../utils/parse'; import { CODE_PLACEHOLDER } from '../../constants'; const getValueAsList = (value: T | Array): T[] => (Array.isArray(value) ? value : [value]); const locateMap: Record = { Identifier: 'name', StringLiteral: 'value', }; export default async ( file: FileInfo, api: API, options: { parser: Parser; reportDir: string; rules: APIRule[]; }, // eslint-disable-next-line sonarjs/cognitive-complexity ): Promise => { const apiCompatibilityWarnings: Warning[] = []; const errors: TransformError[] = []; let domWarnings: string[] = []; try { const j = api.jscodeshift; const root = j(file.source); const isStyleSheet = options.parser === 'flow'; if (!isStyleSheet) { domWarnings = getDOMWarnings(root, j); } options.rules?.forEach(({ parse, name, warningMessage, recommendation, id }) => { const parseList = getValueAsList(parse); parseList.forEach((p) => { const { locate, filter, type, validate } = p; const { message: recommendationMsg, code, placeholderMap, link } = recommendation; const filters = getValueAsList(filter.name); filters.forEach((filter) => { const expressions = root.find(j[locate], { [locateMap[locate]]: filter } as any).closest(j[type]); let updatedCode = code; expressions.forEach((expr) => { const sourceLoc = (expr.node as Expression)?.loc?.start; const location: Location | undefined = sourceLoc ? { ...sourceLoc, } : undefined; if (validate) { const validateValues = getValueAsList(validate.value); validateValues.forEach((value) => { if (get(expr, validate.key || '', undefined) === value) { // Rule Violation if (code && placeholderMap) { // Identifies which value should the PLACEHOLDER be replaced with - parse.filter/validate.value const key = Array.isArray(parse.filter.name) ? filter : value; updatedCode = code.replace(CODE_PLACEHOLDER, placeholderMap[key]); } apiCompatibilityWarnings.push({ id, name, location, warningMessage, recommendation: { message: recommendationMsg, code: updatedCode, link, }, }); } }); } else { // Rule Violation if (code && placeholderMap) { updatedCode = code.replace(CODE_PLACEHOLDER, placeholderMap[filter]); } apiCompatibilityWarnings.push({ id, name, warningMessage, location, recommendation: { message: recommendationMsg, code: updatedCode, link, }, }); } }); }); }); }); } catch (e: any) { errors.push({ file: file.path, message: e.message, }); } await saveTempData>( { apiCompatibility: apiCompatibilityWarnings.length > 0 ? [ { file: file.path, warnings: apiCompatibilityWarnings, }, ] : [], domManipulation: domWarnings.length > 0 ? [ { file: file.path, messages: domWarnings, }, ] : [], errors, }, options.reportDir, ); return file.source; };