unguard 0.2.0 → 0.4.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.
Files changed (137) hide show
  1. package/README.md +113 -0
  2. package/bin/unguard.mjs +2 -79
  3. package/dist/chunk-DYY4VK66.js +1105 -0
  4. package/dist/chunk-DYY4VK66.js.map +1 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.js +79 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/index.d.ts +110 -0
  9. package/dist/index.js +9 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +25 -16
  12. package/rulepacks/ts/rule-tests/__snapshots__/no-any-cast-snapshot.yml +0 -14
  13. package/rulepacks/ts/rule-tests/__snapshots__/no-double-negation-coercion-snapshot.yml +0 -26
  14. package/rulepacks/ts/rule-tests/__snapshots__/no-empty-catch-snapshot.yml +0 -14
  15. package/rulepacks/ts/rule-tests/__snapshots__/no-explicit-any-annotation-snapshot.yml +0 -20
  16. package/rulepacks/ts/rule-tests/__snapshots__/no-implicit-falsy-check-snapshot.yml +0 -14
  17. package/rulepacks/ts/rule-tests/__snapshots__/no-inline-type-in-params-snapshot.yml +0 -32
  18. package/rulepacks/ts/rule-tests/__snapshots__/no-logical-or-fallback-snapshot.yml +0 -100
  19. package/rulepacks/ts/rule-tests/__snapshots__/no-loose-nullish-check-snapshot.yml +0 -30
  20. package/rulepacks/ts/rule-tests/__snapshots__/no-non-null-assertion-snapshot.yml +0 -14
  21. package/rulepacks/ts/rule-tests/__snapshots__/no-null-ternary-normalization-snapshot.yml +0 -58
  22. package/rulepacks/ts/rule-tests/__snapshots__/no-nullish-coalescing-snapshot.yml +0 -20
  23. package/rulepacks/ts/rule-tests/__snapshots__/no-optional-call-snapshot.yml +0 -14
  24. package/rulepacks/ts/rule-tests/__snapshots__/no-optional-element-access-snapshot.yml +0 -8
  25. package/rulepacks/ts/rule-tests/__snapshots__/no-optional-property-access-snapshot.yml +0 -14
  26. package/rulepacks/ts/rule-tests/__snapshots__/no-redundant-existence-guard-snapshot.yml +0 -30
  27. package/rulepacks/ts/rule-tests/__snapshots__/no-redundant-optional-with-default-snapshot.yml +0 -12
  28. package/rulepacks/ts/rule-tests/__snapshots__/no-strict-nullish-check-snapshot.yml +0 -58
  29. package/rulepacks/ts/rule-tests/__snapshots__/no-ts-ignore-snapshot.yml +0 -14
  30. package/rulepacks/ts/rule-tests/__snapshots__/prefer-default-param-value-snapshot.yml +0 -14
  31. package/rulepacks/ts/rule-tests/__snapshots__/prefer-required-param-with-guard-snapshot.yml +0 -14
  32. package/rulepacks/ts/rule-tests/no-any-cast-test.yml +0 -7
  33. package/rulepacks/ts/rule-tests/no-double-negation-coercion-test.yml +0 -9
  34. package/rulepacks/ts/rule-tests/no-empty-catch-test.yml +0 -7
  35. package/rulepacks/ts/rule-tests/no-explicit-any-annotation-test.yml +0 -9
  36. package/rulepacks/ts/rule-tests/no-implicit-falsy-check-test.yml +0 -7
  37. package/rulepacks/ts/rule-tests/no-inline-type-in-params-test.yml +0 -9
  38. package/rulepacks/ts/rule-tests/no-logical-or-fallback-test.yml +0 -13
  39. package/rulepacks/ts/rule-tests/no-loose-nullish-check-test.yml +0 -8
  40. package/rulepacks/ts/rule-tests/no-non-null-assertion-test.yml +0 -7
  41. package/rulepacks/ts/rule-tests/no-null-ternary-normalization-test.yml +0 -9
  42. package/rulepacks/ts/rule-tests/no-nullish-coalescing-test.yml +0 -8
  43. package/rulepacks/ts/rule-tests/no-optional-call-test.yml +0 -7
  44. package/rulepacks/ts/rule-tests/no-optional-element-access-test.yml +0 -5
  45. package/rulepacks/ts/rule-tests/no-optional-property-access-test.yml +0 -6
  46. package/rulepacks/ts/rule-tests/no-redundant-existence-guard-test.yml +0 -7
  47. package/rulepacks/ts/rule-tests/no-redundant-optional-with-default-test.yml +0 -6
  48. package/rulepacks/ts/rule-tests/no-strict-nullish-check-test.yml +0 -9
  49. package/rulepacks/ts/rule-tests/no-ts-ignore-test.yml +0 -7
  50. package/rulepacks/ts/rule-tests/prefer-default-param-value-test.yml +0 -7
  51. package/rulepacks/ts/rule-tests/prefer-required-param-with-guard-test.yml +0 -7
  52. package/rulepacks/ts/rules/no-any-cast.yml +0 -10
  53. package/rulepacks/ts/rules/no-double-negation-coercion.yml +0 -6
  54. package/rulepacks/ts/rules/no-empty-catch.yml +0 -8
  55. package/rulepacks/ts/rules/no-explicit-any-annotation.yml +0 -11
  56. package/rulepacks/ts/rules/no-implicit-falsy-check.yml +0 -8
  57. package/rulepacks/ts/rules/no-inline-type-in-params.yml +0 -11
  58. package/rulepacks/ts/rules/no-logical-or-fallback.yml +0 -13
  59. package/rulepacks/ts/rules/no-loose-nullish-check.yml +0 -13
  60. package/rulepacks/ts/rules/no-non-null-assertion.yml +0 -6
  61. package/rulepacks/ts/rules/no-null-ternary-normalization.yml +0 -18
  62. package/rulepacks/ts/rules/no-nullish-coalescing.yml +0 -6
  63. package/rulepacks/ts/rules/no-optional-call.yml +0 -6
  64. package/rulepacks/ts/rules/no-optional-element-access.yml +0 -6
  65. package/rulepacks/ts/rules/no-optional-property-access.yml +0 -6
  66. package/rulepacks/ts/rules/no-redundant-existence-guard.yml +0 -12
  67. package/rulepacks/ts/rules/no-redundant-optional-with-default.yml +0 -8
  68. package/rulepacks/ts/rules/no-strict-nullish-check.yml +0 -13
  69. package/rulepacks/ts/rules/no-ts-ignore.yml +0 -7
  70. package/rulepacks/ts/rules/prefer-default-param-value.yml +0 -18
  71. package/rulepacks/ts/rules/prefer-required-param-with-guard.yml +0 -18
  72. package/rulepacks/ts/sgconfig.yml +0 -6
  73. package/rulepacks/ts/utils/is-literal.yml +0 -12
  74. package/rulepacks/ts/utils/is-nullish.yml +0 -6
  75. package/rulepacks/tsx/rule-tests/__snapshots__/no-any-cast-snapshot.yml +0 -14
  76. package/rulepacks/tsx/rule-tests/__snapshots__/no-double-negation-coercion-snapshot.yml +0 -26
  77. package/rulepacks/tsx/rule-tests/__snapshots__/no-empty-catch-snapshot.yml +0 -14
  78. package/rulepacks/tsx/rule-tests/__snapshots__/no-explicit-any-annotation-snapshot.yml +0 -20
  79. package/rulepacks/tsx/rule-tests/__snapshots__/no-implicit-falsy-check-snapshot.yml +0 -14
  80. package/rulepacks/tsx/rule-tests/__snapshots__/no-inline-type-in-params-snapshot.yml +0 -32
  81. package/rulepacks/tsx/rule-tests/__snapshots__/no-logical-or-fallback-snapshot.yml +0 -100
  82. package/rulepacks/tsx/rule-tests/__snapshots__/no-loose-nullish-check-snapshot.yml +0 -30
  83. package/rulepacks/tsx/rule-tests/__snapshots__/no-non-null-assertion-snapshot.yml +0 -14
  84. package/rulepacks/tsx/rule-tests/__snapshots__/no-null-ternary-normalization-snapshot.yml +0 -58
  85. package/rulepacks/tsx/rule-tests/__snapshots__/no-nullish-coalescing-snapshot.yml +0 -20
  86. package/rulepacks/tsx/rule-tests/__snapshots__/no-optional-call-snapshot.yml +0 -14
  87. package/rulepacks/tsx/rule-tests/__snapshots__/no-optional-element-access-snapshot.yml +0 -8
  88. package/rulepacks/tsx/rule-tests/__snapshots__/no-optional-property-access-snapshot.yml +0 -14
  89. package/rulepacks/tsx/rule-tests/__snapshots__/no-redundant-existence-guard-snapshot.yml +0 -30
  90. package/rulepacks/tsx/rule-tests/__snapshots__/no-redundant-optional-with-default-snapshot.yml +0 -12
  91. package/rulepacks/tsx/rule-tests/__snapshots__/no-strict-nullish-check-snapshot.yml +0 -58
  92. package/rulepacks/tsx/rule-tests/__snapshots__/no-ts-ignore-snapshot.yml +0 -14
  93. package/rulepacks/tsx/rule-tests/__snapshots__/prefer-default-param-value-snapshot.yml +0 -14
  94. package/rulepacks/tsx/rule-tests/__snapshots__/prefer-required-param-with-guard-snapshot.yml +0 -14
  95. package/rulepacks/tsx/rule-tests/no-any-cast-test.yml +0 -7
  96. package/rulepacks/tsx/rule-tests/no-double-negation-coercion-test.yml +0 -9
  97. package/rulepacks/tsx/rule-tests/no-empty-catch-test.yml +0 -7
  98. package/rulepacks/tsx/rule-tests/no-explicit-any-annotation-test.yml +0 -9
  99. package/rulepacks/tsx/rule-tests/no-implicit-falsy-check-test.yml +0 -7
  100. package/rulepacks/tsx/rule-tests/no-inline-type-in-params-test.yml +0 -9
  101. package/rulepacks/tsx/rule-tests/no-logical-or-fallback-test.yml +0 -13
  102. package/rulepacks/tsx/rule-tests/no-loose-nullish-check-test.yml +0 -8
  103. package/rulepacks/tsx/rule-tests/no-non-null-assertion-test.yml +0 -7
  104. package/rulepacks/tsx/rule-tests/no-null-ternary-normalization-test.yml +0 -9
  105. package/rulepacks/tsx/rule-tests/no-nullish-coalescing-test.yml +0 -8
  106. package/rulepacks/tsx/rule-tests/no-optional-call-test.yml +0 -7
  107. package/rulepacks/tsx/rule-tests/no-optional-element-access-test.yml +0 -5
  108. package/rulepacks/tsx/rule-tests/no-optional-property-access-test.yml +0 -6
  109. package/rulepacks/tsx/rule-tests/no-redundant-existence-guard-test.yml +0 -7
  110. package/rulepacks/tsx/rule-tests/no-redundant-optional-with-default-test.yml +0 -6
  111. package/rulepacks/tsx/rule-tests/no-strict-nullish-check-test.yml +0 -9
  112. package/rulepacks/tsx/rule-tests/no-ts-ignore-test.yml +0 -7
  113. package/rulepacks/tsx/rule-tests/prefer-default-param-value-test.yml +0 -7
  114. package/rulepacks/tsx/rule-tests/prefer-required-param-with-guard-test.yml +0 -7
  115. package/rulepacks/tsx/rules/no-any-cast.yml +0 -7
  116. package/rulepacks/tsx/rules/no-double-negation-coercion.yml +0 -7
  117. package/rulepacks/tsx/rules/no-empty-catch.yml +0 -8
  118. package/rulepacks/tsx/rules/no-explicit-any-annotation.yml +0 -12
  119. package/rulepacks/tsx/rules/no-implicit-falsy-check.yml +0 -8
  120. package/rulepacks/tsx/rules/no-inline-type-in-params.yml +0 -11
  121. package/rulepacks/tsx/rules/no-logical-or-fallback.yml +0 -14
  122. package/rulepacks/tsx/rules/no-loose-nullish-check.yml +0 -13
  123. package/rulepacks/tsx/rules/no-non-null-assertion.yml +0 -6
  124. package/rulepacks/tsx/rules/no-null-ternary-normalization.yml +0 -19
  125. package/rulepacks/tsx/rules/no-nullish-coalescing.yml +0 -7
  126. package/rulepacks/tsx/rules/no-optional-call.yml +0 -7
  127. package/rulepacks/tsx/rules/no-optional-element-access.yml +0 -7
  128. package/rulepacks/tsx/rules/no-optional-property-access.yml +0 -7
  129. package/rulepacks/tsx/rules/no-redundant-existence-guard.yml +0 -12
  130. package/rulepacks/tsx/rules/no-redundant-optional-with-default.yml +0 -9
  131. package/rulepacks/tsx/rules/no-strict-nullish-check.yml +0 -14
  132. package/rulepacks/tsx/rules/no-ts-ignore.yml +0 -8
  133. package/rulepacks/tsx/rules/prefer-default-param-value.yml +0 -43
  134. package/rulepacks/tsx/rules/prefer-required-param-with-guard.yml +0 -24
  135. package/rulepacks/tsx/sgconfig.yml +0 -6
  136. package/rulepacks/tsx/utils/is-literal.yml +0 -12
  137. package/rulepacks/tsx/utils/is-nullish.yml +0 -6
package/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # unguard
2
+
3
+ Unguard your code. Defend agains overdefensive AI-generated code.
4
+
5
+ Built on [oxc-parser](https://github.com/nicolo-ribaudo/oxc-parser-js).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g unguard
11
+ ```
12
+
13
+ or simply
14
+
15
+ ```bash
16
+ npx unguard
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ unguard src/
23
+ unguard src/ --strict # treat warnings as errors (CI)
24
+ unguard src/ --filter no-any-cast # run a single rule
25
+ ```
26
+
27
+ Add `unguard` to your lint check.
28
+
29
+ ## Current Rules
30
+
31
+ ### Type system evasion
32
+
33
+ | Rule | What it catches |
34
+ |------|----------------|
35
+ | `no-any-cast` | `x as any` |
36
+ | `no-explicit-any-annotation` | `param: any`, `const x: any` |
37
+ | `no-type-assertion` | `x as unknown as T` |
38
+ | `no-ts-ignore` | `@ts-ignore` / `@ts-expect-error` |
39
+
40
+ ### Defensive code
41
+
42
+ | Rule | What it catches |
43
+ |------|----------------|
44
+ | `no-optional-property-access` | `obj?.prop` |
45
+ | `no-optional-element-access` | `obj?.[key]` |
46
+ | `no-optional-call` | `fn?.()` |
47
+ | `no-nullish-coalescing` | `x ?? fallback` |
48
+ | `no-logical-or-fallback` | `x \|\| fallback` |
49
+ | `no-null-ternary-normalization` | `x == null ? fallback : x` |
50
+ | `no-non-null-assertion` | `x!` |
51
+ | `no-double-negation-coercion` | `!!value` |
52
+ | `no-redundant-existence-guard` | `obj && obj.prop` |
53
+
54
+ ### Error handling
55
+
56
+ | Rule | What it catches |
57
+ |------|----------------|
58
+ | `no-empty-catch` | `catch {}` with no body |
59
+ | `no-catch-return` | `catch { return fallback }` without rethrowing |
60
+ | `no-error-rewrap` | `throw new Error(e.message)` without `{ cause: e }` |
61
+
62
+ ### Interface design
63
+
64
+ | Rule | What it catches |
65
+ |------|----------------|
66
+ | `no-inline-type-in-params` | `fn(opts: { a: string; b: number })` |
67
+ | `prefer-default-param-value` | Optional param reassigned with `??` in the body |
68
+ | `prefer-required-param-with-guard` | `arg?: T` followed by `if (!arg) throw` |
69
+
70
+ ### Cross-file analysis
71
+
72
+ | Rule | What it catches |
73
+ |------|----------------|
74
+ | `duplicate-type-declaration` | Same type shape in multiple files |
75
+ | `duplicate-type-name` | Same exported type name, different shapes |
76
+ | `duplicate-function-declaration` | Same function body in multiple files |
77
+ | `duplicate-function-name` | Same exported function name, different bodies |
78
+ | `optional-arg-always-used` | Optional param provided at every call site |
79
+ | `explicit-null-arg` | `fn(null)` / `fn(undefined)` to project functions |
80
+
81
+ ### Imports
82
+
83
+ | Rule | What it catches |
84
+ |------|----------------|
85
+ | `no-dynamic-import` | `import("./module")` |
86
+
87
+ ## Annotations
88
+
89
+ Comments near flagged lines appear in the output as context:
90
+
91
+ ```typescript
92
+ // intentional escape hatch for untyped AST access
93
+ type AnyNode = Record<string, any>;
94
+ ```
95
+
96
+ ```txt
97
+ file.ts:2:31 warning Explicit `any` annotation ... (intentional escape hatch for untyped AST access)
98
+ ```
99
+
100
+ ## API
101
+
102
+ ```typescript
103
+ import { scan } from "unguard";
104
+
105
+ const result = await scan({ paths: ["src/"] });
106
+ for (const d of result.diagnostics) {
107
+ console.log(`${d.file}:${d.line} [${d.ruleId}] ${d.message}`);
108
+ }
109
+ ```
110
+
111
+ ## License
112
+
113
+ MIT
package/bin/unguard.mjs CHANGED
@@ -1,80 +1,3 @@
1
1
  #!/usr/bin/env node
2
-
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import crossSpawn from "cross-spawn";
6
-
7
- const binDir = path.dirname(fileURLToPath(import.meta.url));
8
- const packageRoot = path.resolve(binDir, "..");
9
- const localBinDir = path.join(packageRoot, "node_modules", ".bin");
10
-
11
- const rulepacks = [
12
- {
13
- configPath: path.join(packageRoot, "rulepacks", "ts", "sgconfig.yml"),
14
- globs: ["**/*.ts", "**/*.cts", "**/*.mts"],
15
- },
16
- {
17
- configPath: path.join(packageRoot, "rulepacks", "tsx", "sgconfig.yml"),
18
- globs: ["**/*.tsx"],
19
- },
20
- ];
21
-
22
- const rawArgs = process.argv.slice(2);
23
- const firstArg = rawArgs[0];
24
-
25
- if (firstArg === "-h" || firstArg === "--help") {
26
- console.log(`unguard: data-shape AST checker
27
-
28
- Usage:
29
- unguard scan [paths...] [ast-grep scan options]
30
- unguard scan [paths...] --strict
31
- unguard [paths...] [ast-grep scan options]
32
-
33
- Examples:
34
- unguard scan src
35
- unguard scan src --filter no-loose-nullish-check
36
- unguard scan src --strict
37
- unguard src --strict
38
- `);
39
- process.exit(0);
40
- }
41
-
42
- const userArgs = firstArg === "scan" ? rawArgs.slice(1) : rawArgs;
43
- const strictMode = userArgs.includes("--strict");
44
- const forwardedArgs = userArgs.filter((a) => a !== "--strict");
45
-
46
- const envPath = process.env.PATH
47
- ? `${localBinDir}${path.delimiter}${process.env.PATH}`
48
- : localBinDir;
49
-
50
- let finalStatus = 0;
51
- for (const rulepack of rulepacks) {
52
- const scanArgs = ["scan", "--config", rulepack.configPath, ...forwardedArgs];
53
- for (const glob of rulepack.globs) {
54
- scanArgs.push("--globs", glob);
55
- }
56
- if (strictMode) {
57
- scanArgs.push("--error");
58
- }
59
-
60
- const result = crossSpawn.sync("ast-grep", scanArgs, {
61
- stdio: "inherit",
62
- env: { ...process.env, PATH: envPath },
63
- });
64
-
65
- if (result.error) {
66
- if (result.error.code === "ENOENT") {
67
- console.error(
68
- "ast-grep binary not found. Run `npm install` in this package or install @ast-grep/cli globally.",
69
- );
70
- }
71
- console.error(result.error.message);
72
- process.exit(1);
73
- }
74
-
75
- if ((result.status ?? 0) !== 0) {
76
- finalStatus = result.status ?? 1;
77
- }
78
- }
79
-
80
- process.exit(finalStatus);
2
+ import { main } from "../dist/cli.js";
3
+ main(process.argv).then((code) => process.exit(code));