@sap/eslint-plugin-cds
Version:
ESLint plugin including recommended SAP Cloud Application Programming model and environment rules
121 lines (110 loc) • 3.5 kB
JavaScript
const SEP = '[,;\t]'
const EOL = '\\r?\\n'
const findFuzzy = require('./findFuzzy')
module.exports = {
findFuzzy,
/**
* @param {object} definition CSN definition object.
* @param {string} [name] The definition's name. Inferred for "linked CSN".
*/
splitDefName(definition, name = definition.name) {
if (!name)
return null
// Entity names from CSN are of the form:
// <namespace>.<service>.<def>.<'texts'|'localized'>|<composition value>
let prefix = ''
let suffix = ''
const names = name.split('.')
let defName = names[names.length - 1]
if (defName) {
// Managed composition get compiler tag `_up`
let isManagedComposition = false
if (definition.elements) {
isManagedComposition = Object.keys(definition.elements).some(k => k === 'up_')
}
// Check for compiler tags
const compilerTagsToExclude = ['texts', 'localized']
const isCompilerTag = compilerTagsToExclude.includes(defName)
if (isManagedComposition || isCompilerTag) {
suffix = names[names.length - 1]
defName = names[names.length - 2]
}
prefix = name.split(`.${defName}`)[0]
}
return { prefix, name: defName, suffix }
},
_findInCode: function (miss, code) {
// middle
let match = new RegExp(SEP + miss + SEP).exec(code)
if (match) return match.index + 1
// end of line
match = new RegExp(SEP + miss + EOL).exec(code)
if (match) return match.index + 1
// start of doc
match = new RegExp('^' + miss + SEP).exec(code)
if (match) return match.index
// somewhere (fallback)
return code.indexOf(miss)
},
/**
* Returns true if the given string is non-empty. The string is trimmed, i.e. leading/trailing
* whitespace is removed prior to checking.
*
* @param {string} value
* @returns {boolean}
*/
isEmptyString(value) {
return value?.trim() === ''
},
isEmptyObject: function (value) {
function isEmpty (object) {
if (Object.keys(object).length) {
return false
}
return true
}
if (!value || typeof value !== 'object' || (typeof value === 'object' && !isEmpty(value)) ||
(typeof value === 'object' && value && value.length > 0)) {
return false
}
return true
},
isStringInArray (str, arr, caps = false) {
const notIncluded = !arr.includes(str)
if (!caps && notIncluded) {
return false
}
if (caps && notIncluded && !arr.includes(str.toLowerCase()) && !arr.includes(str.toUpperCase())) {
return false
}
return true
},
getReplacementsSuggestions: function (context, value, loc) {
let invalid
const lineToReplace = context.sourcecode.lines[loc.line]
const regExp = /\[([^)]+)\]/
const matches = regExp.exec(lineToReplace)
if (matches && matches[0]) {
invalid = matches[0]
}
const startIndex = lineToReplace.indexOf(invalid)
const candidates = `['${value}']`
const suggest = {
messageId: 'ReplaceItemWith',
data: { invalid, candidates },
fix: fixer => fixer.replaceTextRange([startIndex, startIndex + invalid.length] + 1, candidates)
}
return ({
messageId: 'InvalidItem',
data: { invalid, candidates },
loc: {
start: { line: loc.line + 1, column: startIndex },
end: { line: loc.line + 1, column: startIndex + invalid.length }
},
file: loc.file,
suggest,
severity: 'warn'
})
}
}