@rcrsr/rill-cli 0.7.2 → 0.8.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 (60) hide show
  1. package/dist/cli-check.js +0 -0
  2. package/dist/cli-eval.js +0 -0
  3. package/dist/cli-exec.js +0 -0
  4. package/dist/cli-shared.d.ts.map +1 -1
  5. package/dist/cli-shared.js +3 -1
  6. package/dist/cli-shared.js.map +1 -1
  7. package/package.json +26 -11
  8. package/src/check/config.ts +0 -202
  9. package/src/check/fixer.ts +0 -174
  10. package/src/check/index.ts +0 -39
  11. package/src/check/rules/anti-patterns.ts +0 -585
  12. package/src/check/rules/closures.ts +0 -445
  13. package/src/check/rules/collections.ts +0 -437
  14. package/src/check/rules/conditionals.ts +0 -155
  15. package/src/check/rules/flow.ts +0 -262
  16. package/src/check/rules/formatting.ts +0 -811
  17. package/src/check/rules/helpers.ts +0 -89
  18. package/src/check/rules/index.ts +0 -140
  19. package/src/check/rules/loops.ts +0 -372
  20. package/src/check/rules/naming.ts +0 -242
  21. package/src/check/rules/strings.ts +0 -104
  22. package/src/check/rules/types.ts +0 -213
  23. package/src/check/types.ts +0 -163
  24. package/src/check/validator.ts +0 -136
  25. package/src/check/visitor.ts +0 -338
  26. package/src/cli-check.ts +0 -456
  27. package/src/cli-error-enrichment.ts +0 -274
  28. package/src/cli-error-formatter.ts +0 -313
  29. package/src/cli-eval.ts +0 -145
  30. package/src/cli-exec.ts +0 -408
  31. package/src/cli-explain.ts +0 -76
  32. package/src/cli-lsp-diagnostic.ts +0 -132
  33. package/src/cli-module-loader.ts +0 -101
  34. package/src/cli-shared.ts +0 -187
  35. package/tests/check/cli-check.test.ts +0 -189
  36. package/tests/check/config.test.ts +0 -350
  37. package/tests/check/fixer.test.ts +0 -373
  38. package/tests/check/format-diagnostics.test.ts +0 -327
  39. package/tests/check/rules/anti-patterns.test.ts +0 -467
  40. package/tests/check/rules/closures.test.ts +0 -192
  41. package/tests/check/rules/collections.test.ts +0 -380
  42. package/tests/check/rules/conditionals.test.ts +0 -185
  43. package/tests/check/rules/flow.test.ts +0 -250
  44. package/tests/check/rules/formatting.test.ts +0 -755
  45. package/tests/check/rules/loops.test.ts +0 -334
  46. package/tests/check/rules/naming.test.ts +0 -336
  47. package/tests/check/rules/strings.test.ts +0 -129
  48. package/tests/check/rules/types.test.ts +0 -233
  49. package/tests/check/validator.test.ts +0 -444
  50. package/tests/check/visitor.test.ts +0 -171
  51. package/tests/cli/check.test.ts +0 -801
  52. package/tests/cli/error-enrichment.test.ts +0 -510
  53. package/tests/cli/error-formatter.test.ts +0 -631
  54. package/tests/cli/eval.test.ts +0 -85
  55. package/tests/cli/exec.test.ts +0 -537
  56. package/tests/cli-explain.test.ts +0 -249
  57. package/tests/cli-lsp-diagnostic.test.ts +0 -202
  58. package/tests/cli-shared.test.ts +0 -439
  59. package/tsconfig.json +0 -9
  60. package/tsconfig.tsbuildinfo +0 -1
@@ -1,129 +0,0 @@
1
- /**
2
- * String Handling Convention Rules Tests
3
- * Verify string handling convention enforcement.
4
- */
5
-
6
- import { describe, it, expect } from 'vitest';
7
- import { parse } from '@rcrsr/rill';
8
- import { validateScript } from '../../../src/check/validator.js';
9
- import type { CheckConfig } from '../../../src/check/types.js';
10
-
11
- // ============================================================
12
- // TEST HELPERS
13
- // ============================================================
14
-
15
- /**
16
- * Create a config with string rules enabled.
17
- */
18
- function createConfig(rules: Record<string, 'on' | 'off'> = {}): CheckConfig {
19
- return {
20
- rules: {
21
- USE_EMPTY_METHOD: 'on',
22
- ...rules,
23
- },
24
- severity: {},
25
- };
26
- }
27
-
28
- /**
29
- * Validate source and extract diagnostic messages.
30
- */
31
- function getDiagnostics(source: string, config?: CheckConfig): string[] {
32
- const ast = parse(source);
33
- const diagnostics = validateScript(ast, source, config ?? createConfig());
34
- return diagnostics.map((d) => d.message);
35
- }
36
-
37
- /**
38
- * Validate source and check for violations.
39
- */
40
- function hasViolations(source: string, config?: CheckConfig): boolean {
41
- const ast = parse(source);
42
- const diagnostics = validateScript(ast, source, config ?? createConfig());
43
- return diagnostics.length > 0;
44
- }
45
-
46
- /**
47
- * Validate source and get diagnostic codes.
48
- */
49
- function getCodes(source: string, config?: CheckConfig): string[] {
50
- const ast = parse(source);
51
- const diagnostics = validateScript(ast, source, config ?? createConfig());
52
- return diagnostics.map((d) => d.code);
53
- }
54
-
55
- // ============================================================
56
- // USE_EMPTY_METHOD TESTS
57
- // ============================================================
58
-
59
- describe('USE_EMPTY_METHOD', () => {
60
- const config = createConfig();
61
-
62
- it('accepts .empty method usage', () => {
63
- expect(hasViolations('$str -> .empty', config)).toBe(false);
64
- });
65
-
66
- it('accepts comparisons not involving empty strings', () => {
67
- expect(hasViolations('$str == "hello"', config)).toBe(false);
68
- });
69
-
70
- it('warns on equality comparison with empty string', () => {
71
- const source = '$str == ""';
72
-
73
- const messages = getDiagnostics(source, config);
74
- expect(messages.length).toBeGreaterThan(0);
75
- expect(messages[0]).toContain('Use .empty');
76
- expect(messages[0]).toContain('comparing with ""');
77
- });
78
-
79
- it('warns on inequality comparison with empty string', () => {
80
- const source = '$str != ""';
81
-
82
- const messages = getDiagnostics(source, config);
83
- expect(messages.length).toBeGreaterThan(0);
84
- expect(messages[0]).toContain('Use .empty');
85
- });
86
-
87
- it('suggests correct method for equality', () => {
88
- const source = '$str == ""';
89
-
90
- const messages = getDiagnostics(source, config);
91
- expect(messages.length).toBeGreaterThan(0);
92
- expect(messages[0]).toContain('.empty');
93
- });
94
-
95
- it('suggests correct method for inequality', () => {
96
- const source = '$str != ""';
97
-
98
- const messages = getDiagnostics(source, config);
99
- expect(messages.length).toBeGreaterThan(0);
100
- expect(messages[0]).toContain('.empty -> !');
101
- });
102
-
103
- it('detects empty string on left side', () => {
104
- const source = '"" == $str';
105
-
106
- const messages = getDiagnostics(source, config);
107
- expect(messages.length).toBeGreaterThan(0);
108
- expect(messages[0]).toContain('Use .empty');
109
- });
110
-
111
- it('has correct severity and code', () => {
112
- const source = '$str == ""';
113
- const ast = parse(source);
114
- const diagnostics = validateScript(ast, source, config);
115
-
116
- expect(diagnostics.length).toBeGreaterThan(0);
117
- expect(diagnostics[0]?.code).toBe('USE_EMPTY_METHOD');
118
- expect(diagnostics[0]?.severity).toBe('warning');
119
- });
120
-
121
- it('does not provide auto-fix', () => {
122
- const source = '$str == ""';
123
- const ast = parse(source);
124
- const diagnostics = validateScript(ast, source, config);
125
-
126
- expect(diagnostics.length).toBeGreaterThan(0);
127
- expect(diagnostics[0]?.fix).toBeNull();
128
- });
129
- });
@@ -1,233 +0,0 @@
1
- /**
2
- * Type Safety Convention Rules Tests
3
- * Verify type safety convention enforcement.
4
- */
5
-
6
- import { describe, it, expect } from 'vitest';
7
- import { parse } from '@rcrsr/rill';
8
- import { validateScript } from '../../../src/check/validator.js';
9
- import type { CheckConfig, Fix } from '../../../src/check/types.js';
10
-
11
- /**
12
- * Apply a single fix to source code.
13
- */
14
- function applyFix(source: string, fix: Fix): string {
15
- const before = source.slice(0, fix.range.start.offset);
16
- const after = source.slice(fix.range.end.offset);
17
- return before + fix.replacement + after;
18
- }
19
-
20
- // ============================================================
21
- // TEST HELPERS
22
- // ============================================================
23
-
24
- /**
25
- * Create a config with type rules enabled.
26
- */
27
- function createConfig(rules: Record<string, 'on' | 'off'> = {}): CheckConfig {
28
- return {
29
- rules: {
30
- UNNECESSARY_ASSERTION: 'on',
31
- VALIDATE_EXTERNAL: 'on',
32
- ...rules,
33
- },
34
- severity: {},
35
- };
36
- }
37
-
38
- /**
39
- * Validate source and extract diagnostic messages.
40
- */
41
- function getDiagnostics(source: string, config?: CheckConfig): string[] {
42
- const ast = parse(source);
43
- const diagnostics = validateScript(ast, source, config ?? createConfig());
44
- return diagnostics.map((d) => d.message);
45
- }
46
-
47
- /**
48
- * Validate source and check for violations.
49
- */
50
- function hasViolations(source: string, config?: CheckConfig): boolean {
51
- const ast = parse(source);
52
- const diagnostics = validateScript(ast, source, config ?? createConfig());
53
- return diagnostics.length > 0;
54
- }
55
-
56
- // ============================================================
57
- // UNNECESSARY_ASSERTION TESTS
58
- // ============================================================
59
-
60
- describe('UNNECESSARY_ASSERTION', () => {
61
- const config = createConfig({ VALIDATE_EXTERNAL: 'off' });
62
-
63
- it('accepts assertions on variables', () => {
64
- expect(hasViolations('$val:number', config)).toBe(false);
65
- });
66
-
67
- it('accepts assertions on function results', () => {
68
- expect(hasViolations('getData():dict', config)).toBe(false);
69
- });
70
-
71
- it('accepts bare type assertions', () => {
72
- expect(hasViolations('$ -> :string', config)).toBe(false);
73
- });
74
-
75
- it('detects unnecessary number assertion', () => {
76
- const source = '5:number => $n';
77
-
78
- const messages = getDiagnostics(source, config);
79
- expect(messages.length).toBeGreaterThan(0);
80
- expect(messages[0]).toContain('unnecessary');
81
- expect(messages[0]).toContain('number literal');
82
- });
83
-
84
- it('detects unnecessary string assertion', () => {
85
- const source = '"hello":string => $s';
86
-
87
- const messages = getDiagnostics(source, config);
88
- expect(messages.length).toBeGreaterThan(0);
89
- expect(messages[0]).toContain('unnecessary');
90
- expect(messages[0]).toContain('string literal');
91
- });
92
-
93
- it('detects unnecessary bool assertion', () => {
94
- const source = 'true:bool => $b';
95
-
96
- const messages = getDiagnostics(source, config);
97
- expect(messages.length).toBeGreaterThan(0);
98
- expect(messages[0]).toContain('unnecessary');
99
- expect(messages[0]).toContain('bool literal');
100
- });
101
-
102
- it('has correct severity and code', () => {
103
- const source = '42:number';
104
- const ast = parse(source);
105
- const diagnostics = validateScript(ast, source, config);
106
-
107
- expect(diagnostics.length).toBeGreaterThan(0);
108
- expect(diagnostics[0]?.code).toBe('UNNECESSARY_ASSERTION');
109
- expect(diagnostics[0]?.severity).toBe('info');
110
- });
111
-
112
- it('provides fix to remove assertion', () => {
113
- const source = '5:number => $n';
114
- const ast = parse(source);
115
- const diagnostics = validateScript(ast, source, config);
116
-
117
- expect(diagnostics.length).toBeGreaterThan(0);
118
- const diagnostic = diagnostics[0];
119
- expect(diagnostic?.fix).toBeDefined();
120
- expect(diagnostic?.fix?.applicable).toBe(true);
121
- expect(diagnostic?.fix?.description).toContain('Remove unnecessary');
122
- });
123
-
124
- it('fix removes assertion correctly', () => {
125
- const source = '5:number => $n';
126
- const ast = parse(source);
127
- const diagnostics = validateScript(ast, source, config);
128
-
129
- expect(diagnostics.length).toBeGreaterThan(0);
130
- const diagnostic = diagnostics[0];
131
- if (diagnostic?.fix) {
132
- const fixed = applyFix(source, diagnostic.fix);
133
- expect(fixed).toBe('5 => $n');
134
- }
135
- });
136
-
137
- it('fix handles string assertions', () => {
138
- const source = '"test":string => $s';
139
- const ast = parse(source);
140
- const diagnostics = validateScript(ast, source, config);
141
-
142
- expect(diagnostics.length).toBeGreaterThan(0);
143
- const diagnostic = diagnostics[0];
144
- if (diagnostic?.fix) {
145
- const fixed = applyFix(source, diagnostic.fix);
146
- expect(fixed).toBe('"test" => $s');
147
- }
148
- });
149
- });
150
-
151
- // ============================================================
152
- // VALIDATE_EXTERNAL TESTS
153
- // ============================================================
154
-
155
- describe('VALIDATE_EXTERNAL', () => {
156
- const config = createConfig({ UNNECESSARY_ASSERTION: 'off' });
157
-
158
- it('recommends validation for fetch functions', () => {
159
- const source = 'fetch_data($url)';
160
-
161
- const messages = getDiagnostics(source, config);
162
- expect(messages.length).toBeGreaterThan(0);
163
- expect(messages[0]).toContain('external input');
164
- });
165
-
166
- it('recommends validation for read functions', () => {
167
- const source = 'read_file($path)';
168
-
169
- const messages = getDiagnostics(source, config);
170
- expect(messages.length).toBeGreaterThan(0);
171
- expect(messages[0]).toContain('external input');
172
- });
173
-
174
- it('does not warn on non-external functions', () => {
175
- expect(hasViolations('compute($x)', config)).toBe(false);
176
- });
177
-
178
- it('has correct severity and code', () => {
179
- const source = 'fetch_data($url)';
180
- const ast = parse(source);
181
- const diagnostics = validateScript(ast, source, config);
182
-
183
- expect(diagnostics.length).toBeGreaterThan(0);
184
- expect(diagnostics[0]?.code).toBe('VALIDATE_EXTERNAL');
185
- expect(diagnostics[0]?.severity).toBe('info');
186
- });
187
-
188
- it('does not provide auto-fix', () => {
189
- const source = 'fetch_data($url)';
190
- const ast = parse(source);
191
- const diagnostics = validateScript(ast, source, config);
192
-
193
- expect(diagnostics.length).toBeGreaterThan(0);
194
- expect(diagnostics[0]?.fix).toBeNull();
195
- });
196
-
197
- it('does not warn when already type-asserted (simple case)', () => {
198
- const source = 'fetch_data($url):dict';
199
-
200
- const violations = hasViolations(source, config);
201
- expect(violations).toBe(false);
202
- });
203
-
204
- it('does not warn when already type-asserted (with property access)', () => {
205
- const source = 'ccr::read_frontmatter($path, [status: ""]):dict.status';
206
-
207
- const violations = hasViolations(source, config);
208
- expect(violations).toBe(false);
209
- });
210
-
211
- it('does not warn when already type-asserted (namespaced function)', () => {
212
- const source = 'io::read_file($path):string';
213
-
214
- const violations = hasViolations(source, config);
215
- expect(violations).toBe(false);
216
- });
217
-
218
- it('does not warn for namespaced functions (trusted host APIs)', () => {
219
- // Namespaced functions like ccr::read_frontmatter are trusted host APIs
220
- const source = 'ccr::read_frontmatter($path)';
221
-
222
- const violations = hasViolations(source, config);
223
- expect(violations).toBe(false);
224
- });
225
-
226
- it('does not warn for parse_ prefix functions (transformations, not external data)', () => {
227
- // parse_* functions are transformations, not external data sources
228
- const source = 'parse_something($text)';
229
-
230
- const violations = hasViolations(source, config);
231
- expect(violations).toBe(false);
232
- });
233
- });