release: WRNexusJS 0.8.0
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { testPluginCompatibility } from "../src/index.ts";
|
||||
|
||||
test("plugin compatibility kit evaluates runtime, Bun, OS, and capability matrices", () => {
|
||||
const results = testPluginCompatibility(
|
||||
{
|
||||
runtimes: ["bun", "node"],
|
||||
requires: ["filesystem"],
|
||||
compatibility: { bunMin: "1.3.0", os: ["linux", "darwin"] },
|
||||
},
|
||||
[
|
||||
{ runtime: "bun", version: "1.3.2", os: "linux", capabilities: ["filesystem"] },
|
||||
{ runtime: "bun", version: "1.2.9", os: "win32", capabilities: [] },
|
||||
{ runtime: "edge", os: "linux", capabilities: ["crypto"] },
|
||||
],
|
||||
);
|
||||
expect(results[0]?.ok).toBe(true);
|
||||
expect(results[1]?.issues.map((issue) => issue.code)).toEqual([
|
||||
"WRN-PLUGIN-MATRIX-VERSION",
|
||||
"WRN-PLUGIN-MATRIX-OS",
|
||||
"WRN-PLUGIN-MATRIX-CAPABILITY",
|
||||
]);
|
||||
expect(results[2]?.issues.map((issue) => issue.code)).toEqual([
|
||||
"WRN-PLUGIN-MATRIX-RUNTIME",
|
||||
"WRN-PLUGIN-MATRIX-CAPABILITY",
|
||||
]);
|
||||
});
|
||||
@@ -3,6 +3,7 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { createPluginRunner, discoverPlugins, resolvePlugins } from "../src/index.ts";
|
||||
import { parse } from "@wrnexus/syntax";
|
||||
|
||||
describe("plugin ordering", () => {
|
||||
test("orders pre, normal, and post plugins", () => {
|
||||
@@ -22,6 +23,85 @@ describe("plugin ordering", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("runs the complete lifecycle and exposes ecosystem contribution channels", async () => {
|
||||
const calls: string[] = [];
|
||||
const runner = createPluginRunner(
|
||||
{
|
||||
name: "ecosystem",
|
||||
setup: () => {
|
||||
calls.push("setup");
|
||||
},
|
||||
configure: () => {
|
||||
calls.push("configure");
|
||||
},
|
||||
configSchemas: [
|
||||
{
|
||||
namespace: "feature",
|
||||
validate(value) {
|
||||
calls.push(`schema:${String(value)}`);
|
||||
},
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
{
|
||||
name: "focus",
|
||||
transform: (value) => ({ name: "data-focus", value }),
|
||||
},
|
||||
],
|
||||
cliCommands: [
|
||||
{
|
||||
name: "hello",
|
||||
run: () => {
|
||||
calls.push("cli");
|
||||
},
|
||||
},
|
||||
],
|
||||
virtualModules: [{ id: "virtual:feature", load: () => "export default true" }],
|
||||
deploymentAdapters: [{ name: "test-cloud", build: (value) => value }],
|
||||
documentation: ["docs/feature.md"],
|
||||
typeDefinitions: ["types/feature.d.ts"],
|
||||
render: (html) => `${html}<!-- plugin -->`,
|
||||
hmrUpdate: (files) => {
|
||||
calls.push(`hmr:${files.join(",")}`);
|
||||
},
|
||||
deploy: () => {
|
||||
calls.push("deploy");
|
||||
},
|
||||
shutdown: () => {
|
||||
calls.push("shutdown");
|
||||
},
|
||||
},
|
||||
context("."),
|
||||
);
|
||||
await runner.configure({ feature: true });
|
||||
await runner.configResolved({ feature: true });
|
||||
const contributions = await runner.contributions();
|
||||
expect(contributions.directives[0]?.name).toBe("focus");
|
||||
expect(contributions.cliCommands[0]?.name).toBe("hello");
|
||||
expect(contributions.virtualModules[0]?.id).toBe("virtual:feature");
|
||||
expect(contributions.deploymentAdapters[0]?.name).toBe("test-cloud");
|
||||
expect(contributions.documentation).toEqual(["docs/feature.md"]);
|
||||
expect(contributions.typeDefinitions).toEqual(["types/feature.d.ts"]);
|
||||
const transformed = await runner.transformAst(
|
||||
parse('page Demo { view { <input use:focus="first"> } }'),
|
||||
"app/pages/demo.wrn",
|
||||
);
|
||||
const input = transformed.view.find((node) => node.type === "element");
|
||||
expect(input?.type === "element" ? input.attrs[0]?.name : undefined).toBe("data-focus");
|
||||
expect(await runner.render("<main></main>")).toContain("<!-- plugin -->");
|
||||
await runner.hook("hmrUpdate", ["app/page.wrn"]);
|
||||
await runner.hook("deploy", {});
|
||||
await runner.hook("shutdown");
|
||||
expect(calls).toEqual([
|
||||
"setup",
|
||||
"configure",
|
||||
"schema:true",
|
||||
"hmr:app/page.wrn",
|
||||
"deploy",
|
||||
"shutdown",
|
||||
]);
|
||||
});
|
||||
|
||||
function context(root: string) {
|
||||
return {
|
||||
root,
|
||||
@@ -185,6 +265,96 @@ test("strict discovery surfaces invalid package plugin exports", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("discovery enforces declared deployment runtimes and capabilities", async () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "wrnexus-runtime-discovery-"));
|
||||
const app = join(root, "apps", "web");
|
||||
const pkg = join(root, "packages", "filesystem-plugin");
|
||||
try {
|
||||
mkdirSync(app, { recursive: true });
|
||||
mkdirSync(pkg, { recursive: true });
|
||||
writeFileSync(
|
||||
join(root, "package.json"),
|
||||
JSON.stringify({ private: true, workspaces: ["apps/*", "packages/*"] }),
|
||||
);
|
||||
writeFileSync(
|
||||
join(app, "package.json"),
|
||||
JSON.stringify({ name: "web", dependencies: { "filesystem-plugin": "workspace:*" } }),
|
||||
);
|
||||
writeFileSync(
|
||||
join(pkg, "package.json"),
|
||||
JSON.stringify({
|
||||
name: "filesystem-plugin",
|
||||
version: "1.0.0",
|
||||
wrnexus: { runtimes: ["bun", "node"], requires: ["filesystem"] },
|
||||
}),
|
||||
);
|
||||
await expect(
|
||||
discoverPlugins(app, undefined, { runtime: "edge", capabilities: ["crypto"] }),
|
||||
).rejects.toThrow("WRN-PLUGIN-RUNTIME");
|
||||
await expect(
|
||||
discoverPlugins(app, undefined, { runtime: "bun", capabilities: ["filesystem"] }),
|
||||
).resolves.toBeDefined();
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("discovery enforces declared and application-granted plugin permissions", async () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "wrnexus-permission-discovery-"));
|
||||
const app = join(root, "apps", "web");
|
||||
const pkg = join(root, "packages", "route-plugin");
|
||||
try {
|
||||
mkdirSync(app, { recursive: true });
|
||||
mkdirSync(pkg, { recursive: true });
|
||||
writeFileSync(
|
||||
join(root, "package.json"),
|
||||
JSON.stringify({ private: true, workspaces: ["apps/*", "packages/*"] }),
|
||||
);
|
||||
writeFileSync(
|
||||
join(app, "package.json"),
|
||||
JSON.stringify({ name: "web", dependencies: { "route-plugin": "workspace:*" } }),
|
||||
);
|
||||
writeFileSync(join(pkg, "route.ts"), "export default {};");
|
||||
writeFileSync(
|
||||
join(pkg, "package.json"),
|
||||
JSON.stringify({
|
||||
name: "route-plugin",
|
||||
version: "1.0.0",
|
||||
wrnexus: {
|
||||
permissions: ["routes"],
|
||||
routes: [{ kind: "api", path: "/api/plugin", entry: "./route.ts" }],
|
||||
},
|
||||
}),
|
||||
);
|
||||
await expect(
|
||||
discoverPlugins(app, undefined, { enforcePermissions: true, grantedPermissions: {} }),
|
||||
).rejects.toThrow("WRN-PLUGIN-PERMISSION-DENIED");
|
||||
await expect(
|
||||
discoverPlugins(app, undefined, {
|
||||
enforcePermissions: true,
|
||||
grantedPermissions: { "route-plugin": ["routes"] },
|
||||
}),
|
||||
).resolves.toBeDefined();
|
||||
|
||||
writeFileSync(
|
||||
join(pkg, "package.json"),
|
||||
JSON.stringify({
|
||||
name: "route-plugin",
|
||||
version: "1.0.0",
|
||||
wrnexus: { routes: [{ kind: "api", path: "/api/plugin", entry: "./route.ts" }] },
|
||||
}),
|
||||
);
|
||||
await expect(
|
||||
discoverPlugins(app, undefined, {
|
||||
enforcePermissions: true,
|
||||
grantedPermissions: { "route-plugin": ["routes"] },
|
||||
}),
|
||||
).rejects.toThrow("WRN-PLUGIN-PERMISSION-UNDECLARED");
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("orders package style contributions by pre, normal, and post", async () => {
|
||||
const runner = createPluginRunner(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user