prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
292 lines (218 loc) • 9.26 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _index = require("../values/index.js");
var _jsx = require("../react/jsx.js");
var _index2 = require("../methods/index.js");
var _singletons = require("../singletons.js");
var _invariant = _interopRequireDefault(require("../invariant.js"));
var _elements = require("../react/elements.js");
var _utils = require("../react/utils.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
// taken from Babel
function cleanJSXElementLiteralChild(child) {
let lines = child.split(/\r\n|\n|\r/);
let lastNonEmptyLine = 0;
for (let i = 0; i < lines.length; i++) {
if (lines[i].match(/[^ \t]/)) {
lastNonEmptyLine = i;
}
}
let str = "";
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
let isFirstLine = i === 0;
let isLastLine = i === lines.length - 1;
let isLastNonEmptyLine = i === lastNonEmptyLine; // replace rendered whitespace tabs with spaces
let trimmedLine = line.replace(/\t/g, " "); // trim whitespace touching a newline
if (!isFirstLine) {
trimmedLine = trimmedLine.replace(/^[ ]+/, "");
} // trim whitespace touching an endline
if (!isLastLine) {
trimmedLine = trimmedLine.replace(/[ ]+$/, "");
}
if (trimmedLine) {
if (!isLastNonEmptyLine) {
trimmedLine += " ";
}
str += trimmedLine;
}
}
if (str) {
return str;
}
return null;
}
function evaluateJSXMemberExpression(ast, strictCode, env, realm) {
switch (ast.type) {
case "JSXIdentifier":
return _singletons.Environment.GetValue(realm, _singletons.Environment.ResolveBinding(realm, ast.name, strictCode, env));
case "JSXMemberExpression":
return _singletons.Environment.GetValue(realm, env.evaluate((0, _jsx.convertJSXExpressionToIdentifier)(ast), strictCode));
default:
(0, _invariant.default)(false, "Unknown JSX Identifier");
}
}
function evaluateJSXIdentifier(ast, strictCode, env, realm) {
if (isTagName(ast)) {
// special cased lower-case and custom elements
return new _index.StringValue(realm, ast.name);
}
return evaluateJSXMemberExpression(ast, strictCode, env, realm);
}
function evaluateJSXValue(value, strictCode, env, realm) {
if (value != null) {
switch (value.type) {
case "JSXText":
return new _index.StringValue(realm, value.value);
case "StringLiteral":
return new _index.StringValue(realm, value.value);
case "JSXExpressionContainer":
return _singletons.Environment.GetValue(realm, env.evaluate(value.expression, strictCode));
case "JSXElement":
return _singletons.Environment.GetValue(realm, env.evaluate(value, strictCode));
default:
(0, _invariant.default)(false, `Unknown JSX value type: ${value.type}`);
}
}
(0, _invariant.default)(false, `Null or undefined value passed when trying to evaluate JSX node value`);
}
function isTagName(ast) {
return ast.type === "JSXIdentifier" && /^[a-z]|\-/.test(ast.name);
}
function evaluateJSXChildren(children, strictCode, env, realm) {
if (children.length === 0) {
return undefined;
}
if (children.length === 1) {
let singleChild = evaluateJSXValue(children[0], strictCode, env, realm);
if (singleChild instanceof _index.StringValue) {
let text = cleanJSXElementLiteralChild(singleChild.value);
if (text !== null) {
singleChild.value = text;
}
}
return singleChild;
}
let array = _singletons.Create.ArrayCreate(realm, 0);
let dynamicChildrenLength = children.length;
let dynamicIterator = 0;
let lastChildValue = realm.intrinsics.undefined;
for (let i = 0; i < children.length; i++) {
let value = evaluateJSXValue(children[i], strictCode, env, realm);
if (value instanceof _index.StringValue) {
let text = cleanJSXElementLiteralChild(value.value);
if (text === null) {
dynamicChildrenLength--; // this is a space full of whitespace, so let's proceed
continue;
} else {
value.value = text;
}
}
lastChildValue = value;
_singletons.Create.CreateDataPropertyOrThrow(realm, array, "" + dynamicIterator, value);
dynamicIterator++;
}
if (dynamicChildrenLength === 1) {
return lastChildValue;
}
_singletons.Properties.Set(realm, array, "length", new _index.NumberValue(realm, dynamicChildrenLength), false);
array.makeFinal();
return array;
}
function isObjectEmpty(realm, object) {
let propertyCount = 0;
for (let [, binding] of object.properties) {
if (binding && binding.descriptor && binding.descriptor.throwIfNotConcrete(realm).enumerable) {
propertyCount++;
}
}
return propertyCount === 0;
}
function evaluateJSXAttributes(astAttributes, strictCode, env, realm) {
let config = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
let abstractPropsArgs = [];
let abstractSpreadCount = 0;
let safeAbstractSpreadCount = 0;
let spreadValue;
const setConfigProperty = (name, value) => {
(0, _invariant.default)(config instanceof _index.ObjectValue);
_singletons.Properties.Set(realm, config, name, value, true);
};
for (let astAttribute of astAttributes) {
switch (astAttribute.type) {
case "JSXAttribute":
let {
name,
value
} = astAttribute;
(0, _invariant.default)(name.type === "JSXIdentifier", `JSX attribute name type not supported: ${astAttribute.type}`);
setConfigProperty(name.name, evaluateJSXValue(value, strictCode, env, realm));
break;
case "JSXSpreadAttribute":
spreadValue = _singletons.Environment.GetValue(realm, env.evaluate(astAttribute.argument, strictCode));
if (spreadValue instanceof _index.ObjectValue && !spreadValue.isPartialObject()) {
for (let [spreadPropKey, binding] of spreadValue.properties) {
if (binding && binding.descriptor && binding.descriptor.throwIfNotConcrete(realm).enumerable) {
setConfigProperty(spreadPropKey, (0, _index2.Get)(realm, spreadValue, spreadPropKey));
}
}
} else {
abstractSpreadCount++;
if (spreadValue instanceof _index.AbstractValue && !(spreadValue instanceof _index.AbstractObjectValue)) {
spreadValue = _singletons.To.ToObject(realm, spreadValue);
}
(0, _invariant.default)(spreadValue instanceof _index.AbstractObjectValue || spreadValue instanceof _index.ObjectValue);
if ((0, _utils.hasNoPartialKeyOrRef)(realm, spreadValue)) {
safeAbstractSpreadCount++;
}
if (!isObjectEmpty(realm, config)) {
abstractPropsArgs.push(config);
}
abstractPropsArgs.push(spreadValue);
config = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
}
break;
default:
(0, _invariant.default)(false, `Unknown JSX attribute type: ${astAttribute.type}`);
}
}
if (abstractSpreadCount > 0) {
// if we only have a single spread config, then use that,
// i.e. <div {...something} /> --> React.createElement("div", something)
if (abstractSpreadCount === 1 && astAttributes.length === 1 && (spreadValue instanceof _index.ObjectValue || spreadValue instanceof _index.AbstractObjectValue)) {
return spreadValue;
} // we create an abstract Object.assign() to deal with the fact that we don't what
// the props are because they contain abstract spread attributes that we can't
// evaluate ahead of time
// push the current config
abstractPropsArgs.push(config); // create a new config object that will be the target of the Object.assign
config = _singletons.Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype);
(0, _utils.applyObjectAssignConfigsForReactElement)(realm, config, abstractPropsArgs);
if (safeAbstractSpreadCount === abstractSpreadCount) {
(0, _utils.flagPropsWithNoPartialKeyOrRef)(realm, config);
}
}
(0, _invariant.default)(config instanceof _index.ObjectValue || config instanceof _index.AbstractObjectValue);
return config;
}
function _default(ast, strictCode, env, realm) {
(0, _invariant.default)(realm.react.enabled, "JSXElements can only be evaluated with the reactEnabled option");
let openingElement = ast.openingElement;
let type = evaluateJSXIdentifier(openingElement.name, strictCode, env, realm);
let children = evaluateJSXChildren(ast.children, strictCode, env, realm);
let config = evaluateJSXAttributes(openingElement.attributes, strictCode, env, realm);
(0, _invariant.default)(type instanceof _index.Value);
return (0, _elements.createReactElement)(realm, type, config, children);
}
//# sourceMappingURL=JSXElement.js.map