everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
768 lines (766 loc) • 29.5 kB
JavaScript
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
const require_merge = require('../merge.cjs');
const require_config = require('../config.cjs');
const require_save_config = require('../utils/save-config.cjs');
const require_cli_init = require('./init.cjs');
const require_framework_version = require('./framework-version.cjs');
const require_sync = require('./sync.cjs');
const require_shared = require('../shared.cjs');
const require_timing = require('./timing.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
let node_process = require("node:process");
node_process = require_runtime.__toESM(node_process, 1);
let _clack_prompts = require("@clack/prompts");
_clack_prompts = require_runtime.__toESM(_clack_prompts, 1);
let glob = require("glob");
//#region src/cli/upgrade.ts
const FRAMEWORK_PACKAGES = ["everything-dev", "every-plugin"];
const AUTH_CORE_PACKAGE = "@better-auth/core";
const AUTH_CORE_TRIGGER_PACKAGES = [
"better-auth",
"better-near-auth",
"@better-auth/api-key",
"@better-auth/passkey"
];
const LEGACY_UI_IMPORT_REWRITES = [
["from \"@/auth\"", "from \"@/app\""],
["from '@/auth'", "from '@/app'"],
["from \"@/lib/use-api-client\"", "from \"@/app\""],
["from '@/lib/use-api-client'", "from '@/app'"],
["from \"@/lib/api-client\"", "from \"@/app\""],
["from '@/lib/api-client'", "from '@/app'"]
];
const OBSOLETE_FILES = [
"ui/src/auth.ts",
"ui/src/auth-types.gen.ts",
"ui/src/lib/api-client.ts",
"ui/src/lib/use-api-client.ts",
"ui/src/api-contract.ts",
"ui/src/api-contract.gen.ts",
"ui/src/lib/auth-client.ts",
"ui/src/lib/session.ts",
"ui/scripts/generate-metadata.ts",
".github/dependabot.yml",
".github/templates/dependabot.yml",
".github/renovate.json",
".github/workflows/packages-release.yml",
".github/workflows/release.yml",
".github/workflows/release-sync.yml",
".github/workflows/staging.yml",
"packages/everything-dev/cli.js",
".templatekeep",
".templatesync-exclude"
];
function extractSemver(value) {
if (!value) return null;
return value.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/)?.[0] ?? null;
}
function readJsonFile(filePath) {
return JSON.parse((0, node_fs.readFileSync)(filePath, "utf-8"));
}
function readRootPackageJson(projectDir) {
return readJsonFile((0, node_path.join)(projectDir, "package.json"));
}
function readRootCatalogEntry(projectDir, packageName) {
return readRootPackageJson(projectDir).workspaces?.catalog?.[packageName];
}
function readCurrentPackageSpecifier(projectDir, packageName) {
const pkg = readRootPackageJson(projectDir);
for (const fieldName of [
"dependencies",
"devDependencies",
"peerDependencies"
]) {
const value = pkg[fieldName]?.[packageName];
if (!value) continue;
if (value === "catalog:") return readRootCatalogEntry(projectDir, packageName) ?? readInstalledVersion(projectDir, packageName);
if (value.startsWith("workspace:") || value.startsWith("file:")) return readInstalledVersion(projectDir, packageName);
return value;
}
return readRootCatalogEntry(projectDir, packageName) ?? readInstalledVersion(projectDir, packageName);
}
function setCatalogRefs(field, packageNames) {
if (!field) return false;
let modified = false;
for (const packageName of packageNames) if (setCatalogRef(field, packageName)) modified = true;
return modified;
}
function syncPackageObjectCatalogRefs(pkg, packageNames) {
let modified = false;
for (const fieldName of [
"dependencies",
"devDependencies",
"peerDependencies"
]) {
const field = pkg[fieldName];
if (setCatalogRefs(field, packageNames)) modified = true;
}
return modified;
}
function findPackageFieldWithAnyDependency(pkg, packageNames) {
for (const fieldName of [
"dependencies",
"devDependencies",
"peerDependencies"
]) {
const field = pkg[fieldName];
if (!field) continue;
if (packageNames.some((packageName) => typeof field[packageName] === "string")) return field;
}
}
function packageObjectNeedsAuthCoreCatalogRef(pkg) {
if (!findPackageFieldWithAnyDependency(pkg, AUTH_CORE_TRIGGER_PACKAGES)) return false;
for (const fieldName of [
"dependencies",
"devDependencies",
"peerDependencies"
]) if (pkg[fieldName]?.[AUTH_CORE_PACKAGE]) return false;
return true;
}
function ensureAuthCoreCatalogRef(pkg) {
if (!packageObjectNeedsAuthCoreCatalogRef(pkg)) return false;
const targetField = findPackageFieldWithAnyDependency(pkg, AUTH_CORE_TRIGGER_PACKAGES);
if (!targetField) return false;
targetField[AUTH_CORE_PACKAGE] = "catalog:";
return true;
}
function packageObjectNeedsCatalogRefs(pkg, packageNames) {
for (const fieldName of [
"dependencies",
"devDependencies",
"peerDependencies"
]) {
const field = pkg[fieldName];
if (!field) continue;
for (const packageName of packageNames) {
const value = field[packageName];
if (!value) continue;
if (value !== "catalog:" && !value.startsWith("file:")) return true;
}
}
return false;
}
function packageFileNeedsCatalogRefs(filePath, packageNames) {
return packageObjectNeedsCatalogRefs(readJsonFile(filePath), packageNames);
}
function updatePackageFileCatalogRefs(filePath, packageNames) {
const pkg = readJsonFile(filePath);
const modified = syncPackageObjectCatalogRefs(pkg, packageNames);
if (modified) (0, node_fs.writeFileSync)(filePath, `${JSON.stringify(pkg, null, 2)}\n`);
return modified;
}
function updatePackageFileAuthCoreRef(filePath) {
const pkg = readJsonFile(filePath);
const modified = ensureAuthCoreCatalogRef(pkg);
if (modified) (0, node_fs.writeFileSync)(filePath, `${JSON.stringify(pkg, null, 2)}\n`);
return modified;
}
function syncRootCatalogWithParent(projectDir, parentCatalog) {
const pkgPath = (0, node_path.join)(projectDir, "package.json");
const pkg = readJsonFile(pkgPath);
let modified = syncPackageObjectCatalogRefs(pkg, Object.keys(parentCatalog));
if (!pkg.workspaces || typeof pkg.workspaces !== "object") {
pkg.workspaces = {
packages: [],
catalog: {}
};
modified = true;
}
const workspaces = pkg.workspaces;
if (!workspaces.catalog || typeof workspaces.catalog !== "object") {
workspaces.catalog = {};
modified = true;
}
for (const [packageName, version] of Object.entries(parentCatalog)) if (workspaces.catalog[packageName] !== version) {
workspaces.catalog[packageName] = version;
modified = true;
}
if (modified) (0, node_fs.writeFileSync)(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
return modified;
}
async function readExtendedRootSource(projectDir) {
const configPath = (0, node_path.join)(projectDir, "bos.config.json");
if (!(0, node_fs.existsSync)(configPath)) return {
catalog: {},
extendsChain: []
};
const localConfig = JSON.parse((0, node_fs.readFileSync)(configPath, "utf-8"));
let extendsRef = getExtendsRef(localConfig);
if (!extendsRef?.startsWith("bos://")) return {
catalog: {},
repository: typeof localConfig.repository === "string" ? localConfig.repository : void 0,
extendsChain: []
};
const extendsChain = [];
const visited = /* @__PURE__ */ new Set();
let repository = typeof localConfig.repository === "string" ? localConfig.repository : void 0;
let rootRef = extendsRef;
while (extendsRef?.startsWith("bos://")) {
if (visited.has(extendsRef)) throw new Error(`Circular extends detected while resolving upgrade source: ${extendsRef}`);
visited.add(extendsRef);
extendsChain.push(extendsRef);
const parsed = parseBosRef(extendsRef);
if (!parsed) break;
rootRef = extendsRef;
let parentConfig;
try {
parentConfig = await require_cli_init.fetchParentConfig(parsed.account, parsed.gateway);
} catch {
break;
}
if (typeof parentConfig.repository === "string") repository = parentConfig.repository;
const nextExtendsRef = getExtendsRef(parentConfig);
if (!nextExtendsRef?.startsWith("bos://")) break;
extendsRef = nextExtendsRef;
}
const parsed = parseBosRef(rootRef);
if (!parsed) return {
catalog: {},
repository,
extendsChain
};
const source = await require_cli_init.resolveCatalogChainSource({
extendsAccount: parsed.account,
extendsGateway: parsed.gateway
});
return {
catalog: source.catalog,
repository: source.repository ?? repository,
extendsChain: source.extendsChain.length > 0 ? source.extendsChain : extendsChain
};
}
function getExtendsRef(config) {
if (typeof config.extends === "string") return config.extends;
if (config.extends && typeof config.extends === "object") return require_merge.resolveExtendsRef(config.extends, "production");
}
function parseBosRef(ref) {
const match = ref.match(/^bos:\/\/([^/]+)\/(.+)$/);
if (!match?.[1] || !match[2]) return null;
return {
account: match[1],
gateway: match[2]
};
}
function parseTargetedRef(ref) {
const hashIndex = ref.indexOf("#");
if (hashIndex === -1) return { configRef: ref };
return {
configRef: ref.slice(0, hashIndex),
targetPath: ref.slice(hashIndex + 1) || void 0
};
}
function ensureTargetedRef(ref, targetPath) {
const parsed = parseTargetedRef(ref);
if (parsed.targetPath) return ref;
return `${parsed.configRef}#${targetPath}`;
}
function rewriteExtendsTarget(entry, targetPath) {
if (!entry?.extends) return false;
if (typeof entry.extends === "string") {
const next = ensureTargetedRef(entry.extends, targetPath);
if (next === entry.extends) return false;
entry.extends = next;
return true;
}
if (typeof entry.extends === "object") {
let changed = false;
for (const [key, value] of Object.entries(entry.extends)) {
if (typeof value !== "string") continue;
const next = ensureTargetedRef(value, targetPath);
if (next !== value) {
entry.extends[key] = next;
changed = true;
}
}
return changed;
}
return false;
}
function migrateRootConfigTargets(config) {
let changed = false;
const app = config.app && typeof config.app === "object" ? config.app : void 0;
if (app?.api && typeof app.api === "object") changed = rewriteExtendsTarget(app.api, "app.api") || changed;
if (app?.auth && typeof app.auth === "object") changed = rewriteExtendsTarget(app.auth, "app.auth") || changed;
if (config.plugins && typeof config.plugins === "object") for (const [pluginKey, pluginValue] of Object.entries(config.plugins)) {
if (typeof pluginValue === "string") {
const next = ensureTargetedRef(pluginValue, `plugins.${pluginKey}`);
if (next !== pluginValue) {
config.plugins[pluginKey] = next;
changed = true;
}
continue;
}
if (!pluginValue || typeof pluginValue !== "object") continue;
changed = rewriteExtendsTarget(pluginValue, `plugins.${pluginKey}`) || changed;
}
return changed;
}
function migratePluginProviderConfig(config, pluginKey) {
let changed = false;
if (!config.plugins || typeof config.plugins !== "object") return false;
const entry = config.plugins[pluginKey];
if (!entry || typeof entry !== "object") return false;
const pluginEntry = entry;
if ("name" in pluginEntry) {
delete pluginEntry.name;
changed = true;
}
if (typeof pluginEntry.development === "string" && pluginEntry.development.startsWith("local:")) {
if ("extends" in pluginEntry) {
delete pluginEntry.extends;
changed = true;
}
}
changed = rewriteExtendsTarget(pluginEntry, `plugins.${pluginKey}`) || changed;
return changed;
}
function mergePluginConfigIntoRoot(rootConfig, pluginKey, pluginConfig) {
let changed = false;
if (!rootConfig.plugins || typeof rootConfig.plugins !== "object") {
rootConfig.plugins = {};
changed = true;
}
const plugins = rootConfig.plugins;
if (!plugins[pluginKey] || typeof plugins[pluginKey] !== "object") {
plugins[pluginKey] = {};
changed = true;
}
const entry = plugins[pluginKey];
const pluginData = extractPluginEntry(pluginConfig, pluginKey);
const apiData = getApiEntry(pluginConfig);
if (pluginData) {
for (const key of [
"secrets",
"variables",
"routes",
"sidebar",
"production",
"integrity",
"proxy"
]) if (pluginData[key] !== void 0 && entry[key] === void 0) {
entry[key] = pluginData[key];
changed = true;
}
if (typeof pluginData.development === "string" && pluginData.development.startsWith("local:")) pluginData.development = `local:plugins/${pluginKey}`;
if (entry.development === void 0 && pluginData.development !== void 0) {
entry.development = pluginData.development;
changed = true;
}
}
if (apiData) {
for (const key of [
"production",
"integrity",
"proxy",
"variables",
"secrets",
"sidebar",
"routes"
]) if (apiData[key] !== void 0 && entry[key] === void 0) {
entry[key] = apiData[key];
changed = true;
}
}
if ("extends" in entry) {
const extendsStr = typeof entry.extends === "string" ? entry.extends : void 0;
if (!extendsStr || extendsStr.includes(`#plugins.${pluginKey}`)) {
delete entry.extends;
changed = true;
}
}
if ("name" in entry) {
delete entry.name;
changed = true;
}
if (configHasTopLevelFields(pluginConfig, pluginKey)) {
if (entry.routes === void 0 && Array.isArray(pluginConfig.routes)) {
entry.routes = pluginConfig.routes;
changed = true;
}
if (entry.sidebar === void 0 && Array.isArray(pluginConfig.sidebar)) {
entry.sidebar = pluginConfig.sidebar;
changed = true;
}
const api = getApiEntry(pluginConfig);
if (api) {
if (entry.routes === void 0 && Array.isArray(api.routes)) {
entry.routes = api.routes;
changed = true;
}
if (entry.sidebar === void 0 && Array.isArray(api.sidebar)) {
entry.sidebar = api.sidebar;
changed = true;
}
}
}
return changed;
}
function extractPluginEntry(pluginConfig, pluginKey) {
if (pluginConfig.plugins && typeof pluginConfig.plugins === "object" && pluginConfig.plugins[pluginKey] && typeof pluginConfig.plugins[pluginKey] === "object") return pluginConfig.plugins[pluginKey];
const fallback = {};
if (pluginConfig.sidebar !== void 0) fallback.sidebar = pluginConfig.sidebar;
if (pluginConfig.routes !== void 0) fallback.routes = pluginConfig.routes;
if (Object.keys(fallback).length > 0) return fallback;
return null;
}
function configHasTopLevelFields(pluginConfig, _pluginKey) {
return pluginConfig.routes !== void 0 && Array.isArray(pluginConfig.routes) || pluginConfig.sidebar !== void 0 && Array.isArray(pluginConfig.sidebar) || getApiEntry(pluginConfig) !== null;
}
function getApiEntry(pluginConfig) {
if (!pluginConfig.app || typeof pluginConfig.app !== "object") return null;
const app = pluginConfig.app;
if (!app.api || typeof app.api !== "object") return null;
return app.api;
}
async function migrateBosConfigFiles(projectDir) {
const migrated = [];
const rootConfigPath = (0, node_path.join)(projectDir, "bos.config.json");
if ((0, node_fs.existsSync)(rootConfigPath)) {
const rootConfig = JSON.parse((0, node_fs.readFileSync)(rootConfigPath, "utf-8"));
let rootChanged = migrateRootConfigTargets(rootConfig);
const pluginConfigPaths = await (0, glob.glob)("plugins/*/bos.config.json", {
cwd: projectDir,
nodir: true,
dot: false,
absolute: false
});
for (const relativePath of pluginConfigPaths) {
const pluginKey = relativePath.match(/^plugins\/([^/]+)\/bos\.config\.json$/)?.[1];
if (!pluginKey) continue;
const filePath = (0, node_path.join)(projectDir, relativePath);
try {
rootChanged = mergePluginConfigIntoRoot(rootConfig, pluginKey, JSON.parse((0, node_fs.readFileSync)(filePath, "utf-8"))) || rootChanged;
} catch {}
try {
(0, node_fs.rmSync)(filePath);
migrated.push(relativePath);
} catch {}
}
if (rootConfig.plugins && typeof rootConfig.plugins === "object") for (const pluginKey of Object.keys(rootConfig.plugins)) rootChanged = migratePluginProviderConfig(rootConfig, pluginKey) || rootChanged;
if (rootChanged || migrated.length > 0) {
await require_save_config.saveBosConfig(projectDir, rootConfig);
if (!migrated.includes("bos.config.json")) migrated.push("bos.config.json");
}
}
return migrated;
}
async function loadParentPluginOptions(projectDir) {
const configPath = (0, node_path.join)(projectDir, "bos.config.json");
if (!(0, node_fs.existsSync)(configPath)) return null;
const localConfig = JSON.parse((0, node_fs.readFileSync)(configPath, "utf-8"));
const extendsRef = getExtendsRef(localConfig);
if (!extendsRef?.startsWith("bos://")) return null;
const parsed = parseBosRef(extendsRef);
if (!parsed) return null;
let parentConfig;
try {
parentConfig = await require_cli_init.fetchParentConfig(parsed.account, parsed.gateway);
} catch {
return null;
}
const parentPlugins = parentConfig.plugins && typeof parentConfig.plugins === "object" ? parentConfig.plugins : {};
const localPlugins = localConfig.plugins && typeof localConfig.plugins === "object" ? localConfig.plugins : {};
return {
localConfig,
parentPlugins,
newPluginKeys: Object.keys(parentPlugins).filter((key) => !(key in localPlugins))
};
}
async function addSelectedParentPlugins(projectDir) {
if (!node_process.default.stdin.isTTY || !node_process.default.stdout.isTTY) return [];
const pluginOptions = await loadParentPluginOptions(projectDir);
if (!pluginOptions || pluginOptions.newPluginKeys.length === 0) return [];
const selectedValue = await _clack_prompts.multiselect({
message: "Select new plugins from parent:",
options: pluginOptions.newPluginKeys.map((key) => ({
value: key,
label: key
})),
required: false
});
if (_clack_prompts.isCancel(selectedValue)) node_process.default.exit(0);
const selected = selectedValue;
if (selected.length === 0) return [];
const nextPlugins = { ...pluginOptions.localConfig.plugins && typeof pluginOptions.localConfig.plugins === "object" ? pluginOptions.localConfig.plugins : {} };
for (const key of selected) {
const parentPlugin = pluginOptions.parentPlugins[key];
if (parentPlugin && typeof parentPlugin === "object") {
const nextPlugin = structuredClone(parentPlugin);
rewriteExtendsTarget(nextPlugin, `plugins.${key}`);
nextPlugins[key] = nextPlugin;
} else if (typeof parentPlugin === "string") nextPlugins[key] = ensureTargetedRef(parentPlugin, `plugins.${key}`);
else nextPlugins[key] = parentPlugin;
}
pluginOptions.localConfig.plugins = nextPlugins;
await require_save_config.saveBosConfig(projectDir, pluginOptions.localConfig);
return selected;
}
function readInstalledVersion(projectDir, packageName) {
return require_framework_version.readInstalledFrameworkVersion(projectDir, packageName);
}
function setCatalogRef(field, packageName) {
if (!field || !(packageName in field)) return false;
if (field[packageName] === "catalog:" || field[packageName].startsWith("file:")) return false;
field[packageName] = "catalog:";
return true;
}
async function findWorkspacePackageJsons(projectDir) {
const rootPkgPath = (0, node_path.join)(projectDir, "package.json");
if (!(0, node_fs.existsSync)(rootPkgPath)) return [];
const workspaceConfig = JSON.parse((0, node_fs.readFileSync)(rootPkgPath, "utf-8")).workspaces;
const patterns = [];
if (Array.isArray(workspaceConfig)) patterns.push(...workspaceConfig);
else if (workspaceConfig?.packages && Array.isArray(workspaceConfig.packages)) patterns.push(...workspaceConfig.packages);
if (patterns.length === 0) return [];
const pkgPaths = [];
for (const pattern of patterns) {
const matches = await (0, glob.glob)(pattern, {
cwd: projectDir,
dot: false,
absolute: false
});
for (const match of matches) {
const pkgPath = (0, node_path.join)(projectDir, match, "package.json");
if ((0, node_fs.existsSync)(pkgPath) && (0, node_fs.statSync)(pkgPath).isFile()) pkgPaths.push(pkgPath);
}
}
return [...new Set(pkgPaths)];
}
async function migrateChildRootPackageJson(projectDir) {
const configPath = (0, node_path.join)(projectDir, "bos.config.json");
const pkgPath = (0, node_path.join)(projectDir, "package.json");
if (!(0, node_fs.existsSync)(configPath) || !(0, node_fs.existsSync)(pkgPath)) return false;
if (!getExtendsRef(readJsonFile(configPath))?.startsWith("bos://")) return false;
const pkg = readJsonFile(pkgPath);
let changed = false;
if (pkg.private !== true) {
pkg.private = true;
changed = true;
}
if (pkg.type !== "module") {
pkg.type = "module";
changed = true;
}
if ("module" in pkg) {
delete pkg.module;
changed = true;
}
const pluginPackageJsons = await (0, glob.glob)("plugins/*/package.json", {
cwd: projectDir,
nodir: true,
dot: false,
absolute: false
});
const childScripts = require_cli_init.buildChildRootScripts({
ui: (0, node_fs.existsSync)((0, node_path.join)(projectDir, "ui", "package.json")),
api: (0, node_fs.existsSync)((0, node_path.join)(projectDir, "api", "package.json")),
host: (0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "package.json")),
plugins: pluginPackageJsons.length > 0
});
if (!pkg.scripts || typeof pkg.scripts !== "object") {
pkg.scripts = {};
changed = true;
}
const scripts = pkg.scripts;
for (const [key, value] of Object.entries(childScripts)) if (scripts[key] !== value) {
scripts[key] = value;
changed = true;
}
for (const obsoleteScript of ["sync-catalog", "init"]) if (obsoleteScript in scripts) {
delete scripts[obsoleteScript];
changed = true;
}
const workspaces = pkg.workspaces;
if (workspaces && typeof workspaces === "object") {
const workspaceConfig = workspaces;
if (Array.isArray(workspaceConfig.packages)) {
const nextPackages = workspaceConfig.packages.filter((entry) => entry !== "packages/everything-dev" && entry !== "packages/every-plugin");
if (nextPackages.length !== workspaceConfig.packages.length) {
workspaceConfig.packages = nextPackages;
changed = true;
}
}
}
if (pkg.overrides && typeof pkg.overrides === "object") {
const overrides = pkg.overrides;
for (const packageName of FRAMEWORK_PACKAGES) {
const value = overrides[packageName];
if (typeof value === "string" && value.startsWith("file:packages/")) {
delete overrides[packageName];
changed = true;
}
}
if (Object.keys(overrides).length === 0) {
delete pkg.overrides;
changed = true;
}
}
if (ensureAuthCoreCatalogRef(pkg)) changed = true;
const workspacePackageJsons = await findWorkspacePackageJsons(projectDir);
for (const workspacePkgPath of workspacePackageJsons) if (updatePackageFileAuthCoreRef(workspacePkgPath)) changed = true;
if (changed) (0, node_fs.writeFileSync)(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
return changed;
}
function buildChangelogUrl(oldVersion, newVersion, repository) {
const fromVersion = extractSemver(oldVersion);
const toVersion = extractSemver(newVersion);
if (!fromVersion || !toVersion || fromVersion === toVersion) return void 0;
const repoUrl = repository;
if (!repoUrl) return void 0;
const githubMatch = repoUrl.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
if (!githubMatch) return void 0;
const [, owner, repo] = githubMatch;
return `https://github.com/${owner}/${repo}/compare/v${fromVersion}...v${toVersion}`;
}
async function rewriteLegacyUiImports(projectDir) {
const files = await (0, glob.glob)("ui/src/**/*.{ts,tsx}", {
cwd: projectDir,
nodir: true,
dot: false,
absolute: false
});
const migrated = [];
for (const file of files) {
const filePath = (0, node_path.join)(projectDir, file);
const original = (0, node_fs.readFileSync)(filePath, "utf-8");
let next = original;
for (const [from, to] of LEGACY_UI_IMPORT_REWRITES) next = next.replaceAll(from, to);
if (next !== original) {
(0, node_fs.writeFileSync)(filePath, next);
migrated.push(file);
}
}
return migrated;
}
async function upgradeTemplate(projectDir, options) {
const timings = [];
if (!(0, node_fs.existsSync)((0, node_path.join)(projectDir, "package.json"))) return {
status: "error",
packages: [],
timings,
error: "No package.json found in current directory"
};
const parentSource = await readExtendedRootSource(projectDir);
const sourceRootCatalog = parentSource.catalog;
const inheritedCatalogPackageNames = Object.keys(sourceRootCatalog);
const currentCatalogEntries = readRootPackageJson(projectDir).workspaces?.catalog ?? {};
const workspacePkgPaths = await findWorkspacePackageJsons(projectDir);
const hasCatalogRefRewrites = inheritedCatalogPackageNames.length > 0 && (packageObjectNeedsCatalogRefs(readRootPackageJson(projectDir), inheritedCatalogPackageNames) || workspacePkgPaths.some((pkgPath) => packageFileNeedsCatalogRefs(pkgPath, inheritedCatalogPackageNames)));
const hasAuthCoreRefRewrites = packageObjectNeedsAuthCoreCatalogRef(readRootPackageJson(projectDir)) || workspacePkgPaths.some((pkgPath) => packageObjectNeedsAuthCoreCatalogRef(readJsonFile(pkgPath)));
const { packages, catalogVersionUpdates } = await require_timing.timePhase(timings, "check package versions", async () => {
const nextPackages = [];
for (const name of FRAMEWORK_PACKAGES) {
const current = readCurrentPackageSpecifier(projectDir, name);
const target = sourceRootCatalog[name] ?? current ?? "unknown";
nextPackages.push({
name,
from: current,
to: target
});
}
const nextCatalogVersionUpdates = [];
for (const [name, targetVersion] of Object.entries(sourceRootCatalog)) {
if (FRAMEWORK_PACKAGES.includes(name)) continue;
const currentVersion = currentCatalogEntries[name];
if (currentVersion === targetVersion) continue;
nextCatalogVersionUpdates.push({
name,
from: currentVersion,
to: targetVersion
});
}
return {
packages: nextPackages,
catalogVersionUpdates: nextCatalogVersionUpdates
};
});
const hasFrameworkUpdates = packages.some((p) => p.from !== p.to && p.from !== void 0);
const hasCatalogUpdates = catalogVersionUpdates.length > 0;
const hasUpdates = hasFrameworkUpdates || hasCatalogUpdates || hasCatalogRefRewrites || hasAuthCoreRefRewrites;
if (options.dryRun) {
let changelogUrl;
const pluginOptions = options.noSync ? null : await require_timing.timePhase(timings, "discover parent plugins", () => loadParentPluginOptions(projectDir));
if (hasUpdates) {
const mainPkg = packages.find((p) => p.name === "everything-dev");
if (mainPkg?.from && mainPkg.from !== mainPkg.to) changelogUrl = buildChangelogUrl(mainPkg.from, mainPkg.to, parentSource.repository);
}
return {
status: "dry-run",
packages: [...packages, ...catalogVersionUpdates.map((u) => ({
name: u.name,
from: u.from,
to: u.to
}))],
availablePlugins: pluginOptions?.newPluginKeys,
timings,
changelogUrl
};
}
await require_timing.timePhase(timings, "apply package updates", async () => {
if (inheritedCatalogPackageNames.length > 0) syncRootCatalogWithParent(projectDir, sourceRootCatalog);
if (inheritedCatalogPackageNames.length > 0) for (const pkgPath of workspacePkgPaths) updatePackageFileCatalogRefs(pkgPath, inheritedCatalogPackageNames);
});
const migratedBosConfigs = await require_timing.timePhase(timings, "migrate bos configs", () => migrateBosConfigFiles(projectDir));
const migratedRootPackageJson = await require_timing.timePhase(timings, "migrate root package", () => migrateChildRootPackageJson(projectDir));
let syncResult;
let addedPlugins = [];
if (!options.noSync) {
addedPlugins = await require_timing.timePhase(timings, "discover parent plugins", async () => {
if (options.dryRun) return [];
return addSelectedParentPlugins(projectDir);
});
syncResult = await require_timing.timePhase(timings, "sync template", () => require_sync.syncTemplate(projectDir, {
dryRun: false,
noInstall: true
}));
if (inheritedCatalogPackageNames.length > 0) syncRootCatalogWithParent(projectDir, sourceRootCatalog);
}
const sharedSync = await require_timing.timePhase(timings, "sync shared ui", async () => {
const configResult = await require_config.loadResolvedConfig({ cwd: projectDir });
if (!configResult) throw new Error("No bos.config.json found in current directory");
return require_shared.syncAndGenerateSharedUi({
configDir: projectDir,
hostMode: "local",
bosConfig: configResult.config
});
});
if ((hasUpdates || addedPlugins.length > 0 || sharedSync.catalogChanged) && !options.noInstall) {
await require_timing.timePhase(timings, "install dependencies", () => require_cli_init.runBunInstallForUpgrade(projectDir));
await require_timing.timePhase(timings, "generate types", () => require_cli_init.runTypesGen(projectDir));
}
const migratedFiles = await require_timing.timePhase(timings, "clean obsolete files", async () => {
const nextMigratedFiles = [
...migratedBosConfigs,
...migratedRootPackageJson ? ["package.json"] : [],
...await rewriteLegacyUiImports(projectDir)
];
for (const file of OBSOLETE_FILES) {
const filePath = (0, node_path.join)(projectDir, file);
if ((0, node_fs.existsSync)(filePath)) {
(0, node_fs.rmSync)(filePath);
nextMigratedFiles.push(file);
}
}
return nextMigratedFiles;
});
let changelogUrl;
const mainPkg = packages.find((p) => p.name === "everything-dev");
if (mainPkg?.from && mainPkg.from !== mainPkg.to) changelogUrl = buildChangelogUrl(mainPkg.from, mainPkg.to, parentSource.repository);
return {
status: "upgraded",
packages: [...packages, ...catalogVersionUpdates.map((u) => ({
name: u.name,
from: u.from,
to: u.to
}))],
sync: syncResult,
migrated: migratedFiles.length > 0 ? migratedFiles : void 0,
selectedPlugins: addedPlugins.length > 0 ? addedPlugins : void 0,
timings,
changelogUrl
};
}
//#endregion
exports.upgradeTemplate = upgradeTemplate;
//# sourceMappingURL=upgrade.cjs.map