Skip to content

Commit

Permalink
fix(language-core): prevent append globalTypes to virtual file (#4806)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiyuanzmj authored Sep 4, 2024
1 parent 5c7e153 commit e3f8b91
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 99 deletions.
9 changes: 3 additions & 6 deletions packages/component-meta/lib/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function createCheckerByJsonConfigBase(
rootDir = rootDir.replace(windowsPathReg, '/');
return baseCreate(
ts,
() => vue.createParsedCommandLineByJson(ts, ts.sys, rootDir, json),
() => vue.createParsedCommandLineByJson(ts, ts.sys, rootDir, json, undefined, true),
checkerOptions,
rootDir,
path.join(rootDir, 'jsconfig.json.global.vue')
Expand All @@ -44,7 +44,7 @@ export function createCheckerBase(
tsconfig = tsconfig.replace(windowsPathReg, '/');
return baseCreate(
ts,
() => vue.createParsedCommandLine(ts, ts.sys, tsconfig),
() => vue.createParsedCommandLine(ts, ts.sys, tsconfig, true),
checkerOptions,
path.dirname(tsconfig),
tsconfig + '.global.vue'
Expand Down Expand Up @@ -86,10 +86,7 @@ export function baseCreate(
const vueLanguagePlugin = vue.createVueLanguagePlugin<string>(
ts,
projectHost.getCompilationSettings(),
{
...commandLine.vueOptions,
__setupedGlobalTypes: () => true,
},
commandLine.vueOptions,
id => id
);
const language = vue.createLanguage(
Expand Down
4 changes: 2 additions & 2 deletions packages/language-core/lib/codegen/script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export interface ScriptCodegenOptions {
export function* generateScript(options: ScriptCodegenOptions): Generator<Code, ScriptCodegenContext> {
const ctx = createScriptCodegenContext(options);

if (options.vueCompilerOptions.__setupedGlobalTypes?.()) {
if (options.vueCompilerOptions.__setupedGlobalTypes) {
yield `/// <reference types=".vue-global-types/${options.vueCompilerOptions.lib}_${options.vueCompilerOptions.target}_${options.vueCompilerOptions.strictTemplates}.d.ts" />${newLine}`;
}
else {
Expand Down Expand Up @@ -151,7 +151,7 @@ export function* generateScript(options: ScriptCodegenOptions): Generator<Code,
yield `type __VLS_IntrinsicElementsCompletion = __VLS_IntrinsicElements${endOfLine}`;
}
yield* ctx.localTypes.generate([...ctx.localTypes.getUsedNames()]);
if (!options.vueCompilerOptions.__setupedGlobalTypes?.()) {
if (!options.vueCompilerOptions.__setupedGlobalTypes) {
yield generateGlobalTypes('local', options.vueCompilerOptions.lib, options.vueCompilerOptions.target, options.vueCompilerOptions.strictTemplates);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/language-core/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export interface VueCompilerOptions {
experimentalModelPropName: Record<string, Record<string, boolean | Record<string, string> | Record<string, string>[]>>;

// internal
__setupedGlobalTypes?: () => boolean;
__setupedGlobalTypes?: boolean;
__test?: boolean;
}

Expand Down
48 changes: 45 additions & 3 deletions packages/language-core/lib/utils/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ import type * as ts from 'typescript';
import * as path from 'path-browserify';
import type { RawVueCompilerOptions, VueCompilerOptions, VueLanguagePlugin } from '../types';
import { getAllExtensions } from '../languagePlugin';
import { generateGlobalTypes } from '../codegen/globalTypes';

export type ParsedCommandLine = ts.ParsedCommandLine & {
vueOptions: VueCompilerOptions;
};

export function createParsedCommandLineByJson(
ts: typeof import('typescript'),
parseConfigHost: ts.ParseConfigHost,
parseConfigHost: ts.ParseConfigHost & {
writeFile?(path: string, data: string): void;
},
rootDir: string,
json: any,
configFileName = rootDir + '/jsconfig.json'
configFileName = rootDir + '/jsconfig.json',
skipGlobalTypesSetup = false
): ParsedCommandLine {

const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost);
Expand All @@ -31,6 +35,12 @@ export function createParsedCommandLineByJson(
}

const resolvedVueOptions = resolveVueCompilerOptions(vueOptions);
if (skipGlobalTypesSetup) {
resolvedVueOptions.__setupedGlobalTypes = true;
}
else {
resolvedVueOptions.__setupedGlobalTypes = setupGlobalTypes(rootDir, resolvedVueOptions, parseConfigHost);
}
const parsed = ts.parseJsonConfigFileContent(
json,
proxyHost.host,
Expand Down Expand Up @@ -60,7 +70,8 @@ export function createParsedCommandLineByJson(
export function createParsedCommandLine(
ts: typeof import('typescript'),
parseConfigHost: ts.ParseConfigHost,
tsConfigPath: string
tsConfigPath: string,
skipGlobalTypesSetup = false
): ParsedCommandLine {
try {
const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost);
Expand All @@ -79,6 +90,12 @@ export function createParsedCommandLine(
}

const resolvedVueOptions = resolveVueCompilerOptions(vueOptions);
if (skipGlobalTypesSetup) {
resolvedVueOptions.__setupedGlobalTypes = true;
}
else {
resolvedVueOptions.__setupedGlobalTypes = setupGlobalTypes(path.dirname(tsConfigPath), resolvedVueOptions, parseConfigHost);
}
const parsed = ts.parseJsonSourceFileConfigFileContent(
config,
proxyHost.host,
Expand Down Expand Up @@ -260,3 +277,28 @@ export function resolveVueCompilerOptions(vueOptions: Partial<VueCompilerOptions
).map(([k, v]) => [camelize(k), v])),
};
}

export function setupGlobalTypes(rootDir: string, vueOptions: VueCompilerOptions, host: {
fileExists(path: string): boolean;
writeFile?(path: string, data: string): void;
}) {
if (!host.writeFile) {
return false;
}
try {
let dir = rootDir;
while (!host.fileExists(path.resolve(dir, `node_modules/${vueOptions.lib}/package.json`))) {
const parentDir = path.resolve(dir, '..');
if (dir === parentDir) {
throw 0;
}
dir = parentDir;
}
const globalTypesPath = path.resolve(dir, `node_modules/.vue-global-types/${vueOptions.lib}_${vueOptions.target}_${vueOptions.strictTemplates}.d.ts`);
const globalTypesContents = generateGlobalTypes('global', vueOptions.lib, vueOptions.target, vueOptions.strictTemplates);
host.writeFile(globalTypesPath, globalTypesContents);
return true;
} catch {
return false;
}
}
9 changes: 3 additions & 6 deletions packages/language-server/lib/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export function initialize(
let compilerOptions: ts.CompilerOptions;
let vueCompilerOptions: VueCompilerOptions;
if (configFileName) {
let commandLine = createParsedCommandLine(ts, sys, configFileName);
let commandLine = createParsedCommandLine(ts, sys, configFileName, true);
let sysVersion = sys.version;
let newSysVersion = await sys.sync();
while (sysVersion !== newSysVersion) {
commandLine = createParsedCommandLine(ts, sys, configFileName);
commandLine = createParsedCommandLine(ts, sys, configFileName, true);
sysVersion = newSysVersion;
newSysVersion = await sys.sync();
}
Expand All @@ -44,10 +44,7 @@ export function initialize(
createVueLanguagePlugin(
ts,
compilerOptions,
{
...vueCompilerOptions,
__setupedGlobalTypes: () => true,
},
vueCompilerOptions,
s => uriConverter.asFileName(s)
),
],
Expand Down
24 changes: 1 addition & 23 deletions packages/tsc/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { runTsc } from '@volar/typescript/lib/quickstart/runTsc';
import * as path from 'path';
import * as vue from '@vue/language-core';

const windowsPathReg = /\\/g;
Expand All @@ -22,31 +21,10 @@ export function run(tscPath = require.resolve('typescript/lib/tsc')) {
runExtensions.length === allExtensions.length
&& runExtensions.every(ext => allExtensions.includes(ext))
) {
let setupedGlobalTypes = false;
try {
let dir = typeof configFilePath === 'string'
? configFilePath
: options.host?.getCurrentDirectory() ?? ts.sys.getCurrentDirectory();
while (!ts.sys.directoryExists(path.resolve(dir, 'node_modules'))) {
const parentDir = path.resolve(dir, '..');
if (dir === parentDir) {
throw 0;
}
dir = parentDir;
}
const globalTypesPath = path.resolve(dir, `node_modules/.vue-global-types/${vueOptions.lib}_${vueOptions.target}_${vueOptions.strictTemplates}.d.ts`);
const globalTypesContents = vue.generateGlobalTypes('global', vueOptions.lib, vueOptions.target, vueOptions.strictTemplates);
ts.sys.writeFile(globalTypesPath, globalTypesContents);
setupedGlobalTypes = true;
} catch { }

const vueLanguagePlugin = vue.createVueLanguagePlugin<string>(
ts,
options.options,
{
...vueOptions,
__setupedGlobalTypes: () => setupedGlobalTypes,
},
vueOptions,
id => id
);
return { languagePlugins: [vueLanguagePlugin] };
Expand Down
26 changes: 3 additions & 23 deletions packages/tsc/tests/dts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,18 @@ describe('vue-tsc-dts', () => {
};

let vueOptions: vue.VueCompilerOptions;

const createProgram = proxyCreateProgram(ts, ts.createProgram, (ts, options) => {
const { configFilePath } = options.options;

vueOptions = typeof configFilePath === 'string'
? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/')).vueOptions
: vue.resolveVueCompilerOptions({ extensions: ['.vue', '.cext'] });

let setupedGlobalTypes = false;

try {
let dir = typeof configFilePath === 'string'
? configFilePath
: options.host?.getCurrentDirectory() ?? ts.sys.getCurrentDirectory();
while (!ts.sys.directoryExists(path.resolve(dir, 'node_modules'))) {
const parentDir = path.resolve(dir, '..');
if (dir === parentDir) {
throw 0;
}
dir = parentDir;
}
const globalTypesPath = path.resolve(dir, `node_modules/.vue-global-types/${vueOptions.lib}_${vueOptions.target}_${vueOptions.strictTemplates}.d.ts`);
const globalTypesContents = vue.generateGlobalTypes('global', vueOptions.lib, vueOptions.target, vueOptions.strictTemplates);
ts.sys.writeFile(globalTypesPath, globalTypesContents);
setupedGlobalTypes = true;
} catch { }

const vueLanguagePlugin = vue.createVueLanguagePlugin<string>(
ts,
options.options,
{
...vueOptions,
__setupedGlobalTypes: () => setupedGlobalTypes,
},
vueOptions,
id => id
);
return [vueLanguagePlugin];
Expand Down
37 changes: 2 additions & 35 deletions packages/typescript-plugin/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import { createLanguageServicePlugin } from '@volar/typescript/lib/quickstart/createLanguageServicePlugin';
import * as path from 'path';
import * as vue from '@vue/language-core';
import { proxyLanguageServiceForVue } from './lib/common';
import { startNamedPipeServer } from './lib/server';
import type * as ts from 'typescript';

const windowsPathReg = /\\/g;
const vueCompilerOptions = new WeakMap<ts.server.Project, vue.VueCompilerOptions>();
const setupedProjects = new WeakSet<ts.server.Project>();

const basePlugin = createLanguageServicePlugin(
const plugin = createLanguageServicePlugin(
(ts, info) => {
const vueOptions = getVueCompilerOptions();
const languagePlugin = vue.createVueLanguagePlugin<string>(
ts,
info.languageServiceHost.getCompilationSettings(),
{
...vueOptions,
__setupedGlobalTypes: () => setupedProjects.has(info.project),
},
vueOptions,
id => id
);

Expand Down Expand Up @@ -56,32 +50,5 @@ const basePlugin = createLanguageServicePlugin(
}
}
);
const plugin: ts.server.PluginModuleFactory = mods => {
const pluginModule = basePlugin(mods);

return {
...pluginModule,
getExternalFiles(proj, updateLevel = 0) {
const options = vueCompilerOptions.get(proj);
if (updateLevel >= 1 && options) {
try {
let dir = proj.getCurrentDirectory();
while (!proj.directoryExists(path.resolve(dir, 'node_modules'))) {
const parentDir = path.resolve(dir, '..');
if (dir === parentDir) {
throw 0;
}
dir = parentDir;
}
const globalTypesPath = path.resolve(dir, `node_modules/.vue-global-types/${options.lib}_${options.target}_${options.strictTemplates}.d.ts`);
const globalTypesContents = vue.generateGlobalTypes('global', options.lib, options.target, options.strictTemplates);
proj.writeFile(globalTypesPath, globalTypesContents);
setupedProjects.add(proj);
} catch { }
}
return pluginModule.getExternalFiles?.(proj, updateLevel) ?? [];
},
};
};

export = plugin;

0 comments on commit e3f8b91

Please sign in to comment.