-
I am trying to make a fairly simple custom linting ruleset that checks an API document against a list of denied buzzwords. The ruleset is defined like so: {
"functions": ["noDeniedWordsAnywhere"],
"rules": {
"no-denied-words-anywhere": {
"description": "Won't be used this way for the real linter, but can be used to check an entire API for denied words.",
"message": "{{error}}",
"severity": "error",
"given": "$",
"then": {
"function": "noDeniedWordsAnywhere",
"functionOptions": {
"field": "word"
}
}
}
}
} This example has the root path passed in, but the plan is to extend this to only look in certain API sections. It calls the custom function shown below, which recursively searches every object along the path and checks every key and value against a dictionary of denied words, which is created in another node. /**
* The entire API is being passed in, parse through all of it to check for denied words
* @param {string} targetVal Path to recursively parse
*/
module.exports = function (targetVal, opts, paths) {
const { field } = opts;
const rootPath = paths.target !== void 0 ? paths.target : paths.given;
const results = [];
const deniedWordMap = require('../util/dictionary.js');
// Comes from another node, but deniedWordMap is a map object that maps denied words to their
// corresponding correct words. A simple mock map could be created to test this against a sample API
function recursiveLint(objToLint, path) {
if (typeof objToLint === 'object') {
// Lint every path contained in this object
for (const subObj in objToLint) {
if (typeof subObj === 'string' || typeof subObj === 'number') {
const pathCopy = [...path];
pathCopy.push(subObj);
// Compare keys to the denied list
if (deniedWordMap.has(subObj)) {
results.push({
message: `The ${ field } ${ subObj } is denied; consider using ${ deniedWordMap.get(subObj) }.`,
path: [...pathCopy],
});
}
recursiveLint(objToLint[subObj], pathCopy);
}
}
} else if (typeof objToLint === 'string') {
// Compare value to the denied list
if (deniedWordMap.has(objToLint)) {
results.push({
message: `The ${ field } ${ objToLint } is denied; consider using ${ deniedWordMap.get(objToLint) }.`,
path: [...path],
});
}
}
}
// Pass the root into this recursive function
recursiveLint(targetVal, [...rootPath]);
return results;
}; Because this function returns multiple error messages, the path to the error in question has to be specified as part of the error message structure. I can usually accomplish this by keeping track of the object names as I lint through each sub-object, but this method does not work whenever a line exists that uses the The fix I had in mind was to detect whenever a Is there any way to retrieve this string from inside the custom function? Or is there any better approach to linting an API and ensuring that paths are properly referenced, even if the linter has to go through a |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Not sure if this is the best solution, but I did find a workaround. In the custom function, one of the parameters can be module.exports = function (targetVal, opts, paths, otherValues) {
const { field } = opts;
const rootPath = paths.target !== void 0 ? paths.target : paths.given;
const { documentInventory } = otherValues;
const docString = documentInventory.document.input;
// Rest of the function
} With |
Beta Was this translation helpful? Give feedback.
Not sure if this is the best solution, but I did find a workaround. In the custom function, one of the parameters can be
otherValues
which contains additional information about the linting process. From that object, you can extract a document input which is basically the entire API document in string form. The beginning of such a function looks like this:With
docString
, I was then able to identify w…