fix(studio): resolve exact component filenames for Linux previews
This commit is contained in:
1 parent
f1cf0e9f2b
commit
59f1d9d28a
5 files changed
+61
-8
No files matched your search
@@ -391,7 +391,7 @@
|
|||||||
},
|
},
|
||||||
"packages/design-studio": {
|
"packages/design-studio": {
|
||||||
"name": "@wrnexus/design-studio",
|
"name": "@wrnexus/design-studio",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/ai": "workspace:*",
|
"@wrnexus/ai": "workspace:*",
|
||||||
"@wrnexus/compiler": "workspace:*",
|
"@wrnexus/compiler": "workspace:*",
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Design Studio 0.1.1 — Linux preview lookup
|
||||||
|
|
||||||
|
Composed and gallery previews previously inferred a component's filename from
|
||||||
|
its public name (Input -> Input.wrn). Some shipped components use lowercase
|
||||||
|
filenames (input.wrn), so the lookup happened to work on Windows and failed on
|
||||||
|
Linux with ENOENT. Previews now use uiComponentPath from the shipped UI registry,
|
||||||
|
which resolves declared names to their exact source files, including ComboBox.
|
||||||
|
|
||||||
|
A subprocess regression test enforces exact filesystem casing even on Windows
|
||||||
|
and renders the composed preview and all seven gallery pages (104 components).
|
||||||
|
All 42 Studio tests and the workspace TypeScript check pass. Existing component
|
||||||
|
APIs, design schemas, browser drafts and generation contracts are unchanged.
|
||||||
|
|
||||||
|
Private package publication and the standalone component site's dependency pin
|
||||||
|
are updated as part of this fix. The VM must install the updated lockfile,
|
||||||
|
rebuild and restart before the live preview error can disappear.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/design-studio",
|
"name": "@wrnexus/design-studio",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { validateAgentPage } from "./agent-pages.ts";
|
import { validateAgentPage } from "./agent-pages.ts";
|
||||||
import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
|
import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
|
||||||
import { tmpdir } from "node:os";
|
import { tmpdir } from "node:os";
|
||||||
import { join, resolve } from "node:path";
|
import { join } from "node:path";
|
||||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
import { compileWrnFile } from "@wrnexus/compiler";
|
import { compileWrnFile } from "@wrnexus/compiler";
|
||||||
import { runWithRequestContext } from "@wrnexus/core";
|
import { runWithRequestContext } from "@wrnexus/core";
|
||||||
import { REACTIVE_RUNTIME } from "@wrnexus/csr";
|
import { REACTIVE_RUNTIME } from "@wrnexus/csr";
|
||||||
import { renderDocument } from "@wrnexus/ssr";
|
import { renderDocument } from "@wrnexus/ssr";
|
||||||
import { uiCss, uiComponentsDir } from "@wrnexus/ui/registry";
|
import { uiCss, uiComponentPath } from "@wrnexus/ui/registry";
|
||||||
import { resolveThemeConfig, renderThemeCss } from "@wrnexus/styles/theme";
|
import { resolveThemeConfig, renderThemeCss } from "@wrnexus/styles/theme";
|
||||||
import {
|
import {
|
||||||
COMPONENT_CONTRACTS,
|
COMPONENT_CONTRACTS,
|
||||||
@@ -25,10 +25,7 @@ const escape = (text: string) =>
|
|||||||
async function component(name: string, props: Record<string, unknown> = {}) {
|
async function component(name: string, props: Record<string, unknown> = {}) {
|
||||||
if (!Object.hasOwn(COMPONENT_CONTRACTS, name)) throw Error("Unknown component.");
|
if (!Object.hasOwn(COMPONENT_CONTRACTS, name)) throw Error("Unknown component.");
|
||||||
if (!modules.has(name)) {
|
if (!modules.has(name)) {
|
||||||
const sourcePath = resolve(
|
const sourcePath = uiComponentPath(name);
|
||||||
uiComponentsDir(),
|
|
||||||
name === "ComboBox" ? "Combobox.wrn" : `${name}.wrn`,
|
|
||||||
);
|
|
||||||
const source = readFileSync(sourcePath, "utf8");
|
const source = readFileSync(sourcePath, "utf8");
|
||||||
const directory = join(tmpdir(), "wrnexus-design-studio");
|
const directory = join(tmpdir(), "wrnexus-design-studio");
|
||||||
mkdirSync(directory, { recursive: true });
|
mkdirSync(directory, { recursive: true });
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import { pathToFileURL } from "node:url";
|
||||||
|
import { resolve } from "node:path";
|
||||||
|
|
||||||
|
test("composed and catalog previews use exact shipped filename casing on every platform", () => {
|
||||||
|
const preview = pathToFileURL(resolve(import.meta.dir, "../src/preview.ts")).href;
|
||||||
|
const probe = `
|
||||||
|
import { mock } from "bun:test";
|
||||||
|
import { readFileSync, readdirSync } from "node:fs";
|
||||||
|
import { dirname, basename } from "node:path";
|
||||||
|
import { uiComponentsDir } from "@wrnexus/ui/registry";
|
||||||
|
import { CORE_DESIGN_SYSTEMS } from "@wrnexus/design-system";
|
||||||
|
const directory = uiComponentsDir();
|
||||||
|
const names = new Set(readdirSync(directory));
|
||||||
|
const originalRead = readFileSync;
|
||||||
|
let checked = 0;
|
||||||
|
mock.module("node:fs", () => ({ readFileSync(path, ...options) {
|
||||||
|
if (typeof path === "string" && dirname(path) === directory && path.endsWith(".wrn")) {
|
||||||
|
if (!names.has(basename(path))) throw Error("Case-sensitive component lookup failed: " + basename(path));
|
||||||
|
checked++;
|
||||||
|
}
|
||||||
|
return originalRead(path, ...options);
|
||||||
|
}}));
|
||||||
|
const { previewDocument } = await import(${JSON.stringify(preview)});
|
||||||
|
await previewDocument(CORE_DESIGN_SYSTEMS.square);
|
||||||
|
for (let page = 0; page < 7; page++) await previewDocument(CORE_DESIGN_SYSTEMS.soft, { content: "catalog", page });
|
||||||
|
if (checked < 104) throw Error("Incomplete component coverage: " + checked);
|
||||||
|
console.log("Exact filename casing verified for all 104 preview components.");
|
||||||
|
`;
|
||||||
|
const result = Bun.spawnSync([process.execPath, "--eval", probe], {
|
||||||
|
cwd: resolve(import.meta.dir, "../../.."),
|
||||||
|
stdout: "pipe",
|
||||||
|
stderr: "pipe",
|
||||||
|
});
|
||||||
|
expect(new TextDecoder().decode(result.stderr)).not.toContain(
|
||||||
|
"Case-sensitive component lookup failed",
|
||||||
|
);
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(new TextDecoder().decode(result.stdout)).toContain("all 104 preview components");
|
||||||
|
});
|
||||||
Reference in new issue
Block a user