@atlisp/lint 0.1.14 → 0.1.15

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.
@@ -2,60 +2,48 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkGlobalNaming = checkGlobalNaming;
4
4
  const locale_1 = require("../locale");
5
- const utils_1 = require("../utils");
6
- function checkGlobalNaming(content, file) {
7
- const issues = [];
8
- const lines = content.split('\n');
9
- let depth = 0;
10
- let inDefun = false;
11
- let defunLocals = new Set();
12
- for (let i = 0; i < lines.length; i++) {
13
- const stripped = (0, utils_1.stripLine)(lines[i]);
14
- // Track depth
15
- for (const ch of stripped) {
16
- if (ch === '(')
17
- depth++;
18
- else if (ch === ')')
19
- depth--;
20
- }
21
- // Detect defun start and extract local variables
22
- if (!inDefun) {
23
- const defunMatch = stripped.match(/\(defun\s+\S+\s+\(([^)]*\/\s+[^)]*)\)/);
24
- if (defunMatch) {
25
- inDefun = true;
26
- const all = defunMatch[1];
27
- const slashIdx = all.indexOf('/');
28
- defunLocals = new Set(all
29
- .slice(slashIdx + 1)
30
- .split(/\s+/)
31
- .filter(Boolean));
32
- }
33
- }
34
- if (depth <= 0) {
35
- inDefun = false;
36
- defunLocals = new Set();
37
- }
38
- // setq at depth 0 or 1 (top-level or directly inside progn) is global
39
- if (depth <= 1) {
40
- const m = stripped.match(/\(setq\s+(\S+)/);
41
- if (m) {
42
- const v = m[1];
43
- if (v !== 'T' &&
44
- v !== 'nil' &&
45
- !v.startsWith('*') &&
46
- !v.endsWith('*') &&
47
- !v.includes('/') &&
48
- !defunLocals.has(v)) {
49
- issues.push({
50
- file,
51
- line: i + 1,
52
- severity: 'warn',
53
- rule: 'global_naming',
54
- message: (0, locale_1.t)('global_naming', v),
55
- });
5
+ const parser_1 = require("@atlisp/parser");
6
+ function isInsideLocalScope(node) {
7
+ let cur = node.parent;
8
+ while (cur) {
9
+ if (cur.type === 'list' && cur.children && cur.children.length > 0) {
10
+ const head = cur.children[0];
11
+ if (head.type === 'symbol' && head.name) {
12
+ if (['defun', 'lambda', 'let', 'let*'].includes(head.name)) {
13
+ return true;
56
14
  }
57
15
  }
58
16
  }
17
+ cur = cur.parent;
18
+ }
19
+ return false;
20
+ }
21
+ function checkGlobalNaming(content, file) {
22
+ const issues = [];
23
+ const ast = (0, parser_1.parseAst)(content);
24
+ const setqForms = (0, parser_1.astFindListWithHead)(ast, 'setq');
25
+ for (const form of setqForms) {
26
+ if (!form.children || form.children.length < 2)
27
+ continue;
28
+ // Skip setq inside defun/lambda/let — those are local
29
+ if (isInsideLocalScope(form))
30
+ continue;
31
+ for (let i = 1; i < form.children.length; i += 2) {
32
+ const v = form.children[i];
33
+ if (v.type !== 'symbol' || !v.name)
34
+ continue;
35
+ if (v.name === 'T' || v.name === 'nil')
36
+ continue;
37
+ if (v.name.startsWith('*') && v.name.endsWith('*'))
38
+ continue;
39
+ issues.push({
40
+ file,
41
+ line: v.pos.line,
42
+ severity: 'warn',
43
+ rule: 'global_naming',
44
+ message: (0, locale_1.t)('global_naming', v.name),
45
+ });
46
+ }
59
47
  }
60
48
  return issues;
61
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlisp/lint",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "AutoLISP static analysis tool — parens, security, conventions, SBCL syntax validation",
5
5
  "keywords": [
6
6
  "CAD",