Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"@types/node": "^25.0.8",
"@vitest/coverage-v8": "^4.0.17",
"eslint": "^9.39.2",
"eslint-config-axkit": "^1.0.0",
"eslint-config-axkit": "^1.1.0",
"fta-check": "^1.5.1",
"fta-cli": "^3.0.0",
"knip": "^5.81.0",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 14 additions & 13 deletions src/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import type { Config } from "./config.js";

vi.mock("node:fs/promises");
vi.mock("./constants.js", async () => {
const actual =
await vi.importActual<typeof import("./constants.js")>("./constants.js");
const actual = await vi.importActual("./constants.js");
return {
...actual,
createConfigStore: vi.fn(),
Expand Down Expand Up @@ -88,7 +87,7 @@ describe("config", () => {
projects: [{ path: "~/Developer/project", rules: ["test.md"] }],
});
const config = parseConfig(json);
expect(typeof config.rulesSource).toBe("string");
expectTypeOf(config.rulesSource).toBeString();
expect(config.rulesSource).toMatch(/sync-rules[/\\]rules$/u);
expect(config.projects).toHaveLength(1);
expect(config.projects[0]?.path).toMatch(/\//u);
Expand All @@ -102,7 +101,7 @@ describe("config", () => {
projects: [{ path: "./test", rules: ["!test/**", "!**/*.md"] }],
});

expect(() => parseConfig(json)).toThrow(z.ZodError);
expect(() => parseConfig(json)).toThrowError(z.ZodError);

let zodError: z.ZodError | undefined;
try {
Expand All @@ -118,7 +117,7 @@ describe("config", () => {
).toBe(true);
});
it("throws SyntaxError for invalid JSON syntax", () => {
expect(() => parseConfig("{invalid}")).toThrow(SyntaxError);
expect(() => parseConfig("{invalid}")).toThrowError(SyntaxError);
});

// Missing projects and non-array projects are covered by table-driven tests below
Expand All @@ -143,7 +142,9 @@ describe("config", () => {
},
},
])("should reject invalid project shapes: $name", ({ payload }) => {
expect(() => parseConfig(JSON.stringify(payload))).toThrow(z.ZodError);
expect(() => parseConfig(JSON.stringify(payload))).toThrowError(
z.ZodError,
);
});

// Nested errors are covered by the table-driven test and multi-error tests below
Expand All @@ -157,7 +158,7 @@ describe("config", () => {
],
});

expect(() => parseConfig(json)).toThrow(z.ZodError);
expect(() => parseConfig(json)).toThrowError(z.ZodError);

let zodError: z.ZodError | undefined;
try {
Expand Down Expand Up @@ -328,7 +329,7 @@ describe("config", () => {

const promise = loadConfig(DEFAULT_CONFIG_PATH);

await expect(promise).rejects.toThrow(ConfigNotFoundError);
await expect(promise).rejects.toThrowError(ConfigNotFoundError);
await expect(promise).rejects.toMatchObject({
path: DEFAULT_CONFIG_PATH,
isDefault: true,
Expand All @@ -344,7 +345,7 @@ describe("config", () => {
store: {},
} as never);

await expect(loadConfig("/custom/config.json")).rejects.toThrow(
await expect(loadConfig("/custom/config.json")).rejects.toThrowError(
ConfigNotFoundError,
);
expect(fs.stat).toHaveBeenCalledTimes(1);
Expand All @@ -360,7 +361,7 @@ describe("config", () => {
} as never);

const promise = loadConfig("/path/to/config.json");
await expect(promise).rejects.toThrow(ConfigParseError);
await expect(promise).rejects.toThrowError(ConfigParseError);
await expect(promise).rejects.toMatchObject({
path: "/path/to/config.json",
});
Expand All @@ -375,7 +376,7 @@ describe("config", () => {
store: {},
} as never);

await expect(loadConfig("/path/to/config.json")).rejects.toThrow(
await expect(loadConfig("/path/to/config.json")).rejects.toThrowError(
ConfigAccessError,
);

Expand All @@ -394,7 +395,7 @@ describe("config", () => {
} as never);

const promise = loadConfig("/path/to/config.json");
await expect(promise).rejects.toThrow(ConfigAccessError);
await expect(promise).rejects.toThrowError(ConfigAccessError);
await expect(promise).rejects.toMatchObject({
path: "/path/to/config.json",
});
Expand All @@ -414,7 +415,7 @@ describe("config", () => {
isFile: () => true,
} as never);

await expect(loadConfig("/path/to/config.json")).rejects.toThrow(
await expect(loadConfig("/path/to/config.json")).rejects.toThrowError(
ConfigParseError,
);
});
Expand Down
12 changes: 6 additions & 6 deletions src/core/execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ describe("executeActions - algorithm tests", () => {
{ path: "/test/file.txt", content: "Hello" },
];

await expect(executeActions(actions, { dryRun: false })).rejects.toThrow(
Error,
);
await expect(
executeActions(actions, { dryRun: false }),
).rejects.toThrowError(Error);
});

it("stops on first write error", async () => {
Expand All @@ -65,9 +65,9 @@ describe("executeActions - algorithm tests", () => {
{ path: "/success/file.txt", content: "World" },
];

await expect(executeActions(actions, { dryRun: false })).rejects.toThrow(
Error,
);
await expect(
executeActions(actions, { dryRun: false }),
).rejects.toThrowError(Error);

expect(fsPromises.writeFile).toHaveBeenCalledTimes(1);
});
Expand Down
2 changes: 1 addition & 1 deletion src/core/sync-global.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,6 @@ describe("sync-global", () => {
const paths = actionsArgument.map((action) => action.path);
expect(paths.some((p) => p.endsWith("/.claude/CLAUDE.md"))).toBe(true);
expect(paths.some((p) => p.endsWith("/.codex/AGENTS.md"))).toBe(true);
expect(result.written.length).toBe(2);
expect(result.written).toHaveLength(2);
});
});
10 changes: 5 additions & 5 deletions src/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class SyncError extends Error {

constructor(message: string, details: SyncErrorDetails = {}, cause?: Error) {
super(message, { cause });
this.name = this.constructor.name;
this.name = "SyncError";
this.details = details;
}
}
Expand All @@ -35,7 +35,7 @@ export class ConfigNotFoundError extends Error {
super(
`${location} not found at ${path}.\n${hint}\nTry 'sync-rules --help' for details.`,
);
this.name = this.constructor.name;
this.name = "ConfigNotFoundError";
this.path = path;
this.isDefault = isDefault;
}
Expand All @@ -55,7 +55,7 @@ export class ConfigAccessError extends Error {
const hint = "Check the file path and permissions.";
const baseWithPeriod = /[.!?]$/u.test(base) ? base : `${base}.`;
super(`${baseWithPeriod}\n${hint}`, { cause: originalError });
this.name = this.constructor.name;
this.name = "ConfigAccessError";
this.path = path;
this.originalError = originalError;
}
Expand All @@ -76,7 +76,7 @@ export class ConfigParseError extends Error {
"Fix the JSON and glob patterns, then retry.\nTry 'sync-rules --help' for schema and examples.";
const baseWithPeriod = /[.!?]$/u.test(base) ? base : `${base}.`;
super(`${baseWithPeriod}\n${hint}`, { cause: originalError });
this.name = this.constructor.name;
this.name = "ConfigParseError";
this.path = path;
this.originalError = originalError;
}
Expand All @@ -100,7 +100,7 @@ export class SpawnError extends Error {
) {
const message = SpawnError.buildMessage(command, code, exitCode, signal);
super(message, { cause });
this.name = this.constructor.name;
this.name = "SpawnError";
this.command = command;
this.code = code;
this.exitCode = exitCode;
Expand Down
6 changes: 3 additions & 3 deletions src/utils/paths.resolveInside.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ describe("resolveInside", () => {
});

it("rejects path traversal attempts with ../ segments", () => {
expect(() => resolveInside(baseDirectory, "../../etc/passwd")).toThrow(
expect(() => resolveInside(baseDirectory, "../../etc/passwd")).toThrowError(
/Refusing to write outside/u,
);
});

it("rejects absolute paths outside base directory", () => {
expect(() => resolveInside(baseDirectory, "/etc/passwd")).toThrow(
expect(() => resolveInside(baseDirectory, "/etc/passwd")).toThrowError(
/Refusing to write outside/u,
);
});
Expand All @@ -30,6 +30,6 @@ describe("resolveInside", () => {
it("rejects complex traversal attempts", () => {
expect(() =>
resolveInside(baseDirectory, "valid/../../../etc/passwd"),
).toThrow(/Refusing to write outside/u);
).toThrowError(/Refusing to write outside/u);
});
});
2 changes: 1 addition & 1 deletion tests/integration/rules-fs.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ describe("filesystem operations", () => {

await expect(
readRuleContents(rulesDirectory, relativePaths),
).rejects.toThrow(/Failed to read rule file.*nonexistent\.md/u);
).rejects.toThrowError(/Failed to read rule file.*nonexistent\.md/u);
});
});
});
Loading