@atlisp/lint 0.2.11 → 0.2.13
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/atlisp-lint.schema.json +32 -2
- package/dist/cache.js +19 -9
- package/dist/checks/builtin-arg-count.d.ts +1 -0
- package/dist/checks/builtin-arg-count.js +5 -0
- package/dist/checks/dangerous-calls.js +1 -0
- package/dist/checks/dangling-defun.d.ts +7 -0
- package/dist/checks/dangling-defun.js +19 -0
- package/dist/checks/global-function-naming.js +159 -35
- package/dist/checks/missing-princ.js +2 -2
- package/dist/checks/nth-usage.d.ts +1 -0
- package/dist/checks/nth-usage.js +16 -1
- package/dist/checks/unused-package-dep.d.ts +1 -0
- package/dist/checks/unused-package-dep.js +53 -0
- package/dist/cli/collector.d.ts +7 -0
- package/dist/cli/collector.js +154 -0
- package/dist/cli/parser.d.ts +30 -0
- package/dist/cli/parser.js +119 -0
- package/dist/config.js +32 -6
- package/dist/disable.js +12 -0
- package/dist/fixes/index.d.ts +8 -0
- package/dist/fixes/index.js +200 -0
- package/dist/index.js +56 -236
- package/dist/locale.js +30 -2
- package/dist/presets.js +24 -0
- package/dist/project.js +182 -134
- package/dist/rules.d.ts +1 -0
- package/dist/rules.js +85 -0
- package/dist/runner.d.ts +2 -3
- package/dist/runner.js +46 -371
- package/dist/types.d.ts +6 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +43 -0
- package/dist/validate.js +12 -0
- package/dist/visitor-runner.d.ts +28 -0
- package/dist/visitor-runner.js +115 -1
- package/dist/visitors/equal-nil.d.ts +8 -0
- package/dist/visitors/equal-nil.js +26 -0
- package/dist/visitors/index.d.ts +5 -0
- package/dist/visitors/index.js +14 -0
- package/dist/visitors/progn-in-cond.d.ts +8 -0
- package/dist/visitors/progn-in-cond.js +33 -0
- package/dist/visitors/redundant-and-or.d.ts +8 -0
- package/dist/visitors/redundant-and-or.js +27 -0
- package/dist/visitors/redundant-car-cdr.d.ts +8 -0
- package/dist/visitors/redundant-car-cdr.js +35 -0
- package/dist/visitors/types.d.ts +13 -0
- package/dist/visitors/types.js +72 -0
- package/package.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.collectFiles = collectFiles;
|
|
37
|
+
exports.collectStagedFiles = collectStagedFiles;
|
|
38
|
+
exports.collectChangedFiles = collectChangedFiles;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const GLOB_PLACEHOLDER = '\x00GLOB\x00';
|
|
43
|
+
const GLOB_RE = new RegExp(GLOB_PLACEHOLDER, 'g');
|
|
44
|
+
function* walkFiles(dir, rootDir, regex) {
|
|
45
|
+
let entries;
|
|
46
|
+
try {
|
|
47
|
+
entries = fs.readdirSync(dir);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
const fullPath = path.join(dir, entry);
|
|
54
|
+
let stat;
|
|
55
|
+
try {
|
|
56
|
+
stat = fs.statSync(fullPath);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const rel = path.relative(rootDir, fullPath).replace(/\\/g, '/');
|
|
62
|
+
if (rel.startsWith('..'))
|
|
63
|
+
continue;
|
|
64
|
+
if (stat.isDirectory()) {
|
|
65
|
+
yield* walkFiles(fullPath, rootDir, regex);
|
|
66
|
+
}
|
|
67
|
+
else if (stat.isFile()) {
|
|
68
|
+
if (regex.test(rel))
|
|
69
|
+
yield fullPath;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function collectChangedFiles(rootDir, baseBranch) {
|
|
74
|
+
try {
|
|
75
|
+
const output = (0, child_process_1.execSync)(`git diff --name-only --diff-filter=ACM ${baseBranch}`, {
|
|
76
|
+
cwd: rootDir,
|
|
77
|
+
encoding: 'utf-8',
|
|
78
|
+
});
|
|
79
|
+
return output
|
|
80
|
+
.split('\n')
|
|
81
|
+
.map(l => l.trim())
|
|
82
|
+
.filter(l => l.endsWith('.lsp'))
|
|
83
|
+
.map(l => path.resolve(rootDir, l))
|
|
84
|
+
.filter(f => fs.existsSync(f));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function globFiles(pattern, rootDir) {
|
|
91
|
+
const regexStr = pattern
|
|
92
|
+
.replace(/\./g, '\\.')
|
|
93
|
+
.replace(/\*\*\//g, GLOB_PLACEHOLDER)
|
|
94
|
+
.replace(/\*\*/g, '.*')
|
|
95
|
+
.replace(/\*/g, '[^/]*')
|
|
96
|
+
.replace(/\?/g, '.')
|
|
97
|
+
.replace(GLOB_RE, '(.*/)?');
|
|
98
|
+
const regex = new RegExp(`^${regexStr}$`);
|
|
99
|
+
return Array.from(walkFiles(rootDir, rootDir, regex));
|
|
100
|
+
}
|
|
101
|
+
function collectFiles(rootDir, opts, config) {
|
|
102
|
+
const files = new Set();
|
|
103
|
+
if (opts.src.length > 0 || opts.test.length > 0) {
|
|
104
|
+
for (const d of opts.src) {
|
|
105
|
+
for (const f of globFiles('**/*.lsp', path.resolve(rootDir, d))) {
|
|
106
|
+
files.add(f);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const d of opts.test) {
|
|
110
|
+
for (const f of globFiles('**/*.lsp', path.resolve(rootDir, d))) {
|
|
111
|
+
files.add(f);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
for (const pattern of config.source.globs) {
|
|
117
|
+
for (const f of globFiles(pattern, rootDir)) {
|
|
118
|
+
files.add(f);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const excludePatterns = config.source.exclude.map(e => {
|
|
123
|
+
const str = e
|
|
124
|
+
.replace(/\./g, '\\.')
|
|
125
|
+
.replace(/\*\*\//g, GLOB_PLACEHOLDER)
|
|
126
|
+
.replace(/\*\*/g, '.*')
|
|
127
|
+
.replace(/\*/g, '[^/]*')
|
|
128
|
+
.replace(GLOB_RE, '(.*/)?');
|
|
129
|
+
return new RegExp(`^${str}$`);
|
|
130
|
+
});
|
|
131
|
+
return Array.from(files)
|
|
132
|
+
.filter(f => {
|
|
133
|
+
const rel = path.relative(rootDir, f).replace(/\\/g, '/');
|
|
134
|
+
for (const re of excludePatterns) {
|
|
135
|
+
if (re.test(rel))
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
})
|
|
140
|
+
.sort();
|
|
141
|
+
}
|
|
142
|
+
function collectStagedFiles(rootDir) {
|
|
143
|
+
const output = (0, child_process_1.execSync)('git diff --cached --name-only --diff-filter=ACM', {
|
|
144
|
+
cwd: rootDir,
|
|
145
|
+
encoding: 'utf-8',
|
|
146
|
+
});
|
|
147
|
+
return output
|
|
148
|
+
.split('\n')
|
|
149
|
+
.map(l => l.trim())
|
|
150
|
+
.filter(l => l.endsWith('.lsp'))
|
|
151
|
+
.map(l => path.resolve(rootDir, l))
|
|
152
|
+
.filter(f => fs.existsSync(f));
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=collector.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface CliOptions {
|
|
2
|
+
src: string[];
|
|
3
|
+
test: string[];
|
|
4
|
+
config?: string;
|
|
5
|
+
staged: boolean;
|
|
6
|
+
diff: boolean;
|
|
7
|
+
changed: string;
|
|
8
|
+
format: 'default' | 'json' | 'sarif' | 'html';
|
|
9
|
+
init: boolean;
|
|
10
|
+
installHook: boolean;
|
|
11
|
+
fix: boolean;
|
|
12
|
+
hookArgs: string;
|
|
13
|
+
cache: boolean;
|
|
14
|
+
clearCache: boolean;
|
|
15
|
+
parallel: boolean;
|
|
16
|
+
project: boolean;
|
|
17
|
+
watch: boolean;
|
|
18
|
+
help: boolean;
|
|
19
|
+
version: boolean;
|
|
20
|
+
formatCode: boolean;
|
|
21
|
+
formatCheck: boolean;
|
|
22
|
+
sbcl: boolean;
|
|
23
|
+
docs: boolean;
|
|
24
|
+
listRules: boolean;
|
|
25
|
+
explain: string;
|
|
26
|
+
dryRun: boolean;
|
|
27
|
+
maxWarnings: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function parseArgs(): CliOptions;
|
|
30
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseArgs = parseArgs;
|
|
4
|
+
function parseArgs() {
|
|
5
|
+
const argv = process.argv.slice(2);
|
|
6
|
+
const opts = {
|
|
7
|
+
src: [],
|
|
8
|
+
test: [],
|
|
9
|
+
staged: false,
|
|
10
|
+
diff: false,
|
|
11
|
+
changed: '',
|
|
12
|
+
format: 'default',
|
|
13
|
+
init: false,
|
|
14
|
+
installHook: false,
|
|
15
|
+
fix: false,
|
|
16
|
+
hookArgs: '',
|
|
17
|
+
cache: false,
|
|
18
|
+
clearCache: false,
|
|
19
|
+
parallel: false,
|
|
20
|
+
project: false,
|
|
21
|
+
watch: false,
|
|
22
|
+
help: false,
|
|
23
|
+
version: false,
|
|
24
|
+
formatCode: false,
|
|
25
|
+
formatCheck: false,
|
|
26
|
+
sbcl: false,
|
|
27
|
+
docs: false,
|
|
28
|
+
listRules: false,
|
|
29
|
+
explain: '',
|
|
30
|
+
dryRun: false,
|
|
31
|
+
maxWarnings: -1,
|
|
32
|
+
};
|
|
33
|
+
for (let i = 0; i < argv.length; i++) {
|
|
34
|
+
switch (argv[i]) {
|
|
35
|
+
case '--src':
|
|
36
|
+
opts.src.push(argv[++i]);
|
|
37
|
+
break;
|
|
38
|
+
case '--test':
|
|
39
|
+
opts.test.push(argv[++i]);
|
|
40
|
+
break;
|
|
41
|
+
case '--config':
|
|
42
|
+
opts.config = argv[++i];
|
|
43
|
+
break;
|
|
44
|
+
case '--staged':
|
|
45
|
+
opts.staged = true;
|
|
46
|
+
break;
|
|
47
|
+
case '--diff':
|
|
48
|
+
opts.diff = true;
|
|
49
|
+
break;
|
|
50
|
+
case '--changed':
|
|
51
|
+
opts.changed = argv[++i] || 'main';
|
|
52
|
+
break;
|
|
53
|
+
case '--format':
|
|
54
|
+
opts.format = argv[++i];
|
|
55
|
+
break;
|
|
56
|
+
case '--init':
|
|
57
|
+
opts.init = true;
|
|
58
|
+
break;
|
|
59
|
+
case '--install-hook':
|
|
60
|
+
opts.installHook = true;
|
|
61
|
+
break;
|
|
62
|
+
case '--fix':
|
|
63
|
+
opts.fix = true;
|
|
64
|
+
break;
|
|
65
|
+
case '--hook-args':
|
|
66
|
+
opts.hookArgs = argv[++i];
|
|
67
|
+
break;
|
|
68
|
+
case '--cache':
|
|
69
|
+
opts.cache = true;
|
|
70
|
+
break;
|
|
71
|
+
case '--clear-cache':
|
|
72
|
+
opts.clearCache = true;
|
|
73
|
+
break;
|
|
74
|
+
case '--parallel':
|
|
75
|
+
opts.parallel = true;
|
|
76
|
+
break;
|
|
77
|
+
case '--project':
|
|
78
|
+
opts.project = true;
|
|
79
|
+
break;
|
|
80
|
+
case '--watch':
|
|
81
|
+
opts.watch = true;
|
|
82
|
+
break;
|
|
83
|
+
case '--help':
|
|
84
|
+
opts.help = true;
|
|
85
|
+
break;
|
|
86
|
+
case '--version':
|
|
87
|
+
opts.version = true;
|
|
88
|
+
break;
|
|
89
|
+
case '--format-code':
|
|
90
|
+
opts.formatCode = true;
|
|
91
|
+
break;
|
|
92
|
+
case '--format-check':
|
|
93
|
+
opts.formatCheck = true;
|
|
94
|
+
break;
|
|
95
|
+
case '--sbcl':
|
|
96
|
+
opts.sbcl = true;
|
|
97
|
+
break;
|
|
98
|
+
case '--docs':
|
|
99
|
+
opts.docs = true;
|
|
100
|
+
break;
|
|
101
|
+
case '--list-rules':
|
|
102
|
+
opts.listRules = true;
|
|
103
|
+
break;
|
|
104
|
+
case '--explain':
|
|
105
|
+
opts.explain = argv[++i];
|
|
106
|
+
break;
|
|
107
|
+
case '--dry-run':
|
|
108
|
+
opts.dryRun = true;
|
|
109
|
+
break;
|
|
110
|
+
case '--max-warnings':
|
|
111
|
+
opts.maxWarnings = parseInt(argv[++i], 10);
|
|
112
|
+
break;
|
|
113
|
+
default:
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return opts;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=parser.js.map
|
package/dist/config.js
CHANGED
|
@@ -65,6 +65,18 @@ const DEFAULT_CONFIG = {
|
|
|
65
65
|
missing_doc: 'info',
|
|
66
66
|
trailing_whitespace: 'info',
|
|
67
67
|
undeclared_setq: 'warn',
|
|
68
|
+
command_s: 'warn',
|
|
69
|
+
zerop_usage: 'info',
|
|
70
|
+
progn_in_body: 'info',
|
|
71
|
+
if_progn_both: 'info',
|
|
72
|
+
redundant_cond: 'info',
|
|
73
|
+
selection_set_leak: 'warn',
|
|
74
|
+
empty_branch_cond: 'warn',
|
|
75
|
+
function_reference: 'warn',
|
|
76
|
+
progn_in_cond: 'info',
|
|
77
|
+
redundant_car_cdr: 'info',
|
|
78
|
+
equal_nil: 'info',
|
|
79
|
+
redundant_and_or: 'info',
|
|
68
80
|
module_registration: 'off',
|
|
69
81
|
namespace_header: 'off',
|
|
70
82
|
unused_parameter: 'warn',
|
|
@@ -152,6 +164,7 @@ const DEFAULT_CONFIG = {
|
|
|
152
164
|
command_shell: 'warn',
|
|
153
165
|
startapp: 'warn',
|
|
154
166
|
vl_registry_write: 'warn',
|
|
167
|
+
eval: 'warn',
|
|
155
168
|
},
|
|
156
169
|
module_registration: {
|
|
157
170
|
severity: 'off',
|
|
@@ -172,6 +185,10 @@ const DEFAULT_CONFIG = {
|
|
|
172
185
|
walk_exclude: ['.vscode', 'vendor', '.git'],
|
|
173
186
|
defmacro_allow_files: ['compat-cl'],
|
|
174
187
|
},
|
|
188
|
+
project_analysis: {
|
|
189
|
+
maxFiles: 500,
|
|
190
|
+
batchSize: 50,
|
|
191
|
+
},
|
|
175
192
|
};
|
|
176
193
|
function loadConfig(configPath) {
|
|
177
194
|
if (configPath) {
|
|
@@ -215,13 +232,22 @@ function getCheckSeverity(config, rule) {
|
|
|
215
232
|
return config.checks[rule] || 'off';
|
|
216
233
|
}
|
|
217
234
|
function findOverrides(filepath) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
235
|
+
let dir = path.dirname(filepath);
|
|
236
|
+
for (;;) {
|
|
237
|
+
const configPath = path.join(dir, '.atlisp-lint.json');
|
|
238
|
+
if (fs.existsSync(configPath)) {
|
|
239
|
+
try {
|
|
240
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const parent = path.dirname(dir);
|
|
247
|
+
if (parent === dir)
|
|
248
|
+
return null;
|
|
249
|
+
dir = parent;
|
|
223
250
|
}
|
|
224
|
-
return null;
|
|
225
251
|
}
|
|
226
252
|
function mergeOverrides(base, overrides) {
|
|
227
253
|
const merged = JSON.parse(JSON.stringify(base));
|
package/dist/disable.js
CHANGED
|
@@ -7,6 +7,18 @@ function parseDisableComments(content, fileLine) {
|
|
|
7
7
|
const lines = content.split('\n');
|
|
8
8
|
for (let i = 0; i < lines.length; i++) {
|
|
9
9
|
const line = lines[i];
|
|
10
|
+
const disableFileM = line.match(/;\s*atlisp-lint:\s*disable-file=(.+)/i);
|
|
11
|
+
if (disableFileM) {
|
|
12
|
+
const rules = disableFileM[1]
|
|
13
|
+
.split(',')
|
|
14
|
+
.map(r => r.trim())
|
|
15
|
+
.filter(Boolean);
|
|
16
|
+
for (const rule of rules) {
|
|
17
|
+
if (!map.has(rule))
|
|
18
|
+
map.set(rule, new Set());
|
|
19
|
+
map.get(rule).add(0);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
10
22
|
const m = line.match(/;\s*atlisp-lint:\s*disable=(.+)/i);
|
|
11
23
|
if (!m)
|
|
12
24
|
continue;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Issue } from '../types';
|
|
2
|
+
export type FixResult = string | null;
|
|
3
|
+
export interface FixProvider {
|
|
4
|
+
(line: string): string;
|
|
5
|
+
}
|
|
6
|
+
export declare const FIXABLE_RULES: Set<string>;
|
|
7
|
+
export declare function applyFixesFromProviders(issues: Issue[], content: string, filepath: string): string;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FIXABLE_RULES = void 0;
|
|
4
|
+
exports.applyFixesFromProviders = applyFixesFromProviders;
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const nth_usage_1 = require("../checks/nth-usage");
|
|
7
|
+
const FIX_PROVIDERS = {
|
|
8
|
+
redundant_quotes(line) {
|
|
9
|
+
return line.replace(/''(\S)/g, "'$1");
|
|
10
|
+
},
|
|
11
|
+
double_not(line) {
|
|
12
|
+
return line.replace(/\(not\s+\(not\s+/g, '(not ');
|
|
13
|
+
},
|
|
14
|
+
redundant_nil_else(line) {
|
|
15
|
+
return line.replace(/\s+nil\s*\)$/, ')');
|
|
16
|
+
},
|
|
17
|
+
single_arg_and_or(line) {
|
|
18
|
+
const m = line.match(/\((and|or)\s+([^)\s]+)\s*\)/);
|
|
19
|
+
return m ? m[2] : line;
|
|
20
|
+
},
|
|
21
|
+
redundant_progn(line) {
|
|
22
|
+
const proIdx = line.indexOf('(progn ');
|
|
23
|
+
if (proIdx === -1)
|
|
24
|
+
return line;
|
|
25
|
+
const beforePro = line.slice(0, proIdx);
|
|
26
|
+
const close = (0, utils_1.findMatchingParen)(line, proIdx);
|
|
27
|
+
if (close <= proIdx)
|
|
28
|
+
return line;
|
|
29
|
+
const inner = line.slice(proIdx + 7, close);
|
|
30
|
+
const rest = line.slice(close + 1);
|
|
31
|
+
return beforePro + inner + rest;
|
|
32
|
+
},
|
|
33
|
+
redundant_let(line) {
|
|
34
|
+
return line.replace(/\(let\s+\(\)\s*/, '(progn ');
|
|
35
|
+
},
|
|
36
|
+
quote_style(line) {
|
|
37
|
+
const qIdx = line.indexOf('(quote ');
|
|
38
|
+
if (qIdx === -1)
|
|
39
|
+
return line;
|
|
40
|
+
const beforeQ = line.slice(0, qIdx);
|
|
41
|
+
const close = (0, utils_1.findMatchingParen)(line, qIdx);
|
|
42
|
+
if (close <= qIdx)
|
|
43
|
+
return line;
|
|
44
|
+
const quoted = line.slice(qIdx + 7, close);
|
|
45
|
+
const rest = line.slice(close + 1);
|
|
46
|
+
return beforeQ + "'" + quoted + rest;
|
|
47
|
+
},
|
|
48
|
+
redundant_if(line) {
|
|
49
|
+
const pIdx = line.indexOf('(progn ');
|
|
50
|
+
if (pIdx === -1)
|
|
51
|
+
return line;
|
|
52
|
+
const beforeP = line.slice(0, pIdx);
|
|
53
|
+
const close = (0, utils_1.findMatchingParen)(line, pIdx);
|
|
54
|
+
if (close <= pIdx)
|
|
55
|
+
return line;
|
|
56
|
+
const inner = line.slice(pIdx + 7, close);
|
|
57
|
+
const rest = line.slice(close + 1);
|
|
58
|
+
return beforeP + inner + rest;
|
|
59
|
+
},
|
|
60
|
+
misplaced_else(line) {
|
|
61
|
+
const ifStart = line.indexOf('(if (not ');
|
|
62
|
+
if (ifStart === -1)
|
|
63
|
+
return line;
|
|
64
|
+
const notIdx = line.indexOf('(not ', ifStart);
|
|
65
|
+
if (notIdx === -1)
|
|
66
|
+
return line;
|
|
67
|
+
const notClose = (0, utils_1.findMatchingParen)(line, notIdx);
|
|
68
|
+
if (notClose <= notIdx)
|
|
69
|
+
return line;
|
|
70
|
+
const ifClose = (0, utils_1.findMatchingParen)(line, ifStart);
|
|
71
|
+
if (ifClose <= ifStart)
|
|
72
|
+
return line;
|
|
73
|
+
const indent = line.slice(0, ifStart);
|
|
74
|
+
const condVar = line.slice(notIdx + 5, notClose);
|
|
75
|
+
const branchContent = line.slice(notClose + 1, ifClose).trim();
|
|
76
|
+
const [thenForm, thenEnd] = (0, utils_1.extractForm)(branchContent, 0);
|
|
77
|
+
const elseForm = branchContent.slice(thenEnd).trim();
|
|
78
|
+
if (!thenForm || !elseForm)
|
|
79
|
+
return line;
|
|
80
|
+
const rest = line.slice(ifClose + 1);
|
|
81
|
+
return indent + '(if ' + condVar + ' ' + elseForm + ' ' + thenForm + ')' + rest;
|
|
82
|
+
},
|
|
83
|
+
setq_multiple(line) {
|
|
84
|
+
const fixed = line.replace(/\)\(setq\s+/g, ' ');
|
|
85
|
+
if (fixed === line)
|
|
86
|
+
return line;
|
|
87
|
+
const merged = line.replace(/^\(\s*setq\s+/, '(setq ');
|
|
88
|
+
if (merged.includes('setq') && !merged.match(/\)\(/))
|
|
89
|
+
return merged;
|
|
90
|
+
return line.replace(/\)\(setq\s+/g, '\n');
|
|
91
|
+
},
|
|
92
|
+
append_single(line) {
|
|
93
|
+
const aIdx = line.indexOf('(append ');
|
|
94
|
+
if (aIdx === -1)
|
|
95
|
+
return line;
|
|
96
|
+
const close = (0, utils_1.findMatchingParen)(line, aIdx);
|
|
97
|
+
if (close <= aIdx)
|
|
98
|
+
return line;
|
|
99
|
+
const inner = line.slice(aIdx + 8, close);
|
|
100
|
+
const listMatch = inner.match(/^\(list\s+(.*)\)\s*$/);
|
|
101
|
+
if (!listMatch)
|
|
102
|
+
return line;
|
|
103
|
+
return line.slice(0, aIdx) + '(cons ' + listMatch[1] + ')' + line.slice(close + 1);
|
|
104
|
+
},
|
|
105
|
+
nth_usage(line) {
|
|
106
|
+
return (0, nth_usage_1.replaceNthUsage)(line) || line;
|
|
107
|
+
},
|
|
108
|
+
setq_single_arg(line) {
|
|
109
|
+
return line;
|
|
110
|
+
},
|
|
111
|
+
extra_parens(line) {
|
|
112
|
+
return line.replace(/\){2,}/g, ')');
|
|
113
|
+
},
|
|
114
|
+
empty_branch(line) {
|
|
115
|
+
return line.replace(/\(if\s+\S+\s*\)/g, m => m.slice(0, -1) + ' nil)');
|
|
116
|
+
},
|
|
117
|
+
comment_style(line) {
|
|
118
|
+
return line.replace(/^(\s*;)([^ ;|].*)$/gm, '$1 $2');
|
|
119
|
+
},
|
|
120
|
+
eq_usage(line) {
|
|
121
|
+
return line.replace(/\(eq\s+(\S+)\s+(\d+)\s*\)/g, '(= $1 $2)');
|
|
122
|
+
},
|
|
123
|
+
cond_simplify(line) {
|
|
124
|
+
const condIdx = line.indexOf('(cond ');
|
|
125
|
+
if (condIdx === -1)
|
|
126
|
+
return line;
|
|
127
|
+
const condEnd = (0, utils_1.findMatchingParen)(line, condIdx);
|
|
128
|
+
if (condEnd <= condIdx)
|
|
129
|
+
return line;
|
|
130
|
+
const inner = line.slice(condIdx + 6, condEnd).trim();
|
|
131
|
+
const branchOpen = inner.indexOf('(');
|
|
132
|
+
if (branchOpen === -1)
|
|
133
|
+
return line;
|
|
134
|
+
const branchEnd = (0, utils_1.findMatchingParen)(inner, branchOpen);
|
|
135
|
+
if (branchEnd <= branchOpen)
|
|
136
|
+
return line;
|
|
137
|
+
const indent = line.slice(0, condIdx);
|
|
138
|
+
const branchContent = inner.slice(branchOpen + 1, branchEnd).trim();
|
|
139
|
+
const space = branchContent.search(/\s+/);
|
|
140
|
+
if (space === -1)
|
|
141
|
+
return line;
|
|
142
|
+
const testExpr = branchContent.slice(0, space);
|
|
143
|
+
const bodyExpr = branchContent.slice(space).trim();
|
|
144
|
+
const rest = line.slice(condEnd + 1);
|
|
145
|
+
return indent + '(if ' + testExpr + ' ' + bodyExpr + ')' + rest;
|
|
146
|
+
},
|
|
147
|
+
self_compare(line) {
|
|
148
|
+
return line.replace(/\((?:[=/<>]+|eq|equal)\s+(\S+)\s+\1\s*\)/g, 'T');
|
|
149
|
+
},
|
|
150
|
+
while_constant(line) {
|
|
151
|
+
const trimmed = line.trim();
|
|
152
|
+
const nilMatch = trimmed.match(/^\(\s*while\s+nil\s+(.*)\)\s*$/);
|
|
153
|
+
if (!nilMatch)
|
|
154
|
+
return line;
|
|
155
|
+
return line.replace(trimmed, 'nil');
|
|
156
|
+
},
|
|
157
|
+
redundant_list(line) {
|
|
158
|
+
return line.replace(/\(\s*list\s*\)/g, 'nil');
|
|
159
|
+
},
|
|
160
|
+
zerop_usage(line) {
|
|
161
|
+
return line.replace(/\(=\s+(\S+)\s+0\s*\)/g, '(zerop $1)').replace(/\(=\s+0\s+(\S+)\s*\)/g, '(zerop $1)');
|
|
162
|
+
},
|
|
163
|
+
redundant_cond(line) {
|
|
164
|
+
const m = line.match(/^(\s*)\(cond\s+\(\(([^)]+)\)\s+\(([^)]*)\)\s*\)\s*\)$/);
|
|
165
|
+
if (!m)
|
|
166
|
+
return line;
|
|
167
|
+
return `${m[1]}(if (${m[2]}) (${m[3]}))`;
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
exports.FIXABLE_RULES = new Set(Object.keys(FIX_PROVIDERS));
|
|
171
|
+
function applyFixesFromProviders(issues, content, filepath) {
|
|
172
|
+
const lines = content.split('\n');
|
|
173
|
+
const fixedLines = new Set();
|
|
174
|
+
const fixesByRule = new Map();
|
|
175
|
+
for (const iss of issues) {
|
|
176
|
+
if (iss.file !== filepath)
|
|
177
|
+
continue;
|
|
178
|
+
const set = fixesByRule.get(iss.rule) || new Set();
|
|
179
|
+
set.add(iss.line);
|
|
180
|
+
fixesByRule.set(iss.rule, set);
|
|
181
|
+
}
|
|
182
|
+
for (const [rule, lineSet] of fixesByRule) {
|
|
183
|
+
const provider = FIX_PROVIDERS[rule];
|
|
184
|
+
if (!provider)
|
|
185
|
+
continue;
|
|
186
|
+
const sortedLines = Array.from(lineSet).sort((a, b) => b - a);
|
|
187
|
+
for (const line of sortedLines) {
|
|
188
|
+
const idx = line - 1;
|
|
189
|
+
if (idx < 0 || idx >= lines.length)
|
|
190
|
+
continue;
|
|
191
|
+
const fixed = provider(lines[idx]);
|
|
192
|
+
if (fixed !== lines[idx]) {
|
|
193
|
+
lines[idx] = fixed;
|
|
194
|
+
fixedLines.add(idx);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return lines.join('\n');
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=index.js.map
|