diff --git a/npm-packages/eslint-plugin-meteor/lib/index.js b/npm-packages/eslint-plugin-meteor/lib/index.js index 64477fa8b25..7e415ff3863 100755 --- a/npm-packages/eslint-plugin-meteor/lib/index.js +++ b/npm-packages/eslint-plugin-meteor/lib/index.js @@ -13,6 +13,7 @@ const allRules = { 'no-sync-mongo-methods-on-server': require('./rules/no-sync-mongo-methods-on-server/no-sync-mongo-methods-on-server'), 'no-fibers-future-usage': require('./rules/no-fibers-future-usage'), 'no-promise-fibers-usage': require('./rules/no-promise-fibers-usage'), + 'no-meteor-wrap-async-usage': require('./rules/no-meteor-wrap-async-usage'), }; module.exports = { @@ -40,6 +41,7 @@ module.exports = { 'meteor/no-sync-mongo-methods-on-server': 0, 'meteor/no-fibers-future-usage': 0, 'meteor/no-promise-fibers-usage': 0, + 'meteor/no-meteor-wrap-async-usage': 0, }, }, }, diff --git a/npm-packages/eslint-plugin-meteor/lib/rules/no-meteor-wrap-async-usage.js b/npm-packages/eslint-plugin-meteor/lib/rules/no-meteor-wrap-async-usage.js new file mode 100644 index 00000000000..516196c4154 --- /dev/null +++ b/npm-packages/eslint-plugin-meteor/lib/rules/no-meteor-wrap-async-usage.js @@ -0,0 +1,48 @@ +/** + * @fileoverview This rule checks the usage of Meteor.wrapAsync method. + * @author Matheus Castro + * @copyright 2023 Matheus Castro. All rights reserved. + * See LICENSE file in root directory for full license. + */ + +const meteorIdentifier = "Meteor"; +const wrapAsyncMethodName = "wrapAsync"; +const isAccessingMeteorWrapAsync = (node) => { + const isMemberExpression = node && node.type === "MemberExpression"; + if (!isMemberExpression) { + return; + } + + const nodeObjectName = node && + node.object && + node.object.type === "Identifier" && + node.object.name; + const nodePropertyName = node && + node.property && + node.property.type === "Identifier" && + node.property.name; + + const isMeteorObject = nodeObjectName && nodeObjectName.toLowerCase() === meteorIdentifier.toLowerCase(); + const isWrapAsyncAccess = nodePropertyName && nodePropertyName === wrapAsyncMethodName; + + return isMeteorObject && isWrapAsyncAccess; +}; + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Detect `Meteor.wrapAsync` calls', + recommended: true, + }, + }, + create: (context) => ({ + MemberExpression: (node) => { + if (!isAccessingMeteorWrapAsync(node)) { + return; + } + + context.report(node, "Meteor wrapAsync is going to be removed on Meteor 3.0"); + }, + }), +}; diff --git a/npm-packages/eslint-plugin-meteor/tests/lib/rules/no-meteor-wrap-async-usage.js b/npm-packages/eslint-plugin-meteor/tests/lib/rules/no-meteor-wrap-async-usage.js new file mode 100644 index 00000000000..dd4de0bdf4a --- /dev/null +++ b/npm-packages/eslint-plugin-meteor/tests/lib/rules/no-meteor-wrap-async-usage.js @@ -0,0 +1,80 @@ +/** + * @fileoverview This rule checks the usage of Meteor.wrapAsync method. + * @author Matheus Castro + * @copyright 2023 Matheus Castro. All rights reserved. + * See LICENSE file in root directory for full license. + */ + +const { RuleTester } = require('eslint'); +const rule = require('../../../lib/rules/no-meteor-wrap-async-usage'); + +const ruleTester = new RuleTester({ + parserOptions: { + ecmaVersion: 2015, + }, +}); + +ruleTester.run('no-meteor-wrap-async-usage', rule, { + only: true, + valid: [ + { code: 'Meteor.userAsync()' }, + { code: 'Meteor.userIdAsync()' }, + { code: 'Meteor.callAsync()' }, + { code: 'Meteor.call()' }, + { code: 'this.wrapAsync' }, + { code: 'object.wrapAsync' }, + { code: 'object.wrapAsync()' }, + { code: 'Object.wrapAsync()()' }, + ], + + invalid: [ + { + code: 'Meteor.wrapAsync', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + { + code: 'const asd = Meteor.wrapAsync', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + { + code: 'const asd = Meteor.wrapAsync()', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + { + code: 'const asd = Meteor.wrapAsync(() => {})', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + { + code: 'Meteor.wrapAsync()', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + { + code: 'Meteor.wrapAsync(() => {})', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + { + code: 'Meteor.wrapAsync()()', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + { + code: 'Meteor.wrapAsync(() => {})()', + errors: [ + { message: 'Meteor wrapAsync is going to be removed on Meteor 3.0', type: 'MemberExpression' }, + ], + }, + ], +});