{"version":3,"file":"plugin.cjs","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PostProcessOptions } from '@metamask/snaps-utils/node';\nimport {\n  checkManifest,\n  evalBundle,\n  logWarning,\n  postProcessBundle,\n  useTemporaryFile,\n} from '@metamask/snaps-utils/node';\nimport type { BrowserifyObject } from 'browserify';\nimport { fromSource } from 'convert-source-map';\nimport pathUtils from 'path';\nimport type { TransformCallback } from 'readable-stream';\nimport { Transform } from 'readable-stream';\n\ntype PluginOptions = {\n  eval?: boolean;\n  manifestPath?: string;\n  writeManifest?: boolean;\n};\n\nexport type Options = PluginOptions &\n  Omit<PostProcessOptions, 'sourceMap' | 'inputSourceMap'>;\n\n/**\n * Run eval on the processed bundle and fix the manifest, if configured.\n *\n * @param options - The plugin options.\n * @param code - The code to eval, if the eval option is enabled.\n */\nasync function postBundle(options: Partial<Options>, code: string) {\n  if (options.eval) {\n    await useTemporaryFile('snaps-bundle.js', code, (path) => evalBundle(path));\n  }\n\n  if (options.manifestPath) {\n    const { reports } = await checkManifest(\n      pathUtils.dirname(options.manifestPath),\n      {\n        sourceCode: code,\n        updateAndWriteManifest: options.writeManifest,\n      },\n    );\n\n    const errorsUnfixed = reports\n      .filter((report) => report.severity === 'error' && !report.wasFixed)\n      .map((report) => report.message);\n    const warnings = reports\n      .filter((report) => report.severity === 'warning' && !report.wasFixed)\n      .map((report) => report.message);\n    const fixed = reports\n      .filter((report) => report.wasFixed)\n      .map((report) => report.message);\n\n    if (errorsUnfixed.length > 0) {\n      throw new Error(\n        `Manifest Error: The manifest is invalid.\\n${errorsUnfixed.join('\\n')}`,\n      );\n    }\n\n    if (warnings.length > 0) {\n      logWarning(\n        'Manifest Warning: Validation of snap.manifest.json completed with warnings.',\n      );\n\n      warnings.forEach((warning) => logWarning(`Manifest Warning: ${warning}`));\n    }\n\n    if (fixed.length > 0) {\n      logWarning(\n        `Manifest Warning: Validation of snap.manifest.json fixed following problems.`,\n      );\n\n      fixed.forEach((error) => logWarning(`Manifest Problem Fixed: ${error}`));\n    }\n  }\n}\n\n/**\n * A transform stream which can be used in the Browserify pipeline. It accepts a\n * string input, which is post-processed and pushed to the output stream.\n */\nexport class SnapsBrowserifyTransform extends Transform {\n  readonly #data: Buffer[] = [];\n\n  readonly #options: Partial<Options>;\n\n  /**\n   * Construct an instance of the transform stream.\n   *\n   * @param options - The post-processing options.\n   * @param options.stripComments - Whether to strip comments. Defaults to `true`.\n   * @param options.transformHtmlComments - Whether to transform HTML comments.\n   * Defaults to `true`.\n   */\n  constructor(options: Partial<Options> = {}) {\n    super();\n    this.#options = { ...options };\n  }\n\n  /**\n   * Takes a chunk of data and pushes it into an internal array, for later\n   * processing.\n   *\n   * @param chunk - The chunk of data to transform.\n   * @param _encoding - The encoding of the chunk.\n   * @param callback - The callback to call when the chunk is processed.\n   */\n  _transform(\n    chunk: Buffer,\n    _encoding: BufferEncoding,\n    callback: TransformCallback,\n  ) {\n    // Collects all the chunks into an array.\n    this.#data.push(chunk);\n    callback();\n  }\n\n  /**\n   * Takes the internal array of chunks and processes them. The processed code\n   * is pushed to the output stream.\n   *\n   * @param callback - The callback to call when the stream is finished.\n   */\n  _flush(callback: TransformCallback) {\n    // Merges all the chunks into a single string and processes it.\n    const code = Buffer.concat(this.#data).toString('utf-8');\n\n    // Browserify uses inline source maps, so we attempt to read it here, and\n    // convert it to an object.\n    const inputSourceMap = fromSource(code)?.toObject() ?? undefined;\n\n    const result = postProcessBundle(code, {\n      ...this.#options,\n      sourceMap: Boolean(inputSourceMap) && 'inline',\n      inputSourceMap,\n    });\n\n    if (result.warnings.length > 0) {\n      logWarning(\n        `Bundle Warning: Processing of the Snap bundle completed with warnings.\\n${result.warnings.join(\n          '\\n',\n        )}`,\n      );\n    }\n\n    postBundle(this.#options, result.code)\n      .catch((error) => {\n        callback(error);\n      })\n      .finally(() => {\n        this.push(result.code);\n        callback();\n      });\n  }\n}\n\n/**\n * The Browserify plugin function. Can be passed to the Browserify `plugin`\n * function, or used by simply passing the package name to `plugin`.\n *\n * @param browserifyInstance - The Browserify instance.\n * @param options - The plugin options.\n * @param options.stripComments - Whether to strip comments. Defaults to `true`.\n * @param options.eval - Whether to evaluate the bundle to test SES\n * compatibility. Defaults to `true`.\n * @param options.manifestPath - The path to the manifest file. If provided,\n * the manifest will be validated. Defaults to\n * `process.cwd() + '/snap.manifest.json'`.\n * @param options.writeManifest - Whether to fix the manifest.\n * Defaults to `true`.\n */\nexport default function plugin(\n  browserifyInstance: BrowserifyObject,\n  options?: Partial<Options>,\n): void {\n  const defaultOptions = {\n    eval: true,\n    manifestPath: pathUtils.join(process.cwd(), 'snap.manifest.json'),\n    writeManifest: true,\n    ...options,\n  };\n\n  // Pushes the transform stream at the end of Browserify's pipeline. This\n  // ensures that the transform is run on the entire bundle.\n  browserifyInstance.pipeline.push(\n    new SnapsBrowserifyTransform(defaultOptions),\n  );\n}\n"]}