UNPKG

tsd

Version:

Check TypeScript type definitions

149 lines (148 loc) 8.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDiagnostics = void 0; const typescript_1 = require("@tsd/typescript"); const parser_1 = require("./parser"); const interfaces_1 = require("./interfaces"); const assertions_1 = require("./assertions"); // List of diagnostic codes that should be ignored in general const ignoredDiagnostics = new Set([ // Older TS version report 'await expression only allowed within async function interfaces_1.DiagnosticCode.AwaitExpressionOnlyAllowedWithinAsyncFunction, interfaces_1.DiagnosticCode.TopLevelAwaitOnlyAllowedWhenModuleESNextOrSystem ]); // List of diagnostic codes which should be ignored inside `expectError` statements const expectErrorDiagnosticCodesToIgnore = new Set([ interfaces_1.DiagnosticCode.ArgumentTypeIsNotAssignableToParameterType, interfaces_1.DiagnosticCode.PropertyDoesNotExistOnType, interfaces_1.DiagnosticCode.CannotAssignToReadOnlyProperty, interfaces_1.DiagnosticCode.TypeIsNotAssignableToOtherType, interfaces_1.DiagnosticCode.TypeDoesNotSatisfyTheConstraint, interfaces_1.DiagnosticCode.GenericTypeRequiresTypeArguments, interfaces_1.DiagnosticCode.GenericTypeRequiresBetweenXAndYTypeArugments, interfaces_1.DiagnosticCode.ExpectedArgumentsButGotOther, interfaces_1.DiagnosticCode.ExpectedAtLeastArgumentsButGotOther, interfaces_1.DiagnosticCode.NoOverloadExpectsCountOfArguments, interfaces_1.DiagnosticCode.NoOverloadExpectsCountOfTypeArguments, interfaces_1.DiagnosticCode.NoOverloadMatches, interfaces_1.DiagnosticCode.Type1IsMissingPropertiesFromType2Variant1, interfaces_1.DiagnosticCode.Type1IsMissingPropertiesFromType2Variant2, interfaces_1.DiagnosticCode.PropertyMissingInType1ButRequiredInType2, interfaces_1.DiagnosticCode.TypeHasNoPropertiesInCommonWith, interfaces_1.DiagnosticCode.ThisContextOfTypeNotAssignableToMethodOfThisType, interfaces_1.DiagnosticCode.ValueOfTypeNotCallable, interfaces_1.DiagnosticCode.ExpressionNotCallable, interfaces_1.DiagnosticCode.TypeNotAssignableWithExactOptionalPropertyTypes, interfaces_1.DiagnosticCode.TypeNotAssignableToParameterWithExactOptionalPropertyTypes, interfaces_1.DiagnosticCode.TypeNotAssignableTypeOfTargetWithExactOptionalPropertyTypes, interfaces_1.DiagnosticCode.IndexSignatureOnlyPermitsReading, interfaces_1.DiagnosticCode.OnlyVoidFunctionIsNewCallable, interfaces_1.DiagnosticCode.ExpressionNotConstructable, interfaces_1.DiagnosticCode.NewExpressionTargetLackingConstructSignatureHasAnyType, interfaces_1.DiagnosticCode.MemberCannotHaveOverrideModifierBecauseItIsNotDeclaredInBaseClass, interfaces_1.DiagnosticCode.MemberMustHaveOverrideModifier, interfaces_1.DiagnosticCode.StringLiteralTypeIsNotAssignableToUnionTypeWithSuggestion, interfaces_1.DiagnosticCode.ObjectLiteralMayOnlySpecifyKnownProperties, interfaces_1.DiagnosticCode.ObjectLiteralMayOnlySpecifyKnownProperties2, interfaces_1.DiagnosticCode.UnableToResolveSignatureOfClassDecorator, interfaces_1.DiagnosticCode.UnableToResolveSignatureOfParameterDecorator, interfaces_1.DiagnosticCode.UnableToResolveSignatureOfPropertyDecorator, interfaces_1.DiagnosticCode.UnableToResolveSignatureOfMethodDecorator, interfaces_1.DiagnosticCode.DecoratorCanOnlyDecorateMethodImplementation, interfaces_1.DiagnosticCode.DecoratorFunctionReturnTypeNotAssignableToType, interfaces_1.DiagnosticCode.DecoratorFunctionReturnTypeExpectedToBeVoidOrAny, interfaces_1.DiagnosticCode.RuntimeWillInvokeDecoratorWithXArgumentsButDecoratorExpectsY, interfaces_1.DiagnosticCode.RuntimeWillInvokeDecoratorWithXArgumentsButDecoratorExpectsAtLeastY, interfaces_1.DiagnosticCode.AcceptsTooFewArgumentsToBeUsedAsDecoratorHere, interfaces_1.DiagnosticCode.PropertyDoesNotExistOnTypeDidYouMean, interfaces_1.DiagnosticCode.ErrorIsOfTypeUnknown, interfaces_1.DiagnosticCode.TwoDifferentTypesSameName, ]); /** * Check if the provided diagnostic should be ignored. * * @param diagnostic - The diagnostic to validate. * @param expectedErrors - Map of the expected errors. * @returns Whether the diagnostic should be `'preserve'`d, `'ignore'`d or, in case that * the diagnostic is reported from inside of an `expectError` assertion, the `Location` * of the assertion. */ const ignoreDiagnostic = (diagnostic, expectedErrors) => { if (ignoredDiagnostics.has(diagnostic.code)) { // Filter out diagnostics which are present in the `ignoredDiagnostics` set return 'ignore'; } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const diagnosticFileName = diagnostic.file.fileName; for (const [location, error] of expectedErrors) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const start = diagnostic.start; // Diagnostic is inside of `expectError` clause if (diagnosticFileName === location.fileName && start > location.start && start < location.end) { if (expectErrorDiagnosticCodesToIgnore.has(diagnostic.code)) { return location; } // Ignore syntactical errors if (diagnostic.code < 2000) { expectedErrors.delete(location); return 'preserve'; } // Set diagnostic code on `ExpectedError` to log error.code = diagnostic.code; return 'preserve'; } } return 'preserve'; }; /** * Get a list of TypeScript diagnostics within the current context. * * @param context - The context object. * @returns List of diagnostics */ const getDiagnostics = (context) => { const diagnostics = []; const program = (0, typescript_1.createProgram)(context.testFiles, context.config.compilerOptions); const tsDiagnostics = program .getSemanticDiagnostics() .concat(program.getSyntacticDiagnostics()); const assertions = (0, parser_1.extractAssertions)(program); diagnostics.push(...(0, assertions_1.handle)(program.getTypeChecker(), assertions)); const expectedErrors = (0, parser_1.parseErrorAssertionToLocation)(assertions); const expectedErrorsLocationsWithFoundDiagnostics = []; for (const diagnostic of tsDiagnostics) { /* Filter out all diagnostic messages without a file or from node_modules directories, files under * node_modules are most definitely not under test. */ if (!diagnostic.file || /[/\\]node_modules[/\\]/.test(diagnostic.file.fileName)) { continue; } const ignoreDiagnosticResult = ignoreDiagnostic(diagnostic, expectedErrors); if (ignoreDiagnosticResult !== 'preserve') { if (ignoreDiagnosticResult !== 'ignore') { expectedErrorsLocationsWithFoundDiagnostics.push(ignoreDiagnosticResult); } continue; } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); diagnostics.push({ fileName: diagnostic.file.fileName, message: (0, typescript_1.flattenDiagnosticMessageText)(diagnostic.messageText, '\n'), severity: 'error', line: position.line + 1, column: position.character }); } for (const errorLocationToRemove of expectedErrorsLocationsWithFoundDiagnostics) { expectedErrors.delete(errorLocationToRemove); } for (const [, diagnostic] of expectedErrors) { const message = diagnostic.code ? `Found an error that tsd does not currently support (\`ts${diagnostic.code}\`), consider creating an issue on GitHub.` : 'Expected an error, but found none.'; diagnostics.push(Object.assign(Object.assign({}, diagnostic), { message, severity: 'error' })); } return diagnostics; }; exports.getDiagnostics = getDiagnostics;