@rcrsr/rill 0.1.0 → 0.2.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.
Files changed (260) hide show
  1. package/README.md +16 -8
  2. package/dist/check/config.d.ts +20 -0
  3. package/dist/check/config.d.ts.map +1 -0
  4. package/dist/check/config.js +151 -0
  5. package/dist/check/config.js.map +1 -0
  6. package/dist/check/fixer.d.ts +39 -0
  7. package/dist/check/fixer.d.ts.map +1 -0
  8. package/dist/check/fixer.js +119 -0
  9. package/dist/check/fixer.js.map +1 -0
  10. package/dist/check/index.d.ts +10 -0
  11. package/dist/check/index.d.ts.map +1 -0
  12. package/dist/check/index.js +21 -0
  13. package/dist/check/index.js.map +1 -0
  14. package/dist/check/rules/anti-patterns.d.ts +65 -0
  15. package/dist/check/rules/anti-patterns.d.ts.map +1 -0
  16. package/dist/check/rules/anti-patterns.js +427 -0
  17. package/dist/check/rules/anti-patterns.js.map +1 -0
  18. package/dist/check/rules/closures.d.ts +66 -0
  19. package/dist/check/rules/closures.d.ts.map +1 -0
  20. package/dist/check/rules/closures.js +373 -0
  21. package/dist/check/rules/closures.js.map +1 -0
  22. package/dist/check/rules/collections.d.ts +90 -0
  23. package/dist/check/rules/collections.d.ts.map +1 -0
  24. package/dist/check/rules/collections.js +373 -0
  25. package/dist/check/rules/collections.js.map +1 -0
  26. package/dist/check/rules/conditionals.d.ts +41 -0
  27. package/dist/check/rules/conditionals.d.ts.map +1 -0
  28. package/dist/check/rules/conditionals.js +106 -0
  29. package/dist/check/rules/conditionals.js.map +1 -0
  30. package/dist/check/rules/flow.d.ts +46 -0
  31. package/dist/check/rules/flow.d.ts.map +1 -0
  32. package/dist/check/rules/flow.js +206 -0
  33. package/dist/check/rules/flow.js.map +1 -0
  34. package/dist/check/rules/formatting.d.ts +133 -0
  35. package/dist/check/rules/formatting.d.ts.map +1 -0
  36. package/dist/check/rules/formatting.js +639 -0
  37. package/dist/check/rules/formatting.js.map +1 -0
  38. package/dist/check/rules/helpers.d.ts +26 -0
  39. package/dist/check/rules/helpers.d.ts.map +1 -0
  40. package/dist/check/rules/helpers.js +66 -0
  41. package/dist/check/rules/helpers.js.map +1 -0
  42. package/dist/check/rules/index.d.ts +21 -0
  43. package/dist/check/rules/index.d.ts.map +1 -0
  44. package/dist/check/rules/index.js +78 -0
  45. package/dist/check/rules/index.js.map +1 -0
  46. package/dist/check/rules/loops.d.ts +70 -0
  47. package/dist/check/rules/loops.d.ts.map +1 -0
  48. package/dist/check/rules/loops.js +227 -0
  49. package/dist/check/rules/loops.js.map +1 -0
  50. package/dist/check/rules/naming.d.ts +21 -0
  51. package/dist/check/rules/naming.d.ts.map +1 -0
  52. package/dist/check/rules/naming.js +167 -0
  53. package/dist/check/rules/naming.js.map +1 -0
  54. package/dist/check/rules/strings.d.ts +28 -0
  55. package/dist/check/rules/strings.d.ts.map +1 -0
  56. package/dist/check/rules/strings.js +80 -0
  57. package/dist/check/rules/strings.js.map +1 -0
  58. package/dist/check/rules/types.d.ts +41 -0
  59. package/dist/check/rules/types.d.ts.map +1 -0
  60. package/dist/check/rules/types.js +162 -0
  61. package/dist/check/rules/types.js.map +1 -0
  62. package/dist/check/types.d.ts +106 -0
  63. package/dist/check/types.d.ts.map +1 -0
  64. package/dist/check/types.js +6 -0
  65. package/dist/check/types.js.map +1 -0
  66. package/dist/check/validator.d.ts +18 -0
  67. package/dist/check/validator.d.ts.map +1 -0
  68. package/dist/check/validator.js +88 -0
  69. package/dist/check/validator.js.map +1 -0
  70. package/dist/check/visitor.d.ts +33 -0
  71. package/dist/check/visitor.d.ts.map +1 -0
  72. package/dist/check/visitor.js +243 -0
  73. package/dist/check/visitor.js.map +1 -0
  74. package/dist/cli-check.d.ts +43 -0
  75. package/dist/cli-check.d.ts.map +1 -0
  76. package/dist/cli-check.js +356 -0
  77. package/dist/cli-check.js.map +1 -0
  78. package/dist/cli-eval.d.ts +15 -0
  79. package/dist/cli-eval.d.ts.map +1 -0
  80. package/dist/cli-eval.js +120 -0
  81. package/dist/cli-eval.js.map +1 -0
  82. package/dist/cli-exec.d.ts +49 -0
  83. package/dist/cli-exec.d.ts.map +1 -0
  84. package/dist/cli-exec.js +191 -0
  85. package/dist/cli-exec.js.map +1 -0
  86. package/dist/cli-module-loader.d.ts +19 -0
  87. package/dist/cli-module-loader.d.ts.map +1 -0
  88. package/dist/cli-module-loader.js +83 -0
  89. package/dist/cli-module-loader.js.map +1 -0
  90. package/dist/cli-shared.d.ts +36 -0
  91. package/dist/cli-shared.d.ts.map +1 -0
  92. package/dist/cli-shared.js +101 -0
  93. package/dist/cli-shared.js.map +1 -0
  94. package/dist/cli.d.ts +2 -0
  95. package/dist/cli.d.ts.map +1 -1
  96. package/dist/cli.js +4 -11
  97. package/dist/cli.js.map +1 -1
  98. package/dist/index.d.ts +1 -1
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +1 -1
  101. package/dist/index.js.map +1 -1
  102. package/dist/lexer/readers.d.ts +1 -1
  103. package/dist/lexer/readers.d.ts.map +1 -1
  104. package/dist/lexer/readers.js +62 -32
  105. package/dist/lexer/readers.js.map +1 -1
  106. package/dist/lexer/tokenizer.d.ts.map +1 -1
  107. package/dist/lexer/tokenizer.js +5 -6
  108. package/dist/lexer/tokenizer.js.map +1 -1
  109. package/dist/parser/index.js +1 -1
  110. package/dist/parser/index.js.map +1 -1
  111. package/dist/parser/parser-expr.js +23 -5
  112. package/dist/parser/parser-expr.js.map +1 -1
  113. package/dist/parser/parser-functions.d.ts +2 -2
  114. package/dist/parser/parser-functions.d.ts.map +1 -1
  115. package/dist/parser/parser-functions.js +2 -1
  116. package/dist/parser/parser-functions.js.map +1 -1
  117. package/dist/parser/parser-literals.js +2 -2
  118. package/dist/parser/parser-literals.js.map +1 -1
  119. package/dist/parser/parser-script.js +9 -7
  120. package/dist/parser/parser-script.js.map +1 -1
  121. package/dist/parser/parser-variables.js +4 -3
  122. package/dist/parser/parser-variables.js.map +1 -1
  123. package/dist/runtime/core/callable.d.ts +5 -6
  124. package/dist/runtime/core/callable.d.ts.map +1 -1
  125. package/dist/runtime/core/callable.js.map +1 -1
  126. package/dist/runtime/core/context.d.ts.map +1 -1
  127. package/dist/runtime/core/context.js +19 -32
  128. package/dist/runtime/core/context.js.map +1 -1
  129. package/dist/runtime/core/equals.js +1 -1
  130. package/dist/runtime/core/equals.js.map +1 -1
  131. package/dist/runtime/core/eval/evaluator.d.ts +78 -0
  132. package/dist/runtime/core/eval/evaluator.d.ts.map +1 -1
  133. package/dist/runtime/core/eval/evaluator.js +78 -0
  134. package/dist/runtime/core/eval/evaluator.js.map +1 -1
  135. package/dist/runtime/core/eval/mixins/closures.d.ts.map +1 -1
  136. package/dist/runtime/core/eval/mixins/closures.js +9 -1
  137. package/dist/runtime/core/eval/mixins/closures.js.map +1 -1
  138. package/dist/runtime/core/eval/mixins/variables.d.ts.map +1 -1
  139. package/dist/runtime/core/eval/mixins/variables.js +143 -2
  140. package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
  141. package/dist/runtime/core/types.d.ts +15 -2
  142. package/dist/runtime/core/types.d.ts.map +1 -1
  143. package/dist/runtime/core/types.js.map +1 -1
  144. package/dist/runtime/ext/extensions.d.ts +51 -0
  145. package/dist/runtime/ext/extensions.d.ts.map +1 -0
  146. package/dist/runtime/ext/extensions.js +67 -0
  147. package/dist/runtime/ext/extensions.js.map +1 -0
  148. package/dist/runtime/index.d.ts +3 -0
  149. package/dist/runtime/index.d.ts.map +1 -1
  150. package/dist/runtime/index.js +1 -0
  151. package/dist/runtime/index.js.map +1 -1
  152. package/dist/types.d.ts +8 -4
  153. package/dist/types.d.ts.map +1 -1
  154. package/dist/types.js +5 -4
  155. package/dist/types.js.map +1 -1
  156. package/docs/00_INDEX.md +1 -0
  157. package/docs/01_guide.md +3 -3
  158. package/docs/02_types.md +8 -10
  159. package/docs/03_variables.md +10 -0
  160. package/docs/04_operators.md +3 -3
  161. package/docs/05_control-flow.md +21 -0
  162. package/docs/07_collections.md +2 -0
  163. package/docs/10_parsing.md +9 -9
  164. package/docs/11_reference.md +1 -1
  165. package/docs/12_examples.md +36 -62
  166. package/docs/14_host-integration.md +116 -111
  167. package/docs/15_grammar.ebnf +1 -5
  168. package/docs/16_conventions.md +3 -4
  169. package/docs/17_cli-tools.md +184 -0
  170. package/docs/99_llm-reference.txt +46 -5
  171. package/package.json +13 -4
  172. package/dist/demo.d.ts +0 -6
  173. package/dist/demo.d.ts.map +0 -1
  174. package/dist/demo.js +0 -121
  175. package/dist/demo.js.map +0 -1
  176. package/dist/lexer.d.ts +0 -19
  177. package/dist/lexer.d.ts.map +0 -1
  178. package/dist/lexer.js +0 -344
  179. package/dist/lexer.js.map +0 -1
  180. package/dist/parser/arithmetic.d.ts +0 -16
  181. package/dist/parser/arithmetic.d.ts.map +0 -1
  182. package/dist/parser/arithmetic.js +0 -128
  183. package/dist/parser/arithmetic.js.map +0 -1
  184. package/dist/parser/boolean.d.ts +0 -15
  185. package/dist/parser/boolean.d.ts.map +0 -1
  186. package/dist/parser/boolean.js +0 -20
  187. package/dist/parser/boolean.js.map +0 -1
  188. package/dist/parser/control-flow.d.ts +0 -56
  189. package/dist/parser/control-flow.d.ts.map +0 -1
  190. package/dist/parser/control-flow.js +0 -167
  191. package/dist/parser/control-flow.js.map +0 -1
  192. package/dist/parser/expressions.d.ts +0 -23
  193. package/dist/parser/expressions.d.ts.map +0 -1
  194. package/dist/parser/expressions.js +0 -950
  195. package/dist/parser/expressions.js.map +0 -1
  196. package/dist/parser/extraction.d.ts +0 -48
  197. package/dist/parser/extraction.d.ts.map +0 -1
  198. package/dist/parser/extraction.js +0 -279
  199. package/dist/parser/extraction.js.map +0 -1
  200. package/dist/parser/functions.d.ts +0 -20
  201. package/dist/parser/functions.d.ts.map +0 -1
  202. package/dist/parser/functions.js +0 -96
  203. package/dist/parser/functions.js.map +0 -1
  204. package/dist/parser/literals.d.ts +0 -37
  205. package/dist/parser/literals.d.ts.map +0 -1
  206. package/dist/parser/literals.js +0 -373
  207. package/dist/parser/literals.js.map +0 -1
  208. package/dist/parser/script.d.ts +0 -14
  209. package/dist/parser/script.d.ts.map +0 -1
  210. package/dist/parser/script.js +0 -196
  211. package/dist/parser/script.js.map +0 -1
  212. package/dist/parser/variables.d.ts +0 -10
  213. package/dist/parser/variables.d.ts.map +0 -1
  214. package/dist/parser/variables.js +0 -215
  215. package/dist/parser/variables.js.map +0 -1
  216. package/dist/runtime/ast-equals.d.ts +0 -13
  217. package/dist/runtime/ast-equals.d.ts.map +0 -1
  218. package/dist/runtime/ast-equals.js +0 -447
  219. package/dist/runtime/ast-equals.js.map +0 -1
  220. package/dist/runtime/builtins.d.ts +0 -13
  221. package/dist/runtime/builtins.d.ts.map +0 -1
  222. package/dist/runtime/builtins.js +0 -180
  223. package/dist/runtime/builtins.js.map +0 -1
  224. package/dist/runtime/callable.d.ts +0 -88
  225. package/dist/runtime/callable.d.ts.map +0 -1
  226. package/dist/runtime/callable.js +0 -98
  227. package/dist/runtime/callable.js.map +0 -1
  228. package/dist/runtime/context.d.ts +0 -13
  229. package/dist/runtime/context.d.ts.map +0 -1
  230. package/dist/runtime/context.js +0 -73
  231. package/dist/runtime/context.js.map +0 -1
  232. package/dist/runtime/core/evaluate.d.ts +0 -42
  233. package/dist/runtime/core/evaluate.d.ts.map +0 -1
  234. package/dist/runtime/core/evaluate.debug.js +0 -1251
  235. package/dist/runtime/core/evaluate.js +0 -1913
  236. package/dist/runtime/core/evaluate.js.map +0 -1
  237. package/dist/runtime/evaluate.d.ts +0 -32
  238. package/dist/runtime/evaluate.d.ts.map +0 -1
  239. package/dist/runtime/evaluate.js +0 -1111
  240. package/dist/runtime/evaluate.js.map +0 -1
  241. package/dist/runtime/execute.d.ts +0 -26
  242. package/dist/runtime/execute.d.ts.map +0 -1
  243. package/dist/runtime/execute.js +0 -121
  244. package/dist/runtime/execute.js.map +0 -1
  245. package/dist/runtime/signals.d.ts +0 -19
  246. package/dist/runtime/signals.d.ts.map +0 -1
  247. package/dist/runtime/signals.js +0 -26
  248. package/dist/runtime/signals.js.map +0 -1
  249. package/dist/runtime/types.d.ts +0 -169
  250. package/dist/runtime/types.d.ts.map +0 -1
  251. package/dist/runtime/types.js +0 -50
  252. package/dist/runtime/types.js.map +0 -1
  253. package/dist/runtime/values.d.ts +0 -50
  254. package/dist/runtime/values.d.ts.map +0 -1
  255. package/dist/runtime/values.js +0 -209
  256. package/dist/runtime/values.js.map +0 -1
  257. package/dist/runtime.d.ts +0 -254
  258. package/dist/runtime.d.ts.map +0 -1
  259. package/dist/runtime.js +0 -2014
  260. package/dist/runtime.js.map +0 -1
@@ -0,0 +1,373 @@
1
+ /**
2
+ * Closure Convention Rules
3
+ * Enforces closure best practices from docs/16_conventions.md:237-286.
4
+ */
5
+ import { extractContextLine } from './helpers.js';
6
+ // ============================================================
7
+ // CLOSURE_BARE_DOLLAR RULE
8
+ // ============================================================
9
+ /**
10
+ * Warns on bare $ in stored closures without parameters.
11
+ * Bare $ in stored closures has ambiguous binding - it refers to the
12
+ * pipe value at closure invocation time, not definition time.
13
+ *
14
+ * Detection:
15
+ * - Zero-parameter closures (|| { }) used outside dict context
16
+ * - Body contains bare $ references (VariableNode with name '$')
17
+ *
18
+ * Valid patterns:
19
+ * - Dict closures: [count: ||{ $.items -> .len }] ($ binds to dict)
20
+ * - Parameterized closures: |x|{ $x } (explicit params)
21
+ * - Inline blocks: -> { $ * 2 } (immediate evaluation)
22
+ *
23
+ * References:
24
+ * - docs/16_conventions.md:251-261
25
+ * - docs/06_closures.md: Late binding section
26
+ */
27
+ export const CLOSURE_BARE_DOLLAR = {
28
+ code: 'CLOSURE_BARE_DOLLAR',
29
+ category: 'closures',
30
+ severity: 'warning',
31
+ nodeTypes: ['Closure'],
32
+ validate(node, context) {
33
+ const closureNode = node;
34
+ // Only check zero-parameter closures (|| { })
35
+ if (closureNode.params.length > 0) {
36
+ return [];
37
+ }
38
+ // Check if closure body contains bare $ references
39
+ const hasBareReference = containsBareReference(closureNode.body);
40
+ if (hasBareReference) {
41
+ return [
42
+ {
43
+ location: closureNode.span.start,
44
+ severity: 'warning',
45
+ code: 'CLOSURE_BARE_DOLLAR',
46
+ message: 'Bare $ in stored closure has ambiguous binding. Use explicit capture: $ :> $item',
47
+ context: extractContextLine(closureNode.span.start.line, context.source),
48
+ fix: null, // Cannot auto-fix safely - requires context understanding
49
+ },
50
+ ];
51
+ }
52
+ return [];
53
+ },
54
+ };
55
+ /**
56
+ * Check if a node tree contains bare $ variable references.
57
+ * Recursively walks the AST looking for VariableNode with isPipeVar=true.
58
+ */
59
+ function containsBareReference(node) {
60
+ if (node.type === 'Variable') {
61
+ const varNode = node;
62
+ // $ is represented as isPipeVar: true with name: null
63
+ if (varNode.isPipeVar) {
64
+ return true;
65
+ }
66
+ }
67
+ // Recursively check child nodes based on node type
68
+ switch (node.type) {
69
+ case 'Block': {
70
+ const blockNode = node;
71
+ for (const stmt of blockNode.statements) {
72
+ if (containsBareReference(stmt))
73
+ return true;
74
+ }
75
+ break;
76
+ }
77
+ case 'Statement': {
78
+ const stmtNode = node;
79
+ if (stmtNode.expression && containsBareReference(stmtNode.expression))
80
+ return true;
81
+ break;
82
+ }
83
+ case 'PipeChain': {
84
+ const pipeNode = node;
85
+ if (pipeNode.head && containsBareReference(pipeNode.head))
86
+ return true;
87
+ if (pipeNode.pipes) {
88
+ for (const pipe of pipeNode.pipes) {
89
+ if (containsBareReference(pipe))
90
+ return true;
91
+ }
92
+ }
93
+ break;
94
+ }
95
+ case 'PostfixExpr': {
96
+ const postfixNode = node;
97
+ if (postfixNode.primary && containsBareReference(postfixNode.primary))
98
+ return true;
99
+ if (postfixNode.methods) {
100
+ for (const method of postfixNode.methods) {
101
+ if (containsBareReference(method))
102
+ return true;
103
+ }
104
+ }
105
+ break;
106
+ }
107
+ case 'BinaryExpr': {
108
+ const binaryNode = node;
109
+ if (binaryNode.left && containsBareReference(binaryNode.left))
110
+ return true;
111
+ if (binaryNode.right && containsBareReference(binaryNode.right))
112
+ return true;
113
+ break;
114
+ }
115
+ case 'UnaryExpr': {
116
+ const unaryNode = node;
117
+ if (unaryNode.operand && containsBareReference(unaryNode.operand))
118
+ return true;
119
+ break;
120
+ }
121
+ case 'GroupedExpr': {
122
+ const groupedNode = node;
123
+ if (groupedNode.expression &&
124
+ containsBareReference(groupedNode.expression))
125
+ return true;
126
+ break;
127
+ }
128
+ case 'StringLiteral': {
129
+ const stringNode = node;
130
+ if (stringNode.parts && Array.isArray(stringNode.parts)) {
131
+ for (const part of stringNode.parts) {
132
+ if (typeof part === 'object' && containsBareReference(part))
133
+ return true;
134
+ }
135
+ }
136
+ break;
137
+ }
138
+ case 'Interpolation': {
139
+ const interpNode = node;
140
+ if (interpNode.expression && containsBareReference(interpNode.expression))
141
+ return true;
142
+ break;
143
+ }
144
+ case 'Conditional': {
145
+ const condNode = node;
146
+ if (condNode.condition && containsBareReference(condNode.condition))
147
+ return true;
148
+ if (condNode.thenBranch && containsBareReference(condNode.thenBranch))
149
+ return true;
150
+ if (condNode.elseBranch && containsBareReference(condNode.elseBranch))
151
+ return true;
152
+ break;
153
+ }
154
+ case 'MethodCall':
155
+ case 'HostCall':
156
+ case 'ClosureCall':
157
+ case 'Invoke': {
158
+ const callNode = node;
159
+ if (callNode.args && Array.isArray(callNode.args)) {
160
+ for (const arg of callNode.args) {
161
+ if (containsBareReference(arg))
162
+ return true;
163
+ }
164
+ }
165
+ break;
166
+ }
167
+ }
168
+ return false;
169
+ }
170
+ // ============================================================
171
+ // CLOSURE_BRACES RULE
172
+ // ============================================================
173
+ /**
174
+ * Enforces braces for complex closure bodies.
175
+ * Simple expressions can use parentheses, but complex bodies need braces.
176
+ *
177
+ * Complex body criteria:
178
+ * - Contains Block (multiple statements)
179
+ * - Contains Conditional
180
+ * - Contains loop constructs
181
+ *
182
+ * Simple bodies (parentheses OK):
183
+ * - Single expression: |x|($x * 2)
184
+ * - Single method chain: |s|($s.trim.lower)
185
+ *
186
+ * Complex bodies (braces required):
187
+ * - Conditionals: |n| { ($n < 1) ? 1 ! ($n * $fact($n - 1)) }
188
+ * - Multiple statements: |x| { $x :> $y; $y * 2 }
189
+ *
190
+ * References:
191
+ * - docs/16_conventions.md:239-249
192
+ */
193
+ export const CLOSURE_BRACES = {
194
+ code: 'CLOSURE_BRACES',
195
+ category: 'closures',
196
+ severity: 'info',
197
+ nodeTypes: ['Closure'],
198
+ validate(node, context) {
199
+ const closureNode = node;
200
+ const body = closureNode.body;
201
+ // Check if body is GroupedExpr containing complex content
202
+ if (body.type === 'GroupedExpr') {
203
+ const grouped = body;
204
+ const innerExpr = grouped.expression;
205
+ // Navigate through PipeChain to find the actual content
206
+ let content = innerExpr;
207
+ if (innerExpr && innerExpr.type === 'PipeChain') {
208
+ const head = innerExpr.head;
209
+ // Check if head is PostfixExpr
210
+ if (head && head.type === 'PostfixExpr') {
211
+ content = head.primary;
212
+ }
213
+ else {
214
+ content = head;
215
+ }
216
+ }
217
+ // Check if the content is a conditional or loop
218
+ const isComplex = content &&
219
+ (content.type === 'Conditional' ||
220
+ content.type === 'WhileLoop' ||
221
+ content.type === 'DoWhileLoop');
222
+ if (isComplex) {
223
+ return [
224
+ {
225
+ location: closureNode.span.start,
226
+ severity: 'info',
227
+ code: 'CLOSURE_BRACES',
228
+ message: 'Use braces for complex closure bodies (conditionals, loops)',
229
+ context: extractContextLine(closureNode.span.start.line, context.source),
230
+ fix: null, // Auto-fix would require AST reconstruction
231
+ },
232
+ ];
233
+ }
234
+ }
235
+ return [];
236
+ },
237
+ };
238
+ // ============================================================
239
+ // CLOSURE_LATE_BINDING RULE
240
+ // ============================================================
241
+ /**
242
+ * Detects closures created in loops that may suffer from late binding issues.
243
+ * When creating closures inside loops, variables are captured by reference,
244
+ * not by value. This causes all closures to share the final loop value.
245
+ *
246
+ * Detection:
247
+ * - Each loop body creates a Closure node
248
+ * - Closure references loop variable ($) without explicit capture
249
+ *
250
+ * Solution: Explicit capture per iteration:
251
+ * [1, 2, 3] -> each {
252
+ * $ :> $item
253
+ * || { $item }
254
+ * }
255
+ *
256
+ * References:
257
+ * - docs/16_conventions.md:251-261
258
+ * - docs/06_closures.md: Late binding section
259
+ */
260
+ export const CLOSURE_LATE_BINDING = {
261
+ code: 'CLOSURE_LATE_BINDING',
262
+ category: 'closures',
263
+ severity: 'warning',
264
+ nodeTypes: ['EachExpr'],
265
+ validate(node, context) {
266
+ const eachNode = node;
267
+ const body = eachNode.body;
268
+ // Check if body contains a closure creation
269
+ const hasClosureCreation = containsClosureCreation(body);
270
+ if (hasClosureCreation) {
271
+ // Check if there's an explicit capture before the closure
272
+ const hasExplicitCapture = containsExplicitCapture(body);
273
+ if (!hasExplicitCapture) {
274
+ return [
275
+ {
276
+ location: eachNode.span.start,
277
+ severity: 'warning',
278
+ code: 'CLOSURE_LATE_BINDING',
279
+ message: 'Capture loop variable explicitly for deferred closures: $ :> $item',
280
+ context: extractContextLine(eachNode.span.start.line, context.source),
281
+ fix: null, // Auto-fix would require AST reconstruction
282
+ },
283
+ ];
284
+ }
285
+ }
286
+ return [];
287
+ },
288
+ };
289
+ /**
290
+ * Check if a node contains a closure creation (Closure node).
291
+ */
292
+ function containsClosureCreation(node) {
293
+ if (node.type === 'Closure') {
294
+ return true;
295
+ }
296
+ // Recursively check child nodes
297
+ switch (node.type) {
298
+ case 'Block': {
299
+ const blockNode = node;
300
+ for (const stmt of blockNode.statements) {
301
+ if (containsClosureCreation(stmt))
302
+ return true;
303
+ }
304
+ break;
305
+ }
306
+ case 'Statement': {
307
+ const stmtNode = node;
308
+ if (stmtNode.expression && containsClosureCreation(stmtNode.expression))
309
+ return true;
310
+ break;
311
+ }
312
+ case 'PipeChain': {
313
+ const pipeNode = node;
314
+ if (pipeNode.head && containsClosureCreation(pipeNode.head))
315
+ return true;
316
+ if (pipeNode.pipes) {
317
+ for (const pipe of pipeNode.pipes) {
318
+ if (containsClosureCreation(pipe))
319
+ return true;
320
+ }
321
+ }
322
+ break;
323
+ }
324
+ case 'PostfixExpr': {
325
+ const postfixNode = node;
326
+ if (postfixNode.primary && containsClosureCreation(postfixNode.primary))
327
+ return true;
328
+ break;
329
+ }
330
+ }
331
+ return false;
332
+ }
333
+ /**
334
+ * Check if a Block node contains an explicit capture statement ($ :> $name).
335
+ */
336
+ function containsExplicitCapture(node) {
337
+ if (node.type !== 'Block') {
338
+ return false;
339
+ }
340
+ const blockNode = node;
341
+ const statements = blockNode.statements;
342
+ if (!Array.isArray(statements)) {
343
+ return false;
344
+ }
345
+ // Look for capture of $ into a named variable
346
+ for (const stmt of statements) {
347
+ if (stmt.type === 'Statement' &&
348
+ stmt.expression &&
349
+ stmt.expression.type === 'PipeChain') {
350
+ const chain = stmt.expression;
351
+ // Check if any pipe is a Capture
352
+ if (chain.pipes && Array.isArray(chain.pipes)) {
353
+ for (const pipe of chain.pipes) {
354
+ if (pipe.type === 'Capture') {
355
+ // Check if the head is bare $
356
+ const head = chain.head;
357
+ if (head && head.type === 'PostfixExpr') {
358
+ const postfix = head;
359
+ if (postfix.primary && postfix.primary.type === 'Variable') {
360
+ const varNode = postfix.primary;
361
+ if (varNode.isPipeVar) {
362
+ return true;
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+ }
369
+ }
370
+ }
371
+ return false;
372
+ }
373
+ //# sourceMappingURL=closures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closures.js","sourceRoot":"","sources":["../../../src/check/rules/closures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Collection Operator Rules
3
+ * Enforces conventions for each, map, fold, and filter operators.
4
+ */
5
+ import type { ValidationRule } from '../types.js';
6
+ /**
7
+ * Validates that break is not used in parallel operators (map, filter).
8
+ *
9
+ * Break is semantically invalid in parallel execution contexts:
10
+ * - map: executes in parallel, no iteration order
11
+ * - filter: parallel predicate evaluation
12
+ *
13
+ * Break is valid in sequential operators:
14
+ * - each: sequential iteration with early termination
15
+ * - fold: sequential reduction (though uncommon)
16
+ *
17
+ * Error severity because this is semantically wrong, not just stylistic.
18
+ *
19
+ * References:
20
+ * - docs/16_conventions.md:90-149
21
+ * - docs/07_collections.md
22
+ */
23
+ export declare const BREAK_IN_PARALLEL: ValidationRule;
24
+ /**
25
+ * Suggests using map over each when no side effects are present.
26
+ *
27
+ * Map is semantically clearer for pure transformations:
28
+ * - Signals no side effects (parallel execution)
29
+ * - Better performance potential
30
+ * - More functional style
31
+ *
32
+ * Detects each expressions where:
33
+ * - Body doesn't reference accumulator ($@)
34
+ * - No accumulator initialization
35
+ * - Body doesn't contain side-effecting operations (host calls, logging)
36
+ *
37
+ * This is informational - both work, but map is clearer for pure transforms.
38
+ *
39
+ * References:
40
+ * - docs/16_conventions.md:90-149
41
+ */
42
+ export declare const PREFER_MAP: ValidationRule;
43
+ /**
44
+ * Suggests using fold for final-only results, each(init) for running totals.
45
+ *
46
+ * Semantic distinction:
47
+ * - fold: returns final accumulated value only
48
+ * - each(init): returns list of all intermediate results
49
+ *
50
+ * Detects patterns that might benefit from one or the other:
51
+ * - fold used when intermediate results might be needed
52
+ * - each(init) used when only final result matters
53
+ *
54
+ * This is informational - helps users choose the right operator.
55
+ *
56
+ * References:
57
+ * - docs/16_conventions.md:90-149
58
+ * - docs/07_collections.md
59
+ */
60
+ export declare const FOLD_INTERMEDIATES: ValidationRule;
61
+ /**
62
+ * Validates that negation in filter uses grouped form.
63
+ *
64
+ * Grouped negation is clearer and prevents bugs:
65
+ * - Correct: filter (!.empty) -- grouped negation
66
+ * - Wrong: filter .empty -- filters for empty elements (likely bug)
67
+ *
68
+ * The ungrouped form .empty would return truthy elements,
69
+ * which is likely not intended when filtering.
70
+ *
71
+ * References:
72
+ * - docs/16_conventions.md:90-149
73
+ */
74
+ export declare const FILTER_NEGATION: ValidationRule;
75
+ /**
76
+ * Suggests using method shorthand over block form in collection operators.
77
+ *
78
+ * Method shorthand is more concise and clearer:
79
+ * - Preferred: map .upper
80
+ * - Verbose: map { $.upper() }
81
+ *
82
+ * Detects block forms that wrap a single method call and suggests shorthand.
83
+ *
84
+ * This is informational - both forms work identically.
85
+ *
86
+ * References:
87
+ * - docs/16_conventions.md:90-149
88
+ */
89
+ export declare const METHOD_SHORTHAND: ValidationRule;
90
+ //# sourceMappingURL=collections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../../src/check/rules/collections.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,aAAa,CAAC;AAsLrB;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAyB/B,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,EAAE,cAuCxB,CAAC;AAMF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,kBAAkB,EAAE,cAYhC,CAAC;AAMF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,EAAE,cAiC7B,CAAC;AAMF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAiC9B,CAAC"}