Skip to content

Commit

Permalink
Added createNode helper for nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaKGoldberg committed Feb 6, 2023
1 parent af855b0 commit 733c2d6
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 63 deletions.
49 changes: 14 additions & 35 deletions src/nodes/typeGuards.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as ts from "typescript";
import { describe, expect, it } from "vitest";

import { createNode } from "../test/utils";
import {
isConstAssertionExpression,
isEntityNameExpression,
Expand All @@ -11,44 +12,22 @@ import {

describe("isEntityNameExpression", () => {
it.each([
[false, "a string literal", ts.factory.createStringLiteral("abc")],
[
false,
"a property access expression with an call expression expression",
ts.factory.createPropertyAccessExpression(
ts.factory.createCallExpression(
ts.factory.createIdentifier("abc"),
undefined /* typeArguments */,
undefined /* argumentsArray */
),
"def"
),
],
[true, "an identifier", ts.factory.createIdentifier("abc")],
[
true,
"a property access expression with an identifier expression",
ts.factory.createPropertyAccessExpression(
ts.factory.createIdentifier("abc"),
"def"
),
],
])("returns %j when given %s", (expected, _, node) => {
expect(isEntityNameExpression(node)).toBe(expected);
[false, `"abc"`],
[false, `abc().def`],
[true, "abc"],
[true, `abc.def`],
])("returns %j when given %s", (expected, sourceText) => {
expect(isEntityNameExpression(createNode(sourceText))).toBe(expected);
});
});

describe("isExpression", () => {
it.each([
[
false,
"a literal type node with null",
ts.factory.createLiteralTypeNode(ts.factory.createNull()),
],
[true, "an identifier", ts.factory.createIdentifier("abc")],
[true, "a string literal", ts.factory.createStringLiteral("abc")],
])("returns %j when given %s", (expected, _, node) => {
expect(isExpression(node)).toBe(expected);
[false, `type T = null`],
[true, `abc`],
[true, `"abc"`],
])("returns %j when given %s", (expected, sourceText) => {
expect(isExpression(createNode(sourceText))).toBe(expected);
});
});

Expand Down Expand Up @@ -80,7 +59,7 @@ describe("isParameterDeclaration", () => {
),
],
])("returns %j when given %s", (expected, _, node) => {
expect(isParameterDeclaration(node)).toBe(expected);
expect(isParameterDeclaration(createNode(node))).toBe(expected);
});
});

Expand Down Expand Up @@ -124,6 +103,6 @@ describe("isConstAssertionExpression", () => {
),
],
])("returns %j when given %s", (expected, _, node) => {
expect(isConstAssertionExpression(node)).toBe(expected);
expect(isConstAssertionExpression(createNode(node))).toBe(expected);
});
});
25 changes: 22 additions & 3 deletions src/test/utils.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import ts from "typescript";
import tsvfs from "@typescript/vfs";

export function getSourceFileAndTypeChecker(
textContent: string,
export function createNode<Node extends ts.Node>(
nodeOrSourceText: Node | string
): Node {
if (typeof nodeOrSourceText !== "string") {
return nodeOrSourceText;
}

const sourceFile = ts.createSourceFile(
"file.ts",
nodeOrSourceText,
ts.ScriptTarget.ESNext
);
const statement = sourceFile.statements.at(-1)!;

return (ts.isExpressionStatement(statement)
? statement.expression
: statement) as unknown as Node;
}

export function createSourceFileAndTypeChecker(
sourceText: string,
fileName = "file.ts"
) {
const compilerOptions = {};
const fsMap = tsvfs
.createDefaultMapFromNodeModules(compilerOptions)
.set(fileName, textContent);
.set(fileName, sourceText);
const system = tsvfs.createSystem(fsMap);
const host = tsvfs.createVirtualCompilerHost(system, compilerOptions, ts);
const program = ts.createProgram({
Expand Down
52 changes: 27 additions & 25 deletions src/types/typeGuards.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as ts from "typescript";
import { describe, expect, it } from "vitest";

import { getSourceFileAndTypeChecker } from "../test/utils";
import { createSourceFileAndTypeChecker } from "../test/utils";
import {
isConditionalType,
isIntersectionType,
Expand All @@ -15,15 +15,17 @@ import {
isUniqueESSymbolType,
} from "./typeGuards";

function getTypeForTypeNode(textContent: string) {
const { sourceFile, typeChecker } = getSourceFileAndTypeChecker(textContent);
function getTypeForTypeNode(sourceText: string) {
const { sourceFile, typeChecker } =
createSourceFileAndTypeChecker(sourceText);
const node = sourceFile.statements.at(-1) as ts.TypeAliasDeclaration;

return typeChecker.getTypeAtLocation(node);
}

function getTypeForVariable(textContent: string) {
const { sourceFile, typeChecker } = getSourceFileAndTypeChecker(textContent);
function getTypeForVariable(sourceText: string) {
const { sourceFile, typeChecker } =
createSourceFileAndTypeChecker(sourceText);
const node = sourceFile.statements.at(-1) as ts.VariableStatement;

return typeChecker.getTypeAtLocation(
Expand All @@ -35,8 +37,8 @@ describe("isConditionalType", () => {
it.each([
[false, "type Test = 1;"],
[true, "type Test<T> = T extends 1 ? 2 : 3;"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isConditionalType(type)).toBe(expected);
});
Expand All @@ -46,8 +48,8 @@ describe("isIntersectionType", () => {
it.each([
[false, "type Test = 1;"],
[true, "type Test<T> = T & 1"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isIntersectionType(type)).toBe(expected);
});
Expand All @@ -57,8 +59,8 @@ describe("isLiteralType", () => {
it.each([
[false, "type Test = [];"],
[true, "type Test = 1;"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isLiteralType(type)).toBe(expected);
});
Expand All @@ -68,8 +70,8 @@ describe("isObjectType", () => {
it.each([
[false, "type Test = 1;"],
[true, "type Test = {};"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isObjectType(type)).toBe(expected);
});
Expand All @@ -80,8 +82,8 @@ describe("isUnionOrIntersectionType", () => {
[false, "type Test = 1;"],
[true, "type Test<T> = T | {};"],
[true, "type Test<T> = T & {};"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isUnionOrIntersectionType(type)).toBe(expected);
});
Expand All @@ -91,8 +93,8 @@ describe("isUniqueESSymbolType", () => {
it.each([
[false, "declare const test: 1;"],
[true, "declare const test: unique symbol"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForVariable(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForVariable(sourceText);

expect(isUniqueESSymbolType(type)).toBe(expected);
});
Expand All @@ -102,8 +104,8 @@ describe("isUnionType", () => {
it.each([
[false, "type Test<T> = T & {};"],
[true, "type Test<T> = T | {};"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isUnionType(type)).toBe(expected);
});
Expand All @@ -114,8 +116,8 @@ describe("isTupleType", () => {
[false, "type Test = {};"],
[false, "type Test = string[];"],
[true, "type Test = [];"],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isTupleType(type)).toBe(expected);
});
Expand All @@ -132,8 +134,8 @@ describe("isTupleTypeReference", () => {
type Test = [Data];
`,
],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isTupleTypeReference(type)).toBe(expected);
});
Expand All @@ -150,8 +152,8 @@ describe("isTypeReference", () => {
type Test = Data;
`,
],
])("returns %j when given %s", (expected, textContent) => {
const type = getTypeForTypeNode(textContent);
])("returns %j when given %s", (expected, sourceText) => {
const type = getTypeForTypeNode(sourceText);

expect(isTypeReference(type)).toBe(expected);
});
Expand Down

0 comments on commit 733c2d6

Please sign in to comment.