Skip to content

Commit bee96e2

Browse files
committed
fix(tslint): correctly pad the script content
this avoids manipulating the tslint ruleset, which is only necessary because the padding of vueCompiler does not work for lang="ts" scripts. this also makes vue-cli tslint work with tslint-plugin-prettier prereq for: #761 unexpected upstream behavior: https://github.com/vuejs/vue/blob/dev/src/sfc/parser.js#L119
1 parent 873ad84 commit bee96e2

File tree

1 file changed

+46
-28
lines changed
  • packages/@vue/cli-plugin-typescript/lib

1 file changed

+46
-28
lines changed

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

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ module.exports = function lint (args = {}, api, silent) {
2626

2727
const patchWriteFile = () => {
2828
fs.writeFileSync = (file, content, options) => {
29-
if (isVueFile(file)) {
30-
const parts = vueFileCache.get(path.normalize(file))
31-
if (parts) {
32-
parts.content = content
33-
const { before, after } = parts
34-
content = `${before}\n${content.trim()}\n${after}`
35-
}
29+
const parts = vueFileCache.get(path.normalize(file))
30+
if (parts) {
31+
parts.content = content
32+
const { before, after } = parts
33+
content = content.slice(parts.paddingOffset)
34+
content += /\r?\n$/.test(content) ? '' : '\n'
35+
content = `${before}${content}${after}`
3636
}
3737
return writeFileSync(file, content, options)
3838
}
@@ -42,22 +42,50 @@ module.exports = function lint (args = {}, api, silent) {
4242
fs.writeFileSync = writeFileSync
4343
}
4444

45+
const padContent = (parts) => {
46+
// move trailing newline from opening script tag to the before part
47+
const firstNewline = parts.content.match(/^\r?\n/)
48+
if (firstNewline) {
49+
parts.before += firstNewline[0]
50+
parts.content = parts.content.slice(firstNewline[0].length)
51+
}
52+
53+
const newlineCount = parts.before.split(/\r?\n/g).length
54+
const padding = Array(newlineCount).join('//\n')
55+
parts.content = padding + parts.content
56+
parts.paddingOffset = padding.length
57+
}
58+
4559
const parseTSFromVueFile = file => {
60+
file = path.normalize(file)
4661
// If the file has already been cached, don't read the file again. Use the cache instead.
4762
if (vueFileCache.has(file)) {
4863
return vueFileCache.get(file)
4964
}
5065

51-
const content = fs.readFileSync(file, 'utf-8')
52-
const { script } = vueCompiler.parseComponent(content, { pad: 'line' })
53-
if (script && /^tsx?$/.test(script.lang)) {
54-
vueFileCache.set(file, {
55-
before: content.slice(0, script.start),
56-
after: content.slice(script.end),
57-
content: script.content
58-
})
59-
return script
66+
const fileContent = fs.readFileSync(file, 'utf-8')
67+
const { start, end, content, lang } = vueCompiler.parseComponent(fileContent).script || {}
68+
if (!/^tsx?$/.test(lang)) {
69+
return { content: '', lang: 'js' }
6070
}
71+
72+
const parts = {
73+
before: fileContent.slice(0, start),
74+
after: fileContent.slice(end),
75+
content,
76+
lang,
77+
paddingOffset: 0
78+
}
79+
vueFileCache.set(file, parts)
80+
81+
// FIXME pad script content
82+
// this should be done by vueCompiler.parseComponent with options { pad: 'line' },
83+
// but it does this only if no lang is set, so it does not work for lang="ts".
84+
// https://github.com/vuejs/vue/blob/dev/src/sfc/parser.js#L119
85+
// we do it here until upstream dep supports this correctly
86+
padContent(parts)
87+
88+
return parts
6189
}
6290

6391
const program = tslint.Linter.createProgram(api.resolve('tsconfig.json'))
@@ -68,7 +96,7 @@ module.exports = function lint (args = {}, api, silent) {
6896
const getSourceFile = program.getSourceFile
6997
program.getSourceFile = function (file, languageVersion, onError) {
7098
if (isVueFile(file)) {
71-
const { content, lang = 'js' } = parseTSFromVueFile(file) || { content: '', lang: 'js' }
99+
const { content, lang } = parseTSFromVueFile(file)
72100
const contentLang = ts.ScriptKind[lang.toUpperCase()]
73101
return ts.createSourceFile(file, content, languageVersion, true, contentLang)
74102
} else {
@@ -93,25 +121,15 @@ module.exports = function lint (args = {}, api, silent) {
93121
.find(file => fs.existsSync(file))
94122

95123
const config = tslint.Configuration.findConfiguration(tslintConfigPath).results
96-
// create a patched config that disables the blank lines rule,
97-
// so that we get correct line numbers in error reports for *.vue files.
98-
const vueConfig = Object.assign(config)
99-
const rules = vueConfig.rules = new Map(vueConfig.rules)
100-
const rule = rules.get('no-consecutive-blank-lines')
101-
rules.set('no-consecutive-blank-lines', Object.assign({}, rule, {
102-
ruleSeverity: 'off'
103-
}))
104124

105125
const lint = file => {
106126
const filePath = api.resolve(file)
107-
const isVue = isVueFile(file)
108127
patchWriteFile()
109128
linter.lint(
110129
// append .ts so that tslint apply TS rules
111130
filePath,
112131
'',
113-
// use Vue config to ignore blank lines
114-
isVue ? vueConfig : config
132+
config
115133
)
116134
restoreWriteFile()
117135
}

0 commit comments

Comments
 (0)