├── .editorconfig ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── NO_REPRO_CASE.md ├── PERF_ISSUE.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── ci.yml │ └── rebase.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .prettierignore ├── .prettierrc ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── ThirdPartyNotices.txt ├── asset ├── stepsize.png └── vue.png ├── build ├── release-cleanup.sh ├── rollup-common-config.js ├── rollup-plugins.js ├── update-docs.sh └── vsix-links.js ├── client ├── client.ts ├── commands │ ├── doctorCommand.ts │ ├── generateGrammarCommand.ts │ ├── openUserScaffoldSnippetFolderCommand.ts │ └── virtualFileCommand.ts ├── grammar.ts ├── languages.ts ├── rollup.config.js ├── tsconfig.json ├── userSnippetDir.ts └── vueMain.ts ├── docs ├── .vuepress │ └── config.js ├── README.md ├── credits.md ├── guide │ ├── FAQ.md │ ├── Readme.md │ ├── component-data.md │ ├── debugging.md │ ├── emmet.md │ ├── formatting.md │ ├── global-components.md │ ├── highlighting.md │ ├── intellisense.md │ ├── interpolation.md │ ├── linting-error.md │ ├── semantic-highlighting.md │ ├── setup.md │ ├── snippet.md │ └── vti.md ├── images │ ├── debug.png │ ├── scope.png │ ├── snippet-main.png │ └── snippet-partial.png └── reference │ ├── Readme.md │ ├── package.md │ └── tsconfig.md ├── languages ├── vue-html-language-configuration.json ├── vue-language-configuration.json ├── vue-postcss-language-configuration.json ├── vue-pug-language-configuration.json └── vue-sugarss-language-configuration.json ├── package.json ├── rfcs ├── 001-vetur-config-file.md └── 002-monorepo-support.md ├── rollup.config.js ├── scripts ├── build_grammar.ts └── tsconfig.json ├── server ├── .gitignore ├── .mocharc.yml ├── .npmrc ├── README.md ├── bin │ └── vls ├── package.json ├── rollup.config.js ├── src │ ├── config.ts │ ├── embeddedSupport │ │ ├── embeddedSupport.ts │ │ ├── languageModelCache.ts │ │ ├── languageModes.ts │ │ ├── test │ │ │ └── embeddedSupport.test.ts │ │ └── vueDocumentRegionParser.ts │ ├── index.ts │ ├── log.ts │ ├── modes │ │ ├── nullMode.ts │ │ ├── plugins │ │ │ └── autoImportSfcPlugin.ts │ │ ├── pug │ │ │ ├── index.ts │ │ │ └── languageService.ts │ │ ├── script │ │ │ ├── CodeActionKindConverter.ts │ │ │ ├── childComponents.ts │ │ │ ├── componentInfo.ts │ │ │ ├── globalComponents.ts │ │ │ ├── javascript.ts │ │ │ ├── previewer.ts │ │ │ └── semanticToken.ts │ │ ├── style │ │ │ ├── emmet.ts │ │ │ ├── index.ts │ │ │ ├── sass │ │ │ │ └── sassLanguageMode.ts │ │ │ └── stylus │ │ │ │ ├── built-in.ts │ │ │ │ ├── completion-item.ts │ │ │ │ ├── css-browser-data.ts │ │ │ │ ├── css-colors-list.ts │ │ │ │ ├── index.ts │ │ │ │ ├── parser.ts │ │ │ │ ├── stylus-hover.ts │ │ │ │ ├── stylus-supremacy.ts │ │ │ │ ├── symbols-finder.ts │ │ │ │ └── test │ │ │ │ ├── completion.test.ts │ │ │ │ └── hover.test.ts │ │ ├── template-common │ │ │ └── tagDefinition.ts │ │ ├── template │ │ │ ├── htmlMode.ts │ │ │ ├── index.ts │ │ │ ├── interpolationMode.ts │ │ │ ├── modifierProvider.ts │ │ │ ├── parser │ │ │ │ ├── htmlParser.ts │ │ │ │ └── htmlScanner.ts │ │ │ ├── services │ │ │ │ ├── htmlCompletion.ts │ │ │ │ ├── htmlDefinition.ts │ │ │ │ ├── htmlEslintValidation.ts │ │ │ │ ├── htmlFolding.ts │ │ │ │ ├── htmlFormat.ts │ │ │ │ ├── htmlHighlighting.ts │ │ │ │ ├── htmlHover.ts │ │ │ │ ├── htmlLinks.ts │ │ │ │ ├── htmlSymbolsProvider.ts │ │ │ │ ├── isInsideInterpolation.ts │ │ │ │ └── vuePropValidation.ts │ │ │ ├── tagProviders │ │ │ │ ├── common.ts │ │ │ │ ├── componentInfoTagProvider.ts │ │ │ │ ├── externalTagProviders.ts │ │ │ │ ├── htmlTags.ts │ │ │ │ ├── index.ts │ │ │ │ ├── nuxtTags.ts │ │ │ │ ├── routerTags.ts │ │ │ │ └── vueTags.ts │ │ │ └── test │ │ │ │ ├── completion.test.ts │ │ │ │ ├── emmet.test.ts │ │ │ │ ├── highlighting.test.ts │ │ │ │ ├── hover.test.ts │ │ │ │ ├── isInsideInterpolation.test.ts │ │ │ │ ├── links.test.ts │ │ │ │ ├── parser.test.ts │ │ │ │ ├── scanner.test.ts │ │ │ │ └── symbols.test.ts │ │ ├── test-util │ │ │ ├── completion-test-util.ts │ │ │ └── hover-test-util.ts │ │ ├── test │ │ │ └── region.test.ts │ │ └── vue │ │ │ ├── index.ts │ │ │ ├── snippets.ts │ │ │ └── veturSnippets │ │ │ ├── default.vue │ │ │ ├── script │ │ │ ├── composition-js-vue2.vue │ │ │ ├── composition-js.vue │ │ │ ├── composition-ts-vue2.vue │ │ │ ├── composition-ts.vue │ │ │ ├── javascript.vue │ │ │ └── typescript.vue │ │ │ ├── style │ │ │ ├── css-scoped.vue │ │ │ ├── css.vue │ │ │ ├── less-scoped.vue │ │ │ ├── less.vue │ │ │ ├── postcss-scoped.vue │ │ │ ├── postcss.vue │ │ │ ├── sass-scoped.vue │ │ │ ├── sass.vue │ │ │ ├── scss-scoped.vue │ │ │ ├── scss.vue │ │ │ ├── sss-scoped.vue │ │ │ ├── sss.vue │ │ │ ├── stylus-scoped.vue │ │ │ └── stylus.vue │ │ │ └── template │ │ │ ├── html.vue │ │ │ └── pug.vue │ ├── prettierEslint.d.ts │ ├── prettierTslint.d.ts │ ├── services │ │ ├── EnvironmentService.ts │ │ ├── RefTokenService.ts │ │ ├── dependencyService.ts │ │ ├── documentService.ts │ │ ├── projectService.ts │ │ ├── typescriptService │ │ │ ├── bridge.ts │ │ │ ├── diagnosticFilter.ts │ │ │ ├── moduleResolutionCache.ts │ │ │ ├── preprocess.ts │ │ │ ├── serviceHost.ts │ │ │ ├── sourceMap.ts │ │ │ ├── test │ │ │ │ ├── sourceMap.test.ts │ │ │ │ └── transformTemplate.test.ts │ │ │ ├── transformTemplate.ts │ │ │ ├── util.ts │ │ │ ├── vueSys.ts │ │ │ └── walkExpression.ts │ │ ├── vls.ts │ │ └── vueInfoService.ts │ ├── types.ts │ ├── typing.d.ts │ ├── utils │ │ ├── cancellationToken.ts │ │ ├── paths.ts │ │ ├── prettier │ │ │ └── index.ts │ │ ├── sleep.ts │ │ ├── strings.ts │ │ ├── vueVersion.ts │ │ └── workspace.ts │ └── vueServerMain.ts ├── tsconfig.json ├── tsconfig.test.json └── yarn.lock ├── syntaxes ├── markdown-vue.json ├── pug │ ├── directives.YAML │ ├── directives.tmLanguage.json │ ├── interpolations.YAML │ └── interpolations.tmLanguage.json ├── vue-generated.json ├── vue-html.YAML ├── vue-html.tmLanguage.json ├── vue-postcss.json ├── vue-sugarss.json ├── vue.tmLanguage.json └── vue.yaml ├── test ├── codeTestRunner.ts ├── completionHelper.ts ├── componentData │ ├── data-dir │ │ └── User │ │ │ └── settings.json │ ├── features │ │ ├── beforeAll │ │ │ └── beforeAll.test.ts │ │ ├── completion │ │ │ └── basic.test.ts │ │ └── hover │ │ │ └── basic.test.ts │ ├── fixture │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── attributes.json │ │ ├── beforeAll.vue │ │ ├── completion │ │ │ ├── Element.vue │ │ │ ├── Event.vue │ │ │ ├── Link.vue │ │ │ ├── Quasar.vue │ │ │ ├── VueRouter.vue │ │ │ └── WorkspaceCustomTags.vue │ │ ├── hover │ │ │ └── Element.vue │ │ ├── package.json │ │ ├── tags.json │ │ └── yarn.lock │ ├── index.ts │ └── path.ts ├── definitionHelper.ts ├── diagnosticHelper.ts ├── editorHelper.ts ├── grammar │ ├── data-dir │ │ └── User │ │ │ └── settings.json │ ├── fixture │ │ ├── Functional.vue │ │ ├── Html.vue │ │ ├── Issue1465.vue │ │ ├── PascalCase.vue │ │ ├── Pug.vue │ │ ├── SingleLine.vue │ │ ├── SugarSS.vue │ │ ├── TemplateTag.vue │ │ └── embedded.md │ ├── grammar.test.ts │ ├── index.ts │ └── results │ │ ├── Functional_vue.json │ │ ├── Html_vue.json │ │ ├── Issue1465_vue.json │ │ ├── PascalCase_vue.json │ │ ├── Pug_vue.json │ │ ├── SingleLine_vue.json │ │ ├── SugarSS_vue.json │ │ ├── TemplateTag_vue.json │ │ └── embedded_md.json ├── hoverHelper.ts ├── interpolation │ ├── data-dir │ │ └── User │ │ │ └── settings.json │ ├── features │ │ ├── beforeAll │ │ │ └── beforeAll.test.ts │ │ ├── completion │ │ │ ├── basic.test.ts │ │ │ ├── class.test.ts │ │ │ └── property.test.ts │ │ ├── definition │ │ │ ├── basic.test.ts │ │ │ ├── class.test.ts │ │ │ └── pug.test.ts │ │ ├── diagnostics │ │ │ ├── basic.test.ts │ │ │ ├── propTypeValidation.test.ts │ │ │ └── propsValidation.test.ts │ │ └── hover │ │ │ └── basic.test.ts │ ├── fixture │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── beforeAll.vue │ │ ├── completion │ │ │ ├── Basic.vue │ │ │ ├── Parent.vue │ │ │ ├── TestComp.vue │ │ │ ├── classComponent │ │ │ │ ├── Child.vue │ │ │ │ └── Parent.vue │ │ │ └── propertyDecorator │ │ │ │ ├── Child.vue │ │ │ │ └── Parent.vue │ │ ├── definition │ │ │ ├── Basic.vue │ │ │ ├── BasicPug.vue │ │ │ ├── Child.vue │ │ │ ├── TestBar.vue │ │ │ └── classComponent │ │ │ │ ├── Child.vue │ │ │ │ └── Parent.vue │ │ ├── diagnostics │ │ │ ├── class-in-template.vue │ │ │ ├── directive-dynamic-argument.vue │ │ │ ├── directive.vue │ │ │ ├── expression.vue │ │ │ ├── external-script.ts │ │ │ ├── external-script.vue │ │ │ ├── filter.vue │ │ │ ├── hyphen-attrs.vue │ │ │ ├── issue-1745-duplicate-event-with-modifiers.vue │ │ │ ├── issue-2254.vue │ │ │ ├── issue-2258.vue │ │ │ ├── issue-3107.vue │ │ │ ├── jsdocs-type-check.vue │ │ │ ├── member-modifiers.vue │ │ │ ├── no-implicit-any-parameters.vue │ │ │ ├── no-implicit-any-v-for-array.vue │ │ │ ├── object-literal.vue │ │ │ ├── optional-in-template.vue │ │ │ ├── propTypeValidation │ │ │ │ ├── ArrayPropsChild.vue │ │ │ │ ├── JSChild.vue │ │ │ │ ├── ParentRight.vue │ │ │ │ ├── ParentWrong.vue │ │ │ │ └── TSChild.vue │ │ │ ├── propsValidation │ │ │ │ ├── array-props-child.vue │ │ │ │ ├── class-child.vue │ │ │ │ ├── object-validator-props-child.vue │ │ │ │ ├── parent.vue │ │ │ │ ├── pass-parent.vue │ │ │ │ └── simple-validator-props-child.vue │ │ │ ├── style-in-template.vue │ │ │ ├── template-literal.vue │ │ │ ├── template-position.vue │ │ │ ├── trivia.vue │ │ │ ├── v-for.vue │ │ │ ├── v-if-and-v-for.vue │ │ │ ├── v-if-narrowing.vue │ │ │ ├── v-on.vue │ │ │ ├── v-slot-scope.vue │ │ │ └── v-slot.vue │ │ ├── hover │ │ │ └── Basic.vue │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── yarn.lock │ ├── index.ts │ └── path.ts ├── lsp │ ├── data-dir │ │ └── User │ │ │ └── settings.json │ ├── features │ │ ├── beforeAll │ │ │ └── beforeAll.test.ts │ │ ├── codeAction │ │ │ └── basic.test.ts │ │ ├── completion │ │ │ ├── autoImport.test.ts │ │ │ ├── emmet.test.ts │ │ │ ├── pathCompletion.test.ts │ │ │ ├── scaffold.test.ts │ │ │ ├── script.test.ts │ │ │ ├── style.test.ts │ │ │ └── template.test.ts │ │ ├── definition │ │ │ └── basic.test.ts │ │ ├── diagnostics │ │ │ ├── Deprecated.test.ts │ │ │ ├── basic.test.ts │ │ │ ├── dotPrefix.test.ts │ │ │ ├── eslint.test.ts │ │ │ ├── issue-1336.test.ts │ │ │ ├── noScriptRegion.test.ts │ │ │ └── unused.test.ts │ │ ├── documentColor │ │ │ └── basic.test.ts │ │ ├── documentHighlight │ │ │ └── basic.test.ts │ │ ├── documentLink │ │ │ └── basic.test.ts │ │ ├── documentSymbol │ │ │ └── basic.test.ts │ │ ├── external │ │ │ └── basic.test.ts │ │ ├── formatting │ │ │ └── basic.test.ts │ │ ├── hover │ │ │ └── basic.test.ts │ │ ├── references │ │ │ └── basic.test.ts │ │ ├── renameFiles │ │ │ └── basic.test.ts │ │ └── semanticTokens │ │ │ └── basic.test.ts │ ├── fixture │ │ ├── .gitignore │ │ ├── .prettierrc │ │ ├── .vscode │ │ │ ├── settings.json │ │ │ └── vetur │ │ │ │ └── snippets │ │ │ │ └── foo.vue │ │ ├── beforeAll.vue │ │ ├── codeAction │ │ │ └── Basic.vue │ │ ├── completion │ │ │ ├── autoImport │ │ │ │ ├── defineInOneLine.vue │ │ │ │ ├── kebab-case.vue │ │ │ │ ├── noDefineComponents.vue │ │ │ │ └── sameComponentName.vue │ │ │ ├── script │ │ │ │ ├── Basic.vue │ │ │ │ ├── Hyphen.vue │ │ │ │ ├── Item.vue │ │ │ │ ├── PathCompletion.vue │ │ │ │ ├── issue-2300.vue │ │ │ │ └── kindModifiers.vue │ │ │ ├── style │ │ │ │ ├── Basic.vue │ │ │ │ ├── Double.vue │ │ │ │ └── SassEmmet.vue │ │ │ ├── template │ │ │ │ ├── Basic.vue │ │ │ │ ├── Emmet.vue │ │ │ │ ├── Item.vue │ │ │ │ └── childComponent │ │ │ │ │ ├── Child1775.vue │ │ │ │ │ ├── Child2143.vue │ │ │ │ │ ├── ChildComp.vue │ │ │ │ │ ├── Parent.vue │ │ │ │ │ ├── Parent1775.vue │ │ │ │ │ └── Parent2143.vue │ │ │ └── vue │ │ │ │ ├── Custom.vue │ │ │ │ └── Scaffold.vue │ │ ├── components │ │ │ ├── App.vue │ │ │ ├── Counter.vue │ │ │ └── Item.vue │ │ ├── definition │ │ │ ├── Basic.Item.vue │ │ │ └── Basic.vue │ │ ├── diagnostics │ │ │ ├── .vitepress │ │ │ │ └── Basic.vue │ │ │ ├── Basic.vue │ │ │ ├── Deprecated.vue │ │ │ ├── ESLint.vue │ │ │ ├── Unused.vue │ │ │ ├── issue-1336.vue │ │ │ └── noScriptRegion │ │ │ │ ├── ChildComp.vue │ │ │ │ └── ParentComp.vue │ │ ├── documentColor │ │ │ └── Basic.vue │ │ ├── documentHighlight │ │ │ ├── Basic.Item.vue │ │ │ └── Basic.vue │ │ ├── documentLink │ │ │ └── Basic.vue │ │ ├── documentSymbol │ │ │ └── Basic.vue │ │ ├── external │ │ │ ├── Foo.pug │ │ │ ├── Foo.ts │ │ │ └── Foo.vue │ │ ├── formatting │ │ │ ├── Basic.Expected.vue │ │ │ ├── Basic.vue │ │ │ ├── Pug.Expected.vue │ │ │ ├── Pug.vue │ │ │ ├── Sass.Expected.vue │ │ │ ├── Sass.vue │ │ │ ├── TwoStylus.Expected.vue │ │ │ ├── TwoStylus.vue │ │ │ ├── VueHNUserView.Expected.vue │ │ │ ├── VueHNUserView.vue │ │ │ ├── issue-2467.Expected.vue │ │ │ └── issue-2467.vue │ │ ├── hover │ │ │ └── Basic.vue │ │ ├── package.json │ │ ├── references │ │ │ ├── Basic.Item.vue │ │ │ └── Basic.vue │ │ ├── renameFiles │ │ │ ├── Basic.vue │ │ │ └── Imported.vue │ │ ├── router.js │ │ ├── semanticTokens │ │ │ └── Basic.vue │ │ ├── store.js │ │ ├── tsconfig.json │ │ └── yarn.lock │ ├── index.ts │ └── path.ts ├── monorepo │ ├── data-dir │ │ └── User │ │ │ └── settings.json │ ├── features │ │ ├── beforeAll │ │ │ └── beforeAll.test.ts │ │ ├── completion │ │ │ ├── alias.test.ts │ │ │ └── vue3.test.ts │ │ └── diagnostics │ │ │ ├── basic.ts │ │ │ ├── eslint.test.ts │ │ │ └── globalComponent.test.ts │ ├── fixture │ │ ├── package.json │ │ ├── packages │ │ │ ├── vue2 │ │ │ │ ├── completion │ │ │ │ │ └── Alias.vue │ │ │ │ ├── components │ │ │ │ │ └── AppSpinner.vue │ │ │ │ ├── diagnostics │ │ │ │ │ └── ESLint.vue │ │ │ │ ├── jsconfig.json │ │ │ │ └── package.json │ │ │ └── vue3 │ │ │ │ ├── package.json │ │ │ │ └── src │ │ │ │ ├── App.vue │ │ │ │ ├── components │ │ │ │ └── AppButton.vue │ │ │ │ ├── data │ │ │ │ └── test.json │ │ │ │ └── tsconfig.json │ │ ├── vetur.config.js │ │ └── yarn.lock │ ├── index.ts │ └── path.ts ├── semanticTokenHelper.ts ├── tsconfig.json ├── util.ts └── vue3 │ ├── data-dir │ └── User │ │ └── settings.json │ ├── features │ ├── beforeAll │ │ └── beforeAll.test.ts │ ├── completion │ │ ├── basic.test.ts │ │ ├── interpolation.test.ts │ │ ├── interpolationClassComponent.test.ts │ │ └── interpolationProperty.test.ts │ ├── diagnostics │ │ ├── emitTypeValidation.test.ts │ │ ├── eslint.test.ts │ │ ├── propTypeValidation.test.ts │ │ ├── propValidation.test.ts │ │ └── scriptSetup.test.ts │ └── semanticTokens │ │ └── basic.test.ts │ ├── fixture │ ├── .vscode │ │ └── settings.json │ ├── beforeAll.vue │ ├── completion │ │ ├── Basic.vue │ │ └── interpolation │ │ │ ├── Basic.vue │ │ │ ├── Parent.vue │ │ │ ├── classComponent │ │ │ ├── Child.vue │ │ │ └── Parent.vue │ │ │ └── propertyDecorator │ │ │ ├── Child.vue │ │ │ ├── ChildWithEmitsOption.vue │ │ │ └── Parent.vue │ ├── diagnostics │ │ ├── ESLint.vue │ │ ├── emitTypeValidation │ │ │ ├── JSChild.vue │ │ │ ├── ParentRight.vue │ │ │ ├── ParentWrong.vue │ │ │ ├── PropertyChild.vue │ │ │ └── TSChild.vue │ │ ├── propTypeValidation │ │ │ ├── JSChild.vue │ │ │ ├── ParentRight.vue │ │ │ ├── ParentWrong.vue │ │ │ └── TSChild.vue │ │ ├── propValidation │ │ │ ├── ParentRight.vue │ │ │ └── TSChild.vue │ │ ├── scriptSetup1.vue │ │ ├── scriptSetup2.vue │ │ └── scriptSetupDiag.vue │ ├── package.json │ ├── semanticTokens │ │ └── Basic.vue │ ├── shims-vue.d.ts │ ├── tsconfig.json │ └── yarn.lock │ ├── index.ts │ └── path.ts ├── tsconfig.options.json ├── tslint.json ├── vti ├── README.md ├── bin │ └── vti ├── package.json ├── rollup.config.js ├── src │ ├── cli.ts │ ├── commands │ │ └── diagnostics.ts │ └── initParams.ts ├── tsconfig.json └── yarn.lock └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | indent_style = space 4 | indent_size = 2 5 | end_of_line = lf 6 | insert_final_newline = false 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Use LF for now to work around https://github.com/vuejs/vetur/issues/1319 2 | * text=auto eol=lf 3 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | Contribution is welcome! There are many ways you could help Vetur's development: 4 | 5 | - Triaging Issues 6 | - Writing Code 7 | - Improving Doc 8 | 9 | For more information, please read: https://github.com/vuejs/vetur/wiki#contribution-guide. -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [octref] 4 | issuehunt: vuejs/vetur 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug Report" 3 | about: Something doesn't work 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | - [ ] I have searched through existing issues 13 | - [ ] I have read through [docs](https://vuejs.github.io/vetur) 14 | - [ ] I have read [FAQ](https://vuejs.github.io/vetur/guide/FAQ.html) 15 | - [ ] I have tried restarting VS Code or running `Vetur: Restart VLS` 16 | 17 | ## Info 18 | 19 | - Platform: 20 | - Vetur version: 21 | - VS Code version: 22 | - TypeScript version: 23 | - Vetur output: 24 |
Output 25 |

26 | 27 | ``` 28 | 29 | ``` 30 | 31 |

32 |
33 | - Vetur doctor output 34 |
Doctor output 35 |

36 | 37 | ``` 38 | 39 | ``` 40 | 41 |

42 |
43 | 44 | ## Problem 45 | 46 | 47 | 48 | 49 | ## Reproducible Case 50 | 51 | 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature Request" 3 | about: I have an idea for Vetur 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | - [ ] I have searched through existing issues 13 | 14 | ## Feature Request 15 | 16 | 17 | -------------------------------------------------------------------------------- /.github/NO_REPRO_CASE.md: -------------------------------------------------------------------------------- 1 | # No Repro Case Issues 2 | 3 | You are here because your issue is closed with `no-repro-case` tag. Please read below and open a new issue with repro case. 4 | 5 | ## What is a repro case? 6 | 7 | Repro case, short for *reproducible case*, refers to a minimal example that demonstrates the problem. 8 | 9 | Good repro cases help maintainers a lot: 10 | 11 | 1. They can be reproduced and debugged in maintainers' setup. 12 | 2. They demonstrate a singular bug in a simple setting, so it's easy to find the cause. 13 | 14 | Writing a good repro case helps *you* as well. In the process of reducing your question to the simplest form, you communicate more clearly, gain deeper understanding of the problem, and sometimes even figure out the cause of the bug yourself. 15 | 16 | ## How to create a repro case? 17 | 18 | Read Stack Overflow's guide to writing a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example), if you haven't. 19 | 20 | In the case of Vetur: 21 | 22 | - Clone https://github.com/octref/veturpack and install its dependencies 23 | - Make a minimal code change to demonstrate your problem 24 | - Push your commit to a fork 25 | - Include link to the fork in the issue 26 | 27 | **Note: Turn off all other Vue extensions. If your issue is about a Vetur setting, turn off all other Vetur settings and only change the setting which is causing issue.** -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | versioning-strategy: increase 6 | schedule: 7 | interval: "weekly" 8 | day: "friday" 9 | time: "06:00" 10 | timezone: "Asia/Shanghai" 11 | - package-ecosystem: npm 12 | directory: /server 13 | versioning-strategy: increase 14 | schedule: 15 | interval: "weekly" 16 | day: "friday" 17 | time: "06:00" 18 | timezone: "Asia/Shanghai" 19 | - package-ecosystem: npm 20 | directory: /vti 21 | versioning-strategy: increase 22 | schedule: 23 | interval: "weekly" 24 | day: "friday" 25 | time: "06:00" 26 | timezone: "Asia/Shanghai" -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | on: 2 | issue_comment: 3 | types: [created] 4 | name: Automatic Rebase 5 | jobs: 6 | rebase: 7 | name: Rebase 8 | if: github.event.issue.pull_request != '' && github.event.comment.author_association == 'MEMBER' && contains(github.event.comment.body, '/rebase') 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout the latest code 12 | uses: actions/checkout@v2 13 | with: 14 | fetch-depth: 0 15 | - name: Automatic Rebase 16 | uses: cirrus-actions/rebase@1.3.1 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | 4 | node_modules 5 | .vscode-test 6 | 7 | test/**/data-dir/** 8 | !test/**/data-dir/User 9 | test/**/data-dir/User/** 10 | !test/**/data-dir/User/settings.json 11 | 12 | dist 13 | server/dist 14 | server/typings 15 | docs/.vuepress/dist 16 | dist-test/ 17 | server/dist-test/ 18 | 19 | *.zip 20 | *.vsix 21 | 22 | .nyc_output 23 | coverage.lcov 24 | 25 | **/*.tsbuildinfo 26 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn lint-staged 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | server/src/modes/template/test/completion.test.ts 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "semi": true, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "arrowParens": "avoid" 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "docs/_book": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "watch", 7 | "problemMatcher": [ 8 | "$tsc-watch" 9 | ], 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | } 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | .vscode/ 3 | .vscode-test/ 4 | build/ 5 | docs/ 6 | client/ 7 | **/test/ 8 | server/src/ 9 | server/typings 10 | vti 11 | dist-test/ 12 | server/dist-test/ 13 | 14 | server/node_modules/typescript/lib/tsc.js 15 | server/node_modules/typescript/lib/tsserver.js 16 | server/node_modules/typescript/lib/tsserverlibrary.js 17 | server/node_modules/typescript/lib/typescriptServices.js 18 | 19 | .** 20 | 21 | **/*.map 22 | **/tsconfig.json 23 | **/tsconfig.**.json 24 | **/tslint.json 25 | **/yarn.lock 26 | 27 | .vsix 28 | scripts 29 | 30 | node_modules/.cache/ 31 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 12 | 13 | This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at https://www.contributor-covenant.org/version/1/0/0/code-of-conduct.html 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Pine Wu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /asset/stepsize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/vetur/96aaa707f8ca629f0883c57a47adb0e58995936d/asset/stepsize.png -------------------------------------------------------------------------------- /asset/vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/vetur/96aaa707f8ca629f0883c57a47adb0e58995936d/asset/vue.png -------------------------------------------------------------------------------- /build/release-cleanup.sh: -------------------------------------------------------------------------------- 1 | # Deps 2 | yarn --prod 3 | 4 | # Remove server devDependencies 5 | cd server && yarn --prod && cd .. 6 | -------------------------------------------------------------------------------- /build/rollup-common-config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const json = require('@rollup/plugin-json'); 4 | const commonjs = require('@rollup/plugin-commonjs'); 5 | const typescript = require('rollup-plugin-typescript2'); 6 | const resolve = require('@rollup/plugin-node-resolve').default; 7 | const { terser } = require('rollup-plugin-terser'); 8 | 9 | const getRootPath = root => relative => path.resolve(__dirname, '../', root, relative); 10 | 11 | const clearDist = dist => { 12 | if (fs.existsSync(dist)) { 13 | fs.rmSync(dist, { recursive: true }); 14 | } 15 | }; 16 | 17 | const onwarn = (warning, warn) => { 18 | // typescript tslib 19 | if (warning.code === 'THIS_IS_UNDEFINED') return; 20 | 21 | warn(warning); 22 | }; 23 | 24 | const external = [ 25 | // node built-in 26 | 'path', 27 | 'fs', 28 | 'child_process', 29 | 'os', 30 | 'net', 31 | 'util', 32 | 'crypto', 33 | 'url', 34 | 'assert', 35 | 'inspector', 36 | 'module', 37 | 'events', 38 | 'tty', 39 | 'buffer', 40 | 'stream', 41 | 'string_decoder', 42 | 'perf_hooks', 43 | // vscode 44 | 'vscode' 45 | ]; 46 | 47 | const createPlugins = tsconfig => [ 48 | json(), 49 | resolve(), 50 | commonjs(), 51 | typescript({ tsconfig, tsconfigOverride: { compilerOptions: { module: 'esnext' } } }), 52 | terser() 53 | ]; 54 | 55 | module.exports = { 56 | getRootPath, 57 | clearDist, 58 | onwarn, 59 | external, 60 | createPlugins 61 | }; 62 | -------------------------------------------------------------------------------- /build/update-docs.sh: -------------------------------------------------------------------------------- 1 | # Prepare 2 | cd docs 3 | rm -rf .vuepress/dist 4 | 5 | # Build 6 | vuepress build 7 | 8 | # Publish to GitHub Pages 9 | cd .vuepress/dist 10 | git init 11 | git add -A 12 | git commit -m '[vuepress] update docs' 13 | git push -f git@github.com:vuejs/vetur.git master:gh-pages 14 | 15 | # Cleanup 16 | cd ../.. 17 | rm -rf .vuepress/dist 18 | -------------------------------------------------------------------------------- /build/vsix-links.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Include VSIX Links in Changelog.md 3 | */ 4 | 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | 8 | const CHANGELOG_PATH = path.resolve(__dirname, '../CHANGELOG.md'); 9 | 10 | const changelog = fs.readFileSync(CHANGELOG_PATH, 'utf-8'); 11 | 12 | const newChangelog = changelog.replace(/### ([0-9.]+) \| ([0-9-]+)\n/g, (match, ver, date) => { 13 | const publisher = 'octref'; 14 | const extname = 'vetur'; 15 | const link = `https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher}/vsextensions/${extname}/${ver}/vspackage`; 16 | 17 | return `### ${ver} | ${date} | [VSIX](${link})\n`; 18 | }); 19 | 20 | fs.writeFileSync(CHANGELOG_PATH, newChangelog); 21 | -------------------------------------------------------------------------------- /client/commands/doctorCommand.ts: -------------------------------------------------------------------------------- 1 | import vscode from 'vscode'; 2 | import { LanguageClient } from 'vscode-languageclient/node'; 3 | 4 | export function generateDoctorCommand(client: LanguageClient) { 5 | return async () => { 6 | if (!vscode.window.activeTextEditor || !vscode.window.activeTextEditor.document.fileName.endsWith('.vue')) { 7 | return vscode.window.showInformationMessage('Failed to doctor. Make sure the current file is a .vue file.'); 8 | } 9 | 10 | const fileName = vscode.window.activeTextEditor.document.fileName; 11 | 12 | const result = (await client.sendRequest('$/doctor', { fileName })) as string; 13 | const showText = result.slice(0, 1000) + '....'; 14 | const action = await vscode.window.showInformationMessage(showText, { modal: true }, 'Ok', 'Copy'); 15 | if (action === 'Copy') { 16 | await vscode.env.clipboard.writeText(result); 17 | } 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /client/commands/generateGrammarCommand.ts: -------------------------------------------------------------------------------- 1 | import vscode from 'vscode'; 2 | import { writeFileSync } from 'fs'; 3 | import { resolve } from 'path'; 4 | import { getGeneratedGrammar } from '../grammar'; 5 | 6 | export function generateGrammarCommandHandler(extensionPath: string) { 7 | return () => { 8 | try { 9 | const customBlocks: { [k: string]: string } = 10 | vscode.workspace.getConfiguration().get('vetur.grammar.customBlocks') || {}; 11 | const generatedGrammar = getGeneratedGrammar( 12 | resolve(extensionPath, 'syntaxes/vue.tmLanguage.json'), 13 | customBlocks 14 | ); 15 | writeFileSync(resolve(extensionPath, 'syntaxes/vue-generated.json'), generatedGrammar, 'utf-8'); 16 | vscode.window.showInformationMessage('Successfully generated vue grammar. Reload VS Code to enable it.'); 17 | } catch (e) { 18 | console.error((e as Error).stack); 19 | vscode.window.showErrorMessage( 20 | 'Failed to generate vue grammar. `vetur.grammar.customBlocks` contain invalid language values' 21 | ); 22 | } 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /client/commands/openUserScaffoldSnippetFolderCommand.ts: -------------------------------------------------------------------------------- 1 | import vscode from 'vscode'; 2 | import * as fs from 'fs'; 3 | 4 | export function generateOpenUserScaffoldSnippetFolderCommand(globalSnippetDir: string) { 5 | return async () => { 6 | const uri = vscode.Uri.file(globalSnippetDir); 7 | 8 | if (!fs.existsSync(uri.fsPath)) { 9 | fs.mkdirSync(uri.fsPath); 10 | } 11 | 12 | vscode.commands.executeCommand('vscode.openFolder', uri, true); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /client/languages.ts: -------------------------------------------------------------------------------- 1 | import { languages, IndentAction } from 'vscode'; 2 | 3 | const EMPTY_ELEMENTS: string[] = [ 4 | 'area', 5 | 'base', 6 | 'br', 7 | 'col', 8 | 'embed', 9 | 'hr', 10 | 'img', 11 | 'input', 12 | 'keygen', 13 | 'link', 14 | 'menuitem', 15 | 'meta', 16 | 'param', 17 | 'source', 18 | 'track', 19 | 'wbr' 20 | ]; 21 | 22 | export function registerLanguageConfigurations() { 23 | languages.setLanguageConfiguration('vue-html', { 24 | wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g, 25 | onEnterRules: [ 26 | { 27 | beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), 28 | afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>$/i, 29 | action: { indentAction: IndentAction.IndentOutdent } 30 | }, 31 | { 32 | beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), 33 | action: { indentAction: IndentAction.Indent } 34 | } 35 | ] 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /client/rollup.config.js: -------------------------------------------------------------------------------- 1 | const { getRootPath, clearDist, external, createPlugins } = require('../build/rollup-common-config'); 2 | const clientPkg = require('../package.json'); 3 | 4 | const getClientPath = getRootPath('client'); 5 | 6 | clearDist(getClientPath('../dist')); 7 | module.exports = { 8 | input: getClientPath('vueMain.ts'), 9 | output: { file: clientPkg.main, name: clientPkg.name, format: 'cjs', sourcemap: true }, 10 | external, 11 | watch: { 12 | include: getClientPath('**') 13 | }, 14 | plugins: createPlugins(getClientPath('tsconfig.json')) 15 | }; 16 | -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.options.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "outDir": "../dist", 6 | "rootDir": ".." 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/userSnippetDir.ts: -------------------------------------------------------------------------------- 1 | 2 | import { homedir } from 'os'; 3 | import { resolve } from 'path'; 4 | 5 | export function getGlobalSnippetDir(isInsiders: boolean) { 6 | const appName = isInsiders ? 'Code - Insiders' : 'Code'; 7 | 8 | if (process.platform === 'win32') { 9 | return resolve(process.env['APPDATA'] || '', appName, 'User/snippets/vetur'); 10 | } else if (process.platform === 'darwin') { 11 | return resolve(homedir(), 'Library/Application Support', appName, 'User/snippets/vetur'); 12 | } else { 13 | return resolve(homedir(), '.config', appName, 'User/snippets/vetur'); 14 | } 15 | } -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'Vetur', 3 | description: 'Vue tooling for VS Code.', 4 | base: '/vetur/', 5 | markdown: { 6 | linkify: true 7 | }, 8 | themeConfig: { 9 | repo: 'vuejs/vetur', 10 | editLinks: true, 11 | docsDir: 'docs', 12 | nav: [ 13 | { text: 'Guide', link: '/guide/' }, 14 | { text: 'Reference', link: '/reference/' }, 15 | { text: 'FAQ', link: '/guide/FAQ' }, 16 | { text: 'Roadmap', link: 'https://github.com/vuejs/vetur/issues/873' }, 17 | { text: 'Credits', link: '/credits' }, 18 | { text: 'Contribution Guide', link: 'https://github.com/vuejs/vetur/wiki#contribution-guide' } 19 | ], 20 | sidebar: { 21 | '/guide/': [ 22 | '', 23 | 'setup', 24 | { 25 | title: 'Features', 26 | collapsable: false, 27 | children: [ 28 | 'highlighting', 29 | 'semantic-highlighting', 30 | 'snippet', 31 | 'emmet', 32 | 'linting-error', 33 | 'formatting', 34 | 'intellisense', 35 | 'debugging', 36 | 'component-data', 37 | 'interpolation', 38 | 'vti', 39 | 'global-components' 40 | ] 41 | }, 42 | 'FAQ' 43 | ], 44 | '/reference/': ['', 'tsconfig'] 45 | } 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /docs/credits.md: -------------------------------------------------------------------------------- 1 | # Credits 2 | 3 | Main Developer: [@octref](https://github.com/octref) 4 | 5 | Contributors: 6 | - [@HerringtonDarkholme](https://github.com/HerringtonDarkholme) 7 | - [@sandersn](https://github.com/sandersn) 8 | - [@yoyo930021](https://github.com/yoyo930021) 9 | - [@ktsn](https://github.com/ktsn) 10 | - [@rchl](https://github.com/rchl) 11 | - [@Uninen](https://github.com/Uninen) 12 | 13 | Others: https://github.com/vuejs/vetur/graphs/contributors 14 | 15 | ### Attributions 16 | 17 | Vetur is based on Microsoft's [html language service](https://github.com/Microsoft/vscode/tree/master/extensions/html) for VS Code. 18 | 19 | Others: 20 | - Logo from [vuejs/vuejs.org](https://github.com/vuejs/vuejs.org) 21 | - Grammar based on [vuejs/vue-syntax-highlight](https://github.com/vuejs/vue-syntax-highlight) 22 | - Sass grammar based on [TheRealSyler/vscode-sass-indented](https://github.com/TheRealSyler/vscode-sass-indented) 23 | - PostCSS grammar based on [hudochenkov/Syntax-highlighting-for-PostCSS](https://github.com/hudochenkov/Syntax-highlighting-for-PostCSS) 24 | - TypeScript/JavaScript based on [TypeScript](https://github.com/microsoft/TypeScript/#readme) 25 | - CSS/SCSS/LESS feature based on [vscode-css-languageservice](https://github.com/microsoft/vscode-css-languageservice) 26 | -------------------------------------------------------------------------------- /docs/guide/debugging.md: -------------------------------------------------------------------------------- 1 | # Debugging 2 | 3 | See [https://github.com/Microsoft/vscode-recipes/tree/master/vuejs-cli](https://github.com/Microsoft/vscode-recipes/tree/master/vuejs-cli). 4 | -------------------------------------------------------------------------------- /docs/guide/emmet.md: -------------------------------------------------------------------------------- 1 | # Emmet 2 | 3 | New Emmet support is available for `html`, `css`, `scss`, `less`, `stylus`, `sass` without any configuration for VS Code 1.15.0+. 4 | -------------------------------------------------------------------------------- /docs/guide/global-components.md: -------------------------------------------------------------------------------- 1 | # Global components 2 | 3 | Vetur support define global components. 4 | You can register template interpolation for that components anywhere in the project. 5 | 6 | Please add `projects.globalComponents` in `vetur.config.js`. 7 | 8 | ## Example 9 | When your project isn't a monorepo and `package.json/(ts|js)config.json` at project root. 10 | ```javascript 11 | // vetur.config.js 12 | /** @type {import('vls').VeturConfig} */ 13 | module.exports = { 14 | projects: [ 15 | { 16 | root: './', 17 | // **optional** default: `[]` 18 | // Register globally Vue component glob. 19 | // If you set it, you can get completion by that components. 20 | // It is relative to root property. 21 | // Notice: It won't actually do it. You need to use `require.context` or `Vue.component` 22 | globalComponents: [ 23 | './src/components/**/*.vue', 24 | { 25 | // Component name 26 | name: 'FakeButton', 27 | // Component file path, please use '/'. 28 | path: './src/app/components/AppButton.vue' 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /docs/guide/semantic-highlighting.md: -------------------------------------------------------------------------------- 1 | # Semantic Highlighting 2 | 3 | https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide 4 | 5 | Vetur supports semantic highlighting for the following languages: 6 | - TypeScript 7 | - JavaScript 8 | 9 | ## Ref in composition API 10 | 11 | The `.value` will get `property.refValue`. 12 | Vetur will automatic underline `.value`. You can set `{ "vetur.underline.refValue": false }` to close it in vscode setting. 13 | 14 | And use this setting for customize style. 15 | ```json 16 | { 17 | "editor.semanticTokenColorCustomizations": { 18 | "enabled": true, 19 | "rules": { 20 | "property.refValue": { 21 | "underline": true 22 | } 23 | } 24 | } 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/guide/vti.md: -------------------------------------------------------------------------------- 1 | # VTI 2 | 3 | 🚧 WIP. This feature is not stable yet. 🚧 4 | 5 | VTI (Vetur Terminal Interface) is a CLI that exposes some of Vetur's language features: 6 | 7 | - [x] Diagnostic errors 8 | - [ ] Formatting 9 | 10 | ## Why 11 | 12 | VTI catches type-errors in Vue templates that's not catchable by either Vue or TypeScript alone. 13 | 14 | - Vue compiler: do not understand types. 15 | - TypeScript compiler: do not understand Vue templates. 16 | - VLS: Understand both to do [TS type-checking on Vue templates](https://vuejs.github.io/vetur/guide/interpolation.html). 17 | - VTI: Surfaces VLS's errors on CLI for CI. 18 | 19 | ## Usage 20 | 21 | ```bash 22 | npm i -g vti 23 | # or yarn global add vti 24 | # run this in the root of a Vue project 25 | vti 26 | vti diagnostics 27 | ``` 28 | 29 | ![VTI demo](https://user-images.githubusercontent.com/4033249/72225084-911ef580-3581-11ea-9943-e7165126ace9.gif). 30 | 31 | You also can use [`vetur.config.js`](/reference/) for setting VTI. 32 | 33 | Currently, this is only used for generating interpolation type-checking errors on CLI, which 34 | neither Vue's compiler nor Webpack would catch. 35 | 36 | Please send feedback to: https://github.com/vuejs/vetur/issues/1635. 37 | -------------------------------------------------------------------------------- /docs/images/debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/vetur/96aaa707f8ca629f0883c57a47adb0e58995936d/docs/images/debug.png -------------------------------------------------------------------------------- /docs/images/scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/vetur/96aaa707f8ca629f0883c57a47adb0e58995936d/docs/images/scope.png -------------------------------------------------------------------------------- /docs/images/snippet-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/vetur/96aaa707f8ca629f0883c57a47adb0e58995936d/docs/images/snippet-main.png -------------------------------------------------------------------------------- /docs/images/snippet-partial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuejs/vetur/96aaa707f8ca629f0883c57a47adb0e58995936d/docs/images/snippet-partial.png -------------------------------------------------------------------------------- /docs/reference/package.md: -------------------------------------------------------------------------------- 1 | ## package.json 2 | 3 | Same as `package.json` in nodejs project. 4 | Vetur infer vue version and support other libs from this file. 5 | -------------------------------------------------------------------------------- /docs/reference/tsconfig.md: -------------------------------------------------------------------------------- 1 | # Javascript / Typescript config 2 | 3 | See https://www.typescriptlang.org/tsconfig 4 | -------------------------------------------------------------------------------- /languages/vue-html-language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "blockComment": [ "" ] 4 | }, 5 | "brackets": [ 6 | [""], 7 | ["<", ">"], 8 | ["{", "}"], 9 | ["(", ")"] 10 | ], 11 | "colorizedBracketPairs": [ 12 | ["{", "}"], 13 | ["{{", "}}"], 14 | ["[", "]"], 15 | ["(", ")"] 16 | ], 17 | "autoClosingPairs": [ 18 | { "open": "{", "close": "}"}, 19 | { "open": "[", "close": "]"}, 20 | { "open": "(", "close": ")" }, 21 | { "open": "'", "close": "'" }, 22 | { "open": "\"", "close": "\"" } 23 | ], 24 | "surroundingPairs": [ 25 | { "open": "'", "close": "'" }, 26 | { "open": "\"", "close": "\"" }, 27 | { "open": "{", "close": "}"}, 28 | { "open": "[", "close": "]"}, 29 | { "open": "(", "close": ")" }, 30 | { "open": "<", "close": ">" } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /languages/vue-language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | "lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "/*", "*/" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"] 13 | ], 14 | // symbols that are auto closed when typing 15 | "autoClosingPairs": [ 16 | { "open": "{", "close": "}" }, 17 | { "open": "[", "close": "]" }, 18 | { "open": "(", "close": ")" }, 19 | { "open": "\"", "close": "\"", "notIn": ["string"] }, 20 | { "open": "'", "close": "'", "notIn": ["string", "comment"] }, 21 | { "open": "`", "close": "`", "notIn": ["string", "comment"] }, 22 | { "open": "/**", "close": " */", "notIn": ["string"] } 23 | ], 24 | // symbols that that can be used to surround a selection 25 | "surroundingPairs": [ 26 | ["{", "}"], 27 | ["[", "]"], 28 | ["(", ")"], 29 | ["\"", "\""], 30 | ["'", "'"], 31 | ["`", "`"] 32 | ], 33 | "folding": { 34 | "markers": { 35 | "start": "^<(template|style|script)[^>]*>", 36 | "end": "^" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /languages/vue-postcss-language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 4 | "blockComment": [ "/*", "*/" ] 5 | }, 6 | // symbols used as brackets 7 | "brackets": [ 8 | ["{", "}"], 9 | ["[", "]"], 10 | ["(", ")"] 11 | ], 12 | // symbols that are auto closed when typing 13 | "autoClosingPairs": [ 14 | ["{", "}"], 15 | ["[", "]"], 16 | ["(", ")"], 17 | ["\"", "\""], 18 | ["'", "'"] 19 | ], 20 | // symbols that that can be used to surround a selection 21 | "surroundingPairs": [ 22 | ["{", "}"], 23 | ["[", "]"], 24 | ["(", ")"], 25 | ["\"", "\""], 26 | ["'", "'"] 27 | ] 28 | } -------------------------------------------------------------------------------- /languages/vue-pug-language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//-" 4 | }, 5 | "brackets": [ 6 | ["{", "}"], 7 | ["[", "]"], 8 | ["(", ")"] 9 | ], 10 | "autoClosingPairs": [ 11 | ["{", "}"], 12 | ["[", "]"], 13 | ["(", ")"], 14 | ["'", "'"], 15 | ["\"", "\""] 16 | ], 17 | "surroundingPairs": [ 18 | ["{", "}"], 19 | ["[", "]"], 20 | ["(", ")"], 21 | ["'", "'"], 22 | ["\"", "\""] 23 | ], 24 | "folding": { 25 | "offSide": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /languages/vue-sugarss-language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 4 | "blockComment": [ "/*", "*/" ] 5 | }, 6 | // symbols used as brackets 7 | "brackets": [ 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | // symbols that are auto closed when typing 12 | "autoClosingPairs": [ 13 | ["[", "]"], 14 | ["(", ")"], 15 | ["\"", "\""], 16 | ["'", "'"] 17 | ], 18 | // symbols that that can be used to surround a selection 19 | "surroundingPairs": [ 20 | ["[", "]"], 21 | ["(", ")"], 22 | ["\"", "\""], 23 | ["'", "'"] 24 | ] 25 | } -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | require('./client/rollup.config.js'), 3 | ...require('./server/rollup.config.js'), 4 | require('./vti/rollup.config.js') 5 | ]; 6 | -------------------------------------------------------------------------------- /scripts/build_grammar.ts: -------------------------------------------------------------------------------- 1 | import glob from 'glob'; 2 | import { load } from 'js-yaml'; 3 | import { writeFileSync, readFileSync } from 'fs'; 4 | import { parse } from 'path'; 5 | import { getGeneratedGrammar } from '../client/grammar'; 6 | 7 | glob('syntaxes/**/*.yaml', { nocase: true }, (_, files) => { 8 | for (const file of files) { 9 | const pathData = parse(file); 10 | writeFileSync( 11 | pathData.dir + '/' + pathData.name + '.tmLanguage.json', 12 | JSON.stringify(load(readFileSync(file).toString()), null, 2) 13 | ); 14 | } 15 | 16 | console.log('Built files:\n', JSON.stringify(files)); 17 | 18 | // get default custom blocks from package json 19 | const pJson = JSON.parse(readFileSync('package.json').toString()); 20 | const defaultCustomBlocks = pJson.contributes.configuration.properties['vetur.grammar.customBlocks'].default; 21 | const generatedGrammar = getGeneratedGrammar('syntaxes/vue.tmLanguage.json', defaultCustomBlocks); 22 | writeFileSync('syntaxes/vue-generated.json', generatedGrammar); 23 | console.log('Generated vue-generated.json'); 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.options.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "outDir": "../dist", 6 | "rootDir": ".." 7 | }, 8 | "references": [ 9 | { "path": "../client" } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | typings 4 | -------------------------------------------------------------------------------- /server/.mocharc.yml: -------------------------------------------------------------------------------- 1 | ui: tdd 2 | color: true 3 | require: 'source-map-support/register' 4 | spec: './dist-test/**/*.test.js' 5 | -------------------------------------------------------------------------------- /server/.npmrc: -------------------------------------------------------------------------------- 1 | message = "Vue Language Server %s" 2 | -------------------------------------------------------------------------------- /server/bin/vls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../dist/vueServerMain.js') 3 | -------------------------------------------------------------------------------- /server/src/log.ts: -------------------------------------------------------------------------------- 1 | const enum DEBUG_LEVEL { 2 | DEBUG = 0, 3 | INFO = 1 4 | } 5 | 6 | export const logger = { 7 | _level: DEBUG_LEVEL.INFO, 8 | 9 | setLevel(level: string) { 10 | if (level === 'DEBUG') { 11 | this._level = DEBUG_LEVEL.DEBUG; 12 | } else { 13 | this._level = DEBUG_LEVEL.INFO; 14 | } 15 | }, 16 | 17 | logDebug(msg: string) { 18 | if (this._level <= DEBUG_LEVEL.DEBUG) { 19 | console.log(`[DEBUG] ${msg}`); 20 | } 21 | }, 22 | logInfo(msg: string) { 23 | console.log(`[INFO ] ${msg}`); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /server/src/modes/nullMode.ts: -------------------------------------------------------------------------------- 1 | import { LanguageMode } from '../embeddedSupport/languageModes'; 2 | import { CompletionList } from 'vscode-languageserver-types'; 3 | 4 | export const NULL_HOVER = { 5 | contents: [] 6 | }; 7 | 8 | export const NULL_SIGNATURE = null; 9 | 10 | export const NULL_COMPLETION: CompletionList = { 11 | isIncomplete: false, 12 | items: [] 13 | }; 14 | 15 | export const nullMode: LanguageMode = { 16 | getId: () => '', 17 | onDocumentRemoved() {}, 18 | dispose() {}, 19 | doHover: () => NULL_HOVER, 20 | doComplete: () => NULL_COMPLETION, 21 | doSignatureHelp: () => NULL_SIGNATURE, 22 | findReferences: () => [] 23 | }; 24 | -------------------------------------------------------------------------------- /server/src/modes/pug/languageService.ts: -------------------------------------------------------------------------------- 1 | import lex, { Loc } from 'pug-lexer'; 2 | import { Position, Range } from 'vscode-languageserver-types'; 3 | 4 | export function findTokenAtPosition(code: string, position: Position): lex.Token | null { 5 | const tokens = lex(code); 6 | 7 | const oneBasedPos = Position.create(position.line + 1, position.character + 1); 8 | 9 | return ( 10 | tokens.find( 11 | ({ loc, type }) => 12 | loc.start.line <= oneBasedPos.line && 13 | loc.end.line >= oneBasedPos.line && 14 | loc.start.column <= oneBasedPos.character && 15 | loc.end.column > oneBasedPos.character && 16 | type !== 'newline' 17 | ) || null 18 | ); 19 | } 20 | 21 | export const locToRange = (loc: Loc): Range => ({ 22 | start: Position.create(loc.start.line - 1, loc.start.column - 1), 23 | end: Position.create(loc.end.line - 1, loc.end.column - 1) 24 | }); 25 | -------------------------------------------------------------------------------- /server/src/modes/style/emmet.ts: -------------------------------------------------------------------------------- 1 | export enum StylePriority { 2 | Emmet, 3 | Platform 4 | } 5 | -------------------------------------------------------------------------------- /server/src/modes/style/stylus/css-browser-data.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import { 7 | CSSDataV1, 8 | IPropertyData, 9 | IAtDirectiveData, 10 | IPseudoClassData, 11 | IPseudoElementData 12 | } from 'vscode-css-languageservice'; 13 | // @ts-ignore 14 | import CssData from 'vscode-web-custom-data/data/browsers.css-data.json'; 15 | 16 | export interface LoadedCSSData { 17 | properties: IPropertyData[]; 18 | atDirectives: IAtDirectiveData[]; 19 | pseudoClasses: IPseudoClassData[]; 20 | pseudoElements: IPseudoElementData[]; 21 | } 22 | 23 | const rawData = CssData as CSSDataV1; 24 | 25 | export const cssData: LoadedCSSData = { 26 | properties: rawData.properties || [], 27 | atDirectives: rawData.atDirectives || [], 28 | pseudoClasses: rawData.pseudoClasses || [], 29 | pseudoElements: rawData.pseudoElements || [] 30 | }; 31 | -------------------------------------------------------------------------------- /server/src/modes/style/stylus/stylus-hover.ts: -------------------------------------------------------------------------------- 1 | import { Position, Hover, Range } from 'vscode-languageserver-types'; 2 | import type { TextDocument } from 'vscode-languageserver-textdocument'; 3 | 4 | import { buildAst, findNodeAtPosition } from './parser'; 5 | 6 | import { cssData } from './css-browser-data'; 7 | import _ from 'lodash'; 8 | 9 | export function stylusHover(document: TextDocument, position: Position): Hover { 10 | const ast = buildAst(document.getText()); 11 | if (!ast) { 12 | return { 13 | contents: '' 14 | }; 15 | } 16 | const node = findNodeAtPosition(ast, position); 17 | if (!node) { 18 | return { 19 | contents: 'no node found!' 20 | }; 21 | } 22 | 23 | if (node.__type === 'Property') { 24 | const property = node.segments[0].name; 25 | const properties = cssData.properties; 26 | const item = _.find(properties, item => item.name === property); 27 | const lineno = node.lineno - 1; 28 | const column = node.column; 29 | return { 30 | contents: (item && item.description) || 'unknown property', 31 | range: Range.create(lineno, column, lineno, column + properties.length) 32 | }; 33 | } 34 | return { 35 | contents: [] 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /server/src/modes/style/stylus/stylus-supremacy.ts: -------------------------------------------------------------------------------- 1 | import { FormattingOptions } from 'stylus-supremacy'; 2 | 3 | export interface IStylusSupremacy { 4 | createFormattingOptions(options: any): FormattingOptions; 5 | createFormattingOptionsFromStylint(options: any): FormattingOptions; 6 | format(content: string, options: FormattingOptions): string; 7 | } 8 | -------------------------------------------------------------------------------- /server/src/modes/style/stylus/test/completion.test.ts: -------------------------------------------------------------------------------- 1 | import { CompletionTestSetup, testDSL } from '../../../test-util/completion-test-util'; 2 | 3 | import { provideCompletionItems } from '../completion-item'; 4 | 5 | const setup: CompletionTestSetup = { 6 | langId: 'stylus', 7 | docUri: 'test://test/test.styl', 8 | doComplete(doc, pos) { 9 | return provideCompletionItems(doc, pos); 10 | } 11 | }; 12 | 13 | const stylus = testDSL(setup); 14 | 15 | suite('Stylus Completion', () => { 16 | test('basic property', () => { 17 | stylus`back|`.has('background'); 18 | 19 | stylus`.back|`.hasNo('background'); 20 | 21 | stylus` 22 | .background 23 | back|`.has('background'); 24 | }); 25 | 26 | test('variable', () => { 27 | stylus` 28 | test-var = red 29 | .test-selector 30 | color te|`.has('test-var'); 31 | 32 | stylus` 33 | .test-selector 34 | test-var = red 35 | color test-var 36 | .another-var 37 | hehe te|`.hasNo('test-var'); 38 | 39 | stylus` 40 | test-var = red 41 | .test-selector 42 | te|`.hasNo('test-var'); 43 | 44 | stylus` 45 | test-func(n) 46 | background n 47 | .test-selector 48 | te|`.has('test-func'); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /server/src/modes/style/stylus/test/hover.test.ts: -------------------------------------------------------------------------------- 1 | import { hoverDSL } from '../../../test-util/hover-test-util'; 2 | 3 | import { stylusHover } from '../stylus-hover'; 4 | 5 | const stylus = hoverDSL({ 6 | langId: 'stylus', 7 | docUri: 'test://test/test.styl', 8 | doHover(doc, pos) { 9 | return stylusHover(doc, pos); 10 | } 11 | }); 12 | 13 | suite('Stylus Hover', () => { 14 | test('property hover', () => { 15 | stylus`.test 16 | cu|rsor pointer`.hasHoverAt('Allows control over cursor appearance in an element', 9); 17 | 18 | stylus`.test 19 | cu|rsor: pointer`.hasHoverAt('Allows control over cursor appearance in an element', 9); 20 | 21 | stylus`.test 22 | |cursor: pointer`.hasHoverAt('Allows control over cursor appearance in an element', 9); 23 | 24 | stylus`.test 25 | cursor|: pointer`.hasHoverAt('Allows control over cursor appearance in an element', 9); 26 | 27 | stylus`.test 28 | cursor: p|ointer`.hasNothing(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /server/src/modes/template-common/tagDefinition.ts: -------------------------------------------------------------------------------- 1 | import { Range, Location } from 'vscode-languageserver-types'; 2 | import { VueFileInfo } from '../../services/vueInfoService'; 3 | import { URI } from 'vscode-uri'; 4 | import { kebabCase } from 'lodash'; 5 | 6 | export function getTagDefinition(vueFileInfo: VueFileInfo, tag: string): Location[] { 7 | if (!vueFileInfo.componentInfo.childComponents) { 8 | return []; 9 | } 10 | 11 | const childComponent = vueFileInfo.componentInfo.childComponents.find( 12 | cc => !!cc.definition && [tag, tag.toLowerCase(), kebabCase(tag)].includes(cc.name) 13 | ); 14 | 15 | if (!childComponent) { 16 | return []; 17 | } 18 | 19 | const loc: Location = { 20 | uri: URI.file(childComponent.definition!.path).toString(), 21 | // TODO: Resolve actual default export range 22 | range: Range.create(0, 0, 0, 0) 23 | }; 24 | return [loc]; 25 | } 26 | -------------------------------------------------------------------------------- /server/src/modes/template/services/isInsideInterpolation.ts: -------------------------------------------------------------------------------- 1 | import { Node } from '../parser/htmlParser'; 2 | import { parse } from 'vue-eslint-parser'; 3 | 4 | const PARSER_PRE = ''; 6 | 7 | export function isInsideInterpolation(node: Node, nodeText: string, relativePos: number) { 8 | // Case {{ }} 9 | if (node.isInterpolation && relativePos >= '{{'.length && relativePos <= nodeText.length - '}}'.length) { 10 | return true; 11 | } 12 | 13 | // Case v-, : or @ directives 14 | const templateBody = parse(PARSER_PRE + nodeText + PARSER_POS, {}).templateBody; 15 | if (!templateBody) { 16 | return false; 17 | } 18 | 19 | const onlyChild = templateBody.children[0]; 20 | 21 | if (!onlyChild || onlyChild.type !== 'VElement') { 22 | return false; 23 | } 24 | 25 | if (!onlyChild.startTag || !onlyChild.range) { 26 | return false; 27 | } 28 | 29 | if (!isInsideRange(onlyChild.startTag)) { 30 | return false; 31 | } 32 | 33 | for (const a of onlyChild.startTag.attributes) { 34 | if (isInsideRange(a) && a.directive) { 35 | if (a.value) { 36 | return isInsideRange(a.value); 37 | } 38 | } 39 | } 40 | 41 | return false; 42 | 43 | function isInsideRange(node: { range: number[] }) { 44 | const [start, end] = node.range; 45 | 46 | return start - PARSER_PRE.length < relativePos && end - PARSER_PRE.length > relativePos; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /server/src/modes/template/tagProviders/nuxtTags.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import { getExternalTagProvider } from './externalTagProviders'; 3 | 4 | const NUXT_JSON_SOURCES = ['@nuxt/vue-app-edge', '@nuxt/vue-app', 'nuxt-helper-json']; 5 | 6 | export function getNuxtTagProvider(packageRoot: string) { 7 | let nuxtTags, nuxtAttributes; 8 | for (const source of NUXT_JSON_SOURCES) { 9 | if (tryResolve(join(source, 'package.json'), packageRoot)) { 10 | nuxtTags = tryRequire(join(source, 'vetur/nuxt-tags.json'), packageRoot); 11 | nuxtAttributes = tryRequire(join(source, 'vetur/nuxt-attributes.json'), packageRoot); 12 | if (nuxtTags) { 13 | break; 14 | } 15 | } 16 | } 17 | 18 | const componentsTags = tryRequire(join(packageRoot, '.nuxt/vetur/tags.json'), packageRoot); 19 | const componentsAttributes = tryRequire(join(packageRoot, '.nuxt/vetur/attributes.json'), packageRoot); 20 | 21 | return getExternalTagProvider( 22 | 'nuxt', 23 | { ...nuxtTags, ...componentsTags }, 24 | { ...nuxtAttributes, ...componentsAttributes } 25 | ); 26 | } 27 | 28 | function tryRequire(modulePath: string, findPath: string) { 29 | try { 30 | const resolved = tryResolve(modulePath, findPath); 31 | return resolved ? require(resolved) : undefined; 32 | } catch (_err) {} 33 | } 34 | 35 | function tryResolve(modulePath: string, findPath: string) { 36 | try { 37 | return require.resolve(modulePath, { 38 | paths: [findPath, __dirname] 39 | }); 40 | } catch (_err) {} 41 | } 42 | -------------------------------------------------------------------------------- /server/src/modes/template/test/emmet.test.ts: -------------------------------------------------------------------------------- 1 | import { CompletionTestSetup, testDSL } from '../../test-util/completion-test-util'; 2 | 3 | import { parseHTMLDocument } from '../parser/htmlParser'; 4 | import { doComplete } from '../services/htmlCompletion'; 5 | 6 | const setup: CompletionTestSetup = { 7 | langId: 'vue-html', 8 | docUri: 'test://test/test.html', 9 | doComplete(doc, pos) { 10 | const htmlDoc = parseHTMLDocument(doc); 11 | return doComplete(doc, pos, htmlDoc, [], {}); 12 | } 13 | }; 14 | 15 | const vueHtml = testDSL(setup); 16 | 17 | suite('Emmet Completion', () => { 18 | test('Emmet HTML Expansion', () => { 19 | vueHtml`ul>li*3|`.has(`ul>li*3`).become( 20 | `` 25 | ); 26 | 27 | vueHtml`{{ul>li*3|}}`.hasNo(`ul>li*3`); 28 | 29 | vueHtml`div+p|`.has(`div+p`).become( 30 | `
\${1}
31 |

\${0}

` 32 | ); 33 | }); 34 | 35 | vueHtml`#header|`.has(`#header`).become(``); 36 | }); 37 | -------------------------------------------------------------------------------- /server/src/modes/template/test/hover.test.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 'use strict'; 6 | 7 | import { parseHTMLDocument } from '../parser/htmlParser'; 8 | import { doHover } from '../services/htmlHover'; 9 | import { hoverDSL } from '../../test-util/hover-test-util'; 10 | import { allTagProviders } from '../tagProviders'; 11 | 12 | const html = hoverDSL({ 13 | docUri: 'test://test/test.html', 14 | langId: 'vue-html', 15 | doHover(document, position) { 16 | const htmlAST = parseHTMLDocument(document); 17 | return doHover(document, position, htmlAST, allTagProviders); 18 | } 19 | }); 20 | 21 | suite('HTML Hover', () => { 22 | test('Attribute', function () { 23 | // prettier-ignore 24 | html`
` 25 | .hasNothing(); 26 | // prettier-ignore 27 | html`` 28 | .hasHoverAt('treat inner content as its template rather than distributed content', 11); 29 | // prettier-ignore 30 | html`
` 31 | .hasHoverAt('Conditionally renders the element based on the truthy-ness of the expression value.\n\n[API Reference](https://vuejs.org/v2/api/#v-if)', 5); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/default.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/script/composition-js-vue2.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/script/composition-js.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/script/composition-ts-vue2.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/script/composition-ts.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/script/javascript.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/script/typescript.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/css-scoped.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/css.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/less-scoped.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/less.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/postcss-scoped.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/postcss.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/sass-scoped.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/sass.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/scss-scoped.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/scss.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/sss-scoped.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/sss.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/stylus-scoped.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/style/stylus.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/template/html.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/modes/vue/veturSnippets/template/pug.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/src/services/EnvironmentService.ts: -------------------------------------------------------------------------------- 1 | import { BasicComponentInfo, VLSConfig, VLSFullConfig } from '../config'; 2 | import { inferVueVersion, VueVersion } from '../utils/vueVersion'; 3 | 4 | export interface EnvironmentService { 5 | configure(config: VLSFullConfig): void; 6 | getConfig(): VLSFullConfig; 7 | getRootPathForConfig(): string; 8 | getProjectRoot(): string; 9 | getTsConfigPath(): string | undefined; 10 | getPackagePath(): string | undefined; 11 | getVueVersion(): VueVersion; 12 | getSnippetFolder(): string; 13 | getGlobalComponentInfos(): BasicComponentInfo[]; 14 | } 15 | 16 | export function createEnvironmentService( 17 | rootPathForConfig: string, 18 | projectPath: string, 19 | tsconfigPath: string | undefined, 20 | packagePath: string | undefined, 21 | snippetFolder: string, 22 | globalComponentInfos: BasicComponentInfo[], 23 | initialConfig: VLSConfig 24 | ): EnvironmentService { 25 | let $config = initialConfig; 26 | 27 | return { 28 | configure(config: VLSFullConfig) { 29 | $config = config; 30 | }, 31 | getConfig: () => $config, 32 | getRootPathForConfig: () => rootPathForConfig, 33 | getProjectRoot: () => projectPath, 34 | getTsConfigPath: () => tsconfigPath, 35 | getPackagePath: () => packagePath, 36 | getVueVersion: () => inferVueVersion(packagePath), 37 | getSnippetFolder: () => snippetFolder, 38 | getGlobalComponentInfos: () => globalComponentInfos 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /server/src/services/RefTokenService.ts: -------------------------------------------------------------------------------- 1 | import { Connection, Range } from 'vscode-languageserver'; 2 | 3 | export interface RefTokensService { 4 | send(uri: string, tokens: Range[]): void; 5 | } 6 | 7 | export function createRefTokensService(conn: Connection) { 8 | return { 9 | send(uri: string, tokens: Range[]) { 10 | conn.sendNotification('$/refTokens', { uri, tokens }); 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /server/src/services/documentService.ts: -------------------------------------------------------------------------------- 1 | import { Connection, TextDocuments } from 'vscode-languageserver'; 2 | import { TextDocument } from 'vscode-languageserver-textdocument'; 3 | 4 | /** 5 | * Service responsible for managing documents being syned through LSP 6 | * Todo - Switch to incremental sync 7 | */ 8 | export class DocumentService { 9 | private documents: TextDocuments; 10 | 11 | constructor(conn: Connection) { 12 | this.documents = new TextDocuments(TextDocument); 13 | this.documents.listen(conn); 14 | } 15 | 16 | getDocument(uri: string) { 17 | return this.documents.get(uri); 18 | } 19 | 20 | getAllDocuments() { 21 | return this.documents.all(); 22 | } 23 | 24 | get onDidChangeContent() { 25 | return this.documents.onDidChangeContent; 26 | } 27 | get onDidClose() { 28 | return this.documents.onDidClose; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /server/src/services/typescriptService/vueSys.ts: -------------------------------------------------------------------------------- 1 | import { parseVueScript } from './preprocess'; 2 | import type ts from 'typescript'; 3 | import { isVirtualVueFile } from './util'; 4 | import { RuntimeLibrary } from '../dependencyService'; 5 | 6 | export function getVueSys(tsModule: RuntimeLibrary['typescript'], scriptFileNameSet: Set) { 7 | /** 8 | * This part is only accessed by TS module resolution 9 | */ 10 | const vueSys: ts.System = { 11 | ...tsModule.sys, 12 | fileExists(path: string) { 13 | if (isVirtualVueFile(path, scriptFileNameSet)) { 14 | return tsModule.sys.fileExists(path.slice(0, -'.ts'.length)); 15 | } 16 | return tsModule.sys.fileExists(path); 17 | }, 18 | readFile(path, encoding) { 19 | if (isVirtualVueFile(path, scriptFileNameSet)) { 20 | const fileText = tsModule.sys.readFile(path.slice(0, -'.ts'.length), encoding); 21 | return fileText ? parseVueScript(fileText) : fileText; 22 | } 23 | const fileText = tsModule.sys.readFile(path, encoding); 24 | return fileText; 25 | } 26 | }; 27 | 28 | if (tsModule.sys.realpath) { 29 | const realpath = tsModule.sys.realpath; 30 | vueSys.realpath = function (path) { 31 | if (isVirtualVueFile(path, scriptFileNameSet)) { 32 | return realpath(path.slice(0, -'.ts'.length)) + '.ts'; 33 | } 34 | return realpath(path); 35 | }; 36 | } 37 | 38 | return vueSys; 39 | } 40 | -------------------------------------------------------------------------------- /server/src/typing.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-plugin-vue'; 2 | declare module 'parse-gitignore'; 3 | declare module '@prettier/plugin-pug'; 4 | declare module 'stylus'; 5 | -------------------------------------------------------------------------------- /server/src/utils/cancellationToken.ts: -------------------------------------------------------------------------------- 1 | import { RuntimeLibrary } from '../services/dependencyService'; 2 | import { CancellationToken as TSCancellationToken } from 'typescript'; 3 | import { CancellationTokenSource, CancellationToken as LSPCancellationToken } from 'vscode-languageserver'; 4 | 5 | export interface VCancellationToken extends LSPCancellationToken { 6 | tsToken: TSCancellationToken; 7 | } 8 | 9 | export class VCancellationTokenSource extends CancellationTokenSource { 10 | get token(): VCancellationToken { 11 | const token = super.token as VCancellationToken; 12 | token.tsToken = { 13 | isCancellationRequested() { 14 | return token.isCancellationRequested; 15 | }, 16 | throwIfCancellationRequested() { 17 | if (token.isCancellationRequested) { 18 | throw new Error('OperationCanceledException'); 19 | } 20 | } 21 | }; 22 | return token; 23 | } 24 | } 25 | 26 | export function isVCancellationRequested(token?: VCancellationToken) { 27 | return new Promise(resolve => { 28 | if (!token) { 29 | resolve(false); 30 | } else { 31 | setImmediate(() => resolve(token.isCancellationRequested)); 32 | } 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /server/src/utils/sleep.ts: -------------------------------------------------------------------------------- 1 | export function sleep(ms: number) { 2 | return new Promise(resolve => { 3 | setTimeout(resolve, ms); 4 | }); 5 | } 6 | -------------------------------------------------------------------------------- /server/src/utils/workspace.ts: -------------------------------------------------------------------------------- 1 | import ts from 'typescript'; 2 | 3 | export function findConfigFile(findPath: string, configName: string) { 4 | return ts.findConfigFile(findPath, ts.sys.fileExists, configName); 5 | } 6 | 7 | export function requireUncached(module: string) { 8 | delete require.cache[require.resolve(module)]; 9 | return require(module); 10 | } 11 | -------------------------------------------------------------------------------- /server/src/vueServerMain.ts: -------------------------------------------------------------------------------- 1 | import { createConnection, InitializeParams, InitializeResult } from 'vscode-languageserver/node'; 2 | import { VLS } from './services/vls'; 3 | 4 | const connection = process.argv.length <= 2 ? createConnection(process.stdin, process.stdout) : createConnection(); 5 | 6 | console.log = (...args: any[]) => connection.console.log(args.join(' ')); 7 | console.error = (...args: any[]) => connection.console.error(args.join(' ')); 8 | 9 | const vls = new VLS(connection); 10 | connection.onInitialize( 11 | async (params: InitializeParams): Promise => { 12 | await vls.init(params); 13 | 14 | console.log('Vetur initialized'); 15 | 16 | return { 17 | capabilities: vls.capabilities 18 | }; 19 | } 20 | ); 21 | 22 | vls.listen(); 23 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.options.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "incremental": true, 6 | "outDir": "./dist", 7 | "tsBuildInfoFile": "./typings/tsconfig.tsbuildinfo", 8 | "rootDir": "src", 9 | 10 | "lib": ["es2015", "es2016.array.include"], 11 | // Most classes in VLS are asynchronously initialized 12 | "strictPropertyInitialization": false 13 | }, 14 | "include": [ 15 | "src" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /server/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./dist-test", 5 | "tsBuildInfoFile": "./dist-test/tsconfig.tsbuildinfo", 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /syntaxes/markdown-vue.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "markdown.vue.codeblock", 3 | "fileTypes": [], 4 | "injectionSelector": "L:text.html.markdown", 5 | "patterns": [ 6 | { 7 | "include": "#vue-code-block" 8 | } 9 | ], 10 | "repository": { 11 | "vue-code-block": { 12 | "begin": "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(vue)(\\s+[^`~]*)?$)", 13 | "name": "markup.fenced_code.block.markdown", 14 | "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", 15 | "beginCaptures": { 16 | "3": { 17 | "name": "punctuation.definition.markdown" 18 | }, 19 | "5": { 20 | "name": "fenced_code.block.language" 21 | }, 22 | "6": { 23 | "name": "fenced_code.block.language.attributes" 24 | } 25 | }, 26 | "endCaptures": { 27 | "3": { 28 | "name": "punctuation.definition.markdown" 29 | } 30 | }, 31 | "patterns": [ 32 | { 33 | "begin": "(^|\\G)(\\s*)(.*)", 34 | "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", 35 | "contentName": "meta.embedded.block.vue", 36 | "patterns": [ 37 | { 38 | "include": "source.vue" 39 | } 40 | ] 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /syntaxes/pug/directives.YAML: -------------------------------------------------------------------------------- 1 | # [PackageDev] target_format: plist, ext: tmLanguage 2 | scopeName: vue.pug.directives 3 | injectionSelector: "L:meta.tag.other -text.html.vue-html" 4 | patterns: 5 | - include: 'source.vue#vue-directives' 6 | -------------------------------------------------------------------------------- /syntaxes/pug/directives.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "vue.pug.directives", 3 | "injectionSelector": "L:meta.tag.other -text.html.vue-html", 4 | "patterns": [ 5 | { 6 | "include": "source.vue#vue-directives" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /syntaxes/pug/interpolations.YAML: -------------------------------------------------------------------------------- 1 | # [PackageDev] target_format: plist, ext: tmLanguage 2 | scopeName: vue.pug.interpolations 3 | injectionSelector: "L:text.pug" 4 | patterns: 5 | - include: source.vue#vue-interpolations 6 | -------------------------------------------------------------------------------- /syntaxes/pug/interpolations.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "vue.pug.interpolations", 3 | "injectionSelector": "L:text.pug", 4 | "patterns": [ 5 | { 6 | "include": "source.vue#vue-interpolations" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /test/componentData/data-dir/User/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "update.mode": "none" 3 | } 4 | -------------------------------------------------------------------------------- /test/componentData/features/beforeAll/beforeAll.test.ts: -------------------------------------------------------------------------------- 1 | import { activateLS } from '../../../editorHelper'; 2 | 3 | before(async () => { 4 | await activateLS(); 5 | }); 6 | -------------------------------------------------------------------------------- /test/componentData/fixture/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "vetur.experimental.templateInterpolationService": true 3 | } 4 | -------------------------------------------------------------------------------- /test/componentData/fixture/attributes.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo-tag/error": { 3 | "description": "Custom error" 4 | }, 5 | "foo-tag/foo-attr": { 6 | "description": "An foo-attr description" 7 | }, 8 | "handle-foo": { 9 | "type": "event", 10 | "documentation": "You gotta handle foo" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/componentData/fixture/beforeAll.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/componentData/fixture/completion/Element.vue: -------------------------------------------------------------------------------- 1 |