@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.
- package/dist/checks/global-naming.js +39 -51
- package/package.json +1 -1
|
@@ -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
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
}
|