tslint 检查 vue 文件补丁脚本

在 vue 项目中使用 tslint 来做代码检查,但当执行 npx tslint -p tsconfig.json 时,发现 tslint 并不能对 vue 文件进行检查。

受到 vue-cli3 中的启发,发现 @vue/cli-plugin-typescript/lib/tslint.js 中写了个补丁专门用来解决这个问题。

主要思想是把 vue 文件中包含的ts部分摘出做验证。

下面是稍微修改的脚本。可以直接粘贴在非 cli3 的项目根目录中。

配合 package.json 修改:

"scripts": {	
  "lint:fix": "node ./lint.js --fix"
  "lint": "node ./lint.js"
},

lint.js 内容:

const fs = require('fs')
const path = require('path')
const globby = require('globby')
const tslint = require('tslint')
const ts = require('typescript')
/* eslint-disable-next-line node/no-extraneous-require */
const vueCompiler = require('vue-template-compiler')
const isVueFile = file => /\.vue(\.ts)?$/.test(file)

const options = {
  fix: process.argv.includes('--fix'),
  formatter: 'codeFrame'
}

// hack to make tslint --fix work for *.vue files:
// we save the non-script parts to a cache right before
// linting the file, and patch fs.writeFileSync to combine the fixed script
// back with the non-script parts.
// this works because (luckily) tslint lints synchronously.
const vueFileCache = new Map()
const writeFileSync = fs.writeFileSync

const patchWriteFile = () => {
  fs.writeFileSync = (file, content, options) => {
    if (isVueFile(file)) {
      const parts = vueFileCache.get(path.normalize(file))
      if (parts) {
        const { before, after } = parts
        content = `${before}\n${content.trim()}\n${after}`
      }
    }
    return writeFileSync(file, content, options)
  }
}

const restoreWriteFile = () => {
  fs.writeFileSync = writeFileSync
}

const parseTSFromVueFile = file => {
  const content = fs.readFileSync(file, 'utf-8')
  const { script } = vueCompiler.parseComponent(content, { pad: 'line' })
  if (script && /^tsx?$/.test(script.lang)) {
    vueFileCache.set(file, {
      before: content.slice(0, script.start),
      after: content.slice(script.end)
    })
    return script.content
  }
}

const program = tslint.Linter.createProgram(path.resolve('tsconfig.json'))

// patch getSourceFile for *.vue files
// so that it returns the <script> block only
const patchProgram = program => {
  const getSourceFile = program.getSourceFile
  program.getSourceFile = function(file, languageVersion, onError) {
    if (isVueFile(file)) {
      const script = parseTSFromVueFile(file) || ''
      return ts.createSourceFile(file, script, languageVersion, true)
    } else {
      return getSourceFile.call(this, file, languageVersion, onError)
    }
  }
}

patchProgram(program)

const linter = new tslint.Linter(options, program)

// patch linter.updateProgram to ensure every program has correct getSourceFile
const updateProgram = linter.updateProgram
linter.updateProgram = function(...args) {
  updateProgram.call(this, ...args)
  patchProgram(this.program)
}

const config = tslint.Configuration.findConfiguration(
  path.resolve('tslint.json')
).results
// create a patched config that disables the blank lines rule,
// so that we get correct line numbers in error reports for *.vue files.
const vueConfig = Object.assign(config)
const rules = (vueConfig.rules = new Map(vueConfig.rules))
const rule = rules.get('no-consecutive-blank-lines')
rules.set(
  'no-consecutive-blank-lines',
  Object.assign({}, rule, {
    ruleSeverity: 'off'
  })
)

const lint = file => {
  const filePath = path.resolve(file)
  const isVue = isVueFile(file)
  patchWriteFile()
  linter.lint(
    // append .ts so that tslint apply TS rules
    filePath,
    '',
    // use Vue config to ignore blank lines
    isVue ? vueConfig : config
  )
  restoreWriteFile()
}

const files = [
  'src/**/*.ts',
  'src/**/*.vue',
  'src/**/*.tsx',
  'tests/**/*.ts',
  'tests/**/*.tsx'
]

return globby(files, './').then(files => {
  files.forEach(lint)
  const result = linter.getResult()
  if (result.output.trim()) {
    process.stdout.write(result.output)
  } else if (result.fixes.length) {
    // some formatters do not report fixes.
    const f = new tslint.Formatters.ProseFormatter()
    process.stdout.write(f.format(result.failures, result.fixes))
  } else if (!result.failures.length) {
    console.log(`No lint errors found.\n`)
  }

  if (result.failures.length) {
    process.exitCode = 1
  }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值