mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 09:09:36 +02:00
[monorepo] turn throw statements in callback code into callback calls (#33524)
* [eslint-plugin] add rule for throw inside callback code * [monorepo] enable our custom eslint plugins globally * [monorepo] fix running make lint from root * [monorepo] turn throw statements in callback code into callback calls * [monorepo] add eslint-plugin libraries to all the Dockerfiles * [monorepo] install eslint-plugin library at the root level * [linked-url-proxy] add eslint-plugin library into Dockerfile * [latexqc] add our eslint-plugin to eslint config GitOrigin-RevId: b05e3ebbefb62370f2422e83880dd3913815270d
This commit is contained in:
@@ -8,5 +8,6 @@ module.exports = {
|
||||
'require-vi-doMock-valid-path': require('./require-vi-doMock-valid-path'),
|
||||
'require-loading-label': require('./require-loading-label'),
|
||||
'require-cio-snake-case-properties': require('./require-cio-snake-case-properties'),
|
||||
'no-throw-in-callback': require('./no-throw-in-callback'),
|
||||
},
|
||||
}
|
||||
|
||||
52
libraries/eslint-plugin/no-throw-in-callback.js
Normal file
52
libraries/eslint-plugin/no-throw-in-callback.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const CALLBACK_PARAM_NAMES = new Set(['cb', 'callback', 'done', 'next'])
|
||||
|
||||
function isCallbackParam(param) {
|
||||
return (
|
||||
param && param.type === 'Identifier' && CALLBACK_PARAM_NAMES.has(param.name)
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: 'error',
|
||||
docs: {
|
||||
description: 'Disallow throw statements inside callback-based functions',
|
||||
},
|
||||
messages: {
|
||||
noThrowInCallback:
|
||||
'Pass the error to the callback instead of throwing in callback-based code.',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
// Stack tracks whether each enclosing function is a callback-style function.
|
||||
// A callback-style function is non-async and has a last param named cb/callback/done/next.
|
||||
const stack = []
|
||||
|
||||
function enterFunction(node) {
|
||||
const params = node.params
|
||||
const isCallback =
|
||||
!node.async &&
|
||||
params.length > 0 &&
|
||||
isCallbackParam(params[params.length - 1])
|
||||
stack.push(isCallback)
|
||||
}
|
||||
|
||||
function exitFunction() {
|
||||
stack.pop()
|
||||
}
|
||||
|
||||
return {
|
||||
FunctionDeclaration: enterFunction,
|
||||
'FunctionDeclaration:exit': exitFunction,
|
||||
FunctionExpression: enterFunction,
|
||||
'FunctionExpression:exit': exitFunction,
|
||||
ArrowFunctionExpression: enterFunction,
|
||||
'ArrowFunctionExpression:exit': exitFunction,
|
||||
ThrowStatement(node) {
|
||||
if (stack[stack.length - 1]) {
|
||||
context.report({ node, messageId: 'noThrowInCallback' })
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
const { RuleTester } = require('eslint')
|
||||
const noThrowInCallback = require('./no-throw-in-callback')
|
||||
const preferKebabUrl = require('./prefer-kebab-url')
|
||||
const noUnnecessaryTrans = require('./no-unnecessary-trans')
|
||||
const shouldUnescapeTrans = require('./should-unescape-trans')
|
||||
@@ -267,3 +268,53 @@ ruleTester.run(
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
const noThrowInCallbackMessage =
|
||||
'Pass the error to the callback instead of throwing in callback-based code.'
|
||||
ruleTester.run('no-throw-in-callback', noThrowInCallback, {
|
||||
valid: [
|
||||
// Calling the callback with an error is fine
|
||||
{ code: `function foo(cb) { cb(new Error()) }` },
|
||||
// async functions may throw (they return a rejected promise)
|
||||
{ code: `async function foo(cb) { throw new Error() }` },
|
||||
// Last param not a callback name — not a callback-style function
|
||||
{ code: `function foo(data) { throw new Error() }` },
|
||||
// No params at all
|
||||
{ code: `function foo() { throw new Error() }` },
|
||||
// throw inside a nested non-callback function is fine
|
||||
{ code: `function foo(cb) { [1].map(function() { throw new Error() }) }` },
|
||||
// throw inside a nested async arrow is fine
|
||||
{ code: `function foo(cb) { [1].map(async () => { throw new Error() }) }` },
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: `function foo(cb) { throw new Error() }`,
|
||||
errors: [{ message: noThrowInCallbackMessage }],
|
||||
},
|
||||
{
|
||||
code: `function foo(callback) { throw new Error() }`,
|
||||
errors: [{ message: noThrowInCallbackMessage }],
|
||||
},
|
||||
{
|
||||
code: `function foo(done) { throw new Error() }`,
|
||||
errors: [{ message: noThrowInCallbackMessage }],
|
||||
},
|
||||
{
|
||||
code: `function foo(next) { throw new Error() }`,
|
||||
errors: [{ message: noThrowInCallbackMessage }],
|
||||
},
|
||||
{
|
||||
code: `function foo(data, cb) { throw new Error() }`,
|
||||
errors: [{ message: noThrowInCallbackMessage }],
|
||||
},
|
||||
{
|
||||
code: `const foo = (cb) => { throw new Error() }`,
|
||||
errors: [{ message: noThrowInCallbackMessage }],
|
||||
},
|
||||
// throw in a nested callback-style function inside another callback function
|
||||
{
|
||||
code: `function foo(cb) { bar(function(done) { throw new Error() }) }`,
|
||||
errors: [{ message: noThrowInCallbackMessage }],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user