[AST ESlint] Apply fix with ESlint plugin

Code:

const disallowedMethods = ['log', 'info', 'warn', 'error', 'dir']

module.exports = {
  meta: {
    docs: {
      description: 'Disallow use of console',
      category: 'Best Practices',
      recommended: true,
    },
    fixable: 'code',
    schema: [
      {
        type: 'object',
        properties: {
          allowedMethods: {
            type: 'array',
            items: {
              enum: ['log', 'info', 'warn', 'error', 'dir'],
            },
            minItems: 1,
            uniqueItems: true,
          },
        },
      },
    ],
  },
  create(context) {
    const config = context.options[0] || {}
    const allowedMethods = config.allowedMethods || []
    const consoleUsage = []

    // see the source code
    const sourceCode = context.getSourceCode()
    return {
      Identifier(node) {
        if (node.name !== 'console') {
          return
        }
        consoleUsage.push(node)
      },
      'Program:exit'() {
        consoleUsage.forEach(identifier => {
          if (isDisallowedFunctionCall(identifier)) {
            report(identifier.parent.property, identifier)
          } else {
            const variableDeclaratorParent = findParent(
              identifier,
              parent => parent.type === 'VariableDeclarator',
            )
            if (variableDeclaratorParent) {
              const references = context
                .getDeclaredVariables(variableDeclaratorParent)[0]
                .references.slice(1)
              references.forEach(reference => {
                if (
                  !looksLike(reference, {
                    identifier: {
                      parent: {
                        property: isDisallowedFunctionCall,
                      },
                    },
                  })
                ) {
                  return
                }
                report(reference.identifier.parent.property, identifier)
              })
            }
          }
        })
      },
    }

    function report(property, consoleObject) {
      console.log(sourceCode.getText(property.parent)) // csl.log
      context.report({
        node: property,
        message: 'Using console is not allowed',
        fix(fixer) {
          return fixer.replaceText(consoleObject, 'logger')
        },
      })
    }

    function isDisallowedFunctionCall(identifier) {
      return looksLike(identifier, {
        parent: {
          type: 'MemberExpression',
          parent: {type: 'CallExpression'},
          property: {
            name: val =>
              !allowedMethods.includes(val) && disallowedMethods.includes(val),
          },
        },
      })
    }
  },
}

function findParent(node, test) {
  if (test(node)) {
    return node
  } else if (node.parent) {
    return findParent(node.parent, test)
  }
  return null
}

function looksLike(a, b) {
  return (
    a &&
    b &&
    Object.keys(b).every(bKey => {
      const bVal = b[bKey]
      const aVal = a[bKey]
      if (typeof bVal === 'function') {
        return bVal(aVal)
      }
      return isPrimitive(bVal) ? bVal === aVal : looksLike(aVal, bVal)
    })
  )
}

function isPrimitive(val) {
  return val == null || /^[sbn]/.test(typeof val)
}

 

Test:

const {RuleTester} = require('eslint')
const rule = require('./no-console-6')

const ruleTester = new RuleTester()
ruleTester.run('no-console', rule, {
  valid: [
    'info()',
    'console',
    'console.log',
    'console.baz()',
    {code: 'console.warn()', options: [{allowedMethods: ['warn']}]},
  ],
  invalid: [
    invalid('console.log()', 'logger.log()'),
    invalid('console.info()', 'logger.info()'),
    invalid('console.warn()', 'logger.warn()'),
    invalid(
      `
        var csl = console
        csl.log()
      `,
      `
        var csl = logger
        csl.log()
      `,
    ),
  ],
})

function invalid(code, output) {
  const invalidTest = {
    code,
    errors: [{message: 'Using console is not allowed'}],
  }
  if (output) {
    invalidTest.output = output
  }
  return invalidTest
}

 

posted @ 2020-02-17 19:50  Zhentiw  阅读(224)  评论(0编辑  收藏  举报