Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Known TS Plugin integration regressions #3912

Closed
8 tasks done
johnsoncodehk opened this issue Mar 1, 2024 · 0 comments
Closed
8 tasks done

Known TS Plugin integration regressions #3912

johnsoncodehk opened this issue Mar 1, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@johnsoncodehk
Copy link
Member

johnsoncodehk commented Mar 1, 2024

  • When modifying the script block lang attr, an internal error occurs in the tsserver due to the script kind change in the .vue file. This may need to wait for TypeScript to fix it. Fixed by Ensure correct script kind and text when using cached sourceFile from scriptInfo microsoft/TypeScript#57641
  • Vue Language Server's semantic tokens (component tag) and tsserver's semantic tokens cannot coexist. refactor(language-service): re-implement component tag semantic tokens in TypeScript plugin #3915
  • When multiple tsservers are started (perhaps due to opening multiple IDEs or multiple workspaces), the Vue language server can only communicate with the last started tsserver. feat(typescript-plugin): define named pipe unique file name based on pid #3916
  • fix(language-service): wait for tsserver to be ready when requesting auto insert .value #3914
  • The following code should to TS Plugin refactor(language-service): re-implement auto-import patching in TypeScript plugin #3917
    async provideCompletionItems(document, position, completeContext, item) {
    const result = await baseInstance.provideCompletionItems?.(document, position, completeContext, item);
    if (result) {
    // filter __VLS_
    result.items = result.items.filter(item =>
    item.label.indexOf('__VLS_') === -1
    && (!item.labelDetails?.description || item.labelDetails.description.indexOf('__VLS_') === -1)
    );
    // handle component auto-import patch
    let casing: Awaited<ReturnType<typeof getNameCasing>> | undefined;
    const [virtualCode, sourceFile] = context.documents.getVirtualCodeByUri(document.uri);
    if (virtualCode && sourceFile) {
    for (const map of context.documents.getMaps(virtualCode)) {
    const sourceVirtualFile = context.language.files.get(map.sourceDocument.uri)?.generated?.code;
    if (sourceVirtualFile instanceof VueGeneratedCode) {
    const isAutoImport = !!map.getSourcePosition(position, data => typeof data.completion === 'object' && !!data.completion.onlyImport);
    if (isAutoImport) {
    for (const item of result.items) {
    item.data.__isComponentAutoImport = true;
    }
    // fix #2458
    casing ??= await getNameCasing(context, sourceFile.id);
    if (casing.tag === TagNameCasing.Kebab) {
    for (const item of result.items) {
    item.filterText = hyphenateTag(item.filterText ?? item.label);
    }
    }
    }
    }
    }
    }
    }
    return result;
    },
    async resolveCompletionItem(item, token) {
    item = await baseInstance.resolveCompletionItem?.(item, token) ?? item;
    const itemData = item.data as { uri?: string; } | undefined;
    let newName: string | undefined;
    for (const ext of getVueOptions(context.env).extensions) {
    const suffix = capitalize(ext.substring('.'.length)); // .vue -> Vue
    if (
    itemData?.uri
    && item.textEdit?.newText.endsWith(suffix)
    && item.additionalTextEdits?.length === 1 && item.additionalTextEdits[0].newText.indexOf('import ' + item.textEdit.newText + ' from ') >= 0
    && (await context.env.getConfiguration?.<boolean>('vue.complete.normalizeComponentImportName') ?? true)
    ) {
    newName = item.textEdit.newText.slice(0, -suffix.length);
    newName = newName[0].toUpperCase() + newName.substring(1);
    if (newName === 'Index') {
    const tsItem = (item.data as Data).originalItem;
    if (tsItem.source) {
    const dirs = tsItem.source.split('/');
    if (dirs.length >= 3) {
    newName = dirs[dirs.length - 2];
    newName = newName[0].toUpperCase() + newName.substring(1);
    }
    }
    }
    item.additionalTextEdits[0].newText = item.additionalTextEdits[0].newText.replace(
    'import ' + item.textEdit.newText + ' from ',
    'import ' + newName + ' from ',
    );
    item.textEdit.newText = newName;
    const [_, sourceFile] = context.documents.getVirtualCodeByUri(itemData.uri);
    if (sourceFile) {
    const casing = await getNameCasing(context, sourceFile.id);
    if (casing.tag === TagNameCasing.Kebab) {
    item.textEdit.newText = hyphenateTag(item.textEdit.newText);
    }
    }
    }
    else if (item.textEdit?.newText && new RegExp(`import \\w*${suffix}\\$1 from [\\S\\s]*`).test(item.textEdit.newText)) {
    // https://github.com/vuejs/language-tools/issues/2286
    item.textEdit.newText = item.textEdit.newText.replace(`${suffix}$1`, '$1');
    }
    }
    const data: Data = item.data;
    if (item.data?.__isComponentAutoImport && data && item.additionalTextEdits?.length && item.textEdit && itemData?.uri) {
    const [virtualCode, sourceFile] = context.documents.getVirtualCodeByUri(itemData.uri);
    if (virtualCode && (sourceFile.generated?.code instanceof VueGeneratedCode)) {
    const script = sourceFile.generated.languagePlugin.typescript?.getScript(sourceFile.generated.code);
    if (script) {
    const ast = getAst(sourceFile.generated.code.fileName, script.code.snapshot, script.scriptKind);
    const exportDefault = scriptRanges.parseScriptRanges(ts, ast, false, true).exportDefault;
    if (exportDefault) {
    const componentName = newName ?? item.textEdit.newText;
    const optionEdit = createAddComponentToOptionEdit(ts, ast, componentName);
    if (optionEdit) {
    const textDoc = context.documents.get(context.documents.getVirtualCodeUri(sourceFile.id, virtualCode.id), virtualCode.languageId, virtualCode.snapshot);
    item.additionalTextEdits.push({
    range: {
    start: textDoc.positionAt(optionEdit.range.start),
    end: textDoc.positionAt(optionEdit.range.end),
    },
    newText: optionEdit.newText,
    });
    }
    }
    }
    }
    }
    return item;
    },
    async provideCodeActions(document, range, context, token) {
    const result = await baseInstance.provideCodeActions?.(document, range, context, token);
    return result?.filter(codeAction => codeAction.title.indexOf('__VLS_') === -1);
    },
    async provideSemanticDiagnostics(document, token) {
    const result = await baseInstance.provideSemanticDiagnostics?.(document, token);
    return result?.map(diagnostic => {
    if (
    diagnostic.source === 'ts'
    && diagnostic.code === 2578 /* Unused '@ts-expect-error' directive. */
    && document.getText(diagnostic.range) === '// @ts-expect-error __VLS_TS_EXPECT_ERROR'
    ) {
    diagnostic.source = 'vue';
    diagnostic.code = 'ts-2578';
    diagnostic.message = diagnostic.message.replace(/@ts-expect-error/g, '@vue-expect-error');
    }
    return diagnostic;
    });
    },
  • Plugin API v2 refactor(language-core): plugin api v2 #3918
  • jsconfig/tsconfig is required False positive errors at end-of-file #3942 External bug: [Vue TS Plugin] Modifications to InferredProject's language service were discarded microsoft/TypeScript#57630
  • VSCode 1.88.0 is required Vue server still crashed after upgrading to v2.0.4 in VSCode + Nuxt 3 #3962
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant