prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
134 lines (109 loc) • 5.13 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PreludeGenerator = exports.DisablePlaceholderSuffix = exports.Placeholders = void 0;
var t = _interopRequireWildcard(require("@babel/types"));
var _babelhelpers = require("./babelhelpers.js");
var _NameGenerator = require("./NameGenerator.js");
var _template = _interopRequireDefault(require("@babel/template"));
var _invariant = _interopRequireDefault(require("../invariant.js"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
/**
* 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.
*/
const Placeholders = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
exports.Placeholders = Placeholders;
const placeholderDefaultWhiteList = new Set(["global"]);
const placeholderWhitelist = new Set([...placeholderDefaultWhiteList, ...Placeholders]);
const DisablePlaceholderSuffix = "// disable placeholders";
exports.DisablePlaceholderSuffix = DisablePlaceholderSuffix;
class PreludeGenerator {
constructor(debugNames, uniqueSuffix) {
this.prelude = [];
this.memoizedRefs = new Map();
this.nameGenerator = new _NameGenerator.NameGenerator(new Set(), !!debugNames, uniqueSuffix || "", "_$");
this.usesThis = false;
this.declaredGlobals = new Set();
this.nextInvariantId = 0;
this._expressionTemplates = new Map();
}
createNameGenerator(prefix) {
return new _NameGenerator.NameGenerator(this.nameGenerator.forbiddenNames, this.nameGenerator.debugNames, this.nameGenerator.uniqueSuffix, prefix);
}
convertStringToMember(str) {
return str.split(".").map(name => {
if (name === "global") {
return this.memoizeReference(name);
} else if (name === "this") {
return t.thisExpression();
} else {
return t.identifier(name);
}
}).reduce((obj, prop) => t.memberExpression(obj, prop));
}
globalReference(key, globalScope = false) {
if (globalScope && t.isValidIdentifier(key)) return t.identifier(key);
return (0, _babelhelpers.memberExpressionHelper)(this.memoizeReference("global"), key);
}
memoizeReference(key) {
let ref = this.memoizedRefs.get(key);
if (ref) return ref;
let init;
if (key.includes("(") || key.includes("[")) {
// Horrible but effective hack:
// Some internal object have intrinsic names such as
// ([][Symbol.iterator]().__proto__.__proto__)
// and
// RegExp.prototype[Symbol.match]
// which get turned into a babel node here.
// TODO: We should properly parse such a string, and memoize all references in it separately.
// Instead, we just turn it into a funky identifier, which Babel seems to accept.
init = t.identifier(key);
} else if (key === "global") {
this.usesThis = true;
init = t.thisExpression();
} else {
let i = key.lastIndexOf(".");
if (i === -1) {
init = t.memberExpression(this.memoizeReference("global"), t.identifier(key));
} else {
init = t.memberExpression(this.memoizeReference(key.substr(0, i)), t.identifier(key.substr(i + 1)));
}
}
ref = t.identifier(this.nameGenerator.generate(key));
this.prelude.push(t.variableDeclaration("var", [t.variableDeclarator(ref, init)]));
this.memoizedRefs.set(key, ref);
return ref;
}
buildExpression(code, templateArguments) {
let disablePlaceholders = false;
const key = code;
let template = this._expressionTemplates.get(key);
if (template === undefined) {
if (code.endsWith(DisablePlaceholderSuffix)) {
code = code.substring(0, code.length - DisablePlaceholderSuffix.length);
disablePlaceholders = true;
}
template = (0, _template.default)(code, {
placeholderPattern: false,
placeholderWhitelist: disablePlaceholders ? placeholderDefaultWhiteList : placeholderWhitelist
});
this._expressionTemplates.set(key, template);
}
if (code.includes("global")) templateArguments = Object.assign({
global: this.memoizeReference("global")
}, templateArguments);
let result = template(templateArguments).expression;
(0, _invariant.default)(result !== undefined, "Code does not represent an expression: " + code);
return result;
}
}
exports.PreludeGenerator = PreludeGenerator;
//# sourceMappingURL=PreludeGenerator.js.map