Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/language-core/lib/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function createPlugins(pluginContext: Parameters<VueLanguagePlugin>[0]) {
useMdFilePlugin,
useHtmlFilePlugin,
vueRootTagsPlugin,
vueTsx,
vueScriptJsPlugin,
vueStyleCss,
vueTemplateHtmlPlugin,
Expand All @@ -31,7 +32,6 @@ export function createPlugins(pluginContext: Parameters<VueLanguagePlugin>[0]) {
vueSfcCustomBlocks,
vueSfcScriptsFormat,
vueSfcTemplate,
vueTsx,
...pluginContext.vueCompilerOptions.plugins,
];

Expand Down
2 changes: 1 addition & 1 deletion packages/language-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export function createVueLanguageServicePlugins(
createVueGlobalTypesErrorPlugin(),
createVueScopedClassLinksPlugin(),
createVueSfcPlugin(),
createVueSuggestDefineAssignmentPlugin(),
createVueTemplateRefLinksPlugin(),
createEmmetPlugin({
mappedLanguages: {
Expand All @@ -61,6 +60,7 @@ export function createVueLanguageServicePlugins(
}),

// TS related plugins
createVueSuggestDefineAssignmentPlugin(ts),
createTypeScriptDocCommentTemplatePlugin(ts),
createTypeScriptSyntacticPlugin(ts),
createVueInlayHintsPlugin(ts),
Expand Down
55 changes: 28 additions & 27 deletions packages/language-service/lib/plugins/vue-autoinsert-dotvalue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function create(
if (sourceOffset < startTagEnd || sourceOffset > endTagStart) {
continue;
}
if (isBlacklistNode(ts, ast, sourceOffset - startTagEnd, false)) {
if (shouldSkip(ts, ast, sourceOffset - startTagEnd, false)) {
return;
}
}
Expand Down Expand Up @@ -86,7 +86,7 @@ function isCharacterTyping(document: TextDocument, change: { text: string; range
return charReg.test(lastCharacter) && !charReg.test(nextCharacter);
}

function isBlacklistNode(ts: typeof import('typescript'), node: ts.Node, pos: number, allowAccessDotValue: boolean) {
function shouldSkip(ts: typeof import('typescript'), node: ts.Node, pos: number, allowAccessDotValue: boolean) {
if (ts.isVariableDeclaration(node) && pos >= node.name.getFullStart() && pos <= node.name.getEnd()) {
return true;
}
Expand Down Expand Up @@ -123,47 +123,48 @@ function isBlacklistNode(ts: typeof import('typescript'), node: ts.Node, pos: nu
ts.isCallExpression(node)
&& ts.isIdentifier(node.expression)
&& isWatchOrUseFunction(node.expression.text)
&& isTopLevelArgOrArrayTopLevelItemItem(node)
&& isTopLevelArgOrArrayTopLevelItemItem(ts, node, pos)
) {
return true;
}
else {
let _isBlacklistNode = false;
let _shouldSkip = false;
node.forEachChild(node => {
if (_isBlacklistNode) {
if (_shouldSkip) {
return;
}
if (pos >= node.getFullStart() && pos <= node.getEnd()) {
if (isBlacklistNode(ts, node, pos, allowAccessDotValue)) {
_isBlacklistNode = true;
if (shouldSkip(ts, node, pos, allowAccessDotValue)) {
_shouldSkip = true;
}
}
});
return _isBlacklistNode;
return _shouldSkip;
}
}

function isWatchOrUseFunction(fnName: string) {
return fnName === 'watch'
|| fnName === 'unref'
|| fnName === 'triggerRef'
|| fnName === 'isRef'
|| hyphenateAttr(fnName).startsWith('use-');
}
function isTopLevelArgOrArrayTopLevelItemItem(node: ts.CallExpression) {
for (const arg of node.arguments) {
if (pos >= arg.getFullStart() && pos <= arg.getEnd()) {
if (ts.isIdentifier(arg)) {
return true;
}
if (ts.isArrayLiteralExpression(arg)) {
for (const el of arg.elements) {
if (pos >= el.getFullStart() && pos <= el.getEnd()) {
return ts.isIdentifier(el);
}
function isWatchOrUseFunction(fnName: string) {
return fnName === 'watch'
|| fnName === 'unref'
|| fnName === 'triggerRef'
|| fnName === 'isRef'
|| hyphenateAttr(fnName).startsWith('use-');
}

function isTopLevelArgOrArrayTopLevelItemItem(ts: typeof import('typescript'), node: ts.CallExpression, pos: number) {
for (const arg of node.arguments) {
if (pos >= arg.getFullStart() && pos <= arg.getEnd()) {
if (ts.isIdentifier(arg)) {
return true;
}
if (ts.isArrayLiteralExpression(arg)) {
for (const el of arg.elements) {
if (pos >= el.getFullStart() && pos <= el.getEnd()) {
return ts.isIdentifier(el);
}
}
return false;
}
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import type { CompletionItem, CompletionItemKind, LanguageServicePlugin } from '@volar/language-service';
import type { CompletionItem, CompletionItemKind, LanguageServicePlugin, TextDocument } from '@volar/language-service';
import { type TextRange, tsCodegen } from '@vue/language-core';
import type * as ts from 'typescript';
import { URI } from 'vscode-uri';
import { resolveEmbeddedCode } from '../utils';

export function create(): LanguageServicePlugin {
const documentToSourceFile = new WeakMap<TextDocument, ts.SourceFile>();

export function create(ts: typeof import('typescript')): LanguageServicePlugin {
return {
name: 'vue-suggest-define-assignment',
capabilities: {
Expand All @@ -11,7 +15,7 @@ export function create(): LanguageServicePlugin {
create(context) {
return {
isAdditionalCompletion: true,
async provideCompletionItems(document) {
async provideCompletionItems(document, position) {
const info = resolveEmbeddedCode(context, document.uri);
if (!info?.code.id.startsWith('script_')) {
return;
Expand All @@ -30,6 +34,11 @@ export function create(): LanguageServicePlugin {
return;
}

const sourceFile = getSourceFile(ts, document);
if (shouldSkip(ts, sourceFile, document.offsetAt(position))) {
return;
}

const result: CompletionItem[] = [];
const mappings = [...context.language.maps.forEach(info.code)];

Expand Down Expand Up @@ -93,3 +102,39 @@ export function create(): LanguageServicePlugin {
},
};
}

function shouldSkip(ts: typeof import('typescript'), node: ts.Node, pos: number) {
if (ts.isStringLiteral(node) && pos >= node.getFullStart() && pos <= node.getEnd()) {
return true;
}
else if (ts.isTemplateLiteral(node) && pos >= node.getFullStart() && pos <= node.getEnd()) {
return true;
}
else {
let _shouldSkip = false;
node.forEachChild(node => {
if (_shouldSkip) {
return;
}
if (pos >= node.getFullStart() && pos <= node.getEnd()) {
if (shouldSkip(ts, node, pos)) {
_shouldSkip = true;
}
}
});
return _shouldSkip;
}
}

function getSourceFile(ts: typeof import('typescript'), document: TextDocument): ts.SourceFile {
let sourceFile = documentToSourceFile.get(document);
if (!sourceFile) {
sourceFile = ts.createSourceFile(
URI.parse(document.uri).path,
document.getText(),
ts.ScriptTarget.Latest,
);
documentToSourceFile.set(document, sourceFile);
}
return sourceFile;
}
Loading