@storm-software/workspace-tools
Version:
Tools for managing a Storm workspace, including various Nx generators and executors for common development tasks.
365 lines (358 loc) • 11.4 kB
JavaScript
import {
DEFAULT_TARGET,
addPackageDependencies,
addPackageJsonExport,
addWorkspacePackageJsonFields,
copyAssets,
getEnv
} from "./chunk-I4X5CIJM.mjs";
import {
withRunExecutor
} from "./chunk-EYZGKQNH.mjs";
import {
getWorkspaceConfig
} from "./chunk-4PKTZSV2.mjs";
import {
brandIcon,
getStopwatch,
writeDebug,
writeFatal,
writeInfo,
writeSuccess,
writeWarning
} from "./chunk-MMA4S6LZ.mjs";
import {
findWorkspaceRoot
} from "./chunk-3J2CP54B.mjs";
import {
joinPaths
} from "./chunk-TBW5MCN6.mjs";
// ../tsdown/src/build.ts
import {
createProjectGraphAsync,
readProjectsConfigurationFromProjectGraph,
writeJsonFile
} from "@nx/devkit";
import defu from "defu";
import { existsSync } from "node:fs";
import hf from "node:fs/promises";
import { build as tsdown } from "tsdown";
// ../tsdown/src/clean.ts
import { rm } from "node:fs/promises";
async function cleanDirectories(name = "TSDown", directory, config) {
await rm(directory, { recursive: true, force: true });
}
// ../tsdown/src/config.ts
function getDefaultOptions(config) {
return {
entry: ["./src/*.ts"],
platform: "node",
target: "esnext",
mode: "production",
dts: true,
unused: {
level: "error",
ignore: ["typescript"]
},
publint: true,
fixedExtension: true,
...config
};
}
function toTSDownFormat(format) {
if (!format || Array.isArray(format) && format.length === 0) {
return ["cjs", "es"];
} else if (format === "esm") {
return "es";
} else if (Array.isArray(format)) {
return format.map((f) => f === "esm" ? "es" : f);
}
return format;
}
// ../tsdown/src/build.ts
var resolveOptions = async (userOptions) => {
const options = getDefaultOptions(userOptions);
const workspaceRoot = findWorkspaceRoot(options.projectRoot);
if (!workspaceRoot) {
throw new Error("Cannot find Nx workspace root");
}
const workspaceConfig = await getWorkspaceConfig(options.debug === true, {
workspaceRoot
});
writeDebug(" \u2699\uFE0F Resolving build options", workspaceConfig);
const stopwatch = getStopwatch("Build options resolution");
const projectGraph = await createProjectGraphAsync({
exitOnError: true
});
const projectJsonPath = joinPaths(
workspaceRoot,
options.projectRoot,
"project.json"
);
if (!existsSync(projectJsonPath)) {
throw new Error("Cannot find project.json configuration");
}
const projectJsonFile = await hf.readFile(projectJsonPath, "utf8");
const projectJson = JSON.parse(projectJsonFile);
const projectName = projectJson.name;
const projectConfigurations = readProjectsConfigurationFromProjectGraph(projectGraph);
if (!projectConfigurations?.projects?.[projectName]) {
throw new Error(
"The Build process failed because the project does not have a valid configuration in the project.json file. Check if the file exists in the root of the project."
);
}
const packageJsonPath = joinPaths(
workspaceRoot,
options.projectRoot,
"package.json"
);
if (!existsSync(packageJsonPath)) {
throw new Error("Cannot find package.json configuration");
}
const debug = options.debug ?? (options.mode || workspaceConfig.mode) === "development";
const sourceRoot = projectJson.sourceRoot || joinPaths(options.projectRoot, "src");
const result = {
name: projectName,
mode: "production",
target: DEFAULT_TARGET,
generatePackageJson: true,
outDir: joinPaths("dist", options.projectRoot),
minify: !debug,
plugins: [],
assets: [],
dts: true,
shims: true,
silent: !debug,
logLevel: workspaceConfig.logLevel === "success" || workspaceConfig.logLevel === "performance" || workspaceConfig.logLevel === "debug" || workspaceConfig.logLevel === "trace" || workspaceConfig.logLevel === "all" ? "info" : workspaceConfig.logLevel === "fatal" ? "error" : workspaceConfig.logLevel,
sourcemap: debug ? "inline" : false,
clean: false,
fixedExtension: true,
nodeProtocol: true,
tsconfig: joinPaths(options.projectRoot, "tsconfig.json"),
debug,
sourceRoot,
cwd: workspaceConfig.workspaceRoot,
entry: {
["index"]: joinPaths(sourceRoot, "index.ts")
},
workspace: true,
...options,
treeshake: options.treeShaking !== false,
format: toTSDownFormat(options.format),
workspaceConfig,
projectName,
projectGraph,
projectConfigurations
};
result.env = defu(
options.env,
getEnv("tsdown", result)
);
stopwatch();
return result;
};
async function generatePackageJson(options) {
if (options.generatePackageJson !== false && existsSync(joinPaths(options.projectRoot, "package.json"))) {
writeDebug(" \u270D\uFE0F Writing package.json file", options.workspaceConfig);
const stopwatch = getStopwatch("Write package.json file");
const packageJsonPath = joinPaths(options.projectRoot, "project.json");
if (!existsSync(packageJsonPath)) {
throw new Error("Cannot find package.json configuration");
}
const packageJsonFile = await hf.readFile(
joinPaths(
options.workspaceConfig.workspaceRoot,
options.projectRoot,
"package.json"
),
"utf8"
);
if (!packageJsonFile) {
throw new Error("Cannot find package.json configuration file");
}
let packageJson = JSON.parse(packageJsonFile);
packageJson = await addPackageDependencies(
options.workspaceConfig.workspaceRoot,
options.projectRoot,
options.projectName,
packageJson
);
packageJson = await addWorkspacePackageJsonFields(
options.workspaceConfig,
options.projectRoot,
options.sourceRoot,
options.projectName,
false,
packageJson
);
packageJson.exports ??= {};
packageJson.exports["./package.json"] ??= "./package.json";
packageJson.exports["."] ??= addPackageJsonExport(
"index",
packageJson.type,
options.sourceRoot
);
let entry = [{ in: "./src/index.ts", out: "./src/index.ts" }];
if (options.entry) {
if (Array.isArray(options.entry)) {
entry = options.entry.map(
(entryPoint) => typeof entryPoint === "string" ? { in: entryPoint, out: entryPoint } : entryPoint
);
}
for (const entryPoint of entry) {
const split = entryPoint.out.split(".");
split.pop();
const entry2 = split.join(".").replaceAll("\\", "/");
packageJson.exports[`./${entry2}`] ??= addPackageJsonExport(
entry2,
options.fixedExtension ? "fixed" : packageJson.type,
options.sourceRoot
);
}
}
packageJson.main = !options.fixedExtension && packageJson.type === "commonjs" ? "./dist/index.js" : "./dist/index.cjs";
packageJson.module = !options.fixedExtension && packageJson.type === "module" ? "./dist/index.js" : "./dist/index.mjs";
packageJson.types = `./dist/index.d.${!options.fixedExtension ? "ts" : "mts"}`;
packageJson.exports = Object.keys(packageJson.exports).reduce(
(ret, key) => {
if (key.endsWith("/index") && !ret[key.replace("/index", "")]) {
ret[key.replace("/index", "")] = packageJson.exports[key];
}
return ret;
},
packageJson.exports
);
await writeJsonFile(joinPaths(options.outDir, "package.json"), packageJson);
stopwatch();
}
return options;
}
async function executeTSDown(options) {
writeDebug(` \u{1F680} Running ${options.name} build`, options.workspaceConfig);
const stopwatch = getStopwatch(`${options.name} build`);
await tsdown({
...options,
entry: options.entry,
config: false
});
stopwatch();
return options;
}
async function copyBuildAssets(options) {
writeDebug(
` \u{1F4CB} Copying asset files to output directory: ${options.outDir}`,
options.workspaceConfig
);
const stopwatch = getStopwatch(`${options.name} asset copy`);
await copyAssets(
options.workspaceConfig,
options.assets ?? [],
options.outDir,
options.projectRoot,
options.sourceRoot,
true,
false
);
stopwatch();
return options;
}
async function reportResults(options) {
writeSuccess(
` \u{1F4E6} The ${options.name} build completed successfully`,
options.workspaceConfig
);
}
async function cleanOutputPath(options) {
if (options.clean !== false && options.workspaceConfig) {
writeDebug(
` \u{1F9F9} Cleaning ${options.name} output path: ${options.workspaceConfig}`,
options.workspaceConfig
);
const stopwatch = getStopwatch(`${options.name} output clean`);
await cleanDirectories(
options.name,
options.outDir,
options.workspaceConfig
);
stopwatch();
}
return options;
}
async function build(options) {
writeDebug(` ${brandIcon()} Executing Storm TSDown pipeline`);
const stopwatch = getStopwatch("TSDown pipeline");
try {
const opts = Array.isArray(options) ? options : [options];
if (opts.length === 0) {
throw new Error("No build options were provided");
}
const resolved = await Promise.all(
opts.map(async (opt) => await resolveOptions(opt))
);
if (resolved.length > 0) {
await cleanOutputPath(resolved[0]);
await generatePackageJson(resolved[0]);
await Promise.all(
resolved.map(async (opt) => {
await executeTSDown(opt);
await copyBuildAssets(opt);
await reportResults(opt);
})
);
} else {
writeWarning(
" \u{1F6A7} No options were passed to TSBuild. Please check the parameters passed to the `build` function."
);
}
writeSuccess(" \u{1F3C1} TSDown pipeline build completed successfully");
} catch (error) {
writeFatal(
"Fatal errors that the build process could not recover from have occured. The build process has been terminated."
);
throw error;
} finally {
stopwatch();
}
}
// src/executors/tsdown/executor.ts
async function tsdownExecutorFn(options, context, config) {
writeInfo("\u{1F4E6} Running Storm TSDown executor on the workspace", config);
if (!context.projectsConfigurations?.projects || !context.projectName || !context.projectsConfigurations.projects[context.projectName] || !context.projectsConfigurations.projects[context.projectName]?.root) {
throw new Error(
"The Build process failed because the context is not valid. Please run this command from a workspace."
);
}
await build({
...options,
projectRoot: (
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
context.projectsConfigurations.projects?.[context.projectName].root
),
name: context.projectName,
sourceRoot: context.projectsConfigurations.projects?.[context.projectName]?.sourceRoot,
format: options.format,
platform: options.platform
});
return {
success: true
};
}
var executor_default = withRunExecutor(
"Storm TSDown build",
tsdownExecutorFn,
{
skipReadingConfig: false,
hooks: {
applyDefaultOptions: async (options) => {
options.entry ??= ["src/index.ts"];
options.outputPath ??= "dist/{projectRoot}";
options.tsconfig ??= "{projectRoot}/tsconfig.json";
return options;
}
}
}
);
export {
tsdownExecutorFn,
executor_default
};