zoukankan      html  css  js  c++  java
  • [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
    }
  • 相关阅读:
    POJ 1470 -- Closest Common Ancestors
    js跳转链接的几种方式
    vue移动端项目经验(二)
    css项目知识小汇总
    浏览器滚动条样式自定义(兼容火狐)
    媒体查询
    vue移动端项目经验
    文字溢出时省略号表示
    vue2.0-4.0的移动端及PC端屏幕大小适配
    vue移动端UI组件库
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12323248.html
Copyright © 2011-2022 走看看