From e9184ed05e720601d96c2396536c9d99bf002433 Mon Sep 17 00:00:00 2001 From: Tim Kendrick Date: Fri, 6 Jul 2018 13:45:25 +0100 Subject: [PATCH] [babel-types] Fix isNodesEquivalent() behavior for TemplateElements (#8165) Fixes #8163 The `isNodesEquivalent()` algorithm incorrectly assumes that any object properties must themselves be AST nodes, which is not the case here, causing the error. --- .../src/validators/isNodesEquivalent.js | 15 ++++++++++++++- packages/babel-types/test/validators.js | 8 ++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/babel-types/src/validators/isNodesEquivalent.js b/packages/babel-types/src/validators/isNodesEquivalent.js index ab689f5693..68672ff964 100644 --- a/packages/babel-types/src/validators/isNodesEquivalent.js +++ b/packages/babel-types/src/validators/isNodesEquivalent.js @@ -1,5 +1,5 @@ // @flow -import { NODE_FIELDS } from "../definitions"; +import { NODE_FIELDS, VISITOR_KEYS } from "../definitions"; /** * Check if two nodes are equivalent @@ -19,6 +19,7 @@ export default function isNodesEquivalent(a: any, b: any): boolean { } const fields = Object.keys(NODE_FIELDS[a.type] || a.type); + const visitorKeys = VISITOR_KEYS[a.type]; for (const field of fields) { if (typeof a[field] !== typeof b[field]) { @@ -41,6 +42,18 @@ export default function isNodesEquivalent(a: any, b: any): boolean { continue; } + if ( + typeof a[field] === "object" && + (!visitorKeys || !visitorKeys.includes(field)) + ) { + for (const key in a[field]) { + if (a[field][key] !== b[field][key]) { + return false; + } + } + continue; + } + if (!isNodesEquivalent(a[field], b[field])) { return false; } diff --git a/packages/babel-types/test/validators.js b/packages/babel-types/test/validators.js index aaa02da501..f285b11056 100644 --- a/packages/babel-types/test/validators.js +++ b/packages/babel-types/test/validators.js @@ -26,6 +26,14 @@ describe("validators", function() { expect(t.isNodesEquivalent(parse(program), parse(program2))).toBe(false); }); + it("should handle nodes with object properties", function() { + const original = t.templateElement({ raw: "\\'a", cooked: "'a" }, true); + const identical = t.templateElement({ raw: "\\'a", cooked: "'a" }, true); + const different = t.templateElement({ raw: "'a", cooked: "'a" }, true); + expect(t.isNodesEquivalent(original, identical)).toBe(true); + expect(t.isNodesEquivalent(original, different)).toBe(false); + }); + it("rejects 'await' as an identifier", function() { expect(t.isValidIdentifier("await")).toBe(false); });