forked from sindresorhus/eslint-plugin-unicorn
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rule.js
148 lines (122 loc) · 3.13 KB
/
rule.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
'use strict';
const path = require('node:path');
const fs = require('node:fs');
const getDocumentationUrl = require('./get-documentation-url.js');
const isIterable = object => typeof object[Symbol.iterator] === 'function';
class FixAbortError extends Error {}
const fixOptions = {
abort() {
throw new FixAbortError('Fix aborted.');
},
};
function wrapFixFunction(fix) {
return fixer => {
const result = fix(fixer, fixOptions);
if (result && isIterable(result)) {
try {
return [...result];
} catch (error) {
if (error instanceof FixAbortError) {
return;
}
/* c8 ignore next */
throw error;
}
}
return result;
};
}
function reportListenerProblems(listener, context) {
// Listener arguments can be `codePath, node` or `node`
return function (...listenerArguments) {
let problems = listener(...listenerArguments);
if (!problems) {
return;
}
if (!isIterable(problems)) {
problems = [problems];
}
for (const problem of problems) {
if (problem.fix) {
problem.fix = wrapFixFunction(problem.fix);
}
if (Array.isArray(problem.suggest)) {
for (const suggest of problem.suggest) {
if (suggest.fix) {
suggest.fix = wrapFixFunction(suggest.fix);
}
}
}
context.report(problem);
}
};
}
// `checkVueTemplate` function will wrap `create` function, there is no need to wrap twice
const wrappedFunctions = new Set();
function reportProblems(create) {
if (wrappedFunctions.has(create)) {
return create;
}
const wrapped = context => Object.fromEntries(
Object.entries(create(context))
.map(([selector, listener]) => [selector, reportListenerProblems(listener, context)]),
);
wrappedFunctions.add(wrapped);
return wrapped;
}
function checkVueTemplate(create, options) {
const {
visitScriptBlock,
} = {
visitScriptBlock: true,
...options,
};
create = reportProblems(create);
const wrapped = context => {
const listeners = create(context);
// `vue-eslint-parser`
if (
context.parserServices
&& context.parserServices.defineTemplateBodyVisitor
) {
return visitScriptBlock
? context.parserServices.defineTemplateBodyVisitor(listeners, listeners)
: context.parserServices.defineTemplateBodyVisitor(listeners);
}
return listeners;
};
wrappedFunctions.add(wrapped);
return wrapped;
}
/** @returns {import('eslint').Rule.RuleModule} */
function loadRule(ruleId) {
const rule = require(`../${ruleId}`);
return {
meta: {
// If there is are, options add `[]` so ESLint can validate that no data is passed to the rule.
// https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-schema.md
schema: [],
...rule.meta,
docs: {
...rule.meta.docs,
url: getDocumentationUrl(ruleId),
},
},
create: reportProblems(rule.create),
};
}
function loadRules() {
return Object.fromEntries(
fs.readdirSync(path.join(__dirname, '..'), {withFileTypes: true})
.filter(file => file.isFile())
.map(file => {
const ruleId = path.basename(file.name, '.js');
return [ruleId, loadRule(ruleId)];
}),
);
}
module.exports = {
loadRule,
loadRules,
checkVueTemplate,
};