mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-08 02:46:15 -05:00
tsconfig.json mixed content support
This commit is contained in:
@@ -90,6 +90,7 @@ namespace ts.server {
|
||||
export interface HostConfiguration {
|
||||
formatCodeOptions: FormatCodeSettings;
|
||||
hostInfo: string;
|
||||
fileExtensionMap?: FileExtensionMap;
|
||||
}
|
||||
|
||||
interface ConfigFileConversionResult {
|
||||
@@ -114,13 +115,13 @@ namespace ts.server {
|
||||
interface FilePropertyReader<T> {
|
||||
getFileName(f: T): string;
|
||||
getScriptKind(f: T): ScriptKind;
|
||||
hasMixedContent(f: T): boolean;
|
||||
hasMixedContent(f: T, mixedContentExtensions: string[]): boolean;
|
||||
}
|
||||
|
||||
const fileNamePropertyReader: FilePropertyReader<string> = {
|
||||
getFileName: x => x,
|
||||
getScriptKind: _ => undefined,
|
||||
hasMixedContent: _ => false
|
||||
hasMixedContent: (fileName, mixedContentExtensions) => forEach(mixedContentExtensions, extension => fileExtensionIs(fileName, extension))
|
||||
};
|
||||
|
||||
const externalFilePropertyReader: FilePropertyReader<protocol.ExternalFile> = {
|
||||
@@ -235,12 +236,12 @@ namespace ts.server {
|
||||
private readonly directoryWatchers: DirectoryWatchers;
|
||||
private readonly throttledOperations: ThrottledOperations;
|
||||
|
||||
private readonly hostConfiguration: HostConfiguration;
|
||||
|
||||
private changedFiles: ScriptInfo[];
|
||||
|
||||
private toCanonicalFileName: (f: string) => string;
|
||||
|
||||
public readonly hostConfiguration: HostConfiguration;
|
||||
|
||||
public lastDeletedFile: ScriptInfo;
|
||||
|
||||
constructor(public readonly host: ServerHost,
|
||||
@@ -264,7 +265,8 @@ namespace ts.server {
|
||||
|
||||
this.hostConfiguration = {
|
||||
formatCodeOptions: getDefaultFormatCodeSettings(this.host),
|
||||
hostInfo: "Unknown host"
|
||||
hostInfo: "Unknown host",
|
||||
fileExtensionMap: {}
|
||||
};
|
||||
|
||||
this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames, host.getCurrentDirectory());
|
||||
@@ -455,7 +457,7 @@ namespace ts.server {
|
||||
// If a change was made inside "folder/file", node will trigger the callback twice:
|
||||
// one with the fileName being "folder/file", and the other one with "folder".
|
||||
// We don't respond to the second one.
|
||||
if (fileName && !ts.isSupportedSourceFileName(fileName, project.getCompilerOptions())) {
|
||||
if (fileName && !ts.isSupportedSourceFileName(fileName, project.getCompilerOptions(), this.hostConfiguration.fileExtensionMap)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -610,6 +612,9 @@ namespace ts.server {
|
||||
let projectsToRemove: Project[];
|
||||
for (const p of info.containingProjects) {
|
||||
if (p.projectKind === ProjectKind.Configured) {
|
||||
if (info.hasMixedContent) {
|
||||
info.hasChanges = true;
|
||||
}
|
||||
// last open file in configured project - close it
|
||||
if ((<ConfiguredProject>p).deleteOpenRef() === 0) {
|
||||
(projectsToRemove || (projectsToRemove = [])).push(p);
|
||||
@@ -772,7 +777,9 @@ namespace ts.server {
|
||||
this.host,
|
||||
getDirectoryPath(configFilename),
|
||||
/*existingOptions*/ {},
|
||||
configFilename);
|
||||
configFilename,
|
||||
/*resolutionStack*/ [],
|
||||
this.hostConfiguration.fileExtensionMap);
|
||||
|
||||
if (parsedCommandLine.errors.length) {
|
||||
errors = concatenate(errors, parsedCommandLine.errors);
|
||||
@@ -876,7 +883,7 @@ namespace ts.server {
|
||||
for (const f of files) {
|
||||
const rootFilename = propertyReader.getFileName(f);
|
||||
const scriptKind = propertyReader.getScriptKind(f);
|
||||
const hasMixedContent = propertyReader.hasMixedContent(f);
|
||||
const hasMixedContent = propertyReader.hasMixedContent(f, this.hostConfiguration.fileExtensionMap.mixedContent);
|
||||
if (this.host.fileExists(rootFilename)) {
|
||||
const info = this.getOrCreateScriptInfoForNormalizedPath(toNormalizedPath(rootFilename), /*openedByClient*/ clientFileName == rootFilename, /*fileContent*/ undefined, scriptKind, hasMixedContent);
|
||||
project.addRoot(info);
|
||||
@@ -922,7 +929,7 @@ namespace ts.server {
|
||||
rootFilesChanged = true;
|
||||
if (!scriptInfo) {
|
||||
const scriptKind = propertyReader.getScriptKind(f);
|
||||
const hasMixedContent = propertyReader.hasMixedContent(f);
|
||||
const hasMixedContent = propertyReader.hasMixedContent(f, this.hostConfiguration.fileExtensionMap.mixedContent);
|
||||
scriptInfo = this.getOrCreateScriptInfoForNormalizedPath(normalizedPath, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent);
|
||||
}
|
||||
}
|
||||
@@ -1072,6 +1079,9 @@ namespace ts.server {
|
||||
}
|
||||
if (openedByClient) {
|
||||
info.isOpen = true;
|
||||
if (hasMixedContent) {
|
||||
info.hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
@@ -1103,6 +1113,10 @@ namespace ts.server {
|
||||
mergeMaps(this.hostConfiguration.formatCodeOptions, convertFormatOptions(args.formatOptions));
|
||||
this.logger.info("Format host information updated");
|
||||
}
|
||||
if (args.fileExtensionMap) {
|
||||
this.hostConfiguration.fileExtensionMap = args.fileExtensionMap;
|
||||
this.logger.info("Host file extension mappings updated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1168,12 +1182,12 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean): OpenConfiguredProjectResult {
|
||||
const info = this.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent);
|
||||
const { configFileName = undefined, configFileErrors = undefined }: OpenConfiguredProjectResult = this.findContainingExternalProject(fileName)
|
||||
? {}
|
||||
: this.openOrUpdateConfiguredProjectForFile(fileName);
|
||||
|
||||
// at this point if file is the part of some configured/external project then this project should be created
|
||||
const info = this.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent);
|
||||
this.assignScriptInfoToInferredProjectIfNecessary(info, /*addToListOfOpenFiles*/ true);
|
||||
this.printProjects();
|
||||
return { configFileName, configFileErrors };
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
namespace ts.server {
|
||||
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost, ServerLanguageServiceHost {
|
||||
private compilationSettings: ts.CompilerOptions;
|
||||
private fileExtensionMap: FileExtensionMap;
|
||||
private readonly resolvedModuleNames= createFileMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
private readonly resolvedTypeReferenceDirectives = createFileMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
|
||||
private readonly getCanonicalFileName: (fileName: string) => string;
|
||||
@@ -143,6 +144,10 @@ namespace ts.server {
|
||||
return this.compilationSettings;
|
||||
}
|
||||
|
||||
getFileExtensionMap() {
|
||||
return this.fileExtensionMap;
|
||||
}
|
||||
|
||||
useCaseSensitiveFileNames() {
|
||||
return this.host.useCaseSensitiveFileNames;
|
||||
}
|
||||
@@ -231,5 +236,9 @@ namespace ts.server {
|
||||
}
|
||||
this.compilationSettings = opt;
|
||||
}
|
||||
|
||||
setFileExtensionMap(fileExtensionMap: FileExtensionMap) {
|
||||
this.fileExtensionMap = fileExtensionMap || {};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="..\services\services.ts" />
|
||||
/// <reference path="utilities.ts"/>
|
||||
/// <reference path="scriptInfo.ts"/>
|
||||
/// <reference path="lsHost.ts"/>
|
||||
@@ -202,6 +202,7 @@ namespace ts.server {
|
||||
enableLanguageService() {
|
||||
const lsHost = new LSHost(this.projectService.host, this, this.projectService.cancellationToken);
|
||||
lsHost.setCompilationSettings(this.compilerOptions);
|
||||
lsHost.setFileExtensionMap(this.projectService.hostConfiguration.fileExtensionMap);
|
||||
this.languageService = ts.createLanguageService(lsHost, this.documentRegistry);
|
||||
|
||||
this.lsHost = lsHost;
|
||||
@@ -462,6 +463,10 @@ namespace ts.server {
|
||||
return !hasChanges;
|
||||
}
|
||||
|
||||
private hasChangedFiles() {
|
||||
return this.rootFiles && forEach(this.rootFiles, info => info.hasChanges);
|
||||
}
|
||||
|
||||
private setTypings(typings: SortedReadonlyArray<string>): boolean {
|
||||
if (arrayIsEqualTo(this.typingFiles, typings)) {
|
||||
return false;
|
||||
@@ -475,7 +480,7 @@ namespace ts.server {
|
||||
const oldProgram = this.program;
|
||||
this.program = this.languageService.getProgram();
|
||||
|
||||
let hasChanges = false;
|
||||
let hasChanges = this.hasChangedFiles();
|
||||
// bump up the version if
|
||||
// - oldProgram is not set - this is a first time updateGraph is called
|
||||
// - newProgram is different from the old program and structure of the old program was not reused.
|
||||
@@ -578,6 +583,7 @@ namespace ts.server {
|
||||
|
||||
const added: string[] = [];
|
||||
const removed: string[] = [];
|
||||
const updated = this.rootFiles.filter(info => info.hasChanges).map(info => info.fileName);
|
||||
for (const id in currentFiles) {
|
||||
if (!hasProperty(lastReportedFileNames, id)) {
|
||||
added.push(id);
|
||||
@@ -588,9 +594,12 @@ namespace ts.server {
|
||||
removed.push(id);
|
||||
}
|
||||
}
|
||||
for (const root of this.rootFiles) {
|
||||
root.hasChanges = false;
|
||||
}
|
||||
this.lastReportedFileNames = currentFiles;
|
||||
this.lastReportedVersion = this.projectStructureVersion;
|
||||
return { info, changes: { added, removed }, projectErrors: this.projectErrors };
|
||||
return { info, changes: { added, removed, updated }, projectErrors: this.projectErrors };
|
||||
}
|
||||
else {
|
||||
// unknown version - return everything
|
||||
|
||||
@@ -914,6 +914,10 @@ namespace ts.server.protocol {
|
||||
* List of removed files
|
||||
*/
|
||||
removed: string[];
|
||||
/**
|
||||
* List of updated files
|
||||
*/
|
||||
updated: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -986,6 +990,11 @@ namespace ts.server.protocol {
|
||||
* The format options to use during formatting and other code editing features.
|
||||
*/
|
||||
formatOptions?: FormatCodeSettings;
|
||||
|
||||
/**
|
||||
* The host's supported file extension mappings
|
||||
*/
|
||||
fileExtensionMap?: FileExtensionMap;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,6 @@ namespace ts.server {
|
||||
private fileWatcher: FileWatcher;
|
||||
private svc: ScriptVersionCache;
|
||||
|
||||
// TODO: allow to update hasMixedContent from the outside
|
||||
constructor(
|
||||
private readonly host: ServerHost,
|
||||
readonly fileName: NormalizedPath,
|
||||
@@ -29,6 +28,8 @@ namespace ts.server {
|
||||
: getScriptKindFromFileName(fileName);
|
||||
}
|
||||
|
||||
public hasChanges = false;
|
||||
|
||||
getFormatCodeSettings() {
|
||||
return this.formatCodeSettings;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="types.d.ts" />
|
||||
/// <reference path="types.d.ts" />
|
||||
/// <reference path="shared.ts" />
|
||||
|
||||
namespace ts.server {
|
||||
@@ -211,6 +211,7 @@ namespace ts.server {
|
||||
|
||||
export interface ServerLanguageServiceHost {
|
||||
setCompilationSettings(options: CompilerOptions): void;
|
||||
setFileExtensionMap(fileExtensionMap: FileExtensionMap): void;
|
||||
notifyFileRemoved(info: ScriptInfo): void;
|
||||
startRecordingFilesWithChangedResolutions(): void;
|
||||
finishRecordingFilesWithChangedResolutions(): Path[];
|
||||
@@ -218,6 +219,7 @@ namespace ts.server {
|
||||
|
||||
export const nullLanguageServiceHost: ServerLanguageServiceHost = {
|
||||
setCompilationSettings: () => undefined,
|
||||
setFileExtensionMap: () => undefined,
|
||||
notifyFileRemoved: () => undefined,
|
||||
startRecordingFilesWithChangedResolutions: () => undefined,
|
||||
finishRecordingFilesWithChangedResolutions: () => undefined
|
||||
|
||||
Reference in New Issue
Block a user