mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
Plugin discovery, esbuild builds (optional peer dependency), vm evaluation with pluginFile and mapStack, dependency installs, a watcher with dirty marks and rollout across hosts; host.load and host.reload per plugin with the closure rule; examples 35-39 as folders with real plugin directories.
95 lines
4.1 KiB
TypeScript
95 lines
4.1 KiB
TypeScript
// Tests of discovery (slice 7c §1): names from package.json, the first root winning a duplicate, directories reported
|
|
// (no or an invalid package.json, an invalid name, two files of one kind), contracts-only plugins, symlinks.
|
|
|
|
import { mkdir, realpath, symlink } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import { BACKGROUND_CONTEXT as context } from "../../../src/context/index.ts";
|
|
import { discoverPlugins } from "../../../src/next-node/plugins/index.ts";
|
|
import { KINDS, tempRoot, writeFiles, writePlugin } from "./support.ts";
|
|
|
|
describe("discovery", () => {
|
|
it("names a plugin by its package.json, lists its facet files by kind, its dependencies and externals", async () => {
|
|
const root = await tempRoot(["contracts", "notes"]);
|
|
const dir = await writePlugin(
|
|
root,
|
|
"deps-dir",
|
|
"@test/deps",
|
|
{ "worker.ts": "", "store.ts": "" },
|
|
{
|
|
dependencies: { marked: "1.0.0" },
|
|
chord: { external: ["better-sqlite3"] },
|
|
},
|
|
);
|
|
const { plugins, problems } = await discoverPlugins([root], { kinds: KINDS }, context);
|
|
expect(problems).toEqual([]);
|
|
const real = await realpath(root);
|
|
expect(plugins).toEqual([
|
|
{ name: "@test/contracts", dir: join(real, "contracts"), facets: {}, dependencies: [], external: [] },
|
|
{
|
|
name: "@test/deps",
|
|
dir: await realpath(dir),
|
|
facets: { worker: join(real, "deps-dir", "worker.ts") },
|
|
dependencies: ["marked"],
|
|
external: ["better-sqlite3"],
|
|
},
|
|
{
|
|
name: "@test/notes",
|
|
dir: join(real, "notes"),
|
|
facets: { server: join(real, "notes", "server.ts"), worker: join(real, "notes", "worker.ts") },
|
|
dependencies: [],
|
|
external: [],
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("reports a directory without package.json, with an invalid one, an invalid name or two files of a kind", async () => {
|
|
const root = await tempRoot();
|
|
await mkdir(join(root, "bare"));
|
|
await writeFiles(join(root, "broken"), { "package.json": "{ not json" });
|
|
await writePlugin(root, "invalid", "Not A Name", {});
|
|
await writePlugin(root, "two", "@test/two", { "worker.ts": "", "worker.js": "" });
|
|
await writePlugin(root, "good", "@test/good", { "web.tsx": "" });
|
|
// Not plugins and not reported: hidden directories and a root's own packages.
|
|
await mkdir(join(root, ".git"));
|
|
await mkdir(join(root, "node_modules"));
|
|
const { plugins, problems } = await discoverPlugins([root], { kinds: KINDS }, context);
|
|
expect(plugins.map(({ name }) => name)).toEqual(["@test/good"]);
|
|
const real = await realpath(root);
|
|
expect(problems).toEqual([
|
|
{ path: join(real, "bare"), error: "no package.json" },
|
|
{ path: join(real, "broken"), error: expect.stringMatching(/^package\.json: /) },
|
|
{ path: join(real, "invalid"), error: 'package.json: "Not A Name" is not a valid plugin name' },
|
|
{ path: join(real, "two"), error: "two worker facets: worker.ts, worker.js" },
|
|
]);
|
|
});
|
|
|
|
it("keeps the first root's plugin of a duplicate name and reports the other; a missing root is empty", async () => {
|
|
const first = await tempRoot();
|
|
const second = await tempRoot();
|
|
await writePlugin(first, "a", "@test/same", { "worker.ts": "" });
|
|
await writePlugin(second, "b", "@test/same", { "server.ts": "" });
|
|
const { plugins, problems } = await discoverPlugins(
|
|
[first, join(first, "missing"), second],
|
|
{ kinds: KINDS },
|
|
context,
|
|
);
|
|
expect(plugins.map(({ dir }) => dir)).toEqual([join(await realpath(first), "a")]);
|
|
expect(problems).toEqual([
|
|
{
|
|
path: join(await realpath(second), "b"),
|
|
error: `plugin "@test/same" is in ${join(await realpath(first), "a")} already`,
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("follows a symlinked plugin directory to its real path", async () => {
|
|
const elsewhere = await tempRoot();
|
|
const root = await tempRoot();
|
|
const dir = await writePlugin(elsewhere, "linked", "@test/linked", { "worker.ts": "" });
|
|
await symlink(dir, join(root, "link"));
|
|
const { plugins } = await discoverPlugins([root], { kinds: KINDS }, context);
|
|
expect(plugins.map((each) => [each.name, each.dir])).toEqual([["@test/linked", await realpath(dir)]]);
|
|
expect(plugins[0]!.facets).toEqual({ worker: join(await realpath(dir), "worker.ts") });
|
|
});
|
|
});
|