@sap/eslint-plugin-cds 2.5.0 → 2.6.0
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/CHANGELOG.md +15 -0
- package/README.md +2 -1
- package/lib/api/index.js +9 -9
- package/lib/conf/all.js +20 -19
- package/lib/conf/index.js +10 -10
- package/lib/conf/recommended.js +17 -16
- package/lib/constants.js +15 -14
- package/lib/index.js +10 -11
- package/lib/parser.js +90 -82
- package/lib/rules/assoc2many-ambiguous-key.js +71 -70
- package/lib/rules/auth-no-empty-restrictions.js +16 -15
- package/lib/rules/auth-use-requires.js +19 -18
- package/lib/rules/auth-valid-restrict-grant.js +47 -46
- package/lib/rules/auth-valid-restrict-keys.js +19 -18
- package/lib/rules/auth-valid-restrict-to.js +61 -60
- package/lib/rules/auth-valid-restrict-where.js +44 -43
- package/lib/rules/extension-restrictions.js +69 -0
- package/lib/rules/index.js +23 -22
- package/lib/rules/latest-cds-version.js +21 -20
- package/lib/rules/min-node-version.js +22 -22
- package/lib/rules/no-db-keywords.js +17 -26
- package/lib/rules/no-dollar-prefixed-names.js +12 -11
- package/lib/rules/no-join-on-draft.js +27 -0
- package/lib/rules/require-2many-oncond.js +8 -8
- package/lib/rules/sql-cast-suggestion.js +13 -12
- package/lib/rules/start-elements-lowercase.js +42 -41
- package/lib/rules/start-entities-uppercase.js +26 -25
- package/lib/rules/valid-csv-header.js +58 -57
- package/lib/types.d.ts +1 -0
- package/lib/utils/Cache.js +17 -17
- package/lib/utils/Colors.js +8 -8
- package/lib/utils/createRule.js +166 -153
- package/lib/utils/findFuzzy.js +33 -38
- package/lib/utils/genDocs.js +224 -242
- package/lib/utils/getConfigPath.js +27 -27
- package/lib/utils/getConfiguredFileTypes.js +4 -4
- package/lib/utils/getFileExtensions.js +3 -3
- package/lib/utils/getProjectRootPath.js +25 -0
- package/lib/utils/isConfiguredFileType.js +11 -11
- package/lib/utils/rules.js +59 -59
- package/lib/utils/runRuleTester.js +76 -71
- package/package.json +7 -1
- package/lib/rules/no-join-on-draft-enabled-entities.js +0 -25
- package/lib/utils/createRuleDocs.js +0 -361
- package/lib/utils/jsonc.js +0 -1
- package/lib/utils/jsoncParser.js +0 -1
package/lib/utils/createRule.js
CHANGED
|
@@ -10,102 +10,103 @@
|
|
|
10
10
|
* @returns {RuleModule}
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
const { SourceCode } = require(
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
13
|
+
const { SourceCode } = require('eslint')
|
|
14
|
+
const fs = require('fs')
|
|
15
|
+
const path = require('path')
|
|
16
|
+
const Cache = require('./Cache')
|
|
17
|
+
const constants = require('../constants')
|
|
18
|
+
const isConfiguredFileType = require('./isConfiguredFileType')
|
|
19
|
+
const getProjectRootPath = require('./getProjectRootPath')
|
|
20
|
+
const cds = require('@sap/cds')
|
|
21
|
+
const { exit } = require('process')
|
|
22
|
+
const LOG = cds.debug('lint:plugin')
|
|
23
|
+
let filePrev = ''
|
|
21
24
|
|
|
22
|
-
const REGEX_COMMENT_START =
|
|
23
|
-
const REGEX_COMMENTS = `${REGEX_COMMENT_START}(enable|disable)(-next)?(-line)?(.+)
|
|
25
|
+
const REGEX_COMMENT_START = '(/\\*|(.+)?//)(\\s?)+eslint-'
|
|
26
|
+
const REGEX_COMMENTS = `${REGEX_COMMENT_START}(enable|disable)(-next)?(-line)?(.+)?`
|
|
24
27
|
|
|
25
28
|
module.exports = (spec) => {
|
|
26
|
-
let { meta, create } = spec
|
|
27
|
-
meta = setMetaDefaults(meta)
|
|
29
|
+
let { meta, create } = spec
|
|
30
|
+
meta = setMetaDefaults(meta)
|
|
28
31
|
|
|
29
32
|
return {
|
|
30
33
|
meta,
|
|
31
34
|
create: (context) => ({
|
|
32
35
|
Program: (node) => {
|
|
33
36
|
try {
|
|
34
|
-
const file = context.getFilename()
|
|
37
|
+
const file = context.getFilename()
|
|
35
38
|
if (file !== filePrev) {
|
|
36
|
-
LOG && LOG(`File: ${context.getFilename()}`)
|
|
39
|
+
LOG && LOG(`File: ${context.getFilename()}`)
|
|
37
40
|
}
|
|
38
|
-
const cdscontext = extendContext(node, context, meta)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
const cdscontext = extendContext(node, context, meta)
|
|
42
|
+
Cache.set('context', cdscontext)
|
|
43
|
+
const { isTest, isValidFile, doEnvironmentChecks, doRootModelChecks } = checkEntryCriteria(meta, cdscontext)
|
|
41
44
|
switch (meta.model) {
|
|
42
|
-
case
|
|
45
|
+
case 'none':
|
|
43
46
|
if (doEnvironmentChecks) {
|
|
44
47
|
if (isTest || !Cache.has(`rule:${cdscontext.id}`)) {
|
|
45
|
-
LOG && LOG(` Model: "${meta.model}" Rule: ${context.id}`)
|
|
46
|
-
Cache.set(`rule:${cdscontext.id}`,
|
|
47
|
-
createReport(node, cdscontext, meta, create)
|
|
48
|
+
LOG && LOG(` Model: "${meta.model}" Rule: ${context.id}`)
|
|
49
|
+
Cache.set(`rule:${cdscontext.id}:${Cache.get('rootpath')}`, 'done')
|
|
50
|
+
createReport(node, cdscontext, meta, create)
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
|
-
break
|
|
53
|
+
break
|
|
51
54
|
|
|
52
|
-
case
|
|
55
|
+
case 'inferred':
|
|
53
56
|
if (isValidFile && doRootModelChecks) {
|
|
54
|
-
if (isTest || !Cache.has(`rule:${
|
|
55
|
-
LOG && LOG(` Model: "${meta.model}" Rule: ${context.id}`)
|
|
56
|
-
Cache.set(`rule:${cdscontext.id}`,
|
|
57
|
-
createReport(node, cdscontext, meta, create)
|
|
57
|
+
if (isTest || !Cache.has(`rule:${cdscontext.id}:${Cache.get('rootpath')}`)) {
|
|
58
|
+
LOG && LOG(` Model: "${meta.model}" Rule: ${context.id}`)
|
|
59
|
+
Cache.set(`rule:${cdscontext.id}:${Cache.get('rootpath')}`, 'done')
|
|
60
|
+
createReport(node, cdscontext, meta, create)
|
|
58
61
|
} else {
|
|
59
62
|
if (Cache.has(`report:${context.getFilename()}:${context.id}`)) {
|
|
60
|
-
const reports = Cache.get(`report:${context.getFilename()}:${context.id}`)
|
|
63
|
+
const reports = Cache.get(`report:${context.getFilename()}:${context.id}`)
|
|
61
64
|
for (const r of Array.from(reports)) {
|
|
62
|
-
context.report(r)
|
|
65
|
+
context.report(JSON.parse(r))
|
|
63
66
|
}
|
|
64
|
-
Cache.remove(`report:${context.getFilename()}:${context.id}`)
|
|
67
|
+
Cache.remove(`report:${context.getFilename()}:${context.id}`)
|
|
68
|
+
Cache.set(`rule:${cdscontext.id}:${Cache.get('rootpath')}`, 'done')
|
|
65
69
|
}
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
|
-
break
|
|
72
|
+
break
|
|
69
73
|
|
|
70
74
|
default:
|
|
71
75
|
if (isValidFile) {
|
|
72
|
-
LOG && LOG(` Model: "${meta.model}" Rule: ${context.id}`)
|
|
73
|
-
createReport(node, cdscontext, meta, create)
|
|
76
|
+
LOG && LOG(` Model: "${meta.model}" Rule: ${context.id}`)
|
|
77
|
+
createReport(node, cdscontext, meta, create)
|
|
74
78
|
}
|
|
75
|
-
break
|
|
79
|
+
break
|
|
76
80
|
}
|
|
77
|
-
filePrev = file
|
|
81
|
+
filePrev = file
|
|
78
82
|
} catch (err) {
|
|
79
|
-
|
|
83
|
+
console.error(err)
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
86
|
})
|
|
83
|
-
}
|
|
84
|
-
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
85
89
|
|
|
86
|
-
function isRunningWithCDSLint() {
|
|
87
|
-
return process.argv[0].endsWith(
|
|
90
|
+
function isRunningWithCDSLint () {
|
|
91
|
+
return process.argv[0].endsWith('node') && process.argv[1].endsWith('cds') && process.argv[2] === 'lint'
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
function checkEntryCriteria(meta, cdscontext) {
|
|
91
|
-
const isTest = Cache.has(
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
const isValidFile = isConfiguredFileType(cdscontext.getFilename(), "FILES");
|
|
96
|
-
const isRunningWithCdsLint = isRunningWithCDSLint();
|
|
97
|
-
const doRootModelChecks = isTest || (isProjectRoot && (isRunningWithCdsLint || cdscontext.options.includes("show")));
|
|
94
|
+
function checkEntryCriteria (meta, cdscontext) {
|
|
95
|
+
const isTest = Cache.has('test')
|
|
96
|
+
const hasProjectRoots = Cache.has(`roots:${Cache.get('rootpath')}`)
|
|
97
|
+
const isValidFile = isConfiguredFileType(cdscontext.getFilename(), 'FILES')
|
|
98
|
+
const doRootModelChecks = isTest || (hasProjectRoots && (isRunningWithCDSLint() || cdscontext.options.includes('show')))
|
|
98
99
|
// Also lint empty folders (i.e. lintText "" API)
|
|
99
100
|
const doEnvironmentChecks =
|
|
100
|
-
isTest || (
|
|
101
|
-
return { isTest, isValidFile, doRootModelChecks, doEnvironmentChecks }
|
|
101
|
+
isTest || (hasProjectRoots && isRunningWithCDSLint() && cdscontext.getSourceCode().lines[0] === '')
|
|
102
|
+
return { isTest, isValidFile, doRootModelChecks, doEnvironmentChecks }
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
function setMetaDefaults(meta) {
|
|
105
|
-
if (!meta.severity) meta.severity = constants.DEFAULT_RULE_SEVERITY
|
|
106
|
-
if (meta.docs && !meta.docs.category) meta.docs.category = constants.DEFAULT_RULE_CATEGORY
|
|
107
|
-
if (!meta.model) meta.model =
|
|
108
|
-
return meta
|
|
105
|
+
function setMetaDefaults (meta) {
|
|
106
|
+
if (!meta.severity) meta.severity = constants.DEFAULT_RULE_SEVERITY
|
|
107
|
+
if (meta.docs && !meta.docs.category) meta.docs.category = constants.DEFAULT_RULE_CATEGORY
|
|
108
|
+
if (!meta.model) meta.model = 'parsed'
|
|
109
|
+
return meta
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
/**
|
|
@@ -119,9 +120,8 @@ function setMetaDefaults(meta) {
|
|
|
119
120
|
* @param {*} create
|
|
120
121
|
* @returns
|
|
121
122
|
*/
|
|
122
|
-
function createReport(node, cdscontext, meta, create) {
|
|
123
|
-
const handlers = create(cdscontext)
|
|
124
|
-
|
|
123
|
+
function createReport (node, cdscontext, meta, create) {
|
|
124
|
+
const handlers = create(cdscontext)
|
|
125
125
|
/**
|
|
126
126
|
* TODO: Can these be rewritten to have a visitor? Note, that so far,
|
|
127
127
|
* rules without a visitor cannot use eslint disable comments
|
|
@@ -130,129 +130,142 @@ function createReport(node, cdscontext, meta, create) {
|
|
|
130
130
|
* - Environment rules
|
|
131
131
|
*/
|
|
132
132
|
switch (typeof handlers) {
|
|
133
|
-
case
|
|
134
|
-
handlers()
|
|
135
|
-
break
|
|
133
|
+
case 'function':
|
|
134
|
+
handlers()
|
|
135
|
+
break
|
|
136
|
+
|
|
137
|
+
case 'object': {
|
|
138
|
+
if (meta.model !== 'none') {
|
|
139
|
+
const model = cdscontext.getModel()
|
|
136
140
|
|
|
137
|
-
case "object": {
|
|
138
|
-
if (meta.model !== "none") {
|
|
139
|
-
const model = cdscontext.getModel();
|
|
140
141
|
if (model) {
|
|
141
142
|
model.forall((d) => {
|
|
142
143
|
Object.entries(handlers)
|
|
143
144
|
.filter(([type, lazy]) => d.is(type))
|
|
144
145
|
.forEach(([lazy, handler]) => {
|
|
145
146
|
try {
|
|
146
|
-
handler(d)
|
|
147
|
+
handler(d)
|
|
147
148
|
} catch (err) {
|
|
148
|
-
console.log(`Error in rule "${cdscontext.id}" at ${d.name}`, err)
|
|
149
|
+
console.log(`Error in rule "${cdscontext.id}" at ${d.name}`, err)
|
|
149
150
|
}
|
|
150
|
-
})
|
|
151
|
-
})
|
|
151
|
+
})
|
|
152
|
+
})
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
|
-
break
|
|
155
|
+
break
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
function extendContext(node, context, meta) {
|
|
160
|
-
if (!Cache.has(
|
|
161
|
-
|
|
160
|
+
function extendContext (node, context, meta) {
|
|
161
|
+
if (!Cache.has('test')) {
|
|
162
|
+
const filePath = context.getFilename()
|
|
163
|
+
const rootPath = filePath && fs.existsSync(filePath) ? getProjectRootPath(filePath) : ''
|
|
164
|
+
if (rootPath) {
|
|
165
|
+
Cache.set('rootpath', rootPath)
|
|
166
|
+
}
|
|
162
167
|
}
|
|
163
168
|
|
|
164
169
|
const reportWrapper = (r) => {
|
|
165
|
-
const line = r.loc ? r.loc.start.line : r.node.loc.start.line
|
|
170
|
+
const line = r.loc ? r.loc.start.line : r.node.loc.start.line
|
|
166
171
|
if (!isRuleDisabled(line, context)) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
if (meta.model === 'inferred') {
|
|
173
|
+
if (!r.file) {
|
|
174
|
+
console.error(`Rule ${context.id} must return a "file" property in the rule report!`)
|
|
175
|
+
exit(1)
|
|
176
|
+
}
|
|
177
|
+
const file = Cache.get('rootpath') ? resolveFilePath(r.file) : r.file
|
|
170
178
|
if (cdscontext.getFilename() === file) {
|
|
171
|
-
delete r.file
|
|
172
|
-
context.report(r)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
r.message = meta.messages[r.messageId];
|
|
177
|
-
delete r.message;
|
|
178
|
-
}
|
|
179
|
-
if (r) {
|
|
180
|
-
let reports = new Set();
|
|
181
|
-
if (Cache.has(`report:${file}:${context.id}`)) {
|
|
182
|
-
reports = Cache.get(`report:${file}:${context.id}`);
|
|
183
|
-
}
|
|
184
|
-
reports.add(r);
|
|
185
|
-
Cache.set(`report:${file}:${context.id}`, reports);
|
|
186
|
-
}
|
|
179
|
+
delete r.file
|
|
180
|
+
context.report(r)
|
|
181
|
+
}
|
|
182
|
+
if (r.file) {
|
|
183
|
+
cacheReport(r, file, context, meta)
|
|
187
184
|
}
|
|
188
|
-
|
|
189
185
|
} else {
|
|
190
|
-
context.report(r)
|
|
186
|
+
context.report(r)
|
|
191
187
|
}
|
|
192
188
|
}
|
|
193
|
-
}
|
|
189
|
+
}
|
|
194
190
|
|
|
195
|
-
const descriptors = Object.getOwnPropertyDescriptors(context)
|
|
191
|
+
const descriptors = Object.getOwnPropertyDescriptors(context)
|
|
196
192
|
descriptors.report = {
|
|
197
193
|
value: reportWrapper,
|
|
198
194
|
writable: false,
|
|
199
195
|
enumerable: true,
|
|
200
196
|
configurable: false
|
|
201
|
-
}
|
|
197
|
+
}
|
|
202
198
|
|
|
203
|
-
const cdscontext = Object.create(Object.getPrototypeOf(context), descriptors)
|
|
199
|
+
const cdscontext = Object.create(Object.getPrototypeOf(context), descriptors)
|
|
204
200
|
cdscontext.getModel =
|
|
205
|
-
meta.model ===
|
|
201
|
+
meta.model === 'inferred' ? context.parserServices.getInferredCsn : context.parserServices.getParsedCsn
|
|
206
202
|
cdscontext.getEnvironment = () => {
|
|
207
|
-
const options = context.options
|
|
208
|
-
return options && options[0] && options[0].environment ? options[0].environment : undefined
|
|
209
|
-
}
|
|
210
|
-
cdscontext.getLocation = context.parserServices.getLocation
|
|
211
|
-
cdscontext.getNode = Object.keys(context.parserServices).length > 0 ? context.parserServices.getNode : () => node
|
|
212
|
-
return cdscontext
|
|
203
|
+
const options = context.options
|
|
204
|
+
return options && options[0] && options[0].environment ? options[0].environment : undefined
|
|
205
|
+
}
|
|
206
|
+
cdscontext.getLocation = context.parserServices.getLocation
|
|
207
|
+
cdscontext.getNode = Object.keys(context.parserServices).length > 0 ? context.parserServices.getNode : () => node
|
|
208
|
+
return cdscontext
|
|
213
209
|
}
|
|
214
210
|
|
|
215
|
-
function isRuleDisabled(line, cdscontext) {
|
|
216
|
-
let isDisabled = false
|
|
211
|
+
function isRuleDisabled (line, cdscontext) {
|
|
212
|
+
let isDisabled = false
|
|
217
213
|
if (cdscontext) {
|
|
218
|
-
const sourcecode = cdscontext.getSourceCode()
|
|
219
|
-
const rulesDisabled = getDisabled(sourcecode.getText(), sourcecode, line)
|
|
220
|
-
const id = cdscontext.id
|
|
221
|
-
isDisabled = line && id in rulesDisabled && rulesDisabled[id] ===
|
|
214
|
+
const sourcecode = cdscontext.getSourceCode()
|
|
215
|
+
const rulesDisabled = getDisabled(sourcecode.getText(), sourcecode, line)
|
|
216
|
+
const id = cdscontext.id
|
|
217
|
+
isDisabled = line && id in rulesDisabled && rulesDisabled[id] === 'off'
|
|
222
218
|
}
|
|
223
|
-
return isDisabled
|
|
219
|
+
return isDisabled
|
|
224
220
|
}
|
|
225
221
|
|
|
226
|
-
function
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
222
|
+
function cacheReport (r, file, context, meta) {
|
|
223
|
+
delete r.file
|
|
224
|
+
r.node.range = []
|
|
225
|
+
if (r.messageId) {
|
|
226
|
+
r.message = meta.messages[r.messageId]
|
|
227
|
+
delete r.message
|
|
228
|
+
}
|
|
229
|
+
if (r) {
|
|
230
|
+
let reports = new Set()
|
|
231
|
+
if (Cache.has(`report:${file}:${context.id}`)) {
|
|
232
|
+
reports = Cache.get(`report:${file}:${context.id}`)
|
|
233
|
+
}
|
|
234
|
+
reports.add(JSON.stringify(r))
|
|
235
|
+
Cache.set(`report:${file}:${context.id}`, reports)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function getDisabled (code, sourcecode, line) {
|
|
240
|
+
const listDisabled = []
|
|
241
|
+
const rules = Cache.get('rules')
|
|
242
|
+
const rulesDisabled = Object.keys(rules).reduce((o, key) => ({ ...o, [key]: 'on' }), {})
|
|
243
|
+
let matches = []
|
|
231
244
|
if (code) {
|
|
232
|
-
matches = [...code.matchAll(REGEX_COMMENTS)]
|
|
245
|
+
matches = [...code.matchAll(REGEX_COMMENTS)]
|
|
233
246
|
if (matches.length > 0) {
|
|
234
247
|
matches.forEach((match) => {
|
|
235
248
|
if (match) {
|
|
236
|
-
const index = match.index
|
|
237
|
-
match = match[0]
|
|
238
|
-
if (match.includes(
|
|
239
|
-
match = match.split(
|
|
240
|
-
} else if (match.includes(
|
|
241
|
-
match = match.split(
|
|
249
|
+
const index = match.index
|
|
250
|
+
match = match[0]
|
|
251
|
+
if (match.includes('*/')) {
|
|
252
|
+
match = match.split('*/')[0].replace('/*', '')
|
|
253
|
+
} else if (match.includes('//')) {
|
|
254
|
+
match = match.split('//')[1]
|
|
242
255
|
}
|
|
243
256
|
if (match) {
|
|
244
|
-
match = match.trim()
|
|
257
|
+
match = match.trim()
|
|
245
258
|
}
|
|
246
|
-
[
|
|
247
|
-
const loc = sourcecode.getLocFromIndex(index)
|
|
248
|
-
const disableType = match.split(
|
|
249
|
-
let disableRules = match.split(`${disableType} `)[1]
|
|
259
|
+
['disable', 'enable'].forEach((keyword) => {
|
|
260
|
+
const loc = sourcecode.getLocFromIndex(index)
|
|
261
|
+
const disableType = match.split(' ')[0]
|
|
262
|
+
let disableRules = match.split(`${disableType} `)[1]
|
|
250
263
|
disableRules = disableRules
|
|
251
|
-
? disableRules.split(
|
|
252
|
-
: Object.keys(rules).map((rule) => `@sap/cds/${rule}`)
|
|
253
|
-
let comment = {}
|
|
264
|
+
? disableRules.split(',').map((rule) => rule.trim())
|
|
265
|
+
: Object.keys(rules).map((rule) => `@sap/cds/${rule}`)
|
|
266
|
+
let comment = {}
|
|
254
267
|
if ([`eslint-${keyword}`, `eslint-${keyword}-line`, `eslint-${keyword}-next-line`].includes(disableType)) {
|
|
255
|
-
comment = disableType.includes(
|
|
268
|
+
comment = disableType.includes('-next-line')
|
|
256
269
|
? {
|
|
257
270
|
lineComment: loc.line,
|
|
258
271
|
lineDisabled: loc.line + 1,
|
|
@@ -264,41 +277,41 @@ function getDisabled(code, sourcecode, line) {
|
|
|
264
277
|
lineDisabled: loc.line,
|
|
265
278
|
rules: disableRules,
|
|
266
279
|
type: keyword
|
|
267
|
-
}
|
|
268
|
-
if (!disableType.includes(
|
|
269
|
-
comment.lineDisabled =
|
|
280
|
+
}
|
|
281
|
+
if (!disableType.includes('-line')) {
|
|
282
|
+
comment.lineDisabled = 'EOF'
|
|
270
283
|
}
|
|
271
284
|
}
|
|
272
|
-
listDisabled.push(comment)
|
|
273
|
-
})
|
|
285
|
+
listDisabled.push(comment)
|
|
286
|
+
})
|
|
274
287
|
}
|
|
275
|
-
})
|
|
288
|
+
})
|
|
276
289
|
for (const el of listDisabled.filter(
|
|
277
|
-
(d) => d.lineComment > line && (d.lineDisabled ===
|
|
290
|
+
(d) => d.lineComment > line && (d.lineDisabled === 'EOF' || d.lineDisabled === line)
|
|
278
291
|
)) {
|
|
279
|
-
if (el.lineDisabled ===
|
|
280
|
-
el.lineDisabled = getLastLine(code)
|
|
292
|
+
if (el.lineDisabled === 'EOF') {
|
|
293
|
+
el.lineDisabled = getLastLine(code)
|
|
281
294
|
}
|
|
282
295
|
if (el.rules) {
|
|
283
296
|
el.rules.forEach((rule) => {
|
|
284
|
-
if (el.type ===
|
|
285
|
-
rulesDisabled[rule] =
|
|
286
|
-
} else if (el.type ===
|
|
287
|
-
rulesDisabled[rule] =
|
|
297
|
+
if (el.type === 'disable') {
|
|
298
|
+
rulesDisabled[rule] = 'off'
|
|
299
|
+
} else if (el.type === 'enable') {
|
|
300
|
+
rulesDisabled[rule] = 'on'
|
|
288
301
|
}
|
|
289
|
-
})
|
|
302
|
+
})
|
|
290
303
|
}
|
|
291
304
|
}
|
|
292
305
|
}
|
|
293
306
|
}
|
|
294
|
-
return rulesDisabled
|
|
307
|
+
return rulesDisabled
|
|
295
308
|
}
|
|
296
309
|
|
|
297
|
-
function getLastLine(code) {
|
|
298
|
-
const lines = typeof code ===
|
|
299
|
-
return lines.length - 1
|
|
310
|
+
function getLastLine (code) {
|
|
311
|
+
const lines = typeof code === 'string' ? SourceCode.splitLines(code) : code
|
|
312
|
+
return lines.length - 1
|
|
300
313
|
}
|
|
301
314
|
|
|
302
|
-
function resolveFilePath(file) {
|
|
303
|
-
return path.isAbsolute(file) ? file : path.join(Cache.get(
|
|
315
|
+
function resolveFilePath (file) {
|
|
316
|
+
return path.isAbsolute(file) ? file : path.join(Cache.get('rootpath'), file)
|
|
304
317
|
}
|
package/lib/utils/findFuzzy.js
CHANGED
|
@@ -7,86 +7,81 @@
|
|
|
7
7
|
* @returns array with best matches, is never null but might be empty in case no search was possible
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
const cache = {}
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
module.exports = (input, list, log, keepCase=false) => {
|
|
15
|
-
let minDistWords = [];
|
|
12
|
+
module.exports = (input, list, log, keepCase = false) => {
|
|
13
|
+
let minDistWords = []
|
|
16
14
|
|
|
17
15
|
if (input.length > 50 || list.length > 50) {
|
|
18
|
-
return minDistWords
|
|
16
|
+
return minDistWords
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
let minDist = Number.MAX_SAFE_INTEGER
|
|
19
|
+
let minDist = Number.MAX_SAFE_INTEGER
|
|
22
20
|
|
|
23
|
-
log && log('\nword\t\tlevDist\t\ttime(ms)')
|
|
21
|
+
log && log('\nword\t\tlevDist\t\ttime(ms)')
|
|
24
22
|
|
|
25
|
-
let runtime = 0
|
|
23
|
+
let runtime = 0
|
|
26
24
|
|
|
27
25
|
for (const word of list) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const start = log && Date.now();
|
|
31
|
-
let levDist;
|
|
26
|
+
const start = log && Date.now()
|
|
27
|
+
let levDist
|
|
32
28
|
if (word === word.toUpperCase() && !keepCase) {
|
|
33
|
-
levDist = levDistance(input.toUpperCase(), word)
|
|
29
|
+
levDist = levDistance(input.toUpperCase(), word)
|
|
34
30
|
} else {
|
|
35
|
-
levDist = levDistance(input, word)
|
|
31
|
+
levDist = levDistance(input, word)
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
if (log) {
|
|
39
|
-
const duration = Date.now() - start
|
|
40
|
-
runtime = runtime + duration
|
|
41
|
-
log(`${word}\t\t${levDist}\t\t${duration}`)
|
|
35
|
+
const duration = Date.now() - start
|
|
36
|
+
runtime = runtime + duration
|
|
37
|
+
log(`${word}\t\t${levDist}\t\t${duration}`)
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
if (levDist === minDist) {
|
|
45
|
-
minDistWords.push(word)
|
|
41
|
+
minDistWords.push(word)
|
|
46
42
|
}
|
|
47
43
|
|
|
48
44
|
if (levDist < minDist) {
|
|
49
|
-
minDist = levDist
|
|
50
|
-
minDistWords = [word]
|
|
45
|
+
minDist = levDist
|
|
46
|
+
minDistWords = [word]
|
|
51
47
|
}
|
|
52
48
|
}
|
|
53
49
|
|
|
54
|
-
log && log(`runtime: ${runtime}ms`)
|
|
50
|
+
log && log(`runtime: ${runtime}ms`)
|
|
55
51
|
|
|
56
|
-
return minDistWords.sort()
|
|
52
|
+
return minDistWords.sort()
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
const levDistance = (a, b) => {
|
|
60
|
-
|
|
61
56
|
if (cache[a] && cache[a][b]) {
|
|
62
|
-
return cache[a][b]
|
|
57
|
+
return cache[a][b]
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
if (a.length === 0) {
|
|
66
|
-
return addToCache(a, b, b.length)
|
|
61
|
+
return addToCache(a, b, b.length)
|
|
67
62
|
}
|
|
68
63
|
|
|
69
64
|
if (b.length === 0) {
|
|
70
|
-
return addToCache(a, b, a.length)
|
|
65
|
+
return addToCache(a, b, a.length)
|
|
71
66
|
}
|
|
72
67
|
|
|
73
|
-
const
|
|
74
|
-
const
|
|
68
|
+
const tailA = a.substring(1)
|
|
69
|
+
const tailB = b.substring(1)
|
|
75
70
|
|
|
76
71
|
if (a[0] === b[0]) {
|
|
77
|
-
return levDistance(
|
|
72
|
+
return levDistance(tailA, tailB)
|
|
78
73
|
}
|
|
79
74
|
|
|
80
|
-
const lev1 = levDistance(
|
|
81
|
-
const lev2 = levDistance(a,
|
|
82
|
-
const lev3 = levDistance(
|
|
75
|
+
const lev1 = levDistance(tailA, b)
|
|
76
|
+
const lev2 = levDistance(a, tailB)
|
|
77
|
+
const lev3 = levDistance(tailA, tailB)
|
|
83
78
|
|
|
84
|
-
const levDist = Math.min(lev1, lev2, lev3) + 1
|
|
85
|
-
return addToCache(a, b, levDist)
|
|
79
|
+
const levDist = Math.min(lev1, lev2, lev3) + 1
|
|
80
|
+
return addToCache(a, b, levDist)
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
const addToCache = (a, b, value) => {
|
|
89
|
-
cache[a] = cache[a] || {}
|
|
90
|
-
cache[a][b] = value
|
|
91
|
-
return value
|
|
84
|
+
cache[a] = cache[a] || {}
|
|
85
|
+
cache[a][b] = value
|
|
86
|
+
return value
|
|
92
87
|
}
|