mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' of github.com:Microsoft/TypeScript into multiple-prologue-directives
This commit is contained in:
@@ -225,11 +225,11 @@ namespace ts {
|
||||
node.symbol = symbol;
|
||||
symbol.declarations = append(symbol.declarations, node);
|
||||
|
||||
if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) {
|
||||
if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.Module | SymbolFlags.Variable) && !symbol.exports) {
|
||||
symbol.exports = createSymbolTable();
|
||||
}
|
||||
|
||||
if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) {
|
||||
if (symbolFlags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && !symbol.members) {
|
||||
symbol.members = createSymbolTable();
|
||||
}
|
||||
|
||||
|
||||
+107
-39
@@ -2417,12 +2417,12 @@ namespace ts {
|
||||
// The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
|
||||
// module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
|
||||
function visit(symbol: Symbol | undefined): SymbolTable | undefined {
|
||||
if (!(symbol && symbol.flags & SymbolFlags.HasExports && pushIfUnique(visitedSymbols, symbol))) {
|
||||
if (!(symbol && symbol.exports && pushIfUnique(visitedSymbols, symbol))) {
|
||||
return;
|
||||
}
|
||||
const symbols = cloneMap(symbol.exports!);
|
||||
const symbols = cloneMap(symbol.exports);
|
||||
// All export * declarations are collected in an __export symbol by the binder
|
||||
const exportStars = symbol.exports!.get(InternalSymbolName.ExportStar);
|
||||
const exportStars = symbol.exports.get(InternalSymbolName.ExportStar);
|
||||
if (exportStars) {
|
||||
const nestedSymbols = createSymbolTable();
|
||||
const lookupTable = createMap<ExportCollisionTracker>() as ExportCollisionTrackerTable;
|
||||
@@ -7702,9 +7702,13 @@ namespace ts {
|
||||
return !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0;
|
||||
}
|
||||
|
||||
function getRestTypeOfSignature(signature: Signature) {
|
||||
function getRestTypeOfSignature(signature: Signature): Type {
|
||||
return tryGetRestTypeOfSignature(signature) || anyType;
|
||||
}
|
||||
|
||||
function tryGetRestTypeOfSignature(signature: Signature): Type | undefined {
|
||||
const type = getTypeOfRestParameter(signature);
|
||||
return type && getIndexTypeOfType(type, IndexKind.Number) || anyType;
|
||||
return type && getIndexTypeOfType(type, IndexKind.Number);
|
||||
}
|
||||
|
||||
function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean): Signature {
|
||||
@@ -19069,38 +19073,7 @@ namespace ts {
|
||||
diagnostics.add(createDiagnosticForNode(node, fallbackError));
|
||||
}
|
||||
|
||||
// No signature was applicable. We have already reported the errors for the invalid signature.
|
||||
// If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
|
||||
// Pick the longest signature. This way we can get a contextual type for cases like:
|
||||
// declare function f(a: { xa: number; xb: number; }, b: number);
|
||||
// f({ |
|
||||
// Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
|
||||
// declare function f<T>(k: keyof T);
|
||||
// f<Foo>("
|
||||
if (!produceDiagnostics) {
|
||||
Debug.assert(candidates.length > 0); // Else would have exited above.
|
||||
const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args!.length : apparentArgumentCount);
|
||||
const candidate = candidates[bestIndex];
|
||||
|
||||
const { typeParameters } = candidate;
|
||||
if (typeParameters && callLikeExpressionMayHaveTypeArguments(node) && node.typeArguments) {
|
||||
const typeArguments = node.typeArguments.map(getTypeOfNode) as Type[]; // TODO: GH#18217
|
||||
while (typeArguments.length > typeParameters.length) {
|
||||
typeArguments.pop();
|
||||
}
|
||||
while (typeArguments.length < typeParameters.length) {
|
||||
typeArguments.push(getDefaultTypeArgumentType(isInJavaScriptFile(node)));
|
||||
}
|
||||
|
||||
const instantiated = createSignatureInstantiation(candidate, typeArguments);
|
||||
candidates[bestIndex] = instantiated;
|
||||
return instantiated;
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
return resolveErrorCall(node);
|
||||
return produceDiagnostics || !args ? resolveErrorCall(node) : getCandidateForOverloadFailure(node, candidates, args, !!candidatesOutArray);
|
||||
|
||||
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
|
||||
candidateForArgumentError = undefined;
|
||||
@@ -19171,6 +19144,97 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// No signature was applicable. We have already reported the errors for the invalid signature.
|
||||
// If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
|
||||
function getCandidateForOverloadFailure(
|
||||
node: CallLikeExpression,
|
||||
candidates: Signature[],
|
||||
args: ReadonlyArray<Expression>,
|
||||
hasCandidatesOutArray: boolean,
|
||||
): Signature {
|
||||
Debug.assert(candidates.length > 0); // Else should not have called this.
|
||||
// Normally we will combine overloads. Skip this if they have type parameters since that's hard to combine.
|
||||
// Don't do this if there is a `candidatesOutArray`,
|
||||
// because then we want the chosen best candidate to be one of the overloads, not a combination.
|
||||
return hasCandidatesOutArray || candidates.length === 1 || candidates.some(c => !!c.typeParameters)
|
||||
? pickLongestCandidateSignature(node, candidates, args)
|
||||
: createUnionOfSignaturesForOverloadFailure(candidates);
|
||||
}
|
||||
|
||||
function createUnionOfSignaturesForOverloadFailure(candidates: ReadonlyArray<Signature>): Signature {
|
||||
const thisParameters = mapDefined(candidates, c => c.thisParameter);
|
||||
let thisParameter: Symbol | undefined;
|
||||
if (thisParameters.length) {
|
||||
thisParameter = createCombinedSymbolFromTypes(thisParameters, thisParameters.map(getTypeOfParameter));
|
||||
}
|
||||
const { min: minArgumentCount, max: maxNonRestParam } = minAndMax(candidates, getNumNonRestParameters);
|
||||
const parameters: Symbol[] = [];
|
||||
for (let i = 0; i < maxNonRestParam; i++) {
|
||||
const symbols = mapDefined(candidates, ({ parameters, hasRestParameter }) => hasRestParameter ?
|
||||
i < parameters.length - 1 ? parameters[i] : last(parameters) :
|
||||
i < parameters.length ? parameters[i] : undefined);
|
||||
Debug.assert(symbols.length !== 0);
|
||||
parameters.push(createCombinedSymbolFromTypes(symbols, mapDefined(candidates, candidate => tryGetTypeAtPosition(candidate, i))));
|
||||
}
|
||||
const restParameterSymbols = mapDefined(candidates, c => c.hasRestParameter ? last(c.parameters) : undefined);
|
||||
const hasRestParameter = restParameterSymbols.length !== 0;
|
||||
if (hasRestParameter) {
|
||||
const type = createArrayType(getUnionType(mapDefined(candidates, tryGetRestTypeOfSignature), UnionReduction.Subtype));
|
||||
parameters.push(createCombinedSymbolForOverloadFailure(restParameterSymbols, type));
|
||||
}
|
||||
return createSignature(
|
||||
candidates[0].declaration,
|
||||
/*typeParameters*/ undefined, // Before calling this we tested for `!candidates.some(c => !!c.typeParameters)`.
|
||||
thisParameter,
|
||||
parameters,
|
||||
/*resolvedReturnType*/ getIntersectionType(candidates.map(getReturnTypeOfSignature)),
|
||||
/*typePredicate*/ undefined,
|
||||
minArgumentCount,
|
||||
hasRestParameter,
|
||||
/*hasLiteralTypes*/ candidates.some(c => c.hasLiteralTypes));
|
||||
}
|
||||
|
||||
function getNumNonRestParameters(signature: Signature): number {
|
||||
const numParams = signature.parameters.length;
|
||||
return signature.hasRestParameter ? numParams - 1 : numParams;
|
||||
}
|
||||
|
||||
function createCombinedSymbolFromTypes(sources: ReadonlyArray<Symbol>, types: Type[]): Symbol {
|
||||
return createCombinedSymbolForOverloadFailure(sources, getUnionType(types, UnionReduction.Subtype));
|
||||
}
|
||||
|
||||
function createCombinedSymbolForOverloadFailure(sources: ReadonlyArray<Symbol>, type: Type): Symbol {
|
||||
// This function is currently only used for erroneous overloads, so it's good enough to just use the first source.
|
||||
return createSymbolWithType(first(sources), type);
|
||||
}
|
||||
|
||||
function pickLongestCandidateSignature(node: CallLikeExpression, candidates: Signature[], args: ReadonlyArray<Expression>): Signature {
|
||||
// Pick the longest signature. This way we can get a contextual type for cases like:
|
||||
// declare function f(a: { xa: number; xb: number; }, b: number);
|
||||
// f({ |
|
||||
// Also, use explicitly-supplied type arguments if they are provided, so we can get a contextual signature in cases like:
|
||||
// declare function f<T>(k: keyof T);
|
||||
// f<Foo>("
|
||||
const bestIndex = getLongestCandidateIndex(candidates, apparentArgumentCount === undefined ? args.length : apparentArgumentCount);
|
||||
const candidate = candidates[bestIndex];
|
||||
const { typeParameters } = candidate;
|
||||
if (!typeParameters) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
const typeArgumentNodes: ReadonlyArray<TypeNode> = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments || emptyArray : emptyArray;
|
||||
const typeArguments = typeArgumentNodes.map(n => getTypeOfNode(n) || anyType);
|
||||
while (typeArguments.length > typeParameters.length) {
|
||||
typeArguments.pop();
|
||||
}
|
||||
while (typeArguments.length < typeParameters.length) {
|
||||
typeArguments.push(getConstraintFromTypeParameter(typeParameters[typeArguments.length]) || getDefaultTypeArgumentType(isInJavaScriptFile(node)));
|
||||
}
|
||||
const instantiated = createSignatureInstantiation(candidate, typeArguments);
|
||||
candidates[bestIndex] = instantiated;
|
||||
return instantiated;
|
||||
}
|
||||
|
||||
function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number {
|
||||
let maxParamsIndex = -1;
|
||||
let maxParams = -1;
|
||||
@@ -19955,6 +20019,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getTypeAtPosition(signature: Signature, pos: number): Type {
|
||||
return tryGetTypeAtPosition(signature, pos) || anyType;
|
||||
}
|
||||
|
||||
function tryGetTypeAtPosition(signature: Signature, pos: number): Type | undefined {
|
||||
const paramCount = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
|
||||
if (pos < paramCount) {
|
||||
return getTypeOfParameter(signature.parameters[pos]);
|
||||
@@ -19970,9 +20038,9 @@ namespace ts {
|
||||
return tupleRestType;
|
||||
}
|
||||
}
|
||||
return getIndexTypeOfType(restType, IndexKind.Number) || anyType;
|
||||
return getIndexTypeOfType(restType, IndexKind.Number);
|
||||
}
|
||||
return anyType;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getRestTypeAtPosition(source: Signature, pos: number): Type {
|
||||
|
||||
@@ -2864,6 +2864,10 @@
|
||||
"category": "Error",
|
||||
"code": 5070
|
||||
},
|
||||
"Option '--resolveJsonModule' can only be specified when module code generation is 'commonjs'.": {
|
||||
"category": "Error",
|
||||
"code": 5071
|
||||
},
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
|
||||
@@ -2548,6 +2548,10 @@ namespace ts {
|
||||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy, "resolveJsonModule");
|
||||
}
|
||||
// Any emit other than common js is error
|
||||
else if (getEmitModuleKind(options) !== ModuleKind.CommonJS) {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs, "resolveJsonModule", "module");
|
||||
}
|
||||
}
|
||||
|
||||
// there has to be common source directory if user specified --outdir || --sourceRoot
|
||||
|
||||
@@ -171,8 +171,8 @@ namespace ts {
|
||||
}
|
||||
const t = getTypeOfSymbol(symbol);
|
||||
visitType(t); // Should handle members on classes and such
|
||||
if (symbol.flags & SymbolFlags.HasExports) {
|
||||
symbol.exports!.forEach(visitSymbol);
|
||||
if (symbol.exports) {
|
||||
symbol.exports.forEach(visitSymbol);
|
||||
}
|
||||
forEach(symbol.declarations, d => {
|
||||
// Type queries are too far resolved when we just visit the symbol's type
|
||||
|
||||
+65
-31
@@ -332,9 +332,9 @@ namespace ts {
|
||||
/*@internal*/
|
||||
export interface RecursiveDirectoryWatcherHost {
|
||||
watchDirectory: HostWatchDirectory;
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
getAccessibleSortedChildDirectories(path: string): ReadonlyArray<string>;
|
||||
directoryExists(dir: string): boolean;
|
||||
filePathComparer: Comparer<string>;
|
||||
realpath(s: string): string;
|
||||
}
|
||||
|
||||
@@ -345,60 +345,94 @@ namespace ts {
|
||||
*/
|
||||
/*@internal*/
|
||||
export function createRecursiveDirectoryWatcher(host: RecursiveDirectoryWatcherHost): (directoryName: string, callback: DirectoryWatcherCallback) => FileWatcher {
|
||||
type ChildWatches = ReadonlyArray<DirectoryWatcher>;
|
||||
interface DirectoryWatcher extends FileWatcher {
|
||||
childWatches: ChildWatches;
|
||||
interface ChildDirectoryWatcher extends FileWatcher {
|
||||
dirName: string;
|
||||
}
|
||||
type ChildWatches = ReadonlyArray<ChildDirectoryWatcher>;
|
||||
interface HostDirectoryWatcher {
|
||||
watcher: FileWatcher;
|
||||
childWatches: ChildWatches;
|
||||
refCount: number;
|
||||
}
|
||||
|
||||
const cache = createMap<HostDirectoryWatcher>();
|
||||
const callbackCache = createMultiMap<DirectoryWatcherCallback>();
|
||||
const filePathComparer = getStringComparer(!host.useCaseSensitiveFileNames);
|
||||
const toCanonicalFilePath = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
|
||||
return createDirectoryWatcher;
|
||||
|
||||
/**
|
||||
* Create the directory watcher for the dirPath.
|
||||
*/
|
||||
function createDirectoryWatcher(dirName: string, callback: DirectoryWatcherCallback): DirectoryWatcher {
|
||||
const watcher = host.watchDirectory(dirName, fileName => {
|
||||
// Call the actual callback
|
||||
callback(fileName);
|
||||
function createDirectoryWatcher(dirName: string, callback?: DirectoryWatcherCallback): ChildDirectoryWatcher {
|
||||
const dirPath = toCanonicalFilePath(dirName) as Path;
|
||||
let directoryWatcher = cache.get(dirPath);
|
||||
if (directoryWatcher) {
|
||||
directoryWatcher.refCount++;
|
||||
}
|
||||
else {
|
||||
directoryWatcher = {
|
||||
watcher: host.watchDirectory(dirName, fileName => {
|
||||
// Call the actual callback
|
||||
callbackCache.forEach((callbacks, rootDirName) => {
|
||||
if (rootDirName === dirPath || (startsWith(dirPath, rootDirName) && dirPath[rootDirName.length] === directorySeparator)) {
|
||||
callbacks.forEach(callback => callback(fileName));
|
||||
}
|
||||
});
|
||||
|
||||
// Iterate through existing children and update the watches if needed
|
||||
updateChildWatches(result, callback);
|
||||
});
|
||||
// Iterate through existing children and update the watches if needed
|
||||
updateChildWatches(dirName, dirPath);
|
||||
}),
|
||||
refCount: 1,
|
||||
childWatches: emptyArray
|
||||
};
|
||||
cache.set(dirPath, directoryWatcher);
|
||||
updateChildWatches(dirName, dirPath);
|
||||
}
|
||||
|
||||
let result: DirectoryWatcher = {
|
||||
close: () => {
|
||||
watcher.close();
|
||||
result.childWatches.forEach(closeFileWatcher);
|
||||
result = undefined!;
|
||||
},
|
||||
if (callback) {
|
||||
callbackCache.add(dirPath, callback);
|
||||
}
|
||||
|
||||
return {
|
||||
dirName,
|
||||
childWatches: emptyArray
|
||||
close: () => {
|
||||
const directoryWatcher = Debug.assertDefined(cache.get(dirPath));
|
||||
if (callback) callbackCache.remove(dirPath, callback);
|
||||
directoryWatcher.refCount--;
|
||||
|
||||
if (directoryWatcher.refCount) return;
|
||||
|
||||
cache.delete(dirPath);
|
||||
closeFileWatcherOf(directoryWatcher);
|
||||
directoryWatcher.childWatches.forEach(closeFileWatcher);
|
||||
}
|
||||
};
|
||||
updateChildWatches(result, callback);
|
||||
return result;
|
||||
}
|
||||
|
||||
function updateChildWatches(watcher: DirectoryWatcher, callback: DirectoryWatcherCallback) {
|
||||
function updateChildWatches(dirName: string, dirPath: Path) {
|
||||
// Iterate through existing children and update the watches if needed
|
||||
if (watcher) {
|
||||
watcher.childWatches = watchChildDirectories(watcher.dirName, watcher.childWatches, callback);
|
||||
const parentWatcher = cache.get(dirPath);
|
||||
if (parentWatcher) {
|
||||
parentWatcher.childWatches = watchChildDirectories(dirName, parentWatcher.childWatches);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch the directories in the parentDir
|
||||
*/
|
||||
function watchChildDirectories(parentDir: string, existingChildWatches: ChildWatches, callback: DirectoryWatcherCallback): ChildWatches {
|
||||
let newChildWatches: DirectoryWatcher[] | undefined;
|
||||
enumerateInsertsAndDeletes<string, DirectoryWatcher>(
|
||||
function watchChildDirectories(parentDir: string, existingChildWatches: ChildWatches): ChildWatches {
|
||||
let newChildWatches: ChildDirectoryWatcher[] | undefined;
|
||||
enumerateInsertsAndDeletes<string, ChildDirectoryWatcher>(
|
||||
host.directoryExists(parentDir) ? mapDefined(host.getAccessibleSortedChildDirectories(parentDir), child => {
|
||||
const childFullName = getNormalizedAbsolutePath(child, parentDir);
|
||||
// Filter our the symbolic link directories since those arent included in recursive watch
|
||||
// which is same behaviour when recursive: true is passed to fs.watch
|
||||
return host.filePathComparer(childFullName, host.realpath(childFullName)) === Comparison.EqualTo ? childFullName : undefined;
|
||||
return filePathComparer(childFullName, normalizePath(host.realpath(childFullName))) === Comparison.EqualTo ? childFullName : undefined;
|
||||
}) : emptyArray,
|
||||
existingChildWatches,
|
||||
(child, childWatcher) => host.filePathComparer(child, childWatcher.dirName),
|
||||
(child, childWatcher) => filePathComparer(child, childWatcher.dirName),
|
||||
createAndAddChildDirectoryWatcher,
|
||||
closeFileWatcher,
|
||||
addChildDirectoryWatcher
|
||||
@@ -410,14 +444,14 @@ namespace ts {
|
||||
* Create new childDirectoryWatcher and add it to the new ChildDirectoryWatcher list
|
||||
*/
|
||||
function createAndAddChildDirectoryWatcher(childName: string) {
|
||||
const result = createDirectoryWatcher(childName, callback);
|
||||
const result = createDirectoryWatcher(childName);
|
||||
addChildDirectoryWatcher(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add child directory watcher to the new ChildDirectoryWatcher list
|
||||
*/
|
||||
function addChildDirectoryWatcher(childWatcher: DirectoryWatcher) {
|
||||
function addChildDirectoryWatcher(childWatcher: ChildDirectoryWatcher) {
|
||||
(newChildWatches || (newChildWatches = [])).push(childWatcher);
|
||||
}
|
||||
}
|
||||
@@ -710,7 +744,7 @@ namespace ts {
|
||||
createWatchDirectoryUsing(dynamicPollingWatchFile || createDynamicPriorityPollingWatchFile({ getModifiedTime, setTimeout })) :
|
||||
watchDirectoryUsingFsWatch;
|
||||
const watchDirectoryRecursively = createRecursiveDirectoryWatcher({
|
||||
filePathComparer: getStringComparer(!useCaseSensitiveFileNames),
|
||||
useCaseSensitiveFileNames,
|
||||
directoryExists,
|
||||
getAccessibleSortedChildDirectories: path => getAccessibleFileSystemEntries(path).directories,
|
||||
watchDirectory,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3439,9 +3439,6 @@ namespace ts {
|
||||
|
||||
ExportHasLocal = Function | Class | Enum | ValueModule,
|
||||
|
||||
HasExports = Class | Enum | Module | Variable,
|
||||
HasMembers = Class | Interface | TypeLiteral | ObjectLiteral,
|
||||
|
||||
BlockScoped = BlockScopedVariable | Class | Enum,
|
||||
|
||||
PropertyOrAccessor = Property | Accessor,
|
||||
|
||||
@@ -8087,4 +8087,20 @@ namespace ts {
|
||||
Debug.assert(index !== -1);
|
||||
return arr.slice(index);
|
||||
}
|
||||
|
||||
export function minAndMax<T>(arr: ReadonlyArray<T>, getValue: (value: T) => number): { readonly min: number, readonly max: number } {
|
||||
Debug.assert(arr.length !== 0);
|
||||
let min = getValue(arr[0]);
|
||||
let max = min;
|
||||
for (let i = 1; i < arr.length; i++) {
|
||||
const value = getValue(arr[i]);
|
||||
if (value < min) {
|
||||
min = value;
|
||||
}
|
||||
else if (value > max) {
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return { min, max };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ namespace ts {
|
||||
case WatchLogLevel.TriggerOnly:
|
||||
return createFileWatcherWithTriggerLogging;
|
||||
case WatchLogLevel.Verbose:
|
||||
return createFileWatcherWithLogging;
|
||||
return addWatch === <any>watchDirectory ? createDirectoryWatcherWithLogging : createFileWatcherWithLogging;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,6 +413,25 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function createDirectoryWatcherWithLogging<H, T, U, V, X, Y>(host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<H, T, U, undefined>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined): FileWatcher {
|
||||
const watchInfo = `${watchCaption}:: Added:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`;
|
||||
log(watchInfo);
|
||||
const start = timestamp();
|
||||
const watcher = createFileWatcherWithTriggerLogging(host, file, cb, flags, passThrough, detailInfo1, detailInfo2, addWatch, log, watchCaption, getDetailWatchInfo);
|
||||
const elapsed = timestamp() - start;
|
||||
log(`Elapsed:: ${elapsed}ms ${watchInfo}`);
|
||||
return {
|
||||
close: () => {
|
||||
const watchInfo = `${watchCaption}:: Close:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`;
|
||||
log(watchInfo);
|
||||
const start = timestamp();
|
||||
watcher.close();
|
||||
const elapsed = timestamp() - start;
|
||||
log(`Elapsed:: ${elapsed}ms ${watchInfo}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createFileWatcherWithTriggerLogging<H, T, U, V, X, Y>(host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<H, T, U, undefined>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined): FileWatcher {
|
||||
return addWatch(host, file, (fileName, cbOptional) => {
|
||||
const triggerredInfo = `${watchCaption}:: Triggered with ${fileName}${cbOptional !== undefined ? cbOptional : ""}:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`;
|
||||
|
||||
@@ -352,9 +352,9 @@ interface Array<T> {}`
|
||||
if (tscWatchDirectory === Tsc_WatchDirectory.WatchFile) {
|
||||
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchFile(directory, () => cb(directory), PollingInterval.Medium);
|
||||
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
|
||||
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames,
|
||||
directoryExists: path => this.directoryExists(path),
|
||||
getAccessibleSortedChildDirectories: path => this.getDirectories(path),
|
||||
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
|
||||
watchDirectory,
|
||||
realpath: s => this.realpath(s)
|
||||
});
|
||||
@@ -362,9 +362,9 @@ interface Array<T> {}`
|
||||
else if (tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory) {
|
||||
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchDirectory(directory, fileName => cb(fileName), /*recursive*/ false);
|
||||
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
|
||||
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames,
|
||||
directoryExists: path => this.directoryExists(path),
|
||||
getAccessibleSortedChildDirectories: path => this.getDirectories(path),
|
||||
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
|
||||
watchDirectory,
|
||||
realpath: s => this.realpath(s)
|
||||
});
|
||||
@@ -373,9 +373,9 @@ interface Array<T> {}`
|
||||
const watchFile = createDynamicPriorityPollingWatchFile(this);
|
||||
const watchDirectory: HostWatchDirectory = (directory, cb) => watchFile(directory, () => cb(directory), PollingInterval.Medium);
|
||||
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
|
||||
useCaseSensitiveFileNames: this.useCaseSensitiveFileNames,
|
||||
directoryExists: path => this.directoryExists(path),
|
||||
getAccessibleSortedChildDirectories: path => this.getDirectories(path),
|
||||
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
|
||||
watchDirectory,
|
||||
realpath: s => this.realpath(s)
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* @internal */
|
||||
declare namespace ts.server {
|
||||
export type ActionSet = "action::set";
|
||||
export type ActionInvalidate = "action::invalidate";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
namespace ts.server {
|
||||
/*@internal*/
|
||||
export interface ScriptInfoVersion {
|
||||
svc: number;
|
||||
text: number;
|
||||
|
||||
@@ -1837,7 +1837,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private mapTextChangeToCodeEdit(project: Project, change: FileTextChanges): protocol.FileCodeEdits {
|
||||
return mapTextChangesToCodeEdits(change, project.getSourceFileOrConfigFile(this.normalizePath(change.fileName)));
|
||||
return mapTextChangesToCodeEditsForFile(change, project.getSourceFileOrConfigFile(this.normalizePath(change.fileName)));
|
||||
}
|
||||
|
||||
private mapTextChangeToCodeEditUsingScriptInfo(change: FileTextChanges): protocol.FileCodeEdits {
|
||||
@@ -2357,8 +2357,8 @@ namespace ts.server {
|
||||
return { file: fileName, start: scriptInfo.positionToLineOffset(textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) };
|
||||
}
|
||||
|
||||
function mapTextChangesToCodeEdits(textChanges: FileTextChanges, sourceFile: SourceFile | undefined): protocol.FileCodeEdits {
|
||||
Debug.assert(!!textChanges.isNewFile === !sourceFile);
|
||||
function mapTextChangesToCodeEditsForFile(textChanges: FileTextChanges, sourceFile: SourceFile | undefined): protocol.FileCodeEdits {
|
||||
Debug.assert(!!textChanges.isNewFile === !sourceFile, "Expected isNewFile for (only) new files", () => JSON.stringify({ isNewFile: textChanges.isNewFile, hasSourceFile: !!sourceFile }));
|
||||
if (sourceFile) {
|
||||
return {
|
||||
fileName: textChanges.fileName,
|
||||
|
||||
+12
-10
@@ -111,20 +111,22 @@ namespace ts.Completions {
|
||||
function completionInfoFromData(sourceFile: SourceFile, typeChecker: TypeChecker, compilerOptions: CompilerOptions, log: Log, completionData: CompletionData, preferences: UserPreferences): CompletionInfo | undefined {
|
||||
const { symbols, completionKind, isInSnippetScope, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, literals, symbolToOriginInfoMap, recommendedCompletion, isJsxInitializer } = completionData;
|
||||
|
||||
if (sourceFile.languageVariant === LanguageVariant.JSX && location && location.parent && isJsxClosingElement(location.parent)) {
|
||||
if (location && location.parent && isJsxClosingElement(location.parent)) {
|
||||
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
|
||||
// instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
|
||||
// For example:
|
||||
// var x = <div> </ /*1*/>
|
||||
// The completion list at "1" will contain "div" with type any
|
||||
// var x = <div> </ /*1*/
|
||||
// The completion list at "1" will contain "div>" with type any
|
||||
// And at `<div> </ /*1*/ >` (with a closing `>`), the completion list will contain "div".
|
||||
const tagName = location.parent.parent.openingElement.tagName;
|
||||
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false,
|
||||
entries: [{
|
||||
name: tagName.getFullText(),
|
||||
kind: ScriptElementKind.classElement,
|
||||
kindModifiers: undefined,
|
||||
sortText: "0",
|
||||
}]};
|
||||
const hasClosingAngleBracket = !!findChildOfKind(location.parent, SyntaxKind.GreaterThanToken, sourceFile);
|
||||
const entry: CompletionEntry = {
|
||||
name: tagName.getFullText(sourceFile) + (hasClosingAngleBracket ? "" : ">"),
|
||||
kind: ScriptElementKind.classElement,
|
||||
kindModifiers: undefined,
|
||||
sortText: "0",
|
||||
};
|
||||
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: false, entries: [entry] };
|
||||
}
|
||||
|
||||
const entries: CompletionEntry[] = [];
|
||||
|
||||
@@ -1463,12 +1463,14 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
/** Gets all symbols for one property. Does not get symbols for every property. */
|
||||
function getPropertySymbolsFromContextualType(node: ObjectLiteralElement, checker: TypeChecker): ReadonlyArray<Symbol> {
|
||||
function getPropertySymbolsFromContextualType(node: ObjectLiteralElementWithName, checker: TypeChecker): ReadonlyArray<Symbol> {
|
||||
const contextualType = checker.getContextualType(<ObjectLiteralExpression>node.parent);
|
||||
const name = getNameFromPropertyName(node.name!);
|
||||
const symbol = contextualType && name && contextualType.getProperty(name);
|
||||
if (!contextualType) return emptyArray;
|
||||
const name = getNameFromPropertyName(node.name);
|
||||
if (!name) return emptyArray;
|
||||
const symbol = contextualType.getProperty(name);
|
||||
return symbol ? [symbol] :
|
||||
contextualType && contextualType.isUnion() ? mapDefined(contextualType.types, t => t.getProperty(name!)) : emptyArray; // TODO: GH#18217
|
||||
contextualType.isUnion() ? mapDefined(contextualType.types, t => t.getProperty(name)) : emptyArray;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1884,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);
|
||||
@@ -2181,21 +2186,23 @@ namespace ts {
|
||||
* Returns the containing object literal property declaration given a possible name node, e.g. "a" in x = { "a": 1 }
|
||||
*/
|
||||
/* @internal */
|
||||
export function getContainingObjectLiteralElement(node: Node): ObjectLiteralElement | undefined {
|
||||
export function getContainingObjectLiteralElement(node: Node): ObjectLiteralElementWithName | undefined {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
if (node.parent.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return isObjectLiteralElement(node.parent.parent) ? node.parent.parent : undefined;
|
||||
return isObjectLiteralElement(node.parent.parent) ? node.parent.parent as ObjectLiteralElementWithName : undefined;
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.Identifier:
|
||||
return isObjectLiteralElement(node.parent) &&
|
||||
(node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === SyntaxKind.JsxAttributes) &&
|
||||
node.parent.name === node ? node.parent : undefined;
|
||||
node.parent.name === node ? node.parent as ObjectLiteralElementWithName : undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/* @internal */
|
||||
export type ObjectLiteralElementWithName = ObjectLiteralElement & { name: PropertyName };
|
||||
|
||||
/* @internal */
|
||||
export function getPropertySymbolsFromContextualType(typeChecker: TypeChecker, node: ObjectLiteralElement): Symbol[] {
|
||||
|
||||
@@ -8589,10 +8589,10 @@ export const x = 10;`
|
||||
tscWatchDirectory === Tsc_WatchDirectory.WatchFile ?
|
||||
expectedWatchedFiles :
|
||||
createMap();
|
||||
// For failed resolution lookup and tsconfig files
|
||||
mapOfDirectories.set(projectFolder, 2);
|
||||
// For failed resolution lookup and tsconfig files => cached so only watched only once
|
||||
mapOfDirectories.set(projectFolder, 1);
|
||||
// Through above recursive watches
|
||||
mapOfDirectories.set(projectSrcFolder, 2);
|
||||
mapOfDirectories.set(projectSrcFolder, 1);
|
||||
// node_modules/@types folder
|
||||
mapOfDirectories.set(`${projectFolder}/${nodeModulesAtTypes}`, 1);
|
||||
const expectedCompletions = ["file1"];
|
||||
|
||||
Reference in New Issue
Block a user