{"version":3,"sources":["../../src/rules/expect.ts"],"sourcesContent":["import type ts from \"typescript\";\n\nimport { TSESLint } from \"@typescript-eslint/utils\";\n\nimport { parseAssertions } from \"../assertions/parseAssertions.js\";\nimport { SyntaxError } from \"../assertions/types.js\";\nimport { getExpectTypeFailures } from \"../failures/getExpectTypeFailures.js\";\nimport { UnmetExpectation } from \"../failures/types.js\";\nimport { ExpectRuleContext, MessageIds, messages, Options } from \"../meta.js\";\nimport { createRule } from \"../utils/createRule.js\";\nimport { isDiagnosticWithStart } from \"../utils/diagnostics.js\";\nimport { lineOfPosition, locForTSNode } from \"../utils/locations.js\";\nimport { updateTypeSnapshot } from \"../utils/snapshot.js\";\nimport {\n\tResolvedVersionToTest,\n\tresolveVersionsToTest,\n} from \"../utils/versions.js\";\n\nconst defaultOptions: Options = {\n\tdisableExpectTypeSnapshotFix: false,\n\tversionsToTest: undefined,\n};\n\nexport const expect = createRule<[Options], MessageIds>({\n\tcreate(context, [options]) {\n\t\t// Performance: if the source file doesn't have any triggering comments,\n\t\t// avoid asking for diagnostics or type information altogether.\n\t\tif (!/\\$Expect(?:Type|Error|\\?)|\\^\\?/.test(context.sourceCode.text)) {\n\t\t\treturn {};\n\t\t}\n\n\t\t/* istanbul ignore next */\n\t\t// TODO: Once ESLint <8 support is removed, soon\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tconst fileName = context.filename || context.getFilename();\n\n\t\tconst versionsResolution = resolveVersionsToTest(\n\t\t\tcontext,\n\t\t\tfileName,\n\t\t\toptions.versionsToTest,\n\t\t);\n\t\tif (versionsResolution.error) {\n\t\t\tcontext.report({\n\t\t\t\t...versionsResolution.error,\n\t\t\t\tloc: {\n\t\t\t\t\tend: { column: 0, line: 0 },\n\t\t\t\t\tstart: { column: 0, line: 0 },\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn {};\n\t\t}\n\n\t\tfor (const version of versionsResolution.versionsToTest) {\n\t\t\ttestInVersion(version);\n\t\t}\n\n\t\treturn {};\n\n\t\tfunction testInVersion(version: ResolvedVersionToTest) {\n\t\t\tconst { errorLines, syntaxErrors, twoSlashAssertions, typeAssertions } =\n\t\t\t\tparseAssertions(version.sourceFile);\n\n\t\t\treportNotFoundErrors(context, errorLines, version);\n\t\t\treportSyntaxErrors(context, syntaxErrors);\n\n\t\t\tconst { unmetExpectations, unusedAssertions } = getExpectTypeFailures(\n\t\t\t\t{ twoSlashAssertions, typeAssertions },\n\t\t\t\tversion,\n\t\t\t);\n\n\t\t\treportUnmetExpectations(\n\t\t\t\tcontext,\n\t\t\t\tfileName,\n\t\t\t\toptions,\n\t\t\t\tunmetExpectations,\n\t\t\t\tversion.sourceFile,\n\t\t\t);\n\t\t\treportUnusedAssertions(context, unusedAssertions);\n\t\t}\n\t},\n\tdefaultOptions: [defaultOptions],\n\tmeta: {\n\t\tdocs: {\n\t\t\tdescription: \"Expects type error, type snapshot, or type.\",\n\t\t\trequiresTypeChecking: true,\n\t\t},\n\t\tfixable: \"code\",\n\t\tmessages,\n\t\tschema: {\n\t\t\t$defs: {\n\t\t\t\tversion: {\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\tname: { required: true, type: \"string\" },\n\t\t\t\t\t\tpath: { required: true, type: \"string\" },\n\t\t\t\t\t},\n\t\t\t\t\ttype: \"object\",\n\t\t\t\t},\n\t\t\t},\n\t\t\titems: [\n\t\t\t\t{\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\tdisableExpectTypeSnapshotFix: {\n\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tversionsToTest: {\n\t\t\t\t\t\t\titems: { $ref: \"#/$defs/version\" },\n\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\ttype: \"object\",\n\t\t\t\t},\n\t\t\t],\n\t\t\ttype: \"array\",\n\t\t},\n\t\ttype: \"problem\",\n\t},\n\tname: \"expect\",\n});\n\nfunction reportNotFoundErrors(\n\tcontext: ExpectRuleContext,\n\terrorLines: ReadonlySet<number>,\n\t{ program, sourceFile, tsModule, version }: ResolvedVersionToTest,\n) {\n\tconst diagnostics = tsModule.getPreEmitDiagnostics(program, sourceFile);\n\tconst seenDiagnosticsOnLine = new Set(\n\t\tdiagnostics\n\t\t\t.filter(isDiagnosticWithStart)\n\t\t\t.map((diagnostic) => lineOfPosition(diagnostic.start, sourceFile)),\n\t);\n\n\tfor (const line of errorLines) {\n\t\tif (!seenDiagnosticsOnLine.has(line)) {\n\t\t\tcontext.report({\n\t\t\t\tdata: { version },\n\t\t\t\tloc: {\n\t\t\t\t\tcolumn: 0,\n\t\t\t\t\tline: line + 1,\n\t\t\t\t},\n\t\t\t\tmessageId: version\n\t\t\t\t\t? \"ExpectedErrorNotFoundForVersion\"\n\t\t\t\t\t: \"ExpectedErrorNotFound\",\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction reportSyntaxErrors(\n\tcontext: ExpectRuleContext,\n\tsyntaxErrors: readonly SyntaxError[],\n) {\n\tfor (const { line, type } of syntaxErrors) {\n\t\tcontext.report({\n\t\t\tdata: {\n\t\t\t\tmessage:\n\t\t\t\t\ttype === \"MissingExpectType\"\n\t\t\t\t\t\t? '$ExpectType requires type argument (e.g. // $ExpectType \"string\")'\n\t\t\t\t\t\t: type === \"MissingSnapshotName\"\n\t\t\t\t\t\t\t? \"$ExpectTypeSnapshot requires snapshot name argument (e.g. // $ExpectTypeSnapshot MainComponentAPI)\"\n\t\t\t\t\t\t\t: 'Invalid twoslash assertion; make sure there is a space after the \"^?\".',\n\t\t\t},\n\t\t\tloc: {\n\t\t\t\tcolumn: 0,\n\t\t\t\tline: line + 1,\n\t\t\t},\n\t\t\tmessageId: \"SyntaxError\",\n\t\t});\n\t}\n}\n\nfunction reportUnmetExpectations(\n\tcontext: ExpectRuleContext,\n\tfileName: string,\n\toptions: Options,\n\tunmetExpectations: readonly UnmetExpectation[],\n\tsourceFile: ts.SourceFile,\n) {\n\tfor (const { actual, assertion, node, version } of unmetExpectations) {\n\t\tconst templateDescriptor = {\n\t\t\tdata: {\n\t\t\t\tactual,\n\t\t\t\texpected: assertion.expected,\n\t\t\t\t...(version && { version }),\n\t\t\t},\n\t\t\tloc: locForTSNode(sourceFile, node),\n\t\t};\n\t\tif (assertion.assertionType === \"snapshot\") {\n\t\t\tconst { snapshotName } = assertion;\n\t\t\tconst start = node.getStart();\n\n\t\t\tcontext.report({\n\t\t\t\t...templateDescriptor,\n\n\t\t\t\t// ESLint doesn't indicate whether it's in --fix mode, and fixers run immediately.\n\t\t\t\t// We don't have a way to delay file updates natively in ESLint.\n\t\t\t\t// Instead, we use this inaccurate heuristic to know if we're in CLI --fix...\n\t\t\t\t// See: https://github.com/JoshuaKGoldberg/eslint-plugin-expect-type/issues/14\n\t\t\t\tfix: process.argv.includes(\"--fix\")\n\t\t\t\t\t? (): TSESLint.RuleFix => {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\trange: [start, start],\n\t\t\t\t\t\t\t\tget text() {\n\t\t\t\t\t\t\t\t\tif (!options.disableExpectTypeSnapshotFix) {\n\t\t\t\t\t\t\t\t\t\tupdateTypeSnapshot(\n\t\t\t\t\t\t\t\t\t\t\t// TODO: Once ESLint <8 support is removed, context.filename\n\t\t\t\t\t\t\t\t\t\t\tfileName,\n\t\t\t\t\t\t\t\t\t\t\tsnapshotName,\n\t\t\t\t\t\t\t\t\t\t\tactual,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturn \"\";\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\n\t\t\t\tmessageId:\n\t\t\t\t\ttypeof assertion.expected === \"undefined\"\n\t\t\t\t\t\t? \"TypeSnapshotNotFound\"\n\t\t\t\t\t\t: \"TypeSnapshotDoNotMatch\",\n\t\t\t});\n\t\t} else {\n\t\t\tcontext.report({\n\t\t\t\t...templateDescriptor,\n\t\t\t\tmessageId: templateDescriptor.data.version\n\t\t\t\t\t? \"TypesDoNotMatchForVersion\"\n\t\t\t\t\t: \"TypesDoNotMatch\",\n\t\t\t\t...(assertion.assertionType === \"twoslash\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tfix: (): TSESLint.RuleFix => {\n\t\t\t\t\t\t\t\tconst { expectedPrefix, expectedRange, insertSpace } =\n\t\t\t\t\t\t\t\t\tassertion;\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\trange: expectedRange,\n\t\t\t\t\t\t\t\t\ttext:\n\t\t\t\t\t\t\t\t\t\t(insertSpace ? \" \" : \"\") +\n\t\t\t\t\t\t\t\t\t\tactual\n\t\t\t\t\t\t\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t\t\t\t\t\t\t.map((line, i) => (i > 0 ? expectedPrefix + line : line))\n\t\t\t\t\t\t\t\t\t\t\t.join(\"\\n\"),\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction reportUnusedAssertions(\n\tcontext: ExpectRuleContext,\n\tunusedAssertions: Iterable<number>,\n) {\n\tfor (const line of unusedAssertions) {\n\t\tcontext.report({\n\t\t\tloc: {\n\t\t\t\tcolumn: 0,\n\t\t\t\tline: line + 1,\n\t\t\t},\n\t\t\tmessageId: \"OrphanAssertion\",\n\t\t});\n\t}\n}\n"],"mappings":"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","names":[]}