release: WRNexusJS 0.8.0
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
||||
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
||||
import { extname, join, resolve } from "node:path";
|
||||
import { diagnose } from "@wrnexus/syntax";
|
||||
import { diagnose, formatWrn } from "@wrnexus/syntax";
|
||||
import { buildRouter, findRouteConflicts } from "@wrnexus/router";
|
||||
import { loadAppConfig, validateAppConfig } from "@wrnexus/styles";
|
||||
import { createPluginRunner, discoverPlugins } from "@wrnexus/plugin";
|
||||
@@ -12,6 +12,12 @@ export interface DoctorCheck {
|
||||
level?: "error" | "warning";
|
||||
}
|
||||
|
||||
export interface DoctorRepair {
|
||||
name: string;
|
||||
changed: boolean;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
function parseVersion(value: string): [number, number, number] {
|
||||
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(value.replace(/^[^\d]*/, ""));
|
||||
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : [0, 0, 0];
|
||||
@@ -53,6 +59,81 @@ function frameworkRanges(pkg: Record<string, unknown>): Map<string, string[]> {
|
||||
return ranges;
|
||||
}
|
||||
|
||||
export function repairProject(appRoot: string): DoctorRepair[] {
|
||||
const root = resolve(appRoot);
|
||||
const repairs: DoctorRepair[] = [];
|
||||
const pages = join(root, "app", "pages");
|
||||
if (!existsSync(pages)) {
|
||||
mkdirSync(pages, { recursive: true });
|
||||
repairs.push({ name: "app/pages", changed: true, detail: "created app/pages" });
|
||||
}
|
||||
|
||||
const configNames = ["wrnexus.config.ts", "wrnexus.config.mjs", "wrnexus.config.js"];
|
||||
if (!configNames.some((name) => existsSync(join(root, name)))) {
|
||||
writeFileSync(join(root, "wrnexus.config.ts"), "export default {};\n", "utf8");
|
||||
repairs.push({ name: "configuration", changed: true, detail: "created wrnexus.config.ts" });
|
||||
}
|
||||
|
||||
const pkgPath = join(root, "package.json");
|
||||
if (existsSync(pkgPath)) {
|
||||
try {
|
||||
const source = readFileSync(pkgPath, "utf8");
|
||||
const pkg = JSON.parse(source) as Record<string, unknown>;
|
||||
const ranges = frameworkRanges(pkg);
|
||||
const preferred = [...ranges.keys()].sort((left, right) => {
|
||||
const a = parseVersion(left);
|
||||
const b = parseVersion(right);
|
||||
return b[0] - a[0] || b[1] - a[1] || b[2] - a[2];
|
||||
})[0];
|
||||
let changed = false;
|
||||
if (preferred && ranges.size > 1) {
|
||||
for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
|
||||
const dependencies = pkg[field] as Record<string, string> | undefined;
|
||||
for (const name of Object.keys(dependencies ?? {})) {
|
||||
if (name.startsWith("@wrnexus/") && dependencies![name] !== preferred) {
|
||||
dependencies![name] = preferred;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const marker = (pkg.wrnexus as Record<string, unknown> | undefined) ?? {};
|
||||
if (!marker.version || !versionAtLeast(String(marker.version), "0.8.0")) {
|
||||
marker.version = "0.8.0";
|
||||
pkg.wrnexus = marker;
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf8");
|
||||
repairs.push({
|
||||
name: "package.json",
|
||||
changed: true,
|
||||
detail: preferred
|
||||
? `aligned framework packages to ${preferred}`
|
||||
: "recorded 0.8.0 marker",
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
repairs.push({ name: "package.json", changed: false, detail: "skipped invalid JSON" });
|
||||
}
|
||||
}
|
||||
|
||||
let formatted = 0;
|
||||
for (const file of walk(join(root, "app"), ".wrn")) {
|
||||
const source = readFileSync(file, "utf8");
|
||||
if (diagnose(source).some((item) => item.severity === "error")) continue;
|
||||
const output = formatWrn(source, { tabSize: 2, printWidth: 100, multilineAttributes: true });
|
||||
if (output !== source) {
|
||||
writeFileSync(file, output, "utf8");
|
||||
formatted++;
|
||||
}
|
||||
}
|
||||
if (formatted) {
|
||||
repairs.push({ name: "WRN formatting", changed: true, detail: `formatted ${formatted} files` });
|
||||
}
|
||||
return repairs;
|
||||
}
|
||||
|
||||
export function inspectProject(appRoot: string): DoctorCheck[] {
|
||||
const root = resolve(appRoot);
|
||||
const checks: DoctorCheck[] = [];
|
||||
@@ -174,8 +255,12 @@ export function inspectProject(appRoot: string): DoctorCheck[] {
|
||||
return checks;
|
||||
}
|
||||
|
||||
export async function runDoctor(appRoot: string): Promise<boolean> {
|
||||
export async function runDoctor(
|
||||
appRoot: string,
|
||||
options: { fix?: boolean } = {},
|
||||
): Promise<boolean> {
|
||||
const root = resolve(appRoot);
|
||||
const repairs = options.fix ? repairProject(root) : [];
|
||||
const checks = inspectProject(root);
|
||||
try {
|
||||
const config = await loadAppConfig(root);
|
||||
@@ -257,6 +342,8 @@ export async function runDoctor(appRoot: string): Promise<boolean> {
|
||||
}
|
||||
|
||||
console.log("WRNexus doctor\n");
|
||||
for (const repair of repairs) console.log(` ↻ ${repair.name}: ${repair.detail}`);
|
||||
if (repairs.length) console.log("");
|
||||
for (const check of checks) {
|
||||
const optional = check.level === "warning";
|
||||
console.log(` ${check.ok ? "✓" : optional ? "⚠" : "✗"} ${check.name}: ${check.detail}`);
|
||||
|
||||
Reference in New Issue
Block a user