mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into removeWhitespace
This commit is contained in:
+44
-5
@@ -1211,7 +1211,7 @@ namespace ts {
|
||||
bind(node.statement);
|
||||
popActiveLabel();
|
||||
if (!activeLabel.referenced && !options.allowUnusedLabels) {
|
||||
errorOrSuggestionOnFirstToken(unusedLabelIsError(options), node, Diagnostics.Unused_label);
|
||||
errorOrSuggestionOnNode(unusedLabelIsError(options), node.label, Diagnostics.Unused_label);
|
||||
}
|
||||
if (!node.statement || node.statement.kind !== SyntaxKind.DoStatement) {
|
||||
// do statement sets current flow inside bindDoStatement
|
||||
@@ -1918,9 +1918,16 @@ namespace ts {
|
||||
file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
function errorOrSuggestionOnFirstToken(isError: boolean, node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any) {
|
||||
const span = getSpanOfTokenAtPosition(file, node.pos);
|
||||
const diag = createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2);
|
||||
function errorOrSuggestionOnNode(isError: boolean, node: Node, message: DiagnosticMessage): void {
|
||||
errorOrSuggestionOnRange(isError, node, node, message);
|
||||
}
|
||||
|
||||
function errorOrSuggestionOnRange(isError: boolean, startNode: Node, endNode: Node, message: DiagnosticMessage): void {
|
||||
addErrorOrSuggestionDiagnostic(isError, { pos: getTokenPosOfNode(startNode, file), end: endNode.end }, message);
|
||||
}
|
||||
|
||||
function addErrorOrSuggestionDiagnostic(isError: boolean, range: TextRange, message: DiagnosticMessage): void {
|
||||
const diag = createFileDiagnostic(file, range.pos, range.end - range.pos, message);
|
||||
if (isError) {
|
||||
file.bindDiagnostics.push(diag);
|
||||
}
|
||||
@@ -2792,7 +2799,7 @@ namespace ts {
|
||||
node.declarationList.declarations.some(d => !!d.initializer)
|
||||
);
|
||||
|
||||
errorOrSuggestionOnFirstToken(isError, node, Diagnostics.Unreachable_code_detected);
|
||||
eachUnreachableRange(node, (start, end) => errorOrSuggestionOnRange(isError, start, end, Diagnostics.Unreachable_code_detected));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2800,6 +2807,38 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function eachUnreachableRange(node: Node, cb: (start: Node, last: Node) => void): void {
|
||||
if (isStatement(node) && isExecutableStatement(node) && isBlock(node.parent)) {
|
||||
const { statements } = node.parent;
|
||||
const slice = sliceAfter(statements, node);
|
||||
getRangesWhere(slice, isExecutableStatement, (start, afterEnd) => cb(slice[start], slice[afterEnd - 1]));
|
||||
}
|
||||
else {
|
||||
cb(node, node);
|
||||
}
|
||||
}
|
||||
// As opposed to a pure declaration like an `interface`
|
||||
function isExecutableStatement(s: Statement): boolean {
|
||||
// Don't remove statements that can validly be used before they appear.
|
||||
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
|
||||
// `var x;` may declare a variable used above
|
||||
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
|
||||
}
|
||||
|
||||
function isPurelyTypeDeclaration(s: Statement): boolean {
|
||||
switch (s.kind) {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return getModuleInstanceState(s as ModuleDeclaration) !== ModuleInstanceState.Instantiated;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return hasModifier(s, ModifierFlags.Const);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Expression): boolean {
|
||||
return isExportsIdentifier(node) ||
|
||||
|
||||
+40
-13
@@ -1059,6 +1059,7 @@ namespace ts {
|
||||
// 5. inside a TS export= declaration (since we will move the export statement during emit to avoid TDZ)
|
||||
// or if usage is in a type context:
|
||||
// 1. inside a type query (typeof in type position)
|
||||
// 2. inside a jsdoc comment
|
||||
if (usage.parent.kind === SyntaxKind.ExportSpecifier || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals)) {
|
||||
// export specifiers do not use the variable, they only make it available for use
|
||||
return true;
|
||||
@@ -1069,7 +1070,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const container = getEnclosingBlockScopeContainer(declaration);
|
||||
return isInTypeQuery(usage) || isUsedInFunctionOrInstanceProperty(usage, declaration, container);
|
||||
return !!(usage.flags & NodeFlags.JSDoc) || isInTypeQuery(usage) || isUsedInFunctionOrInstanceProperty(usage, declaration, container);
|
||||
|
||||
function isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration: VariableDeclaration, usage: Node): boolean {
|
||||
const container = getEnclosingBlockScopeContainer(declaration);
|
||||
@@ -10367,9 +10368,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (!issuedElaboration && (length(targetProp && targetProp.declarations) || length(target.symbol && target.symbol.declarations))) {
|
||||
if (!issuedElaboration && (targetProp && length(targetProp.declarations) || target.symbol && length(target.symbol.declarations))) {
|
||||
addRelatedInfo(reportedDiag, createDiagnosticForNode(
|
||||
targetProp ? targetProp.declarations[0] : target.symbol.declarations[0],
|
||||
targetProp && length(targetProp.declarations) ? targetProp.declarations[0] : target.symbol.declarations[0],
|
||||
Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1,
|
||||
propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType),
|
||||
typeToString(target)
|
||||
@@ -19345,6 +19346,38 @@ namespace ts {
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
|
||||
function typeHasProtectedAccessibleBase(target: Symbol, type: InterfaceType): boolean {
|
||||
const baseTypes = getBaseTypes(type);
|
||||
if (!length(baseTypes)) {
|
||||
return false;
|
||||
}
|
||||
const firstBase = baseTypes[0];
|
||||
if (firstBase.flags & TypeFlags.Intersection) {
|
||||
const types = (firstBase as IntersectionType).types;
|
||||
const mixinCount = countWhere(types, isMixinConstructorType);
|
||||
let i = 0;
|
||||
for (const intersectionMember of (firstBase as IntersectionType).types) {
|
||||
i++;
|
||||
// We want to ignore mixin ctors
|
||||
if (mixinCount === 0 || mixinCount === types.length && i === 0 || !isMixinConstructorType(intersectionMember)) {
|
||||
if (getObjectFlags(intersectionMember) & (ObjectFlags.Class | ObjectFlags.Interface)) {
|
||||
if (intersectionMember.symbol === target) {
|
||||
return true;
|
||||
}
|
||||
if (typeHasProtectedAccessibleBase(target, intersectionMember as InterfaceType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (firstBase.symbol === target) {
|
||||
return true;
|
||||
}
|
||||
return typeHasProtectedAccessibleBase(target, firstBase as InterfaceType);
|
||||
}
|
||||
|
||||
function isConstructorAccessible(node: NewExpression, signature: Signature) {
|
||||
if (!signature || !signature.declaration) {
|
||||
return true;
|
||||
@@ -19364,16 +19397,10 @@ namespace ts {
|
||||
// A private or protected constructor can only be instantiated within its own class (or a subclass, for protected)
|
||||
if (!isNodeWithinClass(node, declaringClassDeclaration)) {
|
||||
const containingClass = getContainingClass(node);
|
||||
if (containingClass) {
|
||||
if (containingClass && modifiers & ModifierFlags.Protected) {
|
||||
const containingType = getTypeOfNode(containingClass);
|
||||
let baseTypes = getBaseTypes(containingType as InterfaceType);
|
||||
while (baseTypes.length) {
|
||||
const baseType = baseTypes[0];
|
||||
if (modifiers & ModifierFlags.Protected &&
|
||||
baseType.symbol === declaration.parent.symbol) {
|
||||
return true;
|
||||
}
|
||||
baseTypes = getBaseTypes(baseType as InterfaceType);
|
||||
if (typeHasProtectedAccessibleBase(declaration.parent.symbol, containingType as InterfaceType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (modifiers & ModifierFlags.Private) {
|
||||
@@ -21102,7 +21129,7 @@ namespace ts {
|
||||
getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) :
|
||||
leftType;
|
||||
case SyntaxKind.EqualsToken:
|
||||
const special = getSpecialPropertyAssignmentKind(left.parent as BinaryExpression);
|
||||
const special = isBinaryExpression(left.parent) ? getSpecialPropertyAssignmentKind(left.parent) : SpecialPropertyAssignmentKind.None;
|
||||
checkSpecialAssignment(special, right);
|
||||
if (isJSSpecialPropertyAssignment(special)) {
|
||||
return leftType;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace ts {
|
||||
if (sourceFile.kind === SyntaxKind.Bundle) {
|
||||
const jsFilePath = options.outFile || options.out!;
|
||||
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
|
||||
const declarationFilePath = (forceDtsPaths || options.declaration) ? removeFileExtension(jsFilePath) + Extension.Dts : undefined;
|
||||
const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(jsFilePath) + Extension.Dts : undefined;
|
||||
const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
|
||||
const bundleInfoPath = options.references && jsFilePath ? (removeFileExtension(jsFilePath) + infoExtension) : undefined;
|
||||
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath };
|
||||
@@ -53,7 +53,7 @@ namespace ts {
|
||||
const sourceMapFilePath = isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options);
|
||||
// For legacy reasons (ie, we have baselines capturing the behavior), js files don't report a .d.ts output path - this would only matter if `declaration` and `allowJs` were both on, which is currently an error
|
||||
const isJs = isSourceFileJavaScript(sourceFile);
|
||||
const declarationFilePath = ((forceDtsPaths || options.declaration) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
|
||||
const declarationFilePath = ((forceDtsPaths || getEmitDeclarations(options)) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
|
||||
const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
|
||||
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath: undefined };
|
||||
}
|
||||
@@ -205,7 +205,7 @@ namespace ts {
|
||||
// Setup and perform the transformation to retrieve declarations from the input files
|
||||
const nonJsFiles = filter(sourceFiles, isSourceFileNotJavaScript);
|
||||
const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(nonJsFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : nonJsFiles;
|
||||
if (emitOnlyDtsFiles && !compilerOptions.declaration) {
|
||||
if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
|
||||
// Checker wont collect the linked aliases since thats only done when declaration is enabled.
|
||||
// Do that here when emitting only dts files
|
||||
nonJsFiles.forEach(collectLinkedAliases);
|
||||
|
||||
@@ -2329,7 +2329,7 @@ namespace ts {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, options.rootDir));
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
}
|
||||
@@ -2500,7 +2500,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.declarationMap && !options.declaration) {
|
||||
if (options.declarationMap && !getEmitDeclarations(options)) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationMap", "declaration");
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace ts {
|
||||
let filesWithInvalidatedResolutions: Map<true> | undefined;
|
||||
let filesWithInvalidatedNonRelativeUnresolvedImports: Map<ReadonlyArray<string>> | undefined;
|
||||
let allFilesHaveInvalidatedResolution = false;
|
||||
const nonRelativeExternalModuleResolutions = createMultiMap<ResolutionWithFailedLookupLocations>();
|
||||
|
||||
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory!()); // TODO: GH#18217
|
||||
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();
|
||||
@@ -154,6 +155,7 @@ namespace ts {
|
||||
function clear() {
|
||||
clearMap(directoryWatchesOfFailedLookups, closeFileWatcherOf);
|
||||
customFailedLookupPaths.clear();
|
||||
nonRelativeExternalModuleResolutions.clear();
|
||||
closeTypeRootsWatch();
|
||||
resolvedModuleNames.clear();
|
||||
resolvedTypeReferenceDirectives.clear();
|
||||
@@ -199,19 +201,20 @@ namespace ts {
|
||||
perDirectoryResolvedModuleNames.clear();
|
||||
nonRelaticeModuleNameCache.clear();
|
||||
perDirectoryResolvedTypeReferenceDirectives.clear();
|
||||
nonRelativeExternalModuleResolutions.forEach(watchFailedLookupLocationOfNonRelativeModuleResolutions);
|
||||
nonRelativeExternalModuleResolutions.clear();
|
||||
}
|
||||
|
||||
function finishCachingPerDirectoryResolution() {
|
||||
allFilesHaveInvalidatedResolution = false;
|
||||
filesWithInvalidatedNonRelativeUnresolvedImports = undefined;
|
||||
clearPerDirectoryResolutions();
|
||||
directoryWatchesOfFailedLookups.forEach((watcher, path) => {
|
||||
if (watcher.refCount === 0) {
|
||||
directoryWatchesOfFailedLookups.delete(path);
|
||||
watcher.watcher.close();
|
||||
}
|
||||
});
|
||||
|
||||
clearPerDirectoryResolutions();
|
||||
}
|
||||
|
||||
function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): CachedResolvedModuleWithFailedLookupLocations {
|
||||
@@ -275,7 +278,7 @@ namespace ts {
|
||||
perDirectoryResolution.set(name, resolution);
|
||||
}
|
||||
resolutionsInFile.set(name, resolution);
|
||||
watchFailedLookupLocationOfResolution(resolution);
|
||||
watchFailedLookupLocationsOfExternalModuleResolutions(name, resolution);
|
||||
if (existingResolution) {
|
||||
stopWatchFailedLookupLocationOfResolution(existingResolution);
|
||||
}
|
||||
@@ -441,18 +444,27 @@ namespace ts {
|
||||
return fileExtensionIsOneOf(path, failedLookupDefaultExtensions);
|
||||
}
|
||||
|
||||
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
|
||||
function watchFailedLookupLocationsOfExternalModuleResolutions(name: string, resolution: ResolutionWithFailedLookupLocations) {
|
||||
// No need to set the resolution refCount
|
||||
if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) {
|
||||
return;
|
||||
if (resolution.failedLookupLocations && resolution.failedLookupLocations.length) {
|
||||
if (resolution.refCount) {
|
||||
resolution.refCount++;
|
||||
}
|
||||
else {
|
||||
resolution.refCount = 1;
|
||||
if (isExternalModuleNameRelative(name)) {
|
||||
watchFailedLookupLocationOfResolution(resolution);
|
||||
}
|
||||
else {
|
||||
nonRelativeExternalModuleResolutions.add(name, resolution);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resolution.refCount !== undefined) {
|
||||
resolution.refCount++;
|
||||
return;
|
||||
}
|
||||
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
|
||||
Debug.assert(!!resolution.refCount);
|
||||
|
||||
resolution.refCount = 1;
|
||||
const { failedLookupLocations } = resolution;
|
||||
let setAtRoot = false;
|
||||
for (const failedLookupLocation of failedLookupLocations) {
|
||||
@@ -480,6 +492,16 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function setRefCountToUndefined(resolution: ResolutionWithFailedLookupLocations) {
|
||||
resolution.refCount = undefined;
|
||||
}
|
||||
|
||||
function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) {
|
||||
const updateResolution = resolutionHost.getCurrentProgram().getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name) ?
|
||||
setRefCountToUndefined : watchFailedLookupLocationOfResolution;
|
||||
resolutions.forEach(updateResolution);
|
||||
}
|
||||
|
||||
function setDirectoryWatcher(dir: string, dirPath: Path, nonRecursive?: boolean) {
|
||||
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
|
||||
if (dirWatcher) {
|
||||
@@ -492,11 +514,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function stopWatchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
|
||||
if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) {
|
||||
if (!resolution.refCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
resolution.refCount!--;
|
||||
resolution.refCount--;
|
||||
if (resolution.refCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ namespace ts {
|
||||
|
||||
const outputs: string[] = [];
|
||||
outputs.push(getOutputJavaScriptFileName(inputFileName, configFile));
|
||||
if (configFile.options.declaration && !fileExtensionIs(inputFileName, Extension.Json)) {
|
||||
if (getEmitDeclarations(configFile.options) && !fileExtensionIs(inputFileName, Extension.Json)) {
|
||||
const dts = getOutputDeclarationFileName(inputFileName, configFile);
|
||||
outputs.push(dts);
|
||||
if (configFile.options.declarationMap) {
|
||||
@@ -320,7 +320,7 @@ namespace ts {
|
||||
}
|
||||
const outputs: string[] = [];
|
||||
outputs.push(project.options.outFile);
|
||||
if (project.options.declaration) {
|
||||
if (getEmitDeclarations(project.options)) {
|
||||
const dts = changeExtension(project.options.outFile, Extension.Dts);
|
||||
outputs.push(dts);
|
||||
if (project.options.declarationMap) {
|
||||
@@ -769,7 +769,10 @@ namespace ts {
|
||||
const program = createProgram(programOptions);
|
||||
|
||||
// Don't emit anything in the presence of syntactic errors or options diagnostics
|
||||
const syntaxDiagnostics = [...program.getOptionsDiagnostics(), ...program.getSyntacticDiagnostics()];
|
||||
const syntaxDiagnostics = [
|
||||
...program.getOptionsDiagnostics(),
|
||||
...program.getConfigFileParsingDiagnostics(),
|
||||
...program.getSyntacticDiagnostics()];
|
||||
if (syntaxDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.SyntaxErrors;
|
||||
for (const diag of syntaxDiagnostics) {
|
||||
@@ -780,7 +783,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Don't emit .d.ts if there are decl file errors
|
||||
if (program.getCompilerOptions().declaration) {
|
||||
if (getEmitDeclarations(program.getCompilerOptions())) {
|
||||
const declDiagnostics = program.getDeclarationDiagnostics();
|
||||
if (declDiagnostics.length) {
|
||||
resultFlags |= BuildResultFlags.DeclarationEmitErrors;
|
||||
|
||||
@@ -2994,9 +2994,9 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
|
||||
getApparentType(type: Type): Type;
|
||||
getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
|
||||
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
|
||||
getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined;
|
||||
/* @internal */ getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
|
||||
/* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
|
||||
/* @internal */ getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined;
|
||||
getBaseConstraintOfType(type: Type): Type | undefined;
|
||||
getDefaultFromTypeParameter(type: Type): Type | undefined;
|
||||
|
||||
|
||||
@@ -7273,7 +7273,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getAreDeclarationMapsEnabled(options: CompilerOptions) {
|
||||
return !!(options.declaration && options.declarationMap);
|
||||
return !!(getEmitDeclarations(options) && options.declarationMap);
|
||||
}
|
||||
|
||||
export function getAllowSyntheticDefaultImports(compilerOptions: CompilerOptions) {
|
||||
@@ -8442,4 +8442,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export type Mutable<T extends object> = { -readonly [K in keyof T]: T[K] };
|
||||
|
||||
export function sliceAfter<T>(arr: ReadonlyArray<T>, value: T): ReadonlyArray<T> {
|
||||
const index = arr.indexOf(value);
|
||||
Debug.assert(index !== -1);
|
||||
return arr.slice(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1515,7 +1515,9 @@ Actual: ${stringify(fullActual)}`);
|
||||
"argumentCount",
|
||||
];
|
||||
for (const key in options) {
|
||||
ts.Debug.assert(ts.contains(allKeys, key));
|
||||
if (!ts.contains(allKeys, key)) {
|
||||
ts.Debug.fail("Unexpected key " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3367,7 +3369,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
this.languageServiceAdapterHost.renameFileOrDirectory(oldPath, newPath);
|
||||
this.languageService.cleanupSemanticCache();
|
||||
const pathUpdater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false));
|
||||
const pathUpdater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(/*useCaseSensitiveFileNames*/ false), /*sourceMapper*/ undefined);
|
||||
test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved");
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace Harness.LanguageService {
|
||||
this.vfs.mkdirpSync(ts.getDirectoryPath(newPath));
|
||||
this.vfs.renameSync(oldPath, newPath);
|
||||
|
||||
const updater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()));
|
||||
const updater = ts.getPathUpdater(oldPath, newPath, ts.createGetCanonicalFileName(this.useCaseSensitiveFileNames()), /*sourceMapper*/ undefined);
|
||||
this.scriptInfos.forEach((scriptInfo, key) => {
|
||||
const newFileName = updater(key);
|
||||
if (newFileName !== undefined) {
|
||||
|
||||
+35
-15
@@ -286,6 +286,16 @@ namespace ts.server {
|
||||
: deduplicate(outputs, areEqual);
|
||||
}
|
||||
|
||||
function combineProjectOutputFromEveryProject<T>(projectService: ProjectService, action: (project: Project) => ReadonlyArray<T>, areEqual: (a: T, b: T) => boolean) {
|
||||
const outputs: T[] = [];
|
||||
projectService.forEachProject(project => {
|
||||
if (project.isOrphan() || !project.languageServiceEnabled) return;
|
||||
const theseOutputs = action(project);
|
||||
outputs.push(...theseOutputs.filter(output => !outputs.some(o => areEqual(o, output))));
|
||||
});
|
||||
return outputs;
|
||||
}
|
||||
|
||||
function combineProjectOutputWhileOpeningReferencedProjects<T>(
|
||||
projects: Projects,
|
||||
projectService: ProjectService,
|
||||
@@ -1749,19 +1759,11 @@ namespace ts.server {
|
||||
const newPath = toNormalizedPath(args.newFilePath);
|
||||
const formatOptions = this.getHostFormatOptions();
|
||||
const preferences = this.getHostPreferences();
|
||||
|
||||
const changes: (protocol.FileCodeEdits | FileTextChanges)[] = [];
|
||||
this.projectService.forEachProject(project => {
|
||||
if (project.isOrphan() || !project.languageServiceEnabled) return;
|
||||
for (const fileTextChanges of project.getLanguageService().getEditsForFileRename(oldPath, newPath, formatOptions, preferences)) {
|
||||
// Subsequent projects may make conflicting edits to the same file -- just go with the first.
|
||||
if (!changes.some(f => f.fileName === fileTextChanges.fileName)) {
|
||||
changes.push(simplifiedResult ? this.mapTextChangeToCodeEdit(project, fileTextChanges) : fileTextChanges);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return changes as ReadonlyArray<protocol.FileCodeEdits> | ReadonlyArray<FileTextChanges>;
|
||||
const changes = combineProjectOutputFromEveryProject(
|
||||
this.projectService,
|
||||
project => project.getLanguageService().getEditsForFileRename(oldPath, newPath, formatOptions, preferences),
|
||||
(a, b) => a.fileName === b.fileName);
|
||||
return simplifiedResult ? changes.map(c => this.mapTextChangeToCodeEditUsingScriptInfo(c)) : changes;
|
||||
}
|
||||
|
||||
private getCodeFixes(args: protocol.CodeFixRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.CodeFixAction> | ReadonlyArray<CodeFixAction> | undefined {
|
||||
@@ -1835,8 +1837,15 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private mapTextChangeToCodeEdit(project: Project, change: FileTextChanges): protocol.FileCodeEdits {
|
||||
const path = normalizedPathToPath(toNormalizedPath(change.fileName), this.host.getCurrentDirectory(), fileName => this.getCanonicalFileName(fileName));
|
||||
return mapTextChangesToCodeEdits(change, project.getSourceFileOrConfigFile(path));
|
||||
return mapTextChangesToCodeEdits(change, project.getSourceFileOrConfigFile(this.normalizePath(change.fileName)));
|
||||
}
|
||||
|
||||
private mapTextChangeToCodeEditUsingScriptInfo(change: FileTextChanges): protocol.FileCodeEdits {
|
||||
return mapTextChangesToCodeEditsUsingScriptInfo(change, this.projectService.getScriptInfo(this.normalizePath(change.fileName)));
|
||||
}
|
||||
|
||||
private normalizePath(fileName: string) {
|
||||
return normalizedPathToPath(toNormalizedPath(fileName), this.host.getCurrentDirectory(), fileName => this.getCanonicalFileName(fileName));
|
||||
}
|
||||
|
||||
private convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
|
||||
@@ -2361,6 +2370,13 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
function mapTextChangesToCodeEditsUsingScriptInfo(textChanges: FileTextChanges, scriptInfo: ScriptInfo | undefined): protocol.FileCodeEdits {
|
||||
Debug.assert(!!textChanges.isNewFile === !scriptInfo);
|
||||
return scriptInfo
|
||||
? { fileName: textChanges.fileName, textChanges: textChanges.textChanges.map(textChange => convertTextChangeToCodeEditUsingScriptInfo(textChange, scriptInfo)) }
|
||||
: convertNewFileTextChangeToCodeEdit(textChanges);
|
||||
}
|
||||
|
||||
function convertTextChangeToCodeEdit(change: TextChange, sourceFile: SourceFile): protocol.CodeEdit {
|
||||
return {
|
||||
start: convertToLocation(sourceFile.getLineAndCharacterOfPosition(change.span.start)),
|
||||
@@ -2369,6 +2385,10 @@ namespace ts.server {
|
||||
};
|
||||
}
|
||||
|
||||
function convertTextChangeToCodeEditUsingScriptInfo(change: TextChange, scriptInfo: ScriptInfo) {
|
||||
return { start: scriptInfo.positionToLineOffset(change.span.start), end: scriptInfo.positionToLineOffset(textSpanEnd(change.span)), newText: change.newText };
|
||||
}
|
||||
|
||||
function convertNewFileTextChangeToCodeEdit(textChanges: FileTextChanges): protocol.FileCodeEdits {
|
||||
Debug.assert(textChanges.textChanges.length === 1);
|
||||
const change = first(textChanges.textChanges);
|
||||
|
||||
@@ -5,14 +5,14 @@ namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
getCodeActions(context) {
|
||||
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start));
|
||||
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.span.length));
|
||||
return [createCodeFixAction(fixId, changes, Diagnostics.Remove_unreachable_code, fixId, Diagnostics.Remove_all_unreachable_code)];
|
||||
},
|
||||
fixIds: [fixId],
|
||||
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start)),
|
||||
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start, diag.length)),
|
||||
});
|
||||
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number): void {
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number, length: number): void {
|
||||
const token = getTokenAtPosition(sourceFile, start);
|
||||
const statement = findAncestor(token, isStatement)!;
|
||||
Debug.assert(statement.getStart(sourceFile) === token.getStart(sourceFile));
|
||||
@@ -36,7 +36,9 @@ namespace ts.codefix {
|
||||
break;
|
||||
default:
|
||||
if (isBlock(statement.parent)) {
|
||||
split(sliceAfter(statement.parent.statements, statement), shouldRemove, (start, end) => changes.deleteNodeRange(sourceFile, start, end));
|
||||
const end = start + length;
|
||||
const lastStatement = Debug.assertDefined(lastWhere(sliceAfter(statement.parent.statements, statement), s => s.pos < end));
|
||||
changes.deleteNodeRange(sourceFile, statement, lastStatement);
|
||||
}
|
||||
else {
|
||||
changes.delete(sourceFile, statement);
|
||||
@@ -44,35 +46,12 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function shouldRemove(s: Statement): boolean {
|
||||
// Don't remove statements that can validly be used before they appear.
|
||||
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
|
||||
// `var x;` may declare a variable used above
|
||||
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
|
||||
}
|
||||
|
||||
function isPurelyTypeDeclaration(s: Statement): boolean {
|
||||
switch (s.kind) {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return getModuleInstanceState(s as ModuleDeclaration) !== ModuleInstanceState.Instantiated;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return hasModifier(s, ModifierFlags.Const);
|
||||
default:
|
||||
return false;
|
||||
function lastWhere<T>(a: ReadonlyArray<T>, pred: (value: T) => boolean): T | undefined {
|
||||
let last: T | undefined;
|
||||
for (const value of a) {
|
||||
if (!pred(value)) break;
|
||||
last = value;
|
||||
}
|
||||
}
|
||||
|
||||
function sliceAfter<T>(arr: ReadonlyArray<T>, value: T): ReadonlyArray<T> {
|
||||
const index = arr.indexOf(value);
|
||||
Debug.assert(index !== -1);
|
||||
return arr.slice(index);
|
||||
}
|
||||
|
||||
// Calls 'cb' with the start and end of each range where 'pred' is true.
|
||||
function split<T>(arr: ReadonlyArray<T>, pred: (t: T) => boolean, cb: (start: T, end: T) => void): void {
|
||||
getRangesWhere(arr, pred, (start, afterEnd) => cb(arr[start], arr[afterEnd - 1]));
|
||||
return last;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-11
@@ -2,12 +2,20 @@
|
||||
namespace ts.Completions {
|
||||
export type Log = (message: string) => void;
|
||||
|
||||
type SymbolOriginInfo = { type: "this-type" } | { type: "symbol-member" } | SymbolOriginInfoExport;
|
||||
const enum SymbolOriginInfoKind { ThisType, SymbolMemberNoExport, SymbolMemberExport, Export }
|
||||
type SymbolOriginInfo = { kind: SymbolOriginInfoKind.ThisType } | { kind: SymbolOriginInfoKind.SymbolMemberNoExport } | SymbolOriginInfoExport;
|
||||
interface SymbolOriginInfoExport {
|
||||
type: "export";
|
||||
kind: SymbolOriginInfoKind.SymbolMemberExport | SymbolOriginInfoKind.Export;
|
||||
moduleSymbol: Symbol;
|
||||
isDefaultExport: boolean;
|
||||
}
|
||||
function originIsSymbolMember(origin: SymbolOriginInfo): boolean {
|
||||
return origin.kind === SymbolOriginInfoKind.SymbolMemberExport || origin.kind === SymbolOriginInfoKind.SymbolMemberNoExport;
|
||||
}
|
||||
function originIsExport(origin: SymbolOriginInfo): origin is SymbolOriginInfoExport {
|
||||
return origin.kind === SymbolOriginInfoKind.SymbolMemberExport || origin.kind === SymbolOriginInfoKind.Export;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map from symbol id -> SymbolOriginInfo.
|
||||
* Only populated for symbols that come from other modules.
|
||||
@@ -214,12 +222,12 @@ namespace ts.Completions {
|
||||
|
||||
let insertText: string | undefined;
|
||||
let replacementSpan: TextSpan | undefined;
|
||||
if (origin && origin.type === "this-type") {
|
||||
if (origin && origin.kind === SymbolOriginInfoKind.ThisType) {
|
||||
insertText = needsConvertPropertyAccess ? `this[${quote(name, preferences)}]` : `this.${name}`;
|
||||
}
|
||||
// We should only have needsConvertPropertyAccess if there's a property access to convert. But see #21790.
|
||||
// Somehow there was a global with a non-identifier name. Hopefully someone will complain about getting a "foo bar" global completion and provide a repro.
|
||||
else if ((origin && origin.type === "symbol-member" || needsConvertPropertyAccess) && propertyAccessToConvert) {
|
||||
else if ((origin && originIsSymbolMember(origin) || needsConvertPropertyAccess) && propertyAccessToConvert) {
|
||||
insertText = needsConvertPropertyAccess ? `[${quote(name, preferences)}]` : `[${name}]`;
|
||||
const dot = findChildOfKind(propertyAccessToConvert, SyntaxKind.DotToken, sourceFile)!;
|
||||
// If the text after the '.' starts with this name, write over it. Else, add new text.
|
||||
@@ -253,7 +261,7 @@ namespace ts.Completions {
|
||||
kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),
|
||||
sortText: "0",
|
||||
source: getSourceFromOrigin(origin),
|
||||
hasAction: trueOrUndefined(!!origin && origin.type === "export"),
|
||||
hasAction: trueOrUndefined(!!origin && originIsExport(origin)),
|
||||
isRecommended: trueOrUndefined(isRecommendedCompletionMatch(symbol, recommendedCompletion, typeChecker)),
|
||||
insertText,
|
||||
replacementSpan,
|
||||
@@ -283,7 +291,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
function getSourceFromOrigin(origin: SymbolOriginInfo | undefined): string | undefined {
|
||||
return origin && origin.type === "export" ? stripQuotes(origin.moduleSymbol.name) : undefined;
|
||||
return origin && originIsExport(origin) ? stripQuotes(origin.moduleSymbol.name) : undefined;
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromSymbols(
|
||||
@@ -529,7 +537,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
function getSymbolName(symbol: Symbol, origin: SymbolOriginInfo | undefined, target: ScriptTarget): string {
|
||||
return origin && origin.type === "export" && origin.isDefaultExport && symbol.escapedName === InternalSymbolName.Default
|
||||
return origin && originIsExport(origin) && origin.isDefaultExport && symbol.escapedName === InternalSymbolName.Default
|
||||
// Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase.
|
||||
? firstDefined(symbol.declarations, d => isExportAssignment(d) && isIdentifier(d.expression) ? d.expression.text : undefined)
|
||||
|| codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target)
|
||||
@@ -648,7 +656,7 @@ namespace ts.Completions {
|
||||
preferences: UserPreferences,
|
||||
): CodeActionsAndSourceDisplay {
|
||||
const symbolOriginInfo = symbolToOriginInfoMap[getSymbolId(symbol)];
|
||||
if (!symbolOriginInfo || symbolOriginInfo.type !== "export") {
|
||||
if (!symbolOriginInfo || !originIsExport(symbolOriginInfo)) {
|
||||
return { codeActions: undefined, sourceDisplay: undefined };
|
||||
}
|
||||
|
||||
@@ -1124,7 +1132,9 @@ namespace ts.Completions {
|
||||
const firstAccessibleSymbol = nameSymbol && getFirstSymbolInChain(nameSymbol, contextToken, typeChecker);
|
||||
if (firstAccessibleSymbol && !symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)]) {
|
||||
symbols.push(firstAccessibleSymbol);
|
||||
symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)] = { type: "symbol-member" };
|
||||
const moduleSymbol = firstAccessibleSymbol.parent;
|
||||
symbolToOriginInfoMap[getSymbolId(firstAccessibleSymbol)] =
|
||||
!moduleSymbol || !isExternalModuleSymbol(moduleSymbol) ? { kind: SymbolOriginInfoKind.SymbolMemberNoExport } : { kind: SymbolOriginInfoKind.SymbolMemberExport, moduleSymbol, isDefaultExport: false };
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1222,7 +1232,7 @@ namespace ts.Completions {
|
||||
const thisType = typeChecker.tryGetThisTypeAt(scopeNode);
|
||||
if (thisType) {
|
||||
for (const symbol of getPropertiesForCompletion(thisType, typeChecker)) {
|
||||
symbolToOriginInfoMap[getSymbolId(symbol)] = { type: "this-type" };
|
||||
symbolToOriginInfoMap[getSymbolId(symbol)] = { kind: SymbolOriginInfoKind.ThisType };
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
@@ -1374,7 +1384,7 @@ namespace ts.Completions {
|
||||
symbol = getLocalSymbolForExportDefault(symbol) || symbol;
|
||||
}
|
||||
|
||||
const origin: SymbolOriginInfo = { type: "export", moduleSymbol, isDefaultExport };
|
||||
const origin: SymbolOriginInfoExport = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport };
|
||||
if (detailsEntryId || stringContainsCharactersInOrder(getSymbolName(symbol, origin, target).toLowerCase(), tokenTextLowerCase)) {
|
||||
symbols.push(symbol);
|
||||
symbolToOriginInfoMap[getSymbolId(symbol)] = origin;
|
||||
|
||||
@@ -234,7 +234,8 @@ namespace ts.FindAllReferences.Core {
|
||||
export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName)): SymbolAndEntries[] | undefined {
|
||||
if (isSourceFile(node)) {
|
||||
const reference = GoToDefinition.getReferenceAtPosition(node, position, program);
|
||||
return reference && getReferencedSymbolsForModule(program, program.getTypeChecker().getMergedSymbol(reference.file.symbol), /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
|
||||
const moduleSymbol = reference && program.getTypeChecker().getMergedSymbol(reference.file.symbol);
|
||||
return moduleSymbol && getReferencedSymbolsForModule(program, moduleSymbol, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
|
||||
}
|
||||
|
||||
if (!options.implementations) {
|
||||
@@ -703,7 +704,7 @@ namespace ts.FindAllReferences.Core {
|
||||
- But if the parent has `export as namespace`, the symbol is globally visible through that namespace.
|
||||
*/
|
||||
const exposedByParent = parent && !(symbol.flags & SymbolFlags.TypeParameter);
|
||||
if (exposedByParent && !((parent!.flags & SymbolFlags.Module) && isExternalModuleSymbol(parent!) && !parent!.globalExports)) {
|
||||
if (exposedByParent && !(isExternalModuleSymbol(parent!) && !parent!.globalExports)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function getEditsForFileRename(program: Program, oldFileOrDirPath: string, newFileOrDirPath: string, host: LanguageServiceHost, formatContext: formatting.FormatContext, preferences: UserPreferences): ReadonlyArray<FileTextChanges> {
|
||||
export function getEditsForFileRename(
|
||||
program: Program,
|
||||
oldFileOrDirPath: string,
|
||||
newFileOrDirPath: string,
|
||||
host: LanguageServiceHost,
|
||||
formatContext: formatting.FormatContext,
|
||||
preferences: UserPreferences,
|
||||
sourceMapper: SourceMapper,
|
||||
): ReadonlyArray<FileTextChanges> {
|
||||
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
||||
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName);
|
||||
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName);
|
||||
const oldToNew = getPathUpdater(oldFileOrDirPath, newFileOrDirPath, getCanonicalFileName, sourceMapper);
|
||||
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);
|
||||
@@ -14,13 +22,27 @@ namespace ts {
|
||||
/** If 'path' refers to an old directory, returns path in the new directory. */
|
||||
type PathUpdater = (path: string) => string | undefined;
|
||||
// exported for tests
|
||||
export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName): PathUpdater {
|
||||
export function getPathUpdater(oldFileOrDirPath: string, newFileOrDirPath: string, getCanonicalFileName: GetCanonicalFileName, sourceMapper: SourceMapper | undefined): PathUpdater {
|
||||
const canonicalOldPath = getCanonicalFileName(oldFileOrDirPath);
|
||||
return path => {
|
||||
if (getCanonicalFileName(path) === canonicalOldPath) return newFileOrDirPath;
|
||||
const suffix = tryRemoveDirectoryPrefix(path, canonicalOldPath, getCanonicalFileName);
|
||||
return suffix === undefined ? undefined : newFileOrDirPath + "/" + suffix;
|
||||
const originalPath = sourceMapper && sourceMapper.tryGetOriginalLocation({ fileName: path, position: 0 });
|
||||
const updatedPath = getUpdatedPath(originalPath ? originalPath.fileName : path);
|
||||
return originalPath
|
||||
? updatedPath === undefined ? undefined : makeCorrespondingRelativeChange(originalPath.fileName, updatedPath, path, getCanonicalFileName)
|
||||
: updatedPath;
|
||||
};
|
||||
|
||||
function getUpdatedPath(pathToUpdate: string): string | undefined {
|
||||
if (getCanonicalFileName(pathToUpdate) === canonicalOldPath) return newFileOrDirPath;
|
||||
const suffix = tryRemoveDirectoryPrefix(pathToUpdate, canonicalOldPath, getCanonicalFileName);
|
||||
return suffix === undefined ? undefined : newFileOrDirPath + "/" + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
// Relative path from a0 to b0 should be same as relative path from a1 to b1. Returns b1.
|
||||
function makeCorrespondingRelativeChange(a0: string, b0: string, a1: string, getCanonicalFileName: GetCanonicalFileName): string {
|
||||
const rel = getRelativePathFromFile(a0, b0, getCanonicalFileName);
|
||||
return combinePathsSafe(getDirectoryPath(a1), rel);
|
||||
}
|
||||
|
||||
function updateTsconfigFiles(program: Program, changeTracker: textChanges.ChangeTracker, oldToNew: PathUpdater, newFileOrDirPath: string, currentDirectory: string, useCaseSensitiveFileNames: boolean): void {
|
||||
|
||||
@@ -183,6 +183,26 @@ namespace ts.OutliningElementsCollector {
|
||||
return spanForObjectOrArrayLiteral(n);
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return spanForObjectOrArrayLiteral(n, SyntaxKind.OpenBracketToken);
|
||||
case SyntaxKind.JsxElement:
|
||||
return spanForJSXElement(<JsxElement>n);
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
return spanForJSXAttributes((<JsxOpeningLikeElement>n).attributes);
|
||||
}
|
||||
|
||||
function spanForJSXElement(node: JsxElement): OutliningSpan | undefined {
|
||||
const textSpan = createTextSpanFromBounds(node.openingElement.getStart(sourceFile), node.closingElement.getEnd());
|
||||
const tagName = node.openingElement.tagName.getText(sourceFile);
|
||||
const bannerText = "<" + tagName + ">...</" + tagName + ">";
|
||||
return createOutliningSpan(textSpan, OutliningSpanKind.Code, textSpan, /*autoCollapse*/ false, bannerText);
|
||||
}
|
||||
|
||||
function spanForJSXAttributes(node: JsxAttributes): OutliningSpan | undefined {
|
||||
if (node.properties.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), OutliningSpanKind.Code);
|
||||
}
|
||||
|
||||
function spanForObjectOrArrayLiteral(node: Node, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined {
|
||||
|
||||
@@ -1537,7 +1537,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getDocumentHighlights(fileName: string, position: number, filesToSearch: ReadonlyArray<string>): DocumentHighlights[] | undefined {
|
||||
Debug.assert(filesToSearch.some(f => normalizePath(f) === fileName));
|
||||
const normalizedFileName = normalizePath(fileName);
|
||||
Debug.assert(filesToSearch.some(f => normalizePath(f) === normalizedFileName));
|
||||
synchronizeHostData();
|
||||
const sourceFilesToSearch = map(filesToSearch, f => Debug.assertDefined(program.getSourceFile(f)));
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
@@ -1812,7 +1813,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): ReadonlyArray<FileTextChanges> {
|
||||
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences);
|
||||
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences, sourceMapper);
|
||||
}
|
||||
|
||||
function applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
|
||||
@@ -1883,11 +1884,16 @@ namespace ts {
|
||||
if (!token) return undefined;
|
||||
const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) ? token.parent.parent
|
||||
: isJsxText(token) ? token.parent : undefined;
|
||||
if (element && !tagNamesAreEquivalent(element.openingElement.tagName, element.closingElement.tagName)) {
|
||||
if (element && isUnclosedTag(element)) {
|
||||
return { newText: `</${element.openingElement.tagName.getText(sourceFile)}>` };
|
||||
}
|
||||
}
|
||||
|
||||
function isUnclosedTag({ openingElement, closingElement, parent }: JsxElement): boolean {
|
||||
return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) ||
|
||||
isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) && isUnclosedTag(parent);
|
||||
}
|
||||
|
||||
function getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
const range = formatting.getRangeOfEnclosingComment(sourceFile, position);
|
||||
|
||||
@@ -29,9 +29,12 @@ namespace ts.SignatureHelp {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (shouldCarefullyCheckContext(triggerReason)) {
|
||||
// In the middle of a string, don't provide signature help unless the user explicitly requested it.
|
||||
if (isInString(sourceFile, position, startingToken)) {
|
||||
// Only need to be careful if the user typed a character and signature help wasn't showing.
|
||||
const shouldCarefullyCheckContext = !!triggerReason && triggerReason.kind === "characterTyped";
|
||||
|
||||
// Bail out quickly in the middle of a string or comment, don't provide signature help unless the user explicitly requested it.
|
||||
if (shouldCarefullyCheckContext) {
|
||||
if (isInString(sourceFile, position, startingToken) || isInComment(sourceFile, position)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -41,8 +44,8 @@ namespace ts.SignatureHelp {
|
||||
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// Semantic filtering of signature help
|
||||
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker);
|
||||
// Extra syntactic and semantic filtering of signature help
|
||||
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker, sourceFile, startingToken, shouldCarefullyCheckContext);
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
if (!candidateInfo) {
|
||||
@@ -57,24 +60,57 @@ namespace ts.SignatureHelp {
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
|
||||
}
|
||||
|
||||
function shouldCarefullyCheckContext(reason: SignatureHelpTriggerReason | undefined) {
|
||||
// Only need to be careful if the user typed a character and signature help wasn't showing.
|
||||
return !!reason && reason.kind === "characterTyped";
|
||||
}
|
||||
function getCandidateInfo(
|
||||
argumentInfo: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean):
|
||||
{ readonly candidates: ReadonlyArray<Signature>, readonly resolvedSignature: Signature } | undefined {
|
||||
|
||||
function getCandidateInfo(argumentInfo: ArgumentListInfo, checker: TypeChecker): { readonly candidates: ReadonlyArray<Signature>, readonly resolvedSignature: Signature } | undefined {
|
||||
const { invocation } = argumentInfo;
|
||||
if (invocation.kind === InvocationKind.Call) {
|
||||
if (onlyUseSyntacticOwners) {
|
||||
if (isCallOrNewExpression(invocation.node)) {
|
||||
const invocationChildren = invocation.node.getChildren(sourceFile);
|
||||
switch (startingToken.kind) {
|
||||
case SyntaxKind.OpenParenToken:
|
||||
if (!contains(invocationChildren, startingToken)) {
|
||||
return undefined;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.CommaToken:
|
||||
const containingList = findContainingList(startingToken);
|
||||
if (!containingList || !contains(invocationChildren, findContainingList(startingToken))) {
|
||||
return undefined;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.LessThanToken:
|
||||
if (!lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.node.expression)) {
|
||||
return undefined;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const candidates: Signature[] = [];
|
||||
const resolvedSignature = checker.getResolvedSignature(invocation.node, candidates, argumentInfo.argumentCount)!; // TODO: GH#18217
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
|
||||
}
|
||||
else {
|
||||
else if (invocation.kind === InvocationKind.TypeArgs) {
|
||||
if (onlyUseSyntacticOwners && !lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.called)) {
|
||||
return undefined;
|
||||
}
|
||||
const type = checker.getTypeAtLocation(invocation.called)!; // TODO: GH#18217
|
||||
const signatures = isNewExpression(invocation.called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
|
||||
const candidates = signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= argumentInfo.argumentCount);
|
||||
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
|
||||
}
|
||||
else {
|
||||
Debug.assertNever(invocation);
|
||||
}
|
||||
}
|
||||
|
||||
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
|
||||
@@ -107,6 +143,14 @@ namespace ts.SignatureHelp {
|
||||
}
|
||||
}
|
||||
|
||||
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
|
||||
const precedingToken = Debug.assertDefined(
|
||||
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
|
||||
);
|
||||
|
||||
return rangeContainsRange(calledExpression, precedingToken);
|
||||
}
|
||||
|
||||
export interface ArgumentInfoForCompletions {
|
||||
readonly invocation: CallLikeExpression;
|
||||
readonly argumentIndex: number;
|
||||
|
||||
@@ -679,7 +679,7 @@ namespace ts {
|
||||
let current: Node = sourceFile;
|
||||
outer: while (true) {
|
||||
// find the child that contains 'position'
|
||||
for (const child of current.getChildren()) {
|
||||
for (const child of current.getChildren(sourceFile)) {
|
||||
const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, /*includeJsDoc*/ true);
|
||||
if (start > position) {
|
||||
// If this child begins after position, then all subsequent children will as well.
|
||||
@@ -1184,8 +1184,7 @@ namespace ts {
|
||||
|
||||
/** True if the symbol is for an external module, as opposed to a namespace. */
|
||||
export function isExternalModuleSymbol(moduleSymbol: Symbol): boolean {
|
||||
Debug.assert(!!(moduleSymbol.flags & SymbolFlags.Module));
|
||||
return moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote;
|
||||
return !!(moduleSymbol.flags & SymbolFlags.Module) && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote;
|
||||
}
|
||||
|
||||
/** Returns `true` the first time it encounters a node and `false` afterwards. */
|
||||
|
||||
@@ -285,4 +285,23 @@ namespace ts {
|
||||
});
|
||||
});
|
||||
|
||||
describe("errors when a file in a composite project occurs outside the root", () => {
|
||||
it("Errors when a file is outside the rootdir", () => {
|
||||
const spec: TestSpecification = {
|
||||
"/alpha": {
|
||||
files: { "/alpha/src/a.ts": "import * from '../../beta/b'", "/beta/b.ts": "export { }" },
|
||||
options: {
|
||||
declaration: true,
|
||||
outDir: "bin"
|
||||
},
|
||||
references: []
|
||||
}
|
||||
};
|
||||
testProjectReferences(spec, "/alpha/tsconfig.json", (program) => {
|
||||
assertHasError("Issues an error about the rootDir", program.getOptionsDiagnostics(), Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files);
|
||||
assertHasError("Issues an error about the fileList", program.getOptionsDiagnostics(), Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -8486,7 +8486,7 @@ new C();`
|
||||
});
|
||||
});
|
||||
|
||||
it("when watching directories for failed lookup locations in amd resolution", () => {
|
||||
describe("when watching directories for failed lookup locations in amd resolution", () => {
|
||||
const projectRoot = "/user/username/projects/project";
|
||||
const nodeFile: File = {
|
||||
path: `${projectRoot}/src/typings/node.d.ts`,
|
||||
@@ -8530,19 +8530,35 @@ export const x = 10;`
|
||||
}
|
||||
})
|
||||
};
|
||||
const files = [nodeFile, electronFile, srcFile, moduleFile, configFile, libFile];
|
||||
const host = createServerHost(files);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, projectRoot);
|
||||
checkProjectActualFiles(service.configuredProjects.get(configFile.path)!, files.map(f => f.path));
|
||||
checkWatchedFilesDetailed(host, mapDefined(files, f => f === srcFile ? undefined : f.path), 1);
|
||||
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
|
||||
const expectedWatchedDirectories = createMap<number>();
|
||||
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
|
||||
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
|
||||
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
|
||||
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
|
||||
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);
|
||||
|
||||
function verifyModuleResolution(useNodeFile: boolean) {
|
||||
const files = [...(useNodeFile ? [nodeFile] : []), electronFile, srcFile, moduleFile, configFile, libFile];
|
||||
const host = createServerHost(files);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, projectRoot);
|
||||
checkProjectActualFiles(service.configuredProjects.get(configFile.path)!, files.map(f => f.path));
|
||||
checkWatchedFilesDetailed(host, mapDefined(files, f => f === srcFile ? undefined : f.path), 1);
|
||||
if (useNodeFile) {
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false); // since fs resolves to ambient module, shouldnt watch failed lookup
|
||||
}
|
||||
else {
|
||||
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
|
||||
}
|
||||
const expectedWatchedDirectories = createMap<number>();
|
||||
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
|
||||
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
|
||||
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
|
||||
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
|
||||
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);
|
||||
}
|
||||
|
||||
it("when resolves to ambient module", () => {
|
||||
verifyModuleResolution(/*useNodeFile*/ true);
|
||||
});
|
||||
|
||||
it("when resolution fails", () => {
|
||||
verifyModuleResolution(/*useNodeFile*/ false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9194,6 +9210,22 @@ export function Test2() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("getEditsForFileRename", () => {
|
||||
const { session, aTs, userTs } = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.GetEditsForFileRenameRequest, protocol.GetEditsForFileRenameResponse>(session, protocol.CommandTypes.GetEditsForFileRename, {
|
||||
oldFilePath: aTs.path,
|
||||
newFilePath: "/a/aNew.ts",
|
||||
});
|
||||
assert.deepEqual<ReadonlyArray<protocol.FileCodeEdits>>(response, [
|
||||
{
|
||||
fileName: userTs.path,
|
||||
textChanges: [
|
||||
{ ...protocolTextSpanFromSubstring(userTs.content, "../a/bin/a"), newText: "../a/bin/aNew" },
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
function makeReferenceItem(file: File, isDefinition: boolean, text: string, lineText: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
|
||||
|
||||
+2
-3
@@ -1933,9 +1933,6 @@ declare namespace ts {
|
||||
getAmbientModules(): Symbol[];
|
||||
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
|
||||
getApparentType(type: Type): Type;
|
||||
getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
|
||||
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
|
||||
getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined;
|
||||
getBaseConstraintOfType(type: Type): Type | undefined;
|
||||
getDefaultFromTypeParameter(type: Type): Type | undefined;
|
||||
/**
|
||||
@@ -8900,6 +8897,8 @@ declare namespace ts.server {
|
||||
private mapCodeFixAction;
|
||||
private mapTextChangesToCodeEdits;
|
||||
private mapTextChangeToCodeEdit;
|
||||
private mapTextChangeToCodeEditUsingScriptInfo;
|
||||
private normalizePath;
|
||||
private convertTextChangeToCodeEdit;
|
||||
private getBraceMatching;
|
||||
private getDiagnosticsForProject;
|
||||
|
||||
@@ -1933,9 +1933,6 @@ declare namespace ts {
|
||||
getAmbientModules(): Symbol[];
|
||||
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
|
||||
getApparentType(type: Type): Type;
|
||||
getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
|
||||
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
|
||||
getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined;
|
||||
getBaseConstraintOfType(type: Type): Type | undefined;
|
||||
getDefaultFromTypeParameter(type: Type): Type | undefined;
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ tests/cases/compiler/cf.ts(36,13): error TS7027: Unreachable code detected.
|
||||
if (y==7) {
|
||||
continue L1;
|
||||
x=11;
|
||||
~
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
if (y==3) {
|
||||
@@ -28,7 +28,7 @@ tests/cases/compiler/cf.ts(36,13): error TS7027: Unreachable code detected.
|
||||
if (y==20) {
|
||||
break;
|
||||
x=12;
|
||||
~
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
} while (y<41);
|
||||
@@ -41,13 +41,13 @@ tests/cases/compiler/cf.ts(36,13): error TS7027: Unreachable code detected.
|
||||
L3: if (x<y) {
|
||||
break L2;
|
||||
x=13;
|
||||
~
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
else {
|
||||
break L3;
|
||||
x=14;
|
||||
~
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
tests/cases/compiler/bug25434.js(4,9): error TS2304: Cannot find name 'b'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/bug25434.js (1 errors) ====
|
||||
// should not crash while checking
|
||||
function Test({ b = '' } = {}) {}
|
||||
|
||||
Test(({ b = '5' } = {}));
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'b'.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
=== tests/cases/compiler/bug25434.js ===
|
||||
// should not crash while checking
|
||||
function Test({ b = '' } = {}) {}
|
||||
>Test : Symbol(Test, Decl(bug25434.js, 0, 0))
|
||||
>b : Symbol(b, Decl(bug25434.js, 1, 15))
|
||||
|
||||
Test(({ b = '5' } = {}));
|
||||
>Test : Symbol(Test, Decl(bug25434.js, 0, 0))
|
||||
>b : Symbol(b, Decl(bug25434.js, 3, 7))
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
=== tests/cases/compiler/bug25434.js ===
|
||||
// should not crash while checking
|
||||
function Test({ b = '' } = {}) {}
|
||||
>Test : ({ b }?: { [x: string]: any; }) => void
|
||||
>b : string
|
||||
>'' : ""
|
||||
>{} : { b?: string; }
|
||||
|
||||
Test(({ b = '5' } = {}));
|
||||
>Test(({ b = '5' } = {})) : void
|
||||
>Test : ({ b }?: { [x: string]: any; }) => void
|
||||
>({ b = '5' } = {}) : { b?: any; }
|
||||
>{ b = '5' } = {} : { b?: any; }
|
||||
>{ b = '5' } : { [x: string]: any; b?: any; }
|
||||
>b : any
|
||||
>{} : { b?: any; }
|
||||
|
||||
@@ -2,9 +2,10 @@ tests/cases/compiler/errorElaboration.ts(12,5): error TS2345: Argument of type '
|
||||
Type 'Container<Ref<string>>' is not assignable to type 'Container<Ref<number>>'.
|
||||
Type 'Ref<string>' is not assignable to type 'Ref<number>'.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
tests/cases/compiler/errorElaboration.ts(17,11): error TS2322: Type '"bar"' is not assignable to type '"foo"'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/errorElaboration.ts (1 errors) ====
|
||||
==== tests/cases/compiler/errorElaboration.ts (2 errors) ====
|
||||
// Repro for #5712
|
||||
|
||||
interface Ref<T> {
|
||||
@@ -22,4 +23,13 @@ tests/cases/compiler/errorElaboration.ts(12,5): error TS2345: Argument of type '
|
||||
!!! error TS2345: Type 'Container<Ref<string>>' is not assignable to type 'Container<Ref<number>>'.
|
||||
!!! error TS2345: Type 'Ref<string>' is not assignable to type 'Ref<number>'.
|
||||
!!! error TS2345: Type 'string' is not assignable to type 'number'.
|
||||
|
||||
// Repro for #25498
|
||||
|
||||
function test(): {[A in "foo"]: A} {
|
||||
return {foo: "bar"};
|
||||
~~~
|
||||
!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'.
|
||||
!!! related TS6500 tests/cases/compiler/errorElaboration.ts:16:18: The expected type comes from property 'foo' which is declared here on type '{ foo: "foo"; }'
|
||||
}
|
||||
|
||||
@@ -11,9 +11,19 @@ interface Container<T> {
|
||||
declare function foo(x: () => Container<Ref<number>>): void;
|
||||
let a: () => Container<Ref<string>>;
|
||||
foo(a);
|
||||
|
||||
// Repro for #25498
|
||||
|
||||
function test(): {[A in "foo"]: A} {
|
||||
return {foo: "bar"};
|
||||
}
|
||||
|
||||
|
||||
//// [errorElaboration.js]
|
||||
// Repro for #5712
|
||||
var a;
|
||||
foo(a);
|
||||
// Repro for #25498
|
||||
function test() {
|
||||
return { foo: "bar" };
|
||||
}
|
||||
|
||||
@@ -38,3 +38,14 @@ foo(a);
|
||||
>foo : Symbol(foo, Decl(errorElaboration.ts, 8, 1))
|
||||
>a : Symbol(a, Decl(errorElaboration.ts, 10, 3))
|
||||
|
||||
// Repro for #25498
|
||||
|
||||
function test(): {[A in "foo"]: A} {
|
||||
>test : Symbol(test, Decl(errorElaboration.ts, 11, 7))
|
||||
>A : Symbol(A, Decl(errorElaboration.ts, 15, 19))
|
||||
>A : Symbol(A, Decl(errorElaboration.ts, 15, 19))
|
||||
|
||||
return {foo: "bar"};
|
||||
>foo : Symbol(foo, Decl(errorElaboration.ts, 16, 10))
|
||||
}
|
||||
|
||||
|
||||
@@ -39,3 +39,16 @@ foo(a);
|
||||
>foo : (x: () => Container<Ref<number>>) => void
|
||||
>a : () => Container<Ref<string>>
|
||||
|
||||
// Repro for #25498
|
||||
|
||||
function test(): {[A in "foo"]: A} {
|
||||
>test : () => { foo: "foo"; }
|
||||
>A : A
|
||||
>A : A
|
||||
|
||||
return {foo: "bar"};
|
||||
>{foo: "bar"} : { foo: "bar"; }
|
||||
>foo : "bar"
|
||||
>"bar" : "bar"
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ tests/cases/compiler/a.js(11,9): error TS1100: Invalid use of 'arguments' in str
|
||||
function f() {
|
||||
return;
|
||||
return; // Error: Unreachable code detected.
|
||||
~~~~~~
|
||||
~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ tests/cases/compiler/a.js(19,1): error TS7028: Unused label.
|
||||
function bar2() {
|
||||
}
|
||||
var x = 10; // error
|
||||
~~~
|
||||
~~~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
=== tests/cases/conformance/jsdoc/bug25097.js ===
|
||||
/** @type {C | null} */
|
||||
const c = null
|
||||
>c : Symbol(c, Decl(bug25097.js, 1, 5))
|
||||
|
||||
class C {
|
||||
>C : Symbol(C, Decl(bug25097.js, 1, 14))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
=== tests/cases/conformance/jsdoc/bug25097.js ===
|
||||
/** @type {C | null} */
|
||||
const c = null
|
||||
>c : C
|
||||
>null : null
|
||||
|
||||
class C {
|
||||
>C : C
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
tests/cases/compiler/noCrashOnMixin.ts(21,9): error TS2674: Constructor of class 'Abstract' is protected and only accessible within the class declaration.
|
||||
|
||||
|
||||
==== tests/cases/compiler/noCrashOnMixin.ts (1 errors) ====
|
||||
class Abstract {
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
return class extends Base {
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
public trigger() {
|
||||
new Concrete();
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS2674: Constructor of class 'Abstract' is protected and only accessible within the class declaration.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//// [noCrashOnMixin.ts]
|
||||
class Abstract {
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
return class extends Base {
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
public trigger() {
|
||||
new Concrete();
|
||||
}
|
||||
}
|
||||
|
||||
//// [noCrashOnMixin.js]
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
}
|
||||
return function (d, b) {
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
var Abstract = /** @class */ (function () {
|
||||
function Abstract() {
|
||||
}
|
||||
return Abstract;
|
||||
}());
|
||||
var Concrete = /** @class */ (function (_super) {
|
||||
__extends(Concrete, _super);
|
||||
function Concrete() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return Concrete;
|
||||
}(Abstract));
|
||||
function Mixin(Base) {
|
||||
return /** @class */ (function (_super) {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return class_1;
|
||||
}(Base));
|
||||
}
|
||||
var Empty = /** @class */ (function () {
|
||||
function Empty() {
|
||||
}
|
||||
return Empty;
|
||||
}());
|
||||
var CrashTrigger = /** @class */ (function (_super) {
|
||||
__extends(CrashTrigger, _super);
|
||||
function CrashTrigger() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
CrashTrigger.prototype.trigger = function () {
|
||||
new Concrete();
|
||||
};
|
||||
return CrashTrigger;
|
||||
}(Mixin(Empty)));
|
||||
@@ -0,0 +1,48 @@
|
||||
=== tests/cases/compiler/noCrashOnMixin.ts ===
|
||||
class Abstract {
|
||||
>Abstract : Symbol(Abstract, Decl(noCrashOnMixin.ts, 0, 0))
|
||||
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
>Concrete : Symbol(Concrete, Decl(noCrashOnMixin.ts, 3, 1))
|
||||
>Abstract : Symbol(Abstract, Decl(noCrashOnMixin.ts, 0, 0))
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
>Constructor : Symbol(Constructor, Decl(noCrashOnMixin.ts, 6, 1))
|
||||
>T : Symbol(T, Decl(noCrashOnMixin.ts, 8, 17))
|
||||
>args : Symbol(args, Decl(noCrashOnMixin.ts, 8, 32))
|
||||
>T : Symbol(T, Decl(noCrashOnMixin.ts, 8, 17))
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
>Mixin : Symbol(Mixin, Decl(noCrashOnMixin.ts, 8, 53))
|
||||
>TBase : Symbol(TBase, Decl(noCrashOnMixin.ts, 10, 15))
|
||||
>Constructor : Symbol(Constructor, Decl(noCrashOnMixin.ts, 6, 1))
|
||||
>Base : Symbol(Base, Decl(noCrashOnMixin.ts, 10, 42))
|
||||
>TBase : Symbol(TBase, Decl(noCrashOnMixin.ts, 10, 15))
|
||||
|
||||
return class extends Base {
|
||||
>Base : Symbol(Base, Decl(noCrashOnMixin.ts, 10, 42))
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
>Empty : Symbol(Empty, Decl(noCrashOnMixin.ts, 13, 1))
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
>CrashTrigger : Symbol(CrashTrigger, Decl(noCrashOnMixin.ts, 16, 1))
|
||||
>Mixin : Symbol(Mixin, Decl(noCrashOnMixin.ts, 8, 53))
|
||||
>Empty : Symbol(Empty, Decl(noCrashOnMixin.ts, 13, 1))
|
||||
|
||||
public trigger() {
|
||||
>trigger : Symbol(CrashTrigger.trigger, Decl(noCrashOnMixin.ts, 18, 41))
|
||||
|
||||
new Concrete();
|
||||
>Concrete : Symbol(Concrete, Decl(noCrashOnMixin.ts, 3, 1))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
=== tests/cases/compiler/noCrashOnMixin.ts ===
|
||||
class Abstract {
|
||||
>Abstract : Abstract
|
||||
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
>Concrete : Concrete
|
||||
>Abstract : Abstract
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
>Constructor : Constructor<T>
|
||||
>T : T
|
||||
>args : any[]
|
||||
>T : T
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
>Mixin : <TBase extends Constructor<{}>>(Base: TBase) => { new (...args: any[]): (Anonymous class); prototype: Mixin<any>.(Anonymous class); } & TBase
|
||||
>TBase : TBase
|
||||
>Constructor : Constructor<T>
|
||||
>Base : TBase
|
||||
>TBase : TBase
|
||||
|
||||
return class extends Base {
|
||||
>class extends Base { } : { new (...args: any[]): (Anonymous class); prototype: Mixin<any>.(Anonymous class); } & TBase
|
||||
>Base : {}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
>Empty : Empty
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
>CrashTrigger : CrashTrigger
|
||||
>Mixin(Empty) : Mixin<typeof Empty>.(Anonymous class) & Empty
|
||||
>Mixin : <TBase extends Constructor<{}>>(Base: TBase) => { new (...args: any[]): (Anonymous class); prototype: Mixin<any>.(Anonymous class); } & TBase
|
||||
>Empty : typeof Empty
|
||||
|
||||
public trigger() {
|
||||
>trigger : () => void
|
||||
|
||||
new Concrete();
|
||||
>new Concrete() : any
|
||||
>Concrete : typeof Concrete
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,13 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
|
||||
==== tests/cases/compiler/reachabilityChecks1.ts (7 errors) ====
|
||||
while (true);
|
||||
var x = 1;
|
||||
~~~
|
||||
~~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
|
||||
module A {
|
||||
while (true);
|
||||
let x;
|
||||
~~~
|
||||
~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
@@ -30,10 +30,12 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
|
||||
module A2 {
|
||||
while (true);
|
||||
module A {
|
||||
~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
~~~~~~~~~~
|
||||
var x = 1;
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
}
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
module A3 {
|
||||
@@ -44,10 +46,12 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
|
||||
module A4 {
|
||||
while (true);
|
||||
module A {
|
||||
~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
~~~~~~~~~~
|
||||
const enum E { X }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
}
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
function f1(x) {
|
||||
@@ -63,9 +67,10 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
|
||||
function f2() {
|
||||
return;
|
||||
class A {
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
~~~~~~~~~
|
||||
}
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
module B {
|
||||
@@ -78,10 +83,12 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
|
||||
do {
|
||||
} while (true);
|
||||
enum E {
|
||||
~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
~~~~~~~~
|
||||
X = 1
|
||||
~~~~~~~~~~~~~
|
||||
}
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
function f4() {
|
||||
@@ -89,10 +96,12 @@ tests/cases/compiler/reachabilityChecks1.ts(69,5): error TS7027: Unreachable cod
|
||||
throw new Error();
|
||||
}
|
||||
const enum E {
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
~~~~~~~~~~~~~~
|
||||
X = 1
|
||||
~~~~~~~~~~~~~
|
||||
}
|
||||
~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,17 @@ tests/cases/compiler/reachabilityChecks2.ts(4,1): error TS7027: Unreachable code
|
||||
const enum E { X }
|
||||
|
||||
module A4 {
|
||||
~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
~~~~~~~~~~~
|
||||
while (true);
|
||||
~~~~~~~~~~~~~~~~~
|
||||
module A {
|
||||
~~~~~~~~~~~~~~
|
||||
const enum E { X }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
}
|
||||
~~~~~
|
||||
}
|
||||
~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ tests/cases/compiler/reachabilityChecks5.ts(122,13): error TS7027: Unreachable c
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
~~~~~~
|
||||
~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ tests/cases/compiler/reachabilityChecks5.ts(122,13): error TS7027: Unreachable c
|
||||
try {
|
||||
while (false) {
|
||||
return 1;
|
||||
~~~~~~
|
||||
~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ tests/cases/compiler/reachabilityChecks5.ts(122,13): error TS7027: Unreachable c
|
||||
break test;
|
||||
} while (true);
|
||||
x++;
|
||||
~
|
||||
~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ tests/cases/compiler/reachabilityChecks6.ts(122,13): error TS7027: Unreachable c
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
~~~~~~
|
||||
~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ tests/cases/compiler/reachabilityChecks6.ts(122,13): error TS7027: Unreachable c
|
||||
try {
|
||||
while (false) {
|
||||
return 1;
|
||||
~~~~~~
|
||||
~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ tests/cases/compiler/reachabilityChecks6.ts(122,13): error TS7027: Unreachable c
|
||||
break test;
|
||||
} while (true);
|
||||
x++;
|
||||
~
|
||||
~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
tests/cases/compiler/unreachable.js(3,5): error TS7027: Unreachable code detected.
|
||||
tests/cases/compiler/unreachable.js(6,5): error TS7027: Unreachable code detected.
|
||||
|
||||
|
||||
==== tests/cases/compiler/unreachable.js (1 errors) ====
|
||||
==== tests/cases/compiler/unreachable.js (2 errors) ====
|
||||
function unreachable() {
|
||||
return 1;
|
||||
return f();
|
||||
return 2;
|
||||
~~~~~~
|
||||
~~~~~~~~~
|
||||
return 3;
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
function f() {}
|
||||
return 4;
|
||||
~~~~~~~~~
|
||||
!!! error TS7027: Unreachable code detected.
|
||||
}
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
//// [unreachable.js]
|
||||
function unreachable() {
|
||||
return 1;
|
||||
return f();
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
function f() {}
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
//// [unreachable.js]
|
||||
function unreachable() {
|
||||
return 1;
|
||||
return f();
|
||||
return 2;
|
||||
return 3;
|
||||
function f() { }
|
||||
return 4;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
function unreachable() {
|
||||
>unreachable : Symbol(unreachable, Decl(unreachable.js, 0, 0))
|
||||
|
||||
return 1;
|
||||
return f();
|
||||
>f : Symbol(f, Decl(unreachable.js, 3, 13))
|
||||
|
||||
return 2;
|
||||
return 3;
|
||||
function f() {}
|
||||
>f : Symbol(f, Decl(unreachable.js, 3, 13))
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
=== tests/cases/compiler/unreachable.js ===
|
||||
function unreachable() {
|
||||
>unreachable : () => 1 | 2
|
||||
>unreachable : () => void | 2 | 3 | 4
|
||||
|
||||
return 1;
|
||||
>1 : 1
|
||||
return f();
|
||||
>f() : void
|
||||
>f : () => void
|
||||
|
||||
return 2;
|
||||
>2 : 2
|
||||
|
||||
return 3;
|
||||
>3 : 3
|
||||
|
||||
function f() {}
|
||||
>f : () => void
|
||||
|
||||
return 4;
|
||||
>4 : 4
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// @allowjs: true
|
||||
// @checkjs: true
|
||||
// @noEmit: true
|
||||
// @Filename: bug25434.js
|
||||
// should not crash while checking
|
||||
function Test({ b = '' } = {}) {}
|
||||
|
||||
Test(({ b = '5' } = {}));
|
||||
@@ -10,3 +10,9 @@ interface Container<T> {
|
||||
declare function foo(x: () => Container<Ref<number>>): void;
|
||||
let a: () => Container<Ref<string>>;
|
||||
foo(a);
|
||||
|
||||
// Repro for #25498
|
||||
|
||||
function test(): {[A in "foo"]: A} {
|
||||
return {foo: "bar"};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
class Abstract {
|
||||
protected constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
class Concrete extends Abstract {
|
||||
}
|
||||
|
||||
type Constructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
function Mixin<TBase extends Constructor>(Base: TBase) {
|
||||
return class extends Base {
|
||||
};
|
||||
}
|
||||
|
||||
class Empty {
|
||||
}
|
||||
|
||||
class CrashTrigger extends Mixin(Empty) {
|
||||
public trigger() {
|
||||
new Concrete();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,9 @@
|
||||
// @outDir: out
|
||||
// @allowUnreachableCode: false
|
||||
function unreachable() {
|
||||
return 1;
|
||||
return f();
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
function f() {}
|
||||
return 4;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @Filename: bug25097.js
|
||||
/** @type {C | null} */
|
||||
const c = null
|
||||
class C {
|
||||
}
|
||||
@@ -1,20 +1,51 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.tsx
|
||||
// Using separate files for each example to avoid unclosed JSX tags affecting other tests.
|
||||
|
||||
// @Filename: /0.tsx
|
||||
////const x = <div>/*0*/;
|
||||
|
||||
// @Filename: /1.tsx
|
||||
////const x = <div> foo/*1*/ </div>;
|
||||
|
||||
// @Filename: /2.tsx
|
||||
////const x = <div></div>/*2*/;
|
||||
|
||||
// @Filename: /3.tsx
|
||||
////const x = <div/>/*3*/;
|
||||
|
||||
// @Filename: /4.tsx
|
||||
////const x = <div>
|
||||
//// <p>/*4*/
|
||||
//// </div>
|
||||
////</p>;
|
||||
|
||||
// @Filename: /5.tsx
|
||||
////const x = <div> text /*5*/;
|
||||
|
||||
// @Filename: /6.tsx
|
||||
////const x = <div>
|
||||
//// <div>/*6*/
|
||||
////</div>;
|
||||
|
||||
// @Filename: /7.tsx
|
||||
////const x = <div>
|
||||
//// <p>/*7*/
|
||||
////</div>;
|
||||
|
||||
// @Filename: /8.tsx
|
||||
////const x = <div>
|
||||
//// <div>/*8*/</div>
|
||||
////</div>;
|
||||
|
||||
verify.jsxClosingTag({
|
||||
0: { newText: "</div>" },
|
||||
1: undefined,
|
||||
2: undefined,
|
||||
3: undefined,
|
||||
4: { newText: "</p>" },
|
||||
5: { newText: "</div>" },
|
||||
6: { newText: "</div>" },
|
||||
7: { newText: "</p>" },
|
||||
8: undefined,
|
||||
});
|
||||
|
||||
@@ -2,29 +2,30 @@
|
||||
|
||||
////function f() {
|
||||
//// return f();
|
||||
//// [|return|] 1;
|
||||
//// [|return 1;|]
|
||||
//// function f() {}
|
||||
//// return 2;
|
||||
//// [|return 2;|]
|
||||
//// type T = number;
|
||||
//// interface I {}
|
||||
//// const enum E {}
|
||||
//// enum E {}
|
||||
//// [|enum E {}|]
|
||||
//// namespace N { export type T = number; }
|
||||
//// namespace N { export const x: T = 0; }
|
||||
//// [|namespace N { export const x: T = 0; }|]
|
||||
//// var x: I;
|
||||
//// var y: T = 0;
|
||||
//// E; N; x; y;
|
||||
//// [|var y: T = 0;
|
||||
//// E; N; x; y;|]
|
||||
////}
|
||||
|
||||
verify.getSuggestionDiagnostics([{
|
||||
verify.getSuggestionDiagnostics(test.ranges().map((range): FourSlashInterface.Diagnostic => ({
|
||||
message: "Unreachable code detected.",
|
||||
code: 7027,
|
||||
reportsUnnecessary: true,
|
||||
}]);
|
||||
range,
|
||||
})));
|
||||
|
||||
verify.codeFix({
|
||||
description: "Remove unreachable code",
|
||||
index: 0,
|
||||
verify.codeFixAll({
|
||||
fixId: "fixUnreachableCode",
|
||||
fixAllDescription: "Remove all unreachable code",
|
||||
newFileContent:
|
||||
`function f() {
|
||||
return f();
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
// @noLib: true
|
||||
|
||||
// @Filename: /globals.d.ts
|
||||
////declare const Symbol: () => symbol;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////const privateSym = Symbol();
|
||||
////export const publicSym = Symbol();
|
||||
////export interface I {
|
||||
//// [privateSym]: number;
|
||||
//// [publicSym]: number;
|
||||
//// [defaultPublicSym]: number;
|
||||
//// n: number;
|
||||
////}
|
||||
////export const i: I;
|
||||
@@ -17,10 +22,21 @@
|
||||
|
||||
verify.completions({
|
||||
marker: "",
|
||||
// TODO: GH#25095 Should include `publicSym`
|
||||
exact: "n",
|
||||
exact: [
|
||||
"n",
|
||||
{ name: "publicSym", insertText: "[publicSym]", replacementSpan: test.ranges()[0], hasAction: true },
|
||||
],
|
||||
preferences: {
|
||||
includeInsertTextCompletions: true,
|
||||
includeCompletionsForModuleExports: true,
|
||||
},
|
||||
});
|
||||
|
||||
verify.applyCodeActionFromCompletion("", {
|
||||
name: "publicSym",
|
||||
source: "/a",
|
||||
description: `Add 'publicSym' to existing import declaration from "./a"`,
|
||||
newFileContent:
|
||||
`import { i, publicSym } from "./a";
|
||||
i.;`
|
||||
});
|
||||
|
||||
@@ -554,7 +554,6 @@ declare namespace FourSlashInterface {
|
||||
overloadsCount?: number;
|
||||
docComment?: string;
|
||||
text?: string;
|
||||
name?: string;
|
||||
parameterName?: string;
|
||||
parameterSpan?: string;
|
||||
parameterDocComment?: string;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
////import React, { Component } from 'react';
|
||||
////
|
||||
////export class Home extends Component[| {
|
||||
//// render()[| {
|
||||
//// return (
|
||||
//// [|<div>
|
||||
//// [|<h1>Hello, world!</h1>|]
|
||||
//// [|<ul>
|
||||
//// [|<li>
|
||||
//// [|<a [|href='https://get.asp.net/'|]>
|
||||
//// ASP.NET Core
|
||||
//// </a>|]
|
||||
//// </li>|]
|
||||
//// [|<li>[|<a [|href='https://facebook.github.io/react/'|]>React</a>|] for client-side code</li>|]
|
||||
//// [|<li>[|<a [|href='http://getbootstrap.com/'|]>Bootstrap</a>|] for layout and styling</li>|]
|
||||
//// </ul>|]
|
||||
//// <div
|
||||
//// [|accesskey="test"
|
||||
//// class="active"
|
||||
//// dir="auto"|] />
|
||||
//// <PageHeader [|title="Log in"
|
||||
//// {...[|{
|
||||
//// item: true,
|
||||
//// xs: 9,
|
||||
//// md: 5
|
||||
//// }|]}|]
|
||||
//// />
|
||||
//// </div>|]
|
||||
//// );
|
||||
//// }|]
|
||||
////}|]
|
||||
|
||||
verify.outliningSpansInCurrentFile(test.ranges(), "code");
|
||||
@@ -1,23 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////function foo<T>(x: T): T {
|
||||
//// throw null;
|
||||
////}
|
||||
////
|
||||
////foo("/**/")
|
||||
|
||||
goTo.marker();
|
||||
for (const triggerCharacter of ["<", "(", ","]) {
|
||||
edit.insert(triggerCharacter);
|
||||
verify.noSignatureHelpForTriggerReason({
|
||||
kind: "characterTyped",
|
||||
triggerCharacter,
|
||||
});
|
||||
verify.signatureHelpPresentForTriggerReason({
|
||||
kind: "retrigger",
|
||||
triggerCharacter,
|
||||
});
|
||||
edit.backspace();
|
||||
}
|
||||
verify.signatureHelpPresentForTriggerReason(/*triggerReason*/ undefined);
|
||||
verify.signatureHelpPresentForTriggerReason({ kind: "invoked" });
|
||||
@@ -0,0 +1,31 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////function foo<T>(x: T): T {
|
||||
//// throw null;
|
||||
////}
|
||||
////
|
||||
////foo("/*1*/");
|
||||
////foo('/*2*/');
|
||||
////foo(` ${100}/*3*/`);
|
||||
////foo(/* /*4*/ */);
|
||||
////foo(
|
||||
//// ///*5*/
|
||||
////);
|
||||
|
||||
for (const marker of test.markers()) {
|
||||
goTo.marker(marker);
|
||||
for (const triggerCharacter of ["<", "(", ","]) {
|
||||
edit.insert(triggerCharacter);
|
||||
verify.noSignatureHelpForTriggerReason({
|
||||
kind: "characterTyped",
|
||||
triggerCharacter,
|
||||
});
|
||||
verify.signatureHelpPresentForTriggerReason({
|
||||
kind: "retrigger",
|
||||
triggerCharacter,
|
||||
});
|
||||
edit.backspace();
|
||||
}
|
||||
verify.signatureHelpPresentForTriggerReason(/*triggerReason*/ undefined);
|
||||
verify.signatureHelpPresentForTriggerReason({ kind: "invoked" });
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////function foo<T>(x: T): T {
|
||||
//// throw null;
|
||||
////}
|
||||
////
|
||||
////foo(/*1*/"");
|
||||
////foo(` ${100/*2*/}`);
|
||||
////foo(/*3*/);
|
||||
////foo(100 /*4*/)
|
||||
////foo([/*5*/])
|
||||
////foo({ hello: "hello"/*6*/})
|
||||
|
||||
const charMap = {
|
||||
1: "(",
|
||||
2: ",",
|
||||
3: "(",
|
||||
4: "<",
|
||||
5: ",",
|
||||
6: ",",
|
||||
}
|
||||
|
||||
for (const markerName of Object.keys(charMap)) {
|
||||
const triggerCharacter = charMap[markerName];
|
||||
goTo.marker(markerName);
|
||||
edit.insert(triggerCharacter);
|
||||
verify.noSignatureHelpForTriggerReason({
|
||||
kind: "characterTyped",
|
||||
triggerCharacter,
|
||||
});
|
||||
verify.signatureHelpPresentForTriggerReason({
|
||||
kind: "retrigger",
|
||||
triggerCharacter,
|
||||
});
|
||||
edit.backspace(triggerCharacter.length);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////declare class ViewJayEss {
|
||||
//// constructor(obj: object);
|
||||
////}
|
||||
////new ViewJayEss({
|
||||
//// methods: {
|
||||
//// sayHello/**/
|
||||
//// }
|
||||
////});
|
||||
|
||||
goTo.marker();
|
||||
edit.insert("(");
|
||||
verify.noSignatureHelpForTriggerReason({
|
||||
kind: "characterTyped",
|
||||
triggerCharacter: "(",
|
||||
});
|
||||
|
||||
edit.insert(") {},");
|
||||
verify.noSignatureHelpForTriggerReason({
|
||||
kind: "characterTyped",
|
||||
triggerCharacter: ",",
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////declare function foo<T>(x: T, y: T): T;
|
||||
////
|
||||
////foo/*1*//*2*/;
|
||||
////foo(/*3*/100/*4*/);
|
||||
////foo/*5*//*6*/();
|
||||
|
||||
const charMap = {
|
||||
1: "(",
|
||||
2: "<",
|
||||
3: ",",
|
||||
4: ",",
|
||||
5: "(",
|
||||
6: "<",
|
||||
}
|
||||
|
||||
for (const markerName of Object.keys(charMap)) {
|
||||
const triggerCharacter = charMap[markerName];
|
||||
goTo.marker(markerName);
|
||||
edit.insert(triggerCharacter);
|
||||
verify.signatureHelpPresentForTriggerReason({
|
||||
kind: "characterTyped",
|
||||
triggerCharacter,
|
||||
});
|
||||
verify.signatureHelpPresentForTriggerReason({
|
||||
kind: "retrigger",
|
||||
triggerCharacter,
|
||||
});
|
||||
edit.backspace(triggerCharacter.length);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////declare function foo<T>(x: T, y: T): T;
|
||||
////declare function bar<U>(x: U, y: U): U;
|
||||
////
|
||||
////foo(bar/*1*/)
|
||||
|
||||
goTo.marker("1");
|
||||
|
||||
edit.insert("(");
|
||||
verify.signatureHelp({
|
||||
text: "bar<U>(x: U, y: U): U",
|
||||
triggerReason: {
|
||||
kind: "characterTyped",
|
||||
triggerCharacter: "(",
|
||||
}
|
||||
});
|
||||
edit.backspace();
|
||||
|
||||
edit.insert("<");
|
||||
verify.signatureHelp({
|
||||
text: "bar<U>(x: U, y: U): U",
|
||||
triggerReason: {
|
||||
kind: "characterTyped",
|
||||
triggerCharacter: "(",
|
||||
}
|
||||
});
|
||||
edit.backspace();
|
||||
|
||||
edit.insert(",");
|
||||
verify.signatureHelp({
|
||||
text: "foo(x: <U>(x: U, y: U) => U, y: <U>(x: U, y: U) => U): <U>(x: U, y: U) => U",
|
||||
triggerReason: {
|
||||
kind: "characterTyped",
|
||||
triggerCharacter: "(",
|
||||
}
|
||||
});
|
||||
edit.backspace();
|
||||
@@ -6,7 +6,6 @@
|
||||
"strict": false,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true,
|
||||
"outFile": "./bin/first-output.js"
|
||||
},
|
||||
"files": [
|
||||
|
||||
Reference in New Issue
Block a user