generated from 5app/package-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #92 from 5app/next
chore: release latest
- Loading branch information
Showing
12 changed files
with
546 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
const createSQLTemplateElementHandler = require('../utils/createSQLTemplateElementHandler'); | ||
const getLocation = require('../utils/getLocation.js'); | ||
|
||
/** | ||
* Template Element Handler for Function Names allowed and disallowed | ||
* @param {object} node - Element Node | ||
* @param {object} context - Eslint Context object | ||
* @returns {object|undefined} Returns a format object or undefined | ||
*/ | ||
function templateElementHandler(node, context) { | ||
const text = node.value.raw; | ||
|
||
const {disallowed} = context.options.at(0); | ||
|
||
// Special words? | ||
const regexp = new RegExp( | ||
`\\b(?<funcName>${disallowed.join('|')})\\(`, | ||
'gi' | ||
); | ||
|
||
const test = text.matchAll(regexp); | ||
|
||
const incidents = []; | ||
|
||
for (const match of test) { | ||
const {funcName} = match.groups; | ||
|
||
const report = { | ||
messageId: 'isDisallowed', | ||
data: { | ||
funcName, | ||
}, | ||
...getLocation(node, match.index, funcName), | ||
}; | ||
|
||
incidents.push(report); | ||
} | ||
|
||
return incidents; | ||
} | ||
|
||
/** | ||
* Export `function-case`. | ||
* | ||
* @param {object} context - Eslint Context object | ||
* @returns {object} Object rule | ||
*/ | ||
module.exports = { | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: 'Enforce allowed and disallowed functions', | ||
category: 'Stylistic Issues', | ||
}, | ||
messages: { | ||
isDisallowed: 'Function is disallowed "{{funcName}}"', | ||
}, | ||
schema: { | ||
minItems: 1, | ||
maxItems: 1, | ||
items: [ | ||
{ | ||
type: 'object', | ||
properties: { | ||
disallowed: { | ||
type: 'array', | ||
items: {type: 'string'}, | ||
minItems: 1, | ||
}, | ||
}, | ||
additionalProperties: false, | ||
}, | ||
], | ||
}, | ||
}, | ||
create: createSQLTemplateElementHandler({templateElementHandler}), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
const createSQLTemplateElementHandler = require('../utils/createSQLTemplateElementHandler'); | ||
|
||
/** | ||
* Template Element Handler for Backticks | ||
* @param {object} node - Element Node | ||
* @returns {object|undefined} Returns a format object or undefined | ||
*/ | ||
function templateElementHandler(node) { | ||
const text = node.value.raw; | ||
|
||
const backtick = '\\`'; | ||
|
||
const test = text.matchAll(backtick); | ||
|
||
const incidents = []; | ||
|
||
for (const match of test) { | ||
// Get the text before the match, and split it into lines | ||
const prefixLines = text.slice(0, match.index).split('\n'); | ||
// Extract the last line, everything in the column preceeding the backtick | ||
const prefixLast = prefixLines.pop(); | ||
// Derive the column, if the prefix is empty i.e. no multi-line, include the start column of the node | ||
const column = | ||
(prefixLines.length === 0 ? node.loc.start?.column : -1) + | ||
prefixLast.length; | ||
// Count the lines: the text node, and then the lines within the text node before the backtick | ||
const line = node.loc.start?.line + prefixLines.length; | ||
|
||
const report = { | ||
messageId: 'isDisallowed', | ||
loc: { | ||
start: { | ||
line, | ||
column, | ||
}, | ||
end: { | ||
line, | ||
column: column + backtick.length, | ||
}, | ||
}, | ||
}; | ||
|
||
incidents.push(report); | ||
} | ||
|
||
return incidents; | ||
} | ||
|
||
/** | ||
* Export `no-backticks`. | ||
* | ||
* @param {object} context - Eslint Context object | ||
* @returns {object} Object rule | ||
*/ | ||
module.exports = { | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: | ||
'Enforce allowed and disallowed backticks in SQL template literals', | ||
category: 'Stylistic Issues', | ||
}, | ||
messages: { | ||
isDisallowed: | ||
'Backticks are disallowed as they are incompatible with SQL. Use double quotes instead, prefix identifier names or ammend names of fields stored in the database.', | ||
}, | ||
}, | ||
create: createSQLTemplateElementHandler({templateElementHandler}), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
const isSqlQuery = require('../utils/sqlParser.js'); | ||
const isTagged = require('../utils/isTagged.js'); | ||
const getLocation = require('../utils/getLocation.js'); | ||
|
||
/** | ||
* no-shorthand-offset | ||
* MySQL permits the non-standard `LIMIT offset, count` syntax, but it is not portable to other SQL databases. | ||
* So this rule will flag the potential use of `LIMIT offset, count` syntax. | ||
*/ | ||
module.exports = { | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: 'Disallow the use of `LIMIT offset, count` syntax', | ||
category: 'non-standard SQL', | ||
}, | ||
messages: { | ||
nonStandardSQL: | ||
'Non-standard SQL syntax `LIMIT offset, count` is not portable', | ||
}, | ||
}, | ||
|
||
/** | ||
* Create `no-shorthand-offset` rule | ||
* | ||
* @param {object} context - Eslint Context object | ||
* @returns {object} Object rule | ||
*/ | ||
create(context) { | ||
/** | ||
* Validate node. | ||
* @param {object} templateLiteralNode - Node | ||
* @returns {void} | ||
*/ | ||
function validate(templateLiteralNode) { | ||
const {parent} = templateLiteralNode; | ||
|
||
// Tagged with a 'SQL' like name? | ||
const tagged = isTagged(parent); | ||
|
||
// Join up the parts... | ||
const literal = templateLiteralNode.quasis | ||
.map(quasi => quasi.value.raw) | ||
.join('?'); | ||
|
||
// Is this something other than a SQL expression? | ||
if (!tagged && !isSqlQuery(literal)) { | ||
return; | ||
} | ||
|
||
const incidents = []; | ||
|
||
// Loop through the TemplateElements | ||
templateLiteralNode.quasis.forEach((node, index) => { | ||
// Is there a `LIMIT offset,` clause? | ||
const hardcodedShortHandOffset = node.value.raw.match( | ||
/\b(?<prefix>limit(\s+(--.*\n)*)+)(?<body>(\d+|\?)\s*,)/i | ||
); | ||
|
||
if (hardcodedShortHandOffset) { | ||
const matchStr = hardcodedShortHandOffset.groups.body; | ||
const matchIndex = | ||
hardcodedShortHandOffset.index + | ||
hardcodedShortHandOffset.groups.prefix.length; | ||
|
||
incidents.push({ | ||
messageId: 'nonStandardSQL', | ||
...getLocation(node, matchIndex, matchStr), | ||
}); | ||
return; | ||
} | ||
|
||
// Is there a `LIMIT` clause? | ||
const endsInLimitClause = node.value.raw.match( | ||
/limit(\s+(--.*\n)*)+$/i | ||
); | ||
|
||
if (endsInLimitClause && !node.tail) { | ||
// Get the next node in sequence, does that start with a `,`? | ||
const nextNode = templateLiteralNode.quasis[index + 1]; | ||
|
||
const nextStartsWithComma = | ||
nextNode.value.raw.match(/^(\s*),/i); | ||
|
||
// console.log({ | ||
// nextNode, | ||
// endsInLimitClause, | ||
// nextStartsWithComma, | ||
// }); | ||
|
||
if (nextStartsWithComma) { | ||
const strPattern = ','; | ||
|
||
// Report the error | ||
const matchIndex = | ||
nextNode.value.raw.indexOf(strPattern); | ||
|
||
incidents.push({ | ||
messageId: 'nonStandardSQL', | ||
...getLocation(nextNode, matchIndex, strPattern), | ||
}); | ||
} | ||
} | ||
}); | ||
|
||
// console.log(incidents); | ||
|
||
incidents.forEach(incident => context.report(incident)); | ||
} | ||
|
||
return { | ||
TemplateLiteral: validate, | ||
}; | ||
}, | ||
}; |
Oops, something went wrong.