Refactor types (#1622)

* refactor: isolate babel-types patching
This commit is contained in:
Michael Rawlings 2020-11-04 15:21:53 -08:00 committed by GitHub
parent a8746841cc
commit 769078b26e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 132 additions and 118 deletions

View File

@ -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";

View File

@ -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";

View File

@ -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 };

View File

@ -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);
}
}
}
};

View File

@ -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), [])
)
);

View File

@ -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}".`
);
}
}