diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 1f079b71055..9a9be6bcd33 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -379,7 +379,19 @@ export class Converter { * property instead of a kind property. Recursively copies all children. */ private deeplyCopy(node: TSNode): any { + if ( + node.kind >= SyntaxKind.FirstJSDocNode && + node.kind <= SyntaxKind.LastJSDocNode + ) { + throw createError( + this.ast, + node.pos, + 'JSDoc types can only be used inside documentation comments.', + ); + } + const customType = `TS${SyntaxKind[node.kind]}` as AST_NODE_TYPES; + /** * If the "errorOnUnknownASTType" option is set to true, throw an error, * otherwise fallback to just including the unknown type as-is. @@ -387,6 +399,7 @@ export class Converter { if (this.options.errorOnUnknownASTType && !AST_NODE_TYPES[customType]) { throw new Error(`Unknown AST_NODE_TYPE: "${customType}"`); } + const result = this.createNode(node, { type: customType, }); diff --git a/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap b/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap index b7266a75dd0..82c53ddf8cb 100644 --- a/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap +++ b/packages/typescript-estree/tests/lib/__snapshots__/convert.ts.snap @@ -179,24 +179,6 @@ exports[`convert deeplyCopy should convert node correctly 1`] = ` Object { "body": Array [ Object { - "id": Object { - "loc": Object { - "end": Object { - "column": 8, - "line": 1, - }, - "start": Object { - "column": 5, - "line": 1, - }, - }, - "name": "foo", - "range": Array [ - 5, - 8, - ], - "type": "Identifier", - }, "loc": Object { "end": Object { "column": 35, @@ -207,294 +189,34 @@ Object { "line": 1, }, }, - "range": Array [ - 0, - 35, - ], - "type": "TSTypeAliasDeclaration", - "typeAnnotation": Object { + "modifiers": undefined, + "name": Object { + "escapedText": "foo", "loc": Object { "end": Object { - "column": 35, + "column": 8, "line": 1, }, "start": Object { - "column": 11, + "column": 5, "line": 1, }, }, "range": Array [ - 11, - 35, + 5, + 8, ], "transformFlags": 0, - "type": "TSJSDocNullableType", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 35, - "line": 1, - }, - "start": Object { - "column": 11, - "line": 1, - }, - }, - "range": Array [ - 11, - 35, - ], - "type": "TSTypeAnnotation", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 35, - "line": 1, - }, - "start": Object { - "column": 12, - "line": 1, - }, - }, - "range": Array [ - 12, - 35, - ], - "type": "TSUnionType", - "types": Array [ - Object { - "loc": Object { - "end": Object { - "column": 18, - "line": 1, - }, - "start": Object { - "column": 12, - "line": 1, - }, - }, - "range": Array [ - 12, - 18, - ], - "type": "TSTypeReference", - "typeName": Object { - "loc": Object { - "end": Object { - "column": 15, - "line": 1, - }, - "start": Object { - "column": 12, - "line": 1, - }, - }, - "name": "foo", - "range": Array [ - 12, - 15, - ], - "type": "Identifier", - }, - "typeParameters": Object { - "loc": Object { - "end": Object { - "column": 18, - "line": 1, - }, - "start": Object { - "column": 15, - "line": 1, - }, - }, - "params": Array [ - Object { - "loc": Object { - "end": Object { - "column": 17, - "line": 1, - }, - "start": Object { - "column": 16, - "line": 1, - }, - }, - "range": Array [ - 16, - 17, - ], - "type": "TSTypeReference", - "typeName": Object { - "loc": Object { - "end": Object { - "column": 17, - "line": 1, - }, - "start": Object { - "column": 16, - "line": 1, - }, - }, - "name": "T", - "range": Array [ - 16, - 17, - ], - "type": "Identifier", - }, - "typeParameters": undefined, - }, - ], - "range": Array [ - 15, - 18, - ], - "type": "TSTypeParameterInstantiation", - }, - }, - Object { - "loc": Object { - "end": Object { - "column": 35, - "line": 1, - }, - "start": Object { - "column": 21, - "line": 1, - }, - }, - "range": Array [ - 21, - 35, - ], - "transformFlags": 0, - "type": "TSJSDocNullableType", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 35, - "line": 1, - }, - "start": Object { - "column": 21, - "line": 1, - }, - }, - "range": Array [ - 21, - 35, - ], - "type": "TSTypeAnnotation", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 35, - "line": 1, - }, - "start": Object { - "column": 22, - "line": 1, - }, - }, - "range": Array [ - 22, - 35, - ], - "transformFlags": 0, - "type": "TSJSDocNullableType", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 34, - "line": 1, - }, - "start": Object { - "column": 21, - "line": 1, - }, - }, - "range": Array [ - 21, - 34, - ], - "type": "TSTypeAnnotation", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 34, - "line": 1, - }, - "start": Object { - "column": 22, - "line": 1, - }, - }, - "range": Array [ - 22, - 34, - ], - "type": "TSParenthesizedType", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 33, - "line": 1, - }, - "start": Object { - "column": 23, - "line": 1, - }, - }, - "params": Array [], - "range": Array [ - 23, - 33, - ], - "returnType": Object { - "loc": Object { - "end": Object { - "column": 33, - "line": 1, - }, - "start": Object { - "column": 26, - "line": 1, - }, - }, - "range": Array [ - 26, - 33, - ], - "type": "TSTypeAnnotation", - "typeAnnotation": Object { - "loc": Object { - "end": Object { - "column": 33, - "line": 1, - }, - "start": Object { - "column": 29, - "line": 1, - }, - }, - "range": Array [ - 29, - 33, - ], - "type": "TSVoidKeyword", - }, - }, - "type": "TSFunctionType", - }, - }, - }, - }, - }, - }, - ], - }, - }, + "type": "TSUnparsedPrologue", }, + "range": Array [ + 0, + 35, + ], + "transformFlags": 0, + "type": "TSUnparsedPrologue", + "typeAnnotation": null, + "typeParameters": null, }, ], "loc": Object { diff --git a/packages/typescript-estree/tests/lib/convert.ts b/packages/typescript-estree/tests/lib/convert.ts index e4217be7d22..208513d1aed 100644 --- a/packages/typescript-estree/tests/lib/convert.ts +++ b/packages/typescript-estree/tests/lib/convert.ts @@ -17,6 +17,13 @@ describe('convert', () => { it('deeplyCopy should convert node correctly', () => { const ast = convertCode('type foo = ?foo | ?(() => void)?'); + function fakeUnknownKind(node: ts.Node): void { + ts.forEachChild(node, fakeUnknownKind); + node.kind = ts.SyntaxKind.UnparsedPrologue; + } + + ts.forEachChild(ast, fakeUnknownKind); + const instance = new Converter(ast, { errorOnUnknownASTType: false, useJSXTextNode: false, @@ -32,8 +39,9 @@ describe('convert', () => { errorOnUnknownASTType: false, useJSXTextNode: false, shouldPreserveNodeMaps: false, - }); - expect((instance as any).deeplyCopy(ast.statements[0])).toMatchSnapshot(); + }) as any; + + expect(instance.deeplyCopy(ast.statements[0])).toMatchSnapshot(); }); it('deeplyCopy should convert node with type parameters correctly', () => { @@ -43,8 +51,9 @@ describe('convert', () => { errorOnUnknownASTType: false, useJSXTextNode: false, shouldPreserveNodeMaps: false, - }); - expect((instance as any).deeplyCopy(ast.statements[0])).toMatchSnapshot(); + }) as any; + + expect(instance.deeplyCopy(ast.statements[0])).toMatchSnapshot(); }); it('deeplyCopy should convert node with type arguments correctly', () => { @@ -54,9 +63,10 @@ describe('convert', () => { errorOnUnknownASTType: false, useJSXTextNode: false, shouldPreserveNodeMaps: false, - }); + }) as any; + expect( - (instance as any).deeplyCopy((ast.statements[0] as any).expression), + instance.deeplyCopy((ast.statements[0] as any).expression), ).toMatchSnapshot(); }); @@ -67,8 +77,8 @@ describe('convert', () => { errorOnUnknownASTType: false, useJSXTextNode: false, shouldPreserveNodeMaps: false, - }); - expect((instance as any).deeplyCopy(ast)).toMatchSnapshot(); + }) as any; + expect(instance.deeplyCopy(ast)).toMatchSnapshot(); }); it('deeplyCopy should fail on unknown node', () => { @@ -78,9 +88,10 @@ describe('convert', () => { errorOnUnknownASTType: true, useJSXTextNode: false, shouldPreserveNodeMaps: false, - }); - expect(() => instance.convertProgram()).toThrow( - 'Unknown AST_NODE_TYPE: "TSJSDocNullableType"', + }) as any; + + expect(() => instance.deeplyCopy(ast)).toThrow( + 'Unknown AST_NODE_TYPE: "TSSourceFile"', ); }); @@ -225,4 +236,24 @@ describe('convert', () => { range: [0, 20], }); }); + + it('should throw error on jsDoc node', () => { + const jsDocCode = [ + 'type foo = ?foo | ?(() => void)?', + 'var a: function(b): c;', + ]; + + for (const code of jsDocCode) { + const ast = convertCode(code); + + const instance = new Converter(ast, { + errorOnUnknownASTType: false, + useJSXTextNode: false, + shouldPreserveNodeMaps: false, + }); + expect(() => instance.convertProgram()).toThrow( + 'JSDoc types can only be used inside documentation comments.', + ); + } + }); });