Merge branch 'master' into lazyConfiguredProjectsFromExternalProject
This commit is contained in:
commit
52fef42baa
|
@ -370,7 +370,9 @@ namespace ts {
|
|||
finally {
|
||||
cancellationToken = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getLocalTypeParametersOfClassOrInterfaceOrTypeAlias,
|
||||
};
|
||||
|
||||
function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, isForSignatureHelp: boolean): Signature | undefined {
|
||||
|
@ -1208,17 +1210,23 @@ namespace ts {
|
|||
// local types not visible outside the function body
|
||||
: false;
|
||||
}
|
||||
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.FunctionScopedVariable) {
|
||||
// parameters are visible only inside function body, parameter list and return type
|
||||
// technically for parameter list case here we might mix parameters and variables declared in function,
|
||||
// however it is detected separately when checking initializers of parameters
|
||||
// to make sure that they reference no variables declared after them.
|
||||
useResult =
|
||||
if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.Variable) {
|
||||
// parameter initializer will lookup as normal variable scope when targeting es2015+
|
||||
if (compilerOptions.target && compilerOptions.target >= ScriptTarget.ES2015 && isParameter(lastLocation) && result.valueDeclaration !== lastLocation) {
|
||||
useResult = false;
|
||||
}
|
||||
else if (result.flags & SymbolFlags.FunctionScopedVariable) {
|
||||
// parameters are visible only inside function body, parameter list and return type
|
||||
// technically for parameter list case here we might mix parameters and variables declared in function,
|
||||
// however it is detected separately when checking initializers of parameters
|
||||
// to make sure that they reference no variables declared after them.
|
||||
useResult =
|
||||
lastLocation.kind === SyntaxKind.Parameter ||
|
||||
(
|
||||
lastLocation === (<FunctionLikeDeclaration>location).type &&
|
||||
!!findAncestor(result.valueDeclaration, isParameter)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (location.kind === SyntaxKind.ConditionalType) {
|
||||
|
@ -2280,8 +2288,6 @@ namespace ts {
|
|||
return getPackagesSet().has(getTypesPackageName(packageName));
|
||||
}
|
||||
|
||||
// An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
|
||||
// and an external module with no 'export =' declaration resolves to the module itself.
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol;
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined;
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol {
|
||||
|
@ -3920,13 +3926,22 @@ namespace ts {
|
|||
const links = getSymbolLinks(symbol);
|
||||
let specifier = links.specifierCache && links.specifierCache.get(contextFile.path);
|
||||
if (!specifier) {
|
||||
specifier = moduleSpecifiers.getModuleSpecifierForDeclarationFile(
|
||||
const isBundle = (compilerOptions.out || compilerOptions.outFile);
|
||||
// For declaration bundles, we need to generate absolute paths relative to the common source dir for imports,
|
||||
// just like how the declaration emitter does for the ambient module declarations - we can easily accomplish this
|
||||
// using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative
|
||||
// specifier preference
|
||||
const { moduleResolverHost } = context.tracker;
|
||||
const specifierCompilerOptions = isBundle ? { ...compilerOptions, baseUrl: moduleResolverHost.getCommonSourceDirectory() } : compilerOptions;
|
||||
specifier = first(first(moduleSpecifiers.getModuleSpecifiers(
|
||||
symbol,
|
||||
compilerOptions,
|
||||
specifierCompilerOptions,
|
||||
contextFile,
|
||||
context.tracker.moduleResolverHost,
|
||||
moduleResolverHost,
|
||||
host.getSourceFiles(),
|
||||
{ importModuleSpecifierPreference: isBundle ? "non-relative" : "relative" },
|
||||
host.redirectTargetsMap,
|
||||
);
|
||||
)));
|
||||
links.specifierCache = links.specifierCache || createMap();
|
||||
links.specifierCache.set(contextFile.path, specifier);
|
||||
}
|
||||
|
|
|
@ -815,10 +815,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
function getOptionNameMap(): OptionNameMap {
|
||||
if (optionNameMapCache) {
|
||||
return optionNameMapCache;
|
||||
}
|
||||
return optionNameMapCache || (optionNameMapCache = createOptionNameMap(optionDeclarations));
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function createOptionNameMap(optionDeclarations: ReadonlyArray<CommandLineOption>): OptionNameMap {
|
||||
const optionNameMap = createMap<CommandLineOption>();
|
||||
const shortOptionNames = createMap<string>();
|
||||
forEach(optionDeclarations, option => {
|
||||
|
@ -828,8 +829,7 @@ namespace ts {
|
|||
}
|
||||
});
|
||||
|
||||
optionNameMapCache = { optionNameMap, shortOptionNames };
|
||||
return optionNameMapCache;
|
||||
return { optionNameMap, shortOptionNames };
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -979,7 +979,12 @@ namespace ts {
|
|||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
|
||||
return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
optionName = optionName.toLowerCase();
|
||||
const { optionNameMap, shortOptionNames } = getOptionNameMap();
|
||||
// Try to translate short option names to their full equivalents.
|
||||
|
|
|
@ -2896,6 +2896,11 @@
|
|||
"category": "Error",
|
||||
"code": 5071
|
||||
},
|
||||
"Unknown build option '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 5072
|
||||
},
|
||||
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
|
|
|
@ -1,8 +1,52 @@
|
|||
// Used by importFixes, getEditsForFileRename, and declaration emit to synthesize import module specifiers.
|
||||
/* @internal */
|
||||
namespace ts.moduleSpecifiers {
|
||||
export interface ModuleSpecifierPreferences {
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
const enum RelativePreference { Relative, NonRelative, Auto }
|
||||
// See UserPreferences#importPathEnding
|
||||
const enum Ending { Minimal, Index, JsExtension }
|
||||
|
||||
// Processed preferences
|
||||
interface Preferences {
|
||||
readonly relativePreference: RelativePreference;
|
||||
readonly ending: Ending;
|
||||
}
|
||||
|
||||
function getPreferences({ importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, compilerOptions: CompilerOptions, importingSourceFile: SourceFile): Preferences {
|
||||
return {
|
||||
relativePreference: importModuleSpecifierPreference === "relative" ? RelativePreference.Relative : importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative : RelativePreference.Auto,
|
||||
ending: getEnding(),
|
||||
};
|
||||
function getEnding(): Ending {
|
||||
switch (importModuleSpecifierEnding) {
|
||||
case "minimal": return Ending.Minimal;
|
||||
case "index": return Ending.Index;
|
||||
case "js": return Ending.JsExtension;
|
||||
default: return usesJsExtensionOnImports(importingSourceFile) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs ? Ending.Index : Ending.Minimal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string): Preferences {
|
||||
return {
|
||||
relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative,
|
||||
ending: hasJavaScriptOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateModuleSpecifier(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFileName: Path,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
oldImportSpecifier: string,
|
||||
): string | undefined {
|
||||
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferencesForUpdate(compilerOptions, oldImportSpecifier));
|
||||
if (res === oldImportSpecifier) return undefined;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Note: importingSourceFile is just for usesJsExtensionOnImports
|
||||
|
@ -13,35 +57,25 @@ namespace ts.moduleSpecifiers {
|
|||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
preferences: ModuleSpecifierPreferences = {},
|
||||
preferences: UserPreferences = {},
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
): string {
|
||||
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
return firstDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions)) ||
|
||||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
|
||||
return getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferences(preferences, compilerOptions, importingSourceFile));
|
||||
}
|
||||
|
||||
export function getModuleSpecifierForDeclarationFile(
|
||||
moduleSymbol: Symbol,
|
||||
function getModuleSpecifierWorker(
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: SourceFile,
|
||||
importingSourceFileName: Path,
|
||||
toFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
preferences: Preferences
|
||||
): string {
|
||||
const isBundle = (compilerOptions.out || compilerOptions.outFile);
|
||||
if (isBundle && host.getCommonSourceDirectory) {
|
||||
// For declaration bundles, we need to generate absolute paths relative to the common source dir for imports,
|
||||
// just like how the declaration emitter does for the ambient module declarations - we can easily accomplish this
|
||||
// using the `baseUrl` compiler option (which we would otherwise never use in declaration emit) and a non-relative
|
||||
// specifier preference
|
||||
compilerOptions = {
|
||||
...compilerOptions,
|
||||
baseUrl: host.getCommonSourceDirectory(),
|
||||
};
|
||||
}
|
||||
const preferences: ModuleSpecifierPreferences = { importModuleSpecifierPreference: isBundle ? "non-relative" : "relative" };
|
||||
return first(first(getModuleSpecifiers(moduleSymbol, compilerOptions, importingSourceFile, host, host.getSourceFiles ? host.getSourceFiles() : [importingSourceFile], preferences, redirectTargetsMap)));
|
||||
const info = getInfo(importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
return firstDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions)) ||
|
||||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
|
||||
}
|
||||
|
||||
// For each symlink/original for a module, returns a list of ways to import that file.
|
||||
|
@ -51,60 +85,39 @@ namespace ts.moduleSpecifiers {
|
|||
importingSourceFile: SourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
files: ReadonlyArray<SourceFile>,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
userPreferences: UserPreferences,
|
||||
redirectTargetsMap: RedirectTargetsMap,
|
||||
): ReadonlyArray<ReadonlyArray<string>> {
|
||||
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
|
||||
if (ambient) return [[ambient]];
|
||||
|
||||
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFile.path, host);
|
||||
if (!files) {
|
||||
return Debug.fail("Files list must be present to resolve symlinks in specifier resolution");
|
||||
}
|
||||
const info = getInfo(importingSourceFile.path, host);
|
||||
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration || getNonAugmentationDeclaration(moduleSymbol));
|
||||
const modulePaths = getAllModulePaths(files, importingSourceFile.path, moduleSourceFile.fileName, info.getCanonicalFileName, host, redirectTargetsMap);
|
||||
|
||||
const global = mapDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions));
|
||||
const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile);
|
||||
const global = mapDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions));
|
||||
return global.length ? global.map(g => [g]) : modulePaths.map(moduleFileName =>
|
||||
getLocalModuleSpecifiers(moduleFileName, info, compilerOptions, preferences));
|
||||
}
|
||||
|
||||
interface Info {
|
||||
readonly moduleResolutionKind: ModuleResolutionKind;
|
||||
readonly addJsExtension: boolean;
|
||||
readonly getCanonicalFileName: GetCanonicalFileName;
|
||||
readonly sourceDirectory: Path;
|
||||
}
|
||||
// importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path
|
||||
function getInfo(compilerOptions: CompilerOptions, importingSourceFile: SourceFile, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
|
||||
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
|
||||
const addJsExtension = usesJsExtensionOnImports(importingSourceFile);
|
||||
function getInfo(importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true);
|
||||
const sourceDirectory = getDirectoryPath(importingSourceFileName);
|
||||
return { moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory };
|
||||
return { getCanonicalFileName, sourceDirectory };
|
||||
}
|
||||
|
||||
function getGlobalModuleSpecifier(
|
||||
moduleFileName: string,
|
||||
{ addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
compilerOptions: CompilerOptions,
|
||||
) {
|
||||
return tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension)
|
||||
|| tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory);
|
||||
}
|
||||
|
||||
function getLocalModuleSpecifiers(
|
||||
moduleFileName: string,
|
||||
{ moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
compilerOptions: CompilerOptions,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
): ReadonlyArray<string> {
|
||||
function getLocalModuleSpecifiers(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, compilerOptions: CompilerOptions, { ending, relativePreference }: Preferences): ReadonlyArray<string> {
|
||||
const { baseUrl, paths, rootDirs } = compilerOptions;
|
||||
|
||||
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) ||
|
||||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
|
||||
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
|
||||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions);
|
||||
if (!baseUrl || relativePreference === RelativePreference.Relative) {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
|
@ -113,7 +126,7 @@ namespace ts.moduleSpecifiers {
|
|||
return [relativePath];
|
||||
}
|
||||
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, moduleResolutionKind, addJsExtension);
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions);
|
||||
if (paths) {
|
||||
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
|
||||
if (fromPaths) {
|
||||
|
@ -121,11 +134,11 @@ namespace ts.moduleSpecifiers {
|
|||
}
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference === "non-relative") {
|
||||
if (relativePreference === RelativePreference.NonRelative) {
|
||||
return [importRelativeToBaseUrl];
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference !== undefined) Debug.assertNever(preferences.importModuleSpecifierPreference);
|
||||
if (relativePreference !== RelativePreference.Auto) Debug.assertNever(relativePreference);
|
||||
|
||||
if (isPathRelativeToParent(relativeToBaseUrl)) {
|
||||
return [relativePath];
|
||||
|
@ -164,7 +177,7 @@ namespace ts.moduleSpecifiers {
|
|||
}
|
||||
|
||||
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJavaScriptOrJsonFileExtension(text) : undefined) || false;
|
||||
}
|
||||
|
||||
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
|
||||
|
@ -283,37 +296,8 @@ namespace ts.moduleSpecifiers {
|
|||
return removeFileExtension(relativePath);
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromTypeRoots(
|
||||
options: CompilerOptions,
|
||||
host: GetEffectiveTypeRootsHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
moduleFileName: string,
|
||||
addJsExtension: boolean,
|
||||
): string | undefined {
|
||||
const roots = getEffectiveTypeRoots(options, host);
|
||||
return firstDefined(roots, unNormalizedTypeRoot => {
|
||||
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
|
||||
if (startsWith(moduleFileName, typeRoot)) {
|
||||
// For a type definition, we can strip `/index` even with classic resolution.
|
||||
return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), ModuleResolutionKind.NodeJs, addJsExtension);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(
|
||||
options: CompilerOptions,
|
||||
moduleFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
sourceDirectory: Path,
|
||||
): string | undefined {
|
||||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
|
||||
// nothing to do here
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, host: ModuleSpecifierResolutionHost, options: CompilerOptions): string | undefined {
|
||||
const parts: NodeModulePathParts = getNodeModulePathParts(moduleFileName)!;
|
||||
|
||||
if (!parts) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -325,8 +309,12 @@ namespace ts.moduleSpecifiers {
|
|||
// Get a path that's relative to node_modules or the importing file's path
|
||||
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
|
||||
if (!startsWith(sourceDirectory, getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex)))) return undefined;
|
||||
|
||||
// If the module was found in @types, get the actual Node package name
|
||||
return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
|
||||
const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
|
||||
const packageName = getPackageNameFromAtTypesDirectory(nodeModulesDirectoryName);
|
||||
// For classic resolution, only allow importing from node_modules/@types, not other node_modules
|
||||
return getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs && packageName === nodeModulesDirectoryName ? undefined : packageName;
|
||||
|
||||
function getDirectoryOrExtensionlessFileName(path: string): string {
|
||||
// If the file is the main module, it can be imported by the package name
|
||||
|
@ -440,13 +428,35 @@ namespace ts.moduleSpecifiers {
|
|||
});
|
||||
}
|
||||
|
||||
function removeExtensionAndIndexPostFix(fileName: string, moduleResolutionKind: ModuleResolutionKind, addJsExtension: boolean): string {
|
||||
function removeExtensionAndIndexPostFix(fileName: string, ending: Ending, options: CompilerOptions): string {
|
||||
const noExtension = removeFileExtension(fileName);
|
||||
return addJsExtension
|
||||
? noExtension + ".js"
|
||||
: moduleResolutionKind === ModuleResolutionKind.NodeJs
|
||||
? removeSuffix(noExtension, "/index")
|
||||
: noExtension;
|
||||
switch (ending) {
|
||||
case Ending.Minimal:
|
||||
return removeSuffix(noExtension, "/index");
|
||||
case Ending.Index:
|
||||
return noExtension;
|
||||
case Ending.JsExtension:
|
||||
return noExtension + getJavaScriptExtensionForFile(fileName, options);
|
||||
default:
|
||||
return Debug.assertNever(ending);
|
||||
}
|
||||
}
|
||||
|
||||
function getJavaScriptExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
const ext = extensionFromPath(fileName);
|
||||
switch (ext) {
|
||||
case Extension.Ts:
|
||||
case Extension.Dts:
|
||||
return Extension.Js;
|
||||
case Extension.Tsx:
|
||||
return options.jsx === JsxEmit.Preserve ? Extension.Jsx : Extension.Js;
|
||||
case Extension.Js:
|
||||
case Extension.Jsx:
|
||||
case Extension.Json:
|
||||
return ext;
|
||||
default:
|
||||
return Debug.assertNever(ext);
|
||||
}
|
||||
}
|
||||
|
||||
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined {
|
||||
|
|
|
@ -67,19 +67,24 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
|
||||
return createCompilerHostWorker(options, setParentNodes);
|
||||
}
|
||||
/*@internal*/
|
||||
// TODO(shkamat): update this after reworking ts build API
|
||||
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
|
||||
const existingDirectories = createMap<boolean>();
|
||||
|
||||
function getCanonicalFileName(fileName: string): string {
|
||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||
// otherwise use toLowerCase as a canonical form.
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
|
||||
let text: string | undefined;
|
||||
try {
|
||||
performance.mark("beforeIORead");
|
||||
text = sys.readFile(fileName, options.charset);
|
||||
text = system.readFile(fileName, options.charset);
|
||||
performance.mark("afterIORead");
|
||||
performance.measure("I/O Read", "beforeIORead", "afterIORead");
|
||||
}
|
||||
|
@ -97,7 +102,7 @@ namespace ts {
|
|||
if (existingDirectories.has(directoryPath)) {
|
||||
return true;
|
||||
}
|
||||
if (sys.directoryExists(directoryPath)) {
|
||||
if (system.directoryExists(directoryPath)) {
|
||||
existingDirectories.set(directoryPath, true);
|
||||
return true;
|
||||
}
|
||||
|
@ -108,7 +113,7 @@ namespace ts {
|
|||
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
||||
const parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
sys.createDirectory(directoryPath);
|
||||
system.createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,8 +124,8 @@ namespace ts {
|
|||
outputFingerprints = createMap<OutputFingerprint>();
|
||||
}
|
||||
|
||||
const hash = sys.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = sys.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
const hash = system.createHash!(data); // TODO: GH#18217
|
||||
const mtimeBefore = system.getModifiedTime!(fileName); // TODO: GH#18217
|
||||
|
||||
if (mtimeBefore) {
|
||||
const fingerprint = outputFingerprints.get(fileName);
|
||||
|
@ -133,9 +138,9 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
|
||||
const mtimeAfter = sys.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
|
||||
const mtimeAfter = system.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
|
||||
|
||||
outputFingerprints.set(fileName, {
|
||||
hash,
|
||||
|
@ -149,11 +154,11 @@ namespace ts {
|
|||
performance.mark("beforeIOWrite");
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
|
||||
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
|
||||
if (isWatchSet(options) && system.createHash && system.getModifiedTime) {
|
||||
writeFileIfUpdated(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
else {
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
system.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
|
||||
performance.mark("afterIOWrite");
|
||||
|
@ -167,32 +172,29 @@ namespace ts {
|
|||
}
|
||||
|
||||
function getDefaultLibLocation(): string {
|
||||
return getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
|
||||
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
|
||||
}
|
||||
|
||||
const newLine = getNewLineCharacter(options);
|
||||
const realpath = sys.realpath && ((path: string) => sys.realpath!(path));
|
||||
const newLine = getNewLineCharacter(options, () => system.newLine);
|
||||
const realpath = system.realpath && ((path: string) => system.realpath!(path));
|
||||
|
||||
return {
|
||||
getSourceFile,
|
||||
getDefaultLibLocation,
|
||||
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
||||
writeFile,
|
||||
getCurrentDirectory: memoize(() => sys.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => sys.fileExists(fileName),
|
||||
readFile: fileName => sys.readFile(fileName),
|
||||
trace: (s: string) => sys.write(s + newLine),
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => sys.getDirectories(path),
|
||||
fileExists: fileName => system.fileExists(fileName),
|
||||
readFile: fileName => system.readFile(fileName),
|
||||
trace: (s: string) => system.write(s + newLine),
|
||||
directoryExists: directoryName => system.directoryExists(directoryName),
|
||||
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
|
||||
getDirectories: (path: string) => system.getDirectories(path),
|
||||
realpath,
|
||||
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
|
||||
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
|
||||
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
|
||||
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
|
||||
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3097,6 +3097,10 @@ namespace ts {
|
|||
*/
|
||||
/* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined;
|
||||
/* @internal */ getTypePredicateOfSignature(signature: Signature): TypePredicate;
|
||||
/**
|
||||
* An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
|
||||
* and an external module with no 'export =' declaration resolves to the module itself.
|
||||
*/
|
||||
/* @internal */ resolveExternalModuleSymbol(symbol: Symbol): Symbol;
|
||||
/** @param node A location where we might consider accessing `this`. Not necessarily a ThisExpression. */
|
||||
/* @internal */ tryGetThisTypeAt(node: Node): Type | undefined;
|
||||
|
@ -3114,6 +3118,8 @@ namespace ts {
|
|||
* and the operation is cancelled, then it should be discarded, otherwise it is safe to keep.
|
||||
*/
|
||||
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
|
||||
|
||||
/* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): ReadonlyArray<TypeParameter> | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -4717,16 +4723,6 @@ namespace ts {
|
|||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface UpToDateHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
getModifiedTime(fileName: string): Date | undefined;
|
||||
getUnchangedTime?(fileName: string): Date | undefined;
|
||||
getLastStatus?(fileName: string): UpToDateStatus | undefined;
|
||||
setLastStatus?(fileName: string, status: UpToDateStatus): void;
|
||||
parseConfigFile?(configFilePath: ResolvedConfigFileName): ParsedCommandLine | undefined;
|
||||
}
|
||||
|
||||
export interface ModuleResolutionHost {
|
||||
// TODO: GH#18217 Optional methods frequently used as non-optional
|
||||
|
||||
|
@ -4857,10 +4853,6 @@ namespace ts {
|
|||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||
createHash?(data: string): string;
|
||||
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -5345,8 +5337,6 @@ namespace ts {
|
|||
useCaseSensitiveFileNames?(): boolean;
|
||||
fileExists?(path: string): boolean;
|
||||
readFile?(path: string): string | undefined;
|
||||
getSourceFiles?(): ReadonlyArray<SourceFile>; // Used for cached resolutions to find symlinks without traversing the fs (again)
|
||||
getCommonSourceDirectory?(): string;
|
||||
}
|
||||
|
||||
// Note: this used to be deprecated in our public API, but is still used internally
|
||||
|
@ -5359,7 +5349,7 @@ namespace ts {
|
|||
reportInaccessibleThisError?(): void;
|
||||
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
|
||||
reportInaccessibleUniqueSymbolError?(): void;
|
||||
moduleResolverHost?: ModuleSpecifierResolutionHost;
|
||||
moduleResolverHost?: EmitHost;
|
||||
trackReferencedAmbientModule?(decl: ModuleDeclaration, symbol: Symbol): void;
|
||||
trackExternalModuleSymbolOfImportTypeNode?(symbol: Symbol): void;
|
||||
}
|
||||
|
@ -5609,4 +5599,15 @@ namespace ts {
|
|||
get<TKey extends keyof PragmaPsuedoMap>(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][];
|
||||
forEach(action: <TKey extends keyof PragmaPsuedoMap>(value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void;
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2331,6 +2331,13 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
function skipParenthesesUp(node: Node): Node {
|
||||
while (node.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
node = node.parent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// a node is delete target iff. it is PropertyAccessExpression/ElementAccessExpression with parentheses skipped
|
||||
export function isDeleteTarget(node: Node): boolean {
|
||||
if (node.kind !== SyntaxKind.PropertyAccessExpression && node.kind !== SyntaxKind.ElementAccessExpression) {
|
||||
|
@ -4206,6 +4213,8 @@ namespace ts {
|
|||
if (!parent) return AccessKind.Read;
|
||||
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return accessKind(parent);
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
const { operator } = parent as PrefixUnaryExpression | PostfixUnaryExpression;
|
||||
|
@ -4217,13 +4226,35 @@ namespace ts {
|
|||
: AccessKind.Read;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return (parent as PropertyAccessExpression).name !== node ? AccessKind.Read : accessKind(parent);
|
||||
case SyntaxKind.PropertyAssignment: {
|
||||
const parentAccess = accessKind(parent.parent);
|
||||
// In `({ x: varname }) = { x: 1 }`, the left `x` is a read, the right `x` is a write.
|
||||
return node === (parent as PropertyAssignment).name ? reverseAccessKind(parentAccess) : parentAccess;
|
||||
}
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
// Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals.
|
||||
return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read : accessKind(parent.parent);
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return accessKind(parent);
|
||||
default:
|
||||
return AccessKind.Read;
|
||||
}
|
||||
|
||||
function writeOrReadWrite(): AccessKind {
|
||||
// If grandparent is not an ExpressionStatement, this is used as an expression in addition to having a side effect.
|
||||
return parent.parent && parent.parent.kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
|
||||
return parent.parent && skipParenthesesUp(parent.parent).kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
|
||||
}
|
||||
}
|
||||
function reverseAccessKind(a: AccessKind): AccessKind {
|
||||
switch (a) {
|
||||
case AccessKind.Read:
|
||||
return AccessKind.Write;
|
||||
case AccessKind.Write:
|
||||
return AccessKind.Read;
|
||||
case AccessKind.ReadWrite:
|
||||
return AccessKind.ReadWrite;
|
||||
default:
|
||||
return Debug.assertNever(a);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7905,6 +7936,7 @@ namespace ts {
|
|||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
export const supportedJavaScriptAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
|
||||
|
@ -7930,6 +7962,10 @@ namespace ts {
|
|||
return some(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function hasJavaScriptOrJsonFileExtension(fileName: string): boolean {
|
||||
return supportedJavaScriptAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
|
||||
}
|
||||
|
||||
export function hasTypeScriptFileExtension(fileName: string): boolean {
|
||||
return some(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
|
|
@ -27,12 +27,6 @@ namespace ts {
|
|||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const nonClearingMessageCodes: number[] = [
|
||||
Diagnostics.Found_1_error_Watching_for_file_changes.code,
|
||||
Diagnostics.Found_0_errors_Watching_for_file_changes.code
|
||||
];
|
||||
|
||||
/**
|
||||
* @returns Whether the screen was cleared.
|
||||
*/
|
||||
|
@ -41,7 +35,7 @@ namespace ts {
|
|||
!options.preserveWatchOutput &&
|
||||
!options.extendedDiagnostics &&
|
||||
!options.diagnostics &&
|
||||
!contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
system.clearScreen();
|
||||
return true;
|
||||
}
|
||||
|
@ -174,6 +168,17 @@ namespace ts {
|
|||
|
||||
const noopFileWatcher: FileWatcher = { close: noop };
|
||||
|
||||
export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusReporter): WatchHost {
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
return {
|
||||
onWatchStatusChange,
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the watch compiler host that can be extended with config file or root file names and options host
|
||||
*/
|
||||
|
@ -186,7 +191,7 @@ namespace ts {
|
|||
host; // tslint:disable-line no-unused-expression (TODO: `host` is unused!)
|
||||
const useCaseSensitiveFileNames = () => system.useCaseSensitiveFileNames;
|
||||
const writeFileName = (s: string) => system.write(s + system.newLine);
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
const { onWatchStatusChange, watchFile, watchDirectory, setTimeout, clearTimeout } = createWatchHost(system, reportWatchStatus);
|
||||
return {
|
||||
useCaseSensitiveFileNames,
|
||||
getNewLine: () => system.newLine,
|
||||
|
@ -200,10 +205,10 @@ namespace ts {
|
|||
readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth),
|
||||
realpath: system.realpath && (path => system.realpath!(path)),
|
||||
getEnvironmentVariable: system.getEnvironmentVariable && (name => system.getEnvironmentVariable(name)),
|
||||
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
|
||||
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
|
||||
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
|
||||
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop,
|
||||
watchFile,
|
||||
watchDirectory,
|
||||
setTimeout,
|
||||
clearTimeout,
|
||||
trace: s => system.write(s),
|
||||
onWatchStatusChange,
|
||||
createDirectory: path => system.createDirectory(path),
|
||||
|
@ -224,10 +229,10 @@ namespace ts {
|
|||
|
||||
const reportSummary = (errorCount: number) => {
|
||||
if (errorCount === 1) {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
else {
|
||||
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -270,7 +275,21 @@ namespace ts {
|
|||
export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
export type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
export interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
export interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
// TODO: GH#18217 Optional methods are frequently asserted
|
||||
|
||||
/**
|
||||
|
@ -279,8 +298,6 @@ namespace ts {
|
|||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
|
||||
// Only for testing
|
||||
/*@internal*/
|
||||
|
@ -323,15 +340,6 @@ namespace ts {
|
|||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
|
||||
/** Internal interface used to wire emit through same host */
|
||||
|
|
|
@ -374,5 +374,41 @@ namespace fakes {
|
|||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost {
|
||||
diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
reportDiagnostic(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
reportSolutionBuilderStatus(diagnostic: ts.Diagnostic) {
|
||||
this.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
clearDiagnostics() {
|
||||
this.diagnostics.length = 0;
|
||||
}
|
||||
|
||||
assertDiagnosticMessages(...expected: ts.DiagnosticMessage[]) {
|
||||
const actual = this.diagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = ts.createDiagnosticReporter(ts.sys);
|
||||
ts.sys.write(header + "\r\n");
|
||||
for (const d of this.diagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -908,8 +908,8 @@ namespace FourSlash {
|
|||
}
|
||||
|
||||
private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) {
|
||||
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, sourceDisplay } = typeof expected === "string"
|
||||
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, sourceDisplay: undefined }
|
||||
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, source, sourceDisplay } = typeof expected === "string"
|
||||
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, source: undefined, sourceDisplay: undefined }
|
||||
: expected;
|
||||
|
||||
if (actual.insertText !== insertText) {
|
||||
|
@ -927,6 +927,7 @@ namespace FourSlash {
|
|||
|
||||
assert.equal(actual.hasAction, hasAction);
|
||||
assert.equal(actual.isRecommended, isRecommended);
|
||||
assert.equal(actual.source, source);
|
||||
|
||||
if (text) {
|
||||
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
|
||||
|
@ -4789,6 +4790,7 @@ namespace FourSlashInterface {
|
|||
|
||||
export type ExpectedCompletionEntry = string | {
|
||||
readonly name: string,
|
||||
readonly source?: string,
|
||||
readonly insertText?: string,
|
||||
readonly replacementSpan?: FourSlash.Range,
|
||||
readonly hasAction?: boolean, // If not specified, will assert that this is false.
|
||||
|
|
|
@ -620,14 +620,14 @@ interface Array<T> {}`
|
|||
}
|
||||
}
|
||||
|
||||
removeFile(filePath: string) {
|
||||
deleteFile(filePath: string) {
|
||||
const path = this.toFullPath(filePath);
|
||||
const currentEntry = this.fs.get(path) as FsFile;
|
||||
Debug.assert(isFsFile(currentEntry));
|
||||
this.removeFileOrFolder(currentEntry, returnFalse);
|
||||
}
|
||||
|
||||
removeFolder(folderPath: string, recursive?: boolean) {
|
||||
deleteFolder(folderPath: string, recursive?: boolean) {
|
||||
const path = this.toFullPath(folderPath);
|
||||
const currentEntry = this.fs.get(path) as FsFolder;
|
||||
Debug.assert(isFsFolder(currentEntry));
|
||||
|
@ -635,7 +635,7 @@ interface Array<T> {}`
|
|||
const subEntries = currentEntry.entries.slice();
|
||||
subEntries.forEach(fsEntry => {
|
||||
if (isFsFolder(fsEntry)) {
|
||||
this.removeFolder(fsEntry.fullPath, recursive);
|
||||
this.deleteFolder(fsEntry.fullPath, recursive);
|
||||
}
|
||||
else {
|
||||
this.removeFileOrFolder(fsEntry, returnFalse);
|
||||
|
@ -766,6 +766,14 @@ interface Array<T> {}`
|
|||
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
setModifiedTime(s: string, date: Date) {
|
||||
const path = this.toFullPath(s);
|
||||
const fsEntry = this.fs.get(path);
|
||||
if (fsEntry) {
|
||||
fsEntry.modifiedTime = date;
|
||||
}
|
||||
}
|
||||
|
||||
readFile(s: string): string | undefined {
|
||||
const fsEntry = this.getRealFile(this.toFullPath(s));
|
||||
return fsEntry ? fsEntry.content : undefined;
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
namespace ts {
|
||||
export interface UserPreferences {
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ts.server {
|
||||
export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024;
|
||||
/*@internal*/
|
||||
|
|
|
@ -163,7 +163,7 @@ namespace ts.codefix {
|
|||
position: number,
|
||||
preferences: UserPreferences,
|
||||
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
|
||||
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getTypeChecker(), program.getSourceFiles());
|
||||
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
|
||||
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
|
||||
// We sort the best codefixes first, so taking `first` is best for completions.
|
||||
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences)).moduleSpecifier;
|
||||
|
@ -175,7 +175,7 @@ namespace ts.codefix {
|
|||
return { description, changes, commands };
|
||||
}
|
||||
|
||||
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
|
||||
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
|
||||
const result: SymbolExportInfo[] = [];
|
||||
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
|
||||
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
|
||||
|
@ -183,10 +183,14 @@ namespace ts.codefix {
|
|||
return;
|
||||
}
|
||||
|
||||
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions);
|
||||
if (defaultInfo && defaultInfo.name === symbolName && skipAlias(defaultInfo.symbol, checker) === exportedSymbol) {
|
||||
result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol) });
|
||||
}
|
||||
|
||||
for (const exported of checker.getExportsOfModule(moduleSymbol)) {
|
||||
if ((exported.escapedName === InternalSymbolName.Default || exported.name === symbolName) && skipAlias(exported, checker) === exportedSymbol) {
|
||||
const isDefaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol) === exported;
|
||||
result.push({ moduleSymbol, importKind: isDefaultExport ? ImportKind.Default : ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
|
||||
if (exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) {
|
||||
result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -400,13 +404,9 @@ namespace ts.codefix {
|
|||
forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// check the default export
|
||||
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
|
||||
if (defaultExport) {
|
||||
const info = getDefaultExportInfo(defaultExport, moduleSymbol, program);
|
||||
if (info && info.name === symbolName && symbolHasMeaning(info.symbolForMeaning, currentTokenMeaning)) {
|
||||
addSymbol(moduleSymbol, defaultExport, ImportKind.Default);
|
||||
}
|
||||
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, program.getCompilerOptions());
|
||||
if (defaultInfo && defaultInfo.name === symbolName && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) {
|
||||
addSymbol(moduleSymbol, defaultInfo.symbol, defaultInfo.kind);
|
||||
}
|
||||
|
||||
// check exports with the same name
|
||||
|
@ -418,7 +418,24 @@ namespace ts.codefix {
|
|||
return originalSymbolToExportInfos;
|
||||
}
|
||||
|
||||
function getDefaultExportInfo(defaultExport: Symbol, moduleSymbol: Symbol, program: Program): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
function getDefaultLikeExportInfo(
|
||||
moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
|
||||
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
|
||||
const exported = getDefaultLikeExportWorker(moduleSymbol, checker);
|
||||
if (!exported) return undefined;
|
||||
const { symbol, kind } = exported;
|
||||
const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions);
|
||||
return info && { symbol, symbolForMeaning: info.symbolForMeaning, name: info.name, kind };
|
||||
}
|
||||
|
||||
function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
|
||||
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
|
||||
if (defaultExport) return { symbol: defaultExport, kind: ImportKind.Default };
|
||||
const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol);
|
||||
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: ImportKind.Equals };
|
||||
}
|
||||
|
||||
function getDefaultExportInfoWorker(defaultExport: Symbol, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
|
||||
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
|
||||
if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name };
|
||||
|
||||
|
@ -426,11 +443,11 @@ namespace ts.codefix {
|
|||
if (name !== undefined) return { symbolForMeaning: defaultExport, name };
|
||||
|
||||
if (defaultExport.flags & SymbolFlags.Alias) {
|
||||
const aliased = program.getTypeChecker().getImmediateAliasedSymbol(defaultExport);
|
||||
return aliased && getDefaultExportInfo(aliased, Debug.assertDefined(aliased.parent), program);
|
||||
const aliased = checker.getImmediateAliasedSymbol(defaultExport);
|
||||
return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions);
|
||||
}
|
||||
else {
|
||||
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, program.getCompilerOptions().target!) };
|
||||
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1378,6 +1378,14 @@ namespace ts.Completions {
|
|||
return;
|
||||
}
|
||||
|
||||
if (resolvedModuleSymbol !== moduleSymbol &&
|
||||
// Don't add another completion for `export =` of a symbol that's already global.
|
||||
// So in `declare namespace foo {} declare module "foo" { export = foo; }`, there will just be the global completion for `foo`.
|
||||
resolvedModuleSymbol.declarations.some(d => !!d.getSourceFile().externalModuleIndicator)) {
|
||||
symbols.push(resolvedModuleSymbol);
|
||||
symbolToOriginInfoMap[getSymbolId(resolvedModuleSymbol)] = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport: false };
|
||||
}
|
||||
|
||||
for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
|
||||
// Don't add a completion for a re-export, only for the original.
|
||||
// The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace ts {
|
|||
newFileOrDirPath: string,
|
||||
host: LanguageServiceHost,
|
||||
formatContext: formatting.FormatContext,
|
||||
preferences: UserPreferences,
|
||||
_preferences: UserPreferences,
|
||||
sourceMapper: SourceMapper,
|
||||
): ReadonlyArray<FileTextChanges> {
|
||||
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
||||
|
@ -15,7 +15,7 @@ namespace ts {
|
|||
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper);
|
||||
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
|
||||
updateTsconfigFiles(program, changeTracker, oldToNew, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences);
|
||||
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,6 @@ namespace ts {
|
|||
newToOld: PathUpdater,
|
||||
host: LanguageServiceHost,
|
||||
getCanonicalFileName: GetCanonicalFileName,
|
||||
preferences: UserPreferences,
|
||||
): void {
|
||||
const allFiles = program.getSourceFiles();
|
||||
for (const sourceFile of allFiles) {
|
||||
|
@ -156,7 +155,7 @@ namespace ts {
|
|||
|
||||
// Need an update if the imported file moved, or the importing file moved and was using a relative path.
|
||||
return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text)))
|
||||
? moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, host, allFiles, preferences, program.redirectTargetsMap)
|
||||
? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), newImportFromPath, toImport.newFileName, host, allFiles, program.redirectTargetsMap, importLiteral.text)
|
||||
: undefined;
|
||||
});
|
||||
}
|
||||
|
@ -210,7 +209,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) {
|
||||
for (const ref of sourceFile.referencedFiles) {
|
||||
for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162
|
||||
const updated = updateRef(ref.fileName);
|
||||
if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ts.GoToDefinition {
|
|||
|
||||
const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node);
|
||||
// Don't go to the component constructor definition for a JSX element, just go to the component definition.
|
||||
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorDeclaration(calledDeclaration))) {
|
||||
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorLike(calledDeclaration))) {
|
||||
const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration);
|
||||
// For a function, if this is the original function definition, return just sigInfo.
|
||||
// If this is the original constructor definition, parent is the class.
|
||||
|
@ -319,4 +319,15 @@ namespace ts.GoToDefinition {
|
|||
// Don't go to a function type, go to the value having that type.
|
||||
return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d));
|
||||
}
|
||||
|
||||
function isConstructorLike(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace ts.SignatureHelp {
|
||||
const enum InvocationKind { Call, TypeArgs, Contextual }
|
||||
interface CallInvocation { readonly kind: InvocationKind.Call; readonly node: CallLikeExpression; }
|
||||
interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Expression; }
|
||||
interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Identifier; }
|
||||
interface ContextualInvocation {
|
||||
readonly kind: InvocationKind.Contextual;
|
||||
readonly signature: Signature;
|
||||
|
@ -44,7 +44,7 @@ namespace ts.SignatureHelp {
|
|||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// Extra syntactic and semantic filtering of signature help
|
||||
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
|
||||
const candidateInfo = getCandidateOrTypeInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
if (!candidateInfo) {
|
||||
|
@ -53,11 +53,24 @@ namespace ts.SignatureHelp {
|
|||
return isSourceFileJavaScript(sourceFile) ? createJavaScriptSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined;
|
||||
}
|
||||
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker =>
|
||||
candidateInfo.kind === CandidateOrTypeKind.Candidate
|
||||
? createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker)
|
||||
: createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker));
|
||||
}
|
||||
|
||||
interface CandidateInfo { readonly candidates: ReadonlyArray<Signature>; readonly resolvedSignature: Signature; }
|
||||
function getCandidateInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | undefined {
|
||||
const enum CandidateOrTypeKind { Candidate, Type }
|
||||
interface CandidateInfo {
|
||||
readonly kind: CandidateOrTypeKind.Candidate;
|
||||
readonly candidates: ReadonlyArray<Signature>;
|
||||
readonly resolvedSignature: Signature;
|
||||
}
|
||||
interface TypeInfo {
|
||||
readonly kind: CandidateOrTypeKind.Type;
|
||||
readonly symbol: Symbol;
|
||||
}
|
||||
|
||||
function getCandidateOrTypeInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | TypeInfo | undefined {
|
||||
switch (invocation.kind) {
|
||||
case InvocationKind.Call: {
|
||||
if (onlyUseSyntacticOwners && !isSyntacticOwner(startingToken, invocation.node, sourceFile)) {
|
||||
|
@ -65,17 +78,21 @@ namespace ts.SignatureHelp {
|
|||
}
|
||||
const candidates: Signature[] = [];
|
||||
const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentCount)!; // TODO: GH#18217
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
|
||||
return candidates.length === 0 ? undefined : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature };
|
||||
}
|
||||
case InvocationKind.TypeArgs: {
|
||||
if (onlyUseSyntacticOwners && !lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.called)) {
|
||||
const { called } = invocation;
|
||||
if (onlyUseSyntacticOwners && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called)) {
|
||||
return undefined;
|
||||
}
|
||||
const candidates = getPossibleGenericSignatures(invocation.called, argumentCount, checker);
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
|
||||
const candidates = getPossibleGenericSignatures(called, argumentCount, checker);
|
||||
if (candidates.length !== 0) return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) };
|
||||
|
||||
const symbol = checker.getSymbolAtLocation(called);
|
||||
return symbol && { kind: CandidateOrTypeKind.Type, symbol };
|
||||
}
|
||||
case InvocationKind.Contextual:
|
||||
return { candidates: [invocation.signature], resolvedSignature: invocation.signature };
|
||||
return { kind: CandidateOrTypeKind.Candidate, candidates: [invocation.signature], resolvedSignature: invocation.signature };
|
||||
default:
|
||||
return Debug.assertNever(invocation);
|
||||
}
|
||||
|
@ -92,7 +109,7 @@ namespace ts.SignatureHelp {
|
|||
return !!containingList && contains(invocationChildren, containingList);
|
||||
}
|
||||
case SyntaxKind.LessThanToken:
|
||||
return lessThanFollowsCalledExpression(startingToken, sourceFile, node.expression);
|
||||
return containsPrecedingToken(startingToken, sourceFile, node.expression);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -114,12 +131,12 @@ namespace ts.SignatureHelp {
|
|||
}));
|
||||
}
|
||||
|
||||
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
|
||||
function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) {
|
||||
const precedingToken = Debug.assertDefined(
|
||||
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
|
||||
);
|
||||
|
||||
return rangeContainsRange(calledExpression, precedingToken);
|
||||
return rangeContainsRange(container, precedingToken);
|
||||
}
|
||||
|
||||
export interface ArgumentInfoForCompletions {
|
||||
|
@ -457,6 +474,10 @@ namespace ts.SignatureHelp {
|
|||
return invocation.kind === InvocationKind.Call ? getInvokedExpression(invocation.node) : invocation.called;
|
||||
}
|
||||
|
||||
function getEnclosingDeclarationFromInvocation(invocation: Invocation): Node {
|
||||
return invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
|
||||
}
|
||||
|
||||
const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
|
||||
function createSignatureHelpItems(
|
||||
candidates: ReadonlyArray<Signature>,
|
||||
|
@ -465,7 +486,7 @@ namespace ts.SignatureHelp {
|
|||
sourceFile: SourceFile,
|
||||
typeChecker: TypeChecker,
|
||||
): SignatureHelpItems {
|
||||
const enclosingDeclaration = invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
|
||||
const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation);
|
||||
const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation));
|
||||
const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : emptyArray;
|
||||
const items = candidates.map(candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
|
||||
|
@ -480,11 +501,36 @@ namespace ts.SignatureHelp {
|
|||
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
|
||||
}
|
||||
|
||||
function createTypeHelpItems(
|
||||
symbol: Symbol,
|
||||
{ argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: ArgumentListInfo,
|
||||
sourceFile: SourceFile,
|
||||
checker: TypeChecker
|
||||
): SignatureHelpItems | undefined {
|
||||
const typeParameters = checker.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
if (!typeParameters) return undefined;
|
||||
const items = [getTypeHelpItem(symbol, typeParameters, checker, getEnclosingDeclarationFromInvocation(invocation), sourceFile)];
|
||||
return { items, applicableSpan, selectedItemIndex: 0, argumentIndex, argumentCount };
|
||||
}
|
||||
|
||||
function getTypeHelpItem(symbol: Symbol, typeParameters: ReadonlyArray<TypeParameter>, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
|
||||
const typeSymbolDisplay = symbolToDisplayParts(checker, symbol);
|
||||
|
||||
const printer = createPrinter({ removeComments: true });
|
||||
const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer));
|
||||
|
||||
const documentation = symbol.getDocumentationComment(checker);
|
||||
const tags = symbol.getJsDocTags();
|
||||
const prefixDisplayParts = [...typeSymbolDisplay, punctuationPart(SyntaxKind.LessThanToken)];
|
||||
return { isVariadic: false, prefixDisplayParts, suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], separatorDisplayParts, parameters, documentation, tags };
|
||||
}
|
||||
|
||||
const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
|
||||
|
||||
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: ReadonlyArray<SymbolDisplayPart>, isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
|
||||
const { isVariadic, parameters, prefix, suffix } = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
|
||||
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
|
||||
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
|
||||
const separatorDisplayParts = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
|
||||
const documentation = candidateSignature.getDocumentationComment(checker);
|
||||
const tags = candidateSignature.getJsDocTags();
|
||||
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
|
||||
|
|
|
@ -233,15 +233,6 @@ namespace ts {
|
|||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
|
||||
export interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
/* @internal */
|
||||
export const emptyOptions = {};
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
"unittests/transform.ts",
|
||||
"unittests/transpile.ts",
|
||||
"unittests/tsbuild.ts",
|
||||
"unittests/tsbuildWatchMode.ts",
|
||||
"unittests/tsconfigParsing.ts",
|
||||
"unittests/tscWatchMode.ts",
|
||||
"unittests/versionCache.ts",
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
namespace ts {
|
||||
let currentTime = 100;
|
||||
let lastDiagnostics: Diagnostic[] = [];
|
||||
const reportDiagnostic: DiagnosticReporter = diagnostic => lastDiagnostics.push(diagnostic);
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiagnostic(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiagnostic(d)
|
||||
};
|
||||
|
||||
export namespace Sample1 {
|
||||
tick();
|
||||
const projFs = loadProjectFromDisk("tests/projects/sample1");
|
||||
|
@ -21,12 +11,12 @@ namespace ts {
|
|||
describe("tsbuild - sanity check of clean build of 'sample1' project", () => {
|
||||
it("can build the sample project 'sample1' without error", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
|
@ -37,12 +27,11 @@ namespace ts {
|
|||
|
||||
describe("tsbuild - dry builds", () => {
|
||||
it("doesn't write any files in a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
host.assertDiagnosticMessages(Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0, Diagnostics.A_non_dry_build_would_build_project_0);
|
||||
|
||||
// Check for outputs to not be written. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
|
@ -51,28 +40,26 @@ namespace ts {
|
|||
});
|
||||
|
||||
it("indicates that it would skip builds during a dry build", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
let builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
let builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
tick();
|
||||
|
||||
clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder = createSolutionBuilder(host, ["/src/tests"], { dry: true, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
host.assertDiagnosticMessages(Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date, Diagnostics.Project_0_is_up_to_date);
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - clean builds", () => {
|
||||
it("removes all files it built", () => {
|
||||
clearDiagnostics();
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
// Verify they exist
|
||||
for (const output of allExpectedOutputs) {
|
||||
|
@ -91,9 +78,9 @@ namespace ts {
|
|||
describe("tsbuild - force builds", () => {
|
||||
it("always builds under --force", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: true, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
let currentTime = time();
|
||||
checkOutputTimestamps(currentTime);
|
||||
|
@ -116,14 +103,14 @@ namespace ts {
|
|||
|
||||
describe("tsbuild - can detect when and what to rebuild", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
it("Builds the project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
|
@ -135,10 +122,10 @@ namespace ts {
|
|||
|
||||
// All three projects are up to date
|
||||
it("Detects that all projects are up to date", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2);
|
||||
|
@ -147,12 +134,12 @@ namespace ts {
|
|||
|
||||
// Update a file in the leaf node (tests), only it should rebuild the last one
|
||||
it("Only builds the leaf node project", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
fs.writeFileSync("/src/tests/index.ts", "const m = 10;");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
|
@ -162,12 +149,12 @@ namespace ts {
|
|||
|
||||
// Update a file in the parent (without affecting types), should get fast downstream builds
|
||||
it("Detects type-only changes in upstream projects", () => {
|
||||
clearDiagnostics();
|
||||
host.clearDiagnostics();
|
||||
replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET");
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
|
||||
assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
host.assertDiagnosticMessages(Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
|
||||
Diagnostics.Building_project_0,
|
||||
Diagnostics.Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies,
|
||||
|
@ -180,15 +167,13 @@ namespace ts {
|
|||
describe("tsbuild - downstream-blocked compilations", () => {
|
||||
it("won't build downstream projects if upstream projects have errors", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: true });
|
||||
|
||||
// Induce an error in the middle project
|
||||
replaceText(fs, "/src/logic/index.ts", "c.multiply(10, 15)", `c.muitply()`);
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(
|
||||
host.assertDiagnosticMessages(
|
||||
Diagnostics.Projects_in_this_build_Colon_0,
|
||||
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
|
||||
Diagnostics.Building_project_0,
|
||||
|
@ -204,12 +189,11 @@ namespace ts {
|
|||
describe("tsbuild - project invalidation", () => {
|
||||
it("invalidates projects correctly", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { dry: false, force: false, verbose: false });
|
||||
|
||||
clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*empty*/);
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Update a timestamp in the middle project
|
||||
tick();
|
||||
|
@ -221,14 +205,14 @@ namespace ts {
|
|||
// Rebuild this project
|
||||
tick();
|
||||
builder.invalidateProject("/src/logic");
|
||||
builder.buildInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
// The file should be updated
|
||||
assert.equal(fs.statSync("/src/logic/index.js").mtimeMs, time(), "JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should *not* have been rebuilt");
|
||||
|
||||
// Build downstream projects should update 'tests', but not 'core'
|
||||
tick();
|
||||
builder.buildDependentInvalidatedProjects();
|
||||
builder.buildInvalidatedProject();
|
||||
assert.equal(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/core/index.js").mtimeMs, time(), "Upstream JS file should not have been rebuilt");
|
||||
});
|
||||
|
@ -240,11 +224,10 @@ namespace ts {
|
|||
|
||||
function verifyProjectWithResolveJsonModule(configFile: string, ...expectedDiagnosticMessages: DiagnosticMessage[]) {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, [configFile], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, [configFile], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
host.assertDiagnosticMessages(...expectedDiagnosticMessages);
|
||||
if (!expectedDiagnosticMessages.length) {
|
||||
// Check for outputs. Not an exhaustive list
|
||||
for (const output of allExpectedOutputs) {
|
||||
|
@ -274,11 +257,11 @@ namespace ts {
|
|||
let fs: vfs.FileSystem | undefined;
|
||||
before(() => {
|
||||
fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
});
|
||||
after(() => {
|
||||
fs = undefined;
|
||||
|
@ -293,25 +276,24 @@ namespace ts {
|
|||
describe("tsbuild - downstream prepend projects always get rebuilt", () => {
|
||||
it("", () => {
|
||||
const fs = outFileFs.shadow();
|
||||
const host = new fakes.CompilerHost(fs);
|
||||
const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
clearDiagnostics();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: false });
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "First build timestamp is correct");
|
||||
tick();
|
||||
replaceText(fs, "src/first/first_PART1.ts", "Hello", "Hola");
|
||||
tick();
|
||||
builder.resetBuildContext();
|
||||
builder.buildAllProjects();
|
||||
assertDiagnosticMessages(/*none*/);
|
||||
host.assertDiagnosticMessages(/*none*/);
|
||||
assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "Second build timestamp is correct");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("tsbuild - graph-ordering", () => {
|
||||
let host: fakes.CompilerHost | undefined;
|
||||
let host: fakes.SolutionBuilderHost | undefined;
|
||||
const deps: [string, string][] = [
|
||||
["A", "B"],
|
||||
["B", "C"],
|
||||
|
@ -324,7 +306,7 @@ namespace ts {
|
|||
|
||||
before(() => {
|
||||
const fs = new vfs.FileSystem(false);
|
||||
host = new fakes.CompilerHost(fs);
|
||||
host = new fakes.SolutionBuilderHost(fs);
|
||||
writeProjects(fs, ["A", "B", "C", "D", "E", "F", "G"], deps);
|
||||
});
|
||||
|
||||
|
@ -349,7 +331,7 @@ namespace ts {
|
|||
});
|
||||
|
||||
function checkGraphOrdering(rootNames: string[], expectedBuildSet: string[]) {
|
||||
const builder = createSolutionBuilder(host!, buildHost, rootNames, { dry: true, force: false, verbose: false });
|
||||
const builder = createSolutionBuilder(host!, rootNames, { dry: true, force: false, verbose: false });
|
||||
|
||||
const projFileNames = rootNames.map(getProjectFileName);
|
||||
const graph = builder.getBuildGraph(projFileNames);
|
||||
|
@ -404,30 +386,6 @@ namespace ts {
|
|||
fs.writeFileSync(path, newContent, "utf-8");
|
||||
}
|
||||
|
||||
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
|
||||
const actual = lastDiagnostics.slice();
|
||||
if (actual.length !== expected.length) {
|
||||
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
|
||||
}
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual[i].code !== expected[i].code) {
|
||||
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearDiagnostics() {
|
||||
lastDiagnostics = [];
|
||||
}
|
||||
|
||||
export function printDiagnostics(header = "== Diagnostics ==") {
|
||||
const out = createDiagnosticReporter(sys);
|
||||
sys.write(header + "\r\n");
|
||||
for (const d of lastDiagnostics) {
|
||||
out(d);
|
||||
}
|
||||
}
|
||||
|
||||
function tick() {
|
||||
currentTime += 60_000;
|
||||
}
|
||||
|
|
133
src/testRunner/unittests/tsbuildWatchMode.ts
Normal file
133
src/testRunner/unittests/tsbuildWatchMode.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
namespace ts.tscWatch {
|
||||
export import libFile = TestFSWithWatch.libFile;
|
||||
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const host = createSolutionBuilderWithWatchHost(system);
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { dry: false, force: false, verbose: false, watch: true });
|
||||
}
|
||||
|
||||
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const solutionBuilder = createSolutionBuilder(host, rootNames, defaultOptions);
|
||||
solutionBuilder.buildAllProjects();
|
||||
solutionBuilder.startWatching();
|
||||
return solutionBuilder;
|
||||
}
|
||||
|
||||
describe("tsbuild-watch program updates", () => {
|
||||
const projectsLocation = "/user/username/projects";
|
||||
const project = "sample1";
|
||||
const enum SubProject {
|
||||
core = "core",
|
||||
logic = "logic",
|
||||
tests = "tests",
|
||||
ui = "ui"
|
||||
}
|
||||
type ReadonlyFile = Readonly<File>;
|
||||
/** [tsconfig, index] | [tsconfig, index, anotherModule, someDecl] */
|
||||
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
|
||||
const root = Harness.IO.getWorkspaceRoot();
|
||||
|
||||
function projectFilePath(subProject: SubProject, baseFileName: string) {
|
||||
return `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
return {
|
||||
path: projectFilePath(subProject, baseFileName),
|
||||
content: Harness.IO.readFile(`${root}/tests/projects/${project}/${subProject}/${baseFileName}`)!
|
||||
};
|
||||
}
|
||||
|
||||
function subProjectFiles(subProject: SubProject, anotherModuleAndSomeDecl?: true): SubProjectFiles {
|
||||
const tsconfig = projectFile(subProject, "tsconfig.json");
|
||||
const index = projectFile(subProject, "index.ts");
|
||||
if (!anotherModuleAndSomeDecl) {
|
||||
return [tsconfig, index];
|
||||
}
|
||||
const anotherModule = projectFile(SubProject.core, "anotherModule.ts");
|
||||
const someDecl = projectFile(SubProject.core, "some_decl.ts");
|
||||
return [tsconfig, index, anotherModule, someDecl];
|
||||
}
|
||||
|
||||
function getOutputFileNames(subProject: SubProject, baseFileNameWithoutExtension: string) {
|
||||
const file = projectFilePath(subProject, baseFileNameWithoutExtension);
|
||||
return [`${file}.js`, `${file}.d.ts`];
|
||||
}
|
||||
|
||||
type OutputFileStamp = [string, Date | undefined];
|
||||
function getOutputStamps(host: WatchedSystem, subProject: SubProject, baseFileNameWithoutExtension: string): OutputFileStamp[] {
|
||||
return getOutputFileNames(subProject, baseFileNameWithoutExtension).map(f => [f, host.getModifiedTime(f)] as OutputFileStamp);
|
||||
}
|
||||
|
||||
function getOutputFileStamps(host: WatchedSystem): OutputFileStamp[] {
|
||||
return [
|
||||
...getOutputStamps(host, SubProject.core, "anotherModule"),
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
...getOutputStamps(host, SubProject.tests, "index"),
|
||||
];
|
||||
}
|
||||
|
||||
function verifyChangedFiles(actualStamps: OutputFileStamp[], oldTimeStamps: OutputFileStamp[], changedFiles: string[]) {
|
||||
for (let i = 0; i < oldTimeStamps.length; i++) {
|
||||
const actual = actualStamps[i];
|
||||
const old = oldTimeStamps[i];
|
||||
if (contains(changedFiles, actual[0])) {
|
||||
assert.isTrue((actual[1] || 0) > (old[1] || 0), `${actual[0]} expected to written`);
|
||||
}
|
||||
else {
|
||||
assert.equal(actual[1], old[1], `${actual[0]} expected to not change`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const core = subProjectFiles(SubProject.core, /*anotherModuleAndSomeDecl*/ true);
|
||||
const logic = subProjectFiles(SubProject.logic);
|
||||
const tests = subProjectFiles(SubProject.tests);
|
||||
const ui = subProjectFiles(SubProject.ui);
|
||||
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
|
||||
|
||||
function createSolutionInWatchMode() {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // TODO: #26524
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
return { host, outputFileStamps };
|
||||
}
|
||||
it("creates solution in watch mode", () => {
|
||||
createSolutionInWatchMode();
|
||||
});
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const { host, outputFileStamps } = createSolutionInWatchMode();
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
export class someClass { }`);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedTests, changedCore, [
|
||||
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, changedTests, [
|
||||
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
});
|
||||
}
|
|
@ -1,17 +1,16 @@
|
|||
namespace ts.tscWatch {
|
||||
import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
type File = TestFSWithWatch.File;
|
||||
type SymLink = TestFSWithWatch.SymLink;
|
||||
import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
import checkArray = TestFSWithWatch.checkArray;
|
||||
import libFile = TestFSWithWatch.libFile;
|
||||
import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
export import WatchedSystem = TestFSWithWatch.TestServerHost;
|
||||
export type File = TestFSWithWatch.File;
|
||||
export type SymLink = TestFSWithWatch.SymLink;
|
||||
export import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
|
||||
export import checkArray = TestFSWithWatch.checkArray;
|
||||
export import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
|
||||
export import checkWatchedFilesDetailed = TestFSWithWatch.checkWatchedFilesDetailed;
|
||||
export import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
|
||||
export import checkWatchedDirectoriesDetailed = TestFSWithWatch.checkWatchedDirectoriesDetailed;
|
||||
export import checkOutputContains = TestFSWithWatch.checkOutputContains;
|
||||
export import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
|
||||
export import Tsc_WatchDirectory = TestFSWithWatch.Tsc_WatchDirectory;
|
||||
|
||||
export function checkProgramActualFiles(program: Program, expectedFiles: string[]) {
|
||||
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);
|
||||
|
@ -111,7 +110,7 @@ namespace ts.tscWatch {
|
|||
|
||||
function assertWatchDiagnostic(diagnostic: Diagnostic) {
|
||||
const expected = getWatchDiagnosticWithoutDate(diagnostic);
|
||||
if (!disableConsoleClears && !contains(nonClearingMessageCodes, diagnostic.code)) {
|
||||
if (!disableConsoleClears && contains(screenStartingMessageCodes, diagnostic.code)) {
|
||||
assert.equal(host.screenClears[screenClears], index, `Expected screen clear at this diagnostic: ${expected}`);
|
||||
screenClears++;
|
||||
}
|
||||
|
@ -137,7 +136,7 @@ namespace ts.tscWatch {
|
|||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
}
|
||||
|
||||
function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
|
@ -148,7 +147,7 @@ namespace ts.tscWatch {
|
|||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
|
|
|
@ -8365,7 +8365,7 @@ new C();`
|
|||
|
||||
verifyProjectWithResolvedModule(session);
|
||||
|
||||
host.removeFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.deleteFolder(recognizersTextDist, /*recursive*/ true);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
verifyProjectWithUnresolvedModule(session);
|
||||
|
@ -9281,7 +9281,7 @@ describe("Test Suite 1", () => {
|
|||
checkProjectActualFiles(project, expectedFilesWithUnitTest1);
|
||||
|
||||
const navBarResultUnitTest1 = navBarFull(session, unitTest1);
|
||||
host.removeFile(unitTest1.path);
|
||||
host.deleteFile(unitTest1.path);
|
||||
host.checkTimeoutQueueLengthAndRun(2);
|
||||
checkProjectActualFiles(project, expectedFilesWithoutUnitTest1);
|
||||
|
||||
|
@ -9527,7 +9527,7 @@ export function Test2() {
|
|||
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
|
||||
|
||||
// Testing what happens if we delete the original sources.
|
||||
host.removeFile(bTs.path);
|
||||
host.deleteFile(bTs.path);
|
||||
|
||||
openFilesForSession([userTs], session);
|
||||
const service = session.getProjectService();
|
||||
|
|
158
src/tsc/tsc.ts
158
src/tsc/tsc.ts
|
@ -13,7 +13,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
let reportDiagnostic = createDiagnosticReporter(sys);
|
||||
function updateReportDiagnostic(options: CompilerOptions) {
|
||||
function updateReportDiagnostic(options?: CompilerOptions) {
|
||||
if (shouldBePretty(options)) {
|
||||
reportDiagnostic = createDiagnosticReporter(sys, /*pretty*/ true);
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ namespace ts {
|
|||
return !!sys.writeOutputIsTTY && sys.writeOutputIsTTY();
|
||||
}
|
||||
|
||||
function shouldBePretty(options: CompilerOptions) {
|
||||
if (typeof options.pretty === "undefined") {
|
||||
function shouldBePretty(options?: CompilerOptions) {
|
||||
if (!options || typeof options.pretty === "undefined") {
|
||||
return defaultIsPretty();
|
||||
}
|
||||
return options.pretty;
|
||||
|
@ -54,15 +54,7 @@ namespace ts {
|
|||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) {
|
||||
const reportDiag = createDiagnosticReporter(sys, defaultIsPretty());
|
||||
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiag(createCompilerDiagnostic(message, ...args));
|
||||
const buildHost: BuildHost = {
|
||||
error: report,
|
||||
verbose: report,
|
||||
message: report,
|
||||
errorDiagnostic: d => reportDiag(d)
|
||||
};
|
||||
const result = performBuild(args.slice(1), createCompilerHost({}), buildHost, sys);
|
||||
const result = performBuild(args.slice(1));
|
||||
// undefined = in watch mode, do not exit
|
||||
if (result !== undefined) {
|
||||
return sys.exit(result);
|
||||
|
@ -172,6 +164,146 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function performBuild(args: string[]): number | undefined {
|
||||
const buildOpts: CommandLineOption[] = [
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
type: "boolean",
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Print_this_message,
|
||||
},
|
||||
{
|
||||
name: "help",
|
||||
shortName: "?",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "verbose",
|
||||
shortName: "v",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Enable_verbose_logging,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "dry",
|
||||
shortName: "d",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "force",
|
||||
shortName: "f",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "clean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Delete_the_outputs_of_all_projects,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Watch_input_files,
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
name: "preserveWatchOutput",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
];
|
||||
let buildOptionNameMap: OptionNameMap | undefined;
|
||||
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
|
||||
|
||||
const buildOptions: BuildOptions = {};
|
||||
const projects: string[] = [];
|
||||
for (const arg of args) {
|
||||
if (arg.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
buildOptions[opt.name as keyof BuildOptions] = true;
|
||||
}
|
||||
else {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a flag, parse as filename
|
||||
addProject(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (buildOptions.help) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
// Update to pretty if host supports it
|
||||
updateReportDiagnostic();
|
||||
|
||||
if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.watch) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
}
|
||||
|
||||
// Nonsensical combinations
|
||||
if (buildOptions.clean && buildOptions.force) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.verbose) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.watch) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
if (buildOptions.watch && buildOptions.dry) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
addProject(".");
|
||||
}
|
||||
|
||||
// TODO: change this to host if watch => watchHost otherwiue without wathc
|
||||
const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions);
|
||||
if (buildOptions.clean) {
|
||||
return builder.cleanAllProjects();
|
||||
}
|
||||
|
||||
if (buildOptions.watch) {
|
||||
builder.buildAllProjects();
|
||||
builder.startWatching();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return builder.buildAllProjects();
|
||||
|
||||
function addProject(projectSpecification: string) {
|
||||
const fileName = resolvePath(sys.getCurrentDirectory(), projectSpecification);
|
||||
const refPath = resolveProjectReferencePath(sys, { path: fileName });
|
||||
if (!sys.fileExists(refPath)) {
|
||||
return reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
|
||||
}
|
||||
projects.push(refPath);
|
||||
}
|
||||
}
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
const host = createCompilerHost(options);
|
||||
enableStatistics(options);
|
||||
|
@ -205,7 +337,7 @@ namespace ts {
|
|||
};
|
||||
}
|
||||
|
||||
function createWatchStatusReporter(options: CompilerOptions) {
|
||||
function createWatchStatusReporter(options?: CompilerOptions) {
|
||||
return ts.createWatchStatusReporter(sys, shouldBePretty(options));
|
||||
}
|
||||
|
||||
|
|
|
@ -2690,9 +2690,6 @@ declare namespace ts {
|
|||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
|
@ -2993,6 +2990,16 @@ declare namespace ts {
|
|||
Parameters = 1296,
|
||||
IndexSignatureParameters = 4432
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
|
@ -4312,15 +4319,26 @@ declare namespace ts {
|
|||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
|
@ -4353,14 +4371,6 @@ declare namespace ts {
|
|||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
|
@ -4636,14 +4646,6 @@ declare namespace ts {
|
|||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
|
@ -7795,6 +7797,7 @@ declare namespace ts.server.protocol {
|
|||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
interface CompilerOptions {
|
||||
allowJs?: boolean;
|
||||
|
@ -8198,6 +8201,11 @@ declare namespace ts.server {
|
|||
setTypeAcquisition(newTypeAcquisition: TypeAcquisition): void;
|
||||
}
|
||||
}
|
||||
declare namespace ts {
|
||||
interface UserPreferences {
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
}
|
||||
}
|
||||
declare namespace ts.server {
|
||||
const maxProgramSizeForNonTsFiles: number;
|
||||
const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
|
||||
|
@ -8325,7 +8333,6 @@ declare namespace ts.server {
|
|||
cancellationToken: HostCancellationToken;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
typingsInstaller: ITypingsInstaller;
|
||||
eventHandler?: ProjectServiceEventHandler;
|
||||
suppressDiagnosticEvents?: boolean;
|
||||
|
@ -8398,7 +8405,6 @@ declare namespace ts.server {
|
|||
readonly cancellationToken: HostCancellationToken;
|
||||
readonly useSingleInferredProject: boolean;
|
||||
readonly useInferredProjectPerProjectRoot: boolean;
|
||||
private readonly lazyConfiguredProjectsFromExternalProject?;
|
||||
readonly typingsInstaller: ITypingsInstaller;
|
||||
private readonly globalCacheLocationDirectoryPath;
|
||||
readonly throttleWaitMilliseconds?: number;
|
||||
|
@ -8600,7 +8606,6 @@ declare namespace ts.server {
|
|||
cancellationToken: ServerCancellationToken;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
typingsInstaller: ITypingsInstaller;
|
||||
byteLength: (buf: string, encoding?: string) => number;
|
||||
hrtime: (start?: number[]) => number[];
|
||||
|
|
46
tests/baselines/reference/api/typescript.d.ts
vendored
46
tests/baselines/reference/api/typescript.d.ts
vendored
|
@ -2690,9 +2690,6 @@ declare namespace ts {
|
|||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
createHash?(data: string): string;
|
||||
getModifiedTime?(fileName: string): Date | undefined;
|
||||
setModifiedTime?(fileName: string, date: Date): void;
|
||||
deleteFile?(fileName: string): void;
|
||||
}
|
||||
interface SourceMapRange extends TextRange {
|
||||
source?: SourceMapSource;
|
||||
|
@ -2993,6 +2990,16 @@ declare namespace ts {
|
|||
Parameters = 1296,
|
||||
IndexSignatureParameters = 4432
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
}
|
||||
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
|
||||
declare function clearTimeout(handle: any): void;
|
||||
|
@ -4312,15 +4319,26 @@ declare namespace ts {
|
|||
type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
/** Host that has watch functionality used in --watch mode */
|
||||
interface WatchHost {
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
|
||||
/**
|
||||
* Used to create the program when need for program creation or recreation detected
|
||||
*/
|
||||
createProgram: CreateProgram<T>;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
/** If provided, called with Diagnostic message that informs about change in watch status */
|
||||
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
|
@ -4353,14 +4371,6 @@ declare namespace ts {
|
|||
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
|
||||
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
|
||||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
/** Used to watch changes in source files, missing files needed to update the program or config file */
|
||||
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
|
||||
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
/** If provided, will be used to reset existing delayed compilation */
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
|
@ -4636,14 +4646,6 @@ declare namespace ts {
|
|||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
}
|
||||
interface UserPreferences {
|
||||
readonly disableSuggestions?: boolean;
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeCompletionsWithInsertText?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
}
|
||||
interface LanguageService {
|
||||
cleanupSemanticCache(): void;
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
tests/cases/compiler/noUnusedLocals_writeOnly.ts(1,12): error TS6133: 'x' is declared but its value is never read.
|
||||
tests/cases/compiler/noUnusedLocals_writeOnly.ts(10,9): error TS6133: 'z' is declared but its value is never read.
|
||||
tests/cases/compiler/noUnusedLocals_writeOnly.ts(18,9): error TS6133: 'z' is declared but its value is never read.
|
||||
|
||||
|
||||
==== tests/cases/compiler/noUnusedLocals_writeOnly.ts (2 errors) ====
|
||||
function f(x = 0) {
|
||||
function f(x = 0, b = false) {
|
||||
~
|
||||
!!! error TS6133: 'x' is declared but its value is never read.
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
x++;
|
||||
x /= 2;
|
||||
([x] = [1]);
|
||||
({ x } = { x: 1 });
|
||||
({ x: x } = { x: 1 });
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
let used = 1;
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
|
||||
let y = 0;
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
|
@ -19,4 +27,5 @@ tests/cases/compiler/noUnusedLocals_writeOnly.ts(10,9): error TS6133: 'z' is dec
|
|||
!!! error TS6133: 'z' is declared but its value is never read.
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
|
|
@ -1,8 +1,16 @@
|
|||
//// [noUnusedLocals_writeOnly.ts]
|
||||
function f(x = 0) {
|
||||
function f(x = 0, b = false) {
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
x++;
|
||||
x /= 2;
|
||||
([x] = [1]);
|
||||
({ x } = { x: 1 });
|
||||
({ x: x } = { x: 1 });
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
let used = 1;
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
|
||||
let y = 0;
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
|
@ -11,17 +19,30 @@ function f(x = 0) {
|
|||
let z = 0;
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
|
||||
|
||||
//// [noUnusedLocals_writeOnly.js]
|
||||
function f(x) {
|
||||
"use strict";
|
||||
function f(x, b) {
|
||||
if (x === void 0) { x = 0; }
|
||||
if (b === void 0) { b = false; }
|
||||
var _a, _b;
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
x++;
|
||||
x /= 2;
|
||||
(x = [1][0]);
|
||||
(x = { x: 1 }.x);
|
||||
(x = { x: 1 }.x);
|
||||
(x = { a: [{ b: 1 }] }.a[0].b);
|
||||
(_a = { x: b ? 1 : undefined }.x, x = _a === void 0 ? 2 : _a);
|
||||
var used = 1;
|
||||
(_b = { x: b ? 1 : undefined }.x, x = _b === void 0 ? used : _b);
|
||||
var y = 0;
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
f(y++);
|
||||
var z = 0;
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
}
|
||||
function f2(_) { }
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
=== tests/cases/compiler/noUnusedLocals_writeOnly.ts ===
|
||||
function f(x = 0) {
|
||||
function f(x = 0, b = false) {
|
||||
>f : Symbol(f, Decl(noUnusedLocals_writeOnly.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 0, 17))
|
||||
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
|
||||
|
@ -12,19 +14,58 @@ function f(x = 0) {
|
|||
x /= 2;
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
|
||||
([x] = [1]);
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
|
||||
({ x } = { x: 1 });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 6, 6))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 6, 14))
|
||||
|
||||
({ x: x } = { x: 1 });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 7, 6))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 7, 17))
|
||||
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
>a : Symbol(a, Decl(noUnusedLocals_writeOnly.ts, 8, 6))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 8, 12))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 0, 11))
|
||||
>a : Symbol(a, Decl(noUnusedLocals_writeOnly.ts, 8, 26))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 8, 32))
|
||||
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 9, 6))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 9, 18))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 0, 17))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
let used = 1;
|
||||
>used : Symbol(used, Decl(noUnusedLocals_writeOnly.ts, 10, 7))
|
||||
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 11, 6))
|
||||
>used : Symbol(used, Decl(noUnusedLocals_writeOnly.ts, 10, 7))
|
||||
>x : Symbol(x, Decl(noUnusedLocals_writeOnly.ts, 11, 21))
|
||||
>b : Symbol(b, Decl(noUnusedLocals_writeOnly.ts, 0, 17))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
let y = 0;
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 5, 7))
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 13, 7))
|
||||
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
f(y++);
|
||||
>f : Symbol(f, Decl(noUnusedLocals_writeOnly.ts, 0, 0))
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 5, 7))
|
||||
>y : Symbol(y, Decl(noUnusedLocals_writeOnly.ts, 13, 7))
|
||||
|
||||
let z = 0;
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 9, 7))
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 17, 7))
|
||||
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
>f : Symbol(f, Decl(noUnusedLocals_writeOnly.ts, 0, 0))
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 9, 7))
|
||||
>z : Symbol(z, Decl(noUnusedLocals_writeOnly.ts, 17, 7))
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
>f2 : Symbol(f2, Decl(noUnusedLocals_writeOnly.ts, 19, 1))
|
||||
>_ : Symbol(_, Decl(noUnusedLocals_writeOnly.ts, 20, 12))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
=== tests/cases/compiler/noUnusedLocals_writeOnly.ts ===
|
||||
function f(x = 0) {
|
||||
>f : (x?: number) => void
|
||||
function f(x = 0, b = false) {
|
||||
>f : (x?: number, b?: boolean) => void
|
||||
>x : number
|
||||
>0 : 0
|
||||
>b : boolean
|
||||
>false : false
|
||||
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
>x = 1 : 1
|
||||
>x : number
|
||||
|
@ -18,6 +21,79 @@ function f(x = 0) {
|
|||
>x : number
|
||||
>2 : 2
|
||||
|
||||
([x] = [1]);
|
||||
>([x] = [1]) : [number]
|
||||
>[x] = [1] : [number]
|
||||
>[x] : [number]
|
||||
>x : number
|
||||
>[1] : [number]
|
||||
>1 : 1
|
||||
|
||||
({ x } = { x: 1 });
|
||||
>({ x } = { x: 1 }) : { x: number; }
|
||||
>{ x } = { x: 1 } : { x: number; }
|
||||
>{ x } : { x: number; }
|
||||
>x : number
|
||||
>{ x: 1 } : { x: number; }
|
||||
>x : number
|
||||
>1 : 1
|
||||
|
||||
({ x: x } = { x: 1 });
|
||||
>({ x: x } = { x: 1 }) : { x: number; }
|
||||
>{ x: x } = { x: 1 } : { x: number; }
|
||||
>{ x: x } : { x: number; }
|
||||
>x : number
|
||||
>x : number
|
||||
>{ x: 1 } : { x: number; }
|
||||
>x : number
|
||||
>1 : 1
|
||||
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
>({ a: [{ b: x }] } = { a: [{ b: 1 }] }) : { a: [{ b: number; }]; }
|
||||
>{ a: [{ b: x }] } = { a: [{ b: 1 }] } : { a: [{ b: number; }]; }
|
||||
>{ a: [{ b: x }] } : { a: [{ b: number; }]; }
|
||||
>a : [{ b: number; }]
|
||||
>[{ b: x }] : [{ b: number; }]
|
||||
>{ b: x } : { b: number; }
|
||||
>b : number
|
||||
>x : number
|
||||
>{ a: [{ b: 1 }] } : { a: [{ b: number; }]; }
|
||||
>a : [{ b: number; }]
|
||||
>[{ b: 1 }] : [{ b: number; }]
|
||||
>{ b: 1 } : { b: number; }
|
||||
>b : number
|
||||
>1 : 1
|
||||
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
>({ x = 2 } = { x: b ? 1 : undefined }) : { x?: number | undefined; }
|
||||
>{ x = 2 } = { x: b ? 1 : undefined } : { x?: number | undefined; }
|
||||
>{ x = 2 } : { x?: number; }
|
||||
>x : number
|
||||
>2 : 2
|
||||
>{ x: b ? 1 : undefined } : { x?: number | undefined; }
|
||||
>x : number | undefined
|
||||
>b ? 1 : undefined : 1 | undefined
|
||||
>b : boolean
|
||||
>1 : 1
|
||||
>undefined : undefined
|
||||
|
||||
let used = 1;
|
||||
>used : number
|
||||
>1 : 1
|
||||
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
>({ x = used } = { x: b ? 1 : undefined }) : { x?: number | undefined; }
|
||||
>{ x = used } = { x: b ? 1 : undefined } : { x?: number | undefined; }
|
||||
>{ x = used } : { x?: number; }
|
||||
>x : number
|
||||
>used : number
|
||||
>{ x: b ? 1 : undefined } : { x?: number | undefined; }
|
||||
>x : number | undefined
|
||||
>b ? 1 : undefined : 1 | undefined
|
||||
>b : boolean
|
||||
>1 : 1
|
||||
>undefined : undefined
|
||||
|
||||
let y = 0;
|
||||
>y : number
|
||||
>0 : 0
|
||||
|
@ -25,7 +101,7 @@ function f(x = 0) {
|
|||
// This is a write access to y, but not a write-*only* access.
|
||||
f(y++);
|
||||
>f(y++) : void
|
||||
>f : (x?: number) => void
|
||||
>f : (x?: number, b?: boolean) => void
|
||||
>y++ : number
|
||||
>y : number
|
||||
|
||||
|
@ -35,9 +111,12 @@ function f(x = 0) {
|
|||
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
>f(z = 1) : void
|
||||
>f : (x?: number) => void
|
||||
>f : (x?: number, b?: boolean) => void
|
||||
>z = 1 : 1
|
||||
>z : number
|
||||
>1 : 1
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
>f2 : (_: ReadonlyArray<number>) => void
|
||||
>_ : ReadonlyArray<number>
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(3,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
|
||||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(8,27): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
|
||||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(13,20): error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
|
||||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(21,18): error TS2372: Parameter 'a' cannot be referenced in its initializer.
|
||||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(25,22): error TS2372: Parameter 'async' cannot be referenced in its initializer.
|
||||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts(29,15): error TS2448: Block-scoped variable 'foo' used before its declaration.
|
||||
|
||||
|
||||
==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts (6 errors) ====
|
||||
let foo: string = "";
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
~~~
|
||||
!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
|
||||
var foo: number = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
~~~
|
||||
!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
|
||||
var foo: number = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
~~~
|
||||
!!! error TS2373: Initializer of parameter 'bar' cannot reference identifier 'foo' declared after it.
|
||||
return bar;
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
return bar
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
~
|
||||
!!! error TS2372: Parameter 'a' cannot be referenced in its initializer.
|
||||
return a
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
~~~~~
|
||||
!!! error TS2372: Parameter 'async' cannot be referenced in its initializer.
|
||||
return async
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
~~~
|
||||
!!! error TS2448: Block-scoped variable 'foo' used before its declaration.
|
||||
!!! related TS2728 tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts:30:9: 'foo' is declared here.
|
||||
let foo: number = 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
//// [parameterInitializersForwardReferencing1.ts]
|
||||
let foo: string = "";
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
return bar;
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
return bar
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
return a
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
return async
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
let foo: number = 2;
|
||||
}
|
||||
|
||||
|
||||
//// [parameterInitializersForwardReferencing1.js]
|
||||
var foo = "";
|
||||
function f1(bar) {
|
||||
if (bar === void 0) { bar = foo; }
|
||||
var foo = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
function f2(bar) {
|
||||
if (bar === void 0) { bar = function (baz) {
|
||||
if (baz === void 0) { baz = foo; }
|
||||
return baz;
|
||||
}; }
|
||||
var foo = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
function f3(bar, foo) {
|
||||
if (bar === void 0) { bar = foo; }
|
||||
if (foo === void 0) { foo = 2; }
|
||||
return bar;
|
||||
}
|
||||
function f4(foo, bar) {
|
||||
if (bar === void 0) { bar = foo; }
|
||||
return bar;
|
||||
}
|
||||
function f5(a) {
|
||||
if (a === void 0) { a = a; }
|
||||
return a;
|
||||
}
|
||||
function f6(async) {
|
||||
if (async === void 0) { async = async; }
|
||||
return async;
|
||||
}
|
||||
function f7(_a) {
|
||||
var _b = foo, bar = _a[_b];
|
||||
var foo = 2;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
=== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts ===
|
||||
let foo: string = "";
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 0, 3))
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
>f1 : Symbol(f1, Decl(parameterInitializersForwardReferencing1.ts, 0, 21))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 2, 13))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 3, 7))
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 3, 7))
|
||||
|
||||
return bar; // returns 1
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 2, 13))
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
>f2 : Symbol(f2, Decl(parameterInitializersForwardReferencing1.ts, 5, 1))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 7, 13))
|
||||
>baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1.ts, 7, 20))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 8, 7))
|
||||
>baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1.ts, 7, 20))
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 8, 7))
|
||||
|
||||
return bar(); // returns 1
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 7, 13))
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
>f3 : Symbol(f3, Decl(parameterInitializersForwardReferencing1.ts, 10, 1))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 12, 13))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 12, 23))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 12, 23))
|
||||
|
||||
return bar;
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 12, 13))
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
>f4 : Symbol(f4, Decl(parameterInitializersForwardReferencing1.ts, 14, 1))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 16, 13))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 16, 17))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 16, 13))
|
||||
|
||||
return bar
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 16, 17))
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
>f5 : Symbol(f5, Decl(parameterInitializersForwardReferencing1.ts, 18, 1))
|
||||
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1.ts, 20, 13))
|
||||
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1.ts, 20, 13))
|
||||
|
||||
return a
|
||||
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1.ts, 20, 13))
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
>f6 : Symbol(f6, Decl(parameterInitializersForwardReferencing1.ts, 22, 1))
|
||||
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1.ts, 24, 13))
|
||||
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1.ts, 24, 13))
|
||||
|
||||
return async
|
||||
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1.ts, 24, 13))
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
>f7 : Symbol(f7, Decl(parameterInitializersForwardReferencing1.ts, 26, 1))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 29, 7))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1.ts, 28, 13))
|
||||
|
||||
let foo: number = 2;
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1.ts, 29, 7))
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
=== tests/cases/conformance/functions/parameterInitializersForwardReferencing1.ts ===
|
||||
let foo: string = "";
|
||||
>foo : string
|
||||
>"" : ""
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
>f1 : (bar?: number) => number
|
||||
>bar : number
|
||||
>foo : number
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : number
|
||||
>2 : 2
|
||||
|
||||
return bar; // returns 1
|
||||
>bar : number
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
>f2 : (bar?: (baz?: number) => number) => number
|
||||
>bar : (baz?: number) => number
|
||||
>(baz = foo) => baz : (baz?: number) => number
|
||||
>baz : number
|
||||
>foo : number
|
||||
>baz : number
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : number
|
||||
>2 : 2
|
||||
|
||||
return bar(); // returns 1
|
||||
>bar() : number
|
||||
>bar : (baz?: number) => number
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
>f3 : (bar?: number, foo?: number) => number
|
||||
>bar : number
|
||||
>foo : number
|
||||
>foo : number
|
||||
>2 : 2
|
||||
|
||||
return bar;
|
||||
>bar : number
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
>f4 : (foo: any, bar?: any) => any
|
||||
>foo : any
|
||||
>bar : any
|
||||
>foo : any
|
||||
|
||||
return bar
|
||||
>bar : any
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
>f5 : (a?: any) => any
|
||||
>a : any
|
||||
>a : any
|
||||
|
||||
return a
|
||||
>a : any
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
>f6 : (async?: any) => any
|
||||
>async : any
|
||||
>async : any
|
||||
|
||||
return async
|
||||
>async : any
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
>f7 : ({ [foo]: bar }: any[]) => void
|
||||
>foo : number
|
||||
>bar : any
|
||||
|
||||
let foo: number = 2;
|
||||
>foo : number
|
||||
>2 : 2
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(21,18): error TS2372: Parameter 'a' cannot be referenced in its initializer.
|
||||
tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts(25,22): error TS2372: Parameter 'async' cannot be referenced in its initializer.
|
||||
|
||||
|
||||
==== tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts (2 errors) ====
|
||||
let foo: string = "";
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
return bar;
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
return bar
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
~
|
||||
!!! error TS2372: Parameter 'a' cannot be referenced in its initializer.
|
||||
return a
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
~~~~~
|
||||
!!! error TS2372: Parameter 'async' cannot be referenced in its initializer.
|
||||
return async
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
let foo: number = 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
//// [parameterInitializersForwardReferencing1_es6.ts]
|
||||
let foo: string = "";
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
return bar;
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
return bar
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
return a
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
return async
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
let foo: number = 2;
|
||||
}
|
||||
|
||||
|
||||
//// [parameterInitializersForwardReferencing1_es6.js]
|
||||
let foo = "";
|
||||
function f1(bar = foo) {
|
||||
var foo = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
function f2(bar = (baz = foo) => baz) {
|
||||
var foo = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
function f3(bar = foo, foo = 2) {
|
||||
return bar;
|
||||
}
|
||||
function f4(foo, bar = foo) {
|
||||
return bar;
|
||||
}
|
||||
function f5(a = a) {
|
||||
return a;
|
||||
}
|
||||
function f6(async = async) {
|
||||
return async;
|
||||
}
|
||||
function f7({ [foo]: bar }) {
|
||||
let foo = 2;
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
=== tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts ===
|
||||
let foo: string = "";
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3))
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
>f1 : Symbol(f1, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 21))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 2, 13))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3))
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 3, 7))
|
||||
|
||||
return bar; // returns 1
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 2, 13))
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
>f2 : Symbol(f2, Decl(parameterInitializersForwardReferencing1_es6.ts, 5, 1))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 7, 13))
|
||||
>baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1_es6.ts, 7, 20))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3))
|
||||
>baz : Symbol(baz, Decl(parameterInitializersForwardReferencing1_es6.ts, 7, 20))
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 8, 7))
|
||||
|
||||
return bar(); // returns 1
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 7, 13))
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
>f3 : Symbol(f3, Decl(parameterInitializersForwardReferencing1_es6.ts, 10, 1))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 12, 13))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 12, 23))
|
||||
|
||||
return bar;
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 12, 13))
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
>f4 : Symbol(f4, Decl(parameterInitializersForwardReferencing1_es6.ts, 14, 1))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 16, 13))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 16, 17))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3))
|
||||
|
||||
return bar
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 16, 17))
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
>f5 : Symbol(f5, Decl(parameterInitializersForwardReferencing1_es6.ts, 18, 1))
|
||||
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1_es6.ts, 20, 13))
|
||||
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1_es6.ts, 20, 13))
|
||||
|
||||
return a
|
||||
>a : Symbol(a, Decl(parameterInitializersForwardReferencing1_es6.ts, 20, 13))
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
>f6 : Symbol(f6, Decl(parameterInitializersForwardReferencing1_es6.ts, 22, 1))
|
||||
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1_es6.ts, 24, 13))
|
||||
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1_es6.ts, 24, 13))
|
||||
|
||||
return async
|
||||
>async : Symbol(async, Decl(parameterInitializersForwardReferencing1_es6.ts, 24, 13))
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
>f7 : Symbol(f7, Decl(parameterInitializersForwardReferencing1_es6.ts, 26, 1))
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 0, 3))
|
||||
>bar : Symbol(bar, Decl(parameterInitializersForwardReferencing1_es6.ts, 28, 13))
|
||||
|
||||
let foo: number = 2;
|
||||
>foo : Symbol(foo, Decl(parameterInitializersForwardReferencing1_es6.ts, 29, 7))
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
=== tests/cases/conformance/functions/parameterInitializersForwardReferencing1_es6.ts ===
|
||||
let foo: string = "";
|
||||
>foo : string
|
||||
>"" : ""
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
>f1 : (bar?: string) => string
|
||||
>bar : string
|
||||
>foo : string
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : number
|
||||
>2 : 2
|
||||
|
||||
return bar; // returns 1
|
||||
>bar : string
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
>f2 : (bar?: (baz?: string) => string) => string
|
||||
>bar : (baz?: string) => string
|
||||
>(baz = foo) => baz : (baz?: string) => string
|
||||
>baz : string
|
||||
>foo : string
|
||||
>baz : string
|
||||
|
||||
var foo: number = 2;
|
||||
>foo : number
|
||||
>2 : 2
|
||||
|
||||
return bar(); // returns 1
|
||||
>bar() : string
|
||||
>bar : (baz?: string) => string
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
>f3 : (bar?: string, foo?: number) => string
|
||||
>bar : string
|
||||
>foo : string
|
||||
>foo : number
|
||||
>2 : 2
|
||||
|
||||
return bar;
|
||||
>bar : string
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
>f4 : (foo: any, bar?: string) => string
|
||||
>foo : any
|
||||
>bar : string
|
||||
>foo : string
|
||||
|
||||
return bar
|
||||
>bar : string
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
>f5 : (a?: any) => any
|
||||
>a : any
|
||||
>a : any
|
||||
|
||||
return a
|
||||
>a : any
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
>f6 : (async?: any) => any
|
||||
>async : any
|
||||
>async : any
|
||||
|
||||
return async
|
||||
>async : any
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
>f7 : ({ [foo]: bar }: any[]) => void
|
||||
>foo : string
|
||||
>bar : any
|
||||
|
||||
let foo: number = 2;
|
||||
>foo : number
|
||||
>2 : 2
|
||||
}
|
||||
|
|
@ -1,10 +1,19 @@
|
|||
// @strict: true
|
||||
// @noUnusedLocals: true
|
||||
// @noUnusedParameters: true
|
||||
|
||||
function f(x = 0) {
|
||||
function f(x = 0, b = false) {
|
||||
// None of these statements read from 'x', so it will be marked unused.
|
||||
x = 1;
|
||||
x++;
|
||||
x /= 2;
|
||||
([x] = [1]);
|
||||
({ x } = { x: 1 });
|
||||
({ x: x } = { x: 1 });
|
||||
({ a: [{ b: x }] } = { a: [{ b: 1 }] });
|
||||
({ x = 2 } = { x: b ? 1 : undefined });
|
||||
let used = 1;
|
||||
({ x = used } = { x: b ? 1 : undefined });
|
||||
|
||||
let y = 0;
|
||||
// This is a write access to y, but not a write-*only* access.
|
||||
|
@ -13,3 +22,4 @@ function f(x = 0) {
|
|||
let z = 0;
|
||||
f(z = 1); // This effectively doesn't use `z`, values just pass through it.
|
||||
}
|
||||
function f2(_: ReadonlyArray<number>): void {}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
let foo: string = "";
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
return bar;
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
return bar
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
return a
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
return async
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
let foo: number = 2;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
// @target: es2015
|
||||
|
||||
let foo: string = "";
|
||||
|
||||
function f1 (bar = foo) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar; // returns 1
|
||||
}
|
||||
|
||||
function f2 (bar = (baz = foo) => baz) { // unexpected compiler error; works at runtime
|
||||
var foo: number = 2;
|
||||
return bar(); // returns 1
|
||||
}
|
||||
|
||||
function f3 (bar = foo, foo = 2) { // correct compiler error, error at runtime
|
||||
return bar;
|
||||
}
|
||||
|
||||
function f4 (foo, bar = foo) {
|
||||
return bar
|
||||
}
|
||||
|
||||
function f5 (a = a) {
|
||||
return a
|
||||
}
|
||||
|
||||
function f6 (async = async) {
|
||||
return async
|
||||
}
|
||||
|
||||
function f7({[foo]: bar}: any[]) {
|
||||
let foo: number = 2;
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
////fooB/*1*/
|
||||
|
||||
goTo.marker("0");
|
||||
const preferences = { includeCompletionsForModuleExports: true };
|
||||
const preferences: FourSlashInterface.UserPreferences = { includeCompletionsForModuleExports: true };
|
||||
verify.completions(
|
||||
{ marker: "0", excludes: { name: "default", source: "/src/foo-bar" }, preferences },
|
||||
{ marker: "1", includes: { name: "fooBar", source: "/src/foo-bar", sourceDisplay: "./foo-bar", text: "(property) default: 0", kind: "property", hasAction: true }, preferences }
|
||||
|
|
53
tests/cases/fourslash/completionsImport_exportEquals.ts
Normal file
53
tests/cases/fourslash/completionsImport_exportEquals.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: commonjs
|
||||
|
||||
// @Filename: /a.d.ts
|
||||
////declare function a(): void;
|
||||
////declare namespace a {
|
||||
//// export interface b {}
|
||||
////}
|
||||
////export = a;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////a/*0*/;
|
||||
////let x: b/*1*/;
|
||||
|
||||
const preferences: FourSlashInterface.UserPreferences = { includeCompletionsForModuleExports: true };
|
||||
verify.completions(
|
||||
{
|
||||
marker: "0",
|
||||
includes: { name: "a", source: "/a", hasAction: true, },
|
||||
preferences,
|
||||
},
|
||||
{
|
||||
marker: "1",
|
||||
includes: { name: "b", source: "/a", hasAction: true },
|
||||
preferences,
|
||||
}
|
||||
);
|
||||
|
||||
// Import { b } first, or it will just add a qualified name from 'a' (which isn't what we're trying to test)
|
||||
verify.applyCodeActionFromCompletion("1", {
|
||||
name: "b",
|
||||
source: "/a",
|
||||
description: `Import 'b' from module "./a"`,
|
||||
newFileContent:
|
||||
`import { b } from "./a";
|
||||
|
||||
a;
|
||||
let x: b;`,
|
||||
});
|
||||
|
||||
verify.applyCodeActionFromCompletion("0", {
|
||||
name: "a",
|
||||
source: "/a",
|
||||
description: `Import 'a' from module "./a"`,
|
||||
newFileContent:
|
||||
`import { b } from "./a";
|
||||
import a = require("./a");
|
||||
|
||||
a;
|
||||
let x: b;`,
|
||||
});
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
verify.completions({
|
||||
marker: "",
|
||||
// Tester will assert that it is only included once
|
||||
includes: [{ name: "foo", hasAction: true }],
|
||||
includes: [{ name: "foo", source: "a", hasAction: true }],
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true,
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
verify.completions({
|
||||
marker: "",
|
||||
includes: { name: "Foo", source: "/a.tsx", hasAction: true },
|
||||
includes: { name: "Foo", source: "/a", hasAction: true },
|
||||
excludes: "Bar",
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true,
|
||||
|
|
|
@ -24,7 +24,7 @@ verify.completions({
|
|||
marker: "",
|
||||
exact: [
|
||||
"n",
|
||||
{ name: "publicSym", insertText: "[publicSym]", replacementSpan: test.ranges()[0], hasAction: true },
|
||||
{ name: "publicSym", source: "/a", insertText: "[publicSym]", replacementSpan: test.ranges()[0], hasAction: true },
|
||||
],
|
||||
preferences: {
|
||||
includeInsertTextCompletions: true,
|
||||
|
|
|
@ -528,10 +528,11 @@ declare namespace FourSlashInterface {
|
|||
filesToSearch?: ReadonlyArray<string>;
|
||||
}
|
||||
interface UserPreferences {
|
||||
quotePreference?: "double" | "single";
|
||||
includeCompletionsForModuleExports?: boolean;
|
||||
includeInsertTextCompletions?: boolean;
|
||||
importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly quotePreference?: "double" | "single";
|
||||
readonly includeCompletionsForModuleExports?: boolean;
|
||||
readonly includeInsertTextCompletions?: boolean;
|
||||
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
}
|
||||
interface CompletionsAtOptions extends UserPreferences {
|
||||
triggerCharacter?: string;
|
||||
|
|
|
@ -11,21 +11,37 @@
|
|||
////var x : testClass</*type2*/
|
||||
////class Bar<T> extends testClass</*type3*/
|
||||
////var x : testClass<,, /*type4*/any>;
|
||||
////
|
||||
////interface I<T> {}
|
||||
////let i: I</*interface*/>;
|
||||
////
|
||||
////type Ty<T> = T;
|
||||
////let t: Ty</*typeAlias*/>;
|
||||
|
||||
// TODO: GH#26699
|
||||
|
||||
if (false) {
|
||||
verify.signatureHelp(
|
||||
{
|
||||
marker: ["type1", "type2", "type3"],
|
||||
text: "testClass<T extends IFoo, U, M extends IFoo>",
|
||||
parameterName: "T",
|
||||
parameterSpan: "T extends IFoo",
|
||||
},
|
||||
{
|
||||
marker: "type4",
|
||||
parameterName: "M",
|
||||
parameterSpan: "M extends IFoo",
|
||||
}
|
||||
);
|
||||
}
|
||||
verify.signatureHelp(
|
||||
{
|
||||
marker: ["type1", "type2", "type3"],
|
||||
text: "testClass<T extends IFoo, U, M extends IFoo>",
|
||||
parameterName: "T",
|
||||
parameterSpan: "T extends IFoo",
|
||||
triggerReason: { kind: "characterTyped", triggerCharacter: "<" },
|
||||
},
|
||||
{
|
||||
marker: "type4",
|
||||
parameterName: "M",
|
||||
parameterSpan: "M extends IFoo",
|
||||
triggerReason: { kind: "characterTyped", triggerCharacter: "," },
|
||||
},
|
||||
{
|
||||
marker: "interface",
|
||||
text: "I<T>",
|
||||
parameterName: "T",
|
||||
parameterSpan: "T",
|
||||
},
|
||||
{
|
||||
marker: "typeAlias",
|
||||
text: "Ty<T>",
|
||||
parameterName: "T",
|
||||
parameterSpan: "T",
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @strict: true
|
||||
// @jsx: preserve
|
||||
// @resolveJsonModule: true
|
||||
|
||||
// @Filename: /index.js
|
||||
////export const x = 0;
|
||||
|
||||
// @Filename: /jsx.jsx
|
||||
////export const y = 0;
|
||||
|
||||
// @Filename: /j.jonah.json
|
||||
////{ "j": 0 }
|
||||
|
||||
// @Filename: /a.js
|
||||
////import { x as x0 } from ".";
|
||||
////import { x as x1 } from "./index";
|
||||
////import { x as x2 } from "./index.js";
|
||||
////import { y } from "./jsx.jsx";
|
||||
////import { j } from "./j.jonah.json";
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
verify.getEditsForFileRename({
|
||||
oldPath: "/a.js",
|
||||
newPath: "/b.js",
|
||||
newFileContents: {}, // No change
|
||||
});
|
||||
|
||||
verify.getEditsForFileRename({
|
||||
oldPath: "/b.js",
|
||||
newPath: "/src/b.js",
|
||||
newFileContents: {
|
||||
"/b.js":
|
||||
`import { x as x0 } from "..";
|
||||
import { x as x1 } from "../index";
|
||||
import { x as x2 } from "../index.js";
|
||||
import { y } from "../jsx.jsx";
|
||||
import { j } from "../j.jonah.json";`,
|
||||
},
|
||||
});
|
|
@ -21,9 +21,20 @@
|
|||
////o.[|/*useM*/m|]();
|
||||
|
||||
////class Component { /*componentCtr*/constructor(props: {}) {} }
|
||||
////type ComponentClass = /*ComponentClass*/new () => Component;
|
||||
////interface ComponentClass2 { /*ComponentClass2*/new(): Component; }
|
||||
////
|
||||
////class /*MyComponent*/MyComponent extends Component {}
|
||||
////<[|/*jsxMyComponent*/MyComponent|] />
|
||||
////<[|/*jsxMyComponent*/MyComponent|] />;
|
||||
////new [|/*newMyComponent*/MyComponent|]({});
|
||||
////
|
||||
////declare const /*MyComponent2*/MyComponent2: ComponentClass;
|
||||
////<[|/*jsxMyComponent2*/MyComponent2|] />;
|
||||
////new [|/*newMyComponent2*/MyComponent2|]();
|
||||
////
|
||||
////declare const /*MyComponent3*/MyComponent3: ComponentClass2;
|
||||
////<[|/*jsxMyComponent3*/MyComponent3|] />;
|
||||
////new [|/*newMyComponent3*/MyComponent3|]();
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
|
@ -38,4 +49,10 @@ verify.goToDefinition({
|
|||
|
||||
jsxMyComponent: "MyComponent",
|
||||
newMyComponent: ["MyComponent", "componentCtr"],
|
||||
|
||||
jsxMyComponent2: "MyComponent2",
|
||||
newMyComponent2: ["MyComponent2", "ComponentClass"],
|
||||
|
||||
jsxMyComponent3: "MyComponent3",
|
||||
newMyComponent3: ["MyComponent3", "ComponentClass2"],
|
||||
});
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: a/f1.ts
|
||||
//// [|foo/*0*/();|]
|
||||
|
||||
// @Filename: types/random/index.ts
|
||||
//// export function foo() {};
|
||||
|
||||
// @Filename: tsconfig.json
|
||||
//// {
|
||||
//// "compilerOptions": {
|
||||
//// "typeRoots": [
|
||||
//// "./types"
|
||||
//// ]
|
||||
//// }
|
||||
//// }
|
||||
|
||||
verify.importFixAtPosition([
|
||||
`import { foo } from "random";
|
||||
|
||||
foo();`
|
||||
]);
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: a/f1.ts
|
||||
//// [|foo/*0*/();|]
|
||||
|
||||
// @Filename: types/random/index.ts
|
||||
//// export function foo() {};
|
||||
|
||||
// @Filename: tsconfig.json
|
||||
//// {
|
||||
//// "compilerOptions": {
|
||||
//// "typeRoots": [
|
||||
//// "./types"
|
||||
//// ]
|
||||
//// }
|
||||
//// }
|
||||
|
||||
// "typeRoots" does not affect module resolution. Importing from "random" would be a compile error.
|
||||
verify.importFixAtPosition([
|
||||
`import { foo } from "../types/random";
|
||||
|
||||
foo();`
|
||||
]);
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: a/f1.ts
|
||||
//// [|foo/*0*/();|]
|
||||
|
||||
// @Filename: types/random/index.ts
|
||||
//// export function foo() {};
|
||||
|
||||
// @Filename: tsconfig.json
|
||||
//// {
|
||||
//// "compilerOptions": {
|
||||
//// "baseUrl": ".",
|
||||
//// "typeRoots": [
|
||||
//// "./types"
|
||||
//// ]
|
||||
//// }
|
||||
//// }
|
||||
|
||||
verify.importFixAtPosition([
|
||||
`import { foo } from "random";
|
||||
|
||||
foo();`
|
||||
]);
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: a/f1.ts
|
||||
//// [|foo/*0*/();|]
|
||||
|
||||
// @Filename: types/random/index.ts
|
||||
//// export function foo() {};
|
||||
|
||||
// @Filename: tsconfig.json
|
||||
//// {
|
||||
//// "compilerOptions": {
|
||||
//// "baseUrl": ".",
|
||||
//// "typeRoots": [
|
||||
//// "./types"
|
||||
//// ]
|
||||
//// }
|
||||
//// }
|
||||
|
||||
// "typeRoots" does not affect module resolution. Importing from "random" would be a compile error.
|
||||
verify.importFixAtPosition([
|
||||
`import { foo } from "types/random";
|
||||
|
||||
foo();`,
|
||||
`import { foo } from "../types/random";
|
||||
|
||||
foo();`
|
||||
]);
|
||||
|
|
|
@ -37,11 +37,11 @@ verify.codeFixAll({
|
|||
fixId: "fixMissingImport",
|
||||
fixAllDescription: "Add all missing imports",
|
||||
newFileContent:
|
||||
// TODO: GH#25135 (should import 'e')
|
||||
`import bd, * as b from "./b";
|
||||
import cd, { c0 } from "./c";
|
||||
import dd, { d0, d1 } from "./d";
|
||||
import ad, { a0 } from "./a";
|
||||
import e = require("./e");
|
||||
|
||||
ad; ad; a0; a0;
|
||||
bd; bd; b.b0; b.b0;
|
||||
|
|
26
tests/cases/fourslash/importNameCodeFix_endingPreference.ts
Normal file
26
tests/cases/fourslash/importNameCodeFix_endingPreference.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @moduleResolution: node
|
||||
|
||||
// @Filename: /foo/index.ts
|
||||
////export const foo = 0;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////foo;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////foo;
|
||||
|
||||
// @Filename: /c.ts
|
||||
////foo;
|
||||
|
||||
const tests: ReadonlyArray<[string, FourSlashInterface.UserPreferences["importModuleSpecifierEnding"], string]> = [
|
||||
["/a.ts", "js", "./foo/index.js"],
|
||||
["/b.ts", "index", "./foo/index"],
|
||||
["/c.ts", "minimal", "./foo"],
|
||||
];
|
||||
|
||||
for (const [fileName, importModuleSpecifierEnding, specifier] of tests) {
|
||||
goTo.file(fileName);
|
||||
verify.importFixAtPosition([`import { foo } from "${specifier}";\n\nfoo;`,], /*errorCode*/ undefined, { importModuleSpecifierEnding });
|
||||
}
|
25
tests/cases/fourslash/importNameCodeFix_exportEquals.ts
Normal file
25
tests/cases/fourslash/importNameCodeFix_exportEquals.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.d.ts
|
||||
////declare function a(): void;
|
||||
////declare namespace a {
|
||||
//// export interface b {}
|
||||
////}
|
||||
////export = a;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////a;
|
||||
////let x: b;
|
||||
|
||||
goTo.file("/b.ts");
|
||||
verify.codeFixAll({
|
||||
fixId: "fixMissingImport",
|
||||
fixAllDescription: "Add all missing imports",
|
||||
newFileContent:
|
||||
`import { b } from "./a";
|
||||
|
||||
import a = require("./a");
|
||||
|
||||
a;
|
||||
let x: b;`,
|
||||
});
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
// @moduleResolution: node
|
||||
// @noLib: true
|
||||
// @jsx: preserve
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export function a() {}
|
||||
|
@ -9,17 +10,24 @@
|
|||
// @Filename: /b.ts
|
||||
////export function b() {}
|
||||
|
||||
// @Filename: /c.tsx
|
||||
////export function c() {}
|
||||
|
||||
// @Filename: /c.ts
|
||||
////import * as g from "global"; // Global imports skipped
|
||||
////import { a } from "./a.js";
|
||||
////import { a as a2 } from "./a"; // Ignored, only the first relative import is considered
|
||||
////b;
|
||||
////b; c;
|
||||
|
||||
goTo.file("/c.ts");
|
||||
verify.importFixAtPosition([
|
||||
verify.codeFixAll({
|
||||
fixId: "fixMissingImport",
|
||||
fixAllDescription: "Add all missing imports",
|
||||
newFileContent:
|
||||
`import * as g from "global"; // Global imports skipped
|
||||
import { a } from "./a.js";
|
||||
import { a as a2 } from "./a"; // Ignored, only the first relative import is considered
|
||||
import { b } from "./b.js";
|
||||
b;`,
|
||||
]);
|
||||
import { c } from "./c.jsx";
|
||||
b; c;`,
|
||||
});
|
||||
|
|
|
@ -5,12 +5,22 @@
|
|||
// @Filename: /node_modules/@types/foo/index.d.ts
|
||||
////export const xyz: number;
|
||||
|
||||
// @Filename: /node_modules/bar/index.d.ts
|
||||
////export const qrs: number;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////[|xyz|]
|
||||
////xyz;
|
||||
////qrs;
|
||||
|
||||
goTo.file("/a.ts");
|
||||
verify.importFixAtPosition([
|
||||
verify.codeFixAll({
|
||||
fixId: "fixMissingImport",
|
||||
fixAllDescription: "Add all missing imports",
|
||||
newFileContent:
|
||||
`import { xyz } from "foo";
|
||||
|
||||
xyz`
|
||||
]);
|
||||
import { qrs } from "./node_modules/bar/index";
|
||||
|
||||
xyz;
|
||||
qrs;`,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue