Skip to content

Commit cb92491

Browse files
committed
refactor(typescript): improve tslint implementation
1 parent c5ac93e commit cb92491

File tree

1 file changed

+57
-48
lines changed
  • packages/@vue/cli-plugin-typescript/lib

1 file changed

+57
-48
lines changed

packages/@vue/cli-plugin-typescript/lib/tslint.js

Lines changed: 57 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,93 +4,102 @@ module.exports = function lint (args = {}, api, silent) {
44
const path = require('path')
55
const globby = require('globby')
66
const tslint = require('tslint')
7+
const ts = require('typescript')
78
/* eslint-disable-next-line node/no-extraneous-require */
89
const vueCompiler = require('vue-template-compiler')
10+
const isVueFile = file => /\.vue(\.ts)?$/.test(file)
911

1012
const options = {
1113
fix: args['fix'] !== false,
1214
formatter: args.format || 'codeFrame',
1315
formattersDirectory: args['formatters-dir'],
1416
rulesDirectory: args['rules-dir']
1517
}
16-
const linter = new tslint.Linter(options)
17-
18-
const config = tslint.Configuration.findConfiguration(api.resolve('tslint.json')).results
19-
// create a patched config that disables the blank lines rule,
20-
// so that we get correct line numbers in error reports for *.vue files.
21-
const vueConfig = Object.assign(config)
22-
const rules = vueConfig.rules = new Map(vueConfig.rules)
23-
const rule = rules.get('no-consecutive-blank-lines')
24-
rules.set('no-consecutive-blank-lines', Object.assign({}, rule, {
25-
ruleSeverity: 'off'
26-
}))
2718

2819
// hack to make tslint --fix work for *.vue files
2920
// this works because (luckily) tslint lints synchronously
3021
const vueFileCache = new Map()
3122
const writeFileSync = fs.writeFileSync
23+
3224
const patchWriteFile = () => {
3325
fs.writeFileSync = (file, content, options) => {
34-
if (/\.vue(\.ts)?$/.test(file)) {
35-
file = file.replace(/\.ts$/, '')
26+
if (isVueFile(file)) {
3627
const { before, after } = vueFileCache.get(path.normalize(file))
3728
content = `${before}\n${content.trim()}\n${after}`
3829
}
3930
return writeFileSync(file, content, options)
4031
}
4132
}
33+
4234
const restoreWriteFile = () => {
4335
fs.writeFileSync = writeFileSync
4436
}
4537

46-
const lint = file => new Promise((resolve, reject) => {
38+
const parseTSFromVueFile = file => {
39+
const content = fs.readFileSync(file, 'utf-8')
40+
const { script } = vueCompiler.parseComponent(content, { pad: 'line' })
41+
if (script) {
42+
vueFileCache.set(file, {
43+
before: content.slice(0, script.start),
44+
after: content.slice(script.end)
45+
})
46+
}
47+
return script && script.content
48+
}
49+
50+
const program = tslint.Linter.createProgram(api.resolve('tsconfig.json'))
51+
52+
// patch getSourceFile for *.vue files
53+
const getSourceFile = program.getSourceFile
54+
program.getSourceFile = function (file, languageVersion, onError) {
55+
if (isVueFile(file)) {
56+
const script = parseTSFromVueFile(file)
57+
return ts.createSourceFile(file, script, languageVersion, true)
58+
} else {
59+
return getSourceFile.call(this, file, languageVersion, onError)
60+
}
61+
}
62+
63+
const linter = new tslint.Linter(options, program)
64+
65+
const config = tslint.Configuration.findConfiguration(api.resolve('tslint.json')).results
66+
// create a patched config that disables the blank lines rule,
67+
// so that we get correct line numbers in error reports for *.vue files.
68+
const vueConfig = Object.assign(config)
69+
const rules = vueConfig.rules = new Map(vueConfig.rules)
70+
const rule = rules.get('no-consecutive-blank-lines')
71+
rules.set('no-consecutive-blank-lines', Object.assign({}, rule, {
72+
ruleSeverity: 'off'
73+
}))
74+
75+
const lint = file => {
4776
const filePath = api.resolve(file)
48-
fs.readFile(filePath, 'utf-8', (err, content) => {
49-
if (err) return reject(err)
50-
const isVue = /\.vue(\.ts)?$/.test(file)
51-
if (isVue) {
52-
const { script } = vueCompiler.parseComponent(content, { pad: 'line' })
53-
if (script) {
54-
vueFileCache.set(filePath, {
55-
before: content.slice(0, script.start),
56-
after: content.slice(script.end)
57-
})
58-
}
59-
content = script && script.content
60-
}
61-
if (content) {
62-
patchWriteFile()
63-
linter.lint(
64-
// append .ts so that tslint apply TS rules
65-
`${filePath}${isVue ? `.ts` : ``}`,
66-
content,
67-
// use Vue config to ignore blank lines
68-
isVue ? vueConfig : config
69-
)
70-
restoreWriteFile()
71-
}
72-
resolve()
73-
})
74-
})
77+
const isVue = isVueFile(file)
78+
patchWriteFile()
79+
linter.lint(
80+
// append .ts so that tslint apply TS rules
81+
filePath,
82+
'',
83+
// use Vue config to ignore blank lines
84+
isVue ? vueConfig : config
85+
)
86+
restoreWriteFile()
87+
}
7588

7689
const files = args._ && args._.length
7790
? args._
7891
: ['src/**/*.ts', 'src/**/*.vue', 'src/**/*.tsx', 'tests/**/*.ts', 'tests/**/*.tsx']
7992

80-
const stripTsExtension = str => str.replace(/\.vue\.ts\b/g, '.vue')
81-
8293
return globby(files, { cwd }).then(files => {
83-
return Promise.all(files.map(lint))
84-
}).then(() => {
94+
files.forEach(lint)
8595
if (silent) return
86-
8796
const result = linter.getResult()
8897
if (result.output.trim()) {
89-
process.stdout.write(stripTsExtension(result.output))
98+
process.stdout.write(result.output)
9099
} else if (result.fixes.length) {
91100
// some formatters do not report fixes.
92101
const f = new tslint.Formatters.ProseFormatter()
93-
process.stdout.write(stripTsExtension(f.format(result.failures, result.fixes)))
102+
process.stdout.write(f.format(result.failures, result.fixes))
94103
} else if (!result.failures.length) {
95104
console.log(`No lint errors found.\n`)
96105
}

0 commit comments

Comments
 (0)