Skip to content

Commit

Permalink
simplify default compiler options logic
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonlyu123 committed Aug 20, 2024
1 parent 1395cfb commit 6dac14e
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 97 deletions.
144 changes: 47 additions & 97 deletions packages/language-server/src/plugins/typescript/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ async function createLanguageService(
function getParsedConfig() {
let compilerOptions: ts.CompilerOptions;
let parsedConfig: ts.ParsedCommandLine;
let extendedConfigPaths: Set<string>;
let extendedConfigPaths: Set<string> | undefined;

if (tsconfigPath) {
const info = ensureTsConfigInfoUpToDate(tsconfigPath);
Expand All @@ -683,12 +683,11 @@ async function createLanguageService(
}
compilerOptions = info.parsedCommandLine.options;
parsedConfig = info.parsedCommandLine;
extendedConfigPaths = info.extendedConfigPaths ?? new Set();
extendedConfigPaths = info.extendedConfigPaths;
} else {
const config = parseDefaultCompilerOptions();
compilerOptions = config.compilerOptions;
parsedConfig = config.parsedConfig;
extendedConfigPaths = config.extendedConfigPaths;
}

if (
Expand Down Expand Up @@ -739,105 +738,30 @@ async function createLanguageService(
}

function parseDefaultCompilerOptions() {
const forcedCompilerOptions: ts.CompilerOptions = {
allowNonTsExtensions: true,
target: ts.ScriptTarget.Latest,
allowJs: true,
noEmit: true,
declaration: false,
skipLibCheck: true
};

// always let ts parse config to get default compilerOption
let configJson =
(tsconfigPath && ts.readConfigFile(tsconfigPath, tsSystem.readFile).config) ||
getDefaultJsConfig();

// Only default exclude when no extends for now
if (!configJson.extends) {
configJson = Object.assign(
{
exclude: getDefaultExclude()
},
configJson
);
}

const { cacheMonitorProxy, extendedConfigPaths } = monitorExtendedConfig();

const parsedConfig = ts.parseJsonConfigFileContent(
configJson,
tsSystem,
workspacePath,
forcedCompilerOptions,
tsconfigPath,
undefined,
getExtraExtensions(),
cacheMonitorProxy
);

const compilerOptions: ts.CompilerOptions = {
...parsedConfig.options,
...forcedCompilerOptions
};

return { compilerOptions, parsedConfig, extendedConfigPaths };
}

function monitorExtendedConfig() {
const extendedConfigPaths = new Set<string>();
const { extendedConfigCache } = docContext;
const cacheMonitorProxy = {
...docContext.extendedConfigCache,
get(key: string) {
extendedConfigPaths.add(key);
return extendedConfigCache.get(key);
},
has(key: string) {
extendedConfigPaths.add(key);
return extendedConfigCache.has(key);
},
set(key: string, value: ts.ExtendedConfigCacheEntry) {
extendedConfigPaths.add(key);
return extendedConfigCache.set(key, value);
}
};
return { cacheMonitorProxy, extendedConfigPaths };
}

function getExtraExtensions(): readonly ts.FileExtensionInfo[] | undefined {
return [
{
extension: 'svelte',
isMixedContent: true,
// Deferred was added in a later TS version, fall back to tsx
// If Deferred exists, this means that all Svelte files are included
// in parsedConfig.fileNames
scriptKind: ts.ScriptKind.Deferred ?? ts.ScriptKind.TS
}
];
}

/**
* This should only be used when there's no jsconfig/tsconfig at all
*/
function getDefaultJsConfig(): {
compilerOptions: ts.CompilerOptions;
include: string[];
} {
return {
let configJson = {
compilerOptions: {
allowJs: true,
noEmit: true,
declaration: false,
skipLibCheck: true,
maxNodeModuleJsDepth: 2,
allowSyntheticDefaultImports: true
},
// Necessary to not flood the initial files
// with potentially completely unrelated .ts/.js files:
include: []
};
}

function getDefaultExclude() {
return ['node_modules', ...ignoredBuildDirectories];
const parsedConfig = ts.parseJsonConfigFileContent(configJson, tsSystem, workspacePath);

const compilerOptions: ts.CompilerOptions = {
...parsedConfig.options,
target: ts.ScriptTarget.Latest,
allowNonTsExtensions: true,
moduleResolution: ts.ModuleResolutionKind.Node10
};

return { compilerOptions, parsedConfig };
}

/**
Expand Down Expand Up @@ -874,10 +798,10 @@ async function createLanguageService(
}

function watchConfigFiles(
extendedConfigPaths: Set<string>,
extendedConfigPaths: Set<string> | undefined,
parsedCommandLine: ts.ParsedCommandLine
) {
const tsconfigDependencies = Array.from(extendedConfigPaths).concat(
const tsconfigDependencies = Array.from(extendedConfigPaths ?? []).concat(
parsedCommandLine.projectReferences?.map((r) => r.path) ?? []
);
tsconfigDependencies.forEach((configPath) => {
Expand Down Expand Up @@ -1074,7 +998,24 @@ async function createLanguageService(

const json = ts.parseJsonText(configFilePath, content);

const { cacheMonitorProxy, extendedConfigPaths } = monitorExtendedConfig();
const extendedConfigPaths = new Set<string>();
const { extendedConfigCache } = docContext;
const cacheMonitorProxy = {
...docContext.extendedConfigCache,
get(key: string) {
extendedConfigPaths.add(key);
return extendedConfigCache.get(key);
},
has(key: string) {
extendedConfigPaths.add(key);
return extendedConfigCache.has(key);
},
set(key: string, value: ts.ExtendedConfigCacheEntry) {
extendedConfigPaths.add(key);
return extendedConfigCache.set(key, value);
}
};

// TypeScript will throw if the parsedCommandLine doesn't include the sourceFile for the config file
// i.e. it must be directly parse from the json text instead of a javascript object like we do in getParsedConfig
const parsedCommandLine = ts.parseJsonSourceFileConfigFileContent(
Expand All @@ -1084,7 +1025,16 @@ async function createLanguageService(
/*existingOptions*/ undefined,
configFilePath,
/*resolutionStack*/ undefined,
getExtraExtensions(),
[
{
extension: 'svelte',
isMixedContent: true,
// Deferred was added in a later TS version, fall back to tsx
// If Deferred exists, this means that all Svelte files are included
// in parsedConfig.fileNames
scriptKind: ts.ScriptKind.Deferred ?? ts.ScriptKind.TS
}
],
cacheMonitorProxy
);

Expand Down
25 changes: 25 additions & 0 deletions packages/language-server/test/plugins/typescript/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ describe('service', () => {
});
});

it('can loads default tsconfig', async () => {
const dirPath = getRandomVirtualDirPath(testDir);
const { lsDocumentContext, rootUris } = setup();

const ls = await getService(
path.join(dirPath, 'random.svelte'),
rootUris,
lsDocumentContext
);

assert.deepStrictEqual(ls.compilerOptions, <ts.CompilerOptions>{
allowJs: true,
allowSyntheticDefaultImports: true,
allowNonTsExtensions: true,
configFilePath: undefined,
declaration: false,
maxNodeModuleJsDepth: 2,
module: ts.ModuleKind.ESNext,
moduleResolution: ts.ModuleResolutionKind.Node10,
noEmit: true,
skipLibCheck: true,
target: ts.ScriptTarget.ESNext
});
});

it('patch release document so dispose do not throw', async () => {
// testing this because the patch rely on ts implementation details
// and we want to be aware of the changes
Expand Down

0 comments on commit 6dac14e

Please sign in to comment.