From 769078b26e58bc9bbec8037c4529993a5cb231a3 Mon Sep 17 00:00:00 2001 From: Michael Rawlings Date: Wed, 4 Nov 2020 15:21:53 -0800 Subject: [PATCH] Refactor types (#1622) * refactor: isolate babel-types patching --- packages/babel-types/src/definitions/index.js | 114 ------------------ .../index.js => generator/patch.js} | 4 +- packages/babel-types/src/index.js | 11 +- packages/babel-types/src/traverse/patch.js | 46 +++++++ .../types.js => types/definitions.js} | 10 +- packages/babel-types/src/types/patch.js | 65 ++++++++++ 6 files changed, 132 insertions(+), 118 deletions(-) delete mode 100644 packages/babel-types/src/definitions/index.js rename packages/babel-types/src/{generators/index.js => generator/patch.js} (98%) create mode 100644 packages/babel-types/src/traverse/patch.js rename packages/babel-types/src/{definitions/types.js => types/definitions.js} (94%) create mode 100644 packages/babel-types/src/types/patch.js diff --git a/packages/babel-types/src/definitions/index.js b/packages/babel-types/src/definitions/index.js deleted file mode 100644 index d1546df07..000000000 --- a/packages/babel-types/src/definitions/index.js +++ /dev/null @@ -1,114 +0,0 @@ -import * as babelTypes from "@babel/types"; -import { NodePath, Scope } from "@babel/traverse"; -import builder from "@babel/types/lib/builders/builder"; -import defineType from "@babel/types/lib/definitions/utils"; -import * as generatedValidators from "@babel/types/lib/validators/generated"; -import * as referencedValidators from "@babel/types/lib/validators/isReferenced"; -import types from "./types"; - -const { - TYPES, - VISITOR_KEYS, - FLIPPED_ALIAS_KEYS, - DEPRECATED_KEYS, - is -} = babelTypes; - -const aliases = {}; -export const MARKO_TYPES = Object.keys(types); -MARKO_TYPES.forEach(typeName => { - const type = types[typeName]; - for (const alias of type.aliases) { - aliases[alias] = aliases[alias] || []; - aliases[alias].push(typeName); - } - defineType(typeName, type); -}); -const ALIAS_TYPES = Object.keys(aliases); - -// Update TYPES -for (const type of [ - ...Object.keys(VISITOR_KEYS), - ...Object.keys(FLIPPED_ALIAS_KEYS), - ...Object.keys(DEPRECATED_KEYS) -]) { - if (!TYPES.includes(type)) TYPES.push(type); -} - -// add marko validators & builders to `@babel/types` and `@babel/traverse` -MARKO_TYPES.forEach(typeName => { - const lowerName = typeName[0].toLowerCase() + typeName.slice(1); - const checkKey = `is${typeName}`; - const assertKey = `assert${typeName}`; - const checkFn = (babelTypes[checkKey] = (node, opts) => - is(typeName, node, opts)); - const assertFn = (babelTypes[assertKey] = (node, opts) => - assert(typeName, node, opts)); - NodePath.prototype[checkKey] = function(opts) { - return checkFn(this.node, opts); - }; - NodePath.prototype[assertKey] = function(opts) { - assertFn(this.node, opts); - }; - // Add builder. - babelTypes[typeName] = babelTypes[lowerName] = (...args) => - builder(typeName, ...args); -}); - -ALIAS_TYPES.forEach(aliasName => { - const checkKey = `is${aliasName}`; - const originalCheck = generatedValidators[checkKey]; - generatedValidators[checkKey] = (node, opts) => { - return is(aliasName, node, opts) || originalCheck(node, opts); - }; - const originalProtoCheck = NodePath.prototype[checkKey]; - NodePath.prototype[checkKey] = function(opts) { - return ( - is(aliasName, this.node, opts) || - originalProtoCheck.call(this, this.node, opts) - ); - }; -}); - -const originalIsReferenced = referencedValidators.default; -referencedValidators.default = (node, parent, grandparent) => { - if ( - parent.type === "MarkoTag" && - parent.params && - parent.params.includes(node) - ) { - return false; - } - return originalIsReferenced(node, parent, grandparent); -}; - -const originalCrawl = Scope.prototype.crawl; -Scope.prototype.crawl = function() { - const path = this.path; - - originalCrawl.apply(this, arguments); - - if (path.isMarkoTagBody()) { - const params = path.parentPath.get("params"); - - if (params.length) { - for (const param of params) { - this.registerBinding("param", param); - } - } - } -}; - -function assert(typeName, node, opts) { - if (!is(typeName, node, opts)) { - throw new Error( - `Expected type "${typeName}" with option ${JSON.stringify( - opts - )}, but instead got "${node.type}".` - ); - } -} - -// export babel stuff -Object.assign(exports, babelTypes); -export * from "@babel/types"; diff --git a/packages/babel-types/src/generators/index.js b/packages/babel-types/src/generator/patch.js similarity index 98% rename from packages/babel-types/src/generators/index.js rename to packages/babel-types/src/generator/patch.js index 42a7b5606..c2031b022 100644 --- a/packages/babel-types/src/generators/index.js +++ b/packages/babel-types/src/generator/patch.js @@ -1,4 +1,6 @@ -import * as t from "../definitions"; +import "../types/patch"; + +import * as t from "@babel/types"; import SELF_CLOSING from "self-closing-tags"; import Printer from "@babel/generator/lib/printer"; diff --git a/packages/babel-types/src/index.js b/packages/babel-types/src/index.js index 77adce435..fb764111d 100644 --- a/packages/babel-types/src/index.js +++ b/packages/babel-types/src/index.js @@ -1,3 +1,10 @@ -import "./generators"; -import * as types from "./definitions"; +import "./types/patch"; +import "./generator/patch"; +import "./traverse/patch"; + +import * as types from "@babel/types"; +import { MARKO_TYPES } from "./types/definitions"; + +types.MARKO_TYPES = MARKO_TYPES; + export { types }; diff --git a/packages/babel-types/src/traverse/patch.js b/packages/babel-types/src/traverse/patch.js new file mode 100644 index 000000000..6bfe76da6 --- /dev/null +++ b/packages/babel-types/src/traverse/patch.js @@ -0,0 +1,46 @@ +import "../types/patch"; + +import * as t from "@babel/types"; +import { NodePath, Scope } from "@babel/traverse"; +import { MARKO_TYPES, MARKO_ALIAS_TYPES } from "../types/definitions"; + +MARKO_TYPES.forEach(typeName => { + const checkKey = `is${typeName}`; + const assertKey = `assert${typeName}`; + const checkFn = t[checkKey]; + const assertFn = t[assertKey]; + NodePath.prototype[checkKey] = function(opts) { + return checkFn(this.node, opts); + }; + NodePath.prototype[assertKey] = function(opts) { + assertFn(this.node, opts); + }; +}); + +MARKO_ALIAS_TYPES.forEach(aliasName => { + const checkKey = `is${aliasName}`; + const originalProtoCheck = NodePath.prototype[checkKey]; + NodePath.prototype[checkKey] = function(opts) { + return ( + t.is(aliasName, this.node, opts) || + originalProtoCheck.call(this, this.node, opts) + ); + }; +}); + +const originalCrawl = Scope.prototype.crawl; +Scope.prototype.crawl = function() { + const path = this.path; + + originalCrawl.apply(this, arguments); + + if (path.isMarkoTagBody()) { + const params = path.parentPath.get("params"); + + if (params.length) { + for (const param of params) { + this.registerBinding("param", param); + } + } + } +}; diff --git a/packages/babel-types/src/definitions/types.js b/packages/babel-types/src/types/definitions.js similarity index 94% rename from packages/babel-types/src/definitions/types.js rename to packages/babel-types/src/types/definitions.js index 388a7b439..5fe52f79c 100644 --- a/packages/babel-types/src/definitions/types.js +++ b/packages/babel-types/src/types/definitions.js @@ -13,7 +13,7 @@ const valueFieldCommon = { } }; -export default { +const MarkoDefinitions = { MarkoDocumentType: { aliases: ["Marko", "Statement"], builder: ["value"], @@ -204,3 +204,11 @@ export default { } } }; + +export default MarkoDefinitions; +export const MARKO_TYPES = Object.keys(MarkoDefinitions); +export const MARKO_ALIAS_TYPES = Array.from( + new Set( + MARKO_TYPES.reduce((all, t) => all.concat(MarkoDefinitions[t].aliases), []) + ) +); diff --git a/packages/babel-types/src/types/patch.js b/packages/babel-types/src/types/patch.js new file mode 100644 index 000000000..1824592f2 --- /dev/null +++ b/packages/babel-types/src/types/patch.js @@ -0,0 +1,65 @@ +import * as babelTypes from "@babel/types"; +import builder from "@babel/types/lib/builders/builder"; +import defineType from "@babel/types/lib/definitions/utils"; +import * as generatedValidators from "@babel/types/lib/validators/generated"; +import * as referencedValidators from "@babel/types/lib/validators/isReferenced"; +import definitions, { MARKO_TYPES, MARKO_ALIAS_TYPES } from "./definitions"; + +const { + TYPES, + VISITOR_KEYS, + FLIPPED_ALIAS_KEYS, + DEPRECATED_KEYS, + is +} = babelTypes; + +MARKO_TYPES.forEach(typeName => { + defineType(typeName, definitions[typeName]); +}); + +for (const type of [ + ...Object.keys(VISITOR_KEYS), + ...Object.keys(FLIPPED_ALIAS_KEYS), + ...Object.keys(DEPRECATED_KEYS) +]) { + if (!TYPES.includes(type)) TYPES.push(type); +} + +MARKO_TYPES.forEach(typeName => { + const lowerName = typeName[0].toLowerCase() + typeName.slice(1); + const checkKey = `is${typeName}`; + const assertKey = `assert${typeName}`; + babelTypes[checkKey] = (node, opts) => is(typeName, node, opts); + babelTypes[assertKey] = (node, opts) => assert(typeName, node, opts); + babelTypes[typeName] = babelTypes[lowerName] = (...args) => + builder(typeName, ...args); +}); + +MARKO_ALIAS_TYPES.forEach(aliasName => { + const checkKey = `is${aliasName}`; + const originalCheck = generatedValidators[checkKey]; + generatedValidators[checkKey] = (node, opts) => + is(aliasName, node, opts) || originalCheck(node, opts); +}); + +const originalIsReferenced = referencedValidators.default; +referencedValidators.default = (node, parent, grandparent) => { + if ( + parent.type === "MarkoTag" && + parent.params && + parent.params.includes(node) + ) { + return false; + } + return originalIsReferenced(node, parent, grandparent); +}; + +function assert(typeName, node, opts) { + if (!is(typeName, node, opts)) { + throw new Error( + `Expected type "${typeName}" with option ${JSON.stringify( + opts + )}, but instead got "${node.type}".` + ); + } +}