release: prepare WRNexusJS 0.8.8
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.8.7",
|
||||
"version": "0.8.8",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
+12
-18
@@ -24,6 +24,12 @@ function literalUnion(values: Iterable<string>): string {
|
||||
return unique.length ? unique.map((value) => JSON.stringify(value)).join(" | ") : "never";
|
||||
}
|
||||
|
||||
function generatedContractMap(name: string, members: string): string {
|
||||
return members.trim()
|
||||
? `interface ${name} {\n${members}\n }`
|
||||
: `type ${name} = Record<string, never>;`;
|
||||
}
|
||||
|
||||
function typeImport(fromDirectory: string, file: string): string {
|
||||
const path = relative(fromDirectory, file).replace(/\\/g, "/");
|
||||
return JSON.stringify(path.startsWith(".") ? path : `./${path}`);
|
||||
@@ -203,24 +209,12 @@ declare namespace WRNexusGenerated {
|
||||
type TranslationKey = ${literalUnion(localeKeys)};
|
||||
type QueueName = ${literalUnion(queueNames)};
|
||||
type CacheKey = ${literalUnion(cacheKeys)};
|
||||
interface Components {
|
||||
${componentMap}
|
||||
}
|
||||
interface ApiContracts {
|
||||
${apiContracts}
|
||||
}
|
||||
interface MiddlewareContexts {
|
||||
${middlewareContracts}
|
||||
}
|
||||
interface DatabaseQueries {
|
||||
${databaseContracts}
|
||||
}
|
||||
interface RealtimeMessages {
|
||||
${realtimeContracts}
|
||||
}
|
||||
interface QueuePayloads {
|
||||
${queueContracts}
|
||||
}
|
||||
${generatedContractMap("Components", componentMap)}
|
||||
${generatedContractMap("ApiContracts", apiContracts)}
|
||||
${generatedContractMap("MiddlewareContexts", middlewareContracts)}
|
||||
${generatedContractMap("DatabaseQueries", databaseContracts)}
|
||||
${generatedContractMap("RealtimeMessages", realtimeContracts)}
|
||||
${generatedContractMap("QueuePayloads", queueContracts)}
|
||||
type ApplicationConfig = ${configFile ? `(typeof import(${typeImport(typeDir, configFile)}))["default"]` : "Record<string, never>"};
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -33,6 +33,7 @@ import { pathToFileURL } from "node:url";
|
||||
import { formatWrn, parse } from "@wrnexus/syntax";
|
||||
import { AI_GUIDE, CLAUDE_MD } from "./ai-guide.ts";
|
||||
import { inspectProject, type DoctorCheck } from "./doctor.ts";
|
||||
import { generateApplicationTypes } from "./types.ts";
|
||||
|
||||
/** The version of the CLI currently running (its own package.json). */
|
||||
function cliVersion(): string {
|
||||
@@ -1783,6 +1784,10 @@ const MIGRATIONS: Migration[] = [
|
||||
description:
|
||||
"Adds compatible imports, type checking, stores, and legacy behavior configuration.",
|
||||
apply(ctx) {
|
||||
// Workspace manifests are updated alongside each configured application,
|
||||
// but they are not themselves runnable apps. Keep app-owned declarations
|
||||
// under the individual app roots instead of creating `<workspace>/app`.
|
||||
if (!existsSync(join(ctx.appRoot, "app", "pages"))) return;
|
||||
updateV060Config(ctx);
|
||||
const types = join(ctx.appRoot, "app", "types");
|
||||
if (!existsSync(types)) {
|
||||
@@ -2115,6 +2120,17 @@ const MIGRATIONS: Migration[] = [
|
||||
// select for non-link items as well as navigation items.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.8.8",
|
||||
id: "0.8.8-editor-types-and-update-verification",
|
||||
description:
|
||||
"Adds typed page context support and regenerates lint-safe application declarations before update verification.",
|
||||
apply() {
|
||||
// No source rewrite is required. The 0.8.8 CLI regenerates application
|
||||
// declarations immediately before verification, repairing stale empty
|
||||
// interface contracts produced by earlier releases.
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/** Release tooling uses this to require an explicit migration entry per version. */
|
||||
@@ -2297,6 +2313,10 @@ export function blockingVerificationChecks(checks: DoctorCheck[]): DoctorCheck[]
|
||||
}
|
||||
|
||||
function verifyApp(app: UpdatedApp): boolean {
|
||||
// Generated declarations must reflect the newly installed CLI before the
|
||||
// application's lint/typecheck scripts inspect them. This also repairs stale
|
||||
// generated output left by an older framework version.
|
||||
if (existsSync(join(app.root, "app", "pages"))) generateApplicationTypes(app.root);
|
||||
const health = inspectProject(app.root);
|
||||
const failed = blockingVerificationChecks(health);
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ test("generate types emits application-wide deterministic contracts", () => {
|
||||
expect(output).toContain('"/realtime/chat": RealtimeMessage<');
|
||||
expect(output).toContain("interface QueuePayloads");
|
||||
expect(output).toContain('"email": QueuePayload<');
|
||||
expect(output).toContain("type MiddlewareContexts = Record<string, never>");
|
||||
expect(output).toContain("type DatabaseQueries = Record<string, never>");
|
||||
expect(output).not.toMatch(/interface\s+\w+\s*\{\s*\}/);
|
||||
});
|
||||
|
||||
test("application checker validates every wrn source", () => {
|
||||
|
||||
@@ -169,6 +169,30 @@ test("update verification skips unavailable scripts", () => {
|
||||
expect(verificationCommands({ check: "bun run lint" })).toEqual([["run", "check"]]);
|
||||
});
|
||||
|
||||
test("0.6 type declarations are created only inside runnable apps", () => {
|
||||
const workspaceRoot = mkdtempSync(join(tmpdir(), "wrnexus-update-workspace-"));
|
||||
const appRoot = join(workspaceRoot, "apps", "web");
|
||||
mkdirSync(join(appRoot, "app", "pages"), { recursive: true });
|
||||
writeFileSync(
|
||||
join(workspaceRoot, "package.json"),
|
||||
JSON.stringify({ name: "workspace", wrnexus: { version: "0.5.9" } }),
|
||||
);
|
||||
writeFileSync(
|
||||
join(appRoot, "package.json"),
|
||||
JSON.stringify({ name: "web", wrnexus: { version: "0.5.9" } }),
|
||||
);
|
||||
|
||||
try {
|
||||
updateApp(workspaceRoot, "0.6.0", false);
|
||||
updateApp(appRoot, "0.6.0", false);
|
||||
|
||||
expect(existsSync(join(workspaceRoot, "app", "types", "global.d.ts"))).toBe(false);
|
||||
expect(existsSync(join(appRoot, "app", "types", "global.d.ts"))).toBe(true);
|
||||
} finally {
|
||||
rmSync(workspaceRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("0.3 WRN source normalization is conservative and idempotent", async () => {
|
||||
const { migrateWrnSource } = await import("../src/update.ts");
|
||||
const source = `component Card {
|
||||
|
||||
Reference in New Issue
Block a user