@storm-stack/core
Version:
A build toolkit and runtime used by Storm Software in TypeScript applications
203 lines (200 loc) • 8.61 kB
JavaScript
import { restoreVfs, createVfs, __VFS_VIRTUAL__ } from './chunk-4PZQYL6T.js';
import { resolveConfig } from './chunk-3SXIWFA7.js';
import { getParsedTypeScriptConfig } from './chunk-F3VGKNLX.js';
import { createLog } from './chunk-OKGWWQFP.js';
import { createResolver } from './chunk-XFWES7LF.js';
import { __name } from './chunk-IRPJW6HH.js';
import { LogLevelLabel } from '@storm-software/config-tools/types';
import { getEnvPaths } from '@stryke/env/get-env-paths';
import { existsSync } from '@stryke/fs/exists';
import { getWorkspaceRoot, getProjectRoot, relativeToWorkspaceRoot } from '@stryke/fs/get-workspace-root';
import { readJsonFile } from '@stryke/fs/json';
import { listFiles } from '@stryke/fs/list-files';
import { removeFile } from '@stryke/fs/remove-file';
import { resolvePackage } from '@stryke/fs/resolve';
import { hash } from '@stryke/hash/hash';
import { hashDirectory } from '@stryke/hash/hash-files';
import { getUnique } from '@stryke/helpers/get-unique';
import { hasFileExtension } from '@stryke/path/file-path-fns';
import { joinPaths } from '@stryke/path/join-paths';
import { kebabCase } from '@stryke/string-format/kebab-case';
import { uuid } from '@stryke/unique-id/uuid';
import defu from 'defu';
var PROJECT_ROOT_HASH_LENGTH = 45;
function getPrefixedProjectRootHash(name, projectRootHash) {
const combined = `${kebabCase(name)}_${projectRootHash}`;
return combined.length > PROJECT_ROOT_HASH_LENGTH ? combined.slice(0, PROJECT_ROOT_HASH_LENGTH) : combined;
}
__name(getPrefixedProjectRootHash, "getPrefixedProjectRootHash");
async function discoverTemplatePath(path) {
return (await Promise.all([
Promise.resolve(/.tsx?$/.test(path) && !path.includes("*") && path),
Promise.resolve(!hasFileExtension(path) && joinPaths(path, ".ts")),
Promise.resolve(!hasFileExtension(path) && joinPaths(path, ".tsx")),
Promise.resolve(!hasFileExtension(path) && listFiles(joinPaths(path, "**/*.ts"))),
Promise.resolve(!hasFileExtension(path) && listFiles(joinPaths(path, "**/*.tsx")))
])).flat().filter(Boolean);
}
__name(discoverTemplatePath, "discoverTemplatePath");
async function discoverTemplates(context, paths = []) {
return getUnique((await Promise.all([
...paths.map(discoverTemplatePath),
discoverTemplatePath(joinPaths(context.options.sourceRoot, "plugin")),
discoverTemplatePath(joinPaths(context.envPaths.config, "templates")),
discoverTemplatePath(joinPaths(context.options.projectRoot, "templates"))
])).flat().reduce((ret, path) => {
if (existsSync(path)) {
ret.push(path);
}
return ret;
}, []));
}
__name(discoverTemplates, "discoverTemplates");
async function getChecksum(path) {
return hashDirectory(path, {
ignore: [
"node_modules",
".git",
".nx",
".cache",
".storm",
"tmp",
"dist"
]
});
}
__name(getChecksum, "getChecksum");
async function getPersistedMeta(context) {
const metaFilePath = joinPaths(context.dataPath, "meta.json");
if (existsSync(metaFilePath)) {
try {
return await readJsonFile(metaFilePath);
} catch {
context.log(LogLevelLabel.WARN, `Failed to read meta file at ${metaFilePath}. It may be corrupted.`);
await removeFile(metaFilePath);
context.persistedMeta = void 0;
}
}
return void 0;
}
__name(getPersistedMeta, "getPersistedMeta");
async function createContext(inlineConfig, workspaceConfig, options = {}) {
const workspaceRoot = workspaceConfig?.workspaceRoot ?? getWorkspaceRoot();
const projectRoot = (inlineConfig.root ?? getProjectRoot()) || process.cwd();
const resolvedWorkspaceConfig = defu(workspaceConfig, {
workspaceRoot
});
let projectJson;
const projectJsonPath = joinPaths(projectRoot, "project.json");
if (existsSync(projectJsonPath)) {
projectJson = await readJsonFile(projectJsonPath);
}
let packageJson;
const packageJsonPath = joinPaths(projectRoot, "package.json");
if (existsSync(packageJsonPath)) {
packageJson = await readJsonFile(packageJsonPath);
} else if (inlineConfig.command === "new") {
const workspacePackageJsonPath = joinPaths(workspaceRoot, "package.json");
packageJson = await readJsonFile(workspacePackageJsonPath);
resolvedWorkspaceConfig.repository ??= typeof packageJson?.repository === "string" ? packageJson.repository : packageJson?.repository?.url;
} else {
throw new Error(`The package.json file is missing in the project root directory: ${projectRoot}. Please run the "new" command to create a new Storm Stack project.`);
}
const checksum = await getChecksum(projectRoot);
const meta = {
buildId: uuid(),
releaseId: uuid(),
checksum,
timestamp: Date.now(),
projectRootHash: hash(joinPaths(workspaceRoot, projectRoot), {
maxLength: PROJECT_ROOT_HASH_LENGTH
}),
runtimeIdMap: {},
virtualFiles: {}
};
const artifactsPath = joinPaths(workspaceRoot, projectRoot, ".storm");
const runtimePath = joinPaths(artifactsPath, "runtime");
const entryPath = joinPaths(artifactsPath, "entry");
const envPaths = getEnvPaths({
orgId: "storm-software",
appId: "storm-stack",
workspaceRoot
});
if (!envPaths.cache) {
throw new Error("The cache directory could not be determined.");
}
envPaths.cache = joinPaths(envPaths.cache, "projects", meta.projectRootHash);
const partiallyResolvedContext = {
options: {
...resolvedWorkspaceConfig,
name: projectJson?.name || options.name,
...inlineConfig,
userConfig: {
config: {}
},
inlineConfig,
projectRoot,
workspaceConfig: resolvedWorkspaceConfig,
plugins: {}
},
log: createLog(options.name ?? null, defu(inlineConfig, resolvedWorkspaceConfig)),
meta,
entry: [],
envPaths,
artifactsPath,
runtimePath,
entryPath,
dtsPath: joinPaths(envPaths.cache, "dts"),
runtimeDtsFilePath: joinPaths(projectRoot, "storm.d.ts"),
dataPath: joinPaths(envPaths.data, "projects", meta.projectRootHash),
cachePath: envPaths.cache,
projectJson,
packageJson,
runtime: {
logs: [],
storage: [],
init: []
},
packageDeps: {},
reflections: {},
resolver: createResolver({
workspaceRoot,
projectRoot,
cacheDir: envPaths.cache
}),
relativeToWorkspaceRoot: relativeToWorkspaceRoot(projectRoot)
};
const resolvedOptions = await resolveConfig(partiallyResolvedContext, inlineConfig, void 0, projectRoot);
const context = partiallyResolvedContext;
context.options = resolvedOptions;
context.dataPath = joinPaths(context.envPaths.data, "projects", getPrefixedProjectRootHash(context.options.name, context.meta.projectRootHash));
context.persistedMeta = await getPersistedMeta(context);
context.runtimeDtsFilePath = context.options.output.dts ? context.options.output.dts.startsWith(context.options.workspaceRoot) ? context.options.output.dts : joinPaths(context.options.workspaceRoot, context.options.output.dts) : joinPaths(context.options.workspaceRoot, context.options.projectRoot, "storm.d.ts");
context.tsconfig = getParsedTypeScriptConfig(context.options.workspaceRoot, context.options.projectRoot, context.options.tsconfig);
if (context.persistedMeta?.checksum === context.meta.checksum) {
context.log(LogLevelLabel.TRACE, `Restoring the virtual file system (VFS) as the meta checksum has not changed.`);
context.vfs = restoreVfs(context, {
runtimeIdMap: context.persistedMeta.runtimeIdMap,
virtualFiles: context.persistedMeta.virtualFiles
});
} else {
context.vfs = createVfs(context);
}
const packagePath = process.env.STORM_STACK_LOCAL ? joinPaths(context.options.workspaceRoot, "dist/packages/core") : await resolvePackage("@storm-stack/core");
if (!packagePath) {
throw new Error("Could not resolve the Storm Stack core package. Please ensure it is installed.");
}
return context;
}
__name(createContext, "createContext");
async function writeMetaFile(context) {
const metaFilePath = joinPaths(context.dataPath, "meta.json");
context.log(LogLevelLabel.DEBUG, `Writing runtime metadata to ${metaFilePath}`);
await context.vfs.writeFileToDisk(metaFilePath, JSON.stringify({
...context.meta,
runtimeIdMap: Object.fromEntries(context.vfs.runtimeIdMap.entries()),
virtualFiles: context.vfs[__VFS_VIRTUAL__].toJSON(context.artifactsPath)
}, null, 2));
}
__name(writeMetaFile, "writeMetaFile");
export { PROJECT_ROOT_HASH_LENGTH, createContext, discoverTemplates, getChecksum, getPersistedMeta, getPrefixedProjectRootHash, writeMetaFile };