Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
149 lines
4.6 KiB
TypeScript
149 lines
4.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import type { Snippet } from "./models.ts";
|
|
import {
|
|
applySnippetPackagePathChange,
|
|
collectSnippetPackageTreePaths,
|
|
deleteSnippetPackage,
|
|
renameSnippetPackage,
|
|
} from "./snippetPackage.ts";
|
|
|
|
const snippet = (overrides: Partial<Snippet> & Pick<Snippet, "id">): Snippet => ({
|
|
label: overrides.label ?? overrides.id,
|
|
command: overrides.command ?? "echo ok",
|
|
package: "",
|
|
...overrides,
|
|
});
|
|
|
|
test("deleteSnippetPackage removes the package and descendants but keeps snippet bodies", () => {
|
|
const result = deleteSnippetPackage(
|
|
["ops", "ops/linux", "db"],
|
|
[
|
|
snippet({ id: "keep-ops", label: "Restart", command: "systemctl restart nginx", package: "ops" }),
|
|
snippet({ id: "keep-child", label: "Disk", command: "df -h", package: "ops/linux" }),
|
|
snippet({ id: "untouched", label: "PSQL", command: "psql", package: "db" }),
|
|
snippet({ id: "root", command: "uptime" }),
|
|
],
|
|
"ops",
|
|
);
|
|
|
|
assert.deepEqual(result.packages, ["db"]);
|
|
assert.deepEqual(
|
|
result.snippets.map((item) => ({
|
|
id: item.id,
|
|
package: item.package,
|
|
command: item.command,
|
|
label: item.label,
|
|
})),
|
|
[
|
|
{ id: "keep-ops", package: "", command: "systemctl restart nginx", label: "Restart" },
|
|
{ id: "keep-child", package: "", command: "df -h", label: "Disk" },
|
|
{ id: "untouched", package: "db", command: "psql", label: "PSQL" },
|
|
{ id: "root", package: "", command: "uptime", label: "root" },
|
|
],
|
|
);
|
|
});
|
|
|
|
test("renameSnippetPackage rewrites the package and descendant snippet paths", () => {
|
|
const result = renameSnippetPackage(
|
|
["ops", "ops/linux", "db"],
|
|
[
|
|
snippet({ id: "a", package: "ops" }),
|
|
snippet({ id: "b", package: "ops/linux" }),
|
|
snippet({ id: "c", package: "db" }),
|
|
],
|
|
"ops",
|
|
"platform",
|
|
);
|
|
|
|
assert.equal(result.ok, true);
|
|
if (!result.ok) return;
|
|
assert.equal(result.newPath, "platform");
|
|
assert.deepEqual(result.packages, ["platform", "platform/linux", "db"]);
|
|
assert.deepEqual(
|
|
result.snippets.map((item) => item.package),
|
|
["platform", "platform/linux", "db"],
|
|
);
|
|
});
|
|
|
|
test("renameSnippetPackage preserves a leading slash on absolute packages", () => {
|
|
const result = renameSnippetPackage(["/ops"], [snippet({ id: "a", package: "/ops" })], "/ops", "infra");
|
|
assert.equal(result.ok, true);
|
|
if (!result.ok) return;
|
|
assert.equal(result.newPath, "/infra");
|
|
assert.deepEqual(result.packages, ["/infra"]);
|
|
assert.equal(result.snippets[0].package, "/infra");
|
|
});
|
|
|
|
test("renameSnippetPackage rejects empty, invalid, and duplicate names", () => {
|
|
assert.deepEqual(
|
|
renameSnippetPackage(["ops"], [], "ops", " "),
|
|
{ ok: false, error: "empty" },
|
|
);
|
|
assert.deepEqual(
|
|
renameSnippetPackage(["ops"], [], "ops", "ops/linux"),
|
|
{ ok: false, error: "invalidChars" },
|
|
);
|
|
assert.deepEqual(
|
|
renameSnippetPackage(["ops", "db"], [], "ops", "DB"),
|
|
{ ok: false, error: "duplicate" },
|
|
);
|
|
});
|
|
|
|
test("renameSnippetPackage rejects collisions with inferred ancestor packages", () => {
|
|
assert.deepEqual(
|
|
renameSnippetPackage(["a", "b/x"], [], "a", "b"),
|
|
{ ok: false, error: "duplicate" },
|
|
);
|
|
assert.deepEqual(
|
|
renameSnippetPackage(["a", "B/x"], [], "a", "b"),
|
|
{ ok: false, error: "duplicate" },
|
|
);
|
|
});
|
|
|
|
test("renameSnippetPackage rejects collisions with snippet-implied packages", () => {
|
|
assert.deepEqual(
|
|
renameSnippetPackage(
|
|
["a"],
|
|
[snippet({ id: "s", package: "b/x" })],
|
|
"a",
|
|
"b",
|
|
),
|
|
{ ok: false, error: "duplicate" },
|
|
);
|
|
});
|
|
|
|
test("collectSnippetPackageTreePaths includes persisted and inferred ancestors", () => {
|
|
assert.deepEqual(
|
|
collectSnippetPackageTreePaths(["a", "b/x"], [snippet({ id: "s", package: "c/y" })]).sort(),
|
|
["a", "b", "b/x", "c", "c/y"],
|
|
);
|
|
});
|
|
|
|
test("renameSnippetPackage no-ops when the name is unchanged", () => {
|
|
const packages = ["ops"];
|
|
const snippets = [snippet({ id: "a", package: "ops" })];
|
|
const result = renameSnippetPackage(packages, snippets, "ops", "ops");
|
|
assert.equal(result.ok, true);
|
|
if (!result.ok) return;
|
|
assert.equal(result.newPath, "ops");
|
|
assert.equal(result.packages, packages);
|
|
assert.equal(result.snippets, snippets);
|
|
});
|
|
|
|
test("applySnippetPackagePathChange rewrites descendants and clears deleted paths", () => {
|
|
assert.equal(
|
|
applySnippetPackagePathChange("ops/linux", { from: "ops", to: "platform" }),
|
|
"platform/linux",
|
|
);
|
|
assert.equal(
|
|
applySnippetPackagePathChange("ops/linux", { from: "ops", to: null }),
|
|
"",
|
|
);
|
|
assert.equal(
|
|
applySnippetPackagePathChange("other", { from: "ops", to: "platform" }),
|
|
"other",
|
|
);
|
|
});
|