UNPKG

@chialab/esbuild-rna

Version:

A framework for esbuild plugins with transform and emit capabilities.

150 lines (137 loc) 4.46 kB
import { Buffer } from 'node:buffer'; import crypto from 'node:crypto'; import path from 'node:path'; /** * Create an empty metafile object. * @returns {import('esbuild').Metafile} */ export function createEmptyMetafile() { return { inputs: {}, outputs: {} }; } /** * Create an hash for the given buffer. * @param {Buffer|Uint8Array|string} buffer The buffer input. * @returns A buffer hash. */ export function createFileHash(buffer) { const hash = crypto.createHash('sha1'); hash.update(Buffer.from(buffer)); return hash.digest('hex').substring(0, 8); } /** * @param {string} path * @param {Buffer} contents * @returns {import('esbuild').OutputFile} */ export function createOutputFile(path, contents) { return { path, contents, hash: createFileHash(contents), get text() { return contents.toString(); }, }; } /** * @param {import('esbuild').OutputFile[]} [outputFiles] * @param {import('esbuild').Metafile} [metafile] * @returns {import('./Build.js').Result} */ export function createResult(outputFiles, metafile = createEmptyMetafile()) { return { errors: [], warnings: [], dependencies: {}, outputFiles, metafile, mangleCache: {}, }; } /** * Merge esbuild results into a single object * that collects all inputs and outputs references, errors and warnings. * This is useful when running multiple builds in separated process. * @param {import('./Build.js').Result} context * @param {import('esbuild').BuildResult & { dependencies?: Record<string, string[]> }} result */ export function assignToResult(context, result) { context.errors.push(...result.errors); context.warnings.push(...result.warnings); if (context.outputFiles || result.outputFiles) { context.outputFiles = context.outputFiles || []; context.outputFiles.push(...(result.outputFiles || [])); } const contextMeta = context.metafile || createEmptyMetafile(); const resultMeta = result.metafile || createEmptyMetafile(); context.metafile = contextMeta; contextMeta.inputs = { ...contextMeta.inputs, ...resultMeta.inputs, }; contextMeta.outputs = { ...contextMeta.outputs, ...resultMeta.outputs, }; /** * @type {Record<string, string[]>} */ const dependencies = context.dependencies || {}; context.dependencies = dependencies; if (typeof result.dependencies === 'object') { for (const out of Object.entries(result.dependencies)) { const entryPoint = out[0]; const list = dependencies[entryPoint] || []; dependencies[entryPoint] = list; out[1].forEach((dep) => { if (!list.includes(dep)) { list.push(dep); } }); } } } /** * @param {import('./Build.js').Result} result * @param {string} from * @param {string} to * @returns {import('./Build.js').Result} */ export function remapResult(result, from, to) { const resultMeta = result.metafile || createEmptyMetafile(); const inputs = resultMeta.inputs; const outputs = resultMeta.outputs; return { errors: result.errors, warnings: result.warnings, outputFiles: result.outputFiles, dependencies: result.dependencies, metafile: { inputs: Object.keys(inputs).reduce( (acc, input) => { const newPath = path.relative(to, path.resolve(from, input)); acc[newPath] = inputs[input]; return acc; }, /** @type {import('esbuild').Metafile['inputs']} */ ({}) ), outputs: Object.keys(outputs).reduce( (acc, output) => { const newPath = path.relative(to, path.resolve(from, output)); acc[newPath] = outputs[output]; return acc; }, /** @type {import('esbuild').Metafile['outputs']} */ ({}) ), }, mangleCache: result.mangleCache, }; } /** * Check if a plugin is already part of the list. * @param {import('esbuild').Plugin[]} plugins The plugins list. * @param {string} name The of the plugin to check. */ export function hasPlugin(plugins, name) { return plugins.some((plg) => plg.name === name); }