lively.source-transform
Version:
EcmaScript 6 classes for live development
949 lines (789 loc) • 40.2 kB
JavaScript
;(function() {
var GLOBAL = typeof window !== "undefined" ? window :
typeof global!=="undefined" ? global :
typeof self!=="undefined" ? self : this;
if (typeof lively.lang === "undefined") GLOBAL.livey.lang = {};
})();
(function() {
var GLOBAL = typeof window !== "undefined" ? window :
typeof global!=="undefined" ? global :
typeof self!=="undefined" ? self : this;
this.lively = this.lively || {};
(function (exports,lively_lang,lively_classes,lively_ast) {
;
var _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
var get = function get(object, property, receiver) {
if (object === null) object = Function.prototype;
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent, property, receiver);
}
} else if ("value" in desc) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
var set = function set(object, property, value, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent !== null) {
set(parent, property, value, receiver);
}
} else if ("value" in desc && desc.writable) {
desc.value = value;
} else {
var setter = desc.set;
if (setter !== undefined) {
setter.call(receiver, value);
}
}
return value;
};
var toConsumableArray = function (arr$$1) {
if (Array.isArray(arr$$1)) {
for (var i = 0, arr2 = Array(arr$$1.length); i < arr$$1.length; i++) arr2[i] = arr$$1[i];
return arr2;
} else {
return Array.from(arr$$1);
}
};
var member = lively_ast.nodes.member;
var prop = lively_ast.nodes.prop;
var varDecl = lively_ast.nodes.varDecl;
var assign = lively_ast.nodes.assign;
var id = lively_ast.nodes.id;
var literal = lively_ast.nodes.literal;
var exprStmt = lively_ast.nodes.exprStmt;
var conditional = lively_ast.nodes.conditional;
var binaryExpr = lively_ast.nodes.binaryExpr;
var funcCall = lively_ast.nodes.funcCall;
var topLevelDeclsAndRefs = lively_ast.query.topLevelDeclsAndRefs;
var queryHelpers = lively_ast.query.helpers;
function rewriteToCaptureTopLevelVariables(parsed, assignToObj, options) {
/* replaces var and function declarations with assignment statements.
* Example:
stringify(
rewriteToCaptureTopLevelVariables2(
parse("var x = 3, y = 2, z = 4"),
{name: "A", type: "Identifier"}, ['z']));
// => "A.x = 3; A.y = 2; z = 4"
*/
if (!assignToObj) assignToObj = { type: "Identifier", name: "__rec" };
options = _extends({
ignoreUndeclaredExcept: null,
includeRefs: null,
excludeRefs: options && options.exclude || [],
includeDecls: null,
excludeDecls: options && options.exclude || [],
recordDefRanges: false,
es6ExportFuncId: null,
es6ImportFuncId: null,
captureObj: assignToObj,
moduleExportFunc: { name: options && options.es6ExportFuncId || "_moduleExport", type: "Identifier" },
moduleImportFunc: { name: options && options.es6ImportFuncId || "_moduleImport", type: "Identifier" },
declarationWrapper: undefined,
classToFunction: options && options.hasOwnProperty("classToFunction") ? options.classToFunction : {
classHolder: assignToObj,
functionNode: { type: "Identifier", name: "_createOrExtendClass" },
declarationWrapper: options && options.declarationWrapper,
evalId: options && options.evalId,
sourceAccessorName: options && options.sourceAccessorName
}
}, options);
var rewritten = parsed;
// "ignoreUndeclaredExcept" is null if we want to capture all globals in the toplevel scope
// if it is a list of names we will capture all refs with those names
if (options.ignoreUndeclaredExcept) {
var topLevel = topLevelDeclsAndRefs(parsed);
options.excludeRefs = lively_lang.arr.withoutAll(topLevel.undeclaredNames, options.ignoreUndeclaredExcept).concat(options.excludeRefs);
options.excludeDecls = lively_lang.arr.withoutAll(topLevel.undeclaredNames, options.ignoreUndeclaredExcept).concat(options.excludeDecls);
}
options.excludeRefs = options.excludeRefs.concat(options.captureObj.name);
options.excludeDecls = options.excludeDecls.concat(options.captureObj.name);
// 1. def ranges so that we know at which source code positions the
// definitions are
var defRanges = options.recordDefRanges ? computeDefRanges(rewritten, options) : null;
// 2. find those var declarations that should not be rewritten. we
// currently ignore var declarations in for loops and the error parameter
// declaration in catch clauses. Also es6 import / export declaration need
// a special treatment
// DO NOT rewrite exports like "export { foo as bar }" => "export { _rec.foo as bar }"
// as this is not valid syntax. Instead we add a var declaration using the
// recorder as init for those exports later
options.excludeRefs = options.excludeRefs.concat(additionalIgnoredRefs(parsed, options));
options.excludeDecls = options.excludeDecls.concat(additionalIgnoredDecls(parsed, options));
rewritten = fixDefaultAsyncFunctionExportForRegeneratorBug(rewritten, options);
// 3. if the es6ExportFuncId options is defined we rewrite the es6 form into an
// obj assignment, converting es6 code to es5 using the extra
// options.moduleExportFunc and options.moduleImportFunc as capture / sources
if (options.es6ExportFuncId) {
options.excludeRefs.push(options.es6ExportFuncId);
options.excludeRefs.push(options.es6ImportFuncId);
rewritten = es6ModuleTransforms(rewritten, options);
}
// 4. make all references declared in the toplevel scope into property
// reads of captureObj
// Example "var foo = 3; 99 + foo;" -> "var foo = 3; 99 + Global.foo;"
rewritten = replaceRefs(rewritten, options);
// 5.a turn var declarations into assignments to captureObj
// Example: "var foo = 3; 99 + foo;" -> "Global.foo = 3; 99 + foo;"
// if declarationWrapper is requested:
// "var foo = 3;" -> "Global.foo = _define(3, 'foo', _rec, 'var');"
rewritten = replaceVarDecls(rewritten, options);
// 5.b record class declarations
// Example: "class Foo {}" -> "class Foo {}; Global.Foo = Foo;"
// if declarationWrapper is requested:
// "class Foo {}" -> "Global.Foo = _define(class Foo {});"
rewritten = replaceClassDecls(rewritten, options);
rewritten = splitExportDeclarations(rewritten, options);
// 6. es6 export declaration are left untouched but a capturing assignment
// is added after the export so that we get the value:
// "export var x = 23;" => "export var x = 23; Global.x = x;"
rewritten = insertCapturesForExportDeclarations(rewritten, options);
// 7. es6 import declaration are left untouched but a capturing assignment
// is added after the import so that we get the value:
// "import x from './some-es6-module.js';" =>
// "import x from './some-es6-module.js';\n_rec.x = x;"
rewritten = insertCapturesForImportDeclarations(rewritten, options);
// 8. Since variable declarations like "var x = 23" were transformed to sth
// like "_rex.x = 23" exports can't simply reference vars anymore and
// "export { _rec.x }" is invalid syntax. So in front of those exports we add
// var decls manually
rewritten = insertDeclarationsForExports(rewritten, options);
// 9. assignments for function declarations in the top level scope are
// put in front of everything else to mirror the func hoisting:
// "return bar(); function bar() { return 23 }" ->
// "Global.bar = bar; return bar(); function bar() { return 23 }"
// if declarationWrapper is requested:
// "Global.bar = _define(bar, 'bar', _rec, 'function'); function bar() {}"
rewritten = putFunctionDeclsInFront(rewritten, options);
return rewritten;
}
function rewriteToRegisterModuleToCaptureSetters(parsed, assignToObj, options) {
// for rewriting the setters part in code like
// ```js
// System.register(["a.js"], function (_export, _context) {
// var a, _rec;
// return {
// setters: [function(foo_a_js) { a = foo_a_js.x }],
// execute: function () { _rec.x = 23 + _rec.a; }
// };
// });
// ```
// This allows us to capture (and potentially re-export) imports and their
// changes without actively running the module again.
options = _extends({
captureObj: assignToObj || { type: "Identifier", name: "__rec" },
exclude: [],
declarationWrapper: undefined
}, options);
var registerCall = lively_lang.Path("body.0.expression").get(parsed);
if (registerCall.callee.object.name !== "System") throw new Error("rewriteToRegisterModuleToCaptureSetters: input doesn't seem to be a System.register call: " + lively_ast.stringify(parsed).slice(0, 300) + "...");
if (registerCall.callee.property.name !== "register") throw new Error("rewriteToRegisterModuleToCaptureSetters: input doesn't seem to be a System.register call: " + lively_ast.stringify(parsed).slice(0, 300) + "...");
var registerBody = lively_lang.Path("arguments.1.body.body").get(registerCall),
registerReturn = lively_lang.arr.last(registerBody);
if (registerReturn.type !== "ReturnStatement") throw new Error("rewriteToRegisterModuleToCaptureSetters: input doesn't seem to be a System.register call, at return statement: " + lively_ast.stringify(parsed).slice(0, 300) + "...");
var setters = registerReturn.argument.properties.find(function (prop) {
return prop.key.name === "setters";
});
if (!setters) throw new Error("rewriteToRegisterModuleToCaptureSetters: input doesn't seem to be a System.register call, at finding setters: " + lively_ast.stringify(parsed).slice(0, 300) + "...");
var execute = registerReturn.argument.properties.find(function (prop) {
return prop.key.name === "execute";
});
if (!execute) throw new Error("rewriteToRegisterModuleToCaptureSetters: input doesn't seem to be a System.register call, at finding execute: " + lively_ast.stringify(parsed).slice(0, 300) + "...");
// in each setter function: intercept the assignments to local vars and inject capture object
setters.value.elements.forEach(function (funcExpr) {
return funcExpr.body.body = funcExpr.body.body.map(function (stmt) {
if (stmt.type !== "ExpressionStatement" || stmt.expression.type !== "AssignmentExpression" || stmt.expression.left.type !== "Identifier" || lively_lang.arr.include(options.exclude, stmt.expression.left.name)) return stmt;
var id = stmt.expression.left,
rhs = options.declarationWrapper ? declarationWrapperCall(options.declarationWrapper, null, literal(id.name), literal("var"), stmt.expression, options.captureObj, options) : stmt.expression;
return exprStmt(assign(member(options.captureObj, id), rhs));
});
});
var captureInitialize = execute.value.body.body.find(function (stmt) {
return stmt.type === "ExpressionStatement" && stmt.expression.type == "AssignmentExpression" && stmt.expression.left.name === options.captureObj.name;
});
if (!captureInitialize) captureInitialize = execute.value.body.body.find(function (stmt) {
return stmt.type === "VariableDeclaration" && stmt.declarations[0].id && stmt.declarations[0].id.name === options.captureObj.name;
});
if (captureInitialize) {
lively_lang.arr.remove(execute.value.body.body, captureInitialize);
lively_lang.arr.pushAt(registerBody, captureInitialize, registerBody.length - 1);
}
if (options.sourceAccessorName) {
var origSourceInitialize = execute.value.body.body.find(function (stmt) {
return stmt.type === "ExpressionStatement" && stmt.expression.type == "AssignmentExpression" && stmt.expression.left.name === options.sourceAccessorName;
});
if (!origSourceInitialize) origSourceInitialize = execute.value.body.body.find(function (stmt) {
return stmt.type === "VariableDeclaration" && stmt.declarations[0].id && stmt.declarations[0].id.name === options.sourceAccessorName;
});
if (origSourceInitialize) {
lively_lang.arr.remove(execute.value.body.body, origSourceInitialize);
lively_lang.arr.pushAt(registerBody, origSourceInitialize, registerBody.length - 1);
}
}
return parsed;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// replacement helpers
function replaceRefs(parsed, options) {
var topLevel = topLevelDeclsAndRefs(parsed),
refsToReplace = topLevel.refs.filter(function (ref) {
return shouldRefBeCaptured(ref, topLevel, options);
}),
locallyIgnored = [];
var replaced = lively_ast.ReplaceVisitor.run(parsed, function (node, path) {
// cs 2016/06/27, 1a4661
// ensure keys of shorthand properties are not renamed while capturing
if (node.type === "Property" && refsToReplace.includes(node.key) && node.shorthand) return prop(id(node.key.name), node.value);
// don't replace var refs in expressions such as "export { x }" or "export var x;"
// We make sure that those var references are defined in insertDeclarationsForExports()
if (node.type === "ExportNamedDeclaration") {
var declaration = node.declaration,
specifiers = node.specifiers;
if (declaration) {
if (declaration.id) locallyIgnored.push(declaration.id);else if (declaration.declarations) locallyIgnored.push.apply(locallyIgnored, toConsumableArray(declaration.declarations.map(function (_ref) {
var id = _ref.id;
return id;
})));
}
specifiers && specifiers.forEach(function (_ref2) {
var local = _ref2.local;
return locallyIgnored.push(local);
});
return node;
}
// declaration wrapper function for assignments
// "a = 3" => "a = _define('a', 'assignment', 3, _rec)"
if (node.type === "AssignmentExpression" && refsToReplace.includes(node.left) && options.declarationWrapper) return _extends({}, node, {
right: declarationWrapperCall(options.declarationWrapper, null, literal(node.left.name), literal("assignment"), node.right, options.captureObj, options) });
return node;
});
return lively_ast.ReplaceVisitor.run(replaced, function (node, path, parent) {
return refsToReplace.includes(node) && !locallyIgnored.includes(node) ? member(options.captureObj, node) : node;
});
}
function replaceVarDecls(parsed, options) {
// rewrites var declarations so that they can be captured by
// `options.captureObj`.
// For normal vars we will do a transform like
// "var x = 23;" => "_rec.x = 23";
// For patterns (destructuring assignments) we will create assignments for
// all properties that are being destructured, creating helper vars as needed
// "var {x: [y]} = foo" => "var _1 = foo; var _1$x = _1.x; __rec.y = _1$x[0];"
var topLevel = topLevelDeclsAndRefs(parsed);
return lively_ast.ReplaceManyVisitor.run(parsed, function (node) {
if (!topLevel.varDecls.includes(node) || node.declarations.every(function (decl) {
return !shouldDeclBeCaptured(decl, options);
})) return node;
var replaced = [];
for (var i = 0; i < node.declarations.length; i++) {
var decl = node.declarations[i];
if (!shouldDeclBeCaptured(decl, options)) {
replaced.push({ type: "VariableDeclaration", kind: node.kind || "var", declarations: [decl] });
continue;
}
var init = decl.init || {
operator: "||",
type: "LogicalExpression",
left: { computed: false, object: options.captureObj, property: decl.id, type: "MemberExpression" },
right: { name: "undefined", type: "Identifier" }
};
var initWrapped = options.declarationWrapper && decl.id.name ? declarationWrapperCall(options.declarationWrapper, decl, literal(decl.id.name), literal(node.kind), init, options.captureObj, options) : init;
// Here we create the object pattern / destructuring replacements
if (decl.id.type.includes("Pattern")) {
var declRootName = generateUniqueName(topLevel.declaredNames, "destructured_1"),
declRoot = { type: "Identifier", name: declRootName },
state = { parent: declRoot, declaredNames: topLevel.declaredNames },
extractions = transformPattern(decl.id, state).map(function (decl) {
return decl[annotationSym] && decl[annotationSym].capture ? assignExpr(options.captureObj, decl.declarations[0].id, options.declarationWrapper ? declarationWrapperCall(options.declarationWrapper, null, literal(decl.declarations[0].id.name), literal(node.kind), decl.declarations[0].init, options.captureObj, options) : decl.declarations[0].init, false) : decl;
});
topLevel.declaredNames.push(declRootName);
replaced.push.apply(replaced, toConsumableArray([varDecl(declRoot, initWrapped, node.kind)].concat(extractions)));
continue;
}
// This is rewriting normal vars
replaced.push(assignExpr(options.captureObj, decl.id, initWrapped, false));
}
return replaced;
});
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// naming
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function generateUniqueName(declaredNames, hint) {
var unique = hint,
n = 1;
while (declaredNames.indexOf(unique) > -1) {
if (n > 1000) throw new Error("Endless loop searching for unique variable " + unique);
unique = unique.replace(/_[0-9]+$|$/, "_" + ++n);
}
return unique;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// exclude / include helpers
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function additionalIgnoredDecls(parsed, options) {
var topLevel = topLevelDeclsAndRefs(parsed),
ignoreDecls = [];
for (var i = 0; i < topLevel.scope.varDecls.length; i++) {
var decl = topLevel.scope.varDecls[i],
path = lively_lang.Path(topLevel.scope.varDeclPaths[i]),
parent = path.slice(0, -1).get(parsed);
if (parent.type === "ForStatement" || parent.type === "ForInStatement" || parent.type === "ForOfStatement" || parent.type === "ExportNamedDeclaration") ignoreDecls.push.apply(ignoreDecls, toConsumableArray(decl.declarations));
}
return topLevel.scope.catches.map(function (ea) {
return ea.name;
}).concat(ignoreDecls.map(function (ea) {
return ea.id.name;
}));
}
function additionalIgnoredRefs(parsed, options) {
// FIXME rk 2016-05-11: in shouldRefBeCaptured we now also test for import
// decls, this should somehow be consolidated with this function and with the
// fact that naming based ignores aren't good enough...
var topLevel = topLevelDeclsAndRefs(parsed);
var ignoreDecls = [];
for (var i = 0; i < topLevel.scope.varDecls.length; i++) {
var decl = topLevel.scope.varDecls[i],
path = lively_lang.Path(topLevel.scope.varDeclPaths[i]),
parent = path.slice(0, -1).get(parsed);
if (parent.type === "ForStatement" || parent.type === "ForInStatement" || parent.type === "ForOfStatement") ignoreDecls.push.apply(ignoreDecls, toConsumableArray(decl.declarations));
}
return topLevel.scope.catches.map(function (ea) {
return ea.name;
}).concat(queryHelpers.declIds(ignoreDecls.map(function (ea) {
return ea.id;
})).map(function (ea) {
return ea.name;
}));
}
function shouldDeclBeCaptured(decl, options) {
return options.excludeDecls.indexOf(decl.id.name) === -1 && (!options.includeDecls || options.includeDecls.indexOf(decl.id.name) > -1);
}
function shouldRefBeCaptured(ref, toplevel, options) {
if (toplevel.scope.importSpecifiers.includes(ref)) return false;
for (var i = 0; i < toplevel.scope.exportDecls.length; i++) {
var ea = toplevel.scope.exportDecls[i];
if (ea.declarations && ea.declarations.includes(ref)) return false;
if (ea.declaration === ref) return false;
}
if (options.excludeRefs.includes(ref.name)) return false;
if (options.includeRefs && !options.includeRefs.includes(ref.name)) return false;
return true;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// capturing specific code
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function replaceClassDecls(parsed, options) {
if (options.classToFunction) return lively_classes.classToFunctionTransform(parsed, options.classToFunction);
var topLevel = topLevelDeclsAndRefs(parsed);
if (!topLevel.classDecls.length) return parsed;
for (var i = parsed.body.length - 1; i >= 0; i--) {
var stmt = parsed.body[i];
if (topLevel.classDecls.includes(stmt)) parsed.body.splice(i + 1, 0, assignExpr(options.captureObj, stmt.id, stmt.id, false));
}
return parsed;
}
function splitExportDeclarations(parsed, options) {
var stmts = parsed.body,
newNodes = parsed.body = [];
for (var i = 0; i < stmts.length; i++) {
var stmt = stmts[i];
if (stmt.type !== "ExportNamedDeclaration" || !stmt.declaration || stmt.declaration.type !== "VariableDeclaration" || stmt.declaration.declarations.length <= 1) {
newNodes.push(stmt);continue;
}
var decls = stmt.declaration.declarations;
for (var j = 0; j < decls.length; j++) {
newNodes.push({
type: "ExportNamedDeclaration",
specifiers: [],
declaration: varDecl(decls[j].id, decls[j].init, stmt.declaration.kind)
});
}
}
return parsed;
}
function insertCapturesForExportDeclarations(parsed, options) {
var body = [];
for (var i = 0; i < parsed.body.length; i++) {
var stmt = parsed.body[i];
body.push(stmt);
// ExportNamedDeclaration can have specifieres = refs, those should already
// be captured. Only focus on export declarations and only those
// declarations that are no refs, i.e.
// ignore: "export default x;"
// capture: "export default function foo () {};", "export var x = 23, y = 3;"
if (stmt.type !== "ExportNamedDeclaration" && stmt.type !== "ExportDefaultDeclaration" || !stmt.declaration) {
/*...*/
} else if (stmt.declaration.declarations) {
body.push.apply(body, toConsumableArray(stmt.declaration.declarations.map(function (decl) {
var assignVal = decl.id;
if (options.declarationWrapper) {
var alreadyWrapped = decl.init.callee && decl.init.callee.name === options.declarationWrapper.name;
if (!alreadyWrapped) assignVal = declarationWrapperCall(options.declarationWrapper, decl, literal(decl.id.name), literal("assignment"), decl.id, options.captureObj, options);
}
return assignExpr(options.captureObj, decl.id, assignVal, false);
})));
} else if (stmt.declaration.type === "FunctionDeclaration") {
/*handled by function rewriter as last step*/
} else if (stmt.declaration.type === "ClassDeclaration") {
body.push(assignExpr(options.captureObj, stmt.declaration.id, stmt.declaration.id, false));
}
}
parsed.body = body;
return parsed;
}
function insertCapturesForImportDeclarations(parsed, options) {
parsed.body = parsed.body.reduce(function (stmts, stmt) {
return stmts.concat(stmt.type !== "ImportDeclaration" || !stmt.specifiers.length ? [stmt] : [stmt].concat(stmt.specifiers.map(function (specifier) {
return assignExpr(options.captureObj, specifier.local, specifier.local, false);
})));
}, []);
return parsed;
}
function insertDeclarationsForExports(parsed, options) {
var topLevel = topLevelDeclsAndRefs(parsed),
body = [];
for (var i = 0; i < parsed.body.length; i++) {
var stmt = parsed.body[i];
if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration && stmt.declaration.type.indexOf("Declaration") === -1) {
body = body.concat([varDeclOrAssignment(parsed, {
type: "VariableDeclarator",
id: stmt.declaration,
init: member(options.captureObj, stmt.declaration)
}), stmt]);
} else if (stmt.type !== "ExportNamedDeclaration" || !stmt.specifiers.length || stmt.source) {
body.push(stmt);
} else {
body = body.concat(stmt.specifiers.map(function (specifier) {
return lively_lang.arr.include(topLevel.declaredNames, specifier.local.name) ? null : varDeclOrAssignment(parsed, {
type: "VariableDeclarator",
id: specifier.local,
init: member(options.captureObj, specifier.local)
});
}).filter(Boolean)).concat(stmt);
}
}
parsed.body = body;
return parsed;
}
function fixDefaultAsyncFunctionExportForRegeneratorBug(parsed, options) {
// rk 2016-06-02: see https://github.com/LivelyKernel/lively.modules/issues/9
// FIXME this needs to be removed as soon as the cause for the issue is fixed
var body = [];
for (var i = 0; i < parsed.body.length; i++) {
var stmt = parsed.body[i];
if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration.type === "FunctionDeclaration" && stmt.declaration.id && stmt.declaration.async) {
body.push(stmt.declaration);
stmt.declaration = { type: "Identifier", name: stmt.declaration.id.name };
}
body.push(stmt);
}
parsed.body = body;
return parsed;
}
function es6ModuleTransforms(parsed, options) {
parsed.body = parsed.body.reduce(function (stmts, stmt) {
var nodes$$1;
if (stmt.type === "ExportNamedDeclaration") {
if (stmt.source) {
var key = moduleId = stmt.source;
nodes$$1 = stmt.specifiers.map(function (specifier) {
return {
type: "ExpressionStatement",
expression: exportFromImport({ type: "Literal", value: specifier.exported.name }, { type: "Literal", value: specifier.local.name }, moduleId, options.moduleExportFunc, options.moduleImportFunc) };
});
} else if (stmt.declaration) {
var decls = stmt.declaration.declarations;
if (!decls) {
// func decl or class
nodes$$1 = [stmt.declaration].concat(exportCallStmt(options.moduleExportFunc, stmt.declaration.id.name, stmt.declaration.id));
} else {
nodes$$1 = decls.map(function (decl) {
options.excludeDecls.push(decl.id);
return varDecl(decl.id, assignExpr(options.captureObj, decl.id, options.declarationWrapper ? declarationWrapperCall(options.declarationWrapper, null, literal(decl.id.name), literal(stmt.declaration.kind), decl, options.captureObj, options) : decl.init, false), stmt.declaration.kind);
}).concat(decls.map(function (decl) {
return exportCallStmt(options.moduleExportFunc, decl.id.name, decl.id);
}));
}
} else {
nodes$$1 = stmt.specifiers.map(function (specifier) {
return exportCallStmt(options.moduleExportFunc, specifier.exported.name, shouldDeclBeCaptured({ id: specifier.local }, options) ? member(options.captureObj, specifier.local) : specifier.local);
});
}
} else if (stmt.type === "ExportDefaultDeclaration") {
if (stmt.declaration && stmt.declaration.id) {
nodes$$1 = [stmt.declaration].concat(exportCallStmt(options.moduleExportFunc, "default", stmt.declaration.id));
} else {
nodes$$1 = [exportCallStmt(options.moduleExportFunc, "default", stmt.declaration)];
}
} else if (stmt.type === "ExportAllDeclaration") {
var key = { name: options.es6ExportFuncId + "__iterator__", type: "Identifier" },
moduleId = stmt.source;
nodes$$1 = [{
type: "ForInStatement",
body: { type: "ExpressionStatement", expression: exportFromImport(key, key, moduleId, options.moduleExportFunc, options.moduleImportFunc) },
left: { type: "VariableDeclaration", kind: "var", declarations: [{ type: "VariableDeclarator", id: key, init: null }] },
right: importCall(null, moduleId, options.moduleImportFunc)
}];
options.excludeRefs.push(key.name);
options.excludeDecls.push(key.name);
} else if (stmt.type === "ImportDeclaration") {
nodes$$1 = stmt.specifiers.length ? stmt.specifiers.map(function (specifier) {
var local = specifier.local,
imported = specifier.type === "ImportSpecifier" && specifier.imported.name || specifier.type === "ImportDefaultSpecifier" && "default" || null;
return varDeclAndImportCall(parsed, local, imported || null, stmt.source, options.moduleImportFunc);
}) : importCallStmt(null, stmt.source, options.moduleImportFunc);
} else nodes$$1 = [stmt];
return stmts.concat(nodes$$1);
}, []);
return parsed;
}
function putFunctionDeclsInFront(parsed, options) {
var scope = topLevelDeclsAndRefs(parsed).scope,
funcDecls = scope.funcDecls;
if (!funcDecls.length) return parsed;
var putInFront = [];
for (var i = funcDecls.length; i--;) {
var decl = funcDecls[i];
if (!shouldDeclBeCaptured(decl, options)) continue;
var parentPath = scope.funcDeclPaths[i].slice(0, -1),
// ge the parent so we can replace the original function:
parent = lively_lang.Path(parentPath).get(scope.node),
funcId = { type: "Identifier", name: decl.id.name },
// what we capture:
init = options.declarationWrapper ? declarationWrapperCall(options.declarationWrapper, decl, literal(funcId.name), literal("function"), funcId, options.captureObj, options) : funcId,
declFront = _extends({}, decl);
if (Array.isArray(parent)) {
// If the parent is a body array we remove the original func decl from it
// and replace it with a reference to the function
parent.splice(parent.indexOf(decl), 1, exprStmt(decl.id));
} else if (parent.type === "ExportNamedDeclaration") {
// If the function is exported we change the export declaration into a reference
var parentIndexInBody = scope.node.body.indexOf(parent);
if (parentIndexInBody > -1) {
scope.node.body.splice(parentIndexInBody, 1, { type: "ExportNamedDeclaration", specifiers: [{ type: "ExportSpecifier", exported: decl.id, local: decl.id }] });
}
} else if (parent.type === "ExportDefaultDeclaration") {
parent.declaration = decl.id;
} else {}
// ??? just leave it alone...
// decl.type = "EmptyStatement";
// hoist the function to the front, also it's capture
putInFront.unshift(assignExpr(options.captureObj, funcId, init, false));
putInFront.unshift(declFront);
}
parsed.body = putInFront.concat(parsed.body);
return parsed;
}
function computeDefRanges(parsed, options) {
var topLevel = topLevelDeclsAndRefs(parsed);
return lively_lang.chain(topLevel.scope.varDecls).pluck("declarations").flatten().value().concat(topLevel.scope.funcDecls).reduce(function (defs, decl) {
if (!defs[decl.id.name]) defs[decl.id.name] = [];
defs[decl.id.name].push({ type: decl.type, start: decl.start, end: decl.end });
return defs;
}, {});
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// capturing oobject patters / destructuring
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
var annotationSym = Symbol("lively.ast-destructuring-transform");
function transformPattern(pattern, transformState) {
// For transforming destructuring expressions into plain vars and member access.
// Takes a var or argument pattern node (of type ArrayPattern or
// ObjectPattern) and transforms it into a set of var declarations that will
// "pull out" the nested properties
// Example:
// var parsed = parse("var [{b: {c: [a]}}] = foo;");
// var state = {parent: {type: "Identifier", name: "arg"}, declaredNames: ["foo"]}
// transformPattern(parsed.body[0].declarations[0].id, state).map(stringify).join("\n");
// // => "var arg$0 = arg[0];\n"
// // + "var arg$0$b = arg$0.b;\n"
// // + "var arg$0$b$c = arg$0$b.c;\n"
// // + "var a = arg$0$b$c[0];"
return pattern.type === "ArrayPattern" ? transformArrayPattern(pattern, transformState) : pattern.type === "ObjectPattern" ? transformObjectPattern(pattern, transformState) : [];
}
function transformArrayPattern(pattern, transformState) {
var declaredNames = transformState.declaredNames,
p = annotationSym,
transformed = [];
for (var i = 0; i < pattern.elements.length; i++) {
var el = pattern.elements[i];
// like [a]
if (el.type === "Identifier") {
var decl = varDecl(el, member(transformState.parent, id(i), true));
decl[p] = { capture: true };
transformed.push(decl);
// like [...foo]
} else if (el.type === "RestElement") {
var decl = varDecl(el.argument, {
type: "CallExpression",
arguments: [{ type: "Literal", value: i }],
callee: member(transformState.parent, id("slice"), false) });
decl[p] = { capture: true };
transformed.push(decl);
} else if (el.type == "AssignmentPattern") {
// like [x = 23]
var decl = varDecl(el.left /*id*/
, conditional(binaryExpr(member(transformState.parent, id(i), true), "===", id("undefined")), el.right, member(transformState.parent, id(i), true)));
decl[p] = { capture: true };
transformed.push(decl);
// like [{x}]
} else {
var helperVarId = id(generateUniqueName(declaredNames, transformState.parent.name + "$" + i)),
helperVar = varDecl(helperVarId, member(transformState.parent, i));
// helperVar[p] = {capture: true};
declaredNames.push(helperVarId.name);
transformed.push(helperVar);
transformed.push.apply(transformed, toConsumableArray(transformPattern(el, { parent: helperVarId, declaredNames: declaredNames })));
}
}
return transformed;
}
function transformObjectPattern(pattern, transformState) {
var declaredNames = transformState.declaredNames,
p = annotationSym,
transformed = [];
for (var i = 0; i < pattern.properties.length; i++) {
var prop = pattern.properties[i];
if (prop.value.type == "Identifier") {
// like {x: y}
var decl = varDecl(prop.value, member(transformState.parent, prop.key));
decl[p] = { capture: true };
transformed.push(decl);
} else if (prop.value.type == "AssignmentPattern") {
// like {x = 23}
var decl = varDecl(prop.value.left /*id*/
, conditional(binaryExpr(member(transformState.parent, prop.key), "===", id("undefined")), prop.value.right, member(transformState.parent, prop.key)));
decl[p] = { capture: true };
transformed.push(decl);
} else {
// like {x: {z}} or {x: [a]}
var helperVarId = id(generateUniqueName(declaredNames, transformState.parent.name + "$" + prop.key.name)),
helperVar = varDecl(helperVarId, member(transformState.parent, prop.key));
helperVar[p] = { capture: false };
declaredNames.push(helperVarId.name);
transformed.push.apply(transformed, toConsumableArray([helperVar].concat(transformPattern(prop.value, { parent: helperVarId, declaredNames: declaredNames }))));
}
}
return transformed;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// code generation helpers
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function varDeclOrAssignment(parsed, declarator, kind) {
var topLevel = topLevelDeclsAndRefs(parsed),
name = declarator.id.name;
return topLevel.declaredNames.indexOf(name) > -1 ?
// only create a new declaration if necessary
exprStmt(assign(declarator.id, declarator.init)) : {
declarations: [declarator],
kind: kind || "var", type: "VariableDeclaration"
};
}
function assignExpr(assignee, propId, value, computed) {
return exprStmt(assign(member(assignee, propId, computed), value || id("undefined")));
}
function exportFromImport(keyLeft, keyRight, moduleId, moduleExportFunc, moduleImportFunc) {
return exportCall(moduleExportFunc, keyLeft, importCall(keyRight, moduleId, moduleImportFunc));
}
function varDeclAndImportCall(parsed, localId, imported, moduleSource, moduleImportFunc) {
// return varDeclOrAssignment(parsed, {
// type: "VariableDeclarator",
// id: localId,
// init: importCall(imported, moduleSource, moduleImportFunc)
// });
return varDecl(localId, importCall(imported, moduleSource, moduleImportFunc));
}
function importCall(imported, moduleSource, moduleImportFunc) {
if (typeof imported === "string") imported = literal(imported);
return {
arguments: [moduleSource].concat(imported || []),
callee: moduleImportFunc, type: "CallExpression"
};
}
function importCallStmt(imported, moduleSource, moduleImportFunc) {
return exprStmt(importCall(imported, moduleSource, moduleImportFunc));
}
function exportCall(exportFunc, local, exportedObj) {
if (typeof local === "string") local = literal(local);
exportedObj = lively_lang.obj.deepCopy(exportedObj);
return funcCall(exportFunc, local, exportedObj);
}
function exportCallStmt(exportFunc, local, exportedObj) {
return exprStmt(exportCall(exportFunc, local, exportedObj));
}
function declarationWrapperCall(declarationWrapperNode, declNode, varNameLiteral, varKindLiteral, valueNode, recorder, options) {
if (declNode) {
// here we pass compile-time meta data into the runtime
var keyVals = [];
var addMeta = false;
if (declNode["x-lively-object-meta"]) {
var _declNode$xLivelyOb = declNode["x-lively-object-meta"],
start = _declNode$xLivelyOb.start,
end = _declNode$xLivelyOb.end,
evalId = _declNode$xLivelyOb.evalId,
sourceAccessorName = _declNode$xLivelyOb.sourceAccessorName;
addMeta = true;
keyVals.push("start", lively_ast.nodes.literal(start), "end", lively_ast.nodes.literal(end));
}
if (evalId === undefined && options.hasOwnProperty("evalId")) {
evalId = options.evalId;
addMeta = true;
}
if (sourceAccessorName === undefined && options.hasOwnProperty("sourceAccessorName")) {
sourceAccessorName = options.sourceAccessorName;
addMeta = true;
}
if (evalId !== undefined) keyVals.push("evalId", lively_ast.nodes.literal(evalId));
if (sourceAccessorName) keyVals.push("moduleSource", lively_ast.nodes.id(sourceAccessorName));
if (addMeta) {
return funcCall(declarationWrapperNode, varNameLiteral, varKindLiteral, valueNode, recorder, lively_ast.nodes.objectLiteral(keyVals) /*meta node*/);
}
}
return funcCall(declarationWrapperNode, varNameLiteral, varKindLiteral, valueNode, recorder);
}
var capturing = Object.freeze({
rewriteToCaptureTopLevelVariables: rewriteToCaptureTopLevelVariables,
rewriteToRegisterModuleToCaptureSetters: rewriteToRegisterModuleToCaptureSetters
});
function stringifyFunctionWithoutToplevelRecorder(funcOrSourceOrAst) {
var varRecorderName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "__lvVarRecorder";
// stringifyFunctionWithoutToplevelRecorder((x) => hello + x)
// => x => hello + x
// instead of String((x) => hello + x) // => x => __lvVarRecorder.hello + x
// when run in toplevel scope
if (typeof funcOrSourceOrAst === "function") funcOrSourceOrAst = String(funcOrSourceOrAst);
var parsed = typeof funcOrSourceOrAst === "string" ? lively_ast.parseFunction(funcOrSourceOrAst) : funcOrSourceOrAst,
replaced = lively_ast.ReplaceVisitor.run(parsed, function (node) {
var isVarRecorderMember = node.type === "MemberExpression" && node.object.type === "Identifier" && node.object.name === varRecorderName;
return isVarRecorderMember ? node.property : node;
});
return lively_ast.stringify(replaced);
}
exports.capturing = capturing;
exports.stringifyFunctionWithoutToplevelRecorder = stringifyFunctionWithoutToplevelRecorder;
}((this.lively.sourceTransform = this.lively.sourceTransform || {}),lively.lang,lively.classes,lively.ast));
if (typeof module !== "undefined" && module.exports) module.exports = GLOBAL.lively.sourceTransform;
})();