@fabriziosalmi/slopless 1.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 (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -0
  3. package/dist/engine/api.d.ts +16 -0
  4. package/dist/engine/api.js +543 -0
  5. package/dist/index.d.ts +122 -0
  6. package/dist/index.js +590 -0
  7. package/package.json +59 -0
  8. package/rules/VBC-001.yaml +33 -0
  9. package/rules/VBC-002.yaml +13 -0
  10. package/rules/VBC-003.yaml +36 -0
  11. package/rules/VBC-004.yaml +33 -0
  12. package/rules/VBC-005.yaml +24 -0
  13. package/rules/VBC-006.yaml +16 -0
  14. package/rules/VBC-007.yaml +28 -0
  15. package/rules/VBC-008.yaml +21 -0
  16. package/rules/VBC-009.yaml +24 -0
  17. package/rules/VBC-010.yaml +24 -0
  18. package/rules/VBC-011.yaml +21 -0
  19. package/rules/VBC-012.yaml +21 -0
  20. package/rules/VBC-013.yaml +17 -0
  21. package/rules/VBC-014.yaml +15 -0
  22. package/rules/VBC-015.yaml +40 -0
  23. package/rules/VBC-016.yaml +21 -0
  24. package/rules/VBC-017.yaml +23 -0
  25. package/rules/VBC-018.yaml +19 -0
  26. package/rules/VBC-019.yaml +42 -0
  27. package/rules/VBC-020.yaml +22 -0
  28. package/rules/VBC-021.yaml +22 -0
  29. package/rules/VBC-022.yaml +21 -0
  30. package/rules/VBC-023.yaml +22 -0
  31. package/rules/VBC-024.yaml +26 -0
  32. package/rules/VBC-025.yaml +13 -0
  33. package/rules/VBC-026.yaml +17 -0
  34. package/rules/VBC-027.yaml +27 -0
  35. package/rules/VBC-028.yaml +18 -0
  36. package/rules/VBC-029.yaml +22 -0
  37. package/rules/VBC-030.yaml +22 -0
  38. package/rules/VBC-032.yaml +20 -0
  39. package/rules/VBC-033.yaml +26 -0
  40. package/rules/VBC-034.yaml +41 -0
  41. package/rules/VBC-035.yaml +30 -0
  42. package/rules/VBC-039.yaml +18 -0
  43. package/rules/VBC-042.yaml +26 -0
  44. package/rules/VBC-045.yaml +13 -0
  45. package/rules/VBC-046.yaml +13 -0
  46. package/rules/VBC-048.yaml +23 -0
  47. package/rules/VBC-049.yaml +19 -0
  48. package/rules/VBC-051.yaml +23 -0
  49. package/rules/VBC-052.yaml +19 -0
  50. package/rules/VBC-053.yaml +19 -0
  51. package/rules/VBC-054.yaml +29 -0
  52. package/rules/VBC-056.yaml +28 -0
  53. package/rules/VBC-057.yaml +18 -0
  54. package/rules/VBC-058.yaml +18 -0
  55. package/rules/VBC-059.yaml +21 -0
  56. package/rules/VBC-063-B.yaml +15 -0
  57. package/rules/VBC-063.yaml +18 -0
  58. package/rules/VBC-065.yaml +33 -0
  59. package/rules/VBC-066.yaml +16 -0
  60. package/rules/VBC-068.yaml +21 -0
  61. package/rules/VBC-070.yaml +19 -0
  62. package/rules/VBC-077.yaml +35 -0
  63. package/rules/VBC-079.yaml +18 -0
  64. package/rules/VBC-080.yaml +18 -0
  65. package/rules/VBC-084.yaml +22 -0
  66. package/rules/VBC-086.yaml +22 -0
  67. package/rules/VBC-090.yaml +28 -0
  68. package/rules/VBC-096.yaml +19 -0
  69. package/rules/VBC-097.yaml +21 -0
  70. package/rules/VBC-098.yaml +18 -0
  71. package/rules/VBC-101.yaml +23 -0
  72. package/rules/VBC-102.yaml +20 -0
  73. package/rules/VBC-103.yaml +35 -0
  74. package/rules/VBC-104.yaml +24 -0
  75. package/rules/VBC-106.yaml +14 -0
  76. package/rules/VBC-112.yaml +20 -0
  77. package/rules/VBC-113.yaml +19 -0
  78. package/rules/VBC-117.yaml +21 -0
  79. package/rules/VBC-123.yaml +29 -0
  80. package/rules/VBC-131.yaml +20 -0
  81. package/rules/VBC-150.yaml +27 -0
  82. package/rules/VBC-153.yaml +21 -0
  83. package/rules/VBC-158.yaml +16 -0
  84. package/rules/VBC-161.yaml +27 -0
  85. package/rules/VBC-172.yaml +25 -0
  86. package/rules/VBC-197.yaml +22 -0
  87. package/rules/VBC-201.yaml +35 -0
  88. package/rules/VBC-206.yaml +19 -0
  89. package/rules/VBC-208.yaml +27 -0
  90. package/rules/VBC-212.yaml +19 -0
  91. package/rules/VBC-215.yaml +24 -0
  92. package/rules/VBC-305.yaml +20 -0
  93. package/rules/VBC-324.yaml +24 -0
  94. package/rules/VBC-334.yaml +23 -0
  95. package/rules/VBC-338.yaml +32 -0
  96. package/rules/VBC-340.yaml +22 -0
  97. package/rules/VBC-344.yaml +19 -0
  98. package/rules/VBC-347.yaml +21 -0
  99. package/rules/VBC-348.yaml +19 -0
  100. package/rules/VBC-385.yaml +21 -0
  101. package/rules/VBC-398.yaml +22 -0
  102. package/rules/VBC-401.yaml +12 -0
  103. package/rules/VBC-414.yaml +23 -0
  104. package/rules/VBC-421.yaml +20 -0
  105. package/rules/VBC-501.yaml +18 -0
  106. package/rules/VBC-502.yaml +23 -0
  107. package/rules/VBC-503.yaml +18 -0
  108. package/rules/VBC-504.yaml +20 -0
  109. package/rules/VBC-800.yaml +17 -0
  110. package/rules/VBC-901.yaml +48 -0
  111. package/rules/VBC-902.yaml +19 -0
  112. package/rules/VBC-903.yaml +17 -0
  113. package/rules/VBC-904.yaml +21 -0
  114. package/rules/VBC-905.yaml +17 -0
  115. package/rules/VBC-906.yaml +29 -0
  116. package/rules/VBC-907.yaml +24 -0
  117. package/rules/VBC-908.yaml +22 -0
  118. package/rules/VBC-909.yaml +21 -0
  119. package/rules/VBC-910.yaml +18 -0
  120. package/rules/VBC-911.yaml +21 -0
  121. package/rules/VBC-913.yaml +30 -0
  122. package/rules/VBC-914.yaml +31 -0
  123. package/rules/VBC-915.yaml +19 -0
  124. package/rules/VBC-916.yaml +24 -0
  125. package/rules/VBC-917.yaml +21 -0
  126. package/rules/VBC-918.yaml +22 -0
  127. package/rules/VBC-920.yaml +20 -0
  128. package/rules/VBC-921.yaml +45 -0
  129. package/rules/VBC-922.yaml +15 -0
  130. package/rules/VBC-923.yaml +15 -0
  131. package/rules/VBC-924.yaml +12 -0
  132. package/rules/VBC-925.yaml +14 -0
  133. package/rules/VBC-926.yaml +14 -0
  134. package/rules/VBC-927.yaml +24 -0
  135. package/rules/VBC-928.yaml +25 -0
  136. package/rules/VBC-929.yaml +21 -0
  137. package/rules/VBC-930.yaml +16 -0
  138. package/rules/VBC-931.yaml +16 -0
  139. package/rules/VBC-932.yaml +16 -0
  140. package/rules/VBC-933.yaml +28 -0
  141. package/rules/VBC-934.yaml +24 -0
  142. package/rules/VBC-935.yaml +26 -0
  143. package/rules/VBC-936.yaml +24 -0
  144. package/rules/VBC-937.yaml +24 -0
  145. package/rules/VBC-938.yaml +23 -0
  146. package/rules/VBC-939.yaml +23 -0
  147. package/rules/VBC-940.yaml +30 -0
  148. package/rules/VBC-941.yaml +28 -0
  149. package/rules/VBC-942.yaml +23 -0
  150. package/rules/VBC-943.yaml +22 -0
  151. package/rules/VBC-944.yaml +26 -0
  152. package/rules/VBC-945.yaml +33 -0
  153. package/rules/VBC-946.yaml +26 -0
  154. package/rules/VBC-947.yaml +22 -0
  155. package/rules/VBC-948.yaml +26 -0
@@ -0,0 +1,13 @@
1
+ id: VBC-025
2
+ name: missing-gitignore
3
+ severity: error
4
+ category: git
5
+ tags:
6
+ - git
7
+ - project-health
8
+ match:
9
+ git_check: missing_gitignore
10
+ message: >-
11
+ Missing .gitignore file. This often lead to committed dependencies or secrets.
12
+ tests:
13
+ external: 'git-checker.test.ts: needs a repository working tree'
@@ -0,0 +1,17 @@
1
+ id: VBC-026
2
+ name: empty-file
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ - project-health
8
+ match:
9
+ ast_check:
10
+ type: empty-file
11
+ message: Empty code file detected. This clutters the repository.
12
+ tests:
13
+ fire:
14
+ - ''
15
+ - " \n"
16
+ quiet:
17
+ - export const answer = 42;
@@ -0,0 +1,27 @@
1
+ id: VBC-027
2
+ name: parallax-overuse
3
+ severity: warning
4
+ category: ux-dx
5
+ tags:
6
+ - ux
7
+ - performance
8
+ - accessibility
9
+ match:
10
+ regex: >-
11
+ (scrollY\s*\*\s*0\.[0-9]+|\.parallax\b|parallax[-_]container|data-parallax)
12
+ flags: i
13
+ file_types:
14
+ - js
15
+ - ts
16
+ - css
17
+ - scss
18
+ message: >-
19
+ Parallax scrolling effect detected at line {line}. Parallax effects can trigger vestibular
20
+ disorders (nausea, dizziness) in sensitive users, carry significant GPU cost, and break
21
+ on mobile. Respect prefers-reduced-motion and consider whether the effect adds genuine value.
22
+ tests:
23
+ fire:
24
+ - el.style.top = scrollY * 0.4 + "px";
25
+ - '.parallax { top: 0; }'
26
+ quiet:
27
+ - el.style.top = offset + "px";
@@ -0,0 +1,18 @@
1
+ id: VBC-028
2
+ name: function-params-limit
3
+ severity: warning
4
+ category: core
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ ast_check:
9
+ type: function-params-limit
10
+ threshold: 5
11
+ message: >-
12
+ Function takes {count} parameters at line {line}, over the limit of {threshold}. Positional
13
+ arguments are easy to pass in the wrong order. Take an options object, or split the function.
14
+ tests:
15
+ fire:
16
+ - function build(a, b, c, d, e, f) { return a; }
17
+ quiet:
18
+ - function build(a, b) { return a + b; }
@@ -0,0 +1,22 @@
1
+ id: VBC-029
2
+ name: glassmorphism-overuse
3
+ severity: warning
4
+ category: ux-dx
5
+ tags:
6
+ - ux
7
+ - performance
8
+ match:
9
+ regex: backdrop-filter:\s*blur\(
10
+ file_types:
11
+ - css
12
+ - scss
13
+ - less
14
+ message: >-
15
+ backdrop-filter:blur() (glassmorphism) at line {line}. This effect forces GPU compositing
16
+ on every frame, severely impacting performance on low-end and mobile devices. It also frequently
17
+ reduces text contrast below accessibility thresholds. Use sparingly and test on real hardware.
18
+ tests:
19
+ fire:
20
+ - '.card { backdrop-filter: blur(12px); }'
21
+ quiet:
22
+ - '.card { background: var(--surface); }'
@@ -0,0 +1,22 @@
1
+ id: VBC-030
2
+ name: confetti-overuse
3
+ severity: warning
4
+ category: ux-dx
5
+ tags:
6
+ - ux
7
+ - performance
8
+ match:
9
+ regex: (confetti\(|canvas-confetti|party\.js|tsParticles\.load)
10
+ flags: i
11
+ file_types:
12
+ - js
13
+ - ts
14
+ message: >-
15
+ Confetti or particle animation library detected at line {line}. Overusing celebration effects
16
+ devalues them and creates visual noise. Reserve confetti for genuinely significant milestones
17
+ (first purchase, account creation) rather than every successful action.
18
+ tests:
19
+ fire:
20
+ - 'confetti({ particleCount: 120 });'
21
+ quiet:
22
+ - showSuccessToast();
@@ -0,0 +1,20 @@
1
+ id: VBC-032
2
+ name: css-important
3
+ severity: warning
4
+ category: core
5
+ tags:
6
+ - style
7
+ - css
8
+ match:
9
+ regex: '!important'
10
+ file_types:
11
+ - css
12
+ - scss
13
+ - less
14
+ message: >-
15
+ Global '!important' detected in CSS at line {line}. This breaks the cascade.
16
+ tests:
17
+ fire:
18
+ - '.card { color: red !important; }'
19
+ quiet:
20
+ - '.card { color: red; }'
@@ -0,0 +1,26 @@
1
+ id: VBC-033
2
+ name: placeholder-image-src
3
+ severity: error
4
+ category: ux-dx
5
+ tags:
6
+ - ux
7
+ - slop
8
+ match:
9
+ regex: >-
10
+ (src|href)=['"](https?://)?(via\.placeholder\.com|picsum\.photos|placehold\.co|dummyimage\.com|loremflickr\.com|placekitten\.com)[^'"]*['"]
11
+ flags: i
12
+ file_types:
13
+ - html
14
+ - js
15
+ - ts
16
+ - tsx
17
+ - jsx
18
+ message: >-
19
+ Placeholder image service URL detected at line {line}. External placeholder services break
20
+ when the service is down, look unfinished, and represent content that was never completed.
21
+ Replace with real production images.
22
+ tests:
23
+ fire:
24
+ - <img src="https://via.placeholder.com/400" alt="x" />
25
+ quiet:
26
+ - <img src="/assets/hero.png" alt="Hero" />
@@ -0,0 +1,41 @@
1
+ id: VBC-034
2
+ name: http-not-https
3
+ severity: error
4
+ category: security
5
+ tags:
6
+ - security
7
+ match:
8
+ regex: >-
9
+ http://(?!localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\]|test\b|example\.(?:com|org)|www\.w3\.org|schemas?\.|json-schema\.org|purl\.org|ns\.adobe|www\.apache\.org)
10
+ scan: strings
11
+ file_types:
12
+ - js
13
+ - ts
14
+ - py
15
+ - html
16
+ exclude_files:
17
+ - '**/test/**'
18
+ - '**/tests/**'
19
+ - '**/__tests__/**'
20
+ - '**/testdata/**'
21
+ - '**/fixtures/**'
22
+ - '**/test_*.py'
23
+ - '**/*_test.py'
24
+ - '**/test.py'
25
+ - '**/conftest.py'
26
+ - '**/*_test.go'
27
+ - '**/*_bench.go'
28
+ - '**/*.test.*'
29
+ - '**/*.spec.*'
30
+ - '**/bench/**'
31
+ - '**/benchmark*'
32
+ - '**/*corpus*'
33
+ - '**/*payload*'
34
+ message: Insecure http:// link detected at line {line}. Use https:// instead.
35
+ tests:
36
+ fire:
37
+ - const api = 'http://api.example.com/v1';
38
+ quiet:
39
+ - const api = 'https://api.example.com/v1';
40
+ - const dev = 'http://localhost:3000';
41
+ - const svg = 'http://www.w3.org/2000/svg';
@@ -0,0 +1,30 @@
1
+ id: VBC-035
2
+ name: aria-label-icon-button
3
+ severity: error
4
+ category: ux-dx
5
+ tags:
6
+ - accessibility
7
+ match:
8
+ regex: <button\b(?![^>]*(?:aria-label|aria-labelledby|title))[^>]*>\s*<svg
9
+ multiline: true
10
+ file_types:
11
+ - html
12
+ - tsx
13
+ - jsx
14
+ message: >-
15
+ Icon-only button without aria-label at line {line}. A button containing only an SVG icon
16
+ has no accessible name, making it completely opaque to screen readers. Add aria-label="Descriptive
17
+ action" to every icon-only button.
18
+ tests:
19
+ fire:
20
+ - file: fixture.tsx
21
+ code: |
22
+ <button onClick={close}>
23
+ <svg viewBox="0 0 24 24" />
24
+ </button>
25
+ quiet:
26
+ - file: fixture.tsx
27
+ code: |
28
+ <button aria-label="Close" onClick={close}>
29
+ <svg viewBox="0 0 24 24" />
30
+ </button>
@@ -0,0 +1,18 @@
1
+ id: VBC-039
2
+ name: use-eval
3
+ severity: error
4
+ category: core
5
+ tags:
6
+ - security
7
+ match:
8
+ regex: eval\(
9
+ file_types:
10
+ - js
11
+ - ts
12
+ message: >-
13
+ Use of 'eval()' detected at line {line}. This is a massive security risk.
14
+ tests:
15
+ fire:
16
+ - eval(userInput);
17
+ quiet:
18
+ - JSON.parse(userInput);
@@ -0,0 +1,26 @@
1
+ id: VBC-042
2
+ name: too-many-comments
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: (?:^[ \t]*//.*\n){10,}
9
+ flags: m
10
+ multiline: true
11
+ scan: all
12
+ file_types:
13
+ - js
14
+ - ts
15
+ - py
16
+ message: >-
17
+ Too many consecutive comment lines at line {line}. Code should be self-documenting.
18
+ tests:
19
+ fire:
20
+ - code: |
21
+ // filler comment line
22
+ repeat: 12
23
+ quiet:
24
+ - |
25
+ // one explanatory comment
26
+ const answer = 42;
@@ -0,0 +1,13 @@
1
+ id: VBC-045
2
+ name: missing-license
3
+ severity: warning
4
+ category: git
5
+ tags:
6
+ - git
7
+ - project-health
8
+ match:
9
+ git_check: missing_license
10
+ message: >-
11
+ Missing LICENSE file. Every open source project should define its terms of use.
12
+ tests:
13
+ external: 'git-checker.test.ts: needs a repository working tree'
@@ -0,0 +1,13 @@
1
+ id: VBC-046
2
+ name: binary-files-in-git
3
+ severity: warning
4
+ category: git
5
+ tags:
6
+ - git
7
+ - performance
8
+ match:
9
+ git_check: binary_file
10
+ message: >-
11
+ Binary file committed to Git. Large binaries should use Git LFS or be stored externally.
12
+ tests:
13
+ external: 'git-checker.test.ts: needs a staged file list'
@@ -0,0 +1,23 @@
1
+ id: VBC-048
2
+ name: meaningless-variable-names
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: >-
9
+ \b(?:let|const|var)\s+(?:temp|tmp|obj|variable|thing|stuff|foo|bar|baz|qux|myVar|test1|data2)\b
10
+ file_types:
11
+ - js
12
+ - ts
13
+ - py
14
+ message: >-
15
+ Meaningless variable name '{match}' detected at line {line}. Use descriptive names that
16
+ convey intent.
17
+ tests:
18
+ fire:
19
+ - const temp = load();
20
+ - let thing = compute();
21
+ quiet:
22
+ - const invoiceTotal = load();
23
+ - const data = await response.json();
@@ -0,0 +1,19 @@
1
+ id: VBC-049
2
+ name: magic-boolean
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: \b[a-zA-Z0-9_]+\((true|false)\s*,
9
+ file_types:
10
+ - js
11
+ - ts
12
+ message: >-
13
+ Magic boolean passed as first argument at line {line}. Use named parameters or a descriptive
14
+ variable.
15
+ tests:
16
+ fire:
17
+ - renderList(true, items);
18
+ quiet:
19
+ - 'renderList({ compact: true }, items);'
@@ -0,0 +1,23 @@
1
+ id: VBC-051
2
+ name: mixed-casing
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ - style
8
+ match:
9
+ regex: >-
10
+ ((?<![.'\"])\b[a-z]+_[a-z]+\b(?!\s*[:?]).*?\b[a-z]+[A-Z][a-z]+\b)|(\b[a-z]+[A-Z][a-z]+\b.*?(?<![.'\"])\b[a-z]+_[a-z]+\b(?!\s*[:?]))
11
+ file_types:
12
+ - js
13
+ - ts
14
+ message: >-
15
+ snake_case and camelCase mixed at line {line}. Pick one convention per file. Object keys
16
+ are not reported: a wire format often dictates those names.
17
+ tests:
18
+ fire:
19
+ - const user_name = userName;
20
+ quiet:
21
+ - const userName = firstName;
22
+ - 'max_tokens: Math.min(maxTokens, 1024),'
23
+ - 'const body = { used_tokens: usedTokens };'
@@ -0,0 +1,19 @@
1
+ id: VBC-052
2
+ name: single-letter-variables
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: \b(?:let|const|var)\s+(?!(?:i|j|k|n|x|y|z|e|t|_)\b)[a-z]\b
9
+ file_types:
10
+ - js
11
+ - ts
12
+ message: >-
13
+ Single-letter variable name detected at line {line}. Use more descriptive names.
14
+ tests:
15
+ fire:
16
+ - const p = loadProfile();
17
+ quiet:
18
+ - const profile = loadProfile();
19
+ - for (const i of items) { use(i); }
@@ -0,0 +1,19 @@
1
+ id: VBC-053
2
+ name: redundant-interpolation
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: '`\$\{[a-zA-Z0-9_]+\}`'
9
+ scan: all
10
+ file_types:
11
+ - js
12
+ - ts
13
+ message: >-
14
+ Redundant string interpolation detected at line {line}. Use the variable directly.
15
+ tests:
16
+ fire:
17
+ - const label = `${count}`;
18
+ quiet:
19
+ - const label = `${count} items`;
@@ -0,0 +1,29 @@
1
+ id: VBC-054
2
+ name: unnecessary-else
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: \breturn\b[^\n]*;?\s*\n?\s*\}\s*else\s*\{
9
+ multiline: true
10
+ file_types:
11
+ - js
12
+ - ts
13
+ message: >-
14
+ Unnecessary 'else' after 'return' at line {line}. Remove the else and flatten the code.
15
+ tests:
16
+ fire:
17
+ - |
18
+ if (ready) {
19
+ return 1;
20
+ } else {
21
+ return 2;
22
+ }
23
+ quiet:
24
+ - |
25
+ if (ready) {
26
+ start();
27
+ } else {
28
+ stop();
29
+ }
@@ -0,0 +1,28 @@
1
+ id: VBC-056
2
+ name: stale-todo
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - docs
7
+ match:
8
+ regex: >-
9
+ \b(?:TODO|FIXME|HACK)\b[^\n]{0,90}?\b(?:temporar\w+|for now|quick fix|before (?:launch|release|prod\w*)|remove
10
+ (?:this|later|before)|revisit|come back)\b
11
+ flags: i
12
+ scan: comments
13
+ file_types:
14
+ - js
15
+ - ts
16
+ - py
17
+ - sh
18
+ supersedes:
19
+ - VBC-907
20
+ - VBC-150
21
+ message: >-
22
+ Debt marker that admits it is temporary at line {line}. Temporary code that ships is permanent
23
+ code. Give it an owner and a deadline, or finish it.
24
+ tests:
25
+ fire:
26
+ - '// TODO: temporary shim until the new API lands'
27
+ quiet:
28
+ - '// TODO(fab): rework the cache key'
@@ -0,0 +1,18 @@
1
+ id: VBC-057
2
+ name: use-any
3
+ severity: warning
4
+ category: core
5
+ tags:
6
+ - typescript
7
+ match:
8
+ regex: :\s*any\b
9
+ file_types:
10
+ - ts
11
+ - tsx
12
+ message: >-
13
+ Avoid using 'any' type at line {line}. Use a more specific type or 'unknown'.
14
+ tests:
15
+ fire:
16
+ - 'function parse(input: any) { return input; }'
17
+ quiet:
18
+ - 'function parse(input: unknown) { return input; }'
@@ -0,0 +1,18 @@
1
+ id: VBC-058
2
+ name: overly-long-variable-name
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: \b(let|const|var)\s+[a-zA-Z0-9_]{35,}\b
9
+ file_types:
10
+ - js
11
+ - ts
12
+ message: >-
13
+ Overly long variable name (>35 chars) detected at line {line}. This is getting too vibey.
14
+ tests:
15
+ fire:
16
+ - const theAbsolutelyEnormousConfigurationObject = {};
17
+ quiet:
18
+ - const config = {};
@@ -0,0 +1,21 @@
1
+ id: VBC-059
2
+ name: file-length-limit
3
+ severity: warning
4
+ category: core
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ ast_check:
9
+ type: file-length-limit
10
+ threshold: 500
11
+ message: >-
12
+ File is too long ({count} lines). Consider splitting it into smaller modules. Max recommended:
13
+ {threshold}.
14
+ tests:
15
+ fire:
16
+ - code: |
17
+ const line = 1;
18
+ repeat: 520
19
+ quiet:
20
+ - |
21
+ const line = 1;
@@ -0,0 +1,15 @@
1
+ id: VBC-063-B
2
+ name: empty-block
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ ast_check:
9
+ type: empty-block
10
+ message: Empty block detected at line {line}. This code does nothing.
11
+ tests:
12
+ fire:
13
+ - function noop() {}
14
+ quiet:
15
+ - function run() { start(); }
@@ -0,0 +1,18 @@
1
+ id: VBC-063
2
+ name: empty-else
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: else\s*\{\s*\}
9
+ file_types:
10
+ - js
11
+ - ts
12
+ - py
13
+ message: Empty else block detected at line {line}. This clutters the code.
14
+ tests:
15
+ fire:
16
+ - if (ready) { start(); } else {}
17
+ quiet:
18
+ - if (ready) { start(); } else { stop(); }
@@ -0,0 +1,33 @@
1
+ id: VBC-065
2
+ name: hadouken-nested-logic
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ ast_check:
9
+ type: nested-blocks-limit
10
+ threshold: 4
11
+ message: >-
12
+ Nested logic is {count} levels deep at line {line}, over the limit of {threshold}. Return
13
+ early, extract the inner block, or invert a condition.
14
+ tests:
15
+ fire:
16
+ - |
17
+ function deep(a) {
18
+ if (a) {
19
+ for (;;) {
20
+ while (a) {
21
+ if (a) {
22
+ switch (a) { default: break; }
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ quiet:
29
+ - |
30
+ function shallow(a) {
31
+ if (a) { return 1; }
32
+ return 0;
33
+ }
@@ -0,0 +1,16 @@
1
+ id: VBC-066
2
+ name: redundant-if-true
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ ast_check:
9
+ type: redundant-if-true
10
+ message: >-
11
+ Redundant 'if(true)' detected at line {line}. This logic is either debug code or unnecessary.
12
+ tests:
13
+ fire:
14
+ - if (true) { start(); }
15
+ quiet:
16
+ - if (ready) { start(); }
@@ -0,0 +1,21 @@
1
+ id: VBC-068
2
+ name: overuse-ternary
3
+ severity: warning
4
+ category: clean-code
5
+ tags:
6
+ - clean-code
7
+ match:
8
+ regex: >-
9
+ \?(?![.:])[^\n]*?:[^\n]*?\?(?![.:])[^\n]*?:|\?(?![.:])[^\n]*?\?(?![.:])[^\n]*?:[^\n]*?:
10
+ file_types:
11
+ - js
12
+ - ts
13
+ message: >-
14
+ Chained or nested ternary at line {line}. Stacked conditionals are hard to read and hard
15
+ to debug; use an if/else block or a lookup table.
16
+ tests:
17
+ fire:
18
+ - 'const size = big ? ''lg'' : medium ? ''md'' : ''sm'';'
19
+ quiet:
20
+ - 'const size = big ? ''lg'' : ''sm'';'
21
+ - 'function f(a?: string, b?: number) {}'
@@ -0,0 +1,19 @@
1
+ id: VBC-070
2
+ name: use-innerhtml
3
+ severity: error
4
+ category: core
5
+ tags:
6
+ - security
7
+ match:
8
+ regex: \.innerHTML\s*=(?!=)
9
+ file_types:
10
+ - js
11
+ - ts
12
+ message: >-
13
+ Use of 'innerHTML' detected at line {line}. Use 'textContent' or a sanitizer to avoid XSS.
14
+ tests:
15
+ fire:
16
+ - el.innerHTML = markup;
17
+ quiet:
18
+ - el.textContent = text;
19
+ - if (el.innerHTML === "") { init(); }