UNPKG

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
"use strict"; 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