@atlisp/lint 0.2.17 → 0.2.19
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/formatter.js +141 -25
- package/package.json +1 -1
package/dist/formatter.js
CHANGED
|
@@ -2,13 +2,108 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatCode = formatCode;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
|
+
const parser_1 = require("@atlisp/parser");
|
|
5
6
|
function isCommentLine(line) {
|
|
6
7
|
const trimmed = line.trim();
|
|
7
8
|
return trimmed.startsWith(';') || trimmed.startsWith(';|');
|
|
8
9
|
}
|
|
10
|
+
function findMultiPairSetq(content) {
|
|
11
|
+
try {
|
|
12
|
+
const ast = (0, parser_1.parseAst)(content, { errorRecovery: true });
|
|
13
|
+
if (!ast)
|
|
14
|
+
return [];
|
|
15
|
+
const ranges = [];
|
|
16
|
+
for (const node of (0, parser_1.astWalk)(ast)) {
|
|
17
|
+
if (!(0, parser_1.astIsList)(node))
|
|
18
|
+
continue;
|
|
19
|
+
const children = node.children;
|
|
20
|
+
if (children.length < 6)
|
|
21
|
+
continue;
|
|
22
|
+
const first = children[0];
|
|
23
|
+
if (!(0, parser_1.astIsSymbol)(first) || first.name.toLowerCase() !== 'setq')
|
|
24
|
+
continue;
|
|
25
|
+
const start = node.pos.offset;
|
|
26
|
+
const end = node.end?.offset ?? start;
|
|
27
|
+
const startLine = content.substring(0, start).split('\n').length - 1;
|
|
28
|
+
const endLine = content.substring(0, end).split('\n').length - 1;
|
|
29
|
+
ranges.push({ startLine, endLine, startOffset: start, endOffset: end });
|
|
30
|
+
}
|
|
31
|
+
return ranges;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function formatSetqFromNode(node, depth, indentSize, content) {
|
|
38
|
+
const children = node.children;
|
|
39
|
+
const pairs = [];
|
|
40
|
+
for (let i = 1; i + 1 < children.length; i += 2) {
|
|
41
|
+
const varNode = children[i];
|
|
42
|
+
const valNode = children[i + 1];
|
|
43
|
+
let varText;
|
|
44
|
+
if ((0, parser_1.astIsSymbol)(varNode)) {
|
|
45
|
+
varText = varNode.name;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const vs = varNode.pos.offset;
|
|
49
|
+
const ve = varNode.end?.offset ?? vs;
|
|
50
|
+
varText = content.slice(vs, ve);
|
|
51
|
+
}
|
|
52
|
+
const vs = valNode.pos.offset;
|
|
53
|
+
const ve = valNode.end?.offset ?? vs;
|
|
54
|
+
const valText = content.slice(vs, ve);
|
|
55
|
+
pairs.push({ varText, valText });
|
|
56
|
+
}
|
|
57
|
+
if (pairs.length < 2) {
|
|
58
|
+
const indent = ' '.repeat(depth * indentSize);
|
|
59
|
+
return [indent + '(setq ' + pairs.map(p => p.varText + ' ' + p.valText).join(' ') + ')'];
|
|
60
|
+
}
|
|
61
|
+
const maxVarLen = Math.max(...pairs.map(p => p.varText.length));
|
|
62
|
+
const baseIndent = ' '.repeat(depth * indentSize);
|
|
63
|
+
const setqPrefix = '(setq ';
|
|
64
|
+
const varColumn = depth * indentSize + setqPrefix.length;
|
|
65
|
+
const lines = [];
|
|
66
|
+
lines.push(baseIndent + setqPrefix + pairs[0].varText + ' ' + pairs[0].valText);
|
|
67
|
+
const continuationIndent = ' '.repeat(varColumn);
|
|
68
|
+
for (let i = 1; i < pairs.length; i++) {
|
|
69
|
+
const padding = maxVarLen - pairs[i].varText.length;
|
|
70
|
+
const isLast = i === pairs.length - 1;
|
|
71
|
+
lines.push(continuationIndent + pairs[i].varText + ' '.repeat(padding + 1) + pairs[i].valText + (isLast ? ')' : ''));
|
|
72
|
+
}
|
|
73
|
+
return lines;
|
|
74
|
+
}
|
|
75
|
+
function runStandardFormat(lines, lineIdx, depth, _indentSize, rawLine, trimmed) {
|
|
76
|
+
const isComment = isCommentLine(trimmed);
|
|
77
|
+
const stripped = (0, utils_1.stripLine)(trimmed);
|
|
78
|
+
const trimmedStripped = stripped.trim();
|
|
79
|
+
if (trimmedStripped === '') {
|
|
80
|
+
return {
|
|
81
|
+
formattedLines: [' '.repeat(depth * _indentSize) + trimmed.trimStart()],
|
|
82
|
+
newDepth: depth
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const opens = (trimmedStripped.match(/\(/g) || []).length;
|
|
86
|
+
const closes = (trimmedStripped.match(/\)/g) || []).length;
|
|
87
|
+
let leadingCloseCount = 0;
|
|
88
|
+
for (const ch of trimmedStripped) {
|
|
89
|
+
if (ch === ')')
|
|
90
|
+
leadingCloseCount++;
|
|
91
|
+
else
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
let effectiveDepth = depth;
|
|
95
|
+
if (leadingCloseCount > 0) {
|
|
96
|
+
effectiveDepth = Math.max(0, depth - leadingCloseCount);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
formattedLines: [' '.repeat(effectiveDepth * _indentSize) + trimmed.trimStart()],
|
|
100
|
+
newDepth: depth + opens - closes
|
|
101
|
+
};
|
|
102
|
+
}
|
|
9
103
|
function formatCode(content, indentSize = 2) {
|
|
10
104
|
if (content === '' || content === '\n')
|
|
11
105
|
return content;
|
|
106
|
+
const setqRanges = findMultiPairSetq(content);
|
|
12
107
|
const lines = content.split('\n');
|
|
13
108
|
const result = [];
|
|
14
109
|
let depth = 0;
|
|
@@ -19,33 +114,54 @@ function formatCode(content, indentSize = 2) {
|
|
|
19
114
|
result.push('');
|
|
20
115
|
continue;
|
|
21
116
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
117
|
+
const sqRange = setqRanges.find(sq => sq.startLine === lineIdx);
|
|
118
|
+
if (sqRange) {
|
|
119
|
+
const setqText = content.slice(sqRange.startOffset, sqRange.endOffset);
|
|
120
|
+
const ast = (0, parser_1.parseAst)(setqText, { errorRecovery: true });
|
|
121
|
+
let sqNode;
|
|
122
|
+
if (ast) {
|
|
123
|
+
for (const n of (0, parser_1.astWalk)(ast)) {
|
|
124
|
+
if ((0, parser_1.astIsList)(n)) {
|
|
125
|
+
const f = n.children[0];
|
|
126
|
+
if ((0, parser_1.astIsSymbol)(f) && f.name.toLowerCase() === 'setq') {
|
|
127
|
+
sqNode = n;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (sqNode && (0, parser_1.astIsList)(sqNode)) {
|
|
134
|
+
const formattedLines = formatSetqFromNode(sqNode, depth, indentSize, setqText);
|
|
135
|
+
result.push(...formattedLines);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
const indent = ' '.repeat(depth * indentSize);
|
|
139
|
+
result.push(indent + trimmed.trimStart());
|
|
140
|
+
}
|
|
141
|
+
// Emit any trailing content after setq's end on the same line (e.g., extra ))
|
|
142
|
+
const afterSetqText = content.slice(sqRange.endOffset);
|
|
143
|
+
const afterSetqLine = afterSetqText.split('\n')[0];
|
|
144
|
+
if (afterSetqLine.trim()) {
|
|
145
|
+
const sAfter = (0, utils_1.stripLine)(afterSetqLine);
|
|
146
|
+
const tAfter = sAfter.trim();
|
|
147
|
+
if (tAfter) {
|
|
148
|
+
const opensAfter = (tAfter.match(/\(/g) || []).length;
|
|
149
|
+
const closesAfter = (tAfter.match(/\)/g) || []).length;
|
|
150
|
+
depth += opensAfter - closesAfter;
|
|
151
|
+
if (depth < 0)
|
|
152
|
+
depth = 0;
|
|
153
|
+
const leadingCloseCount = (tAfter.match(/^\)+/g) || [''])[0].length;
|
|
154
|
+
const outdent = depth - leadingCloseCount + (opensAfter - closesAfter);
|
|
155
|
+
const effectiveDepth = Math.max(0, depth - leadingCloseCount + (opensAfter - closesAfter));
|
|
156
|
+
result.push(' '.repeat(effectiveDepth * indentSize) + afterSetqLine.trim());
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
lineIdx = sqRange.endLine;
|
|
27
160
|
continue;
|
|
28
161
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
const opens = (trimmedStripped.match(/\(/g) || []).length;
|
|
34
|
-
const closes = (trimmedStripped.match(/\)/g) || []).length;
|
|
35
|
-
let leadingCloseCount = 0;
|
|
36
|
-
for (const ch of trimmedStripped) {
|
|
37
|
-
if (ch === ')')
|
|
38
|
-
leadingCloseCount++;
|
|
39
|
-
else
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
let effectiveDepth = depth;
|
|
43
|
-
if (leadingCloseCount > 0) {
|
|
44
|
-
effectiveDepth = Math.max(0, depth - leadingCloseCount);
|
|
45
|
-
}
|
|
46
|
-
const indent = ' '.repeat(effectiveDepth * indentSize);
|
|
47
|
-
result.push(indent + trimmed.trimStart());
|
|
48
|
-
depth += opens - closes;
|
|
162
|
+
const { formattedLines, newDepth } = runStandardFormat(lines, lineIdx, depth, indentSize, rawLine, trimmed);
|
|
163
|
+
result.push(...formattedLines);
|
|
164
|
+
depth = newDepth;
|
|
49
165
|
if (depth < 0)
|
|
50
166
|
depth = 0;
|
|
51
167
|
}
|