poe-code 4.0.57 → 4.0.58

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-code",
3
- "version": "4.0.57",
3
+ "version": "4.0.58",
4
4
  "description": "CLI tool to configure Poe API for developer workflows.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,5 +1,4 @@
1
1
  import { AS001 } from "./rules/AS001.js";
2
- import { AS002 } from "./rules/AS002.js";
3
2
  import { AS003 } from "./rules/AS003.js";
4
3
  import { AS004 } from "./rules/AS004.js";
5
4
  import { AS005 } from "./rules/AS005.js";
@@ -30,7 +29,6 @@ import { AS_UNUSED_IMPORT } from "./rules/AS-unused-import.js";
30
29
  import { collectComments, tokenize } from "../parse/tokenizer.js";
31
30
  import { parseModule } from "../parse/parser.js";
32
31
  const RULES = [
33
- AS002,
34
32
  AS003,
35
33
  AS004,
36
34
  AS005,
@@ -170,13 +170,13 @@ class Parser {
170
170
  };
171
171
  }
172
172
  parseExpression(options = {}) {
173
- const first = this.parseNonSequenceExpression();
173
+ const first = this.parseAssignmentExpression();
174
174
  if (options.allowSequence !== true || this.consumePunctuator(",") === undefined) {
175
175
  return first;
176
176
  }
177
177
  const expressions = [first.node];
178
178
  do {
179
- expressions.push(this.parseNonSequenceExpression().node);
179
+ expressions.push(this.parseAssignmentExpression().node);
180
180
  } while (this.consumePunctuator(",") !== undefined);
181
181
  return {
182
182
  node: {
@@ -187,7 +187,7 @@ class Parser {
187
187
  parenthesized: false
188
188
  };
189
189
  }
190
- parseNonSequenceExpression() {
190
+ parseAssignmentExpression() {
191
191
  const arrowFunction = this.tryParseArrowFunctionExpression();
192
192
  if (arrowFunction !== undefined) {
193
193
  return {
@@ -195,9 +195,6 @@ class Parser {
195
195
  parenthesized: false
196
196
  };
197
197
  }
198
- return this.parseAssignmentExpression();
199
- }
200
- parseAssignmentExpression() {
201
198
  const patternAssignment = this.tryParsePatternAssignmentExpression();
202
199
  if (patternAssignment !== undefined) {
203
200
  return {
@@ -271,7 +268,7 @@ class Parser {
271
268
  }
272
269
  const consequent = this.parseExpression();
273
270
  this.expectPunctuator(":");
274
- const alternate = this.parseConditionalExpression();
271
+ const alternate = this.parseAssignmentExpression();
275
272
  return {
276
273
  node: {
277
274
  type: "ConditionalExpression",
@@ -1,13 +0,0 @@
1
- import { type SourceSpan } from "../../parse/parser.js";
2
- export type Diagnostic = {
3
- code: "AS002";
4
- severity: "error";
5
- message: string;
6
- filename: string;
7
- line: number;
8
- column: number;
9
- span: SourceSpan;
10
- };
11
- export declare function AS002(source: string, options?: {
12
- filename?: string;
13
- }): Diagnostic[];
@@ -1,525 +0,0 @@
1
- import { parseModule } from "../../parse/parser.js";
2
- export function AS002(source, options = {}) {
3
- return new AS002Scanner(options.filename ?? "<input>").scan(source);
4
- }
5
- class AS002Scanner {
6
- filename;
7
- diagnostics = [];
8
- scopes = [];
9
- lambdaStack = [];
10
- reportedCaptures = new Set();
11
- constructor(filename) {
12
- this.filename = filename;
13
- }
14
- scan(source) {
15
- const module = parseModule(source, this.filename);
16
- this.visitModule(module);
17
- return this.diagnostics;
18
- }
19
- visitModule(node) {
20
- this.withScope(this.collectModuleBindings(node.body), () => {
21
- for (const statement of node.body) {
22
- this.visitStatement(statement);
23
- }
24
- });
25
- }
26
- visitStatement(node) {
27
- switch (node.type) {
28
- case "BlockStatement":
29
- this.visitBlock(node);
30
- return;
31
- case "ExpressionStatement":
32
- this.visitExpressionStatement(node);
33
- return;
34
- case "IfStatement":
35
- this.visitIfStatement(node);
36
- return;
37
- case "ForStatement":
38
- this.visitForStatement(node);
39
- return;
40
- case "ForInStatement":
41
- case "ForOfStatement":
42
- this.visitForOfStatement(node);
43
- return;
44
- case "WhileStatement":
45
- case "DoWhileStatement":
46
- this.visitWhileStatement(node);
47
- return;
48
- case "TryStatement":
49
- this.visitTryStatement(node);
50
- return;
51
- case "VariableDeclaration":
52
- this.visitVariableDeclaration(node);
53
- return;
54
- case "ReturnStatement":
55
- if (node.argument !== undefined) {
56
- this.visitExpression(node.argument);
57
- }
58
- return;
59
- case "ThrowStatement":
60
- this.visitThrowStatement(node);
61
- return;
62
- case "ExportNamedDeclaration":
63
- this.visitVariableDeclaration(node.declaration);
64
- return;
65
- case "ExportDefaultDeclaration":
66
- this.visitExpression(node.declaration);
67
- return;
68
- case "ImportDeclaration":
69
- case "BreakStatement":
70
- case "ContinueStatement":
71
- return;
72
- }
73
- }
74
- visitBlock(node) {
75
- this.withScope(this.collectBlockBindings(node.body), () => {
76
- for (const statement of node.body) {
77
- this.visitStatement(statement);
78
- }
79
- });
80
- }
81
- visitExpressionStatement(node) {
82
- this.visitExpression(node.expression);
83
- }
84
- visitIfStatement(node) {
85
- this.visitExpression(node.test);
86
- this.visitStatement(node.consequent);
87
- if (node.alternate !== undefined) {
88
- this.visitStatement(node.alternate);
89
- }
90
- }
91
- visitForStatement(node) {
92
- const bindings = node.init?.type === "VariableDeclaration" ? this.collectDeclarationBindings(node.init) : [];
93
- this.withScope(bindings, () => {
94
- if (node.init !== undefined) {
95
- if (node.init.type === "VariableDeclaration") {
96
- this.visitVariableDeclaration(node.init);
97
- }
98
- else {
99
- this.visitExpression(node.init);
100
- }
101
- }
102
- if (node.test !== undefined) {
103
- this.visitExpression(node.test);
104
- }
105
- if (node.update !== undefined) {
106
- this.visitExpression(node.update);
107
- }
108
- this.visitStatement(node.body);
109
- });
110
- }
111
- visitForOfStatement(node) {
112
- const bindings = node.left.type === "VariableDeclaration" ? this.collectDeclarationBindings(node.left) : [];
113
- this.withScope(bindings, () => {
114
- if (node.left.type === "VariableDeclaration") {
115
- this.visitVariableDeclaration(node.left);
116
- }
117
- else {
118
- this.visitAssignmentTarget(node.left);
119
- }
120
- this.visitExpression(node.right);
121
- this.visitStatement(node.body);
122
- });
123
- }
124
- visitWhileStatement(node) {
125
- this.visitExpression(node.test);
126
- this.visitStatement(node.body);
127
- }
128
- visitTryStatement(node) {
129
- this.visitBlock(node.block);
130
- if (node.handler !== undefined) {
131
- this.visitCatchClause(node.handler);
132
- }
133
- if (node.finalizer !== undefined) {
134
- this.visitBlock(node.finalizer);
135
- }
136
- }
137
- visitCatchClause(node) {
138
- this.withScope(this.collectCatchBindings(node), () => {
139
- if (node.param !== undefined) {
140
- this.visitBindingPattern(node.param);
141
- }
142
- this.visitBlock(node.body);
143
- });
144
- }
145
- visitThrowStatement(node) {
146
- this.visitExpression(node.argument);
147
- }
148
- visitVariableDeclaration(node) {
149
- for (const declarator of node.declarations) {
150
- this.visitVariableDeclarator(declarator);
151
- }
152
- }
153
- visitVariableDeclarator(node) {
154
- this.visitBindingPattern(node.id);
155
- if (node.init !== undefined) {
156
- this.visitExpression(node.init);
157
- }
158
- }
159
- visitExpression(node) {
160
- switch (node.type) {
161
- case "Identifier":
162
- this.visitIdentifier(node);
163
- return;
164
- case "ArrowFunctionExpression":
165
- this.visitArrowFunction(node);
166
- return;
167
- case "AwaitExpression":
168
- this.visitAwaitExpression(node);
169
- return;
170
- case "ArrayExpression":
171
- this.visitArrayExpression(node);
172
- return;
173
- case "ObjectExpression":
174
- this.visitObjectExpression(node);
175
- return;
176
- case "UnaryExpression":
177
- this.visitUnaryExpression(node);
178
- return;
179
- case "BinaryExpression":
180
- this.visitBinaryExpression(node);
181
- return;
182
- case "LogicalExpression":
183
- this.visitLogicalExpression(node);
184
- return;
185
- case "ConditionalExpression":
186
- this.visitConditionalExpression(node);
187
- return;
188
- case "MemberExpression":
189
- this.visitMemberExpression(node);
190
- return;
191
- case "AssignmentExpression":
192
- this.visitAssignmentExpression(node);
193
- return;
194
- case "CallExpression":
195
- this.visitCallExpression(node);
196
- return;
197
- case "TemplateLiteral":
198
- this.visitTemplateLiteral(node);
199
- return;
200
- case "BooleanLiteral":
201
- case "NullLiteral":
202
- case "NumericLiteral":
203
- case "StringLiteral":
204
- case "UndefinedLiteral":
205
- return;
206
- }
207
- }
208
- visitArrowFunction(node) {
209
- const lambdaContext = {
210
- depth: this.lambdaStack.length + 1,
211
- nodeId: node.nodeId ?? -1
212
- };
213
- this.lambdaStack.push(lambdaContext);
214
- this.withScope(this.collectParameterBindings(node), () => {
215
- for (const parameter of node.params) {
216
- this.visitBindingElement(parameter);
217
- }
218
- if (node.body.type === "BlockStatement") {
219
- this.visitBlock(node.body);
220
- }
221
- else {
222
- this.visitExpression(node.body);
223
- }
224
- });
225
- this.lambdaStack.pop();
226
- }
227
- visitAwaitExpression(node) {
228
- this.visitExpression(node.argument);
229
- }
230
- visitArrayExpression(node) {
231
- for (const element of node.elements) {
232
- if (element?.type === "SpreadElement") {
233
- this.visitSpreadElement(element);
234
- continue;
235
- }
236
- if (element !== undefined) {
237
- this.visitExpression(element);
238
- }
239
- }
240
- }
241
- visitObjectExpression(node) {
242
- for (const property of node.properties) {
243
- if (property.type === "SpreadElement") {
244
- this.visitSpreadElement(property);
245
- continue;
246
- }
247
- this.visitProperty(property);
248
- }
249
- }
250
- visitUnaryExpression(node) {
251
- this.visitExpression(node.argument);
252
- }
253
- visitBinaryExpression(node) {
254
- this.visitExpression(node.left);
255
- this.visitExpression(node.right);
256
- }
257
- visitLogicalExpression(node) {
258
- this.visitExpression(node.left);
259
- this.visitExpression(node.right);
260
- }
261
- visitConditionalExpression(node) {
262
- this.visitExpression(node.test);
263
- this.visitExpression(node.consequent);
264
- this.visitExpression(node.alternate);
265
- }
266
- visitMemberExpression(node) {
267
- this.visitExpression(node.object);
268
- if (node.computed) {
269
- this.visitExpression(node.property);
270
- }
271
- }
272
- visitAssignmentExpression(node) {
273
- this.visitAssignmentTarget(node.left);
274
- this.visitExpression(node.right);
275
- }
276
- visitCallExpression(node) {
277
- this.visitExpression(node.callee);
278
- for (const argument of node.arguments) {
279
- if (argument.type === "SpreadElement") {
280
- this.visitSpreadElement(argument);
281
- continue;
282
- }
283
- this.visitExpression(argument);
284
- }
285
- }
286
- visitTemplateLiteral(node) {
287
- for (const expression of node.expressions) {
288
- this.visitExpression(expression);
289
- }
290
- }
291
- visitProperty(node) {
292
- if (node.computed) {
293
- this.visitExpression(node.key);
294
- }
295
- this.visitExpression(node.value);
296
- }
297
- visitSpreadElement(node) {
298
- this.visitExpression(node.argument);
299
- }
300
- visitBindingElement(node) {
301
- switch (node.type) {
302
- case "AssignmentPattern":
303
- this.visitBindingPattern(node.left);
304
- this.visitExpression(node.right);
305
- return;
306
- case "RestElement":
307
- this.visitBindingPattern(node.argument);
308
- return;
309
- default:
310
- this.visitBindingPattern(node);
311
- return;
312
- }
313
- }
314
- visitBindingPattern(node) {
315
- switch (node.type) {
316
- case "Identifier":
317
- return;
318
- case "MemberExpression":
319
- this.visitMemberExpression(node);
320
- return;
321
- case "ArrayPattern":
322
- for (const element of node.elements) {
323
- if (element !== null) {
324
- this.visitBindingElement(element);
325
- }
326
- }
327
- return;
328
- case "ObjectPattern":
329
- for (const property of node.properties) {
330
- if (property.type === "RestElement") {
331
- this.visitBindingPattern(property.argument);
332
- continue;
333
- }
334
- this.visitAssignmentProperty(property);
335
- }
336
- return;
337
- }
338
- }
339
- visitAssignmentProperty(node) {
340
- if (node.computed) {
341
- this.visitExpression(node.key);
342
- }
343
- this.visitBindingElement(node.value);
344
- }
345
- visitAssignmentTarget(node) {
346
- switch (node.type) {
347
- case "AssignmentPattern":
348
- this.visitAssignmentTarget(node.left);
349
- this.visitExpression(node.right);
350
- return;
351
- case "RestElement":
352
- this.visitAssignmentTarget(node.argument);
353
- return;
354
- case "Identifier":
355
- this.visitIdentifier(node);
356
- return;
357
- case "MemberExpression":
358
- this.visitMemberExpression(node);
359
- return;
360
- case "ArrayPattern":
361
- for (const element of node.elements) {
362
- if (element === null) {
363
- continue;
364
- }
365
- this.visitAssignmentTarget(element);
366
- }
367
- return;
368
- case "ObjectPattern":
369
- for (const property of node.properties) {
370
- if (property.type === "RestElement") {
371
- this.visitAssignmentTarget(property);
372
- continue;
373
- }
374
- if (property.computed) {
375
- this.visitExpression(property.key);
376
- }
377
- this.visitAssignmentTarget(property.value);
378
- }
379
- return;
380
- }
381
- }
382
- visitIdentifier(node) {
383
- const currentLambda = this.lambdaStack[this.lambdaStack.length - 1];
384
- if (currentLambda === undefined) {
385
- return;
386
- }
387
- const binding = this.resolveBinding(node.name);
388
- if (binding === undefined ||
389
- binding.kind !== "let" ||
390
- binding.ownerLambdaDepth >= currentLambda.depth) {
391
- return;
392
- }
393
- const captureKey = `${currentLambda.nodeId}:${binding.name}`;
394
- if (this.reportedCaptures.has(captureKey)) {
395
- return;
396
- }
397
- this.reportedCaptures.add(captureKey);
398
- this.diagnostics.push({
399
- code: "AS002",
400
- severity: "error",
401
- message: `Lambda closes over let-bound '${binding.name}' from an outer scope. Change it to const or pass it as a parameter.`,
402
- filename: this.filename,
403
- line: node.span.start.line,
404
- column: node.span.start.column,
405
- span: node.span
406
- });
407
- }
408
- withScope(bindings, visit) {
409
- const scope = new Map();
410
- for (const binding of bindings) {
411
- scope.set(binding.name, binding);
412
- }
413
- this.scopes.push(scope);
414
- visit();
415
- this.scopes.pop();
416
- }
417
- resolveBinding(name) {
418
- for (let index = this.scopes.length - 1; index >= 0; index -= 1) {
419
- const binding = this.scopes[index]?.get(name);
420
- if (binding !== undefined) {
421
- return binding;
422
- }
423
- }
424
- return undefined;
425
- }
426
- collectModuleBindings(body) {
427
- const bindings = [];
428
- for (const statement of body) {
429
- if (statement.type === "ImportDeclaration") {
430
- bindings.push(...this.collectImportBindings(statement));
431
- continue;
432
- }
433
- if (statement.type === "VariableDeclaration") {
434
- bindings.push(...this.collectDeclarationBindings(statement));
435
- continue;
436
- }
437
- if (statement.type === "ExportNamedDeclaration") {
438
- bindings.push(...this.collectDeclarationBindings(statement.declaration));
439
- }
440
- }
441
- return bindings;
442
- }
443
- collectBlockBindings(body) {
444
- const bindings = [];
445
- for (const statement of body) {
446
- if (statement.type === "VariableDeclaration") {
447
- bindings.push(...this.collectDeclarationBindings(statement));
448
- }
449
- }
450
- return bindings;
451
- }
452
- collectParameterBindings(node) {
453
- const bindings = [];
454
- for (const parameter of node.params) {
455
- this.collectBindingNamesFromElement(parameter, "param", bindings);
456
- }
457
- return bindings;
458
- }
459
- collectDeclarationBindings(node) {
460
- const bindings = [];
461
- for (const declarator of node.declarations) {
462
- this.collectBindingNamesFromPattern(declarator.id, node.kind, bindings);
463
- }
464
- return bindings;
465
- }
466
- collectCatchBindings(node) {
467
- const bindings = [];
468
- if (node.param !== undefined) {
469
- this.collectBindingNamesFromPattern(node.param, "let", bindings);
470
- }
471
- return bindings;
472
- }
473
- collectImportBindings(node) {
474
- const bindings = [];
475
- for (const specifier of node.specifiers) {
476
- bindings.push(this.createBinding(specifier.local.name, "import"));
477
- }
478
- return bindings;
479
- }
480
- collectBindingNamesFromElement(node, kind, bindings) {
481
- switch (node.type) {
482
- case "AssignmentPattern":
483
- this.collectBindingNamesFromPattern(node.left, kind, bindings);
484
- return;
485
- case "RestElement":
486
- this.collectBindingNamesFromPattern(node.argument, kind, bindings);
487
- return;
488
- default:
489
- this.collectBindingNamesFromPattern(node, kind, bindings);
490
- return;
491
- }
492
- }
493
- collectBindingNamesFromPattern(node, kind, bindings) {
494
- switch (node.type) {
495
- case "Identifier":
496
- bindings.push(this.createBinding(node.name, kind));
497
- return;
498
- case "MemberExpression":
499
- return;
500
- case "ArrayPattern":
501
- for (const element of node.elements) {
502
- if (element !== null) {
503
- this.collectBindingNamesFromElement(element, kind, bindings);
504
- }
505
- }
506
- return;
507
- case "ObjectPattern":
508
- for (const property of node.properties) {
509
- if (property.type === "RestElement") {
510
- this.collectBindingNamesFromPattern(property.argument, kind, bindings);
511
- continue;
512
- }
513
- this.collectBindingNamesFromElement(property.value, kind, bindings);
514
- }
515
- return;
516
- }
517
- }
518
- createBinding(name, kind) {
519
- return {
520
- kind,
521
- name,
522
- ownerLambdaDepth: this.lambdaStack.length
523
- };
524
- }
525
- }