diff --git a/packages/babel-helper-check-duplicate-nodes/src/index.ts b/packages/babel-helper-check-duplicate-nodes/src/index.ts index dbf28a69b271..949c5c2a7871 100644 --- a/packages/babel-helper-check-duplicate-nodes/src/index.ts +++ b/packages/babel-helper-check-duplicate-nodes/src/index.ts @@ -5,7 +5,7 @@ export default function checkDuplicateNodes(ast) { throw new Error("checkDuplicateNodes accepts only one argument: ast"); } // A Map from node to its parent - const parentsMap = new WeakMap(); + const parentsMap = new Map(); const hidePrivateProperties = (key, val) => { // Hides properties like _shadowedFunctionLiteral, @@ -42,7 +42,7 @@ export default function checkDuplicateNodes(ast) { for (const child of subNode) { stack.push({ node: child, parent: node }); } - } else { + } else if (typeof subNode === "object" && subNode !== null) { stack.push({ node: subNode, parent: node }); } } diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index b4863fcba0ec..286218741487 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -13,8 +13,8 @@ const toUnenumerable = (object, key) => defineProperty(object, key, { enumerable: false, value: object[key] }); function toESTreeLocation(node: any) { - toUnenumerable(node.loc.start, "index"); - toUnenumerable(node.loc.end, "index"); + node.loc.start && toUnenumerable(node.loc.start, "index"); + node.loc.end && toUnenumerable(node.loc.end, "index"); return node; } @@ -501,6 +501,11 @@ export default (superClass: Class): Class => return toESTreeLocation(super.finishNodeAt(node, type, endLoc)); } + resetStartLocation(node: N.Node, start: number, startLoc: Position) { + super.resetStartLocation(node, start, startLoc); + toESTreeLocation(node); + } + resetEndLocation( node: NodeBase, endLoc?: Position = this.state.lastTokEndLoc, diff --git a/packages/babel-parser/test/estree-throws.js b/packages/babel-parser/test/estree-throws.js index ee5cfa062928..32a181b1988a 100644 --- a/packages/babel-parser/test/estree-throws.js +++ b/packages/babel-parser/test/estree-throws.js @@ -2,12 +2,43 @@ import path from "path"; import runFixtureTests from "./helpers/run-fixture-tests.js"; import { parse } from "../lib/index.js"; import { fileURLToPath } from "url"; +import { VISITOR_KEYS } from "@babel/types"; runFixtureTests( path.join(path.dirname(fileURLToPath(import.meta.url)), "fixtures"), (input, options = {}) => { const plugins = options.plugins || []; - return parse(input, { ...options, plugins: plugins.concat("estree") }); + const ast = parse(input, { ...options, plugins: plugins.concat("estree") }); + + const stack = [ast]; + + let node; + while ((node = stack.pop())) { + const keys = VISITOR_KEYS[node.type]; + if (!keys) continue; + + const loc = node.loc; + if ( + Object.prototype.propertyIsEnumerable.call(loc.start, "index") || + Object.prototype.propertyIsEnumerable.call(loc.end, "index") + ) { + throw Error("loc.index should be not enumerable with estree"); + } + + for (const key of keys) { + const subNode = node[key]; + + if (Array.isArray(subNode)) { + for (const child of subNode) { + stack.push(child); + } + } else if (typeof subNode === "object" && subNode !== null) { + stack.push(subNode); + } + } + } + + return ast; }, true, ); diff --git a/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/input.ts b/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/input.ts new file mode 100644 index 000000000000..d80709945a69 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/input.ts @@ -0,0 +1,13 @@ +export declare const enum Foo { + foo = 1, + bar +} + +class AssertsFoo { + isBar(): asserts this is string { + return; + } + isBaz = (): asserts this is string => { + return; + } +} diff --git a/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/options.json b/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/options.json new file mode 100644 index 000000000000..2f1ca86a22b1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "typescript", + "estree" + ] +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/output.json b/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/output.json new file mode 100644 index 000000000000..052d6e9172e6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/loc-index-property/1/output.json @@ -0,0 +1,177 @@ +{ + "type": "File", + "start":0,"end":186,"loc":{"start":{"line":1,"column":0},"end":{"line":13,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":186,"loc":{"start":{"line":1,"column":0},"end":{"line":13,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ExportNamedDeclaration", + "start":0,"end":54,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "exportKind": "type", + "specifiers": [], + "source": null, + "declaration": { + "type": "TSEnumDeclaration", + "start":7,"end":54,"loc":{"start":{"line":1,"column":7},"end":{"line":4,"column":1}}, + "const": true, + "id": { + "type": "Identifier", + "start":26,"end":29,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":29},"identifierName":"Foo"}, + "name": "Foo" + }, + "members": [ + { + "type": "TSEnumMember", + "start":36,"end":43,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":11}}, + "id": { + "type": "Identifier", + "start":36,"end":39,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":7},"identifierName":"foo"}, + "name": "foo" + }, + "initializer": { + "type": "Literal", + "start":42,"end":43,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":11}}, + "value": 1, + "raw": "1" + } + }, + { + "type": "TSEnumMember", + "start":49,"end":52,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":7}}, + "id": { + "type": "Identifier", + "start":49,"end":52,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":7},"identifierName":"bar"}, + "name": "bar" + } + } + ], + "declare": true + } + }, + { + "type": "ClassDeclaration", + "start":56,"end":186,"loc":{"start":{"line":6,"column":0},"end":{"line":13,"column":1}}, + "id": { + "type": "Identifier", + "start":62,"end":72,"loc":{"start":{"line":6,"column":6},"end":{"line":6,"column":16},"identifierName":"AssertsFoo"}, + "name": "AssertsFoo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":73,"end":186,"loc":{"start":{"line":6,"column":17},"end":{"line":13,"column":1}}, + "body": [ + { + "type": "MethodDefinition", + "start":77,"end":126,"loc":{"start":{"line":7,"column":2},"end":{"line":9,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":77,"end":82,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":7},"identifierName":"isBar"}, + "name": "isBar" + }, + "computed": false, + "kind": "method", + "value": { + "type": "FunctionExpression", + "start":82,"end":126,"loc":{"start":{"line":7,"column":7},"end":{"line":9,"column":3}}, + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "TSTypeAnnotation", + "start":84,"end":108,"loc":{"start":{"line":7,"column":9},"end":{"line":7,"column":33}}, + "typeAnnotation": { + "type": "TSTypePredicate", + "start":86,"end":108,"loc":{"start":{"line":7,"column":11},"end":{"line":7,"column":33}}, + "parameterName": { + "type": "TSThisType", + "start":94,"end":98,"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":23}} + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":102,"end":108,"loc":{"start":{"line":7,"column":27},"end":{"line":7,"column":33}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":102,"end":108,"loc":{"start":{"line":7,"column":27},"end":{"line":7,"column":33}} + } + }, + "asserts": true + } + }, + "body": { + "type": "BlockStatement", + "start":109,"end":126,"loc":{"start":{"line":7,"column":34},"end":{"line":9,"column":3}}, + "body": [ + { + "type": "ReturnStatement", + "start":115,"end":122,"loc":{"start":{"line":8,"column":4},"end":{"line":8,"column":11}}, + "argument": null + } + ] + } + } + }, + { + "type": "PropertyDefinition", + "start":129,"end":184,"loc":{"start":{"line":10,"column":2},"end":{"line":12,"column":3}}, + "static": false, + "key": { + "type": "Identifier", + "start":129,"end":134,"loc":{"start":{"line":10,"column":2},"end":{"line":10,"column":7},"identifierName":"isBaz"}, + "name": "isBaz" + }, + "computed": false, + "value": { + "type": "ArrowFunctionExpression", + "start":137,"end":184,"loc":{"start":{"line":10,"column":10},"end":{"line":12,"column":3}}, + "returnType": { + "type": "TSTypeAnnotation", + "start":139,"end":163,"loc":{"start":{"line":10,"column":12},"end":{"line":10,"column":36}}, + "typeAnnotation": { + "type": "TSTypePredicate", + "start":141,"end":163,"loc":{"start":{"line":10,"column":14},"end":{"line":10,"column":36}}, + "parameterName": { + "type": "TSThisType", + "start":149,"end":153,"loc":{"start":{"line":10,"column":22},"end":{"line":10,"column":26}} + }, + "typeAnnotation": { + "type": "TSTypeAnnotation", + "start":157,"end":163,"loc":{"start":{"line":10,"column":30},"end":{"line":10,"column":36}}, + "typeAnnotation": { + "type": "TSStringKeyword", + "start":157,"end":163,"loc":{"start":{"line":10,"column":30},"end":{"line":10,"column":36}} + } + }, + "asserts": true + } + }, + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":167,"end":184,"loc":{"start":{"line":10,"column":40},"end":{"line":12,"column":3}}, + "body": [ + { + "type": "ReturnStatement", + "start":173,"end":180,"loc":{"start":{"line":11,"column":4},"end":{"line":11,"column":11}}, + "argument": null + } + ] + } + } + } + ] + } + } + ] + } +}