feat: release design system engine, studio and component contracts
This commit is contained in:
1 parent
ff1065fb27
commit
3943b946d6
693 files changed
+175546
-3894
No files matched your search
@@ -0,0 +1,221 @@
|
||||
/** Copied into an isolated tarball consumer by prepare-design-release.ts. Package imports only. */
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdirSync, writeFileSync, existsSync, readFileSync } from "node:fs";
|
||||
import { join, resolve } from "node:path";
|
||||
import { CORE_DESIGN_SYSTEMS, compileDesignSystem } from "@wrnexus/design-system";
|
||||
import { createDesignPackage, readDesignPackage } from "@wrnexus/design-system/package";
|
||||
import { StudioSession } from "@wrnexus/design-studio";
|
||||
import { planDesignUpgrade, applyDesignUpgrade } from "@wrnexus/design-studio/upgrades";
|
||||
import { createStudioHandler } from "@wrnexus/design-studio/server";
|
||||
import { createFrameworkMcpServer } from "@wrnexus/mcp";
|
||||
import { uiComponentNames } from "@wrnexus/ui/registry";
|
||||
import { resolveThemeConfig } from "@wrnexus/styles/theme";
|
||||
import schema from "@wrnexus/design-system/schema.json";
|
||||
|
||||
assert.equal(uiComponentNames().length, 104);
|
||||
assert.ok(schema);
|
||||
const system = structuredClone(CORE_DESIGN_SYSTEMS.square);
|
||||
const original = await createDesignPackage(system);
|
||||
const next = structuredClone(system);
|
||||
next.version = "1.1.0";
|
||||
next.tokens["color.primary"]!.value = "#abcdef";
|
||||
const upgraded = await createDesignPackage(next);
|
||||
const source = JSON.stringify(upgraded);
|
||||
const sessions: StudioSession[] = [];
|
||||
const applications = [];
|
||||
for (const name of ["application-one", "application-two"]) {
|
||||
const root = resolve(name);
|
||||
mkdirSync(root, { recursive: true });
|
||||
writeFileSync(join(root, "wrn.config.ts"), "export default { existing: true };");
|
||||
const storage = {
|
||||
value: "",
|
||||
getItem() {
|
||||
return this.value || null;
|
||||
},
|
||||
setItem(_key: string, value: string) {
|
||||
this.value = value;
|
||||
},
|
||||
};
|
||||
const session = new StudioSession(system, storage);
|
||||
sessions.push(session);
|
||||
session.setLocks(["/tokens/shape.control"]);
|
||||
const review = await planDesignUpgrade(session, source);
|
||||
assert.equal(review.canApply, true);
|
||||
await applyDesignUpgrade(session, source, review.baseRevision);
|
||||
assert.equal(session.valid.version, "1.1.0");
|
||||
session.undo();
|
||||
assert.equal(session.valid.version, "1.0.0");
|
||||
session.redo();
|
||||
session.edit("{unfinished");
|
||||
const restored = new StudioSession(undefined, storage);
|
||||
assert.equal(restored.restore(), true);
|
||||
assert.equal(restored.source, "{unfinished");
|
||||
restored.undo();
|
||||
assert.equal(restored.valid.version, "1.1.0");
|
||||
const server = createFrameworkMcpServer(root, { design: true, designWrite: true });
|
||||
let draft = (await server.call("wrnexus_design_create", {
|
||||
baseRevision: "none",
|
||||
source: JSON.stringify(system),
|
||||
})) as { revision: string };
|
||||
const migration = (await server.call("wrnexus_design_upgrade_plan", { source })) as {
|
||||
canApply: boolean;
|
||||
};
|
||||
assert.equal(migration.canApply, true);
|
||||
draft = (await server.call("wrnexus_design_upgrade", {
|
||||
baseRevision: draft.revision,
|
||||
source,
|
||||
})) as typeof draft;
|
||||
const page = {
|
||||
id: "account",
|
||||
title: "Account settings",
|
||||
components: [
|
||||
{ component: "Input", props: { id: "name", label: "Display name" } },
|
||||
{ component: "Button", props: { label: "Save profile", variant: "default" } },
|
||||
],
|
||||
};
|
||||
draft = (await server.call("wrnexus_design_page", {
|
||||
baseRevision: draft.revision,
|
||||
page,
|
||||
})) as typeof draft;
|
||||
const preview = (await server.call("wrnexus_design_preview", { pageId: "account" })) as {
|
||||
html: string;
|
||||
};
|
||||
assert.ok(preview.html.includes('data-wrn-component="Button"'));
|
||||
assert.ok(preview.html.includes("Save profile"));
|
||||
const pinned = (await server.call("wrnexus_design_package")) as { package: typeof upgraded };
|
||||
assert.equal(pinned.package.integrity.digest, upgraded.integrity.digest);
|
||||
await server.call("wrnexus_design_apply", {
|
||||
baseRevision: draft.revision,
|
||||
baseApplicationRevision: "none",
|
||||
});
|
||||
const state = (await server.call("wrnexus_design_inspect")) as {
|
||||
application: { revision: string };
|
||||
};
|
||||
assert.notEqual(state.application.revision, "none");
|
||||
assert.equal(
|
||||
readFileSync(join(root, "wrn.config.ts"), "utf8"),
|
||||
"export default { existing: true };",
|
||||
);
|
||||
applications.push({
|
||||
name,
|
||||
digest: pinned.package.integrity.digest,
|
||||
applied: state.application.revision,
|
||||
});
|
||||
}
|
||||
assert.equal(applications[0]!.digest, applications[1]!.digest);
|
||||
assert.equal(applications[0]!.applied, applications[1]!.applied);
|
||||
assert.equal(
|
||||
(await readDesignPackage(JSON.stringify(original))).package.integrity.digest,
|
||||
original.integrity.digest,
|
||||
);
|
||||
for (const system of Object.values(CORE_DESIGN_SYSTEMS)) {
|
||||
assert.ok(compileDesignSystem(system).css);
|
||||
assert.ok(resolveThemeConfig({ designSystem: { system } }).recipeCss);
|
||||
}
|
||||
const handler = await createStudioHandler({ applicationRoot: resolve("application-one") });
|
||||
assert.equal((await handler(new Request("http://127.0.0.1:4320/"))).status, 200);
|
||||
const client = await handler(new Request("http://127.0.0.1:4320/studio.js"));
|
||||
assert.equal(client.status, 200);
|
||||
assert.ok((await client.text()).length > 1000);
|
||||
const req = await handler(
|
||||
new Request("http://127.0.0.1:4320/api/preview", {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({ system: CORE_DESIGN_SYSTEMS.angular, mode: "dark" }),
|
||||
}),
|
||||
);
|
||||
assert.equal(req.status, 200);
|
||||
const result = await req.json();
|
||||
assert.ok(
|
||||
(await (await handler(new Request("http://127.0.0.1:4320" + result.url))).text()).includes(
|
||||
'data-wrn-component="Button"',
|
||||
),
|
||||
);
|
||||
assert.equal(existsSync(resolve("node_modules/@wrnexus/design-studio/src")), false);
|
||||
assert.equal(
|
||||
existsSync(resolve("node_modules/@wrnexus/design-studio/assets/studio-client.js")),
|
||||
true,
|
||||
);
|
||||
writeFileSync(
|
||||
"browser-probe.ts",
|
||||
'import {StudioSession} from "@wrnexus/design-studio"; import {createDesignPackage} from "@wrnexus/design-system/package"; import {planDesignUpgrade} from "@wrnexus/design-studio/upgrades"; console.log(new StudioSession(),createDesignPackage,planDesignUpgrade);',
|
||||
);
|
||||
const browser = await Bun.build({ entrypoints: [resolve("browser-probe.ts")], target: "browser" });
|
||||
assert.equal(browser.success, true, browser.logs.join("\n"));
|
||||
assert.ok(browser.outputs.length);
|
||||
const defaultServer = createFrameworkMcpServer(resolve("application-one"));
|
||||
assert.equal(defaultServer.tools().length, 8);
|
||||
const stdio = resolve("node_modules/@wrnexus/mcp/dist/stdio.js");
|
||||
const child = Bun.spawn(
|
||||
[process.execPath, stdio, "--root=" + resolve("application-one"), "--design"],
|
||||
{ stdin: "pipe", stdout: "pipe", stderr: "pipe" },
|
||||
);
|
||||
child.stdin.write(
|
||||
JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: 1,
|
||||
method: "tools/call",
|
||||
params: { name: "wrnexus_design_context", arguments: { components: ["Button"] } },
|
||||
}) + "\n",
|
||||
);
|
||||
child.stdin.end();
|
||||
const protocol = JSON.parse((await new Response(child.stdout).text()).trim());
|
||||
assert.equal(await child.exited, 0);
|
||||
assert.ok(protocol.result.structuredContent.value.components.Button);
|
||||
const cli = Bun.spawn(
|
||||
[
|
||||
process.execPath,
|
||||
resolve("node_modules/@wrnexus/design-studio/dist/cli.js"),
|
||||
"--app-root",
|
||||
resolve("application-one"),
|
||||
],
|
||||
{ stdout: "pipe", stderr: "pipe", env: { ...process.env, DESIGN_STUDIO_PORT: "0" } },
|
||||
);
|
||||
let startupTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
try {
|
||||
const startup = await Promise.race([
|
||||
cli.stdout.getReader().read(),
|
||||
new Promise<never>((_resolve, reject) => {
|
||||
startupTimer = setTimeout(
|
||||
() => reject(Error("Installed Studio CLI startup timed out.")),
|
||||
10000,
|
||||
);
|
||||
}),
|
||||
]);
|
||||
const line = new TextDecoder().decode(startup.value);
|
||||
const address = /http:\/\/127\.0\.0\.1:\d+\//.exec(line)?.[0];
|
||||
assert.ok(address, line);
|
||||
assert.equal((await fetch(address)).status, 200);
|
||||
} finally {
|
||||
if (startupTimer) clearTimeout(startupTimer);
|
||||
cli.kill();
|
||||
await cli.exited;
|
||||
}
|
||||
writeFileSync(
|
||||
process.env.WRNEXUS_DESIGN_REPORT!,
|
||||
JSON.stringify(
|
||||
{
|
||||
packagingVerified: false,
|
||||
published: false,
|
||||
applications,
|
||||
checks: [
|
||||
"104 shipped component sources",
|
||||
"JSON schema asset",
|
||||
"browser-safe root and upgrades bundle",
|
||||
"prebuilt Studio client without src files",
|
||||
"real composed and agent SSR previews",
|
||||
"shared pin and CSS consistency across two applications",
|
||||
"invalid draft reload and undo/redo",
|
||||
"reviewed package upgrades and MCP operations",
|
||||
"unchanged default MCP tools and installed stdio protocol",
|
||||
"existing application configuration preserved",
|
||||
"installed Studio CLI starts without source files",
|
||||
],
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
);
|
||||
console.log(
|
||||
"Installed tarball consumers passed for two applications, Studio browser/server assets and MCP.",
|
||||
);
|
||||
Reference in new issue
Block a user