Make sure to actually use yarn to install the main-packages, otherwise the packages.json#resolutions property will not be used and @babel/helpers would not get overruled
Overruled @babel/helpers to fix how initializers play with decorated properties. Thus circumventing the imperformant and lengthy code being generated by babel in the non-legacy option.
This commit is contained in:
3
packages/babel-helpers/.npmignore
Normal file
3
packages/babel-helpers/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
||||
src
|
||||
test
|
||||
*.log
|
||||
19
packages/babel-helpers/README.md
Normal file
19
packages/babel-helpers/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# @babel/helpers
|
||||
|
||||
> Collection of helper functions used by Babel transforms.
|
||||
|
||||
See our website [@babel/helpers](https://babeljs.io/docs/en/next/babel-helpers.html) for more information.
|
||||
|
||||
## Install
|
||||
|
||||
Using npm:
|
||||
|
||||
```sh
|
||||
npm install --save-dev @babel/helpers
|
||||
```
|
||||
|
||||
or using yarn:
|
||||
|
||||
```sh
|
||||
yarn add @babel/helpers --dev
|
||||
```
|
||||
1919
packages/babel-helpers/lib/helpers.js
Normal file
1919
packages/babel-helpers/lib/helpers.js
Normal file
File diff suppressed because it is too large
Load Diff
276
packages/babel-helpers/lib/index.js
Normal file
276
packages/babel-helpers/lib/index.js
Normal file
@@ -0,0 +1,276 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.get = get;
|
||||
exports.minVersion = minVersion;
|
||||
exports.getDependencies = getDependencies;
|
||||
exports.ensure = ensure;
|
||||
exports.default = exports.list = void 0;
|
||||
|
||||
var _traverse = _interopRequireDefault(require("@babel/traverse"));
|
||||
|
||||
var t = _interopRequireWildcard(require("@babel/types"));
|
||||
|
||||
var _helpers = _interopRequireDefault(require("./helpers"));
|
||||
|
||||
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
||||
|
||||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; if (obj != null) { var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function makePath(path) {
|
||||
const parts = [];
|
||||
|
||||
for (; path.parentPath; path = path.parentPath) {
|
||||
parts.push(path.key);
|
||||
if (path.inList) parts.push(path.listKey);
|
||||
}
|
||||
|
||||
return parts.reverse().join(".");
|
||||
}
|
||||
|
||||
function getHelperMetadata(file) {
|
||||
const globals = new Set();
|
||||
const localBindingNames = new Set();
|
||||
const dependencies = new Map();
|
||||
let exportName;
|
||||
let exportPath;
|
||||
const exportBindingAssignments = [];
|
||||
const importPaths = [];
|
||||
const importBindingsReferences = [];
|
||||
(0, _traverse.default)(file, {
|
||||
ImportDeclaration(child) {
|
||||
const name = child.node.source.value;
|
||||
|
||||
if (!_helpers.default[name]) {
|
||||
throw child.buildCodeFrameError(`Unknown helper ${name}`);
|
||||
}
|
||||
|
||||
if (child.get("specifiers").length !== 1 || !child.get("specifiers.0").isImportDefaultSpecifier()) {
|
||||
throw child.buildCodeFrameError("Helpers can only import a default value");
|
||||
}
|
||||
|
||||
const bindingIdentifier = child.node.specifiers[0].local;
|
||||
dependencies.set(bindingIdentifier, name);
|
||||
importPaths.push(makePath(child));
|
||||
},
|
||||
|
||||
ExportDefaultDeclaration(child) {
|
||||
const decl = child.get("declaration");
|
||||
|
||||
if (decl.isFunctionDeclaration()) {
|
||||
if (!decl.node.id) {
|
||||
throw decl.buildCodeFrameError("Helpers should give names to their exported func declaration");
|
||||
}
|
||||
|
||||
exportName = decl.node.id.name;
|
||||
}
|
||||
|
||||
exportPath = makePath(child);
|
||||
},
|
||||
|
||||
ExportAllDeclaration(child) {
|
||||
throw child.buildCodeFrameError("Helpers can only export default");
|
||||
},
|
||||
|
||||
ExportNamedDeclaration(child) {
|
||||
throw child.buildCodeFrameError("Helpers can only export default");
|
||||
},
|
||||
|
||||
Statement(child) {
|
||||
if (child.isModuleDeclaration()) return;
|
||||
child.skip();
|
||||
}
|
||||
|
||||
});
|
||||
(0, _traverse.default)(file, {
|
||||
Program(path) {
|
||||
const bindings = path.scope.getAllBindings();
|
||||
Object.keys(bindings).forEach(name => {
|
||||
if (name === exportName) return;
|
||||
if (dependencies.has(bindings[name].identifier)) return;
|
||||
localBindingNames.add(name);
|
||||
});
|
||||
},
|
||||
|
||||
ReferencedIdentifier(child) {
|
||||
const name = child.node.name;
|
||||
const binding = child.scope.getBinding(name, true);
|
||||
|
||||
if (!binding) {
|
||||
globals.add(name);
|
||||
} else if (dependencies.has(binding.identifier)) {
|
||||
importBindingsReferences.push(makePath(child));
|
||||
}
|
||||
},
|
||||
|
||||
AssignmentExpression(child) {
|
||||
const left = child.get("left");
|
||||
if (!(exportName in left.getBindingIdentifiers())) return;
|
||||
|
||||
if (!left.isIdentifier()) {
|
||||
throw left.buildCodeFrameError("Only simple assignments to exports are allowed in helpers");
|
||||
}
|
||||
|
||||
const binding = child.scope.getBinding(exportName);
|
||||
|
||||
if (binding && binding.scope.path.isProgram()) {
|
||||
exportBindingAssignments.push(makePath(child));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
if (!exportPath) throw new Error("Helpers must default-export something.");
|
||||
exportBindingAssignments.reverse();
|
||||
return {
|
||||
globals: Array.from(globals),
|
||||
localBindingNames: Array.from(localBindingNames),
|
||||
dependencies,
|
||||
exportBindingAssignments,
|
||||
exportPath,
|
||||
exportName,
|
||||
importBindingsReferences,
|
||||
importPaths
|
||||
};
|
||||
}
|
||||
|
||||
function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
||||
if (localBindings && !id) {
|
||||
throw new Error("Unexpected local bindings for module-based helpers.");
|
||||
}
|
||||
|
||||
if (!id) return;
|
||||
const {
|
||||
localBindingNames,
|
||||
dependencies,
|
||||
exportBindingAssignments,
|
||||
exportPath,
|
||||
exportName,
|
||||
importBindingsReferences,
|
||||
importPaths
|
||||
} = metadata;
|
||||
const dependenciesRefs = {};
|
||||
dependencies.forEach((name, id) => {
|
||||
dependenciesRefs[id.name] = typeof getDependency === "function" && getDependency(name) || id;
|
||||
});
|
||||
const toRename = {};
|
||||
const bindings = new Set(localBindings || []);
|
||||
localBindingNames.forEach(name => {
|
||||
let newName = name;
|
||||
|
||||
while (bindings.has(newName)) newName = "_" + newName;
|
||||
|
||||
if (newName !== name) toRename[name] = newName;
|
||||
});
|
||||
|
||||
if (id.type === "Identifier" && exportName !== id.name) {
|
||||
toRename[exportName] = id.name;
|
||||
}
|
||||
|
||||
(0, _traverse.default)(file, {
|
||||
Program(path) {
|
||||
const exp = path.get(exportPath);
|
||||
const imps = importPaths.map(p => path.get(p));
|
||||
const impsBindingRefs = importBindingsReferences.map(p => path.get(p));
|
||||
const decl = exp.get("declaration");
|
||||
|
||||
if (id.type === "Identifier") {
|
||||
if (decl.isFunctionDeclaration()) {
|
||||
exp.replaceWith(decl);
|
||||
} else {
|
||||
exp.replaceWith(t.variableDeclaration("var", [t.variableDeclarator(id, decl.node)]));
|
||||
}
|
||||
} else if (id.type === "MemberExpression") {
|
||||
if (decl.isFunctionDeclaration()) {
|
||||
exportBindingAssignments.forEach(assignPath => {
|
||||
const assign = path.get(assignPath);
|
||||
assign.replaceWith(t.assignmentExpression("=", id, assign.node));
|
||||
});
|
||||
exp.replaceWith(decl);
|
||||
path.pushContainer("body", t.expressionStatement(t.assignmentExpression("=", id, t.identifier(exportName))));
|
||||
} else {
|
||||
exp.replaceWith(t.expressionStatement(t.assignmentExpression("=", id, decl.node)));
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unexpected helper format.");
|
||||
}
|
||||
|
||||
Object.keys(toRename).forEach(name => {
|
||||
path.scope.rename(name, toRename[name]);
|
||||
});
|
||||
|
||||
for (const path of imps) path.remove();
|
||||
|
||||
for (const path of impsBindingRefs) {
|
||||
const node = t.cloneNode(dependenciesRefs[path.node.name]);
|
||||
path.replaceWith(node);
|
||||
}
|
||||
|
||||
path.stop();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
const helperData = Object.create(null);
|
||||
|
||||
function loadHelper(name) {
|
||||
if (!helperData[name]) {
|
||||
const helper = _helpers.default[name];
|
||||
|
||||
if (!helper) {
|
||||
throw Object.assign(new ReferenceError(`Unknown helper ${name}`), {
|
||||
code: "BABEL_HELPER_UNKNOWN",
|
||||
helper: name
|
||||
});
|
||||
}
|
||||
|
||||
const fn = () => {
|
||||
return t.file(helper.ast());
|
||||
};
|
||||
|
||||
const metadata = getHelperMetadata(fn());
|
||||
helperData[name] = {
|
||||
build(getDependency, id, localBindings) {
|
||||
const file = fn();
|
||||
permuteHelperAST(file, metadata, id, localBindings, getDependency);
|
||||
return {
|
||||
nodes: file.program.body,
|
||||
globals: metadata.globals
|
||||
};
|
||||
},
|
||||
|
||||
minVersion() {
|
||||
return helper.minVersion;
|
||||
},
|
||||
|
||||
dependencies: metadata.dependencies
|
||||
};
|
||||
}
|
||||
|
||||
return helperData[name];
|
||||
}
|
||||
|
||||
function get(name, getDependency, id, localBindings) {
|
||||
return loadHelper(name).build(getDependency, id, localBindings);
|
||||
}
|
||||
|
||||
function minVersion(name) {
|
||||
return loadHelper(name).minVersion();
|
||||
}
|
||||
|
||||
function getDependencies(name) {
|
||||
return Array.from(loadHelper(name).dependencies.values());
|
||||
}
|
||||
|
||||
function ensure(name) {
|
||||
loadHelper(name);
|
||||
}
|
||||
|
||||
const list = Object.keys(_helpers.default).map(name => name.replace(/^_/, "")).filter(name => name !== "__esModule");
|
||||
exports.list = list;
|
||||
var _default = get;
|
||||
exports.default = _default;
|
||||
21
packages/babel-helpers/package.json
Normal file
21
packages/babel-helpers/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "@babel/helpers",
|
||||
"version": "7.7.0",
|
||||
"description": "Collection of helper functions used by Babel transforms.",
|
||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||
"homepage": "https://babeljs.io/",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": "https://github.com/babel/babel/tree/master/packages/babel-helpers",
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.7.0",
|
||||
"@babel/traverse": "^7.7.0",
|
||||
"@babel/types": "^7.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/helper-plugin-test-runner": "^7.0.0"
|
||||
}
|
||||
}
|
||||
1997
packages/babel-helpers/src/helpers.js
Normal file
1997
packages/babel-helpers/src/helpers.js
Normal file
File diff suppressed because it is too large
Load Diff
291
packages/babel-helpers/src/index.js
Normal file
291
packages/babel-helpers/src/index.js
Normal file
@@ -0,0 +1,291 @@
|
||||
import traverse from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import helpers from "./helpers";
|
||||
|
||||
function makePath(path) {
|
||||
const parts = [];
|
||||
|
||||
for (; path.parentPath; path = path.parentPath) {
|
||||
parts.push(path.key);
|
||||
if (path.inList) parts.push(path.listKey);
|
||||
}
|
||||
|
||||
return parts.reverse().join(".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a file AST for a given helper, get a bunch of metadata about it so that Babel can quickly render
|
||||
* the helper is whatever context it is needed in.
|
||||
*/
|
||||
function getHelperMetadata(file) {
|
||||
const globals = new Set();
|
||||
const localBindingNames = new Set();
|
||||
// Maps imported identifier -> helper name
|
||||
const dependencies = new Map();
|
||||
|
||||
let exportName;
|
||||
let exportPath;
|
||||
const exportBindingAssignments = [];
|
||||
const importPaths = [];
|
||||
const importBindingsReferences = [];
|
||||
|
||||
traverse(file, {
|
||||
ImportDeclaration(child) {
|
||||
const name = child.node.source.value;
|
||||
if (!helpers[name]) {
|
||||
throw child.buildCodeFrameError(`Unknown helper ${name}`);
|
||||
}
|
||||
if (
|
||||
child.get("specifiers").length !== 1 ||
|
||||
!child.get("specifiers.0").isImportDefaultSpecifier()
|
||||
) {
|
||||
throw child.buildCodeFrameError(
|
||||
"Helpers can only import a default value",
|
||||
);
|
||||
}
|
||||
const bindingIdentifier = child.node.specifiers[0].local;
|
||||
dependencies.set(bindingIdentifier, name);
|
||||
importPaths.push(makePath(child));
|
||||
},
|
||||
ExportDefaultDeclaration(child) {
|
||||
const decl = child.get("declaration");
|
||||
|
||||
if (decl.isFunctionDeclaration()) {
|
||||
if (!decl.node.id) {
|
||||
throw decl.buildCodeFrameError(
|
||||
"Helpers should give names to their exported func declaration",
|
||||
);
|
||||
}
|
||||
|
||||
exportName = decl.node.id.name;
|
||||
}
|
||||
exportPath = makePath(child);
|
||||
},
|
||||
ExportAllDeclaration(child) {
|
||||
throw child.buildCodeFrameError("Helpers can only export default");
|
||||
},
|
||||
ExportNamedDeclaration(child) {
|
||||
throw child.buildCodeFrameError("Helpers can only export default");
|
||||
},
|
||||
Statement(child) {
|
||||
if (child.isModuleDeclaration()) return;
|
||||
|
||||
child.skip();
|
||||
},
|
||||
});
|
||||
|
||||
traverse(file, {
|
||||
Program(path) {
|
||||
const bindings = path.scope.getAllBindings();
|
||||
|
||||
Object.keys(bindings).forEach(name => {
|
||||
if (name === exportName) return;
|
||||
if (dependencies.has(bindings[name].identifier)) return;
|
||||
|
||||
localBindingNames.add(name);
|
||||
});
|
||||
},
|
||||
ReferencedIdentifier(child) {
|
||||
const name = child.node.name;
|
||||
const binding = child.scope.getBinding(name, /* noGlobal */ true);
|
||||
if (!binding) {
|
||||
globals.add(name);
|
||||
} else if (dependencies.has(binding.identifier)) {
|
||||
importBindingsReferences.push(makePath(child));
|
||||
}
|
||||
},
|
||||
AssignmentExpression(child) {
|
||||
const left = child.get("left");
|
||||
|
||||
if (!(exportName in left.getBindingIdentifiers())) return;
|
||||
|
||||
if (!left.isIdentifier()) {
|
||||
throw left.buildCodeFrameError(
|
||||
"Only simple assignments to exports are allowed in helpers",
|
||||
);
|
||||
}
|
||||
|
||||
const binding = child.scope.getBinding(exportName);
|
||||
|
||||
if (binding && binding.scope.path.isProgram()) {
|
||||
exportBindingAssignments.push(makePath(child));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (!exportPath) throw new Error("Helpers must default-export something.");
|
||||
|
||||
// Process these in reverse so that mutating the references does not invalidate any later paths in
|
||||
// the list.
|
||||
exportBindingAssignments.reverse();
|
||||
|
||||
return {
|
||||
globals: Array.from(globals),
|
||||
localBindingNames: Array.from(localBindingNames),
|
||||
dependencies,
|
||||
exportBindingAssignments,
|
||||
exportPath,
|
||||
exportName,
|
||||
importBindingsReferences,
|
||||
importPaths,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a helper AST and information about how it will be used, update the AST to match the usage.
|
||||
*/
|
||||
function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
||||
if (localBindings && !id) {
|
||||
throw new Error("Unexpected local bindings for module-based helpers.");
|
||||
}
|
||||
|
||||
if (!id) return;
|
||||
|
||||
const {
|
||||
localBindingNames,
|
||||
dependencies,
|
||||
exportBindingAssignments,
|
||||
exportPath,
|
||||
exportName,
|
||||
importBindingsReferences,
|
||||
importPaths,
|
||||
} = metadata;
|
||||
|
||||
const dependenciesRefs = {};
|
||||
dependencies.forEach((name, id) => {
|
||||
dependenciesRefs[id.name] =
|
||||
(typeof getDependency === "function" && getDependency(name)) || id;
|
||||
});
|
||||
|
||||
const toRename = {};
|
||||
const bindings = new Set(localBindings || []);
|
||||
localBindingNames.forEach(name => {
|
||||
let newName = name;
|
||||
while (bindings.has(newName)) newName = "_" + newName;
|
||||
|
||||
if (newName !== name) toRename[name] = newName;
|
||||
});
|
||||
|
||||
if (id.type === "Identifier" && exportName !== id.name) {
|
||||
toRename[exportName] = id.name;
|
||||
}
|
||||
|
||||
traverse(file, {
|
||||
Program(path) {
|
||||
// We need to compute these in advance because removing nodes would
|
||||
// invalidate the paths.
|
||||
const exp = path.get(exportPath);
|
||||
const imps = importPaths.map(p => path.get(p));
|
||||
const impsBindingRefs = importBindingsReferences.map(p => path.get(p));
|
||||
|
||||
const decl = exp.get("declaration");
|
||||
if (id.type === "Identifier") {
|
||||
if (decl.isFunctionDeclaration()) {
|
||||
exp.replaceWith(decl);
|
||||
} else {
|
||||
exp.replaceWith(
|
||||
t.variableDeclaration("var", [t.variableDeclarator(id, decl.node)]),
|
||||
);
|
||||
}
|
||||
} else if (id.type === "MemberExpression") {
|
||||
if (decl.isFunctionDeclaration()) {
|
||||
exportBindingAssignments.forEach(assignPath => {
|
||||
const assign = path.get(assignPath);
|
||||
assign.replaceWith(t.assignmentExpression("=", id, assign.node));
|
||||
});
|
||||
exp.replaceWith(decl);
|
||||
path.pushContainer(
|
||||
"body",
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression("=", id, t.identifier(exportName)),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
exp.replaceWith(
|
||||
t.expressionStatement(t.assignmentExpression("=", id, decl.node)),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unexpected helper format.");
|
||||
}
|
||||
|
||||
Object.keys(toRename).forEach(name => {
|
||||
path.scope.rename(name, toRename[name]);
|
||||
});
|
||||
|
||||
for (const path of imps) path.remove();
|
||||
for (const path of impsBindingRefs) {
|
||||
const node = t.cloneNode(dependenciesRefs[path.node.name]);
|
||||
path.replaceWith(node);
|
||||
}
|
||||
|
||||
// We only use "traverse" for all the handy scoping helpers, so we can stop immediately without
|
||||
// actually doing the traversal.
|
||||
path.stop();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const helperData = Object.create(null);
|
||||
function loadHelper(name) {
|
||||
if (!helperData[name]) {
|
||||
const helper = helpers[name];
|
||||
if (!helper) {
|
||||
throw Object.assign(new ReferenceError(`Unknown helper ${name}`), {
|
||||
code: "BABEL_HELPER_UNKNOWN",
|
||||
helper: name,
|
||||
});
|
||||
}
|
||||
|
||||
const fn = () => {
|
||||
return t.file(helper.ast());
|
||||
};
|
||||
|
||||
const metadata = getHelperMetadata(fn());
|
||||
|
||||
helperData[name] = {
|
||||
build(getDependency, id, localBindings) {
|
||||
const file = fn();
|
||||
permuteHelperAST(file, metadata, id, localBindings, getDependency);
|
||||
|
||||
return {
|
||||
nodes: file.program.body,
|
||||
globals: metadata.globals,
|
||||
};
|
||||
},
|
||||
minVersion() {
|
||||
return helper.minVersion;
|
||||
},
|
||||
dependencies: metadata.dependencies,
|
||||
};
|
||||
}
|
||||
|
||||
return helperData[name];
|
||||
}
|
||||
|
||||
export function get(
|
||||
name,
|
||||
getDependency?: string => ?t.Expression,
|
||||
id?,
|
||||
localBindings?: string[],
|
||||
) {
|
||||
return loadHelper(name).build(getDependency, id, localBindings);
|
||||
}
|
||||
|
||||
export function minVersion(name: string) {
|
||||
return loadHelper(name).minVersion();
|
||||
}
|
||||
|
||||
export function getDependencies(name: string): $ReadOnlyArray<string> {
|
||||
return Array.from(loadHelper(name).dependencies.values());
|
||||
}
|
||||
|
||||
export function ensure(name: string) {
|
||||
loadHelper(name);
|
||||
}
|
||||
|
||||
export const list = Object.keys(helpers)
|
||||
.map(name => name.replace(/^_/, ""))
|
||||
.filter(name => name !== "__esModule");
|
||||
|
||||
export default get;
|
||||
1
packages/babel-helpers/test/fixtures/dependencies/basic/input.js
vendored
Normal file
1
packages/babel-helpers/test/fixtures/dependencies/basic/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
REPLACE_ME;
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/basic/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/basic/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
5
packages/babel-helpers/test/fixtures/dependencies/basic/output.js
vendored
Normal file
5
packages/babel-helpers/test/fixtures/dependencies/basic/output.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function _$_basic_main() { return _$_basic_dependency(); }
|
||||
|
||||
function _$_basic_dependency() {}
|
||||
|
||||
_$_basic_main;
|
||||
25
packages/babel-helpers/test/fixtures/dependencies/basic/plugin.js
vendored
Normal file
25
packages/babel-helpers/test/fixtures/dependencies/basic/plugin.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const dependency = defineHelper(__dirname, "dependency", `
|
||||
export default function fn() {}
|
||||
`);
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep from "${dependency}";
|
||||
|
||||
export default function helper() {
|
||||
return dep();
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name !== "REPLACE_ME") return;
|
||||
const helper = this.addHelper(main);
|
||||
path.replaceWith(helper);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
1
packages/babel-helpers/test/fixtures/dependencies/deep/input.js
vendored
Normal file
1
packages/babel-helpers/test/fixtures/dependencies/deep/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
REPLACE_ME;
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/deep/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/deep/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
7
packages/babel-helpers/test/fixtures/dependencies/deep/output.js
vendored
Normal file
7
packages/babel-helpers/test/fixtures/dependencies/deep/output.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
function _$_deep_main() { return _$_deep_dependency(); }
|
||||
|
||||
function _$_deep_dependency() { return _$_deep_dependencyDeep; }
|
||||
|
||||
function _$_deep_dependencyDeep() {}
|
||||
|
||||
_$_deep_main;
|
||||
30
packages/babel-helpers/test/fixtures/dependencies/deep/plugin.js
vendored
Normal file
30
packages/babel-helpers/test/fixtures/dependencies/deep/plugin.js
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const dependencyDeep = defineHelper(__dirname, "dependencyDeep", `
|
||||
export default function fn() {}
|
||||
`)
|
||||
|
||||
const dependency = defineHelper(__dirname, "dependency", `
|
||||
import f from "${dependencyDeep}";
|
||||
export default function fn() { return f; }
|
||||
`);
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep from "${dependency}";
|
||||
|
||||
export default function helper() {
|
||||
return dep();
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name !== "REPLACE_ME") return;
|
||||
const helper = this.addHelper(main);
|
||||
path.replaceWith(helper);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
1
packages/babel-helpers/test/fixtures/dependencies/missing/input.js
vendored
Normal file
1
packages/babel-helpers/test/fixtures/dependencies/missing/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
REPLACE_ME;
|
||||
4
packages/babel-helpers/test/fixtures/dependencies/missing/options.json
vendored
Normal file
4
packages/babel-helpers/test/fixtures/dependencies/missing/options.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"plugins": ["./plugin"],
|
||||
"throws": " "
|
||||
}
|
||||
21
packages/babel-helpers/test/fixtures/dependencies/missing/plugin.js
vendored
Normal file
21
packages/babel-helpers/test/fixtures/dependencies/missing/plugin.js
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep from "(!!!)%-..a,4892 missing";
|
||||
|
||||
export default function helper() {
|
||||
return dep();
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name !== "REPLACE_ME") return;
|
||||
const helper = this.addHelper(main);
|
||||
path.replaceWith(helper);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
1
packages/babel-helpers/test/fixtures/dependencies/multiple/input.js
vendored
Normal file
1
packages/babel-helpers/test/fixtures/dependencies/multiple/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
REPLACE_ME;
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/multiple/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/multiple/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
7
packages/babel-helpers/test/fixtures/dependencies/multiple/output.js
vendored
Normal file
7
packages/babel-helpers/test/fixtures/dependencies/multiple/output.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
function _$_multiple_main() { return _$_multiple_dependency() + _$_multiple_dependency2(); }
|
||||
|
||||
function _$_multiple_dependency2() { 1; }
|
||||
|
||||
function _$_multiple_dependency() { 0; }
|
||||
|
||||
_$_multiple_main;
|
||||
30
packages/babel-helpers/test/fixtures/dependencies/multiple/plugin.js
vendored
Normal file
30
packages/babel-helpers/test/fixtures/dependencies/multiple/plugin.js
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const dependency1 = defineHelper(__dirname, "dependency1", `
|
||||
export default function fn() { 0; }
|
||||
`);
|
||||
|
||||
const dependency2 = defineHelper(__dirname, "dependency2", `
|
||||
export default function fn() { 1; }
|
||||
`);
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep1 from "${dependency1}";
|
||||
import dep2 from "${dependency2}";
|
||||
|
||||
export default function helper() {
|
||||
return dep1() + dep2();
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name !== "REPLACE_ME") return;
|
||||
const helper = this.addHelper(main);
|
||||
path.replaceWith(helper);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
1
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/input.js
vendored
Normal file
1
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
REPLACE_ME;
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
9
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/output.js
vendored
Normal file
9
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/output.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
let _foo = "main";
|
||||
|
||||
function _$_renameBindingEqual_main() { return _$_renameBindingEqual_dependency() + _foo; }
|
||||
|
||||
let foo = "dependency";
|
||||
|
||||
function _$_renameBindingEqual_dependency() { return foo; }
|
||||
|
||||
_$_renameBindingEqual_main;
|
||||
28
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/plugin.js
vendored
Normal file
28
packages/babel-helpers/test/fixtures/dependencies/rename-binding-equal/plugin.js
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const dependency = defineHelper(__dirname, "dependency", `
|
||||
let foo = "dependency";
|
||||
export default function fn() { return foo }
|
||||
`);
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep from "${dependency}";
|
||||
|
||||
let foo = "main";
|
||||
|
||||
export default function helper() {
|
||||
return dep() + foo;
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name !== "REPLACE_ME") return;
|
||||
const helper = this.addHelper(main);
|
||||
path.replaceWith(helper);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/input.js
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/input.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
REPLACE_ME;
|
||||
|
||||
let Promise = "I will be a good guy!";
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
6
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/output.js
vendored
Normal file
6
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/output.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
function _$_renameDeepGlobal_main() { return _$_renameDeepGlobal_dependency() || Promise; }
|
||||
|
||||
function _$_renameDeepGlobal_dependency() { return Promise; }
|
||||
|
||||
_$_renameDeepGlobal_main;
|
||||
let _Promise = "I will be a good guy!";
|
||||
27
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/plugin.js
vendored
Normal file
27
packages/babel-helpers/test/fixtures/dependencies/rename-deep-global/plugin.js
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const dependency = defineHelper(__dirname, "dependency", `
|
||||
export default function fn() {
|
||||
return Promise;
|
||||
}
|
||||
`);
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep from "${dependency}";
|
||||
|
||||
export default function helper() {
|
||||
return dep() || Promise;
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name !== "REPLACE_ME") return;
|
||||
const helper = this.addHelper(main);
|
||||
path.replaceWith(helper);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
2
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/input.js
vendored
Normal file
2
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/input.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
REPLACE_ME_1;
|
||||
REPLACE_ME_2;
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
6
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/output.js
vendored
Normal file
6
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/output.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
function _$_reuseDependency_main() { return _$_reuseDependency_dependency(); }
|
||||
|
||||
function _$_reuseDependency_dependency() { 0; }
|
||||
|
||||
_$_reuseDependency_main;
|
||||
_$_reuseDependency_dependency;
|
||||
29
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/plugin.js
vendored
Normal file
29
packages/babel-helpers/test/fixtures/dependencies/reuse-dependency/plugin.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const dependency = defineHelper(__dirname, "dependency", `
|
||||
export default function fn() { 0; }
|
||||
`);
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep from "${dependency}";
|
||||
|
||||
export default function helper() {
|
||||
return dep();
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name === "REPLACE_ME_1") {
|
||||
const mainHelper = this.addHelper(main);
|
||||
path.replaceWith(mainHelper);
|
||||
} else if (path.node.name === "REPLACE_ME_2") {
|
||||
const dependencyHelper = this.addHelper(dependency);
|
||||
path.replaceWith(dependencyHelper);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
1
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/input.js
vendored
Normal file
1
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
REPLACE_ME;
|
||||
3
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/options.json
vendored
Normal file
3
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["./plugin"]
|
||||
}
|
||||
5
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/output.js
vendored
Normal file
5
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/output.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function _$_variableSameNameDependency_main() { let x = _$_variableSameNameDependency_dependency; return function (dep) { return x() + dep; }; }
|
||||
|
||||
function _$_variableSameNameDependency_dependency() {}
|
||||
|
||||
_$_variableSameNameDependency_main;
|
||||
28
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/plugin.js
vendored
Normal file
28
packages/babel-helpers/test/fixtures/dependencies/variable-same-name-dependency/plugin.js
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
const defineHelper = require("../../../helpers/define-helper").default;
|
||||
|
||||
const dependency = defineHelper(__dirname, "dependency", `
|
||||
export default function fn() {}
|
||||
`);
|
||||
|
||||
const main = defineHelper(__dirname, "main", `
|
||||
import dep from "${dependency}";
|
||||
|
||||
export default function helper() {
|
||||
let x = dep;
|
||||
return function (dep) {
|
||||
return x() + dep;
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
visitor: {
|
||||
Identifier(path) {
|
||||
if (path.node.name !== "REPLACE_ME") return;
|
||||
const helper = this.addHelper(main);
|
||||
path.replaceWith(helper);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
26
packages/babel-helpers/test/helpers/define-helper.js
Normal file
26
packages/babel-helpers/test/helpers/define-helper.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import path from "path";
|
||||
import template from "@babel/template";
|
||||
import helpers from "../../lib/helpers";
|
||||
|
||||
function getHelperId(dir, name) {
|
||||
const testName = path.basename(dir);
|
||||
return `_$_${testName}_${name}`;
|
||||
}
|
||||
|
||||
export default function defineHelper(
|
||||
dir: string,
|
||||
name: string,
|
||||
code: string,
|
||||
): string {
|
||||
const id = getHelperId(dir, name);
|
||||
if (id in helpers) {
|
||||
throw new Error(`The ${id} helper is already defined.`);
|
||||
}
|
||||
Object.defineProperty(helpers, id, {
|
||||
value: {
|
||||
minVersion: "7.0.0-beta.0",
|
||||
ast: template.program(code),
|
||||
},
|
||||
});
|
||||
return id;
|
||||
}
|
||||
3
packages/babel-helpers/test/index.js
Normal file
3
packages/babel-helpers/test/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import runner from "@babel/helper-plugin-test-runner";
|
||||
|
||||
runner(__dirname);
|
||||
@@ -2,7 +2,7 @@
|
||||
"presets": [
|
||||
],
|
||||
"plugins": [
|
||||
[ "@babel/plugin-proposal-decorators" , { "decoratorsBeforeExport": true }],
|
||||
[ "@babel/plugin-proposal-decorators" , { "legacy": true }],
|
||||
[ "@babel/plugin-proposal-class-properties", { "loose": true } ],
|
||||
[ "@babel/plugin-proposal-private-methods", {"loose": true } ],
|
||||
[ "@babel/plugin-proposal-optional-chaining" ],
|
||||
|
||||
@@ -1,43 +1,56 @@
|
||||
import {render} from "../vdom";
|
||||
|
||||
|
||||
/** Helper class to mark an initializer-value to be used on first get of a value**/
|
||||
class InitializerValue{ constructor(value){ this.value = value; } }
|
||||
|
||||
/**
|
||||
* The decorators proposal has changed since @babel implemented it. This code will need to change at some point...
|
||||
* THIS IS TOTALLY FIGGIN BROKEN!! valueMap used to be just value, but it turns out is not unique amongst decorated props.
|
||||
* (it appears to be run once per class definition, and thus multiple instances would share the same value-reference)
|
||||
*/
|
||||
export function State() {
|
||||
return function decorator(target){
|
||||
let key = target.key;
|
||||
let descriptor = target.descriptor;
|
||||
let valueMap = new WeakMap();
|
||||
return function decorator(target, key, descriptor){
|
||||
let {get: oldGet, set: oldSet} = descriptor;
|
||||
let valueKey='__'+key;
|
||||
|
||||
// Add a getter/setter or replace if they're already there with something that intercepts it (this gets a whole lot easyer in the new proposal if i'm not mistaken)
|
||||
descriptor['get'] = oldGet || (function(){
|
||||
return valueMap.get(this)
|
||||
});
|
||||
descriptor['set'] = function(newValue){
|
||||
let oldValue = descriptor.get.call(this);
|
||||
if(newValue!==oldValue){
|
||||
valueMap.set(this,newValue);
|
||||
this.markDirty && this.markDirty();
|
||||
|
||||
// Rewrite the property as if using getters and setters (if needed)
|
||||
descriptor.get = oldGet = oldGet || function(){
|
||||
let val = this[valueKey];
|
||||
if(val instanceof InitializerValue){
|
||||
this[valueKey] = val = val.value.call(this);
|
||||
}
|
||||
if(oldSet) return oldSet.call(this, newValue);
|
||||
return val;
|
||||
};
|
||||
|
||||
// CAUTION: this is dangerous. We need intend to conver regular fields to get/set methods here.
|
||||
delete descriptor.writable;
|
||||
oldSet = oldSet || function(newVal){
|
||||
this[valueKey]=newVal;
|
||||
return newVal;
|
||||
};
|
||||
// Overwrite the setter to call markDirty whenever it is used
|
||||
descriptor.set = function(newValue){
|
||||
let result = oldSet.call(this, newValue);
|
||||
this.markDirty && this.markDirty();
|
||||
return result;
|
||||
};
|
||||
|
||||
// Update the descriptor to match with using getters and setters
|
||||
target.kind = 'method'; // update to get and set if need be..
|
||||
delete descriptor.writable;
|
||||
|
||||
// CAUTION: this is again dangerous, the initialize function should be called right before the constructor, but after it was fully defined.
|
||||
if(target.initializer){
|
||||
valueMap.set(target, target.initializer(target));
|
||||
delete target.initializer;
|
||||
// Catch usage of initial value or initalizers
|
||||
if(descriptor.value){
|
||||
Object.defineProperty(target, valueKey, {
|
||||
writable: true,
|
||||
value: descriptor.value
|
||||
});
|
||||
delete descriptor.value;
|
||||
}else if(descriptor.initializer){
|
||||
Object.defineProperty(target, valueKey, {
|
||||
writable: true,
|
||||
value: new InitializerValue(descriptor.initializer)
|
||||
});
|
||||
delete descriptor.initializer;
|
||||
}
|
||||
|
||||
return target;
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,21 +2,16 @@
|
||||
* The decorators proposal has changed since @babel implemented it. This code will need to change at some point...
|
||||
*/
|
||||
export function defineElement(tagName, options) {
|
||||
return function decorator(target) {
|
||||
// Queue defining element in a finisher, because apparantly thats how the non-legacy decorator proposal works (again, new proposal will be different...)
|
||||
target.finisher = (finishedTarget)=>{
|
||||
// Register the tagName as a custom-element with the browser
|
||||
window.customElements.define(tagName, finishedTarget, options);
|
||||
|
||||
// Define the chosen tagName on the class itself so our vdom.render-function knows what DOM-Element to create
|
||||
Object.defineProperty(finishedTarget, 'tagName', {
|
||||
value: tagName,
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
});
|
||||
return finishedTarget;
|
||||
};
|
||||
return target;
|
||||
return function decorator(targetClass) {
|
||||
Object.defineProperty(targetClass, 'tagName', {
|
||||
value: tagName,
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
// Register the tagName as a custom-element with the browser
|
||||
window.customElements.define(tagName, targetClass, options); // Define the chosen tagName on the class itself so our vdom.render-function knows what DOM-Element to create
|
||||
return targetClass;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user