diff --git a/package.json b/package.json index f615f728..e9d7000f 100644 --- a/package.json +++ b/package.json @@ -71,10 +71,10 @@ "ts-loader": "4.3.0", "tslint": "^5.0.0", "typescript": "^2.6.2", - "vue": "^2.5.9", + "vue": "^2.5.16", "vue-class-component": "^6.1.1", "vue-loader": "^15.2.4", - "vue-template-compiler": "^2.5.9", + "vue-template-compiler": "^2.5.16", "webpack": "^4.0.0" }, "peerDependencies": { @@ -92,7 +92,6 @@ "lodash.startswith": "^4.2.1", "minimatch": "^3.0.4", "resolve": "^1.5.0", - "tapable": "^1.0.0", - "vue-parser": "^1.1.5" + "tapable": "^1.0.0" } } diff --git a/src/VueProgram.ts b/src/VueProgram.ts index fc6a78cd..b1ba72ef 100644 --- a/src/VueProgram.ts +++ b/src/VueProgram.ts @@ -3,7 +3,13 @@ import path = require('path'); import ts = require('typescript'); import FilesRegister = require('./FilesRegister'); import FilesWatcher = require('./FilesWatcher'); -import vueParser = require('vue-parser'); +// tslint:disable-next-line +import vueCompiler = require('vue-template-compiler'); + +interface ResolvedScript { + scriptKind: ts.ScriptKind; + content: string; +} class VueProgram { static loadProgramConfig(configFile: string) { @@ -85,19 +91,6 @@ class VueProgram { const host = ts.createCompilerHost(programConfig.options); const realGetSourceFile = host.getSourceFile; - const getScriptKind = (lang: string) => { - if (lang === "ts") { - return ts.ScriptKind.TS; - } else if (lang === "tsx") { - return ts.ScriptKind.TSX; - } else if (lang === "jsx") { - return ts.ScriptKind.JSX; - } else { - // when lang is "js" or no lang specified - return ts.ScriptKind.JS; - } - } - // We need a host that can parse Vue SFCs (single file components). host.getSourceFile = (filePath, languageVersion, onError) => { // first check if watcher is watching file - if not - check it's mtime @@ -123,21 +116,8 @@ class VueProgram { // get typescript contents from Vue file if (source && VueProgram.isVue(filePath)) { - let parsed: string; - let kind: ts.ScriptKind; - for (const lang of ['ts', 'tsx', 'js', 'jsx']) { - parsed = vueParser.parse(source.text, 'script', { lang: [lang], emptyExport: false }); - if (parsed) { - kind = getScriptKind(lang); - break; - } - } - if (!parsed) { - // when script tag has no lang, or no script tag given - parsed = vueParser.parse(source.text, 'script'); - kind = ts.ScriptKind.JS; - } - source = ts.createSourceFile(filePath, parsed, languageVersion, true, kind); + const resolved = VueProgram.resolveScriptBlock(source.text); + source = ts.createSourceFile(filePath, resolved.content, languageVersion, true, resolved.scriptKind); } return source; @@ -201,6 +181,70 @@ class VueProgram { oldProgram // re-use old program ); } + + private static getScriptKindByLang(lang: string) { + if (lang === "ts") { + return ts.ScriptKind.TS; + } else if (lang === "tsx") { + return ts.ScriptKind.TSX; + } else if (lang === "jsx") { + return ts.ScriptKind.JSX; + } else { + // when lang is "js" or no lang specified + return ts.ScriptKind.JS; + } + } + + private static resolveScriptBlock(content: string): ResolvedScript { + // We need to import vue-template-compiler lazily because it cannot be included it + // as direct dependency because it is an optional dependency of fork-ts-checker-webpack-plugin. + // Since its version must not mismatch with user-installed Vue.js, + // we should let the users install vue-template-compiler by themselves. + let parser: typeof vueCompiler; + try { + // tslint:disable-next-line + parser = require('vue-template-compiler'); + } catch (err) { + throw new Error('When you use `vue` option, make sure to install `vue-template-compiler`.'); + } + + const { script } = parser.parseComponent(content, { + pad: 'line' + }); + + // No diff --git a/test/integration/vue/src/attrs/Test.vue b/test/integration/vue/src/attrs/Test.vue new file mode 100644 index 00000000..046d2f23 --- /dev/null +++ b/test/integration/vue/src/attrs/Test.vue @@ -0,0 +1 @@ + diff --git a/test/integration/vue/src/attrs/test.ts b/test/integration/vue/src/attrs/test.ts new file mode 100644 index 00000000..5987f2ec --- /dev/null +++ b/test/integration/vue/src/attrs/test.ts @@ -0,0 +1,2 @@ +const a: number = ""; +export default { a } diff --git a/test/integration/vue/tsconfig-attrs.json b/test/integration/vue/tsconfig-attrs.json new file mode 100644 index 00000000..2bdc66c5 --- /dev/null +++ b/test/integration/vue/tsconfig-attrs.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": {}, + "include": [ + "src/attrs/Test.vue", + "src/attrs/NotFound.vue" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/test/unit/VueProgram.spec.js b/test/unit/VueProgram.spec.js index f0aedaa8..985a3740 100644 --- a/test/unit/VueProgram.spec.js +++ b/test/unit/VueProgram.spec.js @@ -47,7 +47,7 @@ describe('[UNIT] VueProgram', function () { var options = {}; var moduleName = '@/test.vue'; - resolvedModuleName = VueProgram.resolveNonTsModuleName(moduleName, containingFile, basedir, options); + var resolvedModuleName = VueProgram.resolveNonTsModuleName(moduleName, containingFile, basedir, options); expect(resolvedModuleName).to.be.equal('/base/dir/src/test.vue'); options.baseUrl = '/baseurl1'; diff --git a/yarn.lock b/yarn.lock index b5859ff8..a1593eea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2882,12 +2882,6 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" -parse5@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" - dependencies: - "@types/node" "*" - pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -4210,12 +4204,6 @@ vue-loader@^15.2.4: vue-hot-reload-api "^2.3.0" vue-style-loader "^4.1.0" -vue-parser@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/vue-parser/-/vue-parser-1.1.6.tgz#3063c8431795664ebe429c23b5506899706e6355" - dependencies: - parse5 "^3.0.3" - vue-style-loader@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.0.tgz#7588bd778e2c9f8d87bfc3c5a4a039638da7a863" @@ -4223,9 +4211,9 @@ vue-style-loader@^4.1.0: hash-sum "^1.0.2" loader-utils "^1.0.2" -vue-template-compiler@^2.5.9: - version "2.5.13" - resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.13.tgz#12a2aa0ecd6158ac5e5f14d294b0993f399c3d38" +vue-template-compiler@^2.5.16: + version "2.5.16" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.16.tgz#93b48570e56c720cdf3f051cc15287c26fbd04cb" dependencies: de-indent "^1.0.2" he "^1.1.0" @@ -4234,9 +4222,9 @@ vue-template-es2015-compiler@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.6.0.tgz#dc42697133302ce3017524356a6c61b7b69b4a18" -vue@^2.5.9: - version "2.5.13" - resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.13.tgz#95bd31e20efcf7a7f39239c9aa6787ce8cf578e1" +vue@^2.5.16: + version "2.5.16" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.16.tgz#07edb75e8412aaeed871ebafa99f4672584a0085" watchpack@^1.4.0: version "1.4.0"