Skip to content

Commit

Permalink
feat: expectAssignable and expectNotAssignable
Browse files Browse the repository at this point in the history
  • Loading branch information
skarab42 committed Jul 11, 2022
1 parent c040f02 commit fb1eb2e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 7 deletions.
6 changes: 4 additions & 2 deletions src/common/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ export enum ErrorCode {
ASSERT_MISSING_GENERIC,
ASSERT_MISSING_ARGUMENT,
ASSERT_TYPE_NOT_ASSIGNABLE,
ASSERT_TYPE_TOO_WIDE,
ASSERT_TYPE_ASSIGNABLE,
ASSERT_TYPE_NOT_IDENTICAL,
ASSERT_TYPE_IDENTICAL,
ASSERT_TYPE_TOO_WIDE,
}

export const errorMessages: Record<ErrorCode, string> = {
Expand All @@ -23,9 +24,10 @@ export const errorMessages: Record<ErrorCode, string> = {
[ErrorCode.ASSERT_MISSING_GENERIC]: 'Missing generic at position {position}',
[ErrorCode.ASSERT_MISSING_ARGUMENT]: 'Missing argument at position {position}',
[ErrorCode.ASSERT_TYPE_NOT_ASSIGNABLE]: "Type '{expected}' is not assignable to type '{argument}'.",
[ErrorCode.ASSERT_TYPE_TOO_WIDE]: "Type '{expected}' is declared too wide for argument type '{argument}'.",
[ErrorCode.ASSERT_TYPE_ASSIGNABLE]: "Type '{expected}' is assignable to type '{argument}'.",
[ErrorCode.ASSERT_TYPE_NOT_IDENTICAL]: "Type '{expected}' is not identical to argument type '{argument}'.",
[ErrorCode.ASSERT_TYPE_IDENTICAL]: "Type '{expected}' is identical to argument type '{argument}'.",
[ErrorCode.ASSERT_TYPE_TOO_WIDE]: "Type '{expected}' is declared too wide for argument type '{argument}'.",
};

export function errorMessage(code: ErrorCode, data?: Record<string, unknown>): string {
Expand Down
49 changes: 44 additions & 5 deletions src/plugin/assert/tsd/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function typeError(
);
}

// https://github.com/SamVerschueren/tsd/blob/main/source/lib/assertions/handlers/identicality.ts#L12
// https://github.dev/SamVerschueren/tsd/blob/e4a398c1b47a4d2f914446b662840e2be5994997/source/lib/assertions/handlers/identicality.ts#L12
export function expectType({ node }: Assertion, { sourceFile, typeChecker }: Compiler): ts.Diagnostic | undefined {
if (!node.typeArguments?.[0]) {
return missingGeneric(node, sourceFile);
Expand Down Expand Up @@ -71,6 +71,7 @@ export function expectType({ node }: Assertion, { sourceFile, typeChecker }: Com
return;
}

// https://github.dev/SamVerschueren/tsd/blob/e4a398c1b47a4d2f914446b662840e2be5994997/source/lib/assertions/handlers/identicality.ts#L61
export function expectNotType({ node }: Assertion, { sourceFile, typeChecker }: Compiler): ts.Diagnostic | undefined {
if (!node.typeArguments?.[0]) {
return missingGeneric(node, sourceFile);
Expand All @@ -90,12 +91,50 @@ export function expectNotType({ node }: Assertion, { sourceFile, typeChecker }:
return;
}

export function expectAssignable(assertion: Assertion, compiler: Compiler): ts.Diagnostic | undefined {
return createAssertionDiagnostic('Not yet implemented.', compiler.sourceFile, assertion.node.getStart());
// In tsd this is handled directlly by TypeScript.
export function expectAssignable(
{ node }: Assertion,
{ sourceFile, typeChecker }: Compiler,
): ts.Diagnostic | undefined {
if (!node.typeArguments?.[0]) {
return missingGeneric(node, sourceFile);
}

if (!node.arguments[0]) {
return missingArgument(node, sourceFile);
}

const expectedType = typeChecker.getTypeFromTypeNode(node.typeArguments[0]);
const argumentType = typeChecker.getTypeAtLocation(node.arguments[0]);

if (!typeChecker.isTypeAssignableTo(argumentType, expectedType)) {
return typeError(ErrorCode.ASSERT_TYPE_NOT_ASSIGNABLE, typeChecker, expectedType, argumentType, sourceFile, node);
}

return;
}

export function expectNotAssignable(assertion: Assertion, compiler: Compiler): ts.Diagnostic | undefined {
return createAssertionDiagnostic('Not yet implemented.', compiler.sourceFile, assertion.node.getStart());
// https://github.dev/SamVerschueren/tsd/blob/e4a398c1b47a4d2f914446b662840e2be5994997/source/lib/assertions/handlers/assignability.ts#L12-L13
export function expectNotAssignable(
{ node }: Assertion,
{ sourceFile, typeChecker }: Compiler,
): ts.Diagnostic | undefined {
if (!node.typeArguments?.[0]) {
return missingGeneric(node, sourceFile);
}

if (!node.arguments[0]) {
return missingArgument(node, sourceFile);
}

const expectedType = typeChecker.getTypeFromTypeNode(node.typeArguments[0]);
const argumentType = typeChecker.getTypeAtLocation(node.arguments[0]);

if (typeChecker.isTypeAssignableTo(argumentType, expectedType)) {
return typeError(ErrorCode.ASSERT_TYPE_ASSIGNABLE, typeChecker, expectedType, argumentType, sourceFile, node);
}

return;
}

export function expectError(assertion: Assertion, compiler: Compiler): ts.Diagnostic | undefined {
Expand Down

0 comments on commit fb1eb2e

Please sign in to comment.