Skip to content

Commit

Permalink
Add regression test for #161 (#164)
Browse files Browse the repository at this point in the history
  • Loading branch information
tommy-mitchell authored Sep 17, 2022
1 parent 22285f9 commit 09c0d17
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 20 deletions.
54 changes: 34 additions & 20 deletions source/lib/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,47 @@ export const extractAssertions = (program: Program): Map<Assertion, Set<CallExpr
const checker = program.getTypeChecker();

/**
* Recursively loop over all the nodes and extract all the assertions out of the source files.
* Checks if the given node is semantically valid and is an assertion.
*/
function walkNodes(node: Node) {
if (isCallExpression(node)) {
const expression = isPropertyAccessExpression(node.expression) ?
node.expression.name :
node.expression;
function handleNode(node: CallExpression) {
const expression = isPropertyAccessExpression(node.expression) ?
node.expression.name :
node.expression;

const maybeSymbol = checker.getSymbolAtLocation(expression);

if (!maybeSymbol) {
// Bail out if a Symbol doesn't exist for this Node
// This either means a symbol could not be resolved
// for an identifier, or that the expression is
// syntactically valid, but not semantically valid.
return;
}

const symbol = maybeSymbol.flags & SymbolFlags.Alias ?
checker.getAliasedSymbol(maybeSymbol) :
maybeSymbol;

const maybeAlias = checker.getSymbolAtLocation(expression);
if (maybeAlias) {
const symbol = maybeAlias.flags & SymbolFlags.Alias ?
checker.getAliasedSymbol(maybeAlias) :
maybeAlias;
const identifier = symbol.getName();

const identifier = symbol.getName();
// Check if the call type is a valid assertion
if (assertionFnNames.has(identifier)) {
const assertion = identifier as Assertion;

// Check if the call type is a valid assertion
if (assertionFnNames.has(identifier)) {
const assertion = identifier as Assertion;
const nodes = assertions.get(assertion) ?? new Set<CallExpression>();

const nodes = assertions.get(assertion) ?? new Set<CallExpression>();
nodes.add(node);

nodes.add(node);
assertions.set(assertion, nodes);
}
}

assertions.set(assertion, nodes);
}
}
/**
* Recursively loop over all the nodes and extract all the assertions out of the source files.
*/
function walkNodes(node: Node) {
if (isCallExpression(node)) {
handleNode(node);
}

forEachChild(node, walkNodes);
Expand Down
1 change: 1 addition & 0 deletions source/test/fixtures/undefined-symbol/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {}
7 changes: 7 additions & 0 deletions source/test/fixtures/undefined-symbol/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {expectType} from '../../../..';

// Identifier `bar` has no Symbol
const anyCall = (foo: any) => foo.bar();

// Fails with `Cannot read properties of undefined (reading 'flags')` in 0.24.0
expectType<any>(anyCall('foo'));
3 changes: 3 additions & 0 deletions source/test/fixtures/undefined-symbol/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "foo"
}
6 changes: 6 additions & 0 deletions source/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,3 +466,9 @@ test('assertions should be identified if aliased', async t => {

verify(t, diagnostics, []);
});

test('parsing undefined symbol should not fail', async t => {
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/undefined-symbol')});

verify(t, diagnostics, []);
});

0 comments on commit 09c0d17

Please sign in to comment.