Add support for extending builtins (#7020)

This commit is contained in:
Nicolò Ribaudo
2017-12-20 20:46:00 +01:00
committed by Henry Zhu
parent 148fe7d3ff
commit 0c885b3200
22 changed files with 244 additions and 7 deletions

View File

@@ -3,6 +3,15 @@ import VanillaTransformer from "./vanilla";
import annotateAsPure from "@babel/helper-annotate-as-pure";
import nameFunction from "@babel/helper-function-name";
import { types as t } from "@babel/core";
import globals from "globals";
const getBuiltinClasses = category =>
Object.keys(globals[category]).filter(name => /^[A-Z]/.test(name));
const builtinClasses = new Set([
...getBuiltinClasses("builtin"),
...getBuiltinClasses("browser"),
]);
export default function(api, options) {
const { loose } = options;
@@ -54,7 +63,9 @@ export default function(api, options) {
node[VISITED] = true;
path.replaceWith(new Constructor(path, state.file).run());
path.replaceWith(
new Constructor(path, state.file, builtinClasses).run(),
);
if (path.isCallExpression()) {
annotateAsPure(path);

View File

@@ -4,6 +4,8 @@ import optimiseCall from "@babel/helper-optimise-call-expression";
import * as defineMap from "@babel/helper-define-map";
import { traverse, template, types as t } from "@babel/core";
type ReadonlySet<T> = Set<T> | { has(val: T): boolean };
const noMethodVisitor = {
"FunctionExpression|FunctionDeclaration"(path) {
path.skip();
@@ -61,7 +63,7 @@ const findThisesVisitor = traverse.visitors.merge([
]);
export default class ClassTransformer {
constructor(path: NodePath, file) {
constructor(path: NodePath, file, builtinClasses: ReadonlySet<string>) {
this.parent = path.parent;
this.scope = path.scope;
this.node = path.node;
@@ -93,6 +95,12 @@ export default class ClassTransformer {
this.superName = this.node.superClass || t.identifier("Function");
this.isDerived = !!this.node.superClass;
const { name } = this.superName;
this.extendsNative =
this.isDerived &&
builtinClasses.has(name) &&
!this.scope.hasBinding(name, /* noGlobals */ true);
}
run() {
@@ -112,7 +120,13 @@ export default class ClassTransformer {
//
if (this.isDerived) {
closureArgs.push(superName);
if (this.extendsNative) {
closureArgs.push(
t.callExpression(this.file.addHelper("wrapNativeSuper"), [superName]),
);
} else {
closureArgs.push(superName);
}
superName = this.scope.generateUidIdentifierBasedOnNode(superName);
closureParams.push(superName);