@sap/eslint-plugin-cds 4.1.0 → 4.1.1
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 +5 -1
- package/lib/conf/index.js +17 -0
- package/lib/conf/java/all.js +5 -0
- package/lib/conf/java/experimental.js +5 -0
- package/lib/conf/java/recommended.js +3 -0
- package/lib/conf/js/all.js +1 -1
- package/lib/conf/js/recommended.js +1 -1
- package/lib/constants.js +1 -0
- package/lib/index.js +7 -5
- package/lib/languages/java/java-language.js +69 -0
- package/lib/languages/java/java-source-code.js +179 -0
- package/lib/rules/index.js +21 -3
- package/lib/rules/java/cql-class-targets.js +59 -0
- package/lib/utils/runRuleTester.js +1 -1
- package/package.json +5 -2
- /package/lib/rules/js/{use-cql-select-template-strings.js → cql-template-strings.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,8 +6,12 @@ This project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
8
8
|
|
|
9
|
-
## [4.1.
|
|
9
|
+
## [4.1.1] - 2025-12-04
|
|
10
|
+
### Added
|
|
11
|
+
- Top level type definitions for package export
|
|
10
12
|
|
|
13
|
+
|
|
14
|
+
## [4.1.0] - 2025-08-18
|
|
11
15
|
### Added
|
|
12
16
|
- Add new rule `case-sensitive-well-known-events` to detect when a well known event is not cased correctly.
|
|
13
17
|
|
package/lib/conf/index.js
CHANGED
|
@@ -4,6 +4,18 @@ const path = require('node:path')
|
|
|
4
4
|
const { FILES, GLOBALS } = require('../constants')
|
|
5
5
|
const { parserPath } = require('../api')
|
|
6
6
|
|
|
7
|
+
function _createJavaConfig (plugin, configName) {
|
|
8
|
+
return {
|
|
9
|
+
name: '@sap/cds/java',
|
|
10
|
+
plugins: {
|
|
11
|
+
'@sap/cds': plugin,
|
|
12
|
+
},
|
|
13
|
+
files: ['**/*.java'],
|
|
14
|
+
language: '@sap/cds/java',
|
|
15
|
+
rules: require(path.join(__dirname, 'java', configName)),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
7
19
|
function _createJsConfig (plugin, configName) {
|
|
8
20
|
return {
|
|
9
21
|
name: '@sap/cds/js',
|
|
@@ -43,6 +55,11 @@ module.exports = function (plugin) {
|
|
|
43
55
|
js: {
|
|
44
56
|
all: _createJsConfig(plugin, 'all'),
|
|
45
57
|
recommended: _createJsConfig(plugin, 'recommended')
|
|
58
|
+
},
|
|
59
|
+
java: {
|
|
60
|
+
all: _createJavaConfig(plugin, 'all'),
|
|
61
|
+
recommended: _createJavaConfig(plugin, 'recommended'),
|
|
62
|
+
experimental: _createJavaConfig(plugin, 'experimental')
|
|
46
63
|
}
|
|
47
64
|
}
|
|
48
65
|
}
|
package/lib/conf/js/all.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
'@sap/cds/no-shared-handler-variable': 'error',
|
|
5
|
-
'@sap/cds/
|
|
5
|
+
'@sap/cds/cql-template-strings': 'error',
|
|
6
6
|
'@sap/cds/no-cross-service-import': 'warn',
|
|
7
7
|
'@sap/cds/no-deep-sap-cds-import': 'warn',
|
|
8
8
|
'@sap/cds/case-sensitive-well-known-events': 'warn',
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
'@sap/cds/no-shared-handler-variable': 'error',
|
|
5
|
-
'@sap/cds/
|
|
5
|
+
'@sap/cds/cql-template-strings': 'error',
|
|
6
6
|
'@sap/cds/no-cross-service-import': 'warn',
|
|
7
7
|
'@sap/cds/no-deep-sap-cds-import': 'warn',
|
|
8
8
|
'@sap/cds/case-sensitive-well-known-events': 'warn',
|
package/lib/constants.js
CHANGED
|
@@ -21,6 +21,7 @@ const RULE_CATEGORIES = {
|
|
|
21
21
|
javascript: 'JavaScript Validation',
|
|
22
22
|
environment: 'Environment Validation',
|
|
23
23
|
csv: 'CSV Validation',
|
|
24
|
+
java: 'Java Validation'
|
|
24
25
|
}
|
|
25
26
|
const DEFAULT_RULE_CATEGORY = 'Model Validation'
|
|
26
27
|
const DEFAULT_RULE_FLAVOR = RULE_FLAVORS[0]
|
package/lib/index.js
CHANGED
|
@@ -18,18 +18,20 @@
|
|
|
18
18
|
|
|
19
19
|
const api = require('./api')
|
|
20
20
|
const getConfigs = require('./conf')
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
...Object.entries(require('./rules')).map(([k, v]) => ({ [k]: v() }))
|
|
24
|
-
)
|
|
25
|
-
|
|
21
|
+
const { allRules, initialiseRules } = require('./rules')
|
|
22
|
+
const { javaLanguage } = require('./languages/java/java-language')
|
|
26
23
|
const packageJson = require('../package.json')
|
|
27
24
|
|
|
25
|
+
const rules = initialiseRules(allRules)
|
|
26
|
+
|
|
28
27
|
const plugin = {
|
|
29
28
|
meta: {
|
|
30
29
|
name: packageJson.name,
|
|
31
30
|
version: packageJson.version
|
|
32
31
|
},
|
|
32
|
+
languages: {
|
|
33
|
+
java: javaLanguage
|
|
34
|
+
},
|
|
33
35
|
configs: {},
|
|
34
36
|
rules,
|
|
35
37
|
...api
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const TreeSitterParser = require('tree-sitter')
|
|
4
|
+
const Java = require('tree-sitter-java')
|
|
5
|
+
const { JavaSourceCode } = require('./java-source-code')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {object} JavaLanguageOptions
|
|
9
|
+
* @typedef {{languageOptions: JavaLanguageOptions}} JavaLanguageContext
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const jp = new TreeSitterParser()
|
|
13
|
+
jp.setLanguage(Java)
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {import('@eslint/core').File} file
|
|
17
|
+
* @param {JavaLanguageContext} context
|
|
18
|
+
*/
|
|
19
|
+
function parseJavaCode (file /*, context*/) {
|
|
20
|
+
const code = file.body
|
|
21
|
+
const treeSitterAst = jp.parse(code)
|
|
22
|
+
|
|
23
|
+
if (!treeSitterAst) {
|
|
24
|
+
return { ast: null, ok: false }
|
|
25
|
+
}
|
|
26
|
+
if (!treeSitterAst.rootNode) {
|
|
27
|
+
return { ast: treeSitterAst, ok: false }
|
|
28
|
+
}
|
|
29
|
+
return { ast: treeSitterAst, ok: true }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {import('@eslint/core').File} file
|
|
34
|
+
* @param {ReturnType<typeof parseJavaCode>} parseResult
|
|
35
|
+
* @param {JavaLanguageContext} context
|
|
36
|
+
*/
|
|
37
|
+
function createJavaSourceCode(file, parseResult /*, context*/) {
|
|
38
|
+
if (!parseResult.ok || !parseResult.ast) {
|
|
39
|
+
throw new Error('createJavaSourceCode: parseResult is not ok or has no AST', {
|
|
40
|
+
ok: parseResult.ok,
|
|
41
|
+
hasAst: !!parseResult.ast
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
return new JavaSourceCode({ text: file.body, ast: parseResult.ast })
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {JavaLanguageOptions} languageOptions
|
|
49
|
+
*/
|
|
50
|
+
function validateJavaLanguageOptions(/*languageOptions*/) {
|
|
51
|
+
// No specific options to validate for Java currently
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @link https://eslint.org/docs/latest/extend/languages#the-language-object
|
|
56
|
+
*/
|
|
57
|
+
const javaLanguage = /** @type {const}*/({
|
|
58
|
+
fileType: 'text',
|
|
59
|
+
lineStart: 0,
|
|
60
|
+
columnStart: 0,
|
|
61
|
+
nodeTypeKey: 'type',
|
|
62
|
+
validateLanguageOptions: validateJavaLanguageOptions,
|
|
63
|
+
parse: parseJavaCode,
|
|
64
|
+
createSourceCode: createJavaSourceCode
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
javaLanguage,
|
|
69
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// not 100% accurate, as it matches _any_ comment containing 'eslint-disable' etc.
|
|
4
|
+
// but in Java sources, users will hopefully only mention eslint-* when they
|
|
5
|
+
// actually mean to configure ESLint.
|
|
6
|
+
const INLINE_CONFIG = /eslint(?:-enable|-disable(?:(?:-next)?-line)?)?(?:\s|$)/u
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @link see https://github.com/eslint/json/blob/main/src/languages/json-source-code.js
|
|
10
|
+
*/
|
|
11
|
+
const {
|
|
12
|
+
VisitNodeStep,
|
|
13
|
+
TextSourceCodeBase,
|
|
14
|
+
Directive
|
|
15
|
+
} = require('@eslint/plugin-kit')
|
|
16
|
+
|
|
17
|
+
/** @typedef {'disable' | 'enable' | 'disable-next-line' | 'disable-line'} DirectiveType */
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {import('tree-sitter').SyntaxNode} comment
|
|
22
|
+
* @returns {{
|
|
23
|
+
* label: 'eslint-disable' | 'eslint-enable' | 'eslint-disable-next-line' | 'eslint-disable-line',
|
|
24
|
+
* value: string,
|
|
25
|
+
* justification: string | undefined
|
|
26
|
+
* }}
|
|
27
|
+
*/
|
|
28
|
+
function parseDirective(comment) {
|
|
29
|
+
// label, value, justification
|
|
30
|
+
// * but before the "--" that indicates the justification.
|
|
31
|
+
const [, label, value, justification] = comment.text.match(/^\W*(eslint[\w-]*) (\S+)(?: -- (.+))?/)
|
|
32
|
+
return { label, value, justification}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class JavaTraversalStep extends VisitNodeStep {
|
|
36
|
+
/** @param {{ target: unknown, phase: 1|2, args: Array<any> }} arg0 */
|
|
37
|
+
constructor({ target, phase, args }) {
|
|
38
|
+
super({ target, phase, args })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {import('tree-sitter').SyntaxNode} node
|
|
44
|
+
* @param {(node: import('tree-sitter').SyntaxNode) => void} enterAction
|
|
45
|
+
* @param {undefined | (node: import('tree-sitter').SyntaxNode) => void} exitAction
|
|
46
|
+
*/
|
|
47
|
+
function traverse(node, enterAction, exitAction) {
|
|
48
|
+
enterAction?.(node)
|
|
49
|
+
//steps.push(new JavaTraversalStep({ target: node, phase: 1, args: [] }))
|
|
50
|
+
for (const child of node.children) {
|
|
51
|
+
traverse(child, enterAction, exitAction)
|
|
52
|
+
}
|
|
53
|
+
exitAction?.(node)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
/** @param {import('tree-sitter').SyntaxNode} node */
|
|
58
|
+
const getAncestors = node => !node
|
|
59
|
+
? []
|
|
60
|
+
: [...getAncestors(node.parent), node]
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @link https://eslint.org/docs/latest/extend/languages#the-sourcecode-object
|
|
64
|
+
*/
|
|
65
|
+
class JavaSourceCode extends TextSourceCodeBase {
|
|
66
|
+
/** @type {undefined | import('tree-sitter').SyntaxNode[]} */
|
|
67
|
+
#comments
|
|
68
|
+
/** @type {undefined | import('tree-sitter').SyntaxNode[]} */
|
|
69
|
+
#inlineConfigComments
|
|
70
|
+
|
|
71
|
+
get comments() {
|
|
72
|
+
if (!this.#comments) {
|
|
73
|
+
this.#comments = []
|
|
74
|
+
traverse(this.ast.rootNode, node => {
|
|
75
|
+
if (['line_comment', 'block_comment'].includes(node.type)) {
|
|
76
|
+
this.#comments.push(node)
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
return this.#comments
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get inlineConfigNodes() {
|
|
84
|
+
if (!this.#inlineConfigComments) {
|
|
85
|
+
this.#inlineConfigComments = this
|
|
86
|
+
.comments
|
|
87
|
+
.filter(comment =>
|
|
88
|
+
INLINE_CONFIG.test(comment.text),
|
|
89
|
+
) ?? []
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return this.#inlineConfigComments
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get lines () { return this.text.split(/\r\n|\r|\n/) }
|
|
96
|
+
|
|
97
|
+
/** @param {import('tree-sitter').SyntaxNode} node */
|
|
98
|
+
getLoc(node) {
|
|
99
|
+
return {
|
|
100
|
+
start: { line: node.startPosition.row, column: node.startPosition.column },
|
|
101
|
+
end: { line: node.endPosition.row, column: node.endPosition.column }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** @param {import('tree-sitter').SyntaxNode} node */
|
|
106
|
+
getRange(node) {
|
|
107
|
+
return [node.startIndex, node.endIndex]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** @param {import('tree-sitter').SyntaxNode} node */
|
|
111
|
+
getParent(node) {
|
|
112
|
+
return node.parent ?? undefined // .parent is null if root, we need undefined
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** @param {import('tree-sitter').SyntaxNode} node */
|
|
116
|
+
getAncestors(node) {
|
|
117
|
+
// ESLint wants ancestors excluding the node itself
|
|
118
|
+
return getAncestors(node.parent)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @param {import('tree-sitter').SyntaxNode} node */
|
|
122
|
+
getText(node) {
|
|
123
|
+
return node.text
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getDisableDirectives() {
|
|
127
|
+
/** @type {FileProblem[]} */
|
|
128
|
+
const problems = []
|
|
129
|
+
/** @type {Directive[]} */
|
|
130
|
+
const directives = []
|
|
131
|
+
|
|
132
|
+
for (const comment of this.inlineConfigNodes) {
|
|
133
|
+
const { label, value, justification } = parseDirective(comment)
|
|
134
|
+
|
|
135
|
+
// `eslint-disable-line` directives are not allowed to span multiple lines as it would be confusing to which lines they apply
|
|
136
|
+
if (label === 'eslint-disable-line' && comment.loc.start.line !== comment.loc.end.line) {
|
|
137
|
+
problems.push({
|
|
138
|
+
ruleId: null,
|
|
139
|
+
message: `${label} comment should not span multiple lines.`,
|
|
140
|
+
loc: comment.loc,
|
|
141
|
+
})
|
|
142
|
+
} else if (['eslint-disable', 'eslint-enable', 'eslint-disable-next-line', 'eslint-disable-line'].includes(label)) {
|
|
143
|
+
directives.push(
|
|
144
|
+
new Directive({
|
|
145
|
+
type: /** @type {DirectiveType} */ (label.slice('eslint-'.length)),
|
|
146
|
+
node: comment,
|
|
147
|
+
value,
|
|
148
|
+
justification,
|
|
149
|
+
}),
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { problems, directives }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
traverse() {
|
|
157
|
+
const steps = []
|
|
158
|
+
if (!this.ast || !this.ast.rootNode) {
|
|
159
|
+
return steps
|
|
160
|
+
}
|
|
161
|
+
traverse(this.ast.rootNode, node => {
|
|
162
|
+
steps.push(new JavaTraversalStep({ target: node, phase: 1 }))
|
|
163
|
+
}, node => {
|
|
164
|
+
steps.push(new JavaTraversalStep({ target: node, phase: 2 }))
|
|
165
|
+
})
|
|
166
|
+
return steps
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** @param {{text: string, ast: import('tree-sitter').Tree}} param0 */
|
|
170
|
+
constructor({text, ast}) {
|
|
171
|
+
super({text, ast})
|
|
172
|
+
this.text = text
|
|
173
|
+
this.ast = ast
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
JavaSourceCode
|
|
179
|
+
}
|
package/lib/rules/index.js
CHANGED
|
@@ -17,10 +17,28 @@ const readRulesFromDir = (dir, post) => Object.fromEntries(fs.readdirSync(path.j
|
|
|
17
17
|
.filter(([,module]) => Object.hasOwn(module, 'create')) // create() is required to exist on top level by eslint -> good check to find actual rules
|
|
18
18
|
.map(([file, module]) => [file, () => post(module)]))
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Calls the initialisation function for each rule in the given rule set.
|
|
22
|
+
* @param {Record<string, () => unknown>} ruleSet
|
|
23
|
+
* @returns {Record<string, unknown>}
|
|
24
|
+
*/
|
|
25
|
+
const initialiseRules = ruleSet => Object.fromEntries(
|
|
26
|
+
Object.entries(ruleSet)
|
|
27
|
+
.map(([k, v]) => [[k], v()]))
|
|
28
|
+
|
|
20
29
|
const cdsRules = readRulesFromDir('.', createRule)
|
|
21
30
|
const jsRules = readRulesFromDir('js', module => module)
|
|
22
|
-
|
|
31
|
+
// backwards compat, remove in next minor
|
|
32
|
+
jsRules['use-cql-select-template-strings'] = jsRules['cql-template-strings']
|
|
33
|
+
const javaRules = readRulesFromDir('java', module => module)
|
|
34
|
+
const allRules = {...cdsRules, ...jsRules, ...javaRules}
|
|
23
35
|
|
|
24
|
-
globalCache.set('rules',
|
|
36
|
+
globalCache.set('rules', allRules)
|
|
25
37
|
|
|
26
|
-
module.exports =
|
|
38
|
+
module.exports = {
|
|
39
|
+
allRules,
|
|
40
|
+
jsRules,
|
|
41
|
+
javaRules,
|
|
42
|
+
cdsRules,
|
|
43
|
+
initialiseRules
|
|
44
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* In Select.from(x), x should be a class literal.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { RULE_CATEGORIES } = require('../../constants')
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
recommended: true,
|
|
14
|
+
category: RULE_CATEGORIES.java,
|
|
15
|
+
description: 'java.'
|
|
16
|
+
},
|
|
17
|
+
fixable: 'code',
|
|
18
|
+
schema: [],
|
|
19
|
+
messages: {
|
|
20
|
+
selectOnNonClass: `'{{target}}' is not a class. Prefer to pass class literals to Select.from!`,
|
|
21
|
+
},
|
|
22
|
+
hasSuggestions: true
|
|
23
|
+
},
|
|
24
|
+
create: context => {
|
|
25
|
+
const knownClasses = new Set()
|
|
26
|
+
|
|
27
|
+
/** @param {Node} node */
|
|
28
|
+
const refersToClass = node =>
|
|
29
|
+
node.type === 'class_literal'
|
|
30
|
+
// or part of explicit named imports
|
|
31
|
+
|| knownClasses.has(node.text)
|
|
32
|
+
// or first letter of last part of text is uppercase: a.b.C -> true
|
|
33
|
+
// https://unicode.org/reports/tr18/#General_Category_Property
|
|
34
|
+
|| /^\p{Lu}/u.test(node.text.split('.').at(-1))
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
'import_declaration > scoped_identifier': function(node) {
|
|
38
|
+
if (!node) return
|
|
39
|
+
if (node.nameNode) {
|
|
40
|
+
knownClasses.add(node.nameNode.text)
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
"method_invocation > identifier[text='from']": function(node) {
|
|
45
|
+
if (!node?.parent?.argumentsNode) return
|
|
46
|
+
const args = node.parent.argumentsNode.children
|
|
47
|
+
.filter(c => c.constructor.name !== 'SyntaxNode') // filter out commas, parens, etc.
|
|
48
|
+
?? []
|
|
49
|
+
if (!refersToClass(args[0])) {
|
|
50
|
+
context.report({
|
|
51
|
+
node: args[0],
|
|
52
|
+
messageId: 'selectOnNonClass',
|
|
53
|
+
data: { target: args[0].text }
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -9,7 +9,7 @@ const { RuleTester } = require('eslint')
|
|
|
9
9
|
const { globalCache } = require('./Cache')
|
|
10
10
|
const isConfiguredFileType = require('./isConfiguredFileType')
|
|
11
11
|
const { compileModelFromDict } = require('../parser')
|
|
12
|
-
const rules = require('../rules')
|
|
12
|
+
const { allRules: rules } = require('../rules')
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* A wrapper around the return value of `createRule()` that initializes the global
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/eslint-plugin-cds",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"description": "ESLint plugin including recommended SAP Cloud Application Programming model and environment rules",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"keywords": [
|
|
@@ -20,7 +20,10 @@
|
|
|
20
20
|
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"
|
|
23
|
+
"@eslint/plugin-kit": "^0.4.1",
|
|
24
|
+
"semver": "^7.7.1",
|
|
25
|
+
"tree-sitter": "^0.21.1",
|
|
26
|
+
"tree-sitter-java": "^0.23.5"
|
|
24
27
|
},
|
|
25
28
|
"peerDependencies": {
|
|
26
29
|
"@sap/cds": ">=9",
|
|
File without changes
|