@metamask/snaps-browserify-plugin
Version:
A Browserify plugin to build MetaMask Snaps with Browserify
151 lines • 7.44 kB
JavaScript
;
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _SnapsBrowserifyTransform_data, _SnapsBrowserifyTransform_options;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SnapsBrowserifyTransform = void 0;
const node_1 = require("@metamask/snaps-utils/node");
const convert_source_map_1 = require("convert-source-map");
const path_1 = __importDefault(require("path"));
const readable_stream_1 = require("readable-stream");
/**
* Run eval on the processed bundle and fix the manifest, if configured.
*
* @param options - The plugin options.
* @param code - The code to eval, if the eval option is enabled.
*/
async function postBundle(options, code) {
if (options.eval) {
await (0, node_1.useTemporaryFile)('snaps-bundle.js', code, (path) => (0, node_1.evalBundle)(path));
}
if (options.manifestPath) {
const { reports } = await (0, node_1.checkManifest)(path_1.default.dirname(options.manifestPath), {
sourceCode: code,
updateAndWriteManifest: options.writeManifest,
});
const errorsUnfixed = reports
.filter((report) => report.severity === 'error' && !report.wasFixed)
.map((report) => report.message);
const warnings = reports
.filter((report) => report.severity === 'warning' && !report.wasFixed)
.map((report) => report.message);
const fixed = reports
.filter((report) => report.wasFixed)
.map((report) => report.message);
if (errorsUnfixed.length > 0) {
throw new Error(`Manifest Error: The manifest is invalid.\n${errorsUnfixed.join('\n')}`);
}
if (warnings.length > 0) {
(0, node_1.logWarning)('Manifest Warning: Validation of snap.manifest.json completed with warnings.');
warnings.forEach((warning) => (0, node_1.logWarning)(`Manifest Warning: ${warning}`));
}
if (fixed.length > 0) {
(0, node_1.logWarning)(`Manifest Warning: Validation of snap.manifest.json fixed following problems.`);
fixed.forEach((error) => (0, node_1.logWarning)(`Manifest Problem Fixed: ${error}`));
}
}
}
/**
* A transform stream which can be used in the Browserify pipeline. It accepts a
* string input, which is post-processed and pushed to the output stream.
*/
class SnapsBrowserifyTransform extends readable_stream_1.Transform {
/**
* Construct an instance of the transform stream.
*
* @param options - The post-processing options.
* @param options.stripComments - Whether to strip comments. Defaults to `true`.
* @param options.transformHtmlComments - Whether to transform HTML comments.
* Defaults to `true`.
*/
constructor(options = {}) {
super();
_SnapsBrowserifyTransform_data.set(this, []);
_SnapsBrowserifyTransform_options.set(this, void 0);
__classPrivateFieldSet(this, _SnapsBrowserifyTransform_options, { ...options }, "f");
}
/**
* Takes a chunk of data and pushes it into an internal array, for later
* processing.
*
* @param chunk - The chunk of data to transform.
* @param _encoding - The encoding of the chunk.
* @param callback - The callback to call when the chunk is processed.
*/
_transform(chunk, _encoding, callback) {
// Collects all the chunks into an array.
__classPrivateFieldGet(this, _SnapsBrowserifyTransform_data, "f").push(chunk);
callback();
}
/**
* Takes the internal array of chunks and processes them. The processed code
* is pushed to the output stream.
*
* @param callback - The callback to call when the stream is finished.
*/
_flush(callback) {
// Merges all the chunks into a single string and processes it.
const code = Buffer.concat(__classPrivateFieldGet(this, _SnapsBrowserifyTransform_data, "f")).toString('utf-8');
// Browserify uses inline source maps, so we attempt to read it here, and
// convert it to an object.
const inputSourceMap = (0, convert_source_map_1.fromSource)(code)?.toObject() ?? undefined;
const result = (0, node_1.postProcessBundle)(code, {
...__classPrivateFieldGet(this, _SnapsBrowserifyTransform_options, "f"),
sourceMap: Boolean(inputSourceMap) && 'inline',
inputSourceMap,
});
if (result.warnings.length > 0) {
(0, node_1.logWarning)(`Bundle Warning: Processing of the Snap bundle completed with warnings.\n${result.warnings.join('\n')}`);
}
postBundle(__classPrivateFieldGet(this, _SnapsBrowserifyTransform_options, "f"), result.code)
.catch((error) => {
callback(error);
})
.finally(() => {
this.push(result.code);
callback();
});
}
}
exports.SnapsBrowserifyTransform = SnapsBrowserifyTransform;
_SnapsBrowserifyTransform_data = new WeakMap(), _SnapsBrowserifyTransform_options = new WeakMap();
/**
* The Browserify plugin function. Can be passed to the Browserify `plugin`
* function, or used by simply passing the package name to `plugin`.
*
* @param browserifyInstance - The Browserify instance.
* @param options - The plugin options.
* @param options.stripComments - Whether to strip comments. Defaults to `true`.
* @param options.eval - Whether to evaluate the bundle to test SES
* compatibility. Defaults to `true`.
* @param options.manifestPath - The path to the manifest file. If provided,
* the manifest will be validated. Defaults to
* `process.cwd() + '/snap.manifest.json'`.
* @param options.writeManifest - Whether to fix the manifest.
* Defaults to `true`.
*/
function plugin(browserifyInstance, options) {
const defaultOptions = {
eval: true,
manifestPath: path_1.default.join(process.cwd(), 'snap.manifest.json'),
writeManifest: true,
...options,
};
// Pushes the transform stream at the end of Browserify's pipeline. This
// ensures that the transform is run on the entire bundle.
browserifyInstance.pipeline.push(new SnapsBrowserifyTransform(defaultOptions));
}
exports.default = plugin;
//# sourceMappingURL=plugin.cjs.map