@pact-toolbox/unplugin
Version:
224 lines (222 loc) • 7.52 kB
JavaScript
import { PLUGIN_NAME, createPactToolboxNetwork, prettyPrintError } from "./utils-caVmxe1_.js";
import { ParsingError, createPactToJSTransformer } from "./pactToJS-p3Xxm_Ew.js";
import { getNetworkConfig, getSerializableNetworkConfig, isLocalNetwork, resolveConfig } from "@pact-toolbox/config";
import { PactToolboxClient } from "@pact-toolbox/runtime";
import { spinner, writeFile } from "@pact-toolbox/utils";
import { createUnplugin } from "unplugin";
import path from "node:path";
//#region src/plugin/factory.ts
/**
* Factory function to create the Vite plugin.
* @param options Plugin options including transformation hooks.
* @returns An instance of the Unplugin.
*/
const unpluginFactory = (options = {}) => {
const { startNetwork = true } = options;
const cache = /* @__PURE__ */ new Map();
const toolboxConfigPromise = resolveConfig();
let resolvedConfig;
let networkConfig;
let client = options.client;
let network = null;
let isTest = process.env.NODE_ENV === "test";
let isServe = false;
const deploySpinner = spinner({ indicator: "dots" });
const transformPactToJS = createPactToJSTransformer();
/**
* Asynchronous function to handle server configuration.
*/
const configureServer = async () => {
try {
resolvedConfig = await toolboxConfigPromise;
networkConfig = getNetworkConfig(resolvedConfig);
client = new PactToolboxClient(resolvedConfig);
if (startNetwork) {
const { network: networkInstance, client: networkClient } = await createPactToolboxNetwork({
isServe,
isTest,
client,
networkConfig
}, resolvedConfig, options);
network = networkInstance;
client = networkClient;
}
} catch (error) {
console.error("Error during server configuration:", error);
}
};
/**
* Asynchronous function to handle configuration resolution.
* @param config Vite resolved configuration.
*/
const onConfig = async (config, { command }) => {
try {
resolvedConfig = await toolboxConfigPromise;
isTest = command === "test" || isTest;
isServe = command === "serve";
if (!isTest) {
const serializableNetworkConfig = getSerializableNetworkConfig(resolvedConfig);
config.define = config.define || {};
config.define["globalThis.__PACT_TOOLBOX_NETWORK_CONFIG__"] = JSON.stringify(serializableNetworkConfig);
}
} catch (error) {
console.error("Error during config resolution:", error);
}
};
/**
* Asynchronous function to handle file transformation.
* @param src Source code of the `.pact` file.
* @param id File identifier (path).
* @returns Transformed code and source map.
*/
const transformFile = async (src, id) => {
if (!id.endsWith(".pact")) return null;
const cached = cache.get(id);
const shouldTransform = !cached || cached.src !== src;
const cleanName = path.basename(id);
if (!shouldTransform) return {
code: cached.code,
map: null
};
try {
const { code, types, modules } = transformPactToJS(src);
const isDeployed = modules.length > 0 ? (await Promise.all(modules.map((m) => client?.isContractDeployed(m.path)))).every(Boolean) : false;
cache.set(id, {
code,
types,
src,
isDeployed
});
if (isLocalNetwork(networkConfig) && network) deployContract(id, src, isDeployed).catch((error) => {
prettyPrintError(`Failed to deploy contract ${cleanName}`, error);
});
return {
code,
map: null
};
} catch (error) {
if (error instanceof ParsingError) {
console.error(`Parsing error in ${id}:`);
error.errors.forEach((err) => {
console.error(` Line ${err.line}, Column ${err.column}: ${err.message}`);
});
return null;
}
console.error(`Unexpected error during transformation of ${id}:`, error);
throw error;
}
};
/**
* Asynchronous function to handle contract deployment.
* @param id File identifier (path).
* @param src Source code of the `.pact` file.
* @param isDeployed Flag indicating if the contract is already deployed.
*/
const deployContract = async (id, src, isDeployed) => {
if (!client) {
console.error("PactToolboxClient is not initialized.");
return;
}
deploySpinner.start(`Deploying contract ${path.basename(id)}...`);
return Promise.all([writeFile(`${id}.d.ts`, cache.get(id).types), client.deployCode(src, { build: {
upgrade: isDeployed,
init: !isDeployed
} }).then(() => {
const cached = cache.get(id);
if (cached) {
cached.isDeployed = true;
cache.set(id, cached);
}
deploySpinner.stop(`Contract ${path.basename(id)} deployed successfully.`);
})]);
};
/**
* Asynchronous function to handle Rspack integration.
* @param compiler Rspack compiler instance.
*/
const configureRspack = async (compiler) => {
try {
const { DefinePlugin } = await import("@rspack/core");
resolvedConfig = await toolboxConfigPromise;
const serializableNetworkConfig = getSerializableNetworkConfig(resolvedConfig);
const definePlugin = new DefinePlugin({ "globalThis.__PACT_TOOLBOX_NETWORK_CONFIG__": JSON.stringify(serializableNetworkConfig) });
if (!client) client = new PactToolboxClient(resolvedConfig);
if (!networkConfig) networkConfig = getNetworkConfig(resolvedConfig);
definePlugin.apply(compiler);
if (compiler.options.mode === "development") {
const { network: networkInstance, client: networkClient } = await createPactToolboxNetwork({
isServe: true,
isTest: false,
client,
networkConfig
}, resolvedConfig, options);
network = networkInstance;
client = networkClient;
}
compiler.hooks.shutdown.tap(PLUGIN_NAME, async () => {
const shutdownSpinner = spinner({ indicator: "timer" });
if (network) try {
shutdownSpinner.start("Shutting down network...");
await Promise.race([network.stop(), new Promise((resolve) => setTimeout(resolve, 1e4))]);
} finally {
shutdownSpinner.stop("Network stopped!");
}
});
} catch (error) {
console.error("Error during Rspack configuration:", error);
}
};
/**
* Sets up Esbuild options for the plugin.
* @param build Esbuild build instance.
*/
const setupEsbuild = async (build) => {
try {
const serializableNetworkConfig = getSerializableNetworkConfig(await toolboxConfigPromise);
build.initialOptions.define = {
...build.initialOptions.define,
"globalThis.__PACT_TOOLBOX_NETWORK_CONFIG__": JSON.stringify(serializableNetworkConfig)
};
} catch (error) {
console.error("Error during Esbuild setup:", error);
}
};
/**
* Main plugin object created by Unplugin.
*/
return {
name: PLUGIN_NAME,
enforce: "post",
transformInclude(id) {
return id.endsWith(".pact");
},
transform: transformFile,
configureServer,
vite: {
config: onConfig,
closeBundle: async (error) => {
const shutdownSpinner = spinner({ indicator: "timer" });
if (error) console.error("Error during Vite bundle:", error);
if (network) try {
shutdownSpinner.start("Shutting down network...");
await Promise.race([network.stop(), new Promise((resolve) => setTimeout(resolve, 1e4))]);
} finally {
shutdownSpinner.stop("Network stopped!");
}
}
},
esbuild: { setup: setupEsbuild },
rspack: configureRspack
};
};
/**
* Create and export the Unplugin instance with default options.
*/
const unplugin = /* @__PURE__ */ createUnplugin(unpluginFactory);
/**
* Default export of the plugin.
*/
var factory_default = unplugin;
//#endregion
export { factory_default, unplugin, unpluginFactory };
//# sourceMappingURL=factory-BrSZXBjz.js.map