unguard 0.1.0
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/bin/unguard.mjs
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
const binDir = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const packageRoot = path.resolve(binDir, "..");
|
|
9
|
+
const configPath = path.join(packageRoot, "sgconfig.yml");
|
|
10
|
+
const localBinDir = path.join(packageRoot, "node_modules", ".bin");
|
|
11
|
+
|
|
12
|
+
const rawArgs = process.argv.slice(2);
|
|
13
|
+
const firstArg = rawArgs[0];
|
|
14
|
+
|
|
15
|
+
if (firstArg === "-h" || firstArg === "--help") {
|
|
16
|
+
console.log(
|
|
17
|
+
"unguard: data-shape AST checker\n\nUsage:\n unguard scan [paths...] [ast-grep scan options]\n unguard scan [paths...] --strict\n unguard [paths...] [ast-grep scan options]\n\nExamples:\n unguard scan src\n unguard scan src --filter no-loose-null-check\n unguard scan src --strict\n unguard src --strict\n",
|
|
18
|
+
);
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const isScanCommand = firstArg === "scan";
|
|
23
|
+
const userArgs = isScanCommand ? rawArgs.slice(1) : rawArgs;
|
|
24
|
+
|
|
25
|
+
const forwardedArgs = [];
|
|
26
|
+
let strictMode = false;
|
|
27
|
+
for (const arg of userArgs) {
|
|
28
|
+
if (arg === "--strict") {
|
|
29
|
+
strictMode = true;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
forwardedArgs.push(arg);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const scanArgs = ["scan", "--config", configPath, ...forwardedArgs];
|
|
36
|
+
if (strictMode) {
|
|
37
|
+
scanArgs.push("--error");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const astGrepBinary = process.platform === "win32" ? "ast-grep.cmd" : "ast-grep";
|
|
41
|
+
const envPath = process.env.PATH
|
|
42
|
+
? `${localBinDir}${path.delimiter}${process.env.PATH}`
|
|
43
|
+
: localBinDir;
|
|
44
|
+
|
|
45
|
+
const result = spawnSync(astGrepBinary, scanArgs, {
|
|
46
|
+
stdio: "inherit",
|
|
47
|
+
env: {
|
|
48
|
+
...process.env,
|
|
49
|
+
PATH: envPath,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (result.error) {
|
|
54
|
+
if (result.error.code === "ENOENT") {
|
|
55
|
+
console.error(
|
|
56
|
+
"ast-grep binary not found. Run `npm install` in this package or install @ast-grep/cli globally.",
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
console.error(result.error.message);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
process.exit(result.status ?? 0);
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "unguard",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Prove data-shape guarantees with ast-grep rule packs",
|
|
5
|
+
"author": "TwoAbove",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/TwoAbove/unguard.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/TwoAbove/unguard#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/TwoAbove/unguard/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"unguard": "./bin/unguard.mjs"
|
|
18
|
+
},
|
|
19
|
+
"files": ["bin", "rules", "sgconfig.yml"],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"scan": "node ./bin/unguard.mjs scan .",
|
|
22
|
+
"scan:strict": "node ./bin/unguard.mjs scan . --strict",
|
|
23
|
+
"test:rules": "ast-grep test -c sgconfig.yml",
|
|
24
|
+
"test:rules:update": "ast-grep test -c sgconfig.yml -U",
|
|
25
|
+
"prepublishOnly": "npm run test:rules"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@ast-grep/cli": "^0.39.4"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
id: no-nested-existence-guard
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: warning
|
|
4
|
+
message: Nested existence guards indicate missing boundary proof; enforce shape upstream
|
|
5
|
+
rule:
|
|
6
|
+
any:
|
|
7
|
+
- pattern: if ($OBJ && $OBJ.$PROP) { $$$BODY }
|
|
8
|
+
- pattern: if ($OBJ && $OBJ.$PROP) $STMT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
id: no-property-nullish-fallback
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: warning
|
|
4
|
+
message: Property nullish fallback hides upstream guarantees; validate earlier or throw
|
|
5
|
+
rule:
|
|
6
|
+
pattern: $VALUE ?? $DEFAULT
|
|
7
|
+
constraints:
|
|
8
|
+
VALUE:
|
|
9
|
+
all:
|
|
10
|
+
- kind: member_expression
|
|
11
|
+
- not:
|
|
12
|
+
regex: \?\.
|
package/sgconfig.yml
ADDED