feat(FN-4956): complete Step 1 — add scope partition helper

Fusion-Task-Id: FN-4956
Fusion-Task-Lineage: 7105cd5e-27f4-4e84-b2ae-e811a183803f
This commit is contained in:
Fusion (runfusion.ai)
2026-05-18 00:36:28 -07:00
committed by gsxdsm
parent 9f22bf3ca3
commit 863fbeac0f
2 changed files with 98 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
import { describe, expect, it } from "vitest";
import { partitionConflictsByFileScope } from "../merger.js";
describe("partitionConflictsByFileScope", () => {
it("treats empty declared scope as no enforcement", () => {
const result = partitionConflictsByFileScope({
conflictFiles: ["AGENTS.md", "packages/core/src/store.ts"],
declaredScope: [],
});
expect(result).toEqual({
inScope: ["AGENTS.md", "packages/core/src/store.ts"],
outOfScope: [],
});
});
it("returns all in-scope files", () => {
const result = partitionConflictsByFileScope({
conflictFiles: ["packages/engine/src/merger.ts", "packages/engine/src/store.ts"],
declaredScope: ["packages/engine/src/**"],
});
expect(result).toEqual({
inScope: ["packages/engine/src/merger.ts", "packages/engine/src/store.ts"],
outOfScope: [],
});
});
it("returns all out-of-scope files", () => {
const result = partitionConflictsByFileScope({
conflictFiles: ["AGENTS.md", "packages/core/src/store.ts"],
declaredScope: ["packages/desktop/src/**"],
});
expect(result).toEqual({
inScope: [],
outOfScope: ["AGENTS.md", "packages/core/src/store.ts"],
});
});
it("partitions mixed files", () => {
const result = partitionConflictsByFileScope({
conflictFiles: ["packages/desktop/src/foo.ts", "packages/core/src/store.ts"],
declaredScope: ["packages/desktop/src/**"],
});
expect(result).toEqual({
inScope: ["packages/desktop/src/foo.ts"],
outOfScope: ["packages/core/src/store.ts"],
});
});
it("matches glob scope entries", () => {
const result = partitionConflictsByFileScope({
conflictFiles: ["packages/core/src/store.ts", "packages/core/test/store.test.ts"],
declaredScope: ["packages/core/src/**"],
});
expect(result).toEqual({
inScope: ["packages/core/src/store.ts"],
outOfScope: ["packages/core/test/store.test.ts"],
});
});
it("supports .changeset patterns", () => {
const result = partitionConflictsByFileScope({
conflictFiles: [".changeset/fn-4956.md", "AGENTS.md"],
declaredScope: [".changeset/*"],
});
expect(result).toEqual({
inScope: [".changeset/fn-4956.md"],
outOfScope: ["AGENTS.md"],
});
});
});

View File

@@ -3927,6 +3927,27 @@ export function matchesScope(filePath: string, scopePatterns: string[]): boolean
return false;
}
export function partitionConflictsByFileScope(params: {
conflictFiles: string[];
declaredScope: string[];
}): { inScope: string[]; outOfScope: string[] } {
const { conflictFiles, declaredScope } = params;
if (declaredScope.length === 0) {
return { inScope: [...conflictFiles], outOfScope: [] };
}
const inScope: string[] = [];
const outOfScope: string[] = [];
for (const file of conflictFiles) {
if (matchesScope(file, declaredScope)) {
inScope.push(file);
} else {
outOfScope.push(file);
}
}
return { inScope, outOfScope };
}
/**
* Validate that the diff stays within the task's declared File Scope.
* Returns warnings for out-of-scope changes, especially large deletions.