@aliou/pi-guardrails 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -91,4 +91,52 @@ describe("classifyCommandArgs", () => {
|
|
|
91
91
|
expect(tokens("sort", ["-t", "/", "./file"])).toEqual(["./file"]);
|
|
92
92
|
expect(tokens("tr", ["/", ":"])).toEqual([]);
|
|
93
93
|
});
|
|
94
|
+
|
|
95
|
+
describe("go subcommand", () => {
|
|
96
|
+
it("skips Go package wildcard patterns", () => {
|
|
97
|
+
expect(tokens("go", ["test", "./..."])).toEqual([]);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("keeps go run .go file operands", () => {
|
|
101
|
+
expect(tokens("go", ["run", "main.go"])).toEqual(["main.go"]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("skips non-.go positionals for go run", () => {
|
|
105
|
+
expect(tokens("go", ["run", "-exec", "/bin/env", "main.go"])).toEqual([
|
|
106
|
+
"main.go",
|
|
107
|
+
]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("skips package patterns for build/vet/list", () => {
|
|
111
|
+
expect(tokens("go", ["build", "./..."])).toEqual([]);
|
|
112
|
+
expect(tokens("go", ["vet", "./pkg/..."])).toEqual([]);
|
|
113
|
+
expect(tokens("go", ["list", "./..."])).toEqual([]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("keeps file-valued flags", () => {
|
|
117
|
+
expect(tokens("go", ["build", "-modfile", "./go.mod", "./..."])).toEqual([
|
|
118
|
+
"./go.mod",
|
|
119
|
+
]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("keeps -o flag value for go build", () => {
|
|
123
|
+
expect(tokens("go", ["build", "-o", "./bin/app", "./..."])).toEqual([
|
|
124
|
+
"./bin/app",
|
|
125
|
+
]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("handles -C global flag before subcommand", () => {
|
|
129
|
+
expect(tokens("go", ["-C", "/tmp", "test", "./..."])).toEqual([]);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("handles -C joined form before subcommand", () => {
|
|
133
|
+
expect(tokens("go", ["-C=/tmp", "test", "./..."])).toEqual([]);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("keeps go run .go file operands with -C", () => {
|
|
137
|
+
expect(tokens("go", ["-C", "/tmp", "run", "main.go"])).toEqual([
|
|
138
|
+
"main.go",
|
|
139
|
+
]);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
94
142
|
});
|
|
@@ -32,6 +32,7 @@ export function classifyCommandArgs(
|
|
|
32
32
|
) {
|
|
33
33
|
return classifyInterpreterArgs(cmd, args);
|
|
34
34
|
}
|
|
35
|
+
if (cmd === "go") return classifyGoArgs(args);
|
|
35
36
|
if (cmd === "cut")
|
|
36
37
|
return skipOptionValues(args, new Set(["-d", "--delimiter"]));
|
|
37
38
|
if (cmd === "sort")
|
|
@@ -224,3 +225,73 @@ function skipOptionValues(
|
|
|
224
225
|
}
|
|
225
226
|
return out;
|
|
226
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Classify `go` subcommand arguments.
|
|
231
|
+
*
|
|
232
|
+
* Go commands take package patterns, not file paths, as positional args
|
|
233
|
+
* for most subcommands. Package patterns like `./...`, `pkg/...`,
|
|
234
|
+
* or `github.com/user/repo/...` use Go's `...` wildcard and are not
|
|
235
|
+
* filesystem paths.
|
|
236
|
+
*
|
|
237
|
+
* `go run` is an exception: it takes .go file operands, emitted with
|
|
238
|
+
* `forcePath` since bare filenames like `main.go` don't pass
|
|
239
|
+
* `maybePathLike`.
|
|
240
|
+
*
|
|
241
|
+
* File-valued flags (e.g. `-o`, `-modfile`, `-overlay`) are kept
|
|
242
|
+
* so that policy checks can still gate them.
|
|
243
|
+
*
|
|
244
|
+
* Global flags like `-C dir` are handled before subcommand detection
|
|
245
|
+
* so their values aren't mistaken for the subcommand.
|
|
246
|
+
*/
|
|
247
|
+
function classifyGoArgs(args: string[]): ClassifiedArg[] {
|
|
248
|
+
const out: ClassifiedArg[] = [];
|
|
249
|
+
const fileFlags = new Set(["-o", "-modfile", "-overlay"]);
|
|
250
|
+
|
|
251
|
+
// Global flags that consume a value and must be skipped before
|
|
252
|
+
// subcommand detection. E.g. `go -C /tmp test ./...`
|
|
253
|
+
const globalFlagsWithValues = new Set(["-C"]);
|
|
254
|
+
|
|
255
|
+
let subcommand: string | undefined;
|
|
256
|
+
for (let i = 0; i < args.length; i++) {
|
|
257
|
+
const arg = args[i] as string;
|
|
258
|
+
|
|
259
|
+
// Handle file-valued flags
|
|
260
|
+
if (fileFlags.has(arg)) {
|
|
261
|
+
if (args[i + 1]) out.push({ token: args[++i] as string });
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Handle joined file flags like -o=./bin/app
|
|
266
|
+
if (arg.startsWith("-o=")) {
|
|
267
|
+
out.push({ token: arg.slice(3) });
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Skip global flags with values before subcommand detection
|
|
272
|
+
if (!subcommand && globalFlagsWithValues.has(arg)) {
|
|
273
|
+
i++; // skip value
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (!subcommand && arg.startsWith("-C=")) {
|
|
277
|
+
// joined form -C=/tmp
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (isOption(arg)) continue;
|
|
282
|
+
|
|
283
|
+
// First non-flag positional is the subcommand
|
|
284
|
+
if (!subcommand) {
|
|
285
|
+
subcommand = arg;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// `go run` takes .go file operands; emit with forcePath since
|
|
290
|
+
// bare filenames like main.go don't pass maybePathLike.
|
|
291
|
+
// All other subcommands take package patterns; skip them.
|
|
292
|
+
if (subcommand === "run" && arg.endsWith(".go")) {
|
|
293
|
+
out.push({ token: arg, forcePath: true });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return out;
|
|
297
|
+
}
|
|
@@ -6,6 +6,27 @@ const CWD = "/work/project";
|
|
|
6
6
|
const HOME = homedir();
|
|
7
7
|
|
|
8
8
|
describe("extractBashPathCandidates", () => {
|
|
9
|
+
it("does not extract go package wildcard patterns as paths", async () => {
|
|
10
|
+
const result = await extractBashPathCandidates("go test ./...", CWD);
|
|
11
|
+
|
|
12
|
+
expect(result).toEqual([]);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("extracts go run .go file operands", async () => {
|
|
16
|
+
const result = await extractBashPathCandidates("go run main.go", CWD);
|
|
17
|
+
|
|
18
|
+
expect(result).toEqual(["/work/project/main.go"]);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("handles go -C global flag", async () => {
|
|
22
|
+
const result = await extractBashPathCandidates(
|
|
23
|
+
"go -C /tmp test ./...",
|
|
24
|
+
CWD,
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
expect(result).toEqual([]);
|
|
28
|
+
});
|
|
29
|
+
|
|
9
30
|
describe("when a command has regular expression arguments", () => {
|
|
10
31
|
it("ignores sed expressions and extracts file operands", async () => {
|
|
11
32
|
const result = await extractBashPathCandidates(
|