prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
229 lines (187 loc) • 6.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createMarkupForRoot = createMarkupForRoot;
exports.isCustomComponent = isCustomComponent;
exports.escapeHtml = escapeHtml;
exports.normalizeNode = normalizeNode;
exports.convertValueToNode = convertValueToNode;
exports.createHtmlEscapeHelper = createHtmlEscapeHelper;
exports.createArrayHelper = createArrayHelper;
exports.getNonChildrenInnerMarkup = getNonChildrenInnerMarkup;
exports.quoteAttributeValueForBrowser = quoteAttributeValueForBrowser;
var _parser = require("@babel/parser");
var _index = require("../../values/index.js");
var _utils = require("../utils.js");
var _invariant = _interopRequireDefault(require("../../invariant.js"));
var _domConfig = require("./dom-config.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.
*/
// Warning: This code is experimental and might not fully work. There is no guarantee
// that is up-to-date with the curent react-dom/server logic and there may also be
// security holes in the string escaping because of this.
const matchHtmlRegExp = /["'&<>]/;
function createMarkupForRoot() {
return _domConfig.ROOT_ATTRIBUTE_NAME + '=""';
}
function isCustomComponent(realm, tagName, propsValue) {
if (tagName.indexOf("-") === -1) {
let is = (0, _utils.getProperty)(realm, propsValue, "is");
return is instanceof _index.StringValue;
}
switch (tagName) {
case "annotation-xml":
case "color-profile":
case "font-face":
case "font-face-src":
case "font-face-uri":
case "font-face-format":
case "font-face-name":
case "missing-glyph":
return false;
default:
return true;
}
} // $FlowFixMe: we don't want to provides types here as we inject this function into source
function escapeHtml(string) {
if (typeof string === "boolean" || typeof string === "number") {
return "" + string;
}
let str = "" + string;
let match = matchHtmlRegExp.exec(str);
if (!match) {
return str;
}
let escape;
let html = "";
let index = 0;
let lastIndex = 0;
for (index = match.index; index < str.length; index++) {
switch (str.charCodeAt(index)) {
case 34:
escape = """;
break;
case 38:
escape = "&";
break;
case 39:
escape = "'";
break;
case 60:
escape = "<";
break;
case 62:
escape = ">";
break;
default:
continue;
}
if (lastIndex !== index) {
html += str.substring(lastIndex, index);
}
lastIndex = index + 1;
html += escape;
}
return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
}
function normalizeNode(realm, reactNode) {
if (Array.isArray(reactNode)) {
let newReactNode;
for (let element of reactNode) {
if (typeof element === "string") {
if (newReactNode === undefined) {
newReactNode = element;
} else if (typeof newReactNode === "string") {
newReactNode += element;
} else {
let lastNode = newReactNode[newReactNode.length - 1];
if (typeof lastNode === "string") {
newReactNode[newReactNode.length - 1] += element;
} else {
newReactNode.push(element);
}
}
} else if (newReactNode === undefined) {
newReactNode = [element];
} else if (typeof newReactNode === "string") {
newReactNode = [newReactNode, element];
} else {
newReactNode.push(element);
}
}
(0, _invariant.default)(newReactNode !== undefined);
return newReactNode;
} else if (typeof reactNode === "string" || reactNode instanceof _index.AbstractValue) {
return reactNode;
}
(0, _invariant.default)(false, "TODO");
}
function convertValueToNode(value) {
if (value instanceof _index.AbstractValue) {
return value;
} else if (value instanceof _index.StringValue || value instanceof _index.NumberValue) {
return value.value + "";
}
(0, _invariant.default)(false, "TODO");
}
function createHtmlEscapeHelper(realm) {
let escapeHelperAst = (0, _parser.parseExpression)(escapeHtml.toString(), {
plugins: ["flow"]
});
let helper = new _index.ECMAScriptSourceFunctionValue(realm);
helper.initialize(escapeHelperAst.params, escapeHelperAst.body);
return helper;
}
function createArrayHelper(realm) {
let arrayHelper = `
function arrayHelper(array) {
let length = array.length;
let i = 0;
let str = "";
let item;
while (i < length) {
item = array[i++];
if (previousWasTextNode === true) {
str += "<!-- -->" + item;
} else {
str += item;
}
previousWasTextNode = item[0] !== "<";
}
return str;
}
`;
let escapeHelperAst = (0, _parser.parseExpression)(arrayHelper, {
plugins: ["flow"]
});
let helper = new _index.ECMAScriptSourceFunctionValue(realm);
helper.initialize(escapeHelperAst.params, escapeHelperAst.body);
return helper;
}
function getNonChildrenInnerMarkup(realm, propsValue) {
let innerHTML = (0, _utils.getProperty)(realm, propsValue, "dangerouslySetInnerHTML");
if (innerHTML instanceof _index.ObjectValue) {
let _html = (0, _utils.getProperty)(realm, innerHTML, "dangerouslySetInnerHTML");
if (_html instanceof _index.StringValue) {
return _html.value;
}
} else {
let content = (0, _utils.getProperty)(realm, propsValue, "children");
if (content instanceof _index.StringValue || content instanceof _index.NumberValue) {
return escapeHtml(content.value);
}
}
return null;
}
function quoteAttributeValueForBrowser(value) {
return '"' + escapeHtml(value) + '"';
}
//# sourceMappingURL=utils.js.map