Skip to content

Commit

Permalink
fix(instrumenter): don't mutate TS generics (#3268)
Browse files Browse the repository at this point in the history
Don't mutate generic declarations, like `{color} {position}` in

 ```ts
 function foo<T extends `{color} {position}`>() {
 }
 ```
  • Loading branch information
nicojs authored Nov 20, 2021
1 parent 8932322 commit 88d6eaf
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
14 changes: 12 additions & 2 deletions packages/instrumenter/src/util/syntax-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ export function isTypeNode(path: NodePath): boolean {
path.isTypeAnnotation() ||
flowTypeAnnotationNodeTypes.includes(path.node.type) ||
tsTypeAnnotationNodeTypes.includes(path.node.type) ||
isDeclareVariableStatement(path)
isDeclareVariableStatement(path) ||
isDeclareModule(path)
);
}

Expand All @@ -144,15 +145,24 @@ function isDeclareVariableStatement(path: NodePath): boolean {
return path.isVariableDeclaration() && path.node.declare === true;
}

/**
* Determines whether or not a node is a string literal that is the name of a module.
* @example
* declare module "express" {};
*/
function isDeclareModule(path: NodePath): boolean {
return path.isTSModuleDeclaration() && (path.node.declare ?? false);
}

const tsTypeAnnotationNodeTypes: ReadonlyArray<types.Node['type']> = Object.freeze([
'TSAsExpression',
'TSInterfaceDeclaration',
'TSTypeAnnotation',
'TSTypeAliasDeclaration',
'TSModuleDeclaration',
'TSEnumDeclaration',
'TSDeclareFunction',
'TSTypeParameterInstantiation',
'TSTypeParameterDeclaration',
]);

const flowTypeAnnotationNodeTypes: ReadonlyArray<types.Node['type']> = Object.freeze([
Expand Down
53 changes: 53 additions & 0 deletions packages/instrumenter/test/unit/util/syntax-helpers.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect } from 'chai';

import * as syntaxHelpers from '../../../src/util/syntax-helpers';
import { findNodePath, parseTS } from '../../helpers/syntax-test-helpers';

describe('syntax-helpers', () => {
describe('instrumentationBabelHeader', () => {
Expand All @@ -9,4 +10,56 @@ describe('syntax-helpers', () => {
expect(syntaxHelpers.instrumentationBabelHeader[0].leadingComments).frozen;
});
});

describe('isTypeNode', () => {
it('should identify type assertions ("as")', () => {
const input = findNodePath(parseTS('const foo = { bar: "baz" } as const'), (p) => p.isTSAsExpression());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should identify interface declarations', () => {
const input = findNodePath(parseTS('interface Foo {}'), (p) => p.isTSInterfaceDeclaration());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should identify type annotations', () => {
const input = findNodePath(parseTS('const foo: bar = baz;'), (p) => p.isTSTypeAnnotation());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should identify type alias declarations', () => {
const input = findNodePath(parseTS('type Foo = "bar"'), (p) => p.isTSTypeAliasDeclaration());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should identify TS module declarations', () => {
const input = findNodePath(parseTS('declare module "express" {}'), (p) => p.isTSModuleDeclaration());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should be false for module (without `declare`)', () => {
const input = findNodePath(parseTS('namespace A { }'), (p) => p.isTSModuleDeclaration());
expect(syntaxHelpers.isTypeNode(input)).false;
});

it('should identify TS enum declarations', () => {
const input = findNodePath(parseTS('enum A { B }'), (p) => p.isTSEnumDeclaration());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should identify TS declare function syntax', () => {
const input = findNodePath(parseTS('declare function foo(): void;'), (p) => p.isTSDeclareFunction());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should identify TS generic type parameter instantiations', () => {
const input = findNodePath(parseTS('foo<"test">()'), (p) => p.isTSTypeParameterInstantiation());
expect(syntaxHelpers.isTypeNode(input)).true;
});

it('should identify TS generic type parameters declarations', () => {
const input = findNodePath(parseTS('function foo<bar extends `${position} ${color}`>() { }'), (p) => p.isTSTypeParameterDeclaration());
expect(syntaxHelpers.isTypeNode(input)).true;
});
});
});

0 comments on commit 88d6eaf

Please sign in to comment.