mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into js-object-literal-assignments-as-declarations
This commit is contained in:
+1
-1
@@ -1308,7 +1308,7 @@ task("lint", ["build-rules"], () => {
|
||||
: `Gulpfile.ts scripts/generateLocalizedDiagnosticMessages.ts "scripts/tslint/**/*.ts" "src/**/*.ts" --exclude "src/lib/*.d.ts"`;
|
||||
const cmd = `node node_modules/tslint/bin/tslint ${files} --formatters-dir ./built/local/tslint/formatters --format autolinkableStylish`;
|
||||
console.log("Linting: " + cmd);
|
||||
jake.exec([cmd], { interactive: true }, () => {
|
||||
jake.exec([cmd], { interactive: true, windowsVerbatimArguments: true }, () => {
|
||||
if (fold.isTravis()) console.log(fold.end("lint"));
|
||||
complete();
|
||||
});
|
||||
|
||||
Vendored
+1
-2
@@ -792,8 +792,7 @@ interface Date {
|
||||
|
||||
interface DateConstructor {
|
||||
new(): Date;
|
||||
new(value: number): Date;
|
||||
new(value: string): Date;
|
||||
new(value: string | number): Date;
|
||||
new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;
|
||||
(): string;
|
||||
readonly prototype: Date;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Thank you for submitting a pull request!
|
||||
|
||||
Here's a checklist you might find useful.
|
||||
[ ] There is an associated issue that is labelled
|
||||
[ ] There is an associated issue that is labeled
|
||||
'Bug' or 'help wanted' or is in the Community milestone
|
||||
[ ] Code is up-to-date with the `master` branch
|
||||
[ ] You've successfully run `jake runtests` locally
|
||||
|
||||
@@ -55,7 +55,7 @@ function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: st
|
||||
const parsedMajorMinor = majorMinorMatch[1];
|
||||
ts.Debug.assert(parsedMajorMinor === majorMinor, "versionMajorMinor does not match.", () => `${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`);
|
||||
|
||||
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)`;/;
|
||||
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)(-dev)?`;/;
|
||||
const patchMatch = versionRgx.exec(tsFileContents);
|
||||
ts.Debug.assert(patchMatch !== null, "The file seems to no longer have a string matching", () => versionRgx.toString());
|
||||
const parsedPatch = patchMatch[1];
|
||||
@@ -85,4 +85,4 @@ function getPrereleasePatch(tag: string, plainPatch: string): string {
|
||||
return `${plainPatch}-${tag}.${timeStr}`;
|
||||
}
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -393,6 +393,10 @@ namespace ts {
|
||||
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
|
||||
: Diagnostics.Duplicate_identifier_0;
|
||||
|
||||
if (symbol.flags & SymbolFlags.Enum || includes & SymbolFlags.Enum) {
|
||||
message = Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations;
|
||||
}
|
||||
|
||||
if (symbol.declarations && symbol.declarations.length) {
|
||||
// If the current node is a default export of some sort, then check if
|
||||
// there are any other default exports that we need to error on.
|
||||
@@ -756,11 +760,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isNarrowingTypeofOperands(expr1: Expression, expr2: Expression) {
|
||||
return expr1.kind === SyntaxKind.TypeOfExpression && isNarrowableOperand((<TypeOfExpression>expr1).expression) && (expr2.kind === SyntaxKind.StringLiteral || expr2.kind === SyntaxKind.NoSubstitutionTemplateLiteral);
|
||||
return isTypeOfExpression(expr1) && isNarrowableOperand(expr1.expression) && isStringLiteralLike(expr2);
|
||||
}
|
||||
|
||||
function isNarrowableInOperands(left: Expression, right: Expression) {
|
||||
return (left.kind === SyntaxKind.StringLiteral || left.kind === SyntaxKind.NoSubstitutionTemplateLiteral) && isNarrowingExpression(right);
|
||||
return isStringLiteralLike(left) && isNarrowingExpression(right);
|
||||
}
|
||||
|
||||
function isNarrowingBinaryExpression(expr: BinaryExpression) {
|
||||
|
||||
@@ -41,15 +41,9 @@ namespace ts {
|
||||
program: Program;
|
||||
}
|
||||
|
||||
function hasSameKeys<T, U>(map1: ReadonlyMap<T> | undefined, map2: ReadonlyMap<U> | undefined) {
|
||||
if (map1 === undefined) {
|
||||
return map2 === undefined;
|
||||
}
|
||||
if (map2 === undefined) {
|
||||
return map1 === undefined;
|
||||
}
|
||||
function hasSameKeys<T, U>(map1: ReadonlyMap<T> | undefined, map2: ReadonlyMap<U> | undefined): boolean {
|
||||
// Has same size and every key is present in both maps
|
||||
return map1.size === map2.size && !forEachKey(map1, key => !map2.has(key));
|
||||
return map1 as ReadonlyMap<T | U> === map2 || map1 && map2 && map1.size === map2.size && !forEachKey(map1, key => !map2.has(key));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+306
-200
@@ -299,6 +299,10 @@ namespace ts {
|
||||
node = getParseTreeNode(node);
|
||||
return node && tryGetThisTypeAt(node);
|
||||
},
|
||||
getTypeArgumentConstraint: node => {
|
||||
node = getParseTreeNode(node, isTypeNode);
|
||||
return node && getTypeArgumentConstraint(node);
|
||||
},
|
||||
};
|
||||
|
||||
const tupleTypes: GenericType[] = [];
|
||||
@@ -572,8 +576,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
const enum MappedTypeModifiers {
|
||||
Readonly = 1 << 0,
|
||||
Optional = 1 << 1,
|
||||
IncludeReadonly = 1 << 0,
|
||||
ExcludeReadonly = 1 << 1,
|
||||
IncludeOptional = 1 << 2,
|
||||
ExcludeOptional = 1 << 3,
|
||||
}
|
||||
|
||||
const enum ExpandingFlags {
|
||||
@@ -870,8 +876,11 @@ namespace ts {
|
||||
error(getNameOfDeclaration(source.declarations[0]), Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target));
|
||||
}
|
||||
else {
|
||||
const message = target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable
|
||||
? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0;
|
||||
const message = target.flags & SymbolFlags.Enum || source.flags & SymbolFlags.Enum
|
||||
? Diagnostics.Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations
|
||||
: target.flags & SymbolFlags.BlockScopedVariable || source.flags & SymbolFlags.BlockScopedVariable
|
||||
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
|
||||
: Diagnostics.Duplicate_identifier_0;
|
||||
forEach(source.declarations, node => {
|
||||
error(getNameOfDeclaration(node) || node, message, symbolToString(source));
|
||||
});
|
||||
@@ -1157,7 +1166,7 @@ namespace ts {
|
||||
const originalLocation = location; // needed for did-you-mean error reporting, which gathers candidates starting from the original location
|
||||
let result: Symbol;
|
||||
let lastLocation: Node;
|
||||
let lastNonBlockLocation: Node;
|
||||
let lastSelfReferenceLocation: Node;
|
||||
let propertyWithInvalidInitializer: Node;
|
||||
const errorLocation = location;
|
||||
let grandparent: Node;
|
||||
@@ -1381,17 +1390,17 @@ namespace ts {
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isNonBlockLocation(location)) {
|
||||
lastNonBlockLocation = location;
|
||||
if (isSelfReferenceLocation(location)) {
|
||||
lastSelfReferenceLocation = location;
|
||||
}
|
||||
lastLocation = location;
|
||||
location = location.parent;
|
||||
}
|
||||
|
||||
// We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
|
||||
// If `result === lastNonBlockLocation.symbol`, that means that we are somewhere inside `lastNonBlockLocation` looking up a name, and resolving to `lastLocation` itself.
|
||||
// If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself.
|
||||
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
|
||||
if (isUse && result && nameNotFoundMessage && noUnusedIdentifiers && result !== lastNonBlockLocation.symbol) {
|
||||
if (isUse && result && nameNotFoundMessage && noUnusedIdentifiers && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) {
|
||||
result.isReferenced = true;
|
||||
}
|
||||
|
||||
@@ -1474,17 +1483,17 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function isNonBlockLocation({ kind }: Node): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseBlock:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.DefaultClause:
|
||||
return false;
|
||||
default:
|
||||
function isSelfReferenceLocation(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration: // For `namespace N { N; }`
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1503,7 +1512,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean {
|
||||
if ((errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(<Identifier>errorLocation)) || isInTypeQuery(errorLocation))) {
|
||||
if (!isIdentifier(errorLocation) || errorLocation.escapedText !== name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2031,12 +2040,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function resolveExternalModuleNameWorker(location: Node, moduleReferenceExpression: Expression, moduleNotFoundError: DiagnosticMessage, isForAugmentation = false): Symbol {
|
||||
if (moduleReferenceExpression.kind !== SyntaxKind.StringLiteral && moduleReferenceExpression.kind !== SyntaxKind.NoSubstitutionTemplateLiteral) {
|
||||
return;
|
||||
}
|
||||
|
||||
const moduleReferenceLiteral = <LiteralExpression>moduleReferenceExpression;
|
||||
return resolveExternalModule(location, moduleReferenceLiteral.text, moduleNotFoundError, moduleReferenceLiteral, isForAugmentation);
|
||||
return isStringLiteralLike(moduleReferenceExpression)
|
||||
? resolveExternalModule(location, moduleReferenceExpression.text, moduleNotFoundError, moduleReferenceExpression, isForAugmentation)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function resolveExternalModule(location: Node, moduleReference: string, moduleNotFoundError: DiagnosticMessage, errorNode: Node, isForAugmentation = false): Symbol {
|
||||
@@ -2471,10 +2477,6 @@ namespace ts {
|
||||
(ignoreQualification || canQualifySymbol(symbolFromSymbolTable, meaning));
|
||||
}
|
||||
|
||||
function isUMDExportSymbol(symbol: Symbol) {
|
||||
return symbol && symbol.declarations && symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]);
|
||||
}
|
||||
|
||||
function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined) {
|
||||
// If symbol is directly available by its name in the symbol table
|
||||
if (isAccessible(symbols.get(symbol.escapedName), /*resolvedAliasSymbol*/ undefined, ignoreQualification)) {
|
||||
@@ -2975,11 +2977,10 @@ namespace ts {
|
||||
|
||||
function createMappedTypeNodeFromType(type: MappedType) {
|
||||
Debug.assert(!!(type.flags & TypeFlags.Object));
|
||||
const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
|
||||
const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
|
||||
const readonlyToken = type.declaration.readonlyToken ? <ReadonlyToken | PlusToken | MinusToken>createToken(type.declaration.readonlyToken.kind) : undefined;
|
||||
const questionToken = type.declaration.questionToken ? <QuestionToken | PlusToken | MinusToken>createToken(type.declaration.questionToken.kind) : undefined;
|
||||
const typeParameterNode = typeParameterToDeclaration(getTypeParameterFromMappedType(type), context, getConstraintTypeFromMappedType(type));
|
||||
const templateTypeNode = typeToTypeNodeHelper(getTemplateTypeFromMappedType(type), context);
|
||||
|
||||
const mappedTypeNode = createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
|
||||
return setEmitFlags(mappedTypeNode, EmitFlags.SingleLine);
|
||||
}
|
||||
@@ -3226,7 +3227,8 @@ namespace ts {
|
||||
context.tracker.reportPrivateInBaseOfClassExpression(unescapeLeadingUnderscores(propertySymbol.escapedName));
|
||||
}
|
||||
}
|
||||
const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped ? anyType : getTypeOfSymbol(propertySymbol);
|
||||
const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ?
|
||||
anyType : getTypeOfSymbol(propertySymbol);
|
||||
const saveEnclosingDeclaration = context.enclosingDeclaration;
|
||||
context.enclosingDeclaration = undefined;
|
||||
if (getCheckFlags(propertySymbol) & CheckFlags.Late) {
|
||||
@@ -3249,7 +3251,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const savedFlags = context.flags;
|
||||
context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0;
|
||||
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
context.flags = savedFlags;
|
||||
|
||||
const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined;
|
||||
const propertySignature = createPropertySignature(
|
||||
@@ -4418,7 +4423,7 @@ namespace ts {
|
||||
type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true);
|
||||
}
|
||||
else {
|
||||
Debug.fail("Unhandled declaration kind! " + (ts as any).SyntaxKind[declaration.kind]);
|
||||
Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration));
|
||||
}
|
||||
|
||||
if (!popTypeResolution()) {
|
||||
@@ -5828,8 +5833,9 @@ namespace ts {
|
||||
|
||||
function resolveReverseMappedTypeMembers(type: ReverseMappedType) {
|
||||
const indexInfo = getIndexInfoOfType(type.source, IndexKind.String);
|
||||
const readonlyMask = type.mappedType.declaration.readonlyToken ? false : true;
|
||||
const optionalMask = type.mappedType.declaration.questionToken ? 0 : SymbolFlags.Optional;
|
||||
const modifiers = getMappedTypeModifiers(type.mappedType);
|
||||
const readonlyMask = modifiers & MappedTypeModifiers.IncludeReadonly ? false : true;
|
||||
const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional;
|
||||
const stringIndexInfo = indexInfo && createIndexInfo(inferReverseMappedType(indexInfo.type, type.mappedType), readonlyMask && indexInfo.isReadonly);
|
||||
const members = createSymbolTable();
|
||||
for (const prop of getPropertiesOfType(type.source)) {
|
||||
@@ -5855,8 +5861,7 @@ namespace ts {
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>type.target || type);
|
||||
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
|
||||
const templateReadonly = !!type.declaration.readonlyToken;
|
||||
const templateOptional = !!type.declaration.questionToken;
|
||||
const templateModifiers = getMappedTypeModifiers(type);
|
||||
const constraintDeclaration = type.declaration.typeParameter.constraint;
|
||||
if (constraintDeclaration.kind === SyntaxKind.TypeOperator &&
|
||||
(<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword) {
|
||||
@@ -5897,10 +5902,17 @@ namespace ts {
|
||||
if (t.flags & TypeFlags.StringLiteral) {
|
||||
const propName = escapeLeadingUnderscores((<StringLiteralType>t).value);
|
||||
const modifiersProp = getPropertyOfType(modifiersType, propName);
|
||||
const isOptional = templateOptional || !!(modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
|
||||
const checkFlags = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp) ? CheckFlags.Readonly : 0;
|
||||
const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, checkFlags);
|
||||
prop.type = propType;
|
||||
const isOptional = !!(templateModifiers & MappedTypeModifiers.IncludeOptional ||
|
||||
!(templateModifiers & MappedTypeModifiers.ExcludeOptional) && modifiersProp && modifiersProp.flags & SymbolFlags.Optional);
|
||||
const isReadonly = !!(templateModifiers & MappedTypeModifiers.IncludeReadonly ||
|
||||
!(templateModifiers & MappedTypeModifiers.ExcludeReadonly) && modifiersProp && isReadonlySymbol(modifiersProp));
|
||||
const prop = createSymbol(SymbolFlags.Property | (isOptional ? SymbolFlags.Optional : 0), propName, isReadonly ? CheckFlags.Readonly : 0);
|
||||
// When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the
|
||||
// type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks
|
||||
// mode, if the underlying property is optional we remove 'undefined' from the type.
|
||||
prop.type = strictNullChecks && isOptional && !isTypeAssignableTo(undefinedType, propType) ? getOptionalType(propType) :
|
||||
strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) :
|
||||
propType;
|
||||
if (propertySymbol) {
|
||||
prop.syntheticOrigin = propertySymbol;
|
||||
prop.declarations = propertySymbol.declarations;
|
||||
@@ -5909,7 +5921,7 @@ namespace ts {
|
||||
members.set(propName, prop);
|
||||
}
|
||||
else if (t.flags & (TypeFlags.Any | TypeFlags.String)) {
|
||||
stringIndexInfo = createIndexInfo(propType, templateReadonly);
|
||||
stringIndexInfo = createIndexInfo(propType, !!(templateModifiers & MappedTypeModifiers.IncludeReadonly));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5927,7 +5939,7 @@ namespace ts {
|
||||
function getTemplateTypeFromMappedType(type: MappedType) {
|
||||
return type.templateType ||
|
||||
(type.templateType = type.declaration.type ?
|
||||
instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !!type.declaration.questionToken), type.mapper || identityMapper) :
|
||||
instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !!(getMappedTypeModifiers(type) & MappedTypeModifiers.IncludeOptional)), type.mapper || identityMapper) :
|
||||
unknownType);
|
||||
}
|
||||
|
||||
@@ -5955,18 +5967,24 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers {
|
||||
return (type.declaration.readonlyToken ? MappedTypeModifiers.Readonly : 0) |
|
||||
(type.declaration.questionToken ? MappedTypeModifiers.Optional : 0);
|
||||
const declaration = type.declaration;
|
||||
return (declaration.readonlyToken ? declaration.readonlyToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeReadonly : MappedTypeModifiers.IncludeReadonly : 0) |
|
||||
(declaration.questionToken ? declaration.questionToken.kind === SyntaxKind.MinusToken ? MappedTypeModifiers.ExcludeOptional : MappedTypeModifiers.IncludeOptional : 0);
|
||||
}
|
||||
|
||||
function getCombinedMappedTypeModifiers(type: MappedType): MappedTypeModifiers {
|
||||
function getMappedTypeOptionality(type: MappedType): number {
|
||||
const modifiers = getMappedTypeModifiers(type);
|
||||
return modifiers & MappedTypeModifiers.ExcludeOptional ? -1 : modifiers & MappedTypeModifiers.IncludeOptional ? 1 : 0;
|
||||
}
|
||||
|
||||
function getCombinedMappedTypeOptionality(type: MappedType): number {
|
||||
const optionality = getMappedTypeOptionality(type);
|
||||
const modifiersType = getModifiersTypeFromMappedType(type);
|
||||
return getMappedTypeModifiers(type) |
|
||||
(isGenericMappedType(modifiersType) ? getMappedTypeModifiers(<MappedType>modifiersType) : 0);
|
||||
return optionality || (isGenericMappedType(modifiersType) ? getMappedTypeOptionality(<MappedType>modifiersType) : 0);
|
||||
}
|
||||
|
||||
function isPartialMappedType(type: Type) {
|
||||
return getObjectFlags(type) & ObjectFlags.Mapped && !!(<MappedType>type).declaration.questionToken;
|
||||
return !!(getObjectFlags(type) & ObjectFlags.Mapped && getMappedTypeModifiers(<MappedType>type) & MappedTypeModifiers.IncludeOptional);
|
||||
}
|
||||
|
||||
function isGenericMappedType(type: Type): type is MappedType {
|
||||
@@ -6108,11 +6126,13 @@ namespace ts {
|
||||
// with its constraint. We do this because if the constraint is a union type it will be distributed
|
||||
// over the conditional type and possibly reduced. For example, 'T extends undefined ? never : T'
|
||||
// removes 'undefined' from T.
|
||||
const checkType = type.checkType;
|
||||
if (checkType.flags & TypeFlags.TypeParameter) {
|
||||
const constraint = getConstraintOfTypeParameter(<TypeParameter>checkType);
|
||||
if (isDistributiveConditionalType(type)) {
|
||||
const constraint = getConstraintOfType(type.checkType);
|
||||
if (constraint) {
|
||||
return instantiateType(type, createTypeMapper([<TypeParameter>checkType], [constraint]));
|
||||
const target = type.target || type;
|
||||
const mapper = createTypeMapper([<TypeParameter>target.checkType], [constraint]);
|
||||
const combinedMapper = type.mapper ? combineTypeMappers(mapper, type.mapper) : mapper;
|
||||
return instantiateType(target, combinedMapper);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -6975,6 +6995,42 @@ namespace ts {
|
||||
return type.symbol && getDeclarationOfKind<TypeParameterDeclaration>(type.symbol, SyntaxKind.TypeParameter).constraint;
|
||||
}
|
||||
|
||||
function getInferredTypeParameterConstraint(typeParameter: TypeParameter) {
|
||||
let inferences: Type[];
|
||||
if (typeParameter.symbol) {
|
||||
for (const declaration of typeParameter.symbol.declarations) {
|
||||
// When an 'infer T' declaration is immediately contained in a type reference node
|
||||
// (such as 'Foo<infer T>'), T's constraint is inferred from the constraint of the
|
||||
// corresponding type parameter in 'Foo'. When multiple 'infer T' declarations are
|
||||
// present, we form an intersection of the inferred constraint types.
|
||||
if (declaration.parent.kind === SyntaxKind.InferType && declaration.parent.parent.kind === SyntaxKind.TypeReference) {
|
||||
const typeReference = <TypeReferenceNode>declaration.parent.parent;
|
||||
const typeParameters = getTypeParametersForTypeReference(typeReference);
|
||||
if (typeParameters) {
|
||||
const index = typeReference.typeArguments.indexOf(<TypeNode>declaration.parent);
|
||||
if (index < typeParameters.length) {
|
||||
const declaredConstraint = getConstraintOfTypeParameter(typeParameters[index]);
|
||||
if (declaredConstraint) {
|
||||
// Type parameter constraints can reference other type parameters so
|
||||
// constraints need to be instantiated. If instantiation produces the
|
||||
// type parameter itself, we discard that inference. For example, in
|
||||
// type Foo<T extends string, U extends T> = [T, U];
|
||||
// type Bar<T> = T extends Foo<infer X, infer X> ? Foo<X, X> : T;
|
||||
// the instantiated constraint for U is X, so we discard that inference.
|
||||
const mapper = createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReference, typeParameters));
|
||||
const constraint = instantiateType(declaredConstraint, mapper);
|
||||
if (constraint !== typeParameter) {
|
||||
inferences = append(inferences, constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return inferences && getIntersectionType(inferences);
|
||||
}
|
||||
|
||||
function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type {
|
||||
if (!typeParameter.constraint) {
|
||||
if (typeParameter.target) {
|
||||
@@ -6983,7 +7039,8 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const constraintDeclaration = getConstraintDeclaration(typeParameter);
|
||||
typeParameter.constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) : noConstraintType;
|
||||
typeParameter.constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) :
|
||||
getInferredTypeParameterConstraint(typeParameter) || noConstraintType;
|
||||
}
|
||||
}
|
||||
return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
|
||||
@@ -7090,12 +7147,8 @@ namespace ts {
|
||||
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs));
|
||||
return createTypeReference(<GenericType>type, typeArguments);
|
||||
}
|
||||
if (node.typeArguments) {
|
||||
error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
|
||||
return unknownType;
|
||||
return checkNoTypeArguments(node, symbol) ? type : unknownType;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function getTypeAliasInstantiation(symbol: Symbol, typeArguments: Type[]): Type {
|
||||
const type = getDeclaredTypeOfSymbol(symbol);
|
||||
@@ -7132,12 +7185,8 @@ namespace ts {
|
||||
}
|
||||
return getTypeAliasInstantiation(symbol, typeArguments);
|
||||
}
|
||||
if (node.typeArguments) {
|
||||
error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
|
||||
return unknownType;
|
||||
return checkNoTypeArguments(node, symbol) ? type : unknownType;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function getTypeReferenceName(node: TypeReferenceType): EntityNameOrEntityNameExpression | undefined {
|
||||
switch (node.kind) {
|
||||
@@ -7177,12 +7226,10 @@ namespace ts {
|
||||
|
||||
// Get type from reference to named type that cannot be generic (enum or type parameter)
|
||||
const res = tryGetDeclaredTypeOfSymbol(symbol);
|
||||
if (res !== undefined) {
|
||||
if (typeArguments) {
|
||||
error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
|
||||
return unknownType;
|
||||
}
|
||||
return res.flags & TypeFlags.TypeParameter ? getConstrainedTypeParameter(<TypeParameter>res, node) : res;
|
||||
if (res) {
|
||||
return checkNoTypeArguments(node, symbol) ?
|
||||
res.flags & TypeFlags.TypeParameter ? getConstrainedTypeParameter(<TypeParameter>res, node) : res :
|
||||
unknownType;
|
||||
}
|
||||
|
||||
if (!(symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node))) {
|
||||
@@ -7230,7 +7277,7 @@ namespace ts {
|
||||
|
||||
function getConstrainedTypeParameter(typeParameter: TypeParameter, node: Node) {
|
||||
let constraints: Type[];
|
||||
while (isTypeNode(node)) {
|
||||
while (isPartOfTypeNode(node)) {
|
||||
const parent = node.parent;
|
||||
if (parent.kind === SyntaxKind.ConditionalType && node === (<ConditionalTypeNode>parent).trueType) {
|
||||
if (getTypeFromTypeNode((<ConditionalTypeNode>parent).checkType) === typeParameter) {
|
||||
@@ -7246,39 +7293,58 @@ namespace ts {
|
||||
return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference;
|
||||
}
|
||||
|
||||
function checkNoTypeArguments(node: TypeReferenceType, symbol?: Symbol) {
|
||||
if (node.typeArguments) {
|
||||
error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : declarationNameToString((<TypeReferenceNode>node).typeName));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getIntendedTypeFromJSDocTypeReference(node: TypeReferenceNode): Type {
|
||||
if (isIdentifier(node.typeName)) {
|
||||
if (node.typeName.escapedText === "Object") {
|
||||
if (isJSDocIndexSignature(node)) {
|
||||
const indexed = getTypeFromTypeNode(node.typeArguments[0]);
|
||||
const target = getTypeFromTypeNode(node.typeArguments[1]);
|
||||
const index = createIndexInfo(target, /*isReadonly*/ false);
|
||||
return createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, indexed === stringType && index, indexed === numberType && index);
|
||||
}
|
||||
return anyType;
|
||||
}
|
||||
const typeArgs = node.typeArguments;
|
||||
switch (node.typeName.escapedText) {
|
||||
case "String":
|
||||
checkNoTypeArguments(node);
|
||||
return stringType;
|
||||
case "Number":
|
||||
checkNoTypeArguments(node);
|
||||
return numberType;
|
||||
case "Boolean":
|
||||
checkNoTypeArguments(node);
|
||||
return booleanType;
|
||||
case "Void":
|
||||
checkNoTypeArguments(node);
|
||||
return voidType;
|
||||
case "Undefined":
|
||||
checkNoTypeArguments(node);
|
||||
return undefinedType;
|
||||
case "Null":
|
||||
checkNoTypeArguments(node);
|
||||
return nullType;
|
||||
case "Function":
|
||||
case "function":
|
||||
checkNoTypeArguments(node);
|
||||
return globalFunctionType;
|
||||
case "Array":
|
||||
case "array":
|
||||
return !node.typeArguments || !node.typeArguments.length ? anyArrayType : undefined;
|
||||
return !typeArgs || !typeArgs.length ? anyArrayType : undefined;
|
||||
case "Promise":
|
||||
case "promise":
|
||||
return !node.typeArguments || !node.typeArguments.length ? createPromiseType(anyType) : undefined;
|
||||
return !typeArgs || !typeArgs.length ? createPromiseType(anyType) : undefined;
|
||||
case "Object":
|
||||
if (typeArgs && typeArgs.length === 2) {
|
||||
if (isJSDocIndexSignature(node)) {
|
||||
const indexed = getTypeFromTypeNode(typeArgs[0]);
|
||||
const target = getTypeFromTypeNode(typeArgs[1]);
|
||||
const index = createIndexInfo(target, /*isReadonly*/ false);
|
||||
return createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, indexed === stringType && index, indexed === numberType && index);
|
||||
}
|
||||
return anyType;
|
||||
}
|
||||
checkNoTypeArguments(node);
|
||||
return anyType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7303,7 +7369,7 @@ namespace ts {
|
||||
type = getTypeReferenceType(node, symbol);
|
||||
}
|
||||
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
|
||||
// type reference in checkTypeReferenceOrExpressionWithTypeArguments.
|
||||
// type reference in checkTypeReferenceNode.
|
||||
links.resolvedSymbol = symbol;
|
||||
links.resolvedType = type;
|
||||
}
|
||||
@@ -7952,7 +8018,7 @@ namespace ts {
|
||||
}
|
||||
if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) {
|
||||
if (isTypeAny(objectType)) {
|
||||
return anyType;
|
||||
return objectType;
|
||||
}
|
||||
const indexInfo = isTypeAssignableToKind(indexType, TypeFlags.NumberLike) && getIndexInfoOfType(objectType, IndexKind.Number) ||
|
||||
getIndexInfoOfType(objectType, IndexKind.String) ||
|
||||
@@ -8156,7 +8222,7 @@ namespace ts {
|
||||
// types with type parameters mapped to the wildcard type, the most permissive instantiations
|
||||
// possible (the wildcard type is assignable to and from all types). If those are not related,
|
||||
// then no instatiations will be and we can just return the false branch type.
|
||||
if (!isTypeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(extendsType))) {
|
||||
if (!typeMaybeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(extendsType))) {
|
||||
return instantiateType(baseFalseType, mapper);
|
||||
}
|
||||
// The check could be true for some instantiation
|
||||
@@ -8189,19 +8255,24 @@ namespace ts {
|
||||
const erasedCheckType = getActualTypeParameter(checkType);
|
||||
const trueType = instantiateType(baseTrueType, mapper);
|
||||
const falseType = instantiateType(baseFalseType, mapper);
|
||||
const id = target && (target.id + "," + erasedCheckType.id + "," + extendsType.id + "," + trueType.id + "," + falseType.id);
|
||||
const cached = id && conditionalTypes.get(id);
|
||||
// We compute the cache key from the ids of the four constituent types, plus an indicator of whether the
|
||||
// type is distributive (i.e. whether the original declaration has a type parameter as the check type).
|
||||
const isDistributive = (target ? target.checkType : erasedCheckType).flags & TypeFlags.TypeParameter ? 1 : 0;
|
||||
const id = erasedCheckType.id + "," + extendsType.id + "," + trueType.id + "," + falseType.id + "," + isDistributive;
|
||||
const cached = conditionalTypes.get(id);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const result = createConditionalType(erasedCheckType, extendsType, trueType, falseType,
|
||||
inferTypeParameters, target, mapper, aliasSymbol, instantiateTypes(baseAliasTypeArguments, mapper));
|
||||
if (id) {
|
||||
conditionalTypes.set(id, result);
|
||||
}
|
||||
conditionalTypes.set(id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function isDistributiveConditionalType(type: ConditionalType) {
|
||||
return !!((type.target || type).checkType.flags & TypeFlags.TypeParameter);
|
||||
}
|
||||
|
||||
function getInferTypeParameters(node: ConditionalTypeNode): TypeParameter[] {
|
||||
let result: TypeParameter[];
|
||||
if (node.locals) {
|
||||
@@ -8814,9 +8885,9 @@ namespace ts {
|
||||
// Check if we have a conditional type where the check type is a naked type parameter. If so,
|
||||
// the conditional type is distributive over union types and when T is instantiated to a union
|
||||
// type A | B, we produce (A extends U ? X : Y) | (B extends U ? X : Y).
|
||||
const checkType = target.checkType;
|
||||
if (checkType.flags & TypeFlags.TypeParameter) {
|
||||
const instantiatedType = combinedMapper(<TypeParameter>checkType);
|
||||
if (isDistributiveConditionalType(target)) {
|
||||
const checkType = <TypeParameter>target.checkType;
|
||||
const instantiatedType = combinedMapper(checkType);
|
||||
if (checkType !== instantiatedType && instantiatedType.flags & TypeFlags.Union) {
|
||||
return mapType(instantiatedType, t => instantiateConditionalType(target, createReplacementMapper(checkType, t, combinedMapper)));
|
||||
}
|
||||
@@ -9593,17 +9664,43 @@ namespace ts {
|
||||
|
||||
function isIdenticalTo(source: Type, target: Type): Ternary {
|
||||
let result: Ternary;
|
||||
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
|
||||
const flags = source.flags & target.flags;
|
||||
if (flags & TypeFlags.Object) {
|
||||
return recursiveTypeRelatedTo(source, target, /*reportErrors*/ false);
|
||||
}
|
||||
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union ||
|
||||
source.flags & TypeFlags.Intersection && target.flags & TypeFlags.Intersection) {
|
||||
if (flags & (TypeFlags.Union | TypeFlags.Intersection)) {
|
||||
if (result = eachTypeRelatedToSomeType(<UnionOrIntersectionType>source, <UnionOrIntersectionType>target)) {
|
||||
if (result &= eachTypeRelatedToSomeType(<UnionOrIntersectionType>target, <UnionOrIntersectionType>source)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Index) {
|
||||
return isRelatedTo((<IndexType>source).type, (<IndexType>target).type, /*reportErrors*/ false);
|
||||
}
|
||||
if (flags & TypeFlags.IndexedAccess) {
|
||||
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, /*reportErrors*/ false)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Conditional) {
|
||||
if (result = isRelatedTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<ConditionalType>source).trueType, (<ConditionalType>target).trueType, /*reportErrors*/ false)) {
|
||||
if (result &= isRelatedTo((<ConditionalType>source).falseType, (<ConditionalType>target).falseType, /*reportErrors*/ false)) {
|
||||
if (isDistributiveConditionalType(<ConditionalType>source) === isDistributiveConditionalType(<ConditionalType>target)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags & TypeFlags.Substitution) {
|
||||
return isRelatedTo((<SubstitutionType>source).substitute, (<SubstitutionType>target).substitute, /*reportErrors*/ false);
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
@@ -9890,7 +9987,7 @@ namespace ts {
|
||||
if (target.flags & TypeFlags.TypeParameter) {
|
||||
// A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P].
|
||||
if (getObjectFlags(source) & ObjectFlags.Mapped && getConstraintTypeFromMappedType(<MappedType>source) === getIndexType(target)) {
|
||||
if (!(<MappedType>source).declaration.questionToken) {
|
||||
if (!(getMappedTypeModifiers(<MappedType>source) & MappedTypeModifiers.IncludeOptional)) {
|
||||
const templateType = getTemplateTypeFromMappedType(<MappedType>source);
|
||||
const indexedAccessType = getIndexedAccessType(target, getTypeParameterFromMappedType(<MappedType>source));
|
||||
if (result = isRelatedTo(templateType, indexedAccessType, reportErrors)) {
|
||||
@@ -9929,6 +10026,8 @@ namespace ts {
|
||||
else if (isGenericMappedType(target)) {
|
||||
// A source type T is related to a target type { [P in X]: T[P] }
|
||||
const template = getTemplateTypeFromMappedType(<MappedType>target);
|
||||
const modifiers = getMappedTypeModifiers(<MappedType>target);
|
||||
if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) {
|
||||
if (template.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>template).objectType === source &&
|
||||
(<IndexedAccessType>template).indexType === getTypeParameterFromMappedType(<MappedType>target)) {
|
||||
return Ternary.True;
|
||||
@@ -9943,6 +10042,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (source.flags & TypeFlags.TypeParameter) {
|
||||
let constraint = getConstraintForRelation(<TypeParameter>source);
|
||||
@@ -9989,7 +10089,19 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result = isRelatedTo(getDefaultConstraintOfConditionalType(<ConditionalType>source), target, reportErrors)) {
|
||||
if (target.flags & TypeFlags.Conditional) {
|
||||
if (isTypeIdenticalTo((<ConditionalType>source).checkType, (<ConditionalType>target).checkType) &&
|
||||
isTypeIdenticalTo((<ConditionalType>source).extendsType, (<ConditionalType>target).extendsType)) {
|
||||
if (result = isRelatedTo((<ConditionalType>source).trueType, (<ConditionalType>target).trueType, reportErrors)) {
|
||||
result &= isRelatedTo((<ConditionalType>source).falseType, (<ConditionalType>target).falseType, reportErrors);
|
||||
}
|
||||
if (result) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (result = isRelatedTo(getDefaultConstraintOfConditionalType(<ConditionalType>source), target, reportErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
@@ -10080,8 +10192,7 @@ namespace ts {
|
||||
function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary {
|
||||
const modifiersRelated = relation === comparableRelation || (
|
||||
relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) :
|
||||
!(getCombinedMappedTypeModifiers(source) & MappedTypeModifiers.Optional) ||
|
||||
getCombinedMappedTypeModifiers(target) & MappedTypeModifiers.Optional);
|
||||
getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target));
|
||||
if (modifiersRelated) {
|
||||
let result: Ternary;
|
||||
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
|
||||
@@ -11124,7 +11235,7 @@ namespace ts {
|
||||
const t = getTypeOfSymbol(p);
|
||||
if (t.flags & TypeFlags.ContainsWideningType) {
|
||||
if (!reportWideningErrorsInType(t)) {
|
||||
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolName(p), typeToString(getWidenedType(t)));
|
||||
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolToString(p), typeToString(getWidenedType(t)));
|
||||
}
|
||||
errorReported = true;
|
||||
}
|
||||
@@ -12844,11 +12955,11 @@ namespace ts {
|
||||
const operator = expr.operatorToken.kind;
|
||||
const left = getReferenceCandidate(expr.left);
|
||||
const right = getReferenceCandidate(expr.right);
|
||||
if (left.kind === SyntaxKind.TypeOfExpression && (right.kind === SyntaxKind.StringLiteral || right.kind === SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
||||
return narrowTypeByTypeof(type, <TypeOfExpression>left, operator, <LiteralExpression>right, assumeTrue);
|
||||
if (left.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(right)) {
|
||||
return narrowTypeByTypeof(type, <TypeOfExpression>left, operator, right, assumeTrue);
|
||||
}
|
||||
if (right.kind === SyntaxKind.TypeOfExpression && (left.kind === SyntaxKind.StringLiteral || left.kind === SyntaxKind.NoSubstitutionTemplateLiteral)) {
|
||||
return narrowTypeByTypeof(type, <TypeOfExpression>right, operator, <LiteralExpression>left, assumeTrue);
|
||||
if (right.kind === SyntaxKind.TypeOfExpression && isStringLiteralLike(left)) {
|
||||
return narrowTypeByTypeof(type, <TypeOfExpression>right, operator, left, assumeTrue);
|
||||
}
|
||||
if (isMatchingReference(reference, left)) {
|
||||
return narrowTypeByEquality(type, operator, right, assumeTrue);
|
||||
@@ -12870,8 +12981,8 @@ namespace ts {
|
||||
return narrowTypeByInstanceof(type, expr, assumeTrue);
|
||||
case SyntaxKind.InKeyword:
|
||||
const target = getReferenceCandidate(expr.right);
|
||||
if ((expr.left.kind === SyntaxKind.StringLiteral || expr.left.kind === SyntaxKind.NoSubstitutionTemplateLiteral) && isMatchingReference(reference, target)) {
|
||||
return narrowByInKeyword(type, <LiteralExpression>expr.left, assumeTrue);
|
||||
if (isStringLiteralLike(expr.left) && isMatchingReference(reference, target)) {
|
||||
return narrowByInKeyword(type, expr.left, assumeTrue);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.CommaToken:
|
||||
@@ -16212,24 +16323,13 @@ namespace ts {
|
||||
propertyName: __String,
|
||||
type: Type): boolean {
|
||||
|
||||
if (type !== unknownType && !isTypeAny(type)) {
|
||||
const prop = getPropertyOfType(type, propertyName);
|
||||
if (prop) {
|
||||
return checkPropertyAccessibility(node, left, type, prop);
|
||||
}
|
||||
|
||||
// In js files properties of unions are allowed in completion
|
||||
if (isInJavaScriptFile(left) && (type.flags & TypeFlags.Union)) {
|
||||
for (const elementType of (<UnionType>type).types) {
|
||||
if (isValidPropertyAccessWithType(node, left, propertyName, elementType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (type === unknownType || isTypeAny(type)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
const prop = getPropertyOfType(type, propertyName);
|
||||
return prop ? checkPropertyAccessibility(node, left, type, prop)
|
||||
// In js files properties of unions are allowed in completion
|
||||
: isInJavaScriptFile(node) && (type.flags & TypeFlags.Union) && (<UnionType>type).types.some(elementType => isValidPropertyAccessWithType(node, left, propertyName, elementType));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -18348,7 +18448,7 @@ namespace ts {
|
||||
*
|
||||
* @param returnType - return type of the function, can be undefined if return type is not explicitly specified
|
||||
*/
|
||||
function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration, returnType: Type): void {
|
||||
function checkAllCodePathsInNonVoidFunctionReturnOrThrow(func: FunctionLikeDeclaration | MethodSignature, returnType: Type): void {
|
||||
if (!produceDiagnostics) {
|
||||
return;
|
||||
}
|
||||
@@ -18360,7 +18460,7 @@ namespace ts {
|
||||
|
||||
// If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check.
|
||||
// also if HasImplicitReturn flag is not set this means that all codepaths in function body end with return or throw
|
||||
if (nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func)) {
|
||||
if (func.kind === SyntaxKind.MethodSignature || nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block || !functionHasImplicitReturn(func)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19524,7 +19624,7 @@ namespace ts {
|
||||
return nullWideningType;
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
return getFreshTypeOfLiteralType(getLiteralType((node as LiteralExpression).text));
|
||||
return getFreshTypeOfLiteralType(getLiteralType((node as StringLiteralLike).text));
|
||||
case SyntaxKind.NumericLiteral:
|
||||
checkGrammarNumericLiteral(node as NumericLiteral);
|
||||
return getFreshTypeOfLiteralType(getLiteralType(+(node as NumericLiteral).text));
|
||||
@@ -20031,7 +20131,7 @@ namespace ts {
|
||||
checkVariableLikeDeclaration(node);
|
||||
}
|
||||
|
||||
function checkMethodDeclaration(node: MethodDeclaration) {
|
||||
function checkMethodDeclaration(node: MethodDeclaration | MethodSignature) {
|
||||
// Grammar checking
|
||||
if (!checkGrammarMethod(node)) checkGrammarComputedPropertyName(node.name);
|
||||
|
||||
@@ -20040,7 +20140,7 @@ namespace ts {
|
||||
|
||||
// Abstract methods cannot have an implementation.
|
||||
// Extra checks are to avoid reporting multiple errors relating to the "abstractness" of the node.
|
||||
if (hasModifier(node, ModifierFlags.Abstract) && node.body) {
|
||||
if (hasModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) {
|
||||
error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name));
|
||||
}
|
||||
}
|
||||
@@ -20187,8 +20287,12 @@ namespace ts {
|
||||
checkDecorators(node);
|
||||
}
|
||||
|
||||
function checkTypeArgumentConstraints(typeParameters: TypeParameter[], typeArgumentNodes: ReadonlyArray<TypeNode>): boolean {
|
||||
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
|
||||
function getEffectiveTypeArguments(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: TypeParameter[]) {
|
||||
return fillMissingTypeArguments(map(node.typeArguments, getTypeFromTypeNode), typeParameters,
|
||||
getMinTypeArgumentCount(typeParameters), isInJavaScriptFile(node));
|
||||
}
|
||||
|
||||
function checkTypeArgumentConstraints(node: TypeReferenceNode | ExpressionWithTypeArguments, typeParameters: TypeParameter[]): boolean {
|
||||
let typeArguments: Type[];
|
||||
let mapper: TypeMapper;
|
||||
let result = true;
|
||||
@@ -20196,25 +20300,35 @@ namespace ts {
|
||||
const constraint = getConstraintOfTypeParameter(typeParameters[i]);
|
||||
if (constraint) {
|
||||
if (!typeArguments) {
|
||||
typeArguments = fillMissingTypeArguments(map(typeArgumentNodes, getTypeFromTypeNode), typeParameters, minTypeArgumentCount, isInJavaScriptFile(typeArgumentNodes[i]));
|
||||
typeArguments = getEffectiveTypeArguments(node, typeParameters);
|
||||
mapper = createTypeMapper(typeParameters, typeArguments);
|
||||
}
|
||||
const typeArgument = typeArguments[i];
|
||||
result = result && checkTypeAssignableTo(
|
||||
typeArgument,
|
||||
typeArguments[i],
|
||||
instantiateType(constraint, mapper),
|
||||
typeArgumentNodes[i],
|
||||
node.typeArguments[i],
|
||||
Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getTypeParametersForTypeReference(node: TypeReferenceNode | ExpressionWithTypeArguments) {
|
||||
const type = getTypeFromTypeReference(node);
|
||||
if (type !== unknownType) {
|
||||
const symbol = getNodeLinks(node).resolvedSymbol;
|
||||
if (symbol) {
|
||||
return symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters ||
|
||||
(getObjectFlags(type) & ObjectFlags.Reference ? (<TypeReference>type).target.localTypeParameters : undefined);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
|
||||
checkGrammarTypeArguments(node, node.typeArguments);
|
||||
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJavaScriptFile(node) && !isInJSDoc(node)) {
|
||||
grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
|
||||
|
||||
}
|
||||
const type = getTypeFromTypeReference(node);
|
||||
if (type !== unknownType) {
|
||||
@@ -20222,22 +20336,10 @@ namespace ts {
|
||||
// Do type argument local checks only if referenced type is successfully resolved
|
||||
forEach(node.typeArguments, checkSourceElement);
|
||||
if (produceDiagnostics) {
|
||||
const symbol = getNodeLinks(node).resolvedSymbol;
|
||||
if (!symbol) {
|
||||
// There is no resolved symbol cached if the type resolved to a builtin
|
||||
// via JSDoc type reference resolution (eg, Boolean became boolean), none
|
||||
// of which are generic when they have no associated symbol
|
||||
// (additionally, JSDoc's index signature syntax, Object<string, T> actually uses generic syntax without being generic)
|
||||
if (!isJSDocIndexSignature(node)) {
|
||||
error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
|
||||
}
|
||||
return;
|
||||
const typeParameters = getTypeParametersForTypeReference(node);
|
||||
if (typeParameters) {
|
||||
checkTypeArgumentConstraints(node, typeParameters);
|
||||
}
|
||||
let typeParameters = symbol.flags & SymbolFlags.TypeAlias && getSymbolLinks(symbol).typeParameters;
|
||||
if (!typeParameters && getObjectFlags(type) & ObjectFlags.Reference) {
|
||||
typeParameters = (<TypeReference>type).target.localTypeParameters;
|
||||
}
|
||||
checkTypeArgumentConstraints(typeParameters, node.typeArguments);
|
||||
}
|
||||
}
|
||||
if (type.flags & TypeFlags.Enum && getNodeLinks(node).resolvedSymbol.flags & SymbolFlags.EnumMember) {
|
||||
@@ -20246,6 +20348,14 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeArgumentConstraint(node: TypeNode): Type | undefined {
|
||||
const typeReferenceNode = tryCast(node.parent, isTypeReferenceType);
|
||||
if (!typeReferenceNode) return undefined;
|
||||
const typeParameters = getTypeParametersForTypeReference(typeReferenceNode);
|
||||
const constraint = getConstraintOfTypeParameter(typeParameters[typeReferenceNode.typeArguments.indexOf(node)!]);
|
||||
return constraint && instantiateType(constraint, createTypeMapper(typeParameters, getEffectiveTypeArguments(typeReferenceNode, typeParameters)));
|
||||
}
|
||||
|
||||
function checkTypeQuery(node: TypeQueryNode) {
|
||||
getTypeFromTypeQueryNode(node);
|
||||
}
|
||||
@@ -20287,7 +20397,7 @@ namespace ts {
|
||||
const indexType = (<IndexedAccessType>type).indexType;
|
||||
if (isTypeAssignableTo(indexType, getIndexType(objectType))) {
|
||||
if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
|
||||
getObjectFlags(objectType) & ObjectFlags.Mapped && (<MappedType>objectType).declaration.readonlyToken) {
|
||||
getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(<MappedType>objectType) & MappedTypeModifiers.IncludeReadonly) {
|
||||
error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
|
||||
}
|
||||
return type;
|
||||
@@ -20671,7 +20781,7 @@ namespace ts {
|
||||
case SyntaxKind.ImportSpecifier: // https://github.com/Microsoft/TypeScript/pull/7591
|
||||
return DeclarationSpaces.ExportValue;
|
||||
default:
|
||||
Debug.fail((ts as any).SyntaxKind[d.kind]);
|
||||
Debug.fail(Debug.showSyntaxKind(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20867,7 +20977,7 @@ namespace ts {
|
||||
*
|
||||
* @param node The signature to check
|
||||
*/
|
||||
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration): Type {
|
||||
function checkAsyncFunctionReturnType(node: FunctionLikeDeclaration | MethodSignature): Type {
|
||||
// As part of our emit for an async function, we will need to emit the entity name of
|
||||
// the return type annotation as an expression. To meet the necessary runtime semantics
|
||||
// for __awaiter, we must also check that the type of the declaration (e.g. the static
|
||||
@@ -21229,7 +21339,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration): void {
|
||||
function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration | MethodSignature): void {
|
||||
checkDecorators(node);
|
||||
checkSignatureDeclaration(node);
|
||||
const functionFlags = getFunctionFlags(node);
|
||||
@@ -21271,7 +21381,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
checkSourceElement(node.body);
|
||||
const body = node.kind === SyntaxKind.MethodSignature ? undefined : node.body;
|
||||
checkSourceElement(body);
|
||||
|
||||
const returnTypeNode = getEffectiveReturnTypeNode(node);
|
||||
if ((functionFlags & FunctionFlags.Generator) === 0) { // Async function or normal function
|
||||
@@ -21284,11 +21395,11 @@ namespace ts {
|
||||
if (produceDiagnostics && !returnTypeNode) {
|
||||
// Report an implicit any error if there is no body, no explicit return type, and node is not a private method
|
||||
// in an ambient context
|
||||
if (noImplicitAny && nodeIsMissing(node.body) && !isPrivateWithinAmbient(node)) {
|
||||
if (noImplicitAny && nodeIsMissing(body) && !isPrivateWithinAmbient(node)) {
|
||||
reportImplicitAnyError(node, anyType);
|
||||
}
|
||||
|
||||
if (functionFlags & FunctionFlags.Generator && nodeIsPresent(node.body)) {
|
||||
if (functionFlags & FunctionFlags.Generator && nodeIsPresent(body)) {
|
||||
// A generator with a body and no type annotation can still cause errors. It can error if the
|
||||
// yielded values have no common supertype, or it can give an implicit any error if it has no
|
||||
// yielded values. The only way to trigger these errors is to try checking its return type.
|
||||
@@ -21954,20 +22065,6 @@ namespace ts {
|
||||
forEach(node.declarationList.declarations, checkSourceElement);
|
||||
}
|
||||
|
||||
function checkGrammarDisallowedModifiersOnObjectLiteralExpressionMethod(node: MethodDeclaration) {
|
||||
// We only disallow modifier on a method declaration if it is a property of object-literal-expression
|
||||
if (node.modifiers && node.parent.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
if (getFunctionFlags(node) & FunctionFlags.Async) {
|
||||
if (node.modifiers.length > 1) {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkExpressionStatement(node: ExpressionStatement) {
|
||||
// Grammar checking
|
||||
checkGrammarStatementInAmbientContext(node);
|
||||
@@ -22935,7 +23032,7 @@ namespace ts {
|
||||
if (some(baseTypeNode.typeArguments)) {
|
||||
forEach(baseTypeNode.typeArguments, checkSourceElement);
|
||||
for (const constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode)) {
|
||||
if (!checkTypeArgumentConstraints(constructor.typeParameters, baseTypeNode.typeArguments)) {
|
||||
if (!checkTypeArgumentConstraints(baseTypeNode, constructor.typeParameters)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -24021,7 +24118,7 @@ namespace ts {
|
||||
return checkSignatureDeclaration(<SignatureDeclaration>node);
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
return checkMethodDeclaration(<MethodDeclaration>node);
|
||||
return checkMethodDeclaration(<MethodDeclaration | MethodSignature>node);
|
||||
case SyntaxKind.Constructor:
|
||||
return checkConstructorDeclaration(<ConstructorDeclaration>node);
|
||||
case SyntaxKind.GetAccessor:
|
||||
@@ -24619,7 +24716,8 @@ namespace ts {
|
||||
|
||||
if (entityName.kind === SyntaxKind.Identifier) {
|
||||
if (isJSXTagName(entityName) && isJsxIntrinsicIdentifier(entityName)) {
|
||||
return getIntrinsicTagSymbol(<JsxOpeningLikeElement>entityName.parent);
|
||||
const symbol = getIntrinsicTagSymbol(<JsxOpeningLikeElement>entityName.parent);
|
||||
return symbol === unknownSymbol ? undefined : symbol;
|
||||
}
|
||||
|
||||
return resolveEntityName(entityName, SymbolFlags.Value, /*ignoreErrors*/ false, /*dontResolveAlias*/ true);
|
||||
@@ -24829,8 +24927,10 @@ namespace ts {
|
||||
|
||||
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
|
||||
const symbol = getSymbolAtLocation(node);
|
||||
const declaredType = symbol && getDeclaredTypeOfSymbol(symbol);
|
||||
return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol);
|
||||
if (symbol) {
|
||||
const declaredType = getDeclaredTypeOfSymbol(symbol);
|
||||
return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
return unknownType;
|
||||
@@ -25010,7 +25110,7 @@ namespace ts {
|
||||
// we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the
|
||||
// kinds that we do NOT prefix.
|
||||
const exportSymbol = getMergedSymbol(symbol.exportSymbol);
|
||||
if (!prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal) {
|
||||
if (!prefixLocals && exportSymbol.flags & SymbolFlags.ExportHasLocal && !(exportSymbol.flags & SymbolFlags.Variable)) {
|
||||
return undefined;
|
||||
}
|
||||
symbol = exportSymbol;
|
||||
@@ -26049,7 +26149,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean {
|
||||
function checkGrammarFunctionLikeDeclaration(node: FunctionLikeDeclaration | MethodSignature): boolean {
|
||||
// Prevent cascading error by short-circuit
|
||||
const file = getSourceFileOfNode(node);
|
||||
return checkGrammarDecoratorsAndModifiers(node) || checkGrammarTypeParameterList(node.typeParameters, file) ||
|
||||
@@ -26061,16 +26161,15 @@ namespace ts {
|
||||
return checkGrammarClassDeclarationHeritageClauses(node) || checkGrammarTypeParameterList(node.typeParameters, file);
|
||||
}
|
||||
|
||||
function checkGrammarArrowFunction(node: FunctionLikeDeclaration, file: SourceFile): boolean {
|
||||
if (node.kind === SyntaxKind.ArrowFunction) {
|
||||
const arrowFunction = <ArrowFunction>node;
|
||||
const startLine = getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.pos).line;
|
||||
const endLine = getLineAndCharacterOfPosition(file, arrowFunction.equalsGreaterThanToken.end).line;
|
||||
if (startLine !== endLine) {
|
||||
return grammarErrorOnNode(arrowFunction.equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow);
|
||||
}
|
||||
function checkGrammarArrowFunction(node: Node, file: SourceFile): boolean {
|
||||
if (!isArrowFunction(node)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
const { equalsGreaterThanToken } = node;
|
||||
const startLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.pos).line;
|
||||
const endLine = getLineAndCharacterOfPosition(file, equalsGreaterThanToken.end).line;
|
||||
return startLine !== endLine && grammarErrorOnNode(equalsGreaterThanToken, Diagnostics.Line_terminator_not_permitted_before_arrow);
|
||||
}
|
||||
|
||||
function checkGrammarIndexSignatureParameters(node: SignatureDeclaration): boolean {
|
||||
@@ -26535,19 +26634,26 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarMethod(node: MethodDeclaration) {
|
||||
if (checkGrammarDisallowedModifiersOnObjectLiteralExpressionMethod(node) ||
|
||||
checkGrammarFunctionLikeDeclaration(node) ||
|
||||
checkGrammarForGenerator(node)) {
|
||||
function checkGrammarMethod(node: MethodDeclaration | MethodSignature) {
|
||||
if (checkGrammarFunctionLikeDeclaration(node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) {
|
||||
return true;
|
||||
if (node.kind === SyntaxKind.MethodDeclaration) {
|
||||
if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
// We only disallow modifier on a method declaration if it is a property of object-literal-expression
|
||||
if (node.modifiers && !(node.modifiers.length === 1 && first(node.modifiers).kind === SyntaxKind.AsyncKeyword)) {
|
||||
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
|
||||
}
|
||||
else if (checkGrammarForInvalidQuestionMark(node.questionToken, Diagnostics.An_object_member_cannot_be_declared_optional)) {
|
||||
return true;
|
||||
}
|
||||
else if (node.body === undefined) {
|
||||
return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{");
|
||||
}
|
||||
}
|
||||
else if (node.body === undefined) {
|
||||
return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{");
|
||||
if (checkGrammarForGenerator(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26560,7 +26666,7 @@ namespace ts {
|
||||
if (node.flags & NodeFlags.Ambient) {
|
||||
return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_an_ambient_context_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type);
|
||||
}
|
||||
else if (!node.body) {
|
||||
else if (node.kind === SyntaxKind.MethodDeclaration && !node.body) {
|
||||
return checkGrammarForInvalidDynamicName(node.name, Diagnostics.A_computed_property_name_in_a_method_overload_must_refer_to_an_expression_whose_type_is_a_literal_type_or_a_unique_symbol_type);
|
||||
}
|
||||
}
|
||||
|
||||
+43
-3
@@ -6,7 +6,7 @@ namespace ts {
|
||||
// If changing the text in this section, be sure to test `configureNightly` too.
|
||||
export const versionMajorMinor = "2.8";
|
||||
/** The version of the TypeScript compiler release */
|
||||
export const version = `${versionMajorMinor}.0`;
|
||||
export const version = `${versionMajorMinor}.0-dev`;
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
@@ -794,6 +794,18 @@ namespace ts {
|
||||
return deduplicated;
|
||||
}
|
||||
|
||||
export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Comparer<T>): void {
|
||||
if (array.length === 0) {
|
||||
array.push(insert);
|
||||
return;
|
||||
}
|
||||
|
||||
const insertIndex = binarySearch(array, insert, identity, compare);
|
||||
if (insertIndex < 0) {
|
||||
array.splice(~insertIndex, 0, insert);
|
||||
}
|
||||
}
|
||||
|
||||
export function sortAndDeduplicate<T>(array: ReadonlyArray<T>, comparer: Comparer<T>, equalityComparer?: EqualityComparer<T>) {
|
||||
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
|
||||
}
|
||||
@@ -1454,7 +1466,7 @@ namespace ts {
|
||||
if (value !== undefined && test(value)) return value;
|
||||
|
||||
if (value && typeof (value as any).kind === "number") {
|
||||
Debug.fail(`Invalid cast. The supplied ${(ts as any).SyntaxKind[(value as any).kind]} did not pass the test '${Debug.getFunctionName(test)}'.`);
|
||||
Debug.fail(`Invalid cast. The supplied ${Debug.showSyntaxKind(value as any as Node)} did not pass the test '${Debug.getFunctionName(test)}'.`);
|
||||
}
|
||||
else {
|
||||
Debug.fail(`Invalid cast. The supplied value did not pass the test '${Debug.getFunctionName(test)}'.`);
|
||||
@@ -2889,6 +2901,13 @@ namespace ts {
|
||||
return value;
|
||||
}
|
||||
|
||||
export function assertEachDefined<T, A extends ReadonlyArray<T>>(value: A, message: string): A {
|
||||
for (const v of value) {
|
||||
assertDefined(v, message);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function assertNever(member: never, message?: string, stackCrawlMark?: AnyFunction): never {
|
||||
return fail(message || `Illegal value: ${member}`, stackCrawlMark || assertNever);
|
||||
}
|
||||
@@ -2906,6 +2925,27 @@ namespace ts {
|
||||
return match ? match[1] : "";
|
||||
}
|
||||
}
|
||||
|
||||
export function showSymbol(symbol: Symbol): string {
|
||||
const symbolFlags = (ts as any).SymbolFlags;
|
||||
return `{ flags: ${symbolFlags ? showFlags(symbol.flags, symbolFlags) : symbol.flags}; declarations: ${map(symbol.declarations, showSyntaxKind)} }`;
|
||||
}
|
||||
|
||||
function showFlags(flags: number, flagsEnum: { [flag: number]: string }): string {
|
||||
const out = [];
|
||||
for (let pow = 0; pow <= 30; pow++) {
|
||||
const n = 1 << pow;
|
||||
if (flags & n) {
|
||||
out.push(flagsEnum[n]);
|
||||
}
|
||||
}
|
||||
return out.join("|");
|
||||
}
|
||||
|
||||
export function showSyntaxKind(node: Node): string {
|
||||
const syntaxKind = (ts as any).SyntaxKind;
|
||||
return syntaxKind ? syntaxKind[node.kind] : node.kind.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove an item from an array, moving everything to its right one space left. */
|
||||
@@ -2985,7 +3025,7 @@ namespace ts {
|
||||
*/
|
||||
export function matchedText(pattern: Pattern, candidate: string): string {
|
||||
Debug.assert(isPatternMatch(pattern, candidate));
|
||||
return candidate.substr(pattern.prefix.length, candidate.length - pattern.suffix.length);
|
||||
return candidate.substring(pattern.prefix.length, candidate.length - pattern.suffix.length);
|
||||
}
|
||||
|
||||
/** Return the object corresponding to the best pattern to match `candidate`. */
|
||||
|
||||
@@ -593,7 +593,9 @@ namespace ts {
|
||||
writeLine();
|
||||
increaseIndent();
|
||||
if (node.readonlyToken) {
|
||||
write("readonly ");
|
||||
write(node.readonlyToken.kind === SyntaxKind.PlusToken ? "+readonly " :
|
||||
node.readonlyToken.kind === SyntaxKind.MinusToken ? "-readonly " :
|
||||
"readonly ");
|
||||
}
|
||||
write("[");
|
||||
writeEntityName(node.typeParameter.name);
|
||||
@@ -601,7 +603,9 @@ namespace ts {
|
||||
emitType(node.typeParameter.constraint);
|
||||
write("]");
|
||||
if (node.questionToken) {
|
||||
write("?");
|
||||
write(node.questionToken.kind === SyntaxKind.PlusToken ? "+?" :
|
||||
node.questionToken.kind === SyntaxKind.MinusToken ? "-?" :
|
||||
"?");
|
||||
}
|
||||
write(": ");
|
||||
emitType(node.type);
|
||||
|
||||
@@ -1984,6 +1984,11 @@
|
||||
"category": "Error",
|
||||
"code": 2566
|
||||
},
|
||||
"Enum declarations can only merge with namespace or other enum declarations.": {
|
||||
"category": "Error",
|
||||
"code": 2567
|
||||
},
|
||||
|
||||
"JSX element attributes type '{0}' may not be a union type.": {
|
||||
"category": "Error",
|
||||
"code": 2600
|
||||
|
||||
@@ -1251,14 +1251,20 @@ namespace ts {
|
||||
}
|
||||
if (node.readonlyToken) {
|
||||
emit(node.readonlyToken);
|
||||
if (node.readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) {
|
||||
writeKeyword("readonly");
|
||||
}
|
||||
writeSpace();
|
||||
}
|
||||
|
||||
writePunctuation("[");
|
||||
pipelineEmitWithNotification(EmitHint.MappedTypeParameter, node.typeParameter);
|
||||
writePunctuation("]");
|
||||
|
||||
emitIfPresent(node.questionToken);
|
||||
if (node.questionToken) {
|
||||
emit(node.questionToken);
|
||||
if (node.questionToken.kind !== SyntaxKind.QuestionToken) {
|
||||
writePunctuation("?");
|
||||
}
|
||||
}
|
||||
writePunctuation(":");
|
||||
writeSpace();
|
||||
emit(node.type);
|
||||
|
||||
@@ -804,7 +804,7 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
export function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
const node = createSynthesizedNode(SyntaxKind.MappedType) as MappedTypeNode;
|
||||
node.readonlyToken = readonlyToken;
|
||||
node.typeParameter = typeParameter;
|
||||
@@ -813,7 +813,7 @@ namespace ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
return node.readonlyToken !== readonlyToken
|
||||
|| node.typeParameter !== typeParameter
|
||||
|| node.questionToken !== questionToken
|
||||
|
||||
+24
-12
@@ -695,7 +695,7 @@ namespace ts {
|
||||
else if (token() === SyntaxKind.OpenBraceToken ||
|
||||
lookAhead(() => token() === SyntaxKind.StringLiteral)) {
|
||||
result.jsonObject = parseObjectLiteralExpression();
|
||||
sourceFile.endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, /*reportAtCurrentPosition*/ false, Diagnostics.Unexpected_token);
|
||||
sourceFile.endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, Diagnostics.Unexpected_token);
|
||||
}
|
||||
else {
|
||||
parseExpected(SyntaxKind.OpenBraceToken);
|
||||
@@ -1135,10 +1135,10 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): Token<TKind>;
|
||||
function parseExpectedToken(t: SyntaxKind, reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): Node {
|
||||
function parseExpectedToken<TKind extends SyntaxKind>(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<TKind>;
|
||||
function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node {
|
||||
return parseOptionalToken(t) ||
|
||||
createMissingNode(t, reportAtCurrentPosition, diagnosticMessage, arg0);
|
||||
createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t));
|
||||
}
|
||||
|
||||
function parseTokenNode<T extends Node>(): T {
|
||||
@@ -2113,7 +2113,7 @@ namespace ts {
|
||||
literal = parseTemplateMiddleOrTemplateTail();
|
||||
}
|
||||
else {
|
||||
literal = <TemplateTail>parseExpectedToken(SyntaxKind.TemplateTail, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
|
||||
literal = <TemplateTail>parseExpectedToken(SyntaxKind.TemplateTail, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
|
||||
}
|
||||
|
||||
span.literal = literal;
|
||||
@@ -2607,6 +2607,9 @@ namespace ts {
|
||||
|
||||
function isStartOfMappedType() {
|
||||
nextToken();
|
||||
if (token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
|
||||
return nextToken() === SyntaxKind.ReadonlyKeyword;
|
||||
}
|
||||
if (token() === SyntaxKind.ReadonlyKeyword) {
|
||||
nextToken();
|
||||
}
|
||||
@@ -2624,11 +2627,21 @@ namespace ts {
|
||||
function parseMappedType() {
|
||||
const node = <MappedTypeNode>createNode(SyntaxKind.MappedType);
|
||||
parseExpected(SyntaxKind.OpenBraceToken);
|
||||
node.readonlyToken = parseOptionalToken(SyntaxKind.ReadonlyKeyword);
|
||||
if (token() === SyntaxKind.ReadonlyKeyword || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
|
||||
node.readonlyToken = parseTokenNode();
|
||||
if (node.readonlyToken.kind !== SyntaxKind.ReadonlyKeyword) {
|
||||
parseExpectedToken(SyntaxKind.ReadonlyKeyword);
|
||||
}
|
||||
}
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
node.typeParameter = parseMappedTypeParameter();
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
|
||||
if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
|
||||
node.questionToken = parseTokenNode();
|
||||
if (node.questionToken.kind !== SyntaxKind.QuestionToken) {
|
||||
parseExpectedToken(SyntaxKind.QuestionToken);
|
||||
}
|
||||
}
|
||||
node.type = parseTypeAnnotation();
|
||||
parseSemicolon();
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
@@ -3242,7 +3255,7 @@ namespace ts {
|
||||
|
||||
node.parameters = createNodeArray<ParameterDeclaration>([parameter], parameter.pos, parameter.end);
|
||||
|
||||
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>");
|
||||
node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
|
||||
node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier);
|
||||
|
||||
return addJSDocComment(finishNode(node));
|
||||
@@ -3273,7 +3286,7 @@ namespace ts {
|
||||
// If we have an arrow, then try to parse the body. Even if not, try to parse if we
|
||||
// have an opening brace, just in case we're in an error state.
|
||||
const lastToken = token();
|
||||
arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>");
|
||||
arrowFunction.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken);
|
||||
arrowFunction.body = (lastToken === SyntaxKind.EqualsGreaterThanToken || lastToken === SyntaxKind.OpenBraceToken)
|
||||
? parseArrowFunctionExpressionBody(isAsync)
|
||||
: parseIdentifier();
|
||||
@@ -3539,8 +3552,7 @@ namespace ts {
|
||||
node.condition = leftOperand;
|
||||
node.questionToken = questionToken;
|
||||
node.whenTrue = doOutsideOfContext(disallowInAndDecoratorContext, parseAssignmentExpressionOrHigher);
|
||||
node.colonToken = parseExpectedToken(SyntaxKind.ColonToken, /*reportAtCurrentPosition*/ false,
|
||||
Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken));
|
||||
node.colonToken = parseExpectedToken(SyntaxKind.ColonToken);
|
||||
node.whenFalse = nodeIsPresent(node.colonToken)
|
||||
? parseAssignmentExpressionOrHigher()
|
||||
: createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.ColonToken));
|
||||
@@ -4014,7 +4026,7 @@ namespace ts {
|
||||
// If it wasn't then just try to parse out a '.' and report an error.
|
||||
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
|
||||
node.expression = expression;
|
||||
parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
parseExpectedToken(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
|
||||
node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
+6
-3
@@ -120,7 +120,10 @@ namespace ts {
|
||||
};
|
||||
|
||||
export let sys: System = (() => {
|
||||
const utf8ByteOrderMark = "\u00EF\u00BB\u00BF";
|
||||
// NodeJS detects "\uFEFF" at the start of the string and *replaces* it with the actual
|
||||
// byte order mark from the specified encoding. Using any other byte order mark does
|
||||
// not actually work.
|
||||
const byteOrderMarkIndicator = "\uFEFF";
|
||||
|
||||
function getNodeSystem(): System {
|
||||
const _fs = require("fs");
|
||||
@@ -367,7 +370,7 @@ namespace ts {
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
||||
// If a BOM is required, emit one
|
||||
if (writeByteOrderMark) {
|
||||
data = utf8ByteOrderMark + data;
|
||||
data = byteOrderMarkIndicator + data;
|
||||
}
|
||||
|
||||
let fd: number;
|
||||
@@ -572,7 +575,7 @@ namespace ts {
|
||||
writeFile(path: string, data: string, writeByteOrderMark?: boolean) {
|
||||
// If a BOM is required, emit one
|
||||
if (writeByteOrderMark) {
|
||||
data = utf8ByteOrderMark + data;
|
||||
data = byteOrderMarkIndicator + data;
|
||||
}
|
||||
|
||||
ChakraHost.writeFile(path, data);
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace ts {
|
||||
if (statement.kind === SyntaxKind.ForOfStatement && (<ForOfStatement>statement).awaitModifier) {
|
||||
return visitForOfStatement(<ForOfStatement>statement, node);
|
||||
}
|
||||
return restoreEnclosingLabel(visitEachChild(node, visitor, context), node);
|
||||
return restoreEnclosingLabel(visitEachChild(statement, visitor, context), node);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
@@ -214,9 +214,8 @@ namespace ts {
|
||||
* - this is mostly subjective beyond the requirement that the expression not be sideeffecting
|
||||
*/
|
||||
export function isSimpleCopiableExpression(expression: Expression) {
|
||||
return expression.kind === SyntaxKind.StringLiteral ||
|
||||
return isStringLiteralLike(expression) ||
|
||||
expression.kind === SyntaxKind.NumericLiteral ||
|
||||
expression.kind === SyntaxKind.NoSubstitutionTemplateLiteral ||
|
||||
isKeyword(expression.kind) ||
|
||||
isIdentifier(expression);
|
||||
}
|
||||
|
||||
+13
-13
@@ -661,6 +661,8 @@ namespace ts {
|
||||
export type AtToken = Token<SyntaxKind.AtToken>;
|
||||
export type ReadonlyToken = Token<SyntaxKind.ReadonlyKeyword>;
|
||||
export type AwaitKeywordToken = Token<SyntaxKind.AwaitKeyword>;
|
||||
export type PlusToken = Token<SyntaxKind.PlusToken>;
|
||||
export type MinusToken = Token<SyntaxKind.MinusToken>;
|
||||
|
||||
export type Modifier
|
||||
= Token<SyntaxKind.AbstractKeyword>
|
||||
@@ -983,6 +985,7 @@ namespace ts {
|
||||
|
||||
export interface MethodSignature extends SignatureDeclarationBase, TypeElement {
|
||||
kind: SyntaxKind.MethodSignature;
|
||||
parent?: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode;
|
||||
name: PropertyName;
|
||||
}
|
||||
|
||||
@@ -997,6 +1000,7 @@ namespace ts {
|
||||
// of the method, or use helpers like isObjectLiteralMethodDeclaration
|
||||
export interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer {
|
||||
kind: SyntaxKind.MethodDeclaration;
|
||||
parent?: ClassLikeDeclaration | ObjectLiteralExpression;
|
||||
name: PropertyName;
|
||||
body?: FunctionBody;
|
||||
}
|
||||
@@ -1156,9 +1160,9 @@ namespace ts {
|
||||
|
||||
export interface MappedTypeNode extends TypeNode, Declaration {
|
||||
kind: SyntaxKind.MappedType;
|
||||
readonlyToken?: ReadonlyToken;
|
||||
readonlyToken?: ReadonlyToken | PlusToken | MinusToken;
|
||||
typeParameter: TypeParameterDeclaration;
|
||||
questionToken?: QuestionToken;
|
||||
questionToken?: QuestionToken | PlusToken | MinusToken;
|
||||
type?: TypeNode;
|
||||
}
|
||||
|
||||
@@ -1174,7 +1178,7 @@ namespace ts {
|
||||
/* @internal */ singleQuote?: boolean;
|
||||
}
|
||||
|
||||
/* @internal */ export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
|
||||
export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
|
||||
|
||||
// Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing.
|
||||
// Consider 'Expression'. Without the brand, 'Expression' is actually no different
|
||||
@@ -2940,6 +2944,7 @@ namespace ts {
|
||||
/* @internal */ resolveExternalModuleSymbol(symbol: Symbol): Symbol;
|
||||
/** @param node A location where we might consider accessing `this`. Not necessarily a ThisExpression. */
|
||||
/* @internal */ tryGetThisTypeAt(node: Node): Type | undefined;
|
||||
/* @internal */ getTypeArgumentConstraint(node: TypeNode): Type | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2983,6 +2988,7 @@ namespace ts {
|
||||
InObjectTypeLiteral = 1 << 22,
|
||||
InTypeAlias = 1 << 23, // Writing type in type alias declaration
|
||||
InInitialEntityName = 1 << 24, // Set when writing the LHS of an entity name or entity name expression
|
||||
InReverseMappedType = 1 << 25,
|
||||
}
|
||||
|
||||
// Ensure the shared flags between this and `NodeBuilderFlags` stay in alignment
|
||||
@@ -4117,16 +4123,6 @@ namespace ts {
|
||||
[option: string]: string[] | boolean | undefined;
|
||||
}
|
||||
|
||||
export interface DiscoverTypingsInfo {
|
||||
fileNames: string[]; // The file names that belong to the same project.
|
||||
projectRootPath: string; // The path to the project root directory
|
||||
safeListPath: string; // The path used to retrieve the safe list
|
||||
packageNameToTypingLocation: Map<string>; // The map of package names to their cached typing locations
|
||||
typeAcquisition: TypeAcquisition; // Used to customize the type acquisition process
|
||||
compilerOptions: CompilerOptions; // Used as a source for typing inference
|
||||
unresolvedImports: ReadonlyArray<string>; // List of unresolved module ids from imports
|
||||
}
|
||||
|
||||
export enum ModuleKind {
|
||||
None = 0,
|
||||
CommonJS = 1,
|
||||
@@ -5009,6 +5005,10 @@ namespace ts {
|
||||
newLength: number;
|
||||
}
|
||||
|
||||
export interface SortedArray<T> extends Array<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface DiagnosticCollection {
|
||||
// Adds a diagnostic to this diagnostic collection.
|
||||
|
||||
+43
-46
@@ -771,6 +771,8 @@ namespace ts {
|
||||
return node.parent.kind !== SyntaxKind.VoidExpression;
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return !isExpressionWithTypeArgumentsInClassExtendsClause(node);
|
||||
case SyntaxKind.TypeParameter:
|
||||
return node.parent.kind === SyntaxKind.MappedType || node.parent.kind === SyntaxKind.InferType;
|
||||
|
||||
// Identifiers and qualified names may be type nodes, depending on their context. Climb
|
||||
// above them to find the lowest container
|
||||
@@ -1694,17 +1696,19 @@ namespace ts {
|
||||
node.expression.right.right;
|
||||
}
|
||||
|
||||
function getSingleInitializerOfVariableStatement(node: Node, child?: Node): Node {
|
||||
return isVariableStatement(node) &&
|
||||
node.declarationList.declarations.length > 0 &&
|
||||
(!child || node.declarationList.declarations[0].initializer === child) &&
|
||||
node.declarationList.declarations[0].initializer;
|
||||
function getSingleInitializerOfVariableStatementOrPropertyDeclaration(node: Node): Expression | undefined {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.VariableStatement:
|
||||
const v = getSingleVariableOfVariableStatement(node);
|
||||
return v && v.initializer;
|
||||
case ts.SyntaxKind.PropertyDeclaration:
|
||||
return (node as PropertyDeclaration).initializer;
|
||||
}
|
||||
}
|
||||
|
||||
function getSingleVariableOfVariableStatement(node: Node, child?: Node): Node {
|
||||
function getSingleVariableOfVariableStatement(node: Node): VariableDeclaration | undefined {
|
||||
return isVariableStatement(node) &&
|
||||
node.declarationList.declarations.length > 0 &&
|
||||
(!child || node.declarationList.declarations[0] === child) &&
|
||||
node.declarationList.declarations[0];
|
||||
}
|
||||
|
||||
@@ -1722,7 +1726,7 @@ namespace ts {
|
||||
|
||||
function getJSDocCommentsAndTagsWorker(node: Node): void {
|
||||
const parent = node.parent;
|
||||
if (parent && (parent.kind === SyntaxKind.PropertyAssignment || getNestedModuleDeclaration(parent))) {
|
||||
if (parent && (parent.kind === SyntaxKind.PropertyAssignment || parent.kind === SyntaxKind.PropertyDeclaration || getNestedModuleDeclaration(parent))) {
|
||||
getJSDocCommentsAndTagsWorker(parent);
|
||||
}
|
||||
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
|
||||
@@ -1732,11 +1736,11 @@ namespace ts {
|
||||
// */
|
||||
// var x = function(name) { return name.length; }
|
||||
if (parent && parent.parent &&
|
||||
(getSingleVariableOfVariableStatement(parent.parent, node) || getSourceOfAssignment(parent.parent))) {
|
||||
(getSingleVariableOfVariableStatement(parent.parent) === node || getSourceOfAssignment(parent.parent))) {
|
||||
getJSDocCommentsAndTagsWorker(parent.parent);
|
||||
}
|
||||
if (parent && parent.parent && parent.parent.parent &&
|
||||
(getSingleInitializerOfVariableStatement(parent.parent.parent, node) || getSourceOfDefaultedAssignment(parent.parent.parent))) {
|
||||
(getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node || getSourceOfDefaultedAssignment(parent.parent.parent))) {
|
||||
getJSDocCommentsAndTagsWorker(parent.parent.parent);
|
||||
}
|
||||
if (isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) !== SpecialPropertyAssignmentKind.None ||
|
||||
@@ -1780,7 +1784,7 @@ namespace ts {
|
||||
const host = getJSDocHost(node);
|
||||
const decl = getSourceOfDefaultedAssignment(host) ||
|
||||
getSourceOfAssignment(host) ||
|
||||
getSingleInitializerOfVariableStatement(host) ||
|
||||
getSingleInitializerOfVariableStatementOrPropertyDeclaration(host) ||
|
||||
getSingleVariableOfVariableStatement(host) ||
|
||||
getNestedModuleDeclaration(host) ||
|
||||
host;
|
||||
@@ -1830,6 +1834,7 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.SpreadElement:
|
||||
case SyntaxKind.NonNullExpression:
|
||||
node = parent;
|
||||
break;
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
@@ -2519,11 +2524,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function createDiagnosticCollection(): DiagnosticCollection {
|
||||
let nonFileDiagnostics: Diagnostic[] = [];
|
||||
const fileDiagnostics = createMap<Diagnostic[]>();
|
||||
|
||||
let nonFileDiagnostics = [] as SortedArray<Diagnostic>;
|
||||
const filesWithDiagnostics = [] as SortedArray<string>;
|
||||
const fileDiagnostics = createMap<SortedArray<Diagnostic>>();
|
||||
let hasReadNonFileDiagnostics = false;
|
||||
let diagnosticsModified = false;
|
||||
let modificationCount = 0;
|
||||
|
||||
return {
|
||||
@@ -2543,66 +2547,45 @@ namespace ts {
|
||||
}
|
||||
|
||||
function add(diagnostic: Diagnostic): void {
|
||||
let diagnostics: Diagnostic[];
|
||||
let diagnostics: SortedArray<Diagnostic>;
|
||||
if (diagnostic.file) {
|
||||
diagnostics = fileDiagnostics.get(diagnostic.file.fileName);
|
||||
if (!diagnostics) {
|
||||
diagnostics = [];
|
||||
diagnostics = [] as SortedArray<Diagnostic>;
|
||||
fileDiagnostics.set(diagnostic.file.fileName, diagnostics);
|
||||
insertSorted(filesWithDiagnostics, diagnostic.file.fileName, compareStringsCaseSensitive);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we've already read the non-file diagnostics, do not modify the existing array.
|
||||
if (hasReadNonFileDiagnostics) {
|
||||
hasReadNonFileDiagnostics = false;
|
||||
nonFileDiagnostics = nonFileDiagnostics.slice();
|
||||
nonFileDiagnostics = nonFileDiagnostics.slice() as SortedArray<Diagnostic>;
|
||||
}
|
||||
|
||||
diagnostics = nonFileDiagnostics;
|
||||
}
|
||||
|
||||
diagnostics.push(diagnostic);
|
||||
diagnosticsModified = true;
|
||||
insertSorted(diagnostics, diagnostic, compareDiagnostics);
|
||||
modificationCount++;
|
||||
}
|
||||
|
||||
function getGlobalDiagnostics(): Diagnostic[] {
|
||||
sortAndDeduplicate();
|
||||
hasReadNonFileDiagnostics = true;
|
||||
return nonFileDiagnostics;
|
||||
}
|
||||
|
||||
function getDiagnostics(fileName?: string): Diagnostic[] {
|
||||
sortAndDeduplicate();
|
||||
if (fileName) {
|
||||
return fileDiagnostics.get(fileName) || [];
|
||||
}
|
||||
|
||||
const allDiagnostics: Diagnostic[] = [];
|
||||
function pushDiagnostic(d: Diagnostic) {
|
||||
allDiagnostics.push(d);
|
||||
const fileDiags = flatMap(filesWithDiagnostics, f => fileDiagnostics.get(f));
|
||||
if (!nonFileDiagnostics.length) {
|
||||
return fileDiags;
|
||||
}
|
||||
|
||||
forEach(nonFileDiagnostics, pushDiagnostic);
|
||||
|
||||
fileDiagnostics.forEach(diagnostics => {
|
||||
forEach(diagnostics, pushDiagnostic);
|
||||
});
|
||||
|
||||
return sortAndDeduplicateDiagnostics(allDiagnostics);
|
||||
}
|
||||
|
||||
function sortAndDeduplicate() {
|
||||
if (!diagnosticsModified) {
|
||||
return;
|
||||
}
|
||||
|
||||
diagnosticsModified = false;
|
||||
nonFileDiagnostics = sortAndDeduplicateDiagnostics(nonFileDiagnostics);
|
||||
|
||||
fileDiagnostics.forEach((diagnostics, key) => {
|
||||
fileDiagnostics.set(key, sortAndDeduplicateDiagnostics(diagnostics));
|
||||
});
|
||||
fileDiags.unshift(...nonFileDiagnostics);
|
||||
return fileDiags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3868,6 +3851,10 @@ namespace ts {
|
||||
export function forSomeAncestorDirectory(directory: string, callback: (directory: string) => boolean): boolean {
|
||||
return !!forEachAncestorDirectory(directory, d => callback(d) ? true : undefined);
|
||||
}
|
||||
|
||||
export function isUMDExportSymbol(symbol: Symbol) {
|
||||
return symbol && symbol.declarations && symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]);
|
||||
}
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
@@ -5246,6 +5233,7 @@ namespace ts {
|
||||
/**
|
||||
* True if node is of some token syntax kind.
|
||||
* For example, this is true for an IfKeyword but not for an IfStatement.
|
||||
* Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail.
|
||||
*/
|
||||
export function isToken(n: Node): boolean {
|
||||
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
|
||||
@@ -6032,4 +6020,13 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isTypeReferenceType(node: Node): node is TypeReferenceType {
|
||||
return node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ExpressionWithTypeArguments;
|
||||
}
|
||||
|
||||
export function isStringLiteralLike(node: Node): node is StringLiteralLike {
|
||||
return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
|
||||
}
|
||||
}
|
||||
|
||||
+62
-60
@@ -420,6 +420,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const initialVersion = 1;
|
||||
|
||||
/**
|
||||
* Creates the watch from the host for root files and compiler options
|
||||
*/
|
||||
@@ -429,11 +431,17 @@ namespace ts {
|
||||
*/
|
||||
export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>;
|
||||
export function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfFilesAndCompilerOptions<T> & WatchCompilerHostOfConfigFile<T>): WatchOfFilesAndCompilerOptions<T> | WatchOfConfigFile<T> {
|
||||
interface HostFileInfo {
|
||||
interface FilePresentOnHost {
|
||||
version: number;
|
||||
sourceFile: SourceFile;
|
||||
fileWatcher: FileWatcher;
|
||||
}
|
||||
type FileMissingOnHost = number;
|
||||
interface FilePresenceUnknownOnHost {
|
||||
version: number;
|
||||
}
|
||||
type FileMayBePresentOnHost = FilePresentOnHost | FilePresenceUnknownOnHost;
|
||||
type HostFileInfo = FilePresentOnHost | FileMissingOnHost | FilePresenceUnknownOnHost;
|
||||
|
||||
let builderProgram: T;
|
||||
let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc
|
||||
@@ -441,7 +449,7 @@ namespace ts {
|
||||
let watchedWildcardDirectories: Map<WildcardDirectoryWatcher>; // map of watchers for the wild card directories in the config file
|
||||
let timerToUpdateProgram: any; // timer callback to recompile the program
|
||||
|
||||
const sourceFilesCache = createMap<HostFileInfo | string>(); // Cache that stores the source file and version info
|
||||
const sourceFilesCache = createMap<HostFileInfo>(); // Cache that stores the source file and version info
|
||||
let missingFilePathsRequestedForRelease: Path[]; // These paths are held temparirly so that we can remove the entry from source file cache if the file is not tracked by missing files
|
||||
let hasChangedCompilerOptions = false; // True if the compiler options have changed between compilations
|
||||
let hasChangedAutomaticTypeDirectiveNames = false; // True if the automatic type directives have changed
|
||||
@@ -480,14 +488,14 @@ namespace ts {
|
||||
const watchFilePath = compilerOptions.extendedDiagnostics ? ts.addFilePathWatcherWithLogging : ts.addFilePathWatcher;
|
||||
const watchDirectoryWorker = compilerOptions.extendedDiagnostics ? ts.addDirectoryWatcherWithLogging : ts.addDirectoryWatcher;
|
||||
|
||||
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
let newLine = updateNewLine();
|
||||
|
||||
writeLog(`Current directory: ${currentDirectory} CaseSensitiveFileNames: ${useCaseSensitiveFileNames}`);
|
||||
if (configFileName) {
|
||||
watchFile(host, configFileName, scheduleProgramReload, writeLog);
|
||||
}
|
||||
|
||||
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
let newLine = updateNewLine();
|
||||
|
||||
const compilerHost: CompilerHost & ResolutionCacheHost = {
|
||||
// Members for CompilerHost
|
||||
getSourceFile: (fileName, languageVersion, onError?, shouldCreateNewSourceFile?) => getVersionedSourceFileByPath(fileName, toPath(fileName), languageVersion, onError, shouldCreateNewSourceFile),
|
||||
@@ -575,7 +583,9 @@ namespace ts {
|
||||
|
||||
// Compile the program
|
||||
if (loggingEnabled) {
|
||||
writeLog(`CreatingProgramWith::\n roots: ${JSON.stringify(rootFileNames)}\n options: ${JSON.stringify(compilerOptions)}`);
|
||||
writeLog(`CreatingProgramWith::`);
|
||||
writeLog(` roots: ${JSON.stringify(rootFileNames)}`);
|
||||
writeLog(` options: ${JSON.stringify(compilerOptions)}`);
|
||||
}
|
||||
|
||||
const needsUpdateInTypeRootWatch = hasChangedCompilerOptions || !program;
|
||||
@@ -627,11 +637,20 @@ namespace ts {
|
||||
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function isFileMissingOnHost(hostSourceFile: HostFileInfo): hostSourceFile is FileMissingOnHost {
|
||||
return typeof hostSourceFile === "number";
|
||||
}
|
||||
|
||||
function isFilePresentOnHost(hostSourceFile: FileMayBePresentOnHost): hostSourceFile is FilePresentOnHost {
|
||||
return !!(hostSourceFile as FilePresentOnHost).sourceFile;
|
||||
}
|
||||
|
||||
function fileExists(fileName: string) {
|
||||
const path = toPath(fileName);
|
||||
const hostSourceFileInfo = sourceFilesCache.get(path);
|
||||
if (hostSourceFileInfo !== undefined) {
|
||||
return !isString(hostSourceFileInfo);
|
||||
// If file is missing on host from cache, we can definitely say file doesnt exist
|
||||
// otherwise we need to ensure from the disk
|
||||
if (isFileMissingOnHost(sourceFilesCache.get(path))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return directoryStructureHost.fileExists(fileName);
|
||||
@@ -640,39 +659,42 @@ namespace ts {
|
||||
function getVersionedSourceFileByPath(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile {
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
// No source file on the host
|
||||
if (isString(hostSourceFile)) {
|
||||
if (isFileMissingOnHost(hostSourceFile)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Create new source file if requested or the versions dont match
|
||||
if (!hostSourceFile || shouldCreateNewSourceFile || hostSourceFile.version.toString() !== hostSourceFile.sourceFile.version) {
|
||||
if (!hostSourceFile || shouldCreateNewSourceFile || !isFilePresentOnHost(hostSourceFile) || hostSourceFile.version.toString() !== hostSourceFile.sourceFile.version) {
|
||||
const sourceFile = getNewSourceFile();
|
||||
if (hostSourceFile) {
|
||||
if (shouldCreateNewSourceFile) {
|
||||
hostSourceFile.version++;
|
||||
}
|
||||
|
||||
if (sourceFile) {
|
||||
hostSourceFile.sourceFile = sourceFile;
|
||||
// Set the source file and create file watcher now that file was present on the disk
|
||||
(hostSourceFile as FilePresentOnHost).sourceFile = sourceFile;
|
||||
sourceFile.version = hostSourceFile.version.toString();
|
||||
if (!hostSourceFile.fileWatcher) {
|
||||
hostSourceFile.fileWatcher = watchFilePath(host, fileName, onSourceFileChange, path, writeLog);
|
||||
if (!(hostSourceFile as FilePresentOnHost).fileWatcher) {
|
||||
(hostSourceFile as FilePresentOnHost).fileWatcher = watchFilePath(host, fileName, onSourceFileChange, path, writeLog);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// There is no source file on host any more, close the watch, missing file paths will track it
|
||||
hostSourceFile.fileWatcher.close();
|
||||
sourceFilesCache.set(path, hostSourceFile.version.toString());
|
||||
if (isFilePresentOnHost(hostSourceFile)) {
|
||||
hostSourceFile.fileWatcher.close();
|
||||
}
|
||||
sourceFilesCache.set(path, hostSourceFile.version);
|
||||
}
|
||||
}
|
||||
else {
|
||||
let fileWatcher: FileWatcher;
|
||||
if (sourceFile) {
|
||||
sourceFile.version = "1";
|
||||
fileWatcher = watchFilePath(host, fileName, onSourceFileChange, path, writeLog);
|
||||
sourceFilesCache.set(path, { sourceFile, version: 1, fileWatcher });
|
||||
sourceFile.version = initialVersion.toString();
|
||||
const fileWatcher = watchFilePath(host, fileName, onSourceFileChange, path, writeLog);
|
||||
sourceFilesCache.set(path, { sourceFile, version: initialVersion, fileWatcher });
|
||||
}
|
||||
else {
|
||||
sourceFilesCache.set(path, "0");
|
||||
sourceFilesCache.set(path, initialVersion);
|
||||
}
|
||||
}
|
||||
return sourceFile;
|
||||
@@ -697,20 +719,22 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function removeSourceFile(path: Path) {
|
||||
function nextSourceFileVersion(path: Path) {
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
if (hostSourceFile !== undefined) {
|
||||
if (!isString(hostSourceFile)) {
|
||||
hostSourceFile.fileWatcher.close();
|
||||
resolutionCache.invalidateResolutionOfFile(path);
|
||||
if (isFileMissingOnHost(hostSourceFile)) {
|
||||
// The next version, lets set it as presence unknown file
|
||||
sourceFilesCache.set(path, { version: Number(hostSourceFile) + 1 });
|
||||
}
|
||||
else {
|
||||
hostSourceFile.version++;
|
||||
}
|
||||
sourceFilesCache.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
function getSourceVersion(path: Path): string {
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
return !hostSourceFile || isString(hostSourceFile) ? undefined : hostSourceFile.version.toString();
|
||||
return !hostSourceFile || isFileMissingOnHost(hostSourceFile) ? undefined : hostSourceFile.version.toString();
|
||||
}
|
||||
|
||||
function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions) {
|
||||
@@ -721,10 +745,10 @@ namespace ts {
|
||||
// there was version update and new source file was created.
|
||||
if (hostSourceFileInfo) {
|
||||
// record the missing file paths so they can be removed later if watchers arent tracking them
|
||||
if (isString(hostSourceFileInfo)) {
|
||||
if (isFileMissingOnHost(hostSourceFileInfo)) {
|
||||
(missingFilePathsRequestedForRelease || (missingFilePathsRequestedForRelease = [])).push(oldSourceFile.path);
|
||||
}
|
||||
else if (hostSourceFileInfo.sourceFile === oldSourceFile) {
|
||||
else if ((hostSourceFileInfo as FilePresentOnHost).sourceFile === oldSourceFile) {
|
||||
sourceFilesCache.delete(oldSourceFile.path);
|
||||
resolutionCache.removeResolutionsOfFile(oldSourceFile.path);
|
||||
}
|
||||
@@ -808,27 +832,12 @@ namespace ts {
|
||||
|
||||
function onSourceFileChange(fileName: string, eventKind: FileWatcherEventKind, path: Path) {
|
||||
updateCachedSystemWithFile(fileName, path, eventKind);
|
||||
const hostSourceFile = sourceFilesCache.get(path);
|
||||
if (hostSourceFile) {
|
||||
// Update the cache
|
||||
if (eventKind === FileWatcherEventKind.Deleted) {
|
||||
resolutionCache.invalidateResolutionOfFile(path);
|
||||
if (!isString(hostSourceFile)) {
|
||||
hostSourceFile.fileWatcher.close();
|
||||
sourceFilesCache.set(path, (++hostSourceFile.version).toString());
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Deleted file created
|
||||
if (isString(hostSourceFile)) {
|
||||
sourceFilesCache.delete(path);
|
||||
}
|
||||
else {
|
||||
// file changed - just update the version
|
||||
hostSourceFile.version++;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the source file cache
|
||||
if (eventKind === FileWatcherEventKind.Deleted && sourceFilesCache.get(path)) {
|
||||
resolutionCache.invalidateResolutionOfFile(path);
|
||||
}
|
||||
nextSourceFileVersion(path);
|
||||
|
||||
// Update the program
|
||||
scheduleProgramUpdate();
|
||||
@@ -856,7 +865,7 @@ namespace ts {
|
||||
missingFilesMap.delete(missingFilePath);
|
||||
|
||||
// Delete the entry in the source files cache so that new source file is created
|
||||
removeSourceFile(missingFilePath);
|
||||
nextSourceFileVersion(missingFilePath);
|
||||
|
||||
// When a missing file is created, we should update the graph.
|
||||
scheduleProgramUpdate();
|
||||
@@ -885,17 +894,10 @@ namespace ts {
|
||||
const fileOrDirectoryPath = toPath(fileOrDirectory);
|
||||
|
||||
// Since the file existance changed, update the sourceFiles cache
|
||||
const result = cachedDirectoryStructureHost && cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
|
||||
|
||||
// Instead of deleting the file, mark it as changed instead
|
||||
// Many times node calls add/remove/file when watching directories recursively
|
||||
const hostSourceFile = sourceFilesCache.get(fileOrDirectoryPath);
|
||||
if (hostSourceFile && !isString(hostSourceFile) && (result ? result.fileExists : directoryStructureHost.fileExists(fileOrDirectory))) {
|
||||
hostSourceFile.version++;
|
||||
}
|
||||
else {
|
||||
removeSourceFile(fileOrDirectoryPath);
|
||||
if (cachedDirectoryStructureHost) {
|
||||
cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
|
||||
}
|
||||
nextSourceFileVersion(fileOrDirectoryPath);
|
||||
|
||||
// If the the added or created file or directory is not supported file name, ignore the file
|
||||
// But when watched directory is added/removed, we need to reload the file list
|
||||
|
||||
+67
-63
@@ -64,7 +64,7 @@ namespace FourSlash {
|
||||
|
||||
export interface Range {
|
||||
fileName: string;
|
||||
start: number;
|
||||
pos: number;
|
||||
end: number;
|
||||
marker?: Marker;
|
||||
}
|
||||
@@ -710,9 +710,9 @@ namespace FourSlash {
|
||||
if (!range) {
|
||||
this.raiseError(`goToDefinitionsAndBoundSpan failed - found a TextSpan ${JSON.stringify(defs.textSpan)} when it wasn't expected.`);
|
||||
}
|
||||
else if (defs.textSpan.start !== range.start || defs.textSpan.length !== range.end - range.start) {
|
||||
else if (defs.textSpan.start !== range.pos || defs.textSpan.length !== range.end - range.pos) {
|
||||
const expected: ts.TextSpan = {
|
||||
start: range.start, length: range.end - range.start
|
||||
start: range.pos, length: range.end - range.pos
|
||||
};
|
||||
this.raiseError(`goToDefinitionsAndBoundSpan failed - expected to find TextSpan ${JSON.stringify(expected)} but got ${JSON.stringify(defs.textSpan)}`);
|
||||
}
|
||||
@@ -855,7 +855,7 @@ namespace FourSlash {
|
||||
if (completion.insertText !== insertText) {
|
||||
this.raiseError(`Expected completion insert text at index ${index} to be ${insertText}, got ${completion.insertText}`);
|
||||
}
|
||||
const convertedReplacementSpan = replacementSpan && textSpanFromRange(replacementSpan);
|
||||
const convertedReplacementSpan = replacementSpan && ts.createTextSpanFromRange(replacementSpan);
|
||||
try {
|
||||
assert.deepEqual(completion.replacementSpan, convertedReplacementSpan);
|
||||
}
|
||||
@@ -1002,8 +1002,8 @@ namespace FourSlash {
|
||||
private verifyRange(desc: string, expected: Range, actual: ts.Node) {
|
||||
const actualStart = actual.getStart();
|
||||
const actualEnd = actual.getEnd();
|
||||
if (actualStart !== expected.start || actualEnd !== expected.end) {
|
||||
this.raiseError(`${desc} should be ${expected.start}-${expected.end}, got ${actualStart}-${actualEnd}`);
|
||||
if (actualStart !== expected.pos || actualEnd !== expected.end) {
|
||||
this.raiseError(`${desc} should be ${expected.pos}-${expected.end}, got ${actualStart}-${actualEnd}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1053,7 +1053,7 @@ namespace FourSlash {
|
||||
if (actualReferences.length > expectedReferences.length) {
|
||||
// Find the unaccounted-for reference.
|
||||
for (const actual of actualReferences) {
|
||||
if (!ts.forEach(expectedReferences, r => r.start === actual.textSpan.start)) {
|
||||
if (!ts.forEach(expectedReferences, r => r.pos === actual.textSpan.start)) {
|
||||
this.raiseError(`A reference ${stringify(actual)} is unaccounted for.`);
|
||||
}
|
||||
}
|
||||
@@ -1062,13 +1062,13 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
for (const reference of expectedReferences) {
|
||||
const { fileName, start, end } = reference;
|
||||
const { fileName, pos, end } = reference;
|
||||
if (reference.marker && reference.marker.data) {
|
||||
const { isWriteAccess, isDefinition } = reference.marker.data as { isWriteAccess?: boolean, isDefinition?: boolean };
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
|
||||
this.verifyReferencesWorker(actualReferences, fileName, pos, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
else {
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end);
|
||||
this.verifyReferencesWorker(actualReferences, fileName, pos, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1092,14 +1092,14 @@ namespace FourSlash {
|
||||
references: ts.ReferenceEntry[];
|
||||
}
|
||||
const fullExpected = ts.map<FourSlashInterface.ReferenceGroup, ReferenceGroupJson>(parts, ({ definition, ranges }) => ({
|
||||
definition: typeof definition === "string" ? definition : { ...definition, range: textSpanFromRange(definition.range) },
|
||||
definition: typeof definition === "string" ? definition : { ...definition, range: ts.createTextSpanFromRange(definition.range) },
|
||||
references: ranges.map<ts.ReferenceEntry>(r => {
|
||||
const { isWriteAccess = false, isDefinition = false, isInString } = (r.marker && r.marker.data || {}) as { isWriteAccess?: boolean, isDefinition?: boolean, isInString?: true };
|
||||
return {
|
||||
isWriteAccess,
|
||||
isDefinition,
|
||||
fileName: r.fileName,
|
||||
textSpan: textSpanFromRange(r),
|
||||
textSpan: ts.createTextSpanFromRange(r),
|
||||
...(isInString ? { isInString: true } : undefined),
|
||||
};
|
||||
}),
|
||||
@@ -1280,7 +1280,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
assert.equal(actualQuickInfoDocumentation, expectedDocumentation || "", this.assertionMessageAtLastKnownMarker("quick info doc"));
|
||||
}
|
||||
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; },
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: TextSpan,
|
||||
displayParts: ts.SymbolDisplayPart[],
|
||||
documentation: ts.SymbolDisplayPart[],
|
||||
tags: ts.JSDocTagInfo[]
|
||||
@@ -1346,11 +1346,11 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.raiseError("Rename location count does not match result.\n\nExpected: " + stringify(ranges) + "\n\nActual:" + stringify(references));
|
||||
}
|
||||
|
||||
ranges = ranges.sort((r1, r2) => r1.start - r2.start);
|
||||
ranges = ranges.sort((r1, r2) => r1.pos - r2.pos);
|
||||
references = references.sort((r1, r2) => r1.textSpan.start - r2.textSpan.start);
|
||||
|
||||
ts.zipWith(references, ranges, (reference, range) => {
|
||||
if (reference.textSpan.start !== range.start || ts.textSpanEnd(reference.textSpan) !== range.end) {
|
||||
if (reference.textSpan.start !== range.pos || ts.textSpanEnd(reference.textSpan) !== range.end) {
|
||||
this.raiseError("Rename location results do not match.\n\nExpected: " + stringify(ranges) + "\n\nActual:" + stringify(references));
|
||||
}
|
||||
});
|
||||
@@ -1473,9 +1473,9 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
const expectedRange = this.getRanges()[0];
|
||||
if (renameInfo.triggerSpan.start !== expectedRange.start ||
|
||||
if (renameInfo.triggerSpan.start !== expectedRange.pos ||
|
||||
ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end) {
|
||||
this.raiseError("Expected triggerSpan [" + expectedRange.start + "," + expectedRange.end + "). Got [" +
|
||||
this.raiseError("Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" +
|
||||
renameInfo.triggerSpan.start + "," + ts.textSpanEnd(renameInfo.triggerSpan) + ") instead.");
|
||||
}
|
||||
}
|
||||
@@ -1964,7 +1964,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
for (const range of this.testData.ranges) {
|
||||
if (range.fileName === fileName) {
|
||||
range.start = updatePosition(range.start);
|
||||
range.pos = updatePosition(range.pos);
|
||||
range.end = updatePosition(range.end);
|
||||
}
|
||||
}
|
||||
@@ -1999,9 +1999,9 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.goToPosition(len);
|
||||
}
|
||||
|
||||
public goToRangeStart({ fileName, start }: Range) {
|
||||
public goToRangeStart({ fileName, pos }: Range) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
this.goToPosition(pos);
|
||||
}
|
||||
|
||||
public goToTypeDefinition(definitionIndex: number) {
|
||||
@@ -2088,9 +2088,9 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
const delayedErrors: string[] = [];
|
||||
for (const range of ranges) {
|
||||
const length = range.end - range.start;
|
||||
const length = range.end - range.pos;
|
||||
const matchingImpl = ts.find(implementations, impl =>
|
||||
range.fileName === impl.fileName && range.start === impl.textSpan.start && length === impl.textSpan.length);
|
||||
range.fileName === impl.fileName && range.pos === impl.textSpan.start && length === impl.textSpan.length);
|
||||
if (matchingImpl) {
|
||||
if (range.marker && range.marker.data) {
|
||||
const expected = <{ displayParts?: ts.SymbolDisplayPart[], parts: string[], kind?: string }>range.marker.data;
|
||||
@@ -2128,7 +2128,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
if (unsatisfiedRanges.length) {
|
||||
error += "\nUnsatisfied ranges:";
|
||||
for (const range of unsatisfiedRanges) {
|
||||
error += `\n (${range.start}, ${range.end}) in ${range.fileName}: ${this.rangeText(range)}`;
|
||||
error += `\n (${range.pos}, ${range.end}) in ${range.fileName}: ${this.rangeText(range)}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2173,8 +2173,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
private rangeText({ fileName, start, end }: Range): string {
|
||||
return this.getFileContent(fileName).slice(start, end);
|
||||
private rangeText({ fileName, pos, end }: Range): string {
|
||||
return this.getFileContent(fileName).slice(pos, end);
|
||||
}
|
||||
|
||||
public verifyCaretAtMarker(markerName = "") {
|
||||
@@ -2345,7 +2345,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.verifyClassifications(expected, actual, this.activeFile.content);
|
||||
}
|
||||
|
||||
public verifyOutliningSpans(spans: TextSpan[]) {
|
||||
public verifyOutliningSpans(spans: FourSlash.Range[]) {
|
||||
const actual = this.languageService.getOutliningSpans(this.activeFile.fileName);
|
||||
|
||||
if (actual.length !== spans.length) {
|
||||
@@ -2353,13 +2353,13 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
ts.zipWith(spans, actual, (expectedSpan, actualSpan, i) => {
|
||||
if (expectedSpan.start !== actualSpan.textSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan)) {
|
||||
this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.start},${expectedSpan.end}), actual: (${actualSpan.textSpan.start},${ts.textSpanEnd(actualSpan.textSpan)})`);
|
||||
if (expectedSpan.pos !== actualSpan.textSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan)) {
|
||||
this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualSpan.textSpan.start},${ts.textSpanEnd(actualSpan.textSpan)})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public verifyTodoComments(descriptors: string[], spans: TextSpan[]) {
|
||||
public verifyTodoComments(descriptors: string[], spans: Range[]) {
|
||||
const actual = this.languageService.getTodoComments(this.activeFile.fileName,
|
||||
descriptors.map(d => { return { text: d, priority: 0 }; }));
|
||||
|
||||
@@ -2370,8 +2370,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
ts.zipWith(spans, actual, (expectedSpan, actualComment, i) => {
|
||||
const actualCommentSpan = ts.createTextSpan(actualComment.position, actualComment.message.length);
|
||||
|
||||
if (expectedSpan.start !== actualCommentSpan.start || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan)) {
|
||||
this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.start},${expectedSpan.end}), actual: (${actualCommentSpan.start},${ts.textSpanEnd(actualCommentSpan)})`);
|
||||
if (expectedSpan.pos !== actualCommentSpan.start || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan)) {
|
||||
this.raiseError(`verifyOutliningSpans failed - span ${(i + 1)} expected: (${expectedSpan.pos},${expectedSpan.end}), actual: (${actualCommentSpan.start},${ts.textSpanEnd(actualCommentSpan)})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2549,12 +2549,14 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public verifyImportFixAtPosition(expectedTextArray: string[], errorCode?: number) {
|
||||
const ranges = this.getRanges().filter(r => r.fileName === this.activeFile.fileName);
|
||||
const { fileName } = this.activeFile;
|
||||
const ranges = this.getRanges().filter(r => r.fileName === fileName);
|
||||
if (ranges.length !== 1) {
|
||||
this.raiseError("Exactly one range should be specified in the testfile.");
|
||||
}
|
||||
const range = ts.first(ranges);
|
||||
|
||||
const codeFixes = this.getCodeFixes(this.activeFile.fileName, errorCode);
|
||||
const codeFixes = this.getCodeFixes(fileName, errorCode);
|
||||
|
||||
if (codeFixes.length === 0) {
|
||||
if (expectedTextArray.length !== 0) {
|
||||
@@ -2564,11 +2566,14 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
const actualTextArray: string[] = [];
|
||||
const scriptInfo = this.languageServiceAdapterHost.getScriptInfo(codeFixes[0].changes[0].fileName);
|
||||
const scriptInfo = this.languageServiceAdapterHost.getScriptInfo(fileName);
|
||||
const originalContent = scriptInfo.content;
|
||||
for (const codeFix of codeFixes) {
|
||||
this.applyEdits(codeFix.changes[0].fileName, codeFix.changes[0].textChanges, /*isFormattingEdit*/ false);
|
||||
const text = this.rangeText(ranges[0]);
|
||||
ts.Debug.assert(codeFix.changes.length === 1);
|
||||
const change = ts.first(codeFix.changes);
|
||||
ts.Debug.assert(change.fileName === fileName);
|
||||
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
|
||||
const text = this.rangeText(range);
|
||||
actualTextArray.push(text);
|
||||
scriptInfo.updateContent(originalContent);
|
||||
}
|
||||
@@ -2830,7 +2835,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.goToRangeStart(r);
|
||||
this.verifyOccurrencesAtPositionListCount(ranges.length);
|
||||
for (const range of ranges) {
|
||||
this.verifyOccurrencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess);
|
||||
this.verifyOccurrencesAtPositionListContains(range.fileName, range.pos, range.end, isWriteAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2886,8 +2891,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
ts.zipWith(expectedRangesInFile, spansInFile, (expectedRange, span) => {
|
||||
if (span.textSpan.start !== expectedRange.start || ts.textSpanEnd(span.textSpan) !== expectedRange.end) {
|
||||
this.raiseError(`verifyDocumentHighlights failed - span does not match, actual: ${stringify(span.textSpan)}, expected: ${expectedRange.start}--${expectedRange.end}`);
|
||||
if (span.textSpan.start !== expectedRange.pos || ts.textSpanEnd(span.textSpan) !== expectedRange.end) {
|
||||
this.raiseError(`verifyDocumentHighlights failed - span does not match, actual: ${stringify(span.textSpan)}, expected: ${expectedRange.pos}--${expectedRange.end}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -2970,7 +2975,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
throw new Error("Exactly one refactor range is allowed per test.");
|
||||
}
|
||||
|
||||
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, { pos: ranges[0].start, end: ranges[0].end });
|
||||
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, { pos: ranges[0].pos, end: ranges[0].end });
|
||||
const isAvailable = applicableRefactors && applicableRefactors.length > 0;
|
||||
if (negative && isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some.`);
|
||||
@@ -3104,6 +3109,9 @@ Actual: ${stringify(fullActual)}`);
|
||||
hasAction: boolean | undefined,
|
||||
options: FourSlashInterface.VerifyCompletionListContainsOptions | undefined,
|
||||
) {
|
||||
const eq = <T>(a: T, b: T, msg: string) => {
|
||||
assert.deepEqual(a, b, this.assertionMessageAtLastKnownMarker(msg + " for " + stringify(entryId)));
|
||||
};
|
||||
const matchingItems = items.filter(item => item.name === entryId.name && item.source === entryId.source);
|
||||
if (matchingItems.length === 0) {
|
||||
const itemsString = items.map(item => stringify({ name: item.name, source: item.source, kind: item.kind })).join(",\n");
|
||||
@@ -3118,30 +3126,30 @@ Actual: ${stringify(fullActual)}`);
|
||||
const details = this.getCompletionEntryDetails(item.name, item.source);
|
||||
|
||||
if (documentation !== undefined) {
|
||||
assert.equal(ts.displayPartsToString(details.documentation), documentation, this.assertionMessageAtLastKnownMarker("completion item documentation for " + entryId));
|
||||
eq(ts.displayPartsToString(details.documentation), documentation, "completion item documentation");
|
||||
}
|
||||
if (text !== undefined) {
|
||||
assert.equal(ts.displayPartsToString(details.displayParts), text, this.assertionMessageAtLastKnownMarker("completion item detail text for " + entryId));
|
||||
eq(ts.displayPartsToString(details.displayParts), text, "completion item detail text");
|
||||
}
|
||||
|
||||
if (entryId.source === undefined) {
|
||||
assert.equal(options && options.sourceDisplay, undefined);
|
||||
eq(options && options.sourceDisplay, /*b*/ undefined, "source display");
|
||||
}
|
||||
else {
|
||||
assert.deepEqual(details.source, [ts.textPart(options!.sourceDisplay)]);
|
||||
eq(details.source, [ts.textPart(options!.sourceDisplay)], "source display");
|
||||
}
|
||||
}
|
||||
|
||||
if (kind !== undefined) {
|
||||
if (typeof kind === "string") {
|
||||
assert.equal(item.kind, kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + entryId));
|
||||
eq(item.kind, kind, "completion item kind");
|
||||
}
|
||||
else {
|
||||
if (kind.kind) {
|
||||
assert.equal(item.kind, kind.kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + entryId));
|
||||
eq(item.kind, kind.kind, "completion item kind");
|
||||
}
|
||||
if (kind.kindModifiers !== undefined) {
|
||||
assert.equal(item.kindModifiers, kind.kindModifiers, this.assertionMessageAtLastKnownMarker("completion item kindModifiers for " + entryId));
|
||||
eq(item.kindModifiers, kind.kindModifiers, "completion item kindModifiers");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3150,14 +3158,14 @@ Actual: ${stringify(fullActual)}`);
|
||||
|
||||
if (spanIndex !== undefined) {
|
||||
const span = this.getTextSpanForRangeAtIndex(spanIndex);
|
||||
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + entryId));
|
||||
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + stringify(entryId)));
|
||||
}
|
||||
|
||||
assert.equal(item.hasAction, hasAction, "hasAction");
|
||||
assert.equal(item.isRecommended, options && options.isRecommended, "isRecommended");
|
||||
assert.equal(item.insertText, options && options.insertText, "insertText");
|
||||
eq(item.hasAction, hasAction, "hasAction");
|
||||
eq(item.isRecommended, options && options.isRecommended, "isRecommended");
|
||||
eq(item.insertText, options && options.insertText, "insertText");
|
||||
if (options && options.replacementSpan) { // TODO: GH#21679
|
||||
assert.deepEqual(item.replacementSpan, options && options.replacementSpan && textSpanFromRange(options.replacementSpan), "replacementSpan");
|
||||
eq(item.replacementSpan, options && options.replacementSpan && ts.createTextSpanFromRange(options.replacementSpan), "replacementSpan");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3208,7 +3216,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
private getTextSpanForRangeAtIndex(index: number): ts.TextSpan {
|
||||
const ranges = this.getRanges();
|
||||
if (ranges && ranges.length > index) {
|
||||
return textSpanFromRange(ranges[index]);
|
||||
return ts.createTextSpanFromRange(ranges[index]);
|
||||
}
|
||||
else {
|
||||
this.raiseError("Supplied span index: " + index + " does not exist in range list of size: " + (ranges ? 0 : ranges.length));
|
||||
@@ -3238,10 +3246,6 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function textSpanFromRange(range: FourSlash.Range): ts.TextSpan {
|
||||
return ts.createTextSpanFromBounds(range.start, range.end);
|
||||
}
|
||||
|
||||
export function runFourSlashTest(basePath: string, testType: FourSlashTestType, fileName: string) {
|
||||
const content = Harness.IO.readFile(fileName);
|
||||
runFourSlashTestContent(basePath, testType, content, fileName);
|
||||
@@ -3562,7 +3566,7 @@ ${code}
|
||||
|
||||
const range: Range = {
|
||||
fileName,
|
||||
start: rangeStart.position,
|
||||
pos: rangeStart.position,
|
||||
end: (i - 1) - difference,
|
||||
marker: rangeStart.marker
|
||||
};
|
||||
@@ -3682,7 +3686,7 @@ ${code}
|
||||
}
|
||||
|
||||
// put ranges in the correct order
|
||||
localRanges = localRanges.sort((a, b) => a.start < b.start ? -1 : 1);
|
||||
localRanges = localRanges.sort((a, b) => a.pos < b.pos ? -1 : 1);
|
||||
localRanges.forEach((r) => { ranges.push(r); });
|
||||
|
||||
return {
|
||||
@@ -3755,7 +3759,7 @@ namespace FourSlashInterface {
|
||||
}
|
||||
|
||||
public spans(): ts.TextSpan[] {
|
||||
return this.ranges().map(r => ts.createTextSpan(r.start, r.end - r.start));
|
||||
return this.ranges().map(r => ts.createTextSpan(r.pos, r.end - r.pos));
|
||||
}
|
||||
|
||||
public rangesByText(): ts.Map<FourSlash.Range[]> {
|
||||
@@ -4161,7 +4165,7 @@ namespace FourSlashInterface {
|
||||
this.state.verifyCurrentNameOrDottedNameSpanText(text);
|
||||
}
|
||||
|
||||
public outliningSpansInCurrentFile(spans: FourSlash.TextSpan[]) {
|
||||
public outliningSpansInCurrentFile(spans: FourSlash.Range[]) {
|
||||
this.state.verifyOutliningSpans(spans);
|
||||
}
|
||||
|
||||
@@ -4244,7 +4248,7 @@ namespace FourSlashInterface {
|
||||
}
|
||||
|
||||
public occurrencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean) {
|
||||
this.state.verifyOccurrencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess);
|
||||
this.state.verifyOccurrencesAtPositionListContains(range.fileName, range.pos, range.end, isWriteAccess);
|
||||
}
|
||||
|
||||
public occurrencesAtPositionCount(expectedCount: number) {
|
||||
@@ -4309,7 +4313,7 @@ namespace FourSlashInterface {
|
||||
this.state.verifyRenameLocations(startRanges, options);
|
||||
}
|
||||
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; },
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: FourSlash.TextSpan,
|
||||
displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]) {
|
||||
this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation, tags);
|
||||
}
|
||||
|
||||
@@ -170,7 +170,8 @@ namespace RWC {
|
||||
});
|
||||
|
||||
|
||||
it("has the expected emitted code", () => {
|
||||
it("has the expected emitted code", function(this: Mocha.ITestCallbackContext) {
|
||||
this.timeout(10000); // Allow long timeouts for RWC js verification
|
||||
Harness.Baseline.runMultifileBaseline(baseName, "", () => {
|
||||
return Harness.Compiler.iterateOutputs(compilerResult.files);
|
||||
}, baselineOpts, [".js", ".jsx"]);
|
||||
|
||||
@@ -52,7 +52,7 @@ class TypeWriterWalker {
|
||||
}
|
||||
|
||||
private *visitNode(node: ts.Node, isSymbolWalk: boolean): IterableIterator<TypeWriterResult> {
|
||||
if (ts.isExpressionNode(node) || node.kind === ts.SyntaxKind.Identifier) {
|
||||
if (ts.isExpressionNode(node) || node.kind === ts.SyntaxKind.Identifier || ts.isDeclarationName(node)) {
|
||||
const result = this.writeTypeOrSymbol(node, isSymbolWalk);
|
||||
if (result) {
|
||||
yield result;
|
||||
@@ -122,4 +122,4 @@ class TypeWriterWalker {
|
||||
symbol: symbolString
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,6 +546,18 @@ var q = /*b*/ //c
|
||||
/*g*/ + /*h*/ //i
|
||||
/*j*/ 2|] /*k*/ //l
|
||||
/*m*/; /*n*/ //o`);
|
||||
|
||||
testExtractFunction("extractFunction_NamelessClass", `
|
||||
export default class {
|
||||
M() {
|
||||
[#|1 + 1|];
|
||||
}
|
||||
}`);
|
||||
|
||||
testExtractFunction("extractFunction_NoDeclarations", `
|
||||
function F() {
|
||||
[#|arguments.length|]; // arguments has no declaration
|
||||
}`);
|
||||
});
|
||||
|
||||
function testExtractFunction(caption: string, text: string, includeLib?: boolean) {
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace ts {
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractSymbol.getRangeToExtract(file, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const result = refactor.extractSymbol.getRangeToExtract(file, createTextSpanFromRange(selectionRange));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
@@ -23,19 +23,19 @@ namespace ts {
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractSymbol.getRangeToExtract(f, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const result = refactor.extractSymbol.getRangeToExtract(f, createTextSpanFromRange(selectionRange));
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let start: number, end: number;
|
||||
let pos: number, end: number;
|
||||
if (ts.isArray(result.targetRange.range)) {
|
||||
start = result.targetRange.range[0].getStart(f);
|
||||
pos = result.targetRange.range[0].getStart(f);
|
||||
end = ts.lastOrUndefined(result.targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
start = result.targetRange.range.getStart(f);
|
||||
pos = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(start, expectedRange.start, "incorrect start of range");
|
||||
assert.equal(pos, expectedRange.pos, "incorrect pos of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
/// <reference path="tsserverProjectSystem.ts" />
|
||||
|
||||
namespace ts {
|
||||
export interface Range {
|
||||
start: number;
|
||||
interface Range {
|
||||
pos: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Test {
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ namespace ts {
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, start: text.length, end: undefined });
|
||||
activeRanges.push({ name, pos: text.length, end: undefined });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
@@ -123,12 +123,12 @@ namespace ts {
|
||||
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: selectionRange.start,
|
||||
startPosition: selectionRange.pos,
|
||||
endPosition: selectionRange.end,
|
||||
host: notImplementedHost,
|
||||
formatContext: formatting.getFormatContext(testFormatOptions),
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
const actions = find(infos, info => info.description === description.message).actions;
|
||||
@@ -186,12 +186,12 @@ namespace ts {
|
||||
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: selectionRange.start,
|
||||
startPosition: selectionRange.pos,
|
||||
endPosition: selectionRange.end,
|
||||
host: notImplementedHost,
|
||||
formatContext: formatting.getFormatContext(testFormatOptions),
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
|
||||
assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
const infos = refactor.extractSymbol.getAvailableActions(context);
|
||||
assert.isUndefined(find(infos, info => info.description === description.message));
|
||||
|
||||
@@ -1719,6 +1719,38 @@ namespace ts.tscWatch {
|
||||
return [files[0]];
|
||||
}
|
||||
});
|
||||
|
||||
it("file is deleted and created as part of change", () => {
|
||||
const projectLocation = "/home/username/project";
|
||||
const file: FileOrFolder = {
|
||||
path: `${projectLocation}/app/file.ts`,
|
||||
content: "var a = 10;"
|
||||
};
|
||||
const fileJs = `${projectLocation}/app/file.js`;
|
||||
const configFile: FileOrFolder = {
|
||||
path: `${projectLocation}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
include: [
|
||||
"app/**/*.ts"
|
||||
]
|
||||
})
|
||||
};
|
||||
const files = [file, configFile, libFile];
|
||||
const host = createWatchedSystem(files, { currentDirectory: projectLocation, useCaseSensitiveFileNames: true });
|
||||
createWatchOfConfigFile("tsconfig.json", host);
|
||||
verifyProgram();
|
||||
|
||||
file.content += "\nvar b = 10;";
|
||||
|
||||
host.reloadFS(files, { invokeFileDeleteCreateAsPartInsteadOfChange: true });
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
verifyProgram();
|
||||
|
||||
function verifyProgram() {
|
||||
assert.isTrue(host.fileExists(fileJs));
|
||||
assert.equal(host.readFile(fileJs), file.content + "\n");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsc-watch module resolution caching", () => {
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace ts.projectSystem {
|
||||
readonly globalTypingsCacheLocation: string,
|
||||
throttleLimit: number,
|
||||
installTypingHost: server.ServerHost,
|
||||
readonly typesRegistry = createMap<void>(),
|
||||
readonly typesRegistry = createMap<MapLike<string>>(),
|
||||
log?: TI.Log) {
|
||||
super(installTypingHost, globalTypingsCacheLocation, safeList.path, customTypesMap.path, throttleLimit, log);
|
||||
}
|
||||
@@ -126,6 +126,25 @@ namespace ts.projectSystem {
|
||||
return JSON.stringify({ dependencies });
|
||||
}
|
||||
|
||||
export function createTypesRegistry(...list: string[]): Map<MapLike<string>> {
|
||||
const versionMap = {
|
||||
"latest": "1.3.0",
|
||||
"ts2.0": "1.0.0",
|
||||
"ts2.1": "1.0.0",
|
||||
"ts2.2": "1.2.0",
|
||||
"ts2.3": "1.3.0",
|
||||
"ts2.4": "1.3.0",
|
||||
"ts2.5": "1.3.0",
|
||||
"ts2.6": "1.3.0",
|
||||
"ts2.7": "1.3.0"
|
||||
};
|
||||
const map = createMap<MapLike<string>>();
|
||||
for (const l of list) {
|
||||
map.set(l, versionMap);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function toExternalFile(fileName: string): protocol.ExternalFile {
|
||||
return { fileName };
|
||||
}
|
||||
@@ -2092,9 +2111,6 @@ namespace ts.projectSystem {
|
||||
/*closedFiles*/ undefined);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const changedFiles = projectService.getChangedFiles_TestOnly();
|
||||
assert(changedFiles && changedFiles.length === 1, `expected 1 changed file, got ${JSON.stringify(changedFiles && changedFiles.length || 0)}`);
|
||||
|
||||
projectService.ensureInferredProjectsUpToDate_TestOnly();
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 2 });
|
||||
});
|
||||
@@ -2885,9 +2901,109 @@ namespace ts.projectSystem {
|
||||
tags: []
|
||||
});
|
||||
});
|
||||
|
||||
it("files opened, closed affecting multiple projects", () => {
|
||||
const file: FileOrFolder = {
|
||||
path: "/a/b/projects/config/file.ts",
|
||||
content: `import {a} from "../files/file1"; export let b = a;`
|
||||
};
|
||||
const config: FileOrFolder = {
|
||||
path: "/a/b/projects/config/tsconfig.json",
|
||||
content: ""
|
||||
};
|
||||
const filesFile1: FileOrFolder = {
|
||||
path: "/a/b/projects/files/file1.ts",
|
||||
content: "export let a = 10;"
|
||||
};
|
||||
const filesFile2: FileOrFolder = {
|
||||
path: "/a/b/projects/files/file2.ts",
|
||||
content: "export let aa = 10;"
|
||||
};
|
||||
|
||||
const files = [config, file, filesFile1, filesFile2, libFile];
|
||||
const host = createServerHost(files);
|
||||
const session = createSession(host);
|
||||
// Create configured project
|
||||
session.executeCommandSeq<protocol.OpenRequest>({
|
||||
command: protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: file.path
|
||||
}
|
||||
});
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
const configuredProject = projectService.configuredProjects.get(config.path);
|
||||
verifyConfiguredProject();
|
||||
|
||||
// open files/file1 = should not create another project
|
||||
session.executeCommandSeq<protocol.OpenRequest>({
|
||||
command: protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: filesFile1.path
|
||||
}
|
||||
});
|
||||
verifyConfiguredProject();
|
||||
|
||||
// Close the file = should still have project
|
||||
session.executeCommandSeq<protocol.CloseRequest>({
|
||||
command: protocol.CommandTypes.Close,
|
||||
arguments: {
|
||||
file: file.path
|
||||
}
|
||||
});
|
||||
verifyConfiguredProject();
|
||||
|
||||
// Open files/file2 - should create inferred project and close configured project
|
||||
session.executeCommandSeq<protocol.OpenRequest>({
|
||||
command: protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: filesFile2.path
|
||||
}
|
||||
});
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [libFile.path, filesFile2.path]);
|
||||
|
||||
// Actions on file1 would result in assert
|
||||
session.executeCommandSeq<protocol.OccurrencesRequest>({
|
||||
command: protocol.CommandTypes.Occurrences,
|
||||
arguments: {
|
||||
file: filesFile1.path,
|
||||
line: 1,
|
||||
offset: filesFile1.content.indexOf("a")
|
||||
}
|
||||
});
|
||||
|
||||
function verifyConfiguredProject() {
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkProjectActualFiles(configuredProject, [file.path, filesFile1.path, libFile.path, config.path]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem Proper errors", () => {
|
||||
function createErrorLogger() {
|
||||
let hasError = false;
|
||||
const errorLogger: server.Logger = {
|
||||
close: noop,
|
||||
hasLevel: () => true,
|
||||
loggingEnabled: () => true,
|
||||
perftrc: noop,
|
||||
info: noop,
|
||||
msg: (_s, type) => {
|
||||
if (type === server.Msg.Err) {
|
||||
hasError = true;
|
||||
}
|
||||
},
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
};
|
||||
return {
|
||||
errorLogger,
|
||||
hasError: () => hasError
|
||||
};
|
||||
}
|
||||
|
||||
it("document is not contained in project", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/app.ts",
|
||||
@@ -2910,23 +3026,8 @@ namespace ts.projectSystem {
|
||||
describe("when opening new file that doesnt exist on disk yet", () => {
|
||||
function verifyNonExistentFile(useProjectRoot: boolean) {
|
||||
const host = createServerHost([libFile]);
|
||||
let hasError = false;
|
||||
const errLogger: server.Logger = {
|
||||
close: noop,
|
||||
hasLevel: () => true,
|
||||
loggingEnabled: () => true,
|
||||
perftrc: noop,
|
||||
info: noop,
|
||||
msg: (_s, type) => {
|
||||
if (type === server.Msg.Err) {
|
||||
hasError = true;
|
||||
}
|
||||
},
|
||||
startGroup: noop,
|
||||
endGroup: noop,
|
||||
getLogFileName: (): string => undefined
|
||||
};
|
||||
const session = createSession(host, { canUseEvents: true, logger: errLogger, useInferredProjectPerProjectRoot: true });
|
||||
const { hasError, errorLogger } = createErrorLogger();
|
||||
const session = createSession(host, { canUseEvents: true, logger: errorLogger, useInferredProjectPerProjectRoot: true });
|
||||
|
||||
const folderPath = "/user/someuser/projects/someFolder";
|
||||
const projectService = session.getProjectService();
|
||||
@@ -2967,13 +3068,13 @@ namespace ts.projectSystem {
|
||||
// Run the last one = get error request
|
||||
host.runQueuedTimeoutCallbacks(newTimeoutId);
|
||||
|
||||
assert.isFalse(hasError);
|
||||
assert.isFalse(hasError());
|
||||
host.checkTimeoutQueueLength(2);
|
||||
checkErrorMessage(session, "syntaxDiag", { file: untitledFile, diagnostics: [] });
|
||||
session.clearMessages();
|
||||
|
||||
host.runQueuedImmediateCallbacks();
|
||||
assert.isFalse(hasError);
|
||||
assert.isFalse(hasError());
|
||||
checkErrorMessage(session, "semanticDiag", { file: untitledFile, diagnostics: [] });
|
||||
|
||||
checkCompleteEvent(session, 2, expectedSequenceId);
|
||||
@@ -3039,6 +3140,31 @@ namespace ts.projectSystem {
|
||||
session.clearMessages();
|
||||
}
|
||||
});
|
||||
|
||||
it("Getting errors before opening file", () => {
|
||||
const file: FileOrFolder = {
|
||||
path: "/a/b/project/file.ts",
|
||||
content: "let x: number = false;"
|
||||
};
|
||||
const host = createServerHost([file, libFile]);
|
||||
const { hasError, errorLogger } = createErrorLogger();
|
||||
const session = createSession(host, { canUseEvents: true, logger: errorLogger });
|
||||
|
||||
session.clearMessages();
|
||||
const expectedSequenceId = session.getNextSeq();
|
||||
session.executeCommandSeq<protocol.GeterrRequest>({
|
||||
command: server.CommandNames.Geterr,
|
||||
arguments: {
|
||||
delay: 0,
|
||||
files: [file.path]
|
||||
}
|
||||
});
|
||||
|
||||
host.runQueuedImmediateCallbacks();
|
||||
assert.isFalse(hasError());
|
||||
checkCompleteEvent(session, 1, expectedSequenceId);
|
||||
session.clearMessages();
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem autoDiscovery", () => {
|
||||
@@ -6649,12 +6775,18 @@ namespace ts.projectSystem {
|
||||
},
|
||||
})
|
||||
};
|
||||
const typingsCachePackageLockJson: FileOrFolder = {
|
||||
path: `${typingsCache}/package-lock.json`,
|
||||
content: JSON.stringify({
|
||||
dependencies: {
|
||||
},
|
||||
})
|
||||
};
|
||||
|
||||
const files = [file, packageJsonInCurrentDirectory, packageJsonOfPkgcurrentdirectory, indexOfPkgcurrentdirectory, typingsCachePackageJson];
|
||||
const files = [file, packageJsonInCurrentDirectory, packageJsonOfPkgcurrentdirectory, indexOfPkgcurrentdirectory, typingsCachePackageJson, typingsCachePackageLockJson];
|
||||
const host = createServerHost(files, { currentDirectory });
|
||||
|
||||
const typesRegistry = createMap<void>();
|
||||
typesRegistry.set("pkgcurrentdirectory", void 0);
|
||||
const typesRegistry = createTypesRegistry("pkgcurrentdirectory");
|
||||
const typingsInstaller = new TestTypingsInstaller(typingsCache, /*throttleLimit*/ 5, host, typesRegistry);
|
||||
|
||||
const projectService = createProjectService(host, { typingsInstaller });
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// <reference path="../harness.ts" />
|
||||
/// <reference path="./tsserverProjectSystem.ts" />
|
||||
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />
|
||||
/// <reference path="../../services/semver.ts" />
|
||||
|
||||
namespace ts.projectSystem {
|
||||
import TI = server.typingsInstaller;
|
||||
@@ -10,15 +11,7 @@ namespace ts.projectSystem {
|
||||
interface InstallerParams {
|
||||
globalTypingsCacheLocation?: string;
|
||||
throttleLimit?: number;
|
||||
typesRegistry?: Map<void>;
|
||||
}
|
||||
|
||||
function createTypesRegistry(...list: string[]): Map<void> {
|
||||
const map = createMap<void>();
|
||||
for (const l of list) {
|
||||
map.set(l, undefined);
|
||||
}
|
||||
return map;
|
||||
typesRegistry?: Map<MapLike<string>>;
|
||||
}
|
||||
|
||||
class Installer extends TestTypingsInstaller {
|
||||
@@ -50,7 +43,7 @@ namespace ts.projectSystem {
|
||||
const logs: string[] = [];
|
||||
return {
|
||||
log(message) {
|
||||
logs.push(message);
|
||||
logs.push(message);
|
||||
},
|
||||
finish() {
|
||||
return logs;
|
||||
@@ -1053,6 +1046,142 @@ namespace ts.projectSystem {
|
||||
const version2 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion();
|
||||
assert.notEqual(version1, version2, "set of unresolved imports should change");
|
||||
});
|
||||
|
||||
it("expired cache entry (inferred project, should install typings)", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/app.js",
|
||||
content: ""
|
||||
};
|
||||
const packageJson = {
|
||||
path: "/a/b/package.json",
|
||||
content: JSON.stringify({
|
||||
name: "test",
|
||||
dependencies: {
|
||||
jquery: "^3.1.0"
|
||||
}
|
||||
})
|
||||
};
|
||||
const jquery = {
|
||||
path: "/a/data/node_modules/@types/jquery/index.d.ts",
|
||||
content: "declare const $: { x: number }"
|
||||
};
|
||||
const cacheConfig = {
|
||||
path: "/a/data/package.json",
|
||||
content: JSON.stringify({
|
||||
dependencies: {
|
||||
"types-registry": "^0.1.317"
|
||||
},
|
||||
devDependencies: {
|
||||
"@types/jquery": "^1.0.0"
|
||||
}
|
||||
})
|
||||
};
|
||||
const cacheLockConfig = {
|
||||
path: "/a/data/package-lock.json",
|
||||
content: JSON.stringify({
|
||||
dependencies: {
|
||||
"@types/jquery": {
|
||||
version: "1.0.0"
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
const host = createServerHost([file1, packageJson, jquery, cacheConfig, cacheLockConfig]);
|
||||
const installer = new (class extends Installer {
|
||||
constructor() {
|
||||
super(host, { typesRegistry: createTypesRegistry("jquery") });
|
||||
}
|
||||
installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) {
|
||||
const installedTypings = ["@types/jquery"];
|
||||
const typingFiles = [jquery];
|
||||
executeCommand(this, host, installedTypings, typingFiles, cb);
|
||||
}
|
||||
})();
|
||||
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer });
|
||||
projectService.openClientFile(file1.path);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const p = projectService.inferredProjects[0];
|
||||
checkProjectActualFiles(p, [file1.path]);
|
||||
|
||||
installer.installAll(/*expectedCount*/ 1);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(p, [file1.path, jquery.path]);
|
||||
});
|
||||
|
||||
it("non-expired cache entry (inferred project, should not install typings)", () => {
|
||||
const file1 = {
|
||||
path: "/a/b/app.js",
|
||||
content: ""
|
||||
};
|
||||
const packageJson = {
|
||||
path: "/a/b/package.json",
|
||||
content: JSON.stringify({
|
||||
name: "test",
|
||||
dependencies: {
|
||||
jquery: "^3.1.0"
|
||||
}
|
||||
})
|
||||
};
|
||||
const timestamps = {
|
||||
path: "/a/data/timestamps.json",
|
||||
content: JSON.stringify({
|
||||
entries: {
|
||||
"@types/jquery": Date.now()
|
||||
}
|
||||
})
|
||||
};
|
||||
const cacheConfig = {
|
||||
path: "/a/data/package.json",
|
||||
content: JSON.stringify({
|
||||
dependencies: {
|
||||
"types-registry": "^0.1.317"
|
||||
},
|
||||
devDependencies: {
|
||||
"@types/jquery": "^1.3.0"
|
||||
}
|
||||
})
|
||||
};
|
||||
const cacheLockConfig = {
|
||||
path: "/a/data/package-lock.json",
|
||||
content: JSON.stringify({
|
||||
dependencies: {
|
||||
"@types/jquery": {
|
||||
version: "1.3.0"
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
const jquery = {
|
||||
path: "/a/data/node_modules/@types/jquery/index.d.ts",
|
||||
content: "declare const $: { x: number }"
|
||||
};
|
||||
const host = createServerHost([file1, packageJson, timestamps, cacheConfig, cacheLockConfig, jquery]);
|
||||
const installer = new (class extends Installer {
|
||||
constructor() {
|
||||
super(host, { typesRegistry: createTypesRegistry("jquery") });
|
||||
}
|
||||
installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction) {
|
||||
const installedTypings: string[] = [];
|
||||
const typingFiles: FileOrFolder[] = [];
|
||||
executeCommand(this, host, installedTypings, typingFiles, cb);
|
||||
}
|
||||
})();
|
||||
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true, typingsInstaller: installer });
|
||||
projectService.openClientFile(file1.path);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const p = projectService.inferredProjects[0];
|
||||
checkProjectActualFiles(p, [file1.path]);
|
||||
|
||||
installer.installAll(/*expectedCount*/ 0);
|
||||
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(p, [file1.path]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Validate package name:", () => {
|
||||
@@ -1132,7 +1261,7 @@ namespace ts.projectSystem {
|
||||
|
||||
const host = createServerHost([app, jquery, chroma]);
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), safeList, emptyMap, { enable: true }, emptyArray);
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), safeList, emptyMap, { enable: true }, emptyArray, emptyMap);
|
||||
const finish = logger.finish();
|
||||
assert.deepEqual(finish, [
|
||||
'Inferred typings from file names: ["jquery","chroma-js"]',
|
||||
@@ -1148,11 +1277,11 @@ namespace ts.projectSystem {
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f]);
|
||||
const cache = createMap<string>();
|
||||
const cache = createMap<JsTyping.CachedTyping>();
|
||||
|
||||
for (const name of JsTyping.nodeCoreModuleList) {
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, [name, "somename"]);
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, [name, "somename"], emptyMap);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from unresolved imports: ["node","somename"]',
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["node","somename"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
|
||||
@@ -1171,9 +1300,10 @@ namespace ts.projectSystem {
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f, node]);
|
||||
const cache = createMapFromTemplate<string>({ node: node.path });
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({ node: { typingLocation: node.path, version: Semver.parse("1.3.0") } });
|
||||
const registry = createTypesRegistry("node");
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, ["fs", "bar"]);
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, ["fs", "bar"], registry);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from unresolved imports: ["node","bar"]',
|
||||
'Result: {"cachedTypingPaths":["/a/b/node.d.ts"],"newTypingNames":["bar"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
|
||||
@@ -1196,9 +1326,9 @@ namespace ts.projectSystem {
|
||||
content: JSON.stringify({ name: "b" }),
|
||||
};
|
||||
const host = createServerHost([app, a, b]);
|
||||
const cache = createMap<string>();
|
||||
const cache = createMap<JsTyping.CachedTyping>();
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), emptySafeList, cache, { enable: true }, /*unresolvedImports*/ []);
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), emptySafeList, cache, { enable: true }, /*unresolvedImports*/ [], emptyMap);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Searching for typing names in /node_modules; all files: ["/node_modules/a/package.json"]',
|
||||
' Found package names: ["a"]',
|
||||
@@ -1211,6 +1341,94 @@ namespace ts.projectSystem {
|
||||
filesToWatch: ["/bower_components", "/node_modules"],
|
||||
});
|
||||
});
|
||||
|
||||
it("should install expired typings", () => {
|
||||
const app = {
|
||||
path: "/a/app.js",
|
||||
content: ""
|
||||
};
|
||||
const cachePath = "/a/cache/";
|
||||
const commander = {
|
||||
path: cachePath + "node_modules/@types/commander/index.d.ts",
|
||||
content: "export let x: number"
|
||||
};
|
||||
const node = {
|
||||
path: cachePath + "node_modules/@types/node/index.d.ts",
|
||||
content: "export let y: number"
|
||||
};
|
||||
const host = createServerHost([app]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({
|
||||
node: { typingLocation: node.path, version: Semver.parse("1.3.0") },
|
||||
commander: { typingLocation: commander.path, version: Semver.parse("1.0.0") }
|
||||
});
|
||||
const registry = createTypesRegistry("node", "commander");
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), emptySafeList, cache, { enable: true }, ["http", "commander"], registry);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from unresolved imports: ["node","commander"]',
|
||||
'Result: {"cachedTypingPaths":["/a/cache/node_modules/@types/node/index.d.ts"],"newTypingNames":["commander"],"filesToWatch":["/a/bower_components","/a/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result.cachedTypingPaths, [node.path]);
|
||||
assert.deepEqual(result.newTypingNames, ["commander"]);
|
||||
});
|
||||
|
||||
it("should install expired typings with prerelease version of tsserver", () => {
|
||||
const app = {
|
||||
path: "/a/app.js",
|
||||
content: ""
|
||||
};
|
||||
const cachePath = "/a/cache/";
|
||||
const node = {
|
||||
path: cachePath + "node_modules/@types/node/index.d.ts",
|
||||
content: "export let y: number"
|
||||
};
|
||||
const host = createServerHost([app]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({
|
||||
node: { typingLocation: node.path, version: Semver.parse("1.0.0") }
|
||||
});
|
||||
const registry = createTypesRegistry("node");
|
||||
registry.delete(`ts${ts.versionMajorMinor}`);
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), emptySafeList, cache, { enable: true }, ["http"], registry);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from unresolved imports: ["node"]',
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["node"],"filesToWatch":["/a/bower_components","/a/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result.cachedTypingPaths, []);
|
||||
assert.deepEqual(result.newTypingNames, ["node"]);
|
||||
});
|
||||
|
||||
|
||||
it("prerelease typings are properly handled", () => {
|
||||
const app = {
|
||||
path: "/a/app.js",
|
||||
content: ""
|
||||
};
|
||||
const cachePath = "/a/cache/";
|
||||
const commander = {
|
||||
path: cachePath + "node_modules/@types/commander/index.d.ts",
|
||||
content: "export let x: number"
|
||||
};
|
||||
const node = {
|
||||
path: cachePath + "node_modules/@types/node/index.d.ts",
|
||||
content: "export let y: number"
|
||||
};
|
||||
const host = createServerHost([app]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({
|
||||
node: { typingLocation: node.path, version: Semver.parse("1.3.0-next.0") },
|
||||
commander: { typingLocation: commander.path, version: Semver.parse("1.3.0-next.0") }
|
||||
});
|
||||
const registry = createTypesRegistry("node", "commander");
|
||||
registry.get("node")[`ts${ts.versionMajorMinor}`] = "1.3.0-next.1";
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), emptySafeList, cache, { enable: true }, ["http", "commander"], registry);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from unresolved imports: ["node","commander"]',
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["node","commander"],"filesToWatch":["/a/bower_components","/a/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result.cachedTypingPaths, []);
|
||||
assert.deepEqual(result.newTypingNames, ["node", "commander"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("telemetry events", () => {
|
||||
@@ -1273,12 +1491,22 @@ namespace ts.projectSystem {
|
||||
path: "/a/package.json",
|
||||
content: JSON.stringify({ dependencies: { commander: "1.0.0" } })
|
||||
};
|
||||
const packageLockFile = {
|
||||
path: "/a/cache/package-lock.json",
|
||||
content: JSON.stringify({
|
||||
dependencies: {
|
||||
"@types/commander": {
|
||||
version: "1.0.0"
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
const cachePath = "/a/cache/";
|
||||
const commander = {
|
||||
path: cachePath + "node_modules/@types/commander/index.d.ts",
|
||||
content: "export let x: number"
|
||||
};
|
||||
const host = createServerHost([f1, packageFile]);
|
||||
const host = createServerHost([f1, packageFile, packageLockFile]);
|
||||
let beginEvent: server.BeginInstallTypes;
|
||||
let endEvent: server.EndInstallTypes;
|
||||
const installer = new (class extends Installer {
|
||||
|
||||
@@ -246,8 +246,12 @@ interface Array<T> {}`
|
||||
}
|
||||
|
||||
export interface ReloadWatchInvokeOptions {
|
||||
/** Invokes the directory watcher for the parent instead of the file changed */
|
||||
invokeDirectoryWatcherInsteadOfFileChanged: boolean;
|
||||
/** When new file is created, do not invoke watches for it */
|
||||
ignoreWatchInvokedWithTriggerAsFileCreate: boolean;
|
||||
/** Invoke the file delete, followed by create instead of file changed */
|
||||
invokeFileDeleteCreateAsPartInsteadOfChange: boolean;
|
||||
}
|
||||
|
||||
export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost {
|
||||
@@ -315,12 +319,18 @@ interface Array<T> {}`
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
// Update file
|
||||
if (currentEntry.content !== fileOrDirectory.content) {
|
||||
currentEntry.content = fileOrDirectory.content;
|
||||
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
|
||||
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
|
||||
if (options && options.invokeFileDeleteCreateAsPartInsteadOfChange) {
|
||||
this.removeFileOrFolder(currentEntry, returnFalse);
|
||||
this.ensureFileOrFolder(fileOrDirectory);
|
||||
}
|
||||
else {
|
||||
this.invokeFileWatcher(currentEntry.fullPath, FileWatcherEventKind.Changed);
|
||||
currentEntry.content = fileOrDirectory.content;
|
||||
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
|
||||
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
|
||||
}
|
||||
else {
|
||||
this.invokeFileWatcher(currentEntry.fullPath, FileWatcherEventKind.Changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,9 +405,11 @@ interface Array<T> {}`
|
||||
ensureFileOrFolder(fileOrDirectory: FileOrFolder, ignoreWatchInvokedWithTriggerAsFileCreate?: boolean) {
|
||||
if (isString(fileOrDirectory.content)) {
|
||||
const file = this.toFile(fileOrDirectory);
|
||||
Debug.assert(!this.fs.get(file.path));
|
||||
const baseFolder = this.ensureFolder(getDirectoryPath(file.fullPath));
|
||||
this.addFileOrFolderInFolder(baseFolder, file, ignoreWatchInvokedWithTriggerAsFileCreate);
|
||||
// file may already exist when updating existing type declaration file
|
||||
if (!this.fs.get(file.path)) {
|
||||
const baseFolder = this.ensureFolder(getDirectoryPath(file.fullPath));
|
||||
this.addFileOrFolderInFolder(baseFolder, file, ignoreWatchInvokedWithTriggerAsFileCreate);
|
||||
}
|
||||
}
|
||||
else if (isString(fileOrDirectory.symLink)) {
|
||||
const symLink = this.toSymLink(fileOrDirectory);
|
||||
|
||||
Vendored
+485
-426
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
@@ -69,7 +69,7 @@ interface ArrayConstructor {
|
||||
}
|
||||
|
||||
interface DateConstructor {
|
||||
new (value: Date): Date;
|
||||
new (value: number | string | Date): Date;
|
||||
}
|
||||
|
||||
interface Function {
|
||||
|
||||
Vendored
+34
-2
@@ -985,7 +985,7 @@ interface ReadonlyArray<T> {
|
||||
*/
|
||||
toString(): string;
|
||||
/**
|
||||
* Returns a string representation of an array. The elements are converted to string using thier toLocalString methods.
|
||||
* Returns a string representation of an array. The elements are converted to string using their toLocalString methods.
|
||||
*/
|
||||
toLocaleString(): string;
|
||||
/**
|
||||
@@ -1104,7 +1104,7 @@ interface Array<T> {
|
||||
*/
|
||||
toString(): string;
|
||||
/**
|
||||
* Returns a string representation of an array. The elements are converted to string using thier toLocalString methods.
|
||||
* Returns a string representation of an array. The elements are converted to string using their toLocalString methods.
|
||||
*/
|
||||
toLocaleString(): string;
|
||||
/**
|
||||
@@ -1317,6 +1317,13 @@ type Partial<T> = {
|
||||
[P in keyof T]?: T[P];
|
||||
};
|
||||
|
||||
/**
|
||||
* Make all properties in T required
|
||||
*/
|
||||
type Required<T> = {
|
||||
[P in keyof T]-?: T[P];
|
||||
};
|
||||
|
||||
/**
|
||||
* Make all properties in T readonly
|
||||
*/
|
||||
@@ -1338,6 +1345,31 @@ type Record<K extends string, T> = {
|
||||
[P in K]: T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exclude from T those types that are assignable to U
|
||||
*/
|
||||
type Exclude<T, U> = T extends U ? never : T;
|
||||
|
||||
/**
|
||||
* Extract from T those types that are assignable to U
|
||||
*/
|
||||
type Extract<T, U> = T extends U ? T : never;
|
||||
|
||||
/**
|
||||
* Exclude null and undefined from T
|
||||
*/
|
||||
type NonNullable<T> = T extends null | undefined ? never : T;
|
||||
|
||||
/**
|
||||
* Obtain the return type of a function type
|
||||
*/
|
||||
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
|
||||
|
||||
/**
|
||||
* Obtain the return type of a constructor function type
|
||||
*/
|
||||
type InstanceType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer R ? R : any;
|
||||
|
||||
/**
|
||||
* Marker for contextual 'this' type
|
||||
*/
|
||||
|
||||
Vendored
+48
-68
@@ -128,21 +128,7 @@ interface SyncEventInit extends ExtendableEventInit {
|
||||
lastChance?: boolean;
|
||||
}
|
||||
|
||||
interface EventListener {
|
||||
(evt: Event): void;
|
||||
}
|
||||
|
||||
interface WebKitEntriesCallback {
|
||||
(evt: Event): void;
|
||||
}
|
||||
|
||||
interface WebKitErrorCallback {
|
||||
(evt: Event): void;
|
||||
}
|
||||
|
||||
interface WebKitFileCallback {
|
||||
(evt: Event): void;
|
||||
}
|
||||
type EventListener = (evt: Event) => void | { handleEvent(evt: Event): void; };
|
||||
|
||||
interface AudioBuffer {
|
||||
readonly duration: number;
|
||||
@@ -404,9 +390,9 @@ declare var Event: {
|
||||
};
|
||||
|
||||
interface EventTarget {
|
||||
addEventListener(type: string, listener?: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
dispatchEvent(evt: Event): boolean;
|
||||
removeEventListener(type: string, listener?: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var EventTarget: {
|
||||
@@ -444,9 +430,9 @@ interface FileReader extends EventTarget, MSBaseReader {
|
||||
readAsDataURL(blob: Blob): void;
|
||||
readAsText(blob: Blob, encoding?: string): void;
|
||||
addEventListener<K extends keyof MSBaseReaderEventMap>(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof MSBaseReaderEventMap>(type: K, listener: (this: FileReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var FileReader: {
|
||||
@@ -529,9 +515,9 @@ interface IDBDatabase extends EventTarget {
|
||||
addEventListener(type: "versionchange", listener: (this: IDBDatabase, ev: IDBVersionChangeEvent) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener(type: "versionchange", listener: (this: IDBDatabase, ev: IDBVersionChangeEvent) => any, options?: boolean | EventListenerOptions): void;
|
||||
addEventListener<K extends keyof IDBDatabaseEventMap>(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof IDBDatabaseEventMap>(type: K, listener: (this: IDBDatabase, ev: IDBDatabaseEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var IDBDatabase: {
|
||||
@@ -616,9 +602,9 @@ interface IDBOpenDBRequest extends IDBRequest {
|
||||
onblocked: (this: IDBOpenDBRequest, ev: Event) => any;
|
||||
onupgradeneeded: (this: IDBOpenDBRequest, ev: IDBVersionChangeEvent) => any;
|
||||
addEventListener<K extends keyof IDBOpenDBRequestEventMap>(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof IDBOpenDBRequestEventMap>(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var IDBOpenDBRequest: {
|
||||
@@ -640,9 +626,9 @@ interface IDBRequest extends EventTarget {
|
||||
source: IDBObjectStore | IDBIndex | IDBCursor;
|
||||
readonly transaction: IDBTransaction;
|
||||
addEventListener<K extends keyof IDBRequestEventMap>(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof IDBRequestEventMap>(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var IDBRequest: {
|
||||
@@ -669,9 +655,9 @@ interface IDBTransaction extends EventTarget {
|
||||
readonly READ_WRITE: string;
|
||||
readonly VERSION_CHANGE: string;
|
||||
addEventListener<K extends keyof IDBTransactionEventMap>(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof IDBTransactionEventMap>(type: K, listener: (this: IDBTransaction, ev: IDBTransactionEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var IDBTransaction: {
|
||||
@@ -737,9 +723,9 @@ interface MessagePort extends EventTarget {
|
||||
postMessage(message?: any, transfer?: any[]): void;
|
||||
start(): void;
|
||||
addEventListener<K extends keyof MessagePortEventMap>(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof MessagePortEventMap>(type: K, listener: (this: MessagePort, ev: MessagePortEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var MessagePort: {
|
||||
@@ -768,9 +754,9 @@ interface Notification extends EventTarget {
|
||||
readonly title: string;
|
||||
close(): void;
|
||||
addEventListener<K extends keyof NotificationEventMap>(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof NotificationEventMap>(type: K, listener: (this: Notification, ev: NotificationEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var Notification: {
|
||||
@@ -892,7 +878,7 @@ declare var ProgressEvent: {
|
||||
};
|
||||
|
||||
interface PushManager {
|
||||
getSubscription(): Promise<PushSubscription>;
|
||||
getSubscription(): Promise<PushSubscription | null>;
|
||||
permissionState(options?: PushSubscriptionOptionsInit): Promise<PushPermissionState>;
|
||||
subscribe(options?: PushSubscriptionOptionsInit): Promise<PushSubscription>;
|
||||
}
|
||||
@@ -999,9 +985,9 @@ interface ServiceWorker extends EventTarget, AbstractWorker {
|
||||
readonly state: ServiceWorkerState;
|
||||
postMessage(message: any, transfer?: any[]): void;
|
||||
addEventListener<K extends keyof ServiceWorkerEventMap>(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof ServiceWorkerEventMap>(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var ServiceWorker: {
|
||||
@@ -1026,9 +1012,9 @@ interface ServiceWorkerRegistration extends EventTarget {
|
||||
unregister(): Promise<boolean>;
|
||||
update(): Promise<void>;
|
||||
addEventListener<K extends keyof ServiceWorkerRegistrationEventMap>(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof ServiceWorkerRegistrationEventMap>(type: K, listener: (this: ServiceWorkerRegistration, ev: ServiceWorkerRegistrationEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var ServiceWorkerRegistration: {
|
||||
@@ -1088,15 +1074,15 @@ interface WebSocket extends EventTarget {
|
||||
readonly readyState: number;
|
||||
readonly url: string;
|
||||
close(code?: number, reason?: string): void;
|
||||
send(data: any): void;
|
||||
send(data: USVString | ArrayBuffer | Blob | ArrayBufferView): void;
|
||||
readonly CLOSED: number;
|
||||
readonly CLOSING: number;
|
||||
readonly CONNECTING: number;
|
||||
readonly OPEN: number;
|
||||
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var WebSocket: {
|
||||
@@ -1117,9 +1103,9 @@ interface Worker extends EventTarget, AbstractWorker {
|
||||
postMessage(message: any, transfer?: any[]): void;
|
||||
terminate(): void;
|
||||
addEventListener<K extends keyof WorkerEventMap>(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof WorkerEventMap>(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var Worker: {
|
||||
@@ -1160,9 +1146,9 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
|
||||
readonly OPENED: number;
|
||||
readonly UNSENT: number;
|
||||
addEventListener<K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof XMLHttpRequestEventMap>(type: K, listener: (this: XMLHttpRequest, ev: XMLHttpRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var XMLHttpRequest: {
|
||||
@@ -1177,9 +1163,9 @@ declare var XMLHttpRequest: {
|
||||
|
||||
interface XMLHttpRequestUpload extends EventTarget, XMLHttpRequestEventTarget {
|
||||
addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestUpload, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var XMLHttpRequestUpload: {
|
||||
@@ -1194,9 +1180,9 @@ interface AbstractWorkerEventMap {
|
||||
interface AbstractWorker {
|
||||
onerror: (this: AbstractWorker, ev: ErrorEvent) => any;
|
||||
addEventListener<K extends keyof AbstractWorkerEventMap>(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof AbstractWorkerEventMap>(type: K, listener: (this: AbstractWorker, ev: AbstractWorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
interface Body {
|
||||
@@ -1234,9 +1220,9 @@ interface MSBaseReader {
|
||||
readonly EMPTY: number;
|
||||
readonly LOADING: number;
|
||||
addEventListener<K extends keyof MSBaseReaderEventMap>(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof MSBaseReaderEventMap>(type: K, listener: (this: MSBaseReader, ev: MSBaseReaderEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
interface NavigatorBeacon {
|
||||
@@ -1291,9 +1277,9 @@ interface XMLHttpRequestEventTarget {
|
||||
onprogress: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
ontimeout: (this: XMLHttpRequest, ev: ProgressEvent) => any;
|
||||
addEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof XMLHttpRequestEventTargetEventMap>(type: K, listener: (this: XMLHttpRequestEventTarget, ev: XMLHttpRequestEventTargetEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
interface Client {
|
||||
@@ -1329,9 +1315,9 @@ interface DedicatedWorkerGlobalScope extends WorkerGlobalScope {
|
||||
close(): void;
|
||||
postMessage(message: any, transfer?: any[]): void;
|
||||
addEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var DedicatedWorkerGlobalScope: {
|
||||
@@ -1442,9 +1428,9 @@ interface ServiceWorkerGlobalScope extends WorkerGlobalScope {
|
||||
readonly registration: ServiceWorkerRegistration;
|
||||
skipWaiting(): Promise<void>;
|
||||
addEventListener<K extends keyof ServiceWorkerGlobalScopeEventMap>(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof ServiceWorkerGlobalScopeEventMap>(type: K, listener: (this: ServiceWorkerGlobalScope, ev: ServiceWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var ServiceWorkerGlobalScope: {
|
||||
@@ -1489,9 +1475,9 @@ interface WorkerGlobalScope extends EventTarget, WorkerUtils, WindowConsole, Glo
|
||||
createImageBitmap(image: ImageBitmap | ImageData | Blob, options?: ImageBitmapOptions): Promise<ImageBitmap>;
|
||||
createImageBitmap(image: ImageBitmap | ImageData | Blob, sx: number, sy: number, sw: number, sh: number, options?: ImageBitmapOptions): Promise<ImageBitmap>;
|
||||
addEventListener<K extends keyof WorkerGlobalScopeEventMap>(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof WorkerGlobalScopeEventMap>(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var WorkerGlobalScope: {
|
||||
@@ -1549,9 +1535,9 @@ interface BroadcastChannel extends EventTarget {
|
||||
close(): void;
|
||||
postMessage(message: any): void;
|
||||
addEventListener<K extends keyof BroadcastChannelEventMap>(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
removeEventListener<K extends keyof BroadcastChannelEventMap>(type: K, listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
}
|
||||
|
||||
declare var BroadcastChannel: {
|
||||
@@ -1631,10 +1617,6 @@ interface FilePropertyBag extends BlobPropertyBag {
|
||||
lastModified?: number;
|
||||
}
|
||||
|
||||
interface EventListenerObject {
|
||||
handleEvent(evt: Event): void;
|
||||
}
|
||||
|
||||
interface ProgressEventInit extends EventInit {
|
||||
lengthComputable?: boolean;
|
||||
loaded?: number;
|
||||
@@ -1861,8 +1843,6 @@ interface EventSourceInit {
|
||||
readonly withCredentials: boolean;
|
||||
}
|
||||
|
||||
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
|
||||
|
||||
interface DecodeErrorCallback {
|
||||
(error: DOMException): void;
|
||||
}
|
||||
@@ -1873,7 +1853,7 @@ interface ErrorEventHandler {
|
||||
(message: string, filename?: string, lineno?: number, colno?: number, error?: Error): void;
|
||||
}
|
||||
interface ForEachCallback {
|
||||
(keyId: BufferSource, status: MediaKeyStatus): void;
|
||||
(keyId: any, status: MediaKeyStatus): void;
|
||||
}
|
||||
interface FunctionStringCallback {
|
||||
(data: string): void;
|
||||
@@ -1919,9 +1899,9 @@ declare var console: Console;
|
||||
declare function fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
|
||||
declare function dispatchEvent(evt: Event): boolean;
|
||||
declare function addEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||
declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||
declare function addEventListener(type: string, listener: EventListener, options?: boolean | AddEventListenerOptions): void;
|
||||
declare function removeEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||
declare function removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||
declare function removeEventListener(type: string, listener: EventListener, options?: boolean | EventListenerOptions): void;
|
||||
type AlgorithmIdentifier = string | Algorithm;
|
||||
type BodyInit = Blob | BufferSource | FormData | string;
|
||||
type IDBKeyPath = string;
|
||||
|
||||
@@ -8778,6 +8778,15 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type_1338" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['infer' declarations are only permitted in the 'extends' clause of a conditional type.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Deklarace infer jsou povolené jenom v klauzuli extends podmíněného typu.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";interface_declarations_can_only_be_used_in_a_ts_file_8006" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['interface declarations' can only be used in a .ts file.]]></Val>
|
||||
|
||||
@@ -8760,6 +8760,15 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type_1338" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['infer' declarations are only permitted in the 'extends' clause of a conditional type.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[infer-Deklarationen sind nur in der extends-Klausel eines bedingten Typs zulässig.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";interface_declarations_can_only_be_used_in_a_ts_file_8006" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['interface declarations' can only be used in a .ts file.]]></Val>
|
||||
|
||||
@@ -8778,6 +8778,15 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type_1338" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['infer' declarations are only permitted in the 'extends' clause of a conditional type.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Les déclarations 'infer' sont uniquement autorisées dans la clause 'extends' d’un type conditionnel.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";interface_declarations_can_only_be_used_in_a_ts_file_8006" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['interface declarations' can only be used in a .ts file.]]></Val>
|
||||
|
||||
@@ -8768,6 +8768,15 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type_1338" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['infer' declarations are only permitted in the 'extends' clause of a conditional type.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA[Объявления "infer" допустимы только в предложении "extends" условного типа.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";interface_declarations_can_only_be_used_in_a_ts_file_8006" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['interface declarations' can only be used in a .ts file.]]></Val>
|
||||
|
||||
@@ -8762,6 +8762,15 @@
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type_1338" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['infer' declarations are only permitted in the 'extends' clause of a conditional type.]]></Val>
|
||||
<Tgt Cat="Text" Stat="Loc" Orig="New">
|
||||
<Val><![CDATA['infer' bildirimlerine yalnızca bir koşullu türün 'extends' yan tümcesinde izin verilir.]]></Val>
|
||||
</Tgt>
|
||||
</Str>
|
||||
<Disp Icon="Str" />
|
||||
</Item>
|
||||
<Item ItemId=";interface_declarations_can_only_be_used_in_a_ts_file_8006" ItemType="0" PsrId="306" Leaf="true">
|
||||
<Str Cat="Text">
|
||||
<Val><![CDATA['interface declarations' can only be used in a .ts file.]]></Val>
|
||||
|
||||
+87
-147
@@ -376,9 +376,9 @@ namespace ts.server {
|
||||
private safelist: SafeList = defaultTypeSafeList;
|
||||
private legacySafelist: { [key: string]: string } = {};
|
||||
|
||||
private changedFiles: ScriptInfo[];
|
||||
private pendingProjectUpdates = createMap<Project>();
|
||||
private pendingInferredProjectUpdate: boolean;
|
||||
/* @internal */
|
||||
pendingEnsureProjectForOpenFiles: boolean;
|
||||
|
||||
readonly currentDirectory: string;
|
||||
readonly toCanonicalFileName: (f: string) => string;
|
||||
@@ -483,11 +483,6 @@ namespace ts.server {
|
||||
return getNormalizedAbsolutePath(fileName, this.host.getCurrentDirectory());
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
getChangedFiles_TestOnly() {
|
||||
return this.changedFiles;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
ensureInferredProjectsUpToDate_TestOnly() {
|
||||
this.ensureProjectStructuresUptoDate();
|
||||
@@ -552,19 +547,18 @@ namespace ts.server {
|
||||
this.typingsCache.deleteTypingsForProject(response.projectName);
|
||||
break;
|
||||
}
|
||||
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
|
||||
this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project);
|
||||
}
|
||||
|
||||
private delayInferredProjectsRefresh() {
|
||||
this.pendingInferredProjectUpdate = true;
|
||||
this.throttledOperations.schedule("*refreshInferredProjects*", /*delay*/ 250, () => {
|
||||
private delayEnsureProjectForOpenFiles() {
|
||||
this.pendingEnsureProjectForOpenFiles = true;
|
||||
this.throttledOperations.schedule("*ensureProjectForOpenFiles*", /*delay*/ 250, () => {
|
||||
if (this.pendingProjectUpdates.size !== 0) {
|
||||
this.delayInferredProjectsRefresh();
|
||||
this.delayEnsureProjectForOpenFiles();
|
||||
}
|
||||
else {
|
||||
if (this.pendingInferredProjectUpdate) {
|
||||
this.pendingInferredProjectUpdate = false;
|
||||
this.refreshInferredProjects();
|
||||
if (this.pendingEnsureProjectForOpenFiles) {
|
||||
this.ensureProjectForOpenFiles();
|
||||
}
|
||||
// Send the event to notify that there were background project updates
|
||||
// send current list of open files
|
||||
@@ -574,6 +568,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private delayUpdateProjectGraph(project: Project) {
|
||||
project.markAsDirty();
|
||||
const projectName = project.getProjectName();
|
||||
this.pendingProjectUpdates.set(projectName, project);
|
||||
this.throttledOperations.schedule(projectName, /*delay*/ 250, () => {
|
||||
@@ -603,17 +598,16 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
delayUpdateProjectGraphAndInferredProjectsRefresh(project: Project) {
|
||||
project.markAsDirty();
|
||||
delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project: Project) {
|
||||
this.delayUpdateProjectGraph(project);
|
||||
this.delayInferredProjectsRefresh();
|
||||
this.delayEnsureProjectForOpenFiles();
|
||||
}
|
||||
|
||||
private delayUpdateProjectGraphs(projects: Project[]) {
|
||||
private delayUpdateProjectGraphs(projects: ReadonlyArray<Project>) {
|
||||
for (const project of projects) {
|
||||
this.delayUpdateProjectGraph(project);
|
||||
}
|
||||
this.delayInferredProjectsRefresh();
|
||||
this.delayEnsureProjectForOpenFiles();
|
||||
}
|
||||
|
||||
setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.ExternalProjectCompilerOptions, projectRootPath?: string): void {
|
||||
@@ -632,7 +626,6 @@ namespace ts.server {
|
||||
this.compilerOptionsForInferredProjects = compilerOptions;
|
||||
}
|
||||
|
||||
const projectsToUpdate: Project[] = [];
|
||||
for (const project of this.inferredProjects) {
|
||||
// Only update compiler options in the following cases:
|
||||
// - Inferred projects without a projectRootPath, if the new options do not apply to
|
||||
@@ -648,11 +641,11 @@ namespace ts.server {
|
||||
project.setCompilerOptions(compilerOptions);
|
||||
project.compileOnSaveEnabled = compilerOptions.compileOnSave;
|
||||
project.markAsDirty();
|
||||
projectsToUpdate.push(project);
|
||||
this.delayUpdateProjectGraph(project);
|
||||
}
|
||||
}
|
||||
|
||||
this.delayUpdateProjectGraphs(projectsToUpdate);
|
||||
this.delayEnsureProjectForOpenFiles();
|
||||
}
|
||||
|
||||
findProject(projectName: string): Project | undefined {
|
||||
@@ -668,7 +661,7 @@ namespace ts.server {
|
||||
|
||||
getDefaultProjectForFile(fileName: NormalizedPath, ensureProject: boolean) {
|
||||
let scriptInfo = this.getScriptInfoForNormalizedPath(fileName);
|
||||
if (ensureProject && !scriptInfo || scriptInfo.isOrphan()) {
|
||||
if (ensureProject && (!scriptInfo || scriptInfo.isOrphan())) {
|
||||
this.ensureProjectStructuresUptoDate();
|
||||
scriptInfo = this.getScriptInfoForNormalizedPath(fileName);
|
||||
if (!scriptInfo) {
|
||||
@@ -687,41 +680,27 @@ namespace ts.server {
|
||||
/**
|
||||
* Ensures the project structures are upto date
|
||||
* This means,
|
||||
* - if there are changedFiles (the files were updated but their containing project graph was not upto date),
|
||||
* their project graph is updated
|
||||
* - If there are pendingProjectUpdates (scheduled to be updated with delay so they can batch update the graph if there are several changes in short time span)
|
||||
* their project graph is updated
|
||||
* - If there were project graph updates and/or there was pending inferred project update and/or called forced the inferred project structure refresh
|
||||
* Inferred projects are created/updated/deleted based on open files states
|
||||
* @param forceInferredProjectsRefresh when true updates the inferred projects even if there is no pending work to update the files/project structures
|
||||
* - we go through all the projects and update them if they are dirty
|
||||
* - if updates reflect some change in structure or there was pending request to ensure projects for open files
|
||||
* ensure that each open script info has project
|
||||
*/
|
||||
private ensureProjectStructuresUptoDate(forceInferredProjectsRefresh?: boolean) {
|
||||
if (this.changedFiles) {
|
||||
let projectsToUpdate: Project[];
|
||||
if (this.changedFiles.length === 1) {
|
||||
// simpliest case - no allocations
|
||||
projectsToUpdate = this.changedFiles[0].containingProjects;
|
||||
}
|
||||
else {
|
||||
projectsToUpdate = [];
|
||||
for (const f of this.changedFiles) {
|
||||
addRange(projectsToUpdate, f.containingProjects);
|
||||
}
|
||||
}
|
||||
this.changedFiles = undefined;
|
||||
this.updateProjectGraphs(projectsToUpdate);
|
||||
}
|
||||
private ensureProjectStructuresUptoDate() {
|
||||
let hasChanges = this.pendingEnsureProjectForOpenFiles;
|
||||
this.pendingProjectUpdates.clear();
|
||||
const updateGraph = (project: Project) => {
|
||||
hasChanges = this.updateProjectIfDirty(project) || hasChanges;
|
||||
};
|
||||
|
||||
if (this.pendingProjectUpdates.size !== 0) {
|
||||
const projectsToUpdate = arrayFrom(this.pendingProjectUpdates.values());
|
||||
this.pendingProjectUpdates.clear();
|
||||
this.updateProjectGraphs(projectsToUpdate);
|
||||
this.externalProjects.forEach(updateGraph);
|
||||
this.configuredProjects.forEach(updateGraph);
|
||||
this.inferredProjects.forEach(updateGraph);
|
||||
if (hasChanges) {
|
||||
this.ensureProjectForOpenFiles();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pendingInferredProjectUpdate || forceInferredProjectsRefresh) {
|
||||
this.pendingInferredProjectUpdate = false;
|
||||
this.refreshInferredProjects();
|
||||
}
|
||||
private updateProjectIfDirty(project: Project) {
|
||||
return project.dirty && project.updateGraph();
|
||||
}
|
||||
|
||||
getFormatCodeOptions(file?: NormalizedPath) {
|
||||
@@ -735,14 +714,6 @@ namespace ts.server {
|
||||
return formatCodeSettings || this.hostConfiguration.formatCodeOptions;
|
||||
}
|
||||
|
||||
private updateProjectGraphs(projects: Project[]) {
|
||||
for (const p of projects) {
|
||||
if (!p.updateGraph()) {
|
||||
this.pendingInferredProjectUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onSourceFileChanged(fileName: NormalizedPath, eventKind: FileWatcherEventKind) {
|
||||
const info = this.getScriptInfoForNormalizedPath(fileName);
|
||||
if (!info) {
|
||||
@@ -770,8 +741,6 @@ namespace ts.server {
|
||||
private handleDeletedFile(info: ScriptInfo) {
|
||||
this.stopWatchingScriptInfo(info);
|
||||
|
||||
// TODO: handle isOpen = true case
|
||||
|
||||
if (!info.isScriptOpen()) {
|
||||
this.deleteScriptInfo(info);
|
||||
|
||||
@@ -808,7 +777,7 @@ namespace ts.server {
|
||||
// Reload is pending, do the reload
|
||||
if (project.pendingReload !== ConfigFileProgramReloadLevel.Full) {
|
||||
project.pendingReload = ConfigFileProgramReloadLevel.Partial;
|
||||
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
|
||||
this.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project);
|
||||
}
|
||||
},
|
||||
flags,
|
||||
@@ -1317,7 +1286,11 @@ namespace ts.server {
|
||||
|
||||
this.logger.info("Open files: ");
|
||||
this.openFiles.forEach((projectRootPath, path) => {
|
||||
this.logger.info(`\tFileName: ${this.getScriptInfoForPath(path as Path).fileName} ProjectRootPath: ${projectRootPath}`);
|
||||
const info = this.getScriptInfoForPath(path as Path);
|
||||
this.logger.info(`\tFileName: ${info.fileName} ProjectRootPath: ${projectRootPath}`);
|
||||
if (writeProjectFileNames) {
|
||||
this.logger.info(`\t\tProjects: ${info.containingProjects.map(p => p.getProjectName())}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.endGroup();
|
||||
@@ -1377,9 +1350,10 @@ namespace ts.server {
|
||||
return { projectOptions, configFileErrors: errors, configFileSpecs: parsedCommandLine.configFileSpecs };
|
||||
}
|
||||
|
||||
private exceededTotalSizeLimitForNonTsFiles<T>(name: string, options: CompilerOptions, fileNames: T[], propertyReader: FilePropertyReader<T>) {
|
||||
/** Get a filename if the language service exceeds the maximum allowed program size; otherwise returns undefined. */
|
||||
private getFilenameForExceededTotalSizeLimitForNonTsFiles<T>(name: string, options: CompilerOptions, fileNames: T[], propertyReader: FilePropertyReader<T>): string | undefined {
|
||||
if (options && options.disableSizeLimit || !this.host.getFileSize) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
let availableSpace = maxProgramSizeForNonTsFiles;
|
||||
@@ -1396,20 +1370,16 @@ namespace ts.server {
|
||||
|
||||
totalNonTsFileSize += this.host.getFileSize(fileName);
|
||||
|
||||
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles) {
|
||||
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles || totalNonTsFileSize > availableSpace) {
|
||||
this.logger.info(getExceedLimitMessage({ propertyReader, hasTypeScriptFileExtension, host: this.host }, totalNonTsFileSize));
|
||||
// Keep the size as zero since it's disabled
|
||||
return true;
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalNonTsFileSize > availableSpace) {
|
||||
this.logger.info(getExceedLimitMessage({ propertyReader, hasTypeScriptFileExtension, host: this.host }, totalNonTsFileSize));
|
||||
return true;
|
||||
}
|
||||
|
||||
this.projectToSizeMap.set(name, totalNonTsFileSize);
|
||||
return false;
|
||||
|
||||
return;
|
||||
|
||||
function getExceedLimitMessage(context: { propertyReader: FilePropertyReader<any>, hasTypeScriptFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) {
|
||||
const files = getTop5LargestFiles(context);
|
||||
@@ -1432,7 +1402,7 @@ namespace ts.server {
|
||||
this,
|
||||
this.documentRegistry,
|
||||
compilerOptions,
|
||||
/*languageServiceEnabled*/ !this.exceededTotalSizeLimitForNonTsFiles(projectFileName, compilerOptions, files, externalFilePropertyReader),
|
||||
/*lastFileExceededProgramSize*/ this.getFilenameForExceededTotalSizeLimitForNonTsFiles(projectFileName, compilerOptions, files, externalFilePropertyReader),
|
||||
options.compileOnSave === undefined ? true : options.compileOnSave);
|
||||
project.excludedFiles = excludedFiles;
|
||||
|
||||
@@ -1498,14 +1468,14 @@ namespace ts.server {
|
||||
const cachedDirectoryStructureHost = createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames);
|
||||
const { projectOptions, configFileErrors, configFileSpecs } = this.convertConfigFileContentToProjectOptions(configFileName, cachedDirectoryStructureHost);
|
||||
this.logger.info(`Opened configuration file ${configFileName}`);
|
||||
const languageServiceEnabled = !this.exceededTotalSizeLimitForNonTsFiles(configFileName, projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader);
|
||||
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(configFileName, projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader);
|
||||
const project = new ConfiguredProject(
|
||||
configFileName,
|
||||
this,
|
||||
this.documentRegistry,
|
||||
projectOptions.configHasFilesProperty,
|
||||
projectOptions.compilerOptions,
|
||||
languageServiceEnabled,
|
||||
lastFileExceededProgramSize,
|
||||
projectOptions.compileOnSave === undefined ? false : projectOptions.compileOnSave,
|
||||
cachedDirectoryStructureHost);
|
||||
|
||||
@@ -1518,7 +1488,7 @@ namespace ts.server {
|
||||
WatchType.ConfigFilePath,
|
||||
project
|
||||
);
|
||||
if (languageServiceEnabled) {
|
||||
if (!lastFileExceededProgramSize) {
|
||||
project.watchWildcards(projectOptions.wildcardDirectories);
|
||||
}
|
||||
|
||||
@@ -1631,8 +1601,9 @@ namespace ts.server {
|
||||
// Update the project
|
||||
project.configFileSpecs = configFileSpecs;
|
||||
project.setProjectErrors(configFileErrors);
|
||||
if (this.exceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader)) {
|
||||
project.disableLanguageService();
|
||||
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader);
|
||||
if (lastFileExceededProgramSize) {
|
||||
project.disableLanguageService(lastFileExceededProgramSize);
|
||||
project.stopWatchingWildCards();
|
||||
}
|
||||
else {
|
||||
@@ -1898,7 +1869,7 @@ namespace ts.server {
|
||||
|
||||
// Reload Projects
|
||||
this.reloadConfiguredProjectForFiles(this.openFiles, /*delayReload*/ false, returnTrue);
|
||||
this.refreshInferredProjects();
|
||||
this.ensureProjectForOpenFiles();
|
||||
}
|
||||
|
||||
private delayReloadConfiguredProjectForFiles(configFileExistenceInfo: ConfigFileExistenceInfo, ignoreIfNotRootOfInferredProject: boolean) {
|
||||
@@ -1910,7 +1881,7 @@ namespace ts.server {
|
||||
isRootOfInferredProject => isRootOfInferredProject : // Reload open files if they are root of inferred project
|
||||
returnTrue // Reload all the open files impacted by config file
|
||||
);
|
||||
this.delayInferredProjectsRefresh();
|
||||
this.delayEnsureProjectForOpenFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1994,8 +1965,8 @@ namespace ts.server {
|
||||
* This will go through open files and assign them to inferred project if open file is not part of any other project
|
||||
* After that all the inferred project graphs are updated
|
||||
*/
|
||||
private refreshInferredProjects() {
|
||||
this.logger.info("refreshInferredProjects: updating project structure from ...");
|
||||
private ensureProjectForOpenFiles() {
|
||||
this.logger.info("Structure before ensureProjectForOpenFiles:");
|
||||
this.printProjects();
|
||||
|
||||
this.openFiles.forEach((projectRootPath, path) => {
|
||||
@@ -2009,12 +1980,10 @@ namespace ts.server {
|
||||
this.removeRootOfInferredProjectIfNowPartOfOtherProject(info);
|
||||
}
|
||||
});
|
||||
this.pendingEnsureProjectForOpenFiles = false;
|
||||
this.inferredProjects.forEach(p => this.updateProjectIfDirty(p));
|
||||
|
||||
for (const p of this.inferredProjects) {
|
||||
p.updateGraph();
|
||||
}
|
||||
|
||||
this.logger.info("refreshInferredProjects: updated project structure ...");
|
||||
this.logger.info("Structure after ensureProjectForOpenFiles:");
|
||||
this.printProjects();
|
||||
}
|
||||
|
||||
@@ -2040,7 +2009,6 @@ namespace ts.server {
|
||||
|
||||
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
|
||||
let configFileName: NormalizedPath;
|
||||
let sendConfigFileDiagEvent = false;
|
||||
let configFileErrors: ReadonlyArray<Diagnostic>;
|
||||
|
||||
const info = this.getOrCreateScriptInfoOpenedByClientForNormalizedPath(fileName, projectRootPath ? this.getNormalizedAbsolutePath(projectRootPath) : this.currentDirectory, fileContent, scriptKind, hasMixedContent);
|
||||
@@ -2051,8 +2019,15 @@ namespace ts.server {
|
||||
project = this.findConfiguredProjectByProjectName(configFileName);
|
||||
if (!project) {
|
||||
project = this.createConfiguredProject(configFileName);
|
||||
// Send the event only if the project got created as part of this open request
|
||||
sendConfigFileDiagEvent = true;
|
||||
// Send the event only if the project got created as part of this open request and info is part of the project
|
||||
if (info.isOrphan()) {
|
||||
// Since the file isnt part of configured project, do not send config file info
|
||||
configFileName = undefined;
|
||||
}
|
||||
else {
|
||||
configFileErrors = project.getAllProjectErrors();
|
||||
this.sendConfigFileDiagEvent(project as ConfiguredProject, fileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Ensure project is ready to check if it contains opened script info
|
||||
@@ -2060,30 +2035,20 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (project && !project.languageServiceEnabled) {
|
||||
// if project language service is disabled then we create a program only for open files.
|
||||
// this means that project should be marked as dirty to force rebuilding of the program
|
||||
// on the next request
|
||||
project.markAsDirty();
|
||||
}
|
||||
|
||||
// Project we have at this point is going to be updated since its either found through
|
||||
// - external project search, which updates the project before checking if info is present in it
|
||||
// - configured project - either created or updated to ensure we know correct status of info
|
||||
|
||||
// At this point if file is part of any any configured or external project, then it would be present in the containing projects
|
||||
// So if it still doesnt have any containing projects, it needs to be part of inferred project
|
||||
if (info.isOrphan()) {
|
||||
// Since the file isnt part of configured project, do not send config file event
|
||||
configFileName = undefined;
|
||||
sendConfigFileDiagEvent = false;
|
||||
|
||||
this.assignOrphanScriptInfoToInferredProject(info, projectRootPath);
|
||||
}
|
||||
|
||||
Debug.assert(!info.isOrphan());
|
||||
this.openFiles.set(info.path, projectRootPath);
|
||||
|
||||
if (sendConfigFileDiagEvent) {
|
||||
configFileErrors = project.getAllProjectErrors();
|
||||
this.sendConfigFileDiagEvent(project as ConfiguredProject, fileName);
|
||||
}
|
||||
|
||||
// Remove the configured projects that have zero references from open files.
|
||||
// This was postponed from closeOpenFile to after opening next file,
|
||||
// so that we can reuse the project if we need to right away
|
||||
@@ -2155,11 +2120,6 @@ namespace ts.server {
|
||||
this.closeClientFile(file);
|
||||
}
|
||||
}
|
||||
// if files were open or closed then explicitly refresh list of inferred projects
|
||||
// otherwise if there were only changes in files - record changed files in `changedFiles` and defer the update
|
||||
if (openFiles || closedFiles) {
|
||||
this.ensureProjectStructuresUptoDate(/*refreshInferredProjects*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2169,49 +2129,33 @@ namespace ts.server {
|
||||
const change = changes[i];
|
||||
scriptInfo.editContent(change.span.start, change.span.start + change.span.length, change.newText);
|
||||
}
|
||||
if (!this.changedFiles) {
|
||||
this.changedFiles = [scriptInfo];
|
||||
}
|
||||
else if (!contains(this.changedFiles, scriptInfo)) {
|
||||
this.changedFiles.push(scriptInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private closeConfiguredProjectReferencedFromExternalProject(configFile: NormalizedPath): boolean {
|
||||
private closeConfiguredProjectReferencedFromExternalProject(configFile: NormalizedPath) {
|
||||
const configuredProject = this.findConfiguredProjectByProjectName(configFile);
|
||||
if (configuredProject) {
|
||||
configuredProject.deleteExternalProjectReference();
|
||||
if (!configuredProject.hasOpenRef()) {
|
||||
this.removeProject(configuredProject);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
closeExternalProject(uncheckedFileName: string, suppressRefresh = false): void {
|
||||
closeExternalProject(uncheckedFileName: string): void {
|
||||
const fileName = toNormalizedPath(uncheckedFileName);
|
||||
const configFiles = this.externalProjectToConfiguredProjectMap.get(fileName);
|
||||
if (configFiles) {
|
||||
let shouldRefreshInferredProjects = false;
|
||||
for (const configFile of configFiles) {
|
||||
if (this.closeConfiguredProjectReferencedFromExternalProject(configFile)) {
|
||||
shouldRefreshInferredProjects = true;
|
||||
}
|
||||
this.closeConfiguredProjectReferencedFromExternalProject(configFile);
|
||||
}
|
||||
this.externalProjectToConfiguredProjectMap.delete(fileName);
|
||||
if (shouldRefreshInferredProjects && !suppressRefresh) {
|
||||
this.ensureProjectStructuresUptoDate(/*refreshInferredProjects*/ true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// close external project
|
||||
const externalProject = this.findExternalProjectByProjectName(uncheckedFileName);
|
||||
if (externalProject) {
|
||||
this.removeProject(externalProject);
|
||||
if (!suppressRefresh) {
|
||||
this.ensureProjectStructuresUptoDate(/*refreshInferredProjects*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2224,17 +2168,15 @@ namespace ts.server {
|
||||
});
|
||||
|
||||
for (const externalProject of projects) {
|
||||
this.openExternalProject(externalProject, /*suppressRefreshOfInferredProjects*/ true);
|
||||
this.openExternalProject(externalProject);
|
||||
// delete project that is present in input list
|
||||
projectsToClose.delete(externalProject.projectFileName);
|
||||
}
|
||||
|
||||
// close projects that were missing in the input list
|
||||
forEachKey(projectsToClose, externalProjectName => {
|
||||
this.closeExternalProject(externalProjectName, /*suppressRefresh*/ true);
|
||||
this.closeExternalProject(externalProjectName);
|
||||
});
|
||||
|
||||
this.ensureProjectStructuresUptoDate(/*refreshInferredProjects*/ true);
|
||||
}
|
||||
|
||||
/** Makes a filename safe to insert in a RegExp */
|
||||
@@ -2355,7 +2297,7 @@ namespace ts.server {
|
||||
return excludedFiles;
|
||||
}
|
||||
|
||||
openExternalProject(proj: protocol.ExternalProject, suppressRefreshOfInferredProjects = false): void {
|
||||
openExternalProject(proj: protocol.ExternalProject): void {
|
||||
// typingOptions has been deprecated and is only supported for backward compatibility
|
||||
// purposes. It should be removed in future releases - use typeAcquisition instead.
|
||||
if (proj.typingOptions && !proj.typeAcquisition) {
|
||||
@@ -2396,8 +2338,9 @@ namespace ts.server {
|
||||
externalProject.excludedFiles = excludedFiles;
|
||||
if (!tsConfigFiles) {
|
||||
const compilerOptions = convertCompilerOptions(proj.options);
|
||||
if (this.exceededTotalSizeLimitForNonTsFiles(proj.projectFileName, compilerOptions, proj.rootFiles, externalFilePropertyReader)) {
|
||||
externalProject.disableLanguageService();
|
||||
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(proj.projectFileName, compilerOptions, proj.rootFiles, externalFilePropertyReader);
|
||||
if (lastFileExceededProgramSize) {
|
||||
externalProject.disableLanguageService(lastFileExceededProgramSize);
|
||||
}
|
||||
else {
|
||||
externalProject.enableLanguageService();
|
||||
@@ -2408,13 +2351,13 @@ namespace ts.server {
|
||||
}
|
||||
// some config files were added to external project (that previously were not there)
|
||||
// close existing project and later we'll open a set of configured projects for these files
|
||||
this.closeExternalProject(proj.projectFileName, /*suppressRefresh*/ true);
|
||||
this.closeExternalProject(proj.projectFileName);
|
||||
}
|
||||
else if (this.externalProjectToConfiguredProjectMap.get(proj.projectFileName)) {
|
||||
// this project used to include config files
|
||||
if (!tsConfigFiles) {
|
||||
// config files were removed from the project - close existing external project which in turn will close configured projects
|
||||
this.closeExternalProject(proj.projectFileName, /*suppressRefresh*/ true);
|
||||
this.closeExternalProject(proj.projectFileName);
|
||||
}
|
||||
else {
|
||||
// project previously had some config files - compare them with new set of files and close all configured projects that correspond to unused files
|
||||
@@ -2464,9 +2407,6 @@ namespace ts.server {
|
||||
this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName);
|
||||
this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition, excludedFiles);
|
||||
}
|
||||
if (!suppressRefreshOfInferredProjects) {
|
||||
this.ensureProjectStructuresUptoDate(/*refreshInferredProjects*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+33
-26
@@ -126,6 +126,8 @@ namespace ts.server {
|
||||
private cachedUnresolvedImportsPerFile = new UnresolvedImportsMap();
|
||||
private lastCachedUnresolvedImportsList: SortedReadonlyArray<string>;
|
||||
|
||||
private lastFileExceededProgramSize: string | undefined;
|
||||
|
||||
// wrapper over the real language service that will suppress all semantic operations
|
||||
protected languageService: LanguageService;
|
||||
|
||||
@@ -166,6 +168,9 @@ namespace ts.server {
|
||||
*/
|
||||
private projectStateVersion = 0;
|
||||
|
||||
/*@internal*/
|
||||
dirty = false;
|
||||
|
||||
/*@internal*/
|
||||
hasChangedAutomaticTypeDirectiveNames = false;
|
||||
|
||||
@@ -212,7 +217,7 @@ namespace ts.server {
|
||||
readonly projectService: ProjectService,
|
||||
private documentRegistry: DocumentRegistry,
|
||||
hasExplicitListOfFiles: boolean,
|
||||
languageServiceEnabled: boolean,
|
||||
lastFileExceededProgramSize: string | undefined,
|
||||
private compilerOptions: CompilerOptions,
|
||||
public compileOnSaveEnabled: boolean,
|
||||
directoryStructureHost: DirectoryStructureHost,
|
||||
@@ -244,10 +249,11 @@ namespace ts.server {
|
||||
// Use the current directory as resolution root only if the project created using current directory string
|
||||
this.resolutionCache = createResolutionCache(this, currentDirectory && this.currentDirectory, /*logChangesWhenResolvingModule*/ true);
|
||||
this.languageService = createLanguageService(this, this.documentRegistry);
|
||||
if (!languageServiceEnabled) {
|
||||
this.disableLanguageService();
|
||||
if (lastFileExceededProgramSize) {
|
||||
this.disableLanguageService(lastFileExceededProgramSize);
|
||||
}
|
||||
this.markAsDirty();
|
||||
this.projectService.pendingEnsureProjectForOpenFiles = true;
|
||||
}
|
||||
|
||||
isKnownTypesPackageName(name: string): boolean {
|
||||
@@ -397,7 +403,7 @@ namespace ts.server {
|
||||
|
||||
/*@internal*/
|
||||
onInvalidatedResolution() {
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@@ -415,7 +421,7 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
onChangedAutomaticTypeDirectiveNames() {
|
||||
this.hasChangedAutomaticTypeDirectiveNames = true;
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@@ -497,15 +503,17 @@ namespace ts.server {
|
||||
return;
|
||||
}
|
||||
this.languageServiceEnabled = true;
|
||||
this.lastFileExceededProgramSize = undefined;
|
||||
this.projectService.onUpdateLanguageServiceStateForProject(this, /*languageServiceEnabled*/ true);
|
||||
}
|
||||
|
||||
disableLanguageService() {
|
||||
disableLanguageService(lastFileExceededProgramSize?: string) {
|
||||
if (!this.languageServiceEnabled) {
|
||||
return;
|
||||
}
|
||||
this.languageService.cleanupSemanticCache();
|
||||
this.languageServiceEnabled = false;
|
||||
this.lastFileExceededProgramSize = lastFileExceededProgramSize;
|
||||
this.builderState = undefined;
|
||||
this.resolutionCache.closeTypeRootsWatch();
|
||||
this.projectService.onUpdateLanguageServiceStateForProject(this, /*languageServiceEnabled*/ false);
|
||||
@@ -561,6 +569,7 @@ namespace ts.server {
|
||||
for (const root of this.rootFiles) {
|
||||
root.detachFromProject(this);
|
||||
}
|
||||
this.projectService.pendingEnsureProjectForOpenFiles = true;
|
||||
|
||||
this.rootFiles = undefined;
|
||||
this.rootFilesMap = undefined;
|
||||
@@ -744,7 +753,10 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
markAsDirty() {
|
||||
this.projectStateVersion++;
|
||||
if (!this.dirty) {
|
||||
this.projectStateVersion++;
|
||||
this.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -819,7 +831,9 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
const cachedTypings = this.projectService.typingsCache.getTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasChanges);
|
||||
if (this.setTypings(cachedTypings)) {
|
||||
if (!arrayIsEqualTo(this.typingFiles, cachedTypings)) {
|
||||
this.typingFiles = cachedTypings;
|
||||
this.markAsDirty();
|
||||
hasChanges = this.updateGraphWorker() || hasChanges;
|
||||
}
|
||||
}
|
||||
@@ -843,15 +857,6 @@ namespace ts.server {
|
||||
return include.filter(i => existing.indexOf(i) < 0);
|
||||
}
|
||||
|
||||
private setTypings(typings: SortedReadonlyArray<string>): boolean {
|
||||
if (arrayIsEqualTo(this.typingFiles, typings)) {
|
||||
return false;
|
||||
}
|
||||
this.typingFiles = typings;
|
||||
this.markAsDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
private updateGraphWorker() {
|
||||
const oldProgram = this.program;
|
||||
Debug.assert(!this.isClosed(), "Called update graph worker of closed project");
|
||||
@@ -860,6 +865,7 @@ namespace ts.server {
|
||||
this.hasInvalidatedResolution = this.resolutionCache.createHasInvalidatedResolution();
|
||||
this.resolutionCache.startCachingPerDirectoryResolution();
|
||||
this.program = this.languageService.getProgram();
|
||||
this.dirty = false;
|
||||
this.resolutionCache.finishCachingPerDirectoryResolution();
|
||||
|
||||
// bump up the version if
|
||||
@@ -906,7 +912,7 @@ namespace ts.server {
|
||||
compareStringsCaseSensitive
|
||||
);
|
||||
const elapsed = timestamp() - start;
|
||||
this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} structureChanged: ${hasChanges} Elapsed: ${elapsed}ms`);
|
||||
this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasChanges} Elapsed: ${elapsed}ms`);
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
@@ -932,7 +938,7 @@ namespace ts.server {
|
||||
fileWatcher.close();
|
||||
|
||||
// When a missing file is created, we should update the graph.
|
||||
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
|
||||
this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this);
|
||||
}
|
||||
},
|
||||
WatchType.MissingFilePath,
|
||||
@@ -993,12 +999,13 @@ namespace ts.server {
|
||||
getChangesSinceVersion(lastKnownVersion?: number): ProjectFilesWithTSDiagnostics {
|
||||
this.updateGraph();
|
||||
|
||||
const info = {
|
||||
const info: protocol.ProjectVersionInfo = {
|
||||
projectName: this.getProjectName(),
|
||||
version: this.projectStructureVersion,
|
||||
isInferred: this.projectKind === ProjectKind.Inferred,
|
||||
options: this.getCompilationSettings(),
|
||||
languageServiceDisabled: !this.languageServiceEnabled
|
||||
languageServiceDisabled: !this.languageServiceEnabled,
|
||||
lastFileExceededProgramSize: this.lastFileExceededProgramSize
|
||||
};
|
||||
const updatedFileNames = this.updatedFileNames;
|
||||
this.updatedFileNames = undefined;
|
||||
@@ -1182,7 +1189,7 @@ namespace ts.server {
|
||||
projectService,
|
||||
documentRegistry,
|
||||
/*files*/ undefined,
|
||||
/*languageServiceEnabled*/ true,
|
||||
/*lastFileExceededProgramSize*/ undefined,
|
||||
compilerOptions,
|
||||
/*compileOnSaveEnabled*/ false,
|
||||
projectService.host,
|
||||
@@ -1261,7 +1268,7 @@ namespace ts.server {
|
||||
documentRegistry: DocumentRegistry,
|
||||
hasExplicitListOfFiles: boolean,
|
||||
compilerOptions: CompilerOptions,
|
||||
languageServiceEnabled: boolean,
|
||||
lastFileExceededProgramSize: string | undefined,
|
||||
public compileOnSaveEnabled: boolean,
|
||||
cachedDirectoryStructureHost: CachedDirectoryStructureHost) {
|
||||
super(configFileName,
|
||||
@@ -1269,7 +1276,7 @@ namespace ts.server {
|
||||
projectService,
|
||||
documentRegistry,
|
||||
hasExplicitListOfFiles,
|
||||
languageServiceEnabled,
|
||||
lastFileExceededProgramSize,
|
||||
compilerOptions,
|
||||
compileOnSaveEnabled,
|
||||
cachedDirectoryStructureHost,
|
||||
@@ -1456,7 +1463,7 @@ namespace ts.server {
|
||||
projectService: ProjectService,
|
||||
documentRegistry: DocumentRegistry,
|
||||
compilerOptions: CompilerOptions,
|
||||
languageServiceEnabled: boolean,
|
||||
lastFileExceededProgramSize: string | undefined,
|
||||
public compileOnSaveEnabled: boolean,
|
||||
projectFilePath?: string) {
|
||||
super(externalProjectName,
|
||||
@@ -1464,7 +1471,7 @@ namespace ts.server {
|
||||
projectService,
|
||||
documentRegistry,
|
||||
/*hasExplicitListOfFiles*/ true,
|
||||
languageServiceEnabled,
|
||||
lastFileExceededProgramSize,
|
||||
compilerOptions,
|
||||
compileOnSaveEnabled,
|
||||
projectService.host,
|
||||
|
||||
@@ -1104,11 +1104,14 @@ namespace ts.server.protocol {
|
||||
* Current set of compiler options for project
|
||||
*/
|
||||
options: ts.CompilerOptions;
|
||||
|
||||
/**
|
||||
* true if project language service is disabled
|
||||
*/
|
||||
languageServiceDisabled: boolean;
|
||||
/**
|
||||
* Filename of the last file analyzed before disabling the language service. undefined, if the language service is enabled.
|
||||
*/
|
||||
lastFileExceededProgramSize: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -253,7 +253,7 @@ namespace ts.server {
|
||||
private requestMap = createMap<QueuedOperation>(); // Maps operation ID to newest requestQueue entry with that ID
|
||||
/** We will lazily request the types registry on the first call to `isKnownTypesPackageName` and store it in `typesRegistryCache`. */
|
||||
private requestedRegistry: boolean;
|
||||
private typesRegistryCache: Map<void> | undefined;
|
||||
private typesRegistryCache: Map<MapLike<string>> | undefined;
|
||||
|
||||
// This number is essentially arbitrary. Processing more than one typings request
|
||||
// at a time makes sense, but having too many in the pipe results in a hang
|
||||
|
||||
@@ -1769,7 +1769,7 @@ namespace ts.server {
|
||||
return this.requiredResponse(response);
|
||||
},
|
||||
[CommandNames.OpenExternalProject]: (request: protocol.OpenExternalProjectRequest) => {
|
||||
this.projectService.openExternalProject(request.arguments, /*suppressRefreshOfInferredProjects*/ false);
|
||||
this.projectService.openExternalProject(request.arguments);
|
||||
// TODO: GH#20447 report errors
|
||||
return this.requiredResponse(/*response*/ true);
|
||||
},
|
||||
|
||||
+1
-5
@@ -22,10 +22,6 @@ declare namespace ts.server {
|
||||
require?(initialPath: string, moduleName: string): RequireResult;
|
||||
}
|
||||
|
||||
export interface SortedArray<T> extends Array<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
@@ -79,7 +75,7 @@ declare namespace ts.server {
|
||||
/* @internal */
|
||||
export interface TypesRegistryResponse extends TypingInstallerResponse {
|
||||
readonly kind: EventTypesRegistry;
|
||||
readonly typesRegistry: MapLike<void>;
|
||||
readonly typesRegistry: MapLike<MapLike<string>>;
|
||||
}
|
||||
|
||||
export interface PackageInstalledResponse extends ProjectResponse {
|
||||
|
||||
@@ -41,15 +41,15 @@ namespace ts.server.typingsInstaller {
|
||||
}
|
||||
|
||||
interface TypesRegistryFile {
|
||||
entries: MapLike<void>;
|
||||
entries: MapLike<MapLike<string>>;
|
||||
}
|
||||
|
||||
function loadTypesRegistryFile(typesRegistryFilePath: string, host: InstallTypingHost, log: Log): Map<void> {
|
||||
function loadTypesRegistryFile(typesRegistryFilePath: string, host: InstallTypingHost, log: Log): Map<MapLike<string>> {
|
||||
if (!host.fileExists(typesRegistryFilePath)) {
|
||||
if (log.isEnabled()) {
|
||||
log.writeLine(`Types registry file '${typesRegistryFilePath}' does not exist`);
|
||||
}
|
||||
return createMap<void>();
|
||||
return createMap<MapLike<string>>();
|
||||
}
|
||||
try {
|
||||
const content = <TypesRegistryFile>JSON.parse(host.readFile(typesRegistryFilePath));
|
||||
@@ -59,7 +59,7 @@ namespace ts.server.typingsInstaller {
|
||||
if (log.isEnabled()) {
|
||||
log.writeLine(`Error when loading types registry file '${typesRegistryFilePath}': ${(<Error>e).message}, ${(<Error>e).stack}`);
|
||||
}
|
||||
return createMap<void>();
|
||||
return createMap<MapLike<string>>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace ts.server.typingsInstaller {
|
||||
export class NodeTypingsInstaller extends TypingsInstaller {
|
||||
private readonly nodeExecSync: ExecSync;
|
||||
private readonly npmPath: string;
|
||||
readonly typesRegistry: Map<void>;
|
||||
readonly typesRegistry: Map<MapLike<string>>;
|
||||
|
||||
private delayedInitializationError: InitializationFailedResponse | undefined;
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace ts.server.typingsInstaller {
|
||||
this.closeProject(req);
|
||||
break;
|
||||
case "typesRegistry": {
|
||||
const typesRegistry: { [key: string]: void } = {};
|
||||
const typesRegistry: { [key: string]: MapLike<string> } = {};
|
||||
this.typesRegistry.forEach((value, key) => {
|
||||
typesRegistry[key] = value;
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// <reference path="../../compiler/core.ts" />
|
||||
/// <reference path="../../compiler/moduleNameResolver.ts" />
|
||||
/// <reference path="../../services/jsTyping.ts"/>
|
||||
/// <reference path="../../services/semver.ts"/>
|
||||
/// <reference path="../types.ts"/>
|
||||
/// <reference path="../shared.ts"/>
|
||||
|
||||
@@ -9,6 +10,10 @@ namespace ts.server.typingsInstaller {
|
||||
devDependencies: MapLike<any>;
|
||||
}
|
||||
|
||||
interface NpmLock {
|
||||
dependencies: { [packageName: string]: { version: string } };
|
||||
}
|
||||
|
||||
export interface Log {
|
||||
isEnabled(): boolean;
|
||||
writeLine(text: string): void;
|
||||
@@ -42,7 +47,7 @@ namespace ts.server.typingsInstaller {
|
||||
}
|
||||
|
||||
export abstract class TypingsInstaller {
|
||||
private readonly packageNameToTypingLocation: Map<string> = createMap<string>();
|
||||
private readonly packageNameToTypingLocation: Map<JsTyping.CachedTyping> = createMap<JsTyping.CachedTyping>();
|
||||
private readonly missingTypingsSet: Map<true> = createMap<true>();
|
||||
private readonly knownCachesSet: Map<true> = createMap<true>();
|
||||
private readonly projectWatchers: Map<FileWatcher[]> = createMap<FileWatcher[]>();
|
||||
@@ -52,7 +57,7 @@ namespace ts.server.typingsInstaller {
|
||||
private installRunCount = 1;
|
||||
private inFlightRequestCount = 0;
|
||||
|
||||
abstract readonly typesRegistry: Map<void>;
|
||||
abstract readonly typesRegistry: Map<MapLike<string>>;
|
||||
|
||||
constructor(
|
||||
protected readonly installTypingHost: InstallTypingHost,
|
||||
@@ -117,7 +122,8 @@ namespace ts.server.typingsInstaller {
|
||||
this.safeList,
|
||||
this.packageNameToTypingLocation,
|
||||
req.typeAcquisition,
|
||||
req.unresolvedImports);
|
||||
req.unresolvedImports,
|
||||
this.typesRegistry);
|
||||
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Finished typings discovery: ${JSON.stringify(discoverTypingsResult)}`);
|
||||
@@ -156,23 +162,30 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Processing cache location '${cacheLocation}'`);
|
||||
}
|
||||
if (this.knownCachesSet.get(cacheLocation)) {
|
||||
if (this.knownCachesSet.has(cacheLocation)) {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Cache location was already processed...`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const packageJson = combinePaths(cacheLocation, "package.json");
|
||||
const packageLockJson = combinePaths(cacheLocation, "package-lock.json");
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Trying to find '${packageJson}'...`);
|
||||
}
|
||||
if (this.installTypingHost.fileExists(packageJson)) {
|
||||
if (this.installTypingHost.fileExists(packageJson) && this.installTypingHost.fileExists(packageLockJson)) {
|
||||
const npmConfig = <NpmConfig>JSON.parse(this.installTypingHost.readFile(packageJson));
|
||||
const npmLock = <NpmLock>JSON.parse(this.installTypingHost.readFile(packageLockJson));
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Loaded content of '${packageJson}': ${JSON.stringify(npmConfig)}`);
|
||||
this.log.writeLine(`Loaded content of '${packageLockJson}'`);
|
||||
}
|
||||
if (npmConfig.devDependencies) {
|
||||
if (npmConfig.devDependencies && npmLock.dependencies) {
|
||||
for (const key in npmConfig.devDependencies) {
|
||||
if (!hasProperty(npmLock.dependencies, key)) {
|
||||
// if package in package.json but not package-lock.json, skip adding to cache so it is reinstalled on next use
|
||||
continue;
|
||||
}
|
||||
// key is @types/<package name>
|
||||
const packageName = getBaseFileName(key);
|
||||
if (!packageName) {
|
||||
@@ -184,10 +197,11 @@ namespace ts.server.typingsInstaller {
|
||||
continue;
|
||||
}
|
||||
const existingTypingFile = this.packageNameToTypingLocation.get(packageName);
|
||||
if (existingTypingFile === typingFile) {
|
||||
continue;
|
||||
}
|
||||
if (existingTypingFile) {
|
||||
if (existingTypingFile.typingLocation === typingFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`New typing for package ${packageName} from '${typingFile}' conflicts with existing typing file '${existingTypingFile}'`);
|
||||
}
|
||||
@@ -195,7 +209,11 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Adding entry into typings cache: '${packageName}' => '${typingFile}'`);
|
||||
}
|
||||
this.packageNameToTypingLocation.set(packageName, typingFile);
|
||||
const info = getProperty(npmLock.dependencies, key);
|
||||
const version = info && info.version;
|
||||
const semver = Semver.parse(version);
|
||||
const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: semver };
|
||||
this.packageNameToTypingLocation.set(packageName, newTyping);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,10 +229,6 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) this.log.writeLine(`'${typing}' is in missingTypingsSet - skipping...`);
|
||||
return false;
|
||||
}
|
||||
if (this.packageNameToTypingLocation.get(typing)) {
|
||||
if (this.log.isEnabled()) this.log.writeLine(`'${typing}' already has a typing - skipping...`);
|
||||
return false;
|
||||
}
|
||||
const validationResult = JsTyping.validatePackageName(typing);
|
||||
if (validationResult !== JsTyping.PackageNameValidationResult.Ok) {
|
||||
// add typing name to missing set so we won't process it again
|
||||
@@ -226,6 +240,10 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) this.log.writeLine(`Entry for package '${typing}' does not exist in local types registry - skipping...`);
|
||||
return false;
|
||||
}
|
||||
if (this.packageNameToTypingLocation.get(typing) && JsTyping.isTypingUpToDate(this.packageNameToTypingLocation.get(typing), this.typesRegistry.get(typing))) {
|
||||
if (this.log.isEnabled()) this.log.writeLine(`'${typing}' already has an up-to-date typing - skipping...`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -294,9 +312,12 @@ namespace ts.server.typingsInstaller {
|
||||
this.missingTypingsSet.set(packageName, true);
|
||||
continue;
|
||||
}
|
||||
if (!this.packageNameToTypingLocation.has(packageName)) {
|
||||
this.packageNameToTypingLocation.set(packageName, typingFile);
|
||||
}
|
||||
|
||||
// packageName is guaranteed to exist in typesRegistry by filterTypings
|
||||
const distTags = this.typesRegistry.get(packageName);
|
||||
const newVersion = Semver.parse(distTags[`ts${ts.versionMajorMinor}`] || distTags[latestDistTag]);
|
||||
const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: newVersion };
|
||||
this.packageNameToTypingLocation.set(packageName, newTyping);
|
||||
installedTypingFiles.push(typingFile);
|
||||
}
|
||||
if (this.log.isEnabled()) {
|
||||
@@ -390,4 +411,6 @@ namespace ts.server.typingsInstaller {
|
||||
export function typingsName(packageName: string): string {
|
||||
return `@types/${packageName}@ts${versionMajorMinor}`;
|
||||
}
|
||||
|
||||
const latestDistTag = "latest";
|
||||
}
|
||||
@@ -232,18 +232,6 @@ namespace ts.server {
|
||||
return base === "tsconfig.json" || base === "jsconfig.json" ? base : undefined;
|
||||
}
|
||||
|
||||
export function insertSorted<T>(array: SortedArray<T>, insert: T, compare: Comparer<T>): void {
|
||||
if (array.length === 0) {
|
||||
array.push(insert);
|
||||
return;
|
||||
}
|
||||
|
||||
const insertIndex = binarySearch(array, insert, identity, compare);
|
||||
if (insertIndex < 0) {
|
||||
array.splice(~insertIndex, 0, insert);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeSorted<T>(array: SortedArray<T>, remove: T, compare: Comparer<T>): void {
|
||||
if (!array || array.length === 0) {
|
||||
return;
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace ts.codefix {
|
||||
else {
|
||||
const leftExpressionType = checker.getTypeAtLocation(parent.expression);
|
||||
const { symbol } = leftExpressionType;
|
||||
if (!(leftExpressionType.flags & TypeFlags.Object && symbol.flags & SymbolFlags.Class)) {
|
||||
if (!(symbol && leftExpressionType.flags & TypeFlags.Object && symbol.flags & SymbolFlags.Class)) {
|
||||
return undefined;
|
||||
}
|
||||
const classDeclaration = cast(first(symbol.declarations), isClassLike);
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ts.codefix {
|
||||
|
||||
function getNodes(sourceFile: SourceFile, pos: number): { readonly constructor: ConstructorDeclaration, readonly superCall: ExpressionStatement } {
|
||||
const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
|
||||
Debug.assert(token.kind === SyntaxKind.ThisKeyword);
|
||||
if (token.kind !== SyntaxKind.ThisKeyword) return undefined;
|
||||
const constructor = getContainingFunction(token) as ConstructorDeclaration;
|
||||
const superCall = findSuperCall(constructor.body);
|
||||
// figure out if the `this` access is actually inside the supercall
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
function doChanges(changes: textChanges.ChangeTracker, sourceFile: SourceFile, extendsToken: Node, heritageClauses: ReadonlyArray<HeritageClause>): void {
|
||||
changes.replaceRange(sourceFile, { pos: extendsToken.getStart(), end: extendsToken.end }, createToken(SyntaxKind.ImplementsKeyword));
|
||||
changes.replaceNode(sourceFile, extendsToken, createToken(SyntaxKind.ImplementsKeyword), textChanges.useNonAdjustedPositions);
|
||||
|
||||
// If there is already an implements clause, replace the implements keyword with a comma.
|
||||
if (heritageClauses.length === 2 &&
|
||||
|
||||
@@ -7,6 +7,9 @@ namespace ts.codefix {
|
||||
getCodeActions(context) {
|
||||
const { sourceFile } = context;
|
||||
const token = getNode(sourceFile, context.span.start);
|
||||
if (!token) {
|
||||
return undefined;
|
||||
}
|
||||
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, token));
|
||||
return [{ description: getLocaleSpecificMessage(Diagnostics.Add_this_to_unresolved_variable), changes, fixId }];
|
||||
},
|
||||
@@ -16,13 +19,17 @@ namespace ts.codefix {
|
||||
}),
|
||||
});
|
||||
|
||||
function getNode(sourceFile: SourceFile, pos: number): Identifier {
|
||||
return cast(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false), isIdentifier);
|
||||
function getNode(sourceFile: SourceFile, pos: number): Identifier | undefined {
|
||||
const node = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
|
||||
return isIdentifier(node) ? node : undefined;
|
||||
}
|
||||
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Identifier): void {
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Identifier | undefined): void {
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
// TODO (https://github.com/Microsoft/TypeScript/issues/21246): use shared helper
|
||||
suppressLeadingAndTrailingTrivia(token);
|
||||
changes.replaceRange(sourceFile, { pos: token.getStart(), end: token.end }, createPropertyAccess(createThis(), token));
|
||||
changes.replaceNode(sourceFile, token, createPropertyAccess(createThis(), token), textChanges.useNonAdjustedPositions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace ts.codefix {
|
||||
// and trailing trivia will remain.
|
||||
suppressLeadingAndTrailingTrivia(newFunction);
|
||||
|
||||
changes.replaceRange(sourceFile, { pos: oldFunction.getStart(), end: oldFunction.end }, newFunction);
|
||||
changes.replaceNode(sourceFile, oldFunction, newFunction, textChanges.useNonAdjustedPositions);
|
||||
}
|
||||
else {
|
||||
changes.deleteNodeInList(sourceFile, parent);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
interface ImportCodeFixContext extends SymbolContext {
|
||||
symbolToken: Identifier | undefined;
|
||||
symbolToken: Node;
|
||||
program: Program;
|
||||
checker: TypeChecker;
|
||||
compilerOptions: CompilerOptions;
|
||||
@@ -38,12 +38,11 @@ namespace ts.codefix {
|
||||
return { description, changes, fixId: undefined };
|
||||
}
|
||||
|
||||
function convertToImportCodeFixContext(context: CodeFixContext): ImportCodeFixContext {
|
||||
function convertToImportCodeFixContext(context: CodeFixContext, symbolToken: Node, symbolName: string): ImportCodeFixContext {
|
||||
const useCaseSensitiveFileNames = context.host.useCaseSensitiveFileNames ? context.host.useCaseSensitiveFileNames() : false;
|
||||
const { program } = context;
|
||||
const checker = program.getTypeChecker();
|
||||
// This will always be an Identifier, since the diagnostics we fix only fail on identifiers.
|
||||
const symbolToken = cast(getTokenAtPosition(context.sourceFile, context.span.start, /*includeJsDocComment*/ false), isIdentifier);
|
||||
|
||||
return {
|
||||
host: context.host,
|
||||
formatContext: context.formatContext,
|
||||
@@ -53,8 +52,8 @@ namespace ts.codefix {
|
||||
compilerOptions: program.getCompilerOptions(),
|
||||
cachedImportDeclarations: [],
|
||||
getCanonicalFileName: createGetCanonicalFileName(useCaseSensitiveFileNames),
|
||||
symbolName: symbolToken.getText(),
|
||||
symbolToken,
|
||||
symbolName,
|
||||
symbolToken
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,7 +94,7 @@ namespace ts.codefix {
|
||||
allSourceFiles: ReadonlyArray<ts.SourceFile>,
|
||||
formatContext: ts.formatting.FormatContext,
|
||||
getCanonicalFileName: GetCanonicalFileName,
|
||||
symbolToken: Identifier | undefined,
|
||||
symbolToken: Node | undefined,
|
||||
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
|
||||
const exportInfos = getAllReExportingModules(exportedSymbol, checker, allSourceFiles);
|
||||
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
|
||||
@@ -132,12 +131,12 @@ namespace ts.codefix {
|
||||
// 1. change "member3" to "ns.member3"
|
||||
// 2. add "member3" to the second import statement's import list
|
||||
// and it is up to the user to decide which one fits best.
|
||||
const useExistingImportActions = !context.symbolToken ? emptyArray : mapDefined(existingImports, ({ declaration }) => {
|
||||
const useExistingImportActions = !context.symbolToken || !isIdentifier(context.symbolToken) ? emptyArray : mapDefined(existingImports, ({ declaration }) => {
|
||||
const namespace = getNamespaceImportName(declaration);
|
||||
if (namespace) {
|
||||
const moduleSymbol = context.checker.getAliasedSymbol(context.checker.getSymbolAtLocation(namespace));
|
||||
if (moduleSymbol && moduleSymbol.exports.has(escapeLeadingUnderscores(context.symbolName))) {
|
||||
return getCodeActionForUseExistingNamespaceImport(namespace.text, context, context.symbolToken);
|
||||
return getCodeActionForUseExistingNamespaceImport(namespace.text, context, context.symbolToken as Identifier);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -638,37 +637,48 @@ namespace ts.codefix {
|
||||
* become "ns.foo"
|
||||
*/
|
||||
const changes = ChangeTracker.with(context, tracker =>
|
||||
tracker.changeIdentifierToPropertyAccess(sourceFile, namespacePrefix, symbolToken));
|
||||
tracker.replaceNode(sourceFile, symbolToken, createPropertyAccess(createIdentifier(namespacePrefix), symbolToken)));
|
||||
return createCodeAction(Diagnostics.Change_0_to_1, [symbolName, `${namespacePrefix}.${symbolName}`], changes);
|
||||
}
|
||||
|
||||
function getImportCodeActions(context: CodeFixContext): CodeAction[] {
|
||||
const importFixContext = convertToImportCodeFixContext(context);
|
||||
return context.errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code
|
||||
? getActionsForUMDImport(importFixContext)
|
||||
: getActionsForNonUMDImport(importFixContext, context.program.getSourceFiles(), context.cancellationToken);
|
||||
? getActionsForUMDImport(context)
|
||||
: getActionsForNonUMDImport(context);
|
||||
}
|
||||
|
||||
function getActionsForUMDImport(context: ImportCodeFixContext): CodeAction[] {
|
||||
const { checker, symbolToken, compilerOptions } = context;
|
||||
const umdSymbol = checker.getSymbolAtLocation(symbolToken);
|
||||
let symbol: ts.Symbol;
|
||||
let symbolName: string;
|
||||
if (umdSymbol.flags & ts.SymbolFlags.Alias) {
|
||||
symbol = checker.getAliasedSymbol(umdSymbol);
|
||||
symbolName = context.symbolName;
|
||||
function getActionsForUMDImport(context: CodeFixContext): CodeAction[] {
|
||||
const token = getTokenAtPosition(context.sourceFile, context.span.start, /*includeJsDocComment*/ false);
|
||||
const checker = context.program.getTypeChecker();
|
||||
|
||||
let umdSymbol: Symbol | undefined;
|
||||
|
||||
if (isIdentifier(token)) {
|
||||
// try the identifier to see if it is the umd symbol
|
||||
umdSymbol = checker.getSymbolAtLocation(token);
|
||||
}
|
||||
else if (isJsxOpeningLikeElement(symbolToken.parent) && symbolToken.parent.tagName === symbolToken) {
|
||||
|
||||
if (!isUMDExportSymbol(umdSymbol)) {
|
||||
// The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`.
|
||||
symbol = checker.getAliasedSymbol(checker.resolveName(checker.getJsxNamespace(), symbolToken.parent.tagName, SymbolFlags.Value, /*excludeGlobals*/ false));
|
||||
symbolName = symbol.name;
|
||||
}
|
||||
else {
|
||||
throw Debug.fail("Either the symbol or the JSX namespace should be a UMD global if we got here");
|
||||
const parent = token.parent;
|
||||
const isNodeOpeningLikeElement = isJsxOpeningLikeElement(parent);
|
||||
if ((isJsxOpeningLikeElement && (<JsxOpeningLikeElement>parent).tagName === token) || parent.kind === SyntaxKind.JsxOpeningFragment) {
|
||||
umdSymbol = checker.resolveName(checker.getJsxNamespace(),
|
||||
isNodeOpeningLikeElement ? (<JsxOpeningLikeElement>parent).tagName : parent, SymbolFlags.Value, /*excludeGlobals*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
return getCodeActionsForImport([{ moduleSymbol: symbol, importKind: getUmdImportKind(compilerOptions) }], { ...context, symbolName });
|
||||
if (isUMDExportSymbol(umdSymbol)) {
|
||||
const symbol = checker.getAliasedSymbol(umdSymbol);
|
||||
if (symbol) {
|
||||
return getCodeActionsForImport([{ moduleSymbol: symbol, importKind: getUmdImportKind(context.program.getCompilerOptions()) }],
|
||||
convertToImportCodeFixContext(context, token, umdSymbol.name));
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getUmdImportKind(compilerOptions: CompilerOptions) {
|
||||
// Import a synthetic `default` if enabled.
|
||||
if (getAllowSyntheticDefaultImports(compilerOptions)) {
|
||||
@@ -693,8 +703,19 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function getActionsForNonUMDImport(context: ImportCodeFixContext, allSourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): CodeAction[] {
|
||||
const { sourceFile, checker, symbolName, symbolToken } = context;
|
||||
function getActionsForNonUMDImport(context: CodeFixContext): CodeAction[] {
|
||||
// This will always be an Identifier, since the diagnostics we fix only fail on identifiers.
|
||||
const { sourceFile, span, program, cancellationToken } = context;
|
||||
const checker = program.getTypeChecker();
|
||||
const symbolToken = getTokenAtPosition(sourceFile, span.start, /*includeJsDocComment*/ false);
|
||||
const isJsxNamespace = isJsxOpeningLikeElement(symbolToken.parent) && symbolToken.parent.tagName === symbolToken;
|
||||
if (!isJsxNamespace && !isIdentifier(symbolToken)) {
|
||||
return undefined;
|
||||
}
|
||||
const symbolName = isJsxNamespace ? checker.getJsxNamespace() : (<Identifier>symbolToken).text;
|
||||
const allSourceFiles = program.getSourceFiles();
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
|
||||
// "default" is a keyword and not a legal identifier for the import, so we don't expect it here
|
||||
Debug.assert(symbolName !== "default");
|
||||
const currentTokenMeaning = getMeaningFromLocation(symbolToken);
|
||||
@@ -715,7 +736,7 @@ namespace ts.codefix {
|
||||
if ((
|
||||
localSymbol && localSymbol.escapedName === symbolName ||
|
||||
getEscapedNameForExportDefault(defaultExport) === symbolName ||
|
||||
moduleSymbolToValidIdentifier(moduleSymbol, context.compilerOptions.target) === symbolName
|
||||
moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target) === symbolName
|
||||
) && checkSymbolHasMeaning(localSymbol || defaultExport, currentTokenMeaning)) {
|
||||
addSymbol(moduleSymbol, localSymbol || defaultExport, ImportKind.Default);
|
||||
}
|
||||
@@ -744,7 +765,7 @@ namespace ts.codefix {
|
||||
}
|
||||
});
|
||||
|
||||
return arrayFrom(flatMapIterator(originalSymbolToExportInfos.values(), exportInfos => getCodeActionsForImport(exportInfos, context)));
|
||||
return arrayFrom(flatMapIterator(originalSymbolToExportInfos.values(), exportInfos => getCodeActionsForImport(exportInfos, convertToImportCodeFixContext(context, symbolToken, symbolName))));
|
||||
}
|
||||
|
||||
function checkSymbolHasMeaning({ declarations }: Symbol, meaning: SemanticMeaning): boolean {
|
||||
|
||||
@@ -74,11 +74,11 @@ namespace ts.codefix {
|
||||
// Variable and Property declarations
|
||||
case Diagnostics.Member_0_implicitly_has_an_1_type.code:
|
||||
case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code:
|
||||
return getCodeActionForVariableDeclaration(<PropertyDeclaration | PropertySignature | VariableDeclaration>token.parent, sourceFile, program, cancellationToken);
|
||||
return getCodeActionForVariableDeclaration(<PropertyDeclaration | PropertySignature | VariableDeclaration>token.parent, program, cancellationToken);
|
||||
|
||||
case Diagnostics.Variable_0_implicitly_has_an_1_type.code: {
|
||||
const symbol = program.getTypeChecker().getSymbolAtLocation(token);
|
||||
return symbol && symbol.valueDeclaration && getCodeActionForVariableDeclaration(<VariableDeclaration>symbol.valueDeclaration, sourceFile, program, cancellationToken);
|
||||
return symbol && symbol.valueDeclaration && getCodeActionForVariableDeclaration(<VariableDeclaration>symbol.valueDeclaration, program, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,17 +86,17 @@ namespace ts.codefix {
|
||||
if (containingFunction === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
switch (errorCode) {
|
||||
|
||||
switch (errorCode) {
|
||||
// Parameter declarations
|
||||
case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
|
||||
if (isSetAccessor(containingFunction)) {
|
||||
return getCodeActionForSetAccessor(containingFunction, sourceFile, program, cancellationToken);
|
||||
return getCodeActionForSetAccessor(containingFunction, program, cancellationToken);
|
||||
}
|
||||
// falls through
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
||||
return !seenFunctions || addToSeen(seenFunctions, getNodeId(containingFunction))
|
||||
? getCodeActionForParameters(<ParameterDeclaration>token.parent, containingFunction, sourceFile, program, cancellationToken)
|
||||
? getCodeActionForParameters(cast(token.parent, isParameter), containingFunction, sourceFile, program, cancellationToken)
|
||||
: undefined;
|
||||
|
||||
// Get Accessor declarations
|
||||
@@ -106,7 +106,7 @@ namespace ts.codefix {
|
||||
|
||||
// Set Accessor declarations
|
||||
case Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code:
|
||||
return isSetAccessor(containingFunction) ? getCodeActionForSetAccessor(containingFunction, sourceFile, program, cancellationToken) : undefined;
|
||||
return isSetAccessor(containingFunction) ? getCodeActionForSetAccessor(containingFunction, program, cancellationToken) : undefined;
|
||||
|
||||
default:
|
||||
throw Debug.fail(String(errorCode));
|
||||
@@ -127,9 +127,9 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function getCodeActionForVariableDeclaration(declaration: VariableDeclaration | PropertyDeclaration | PropertySignature, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): Fix | undefined {
|
||||
function getCodeActionForVariableDeclaration(declaration: VariableDeclaration | PropertyDeclaration | PropertySignature, program: Program, cancellationToken: CancellationToken): Fix | undefined {
|
||||
if (!isIdentifier(declaration.name)) return undefined;
|
||||
const type = inferTypeForVariableFromUsage(declaration.name, sourceFile, program, cancellationToken);
|
||||
const type = inferTypeForVariableFromUsage(declaration.name, program, cancellationToken);
|
||||
return makeFix(declaration, declaration.name.getEnd(), type, program);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
const types = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
|
||||
containingFunction.parameters.map(p => isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, sourceFile, program, cancellationToken) : undefined);
|
||||
containingFunction.parameters.map(p => isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : undefined);
|
||||
if (!types) return undefined;
|
||||
|
||||
// We didn't actually find a set of type inference positions matching each parameter position
|
||||
@@ -164,14 +164,14 @@ namespace ts.codefix {
|
||||
return textChanges.length ? { declaration: parameterDeclaration, textChanges } : undefined;
|
||||
}
|
||||
|
||||
function getCodeActionForSetAccessor(setAccessorDeclaration: SetAccessorDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): Fix | undefined {
|
||||
function getCodeActionForSetAccessor(setAccessorDeclaration: SetAccessorDeclaration, program: Program, cancellationToken: CancellationToken): Fix | undefined {
|
||||
const setAccessorParameter = setAccessorDeclaration.parameters[0];
|
||||
if (!setAccessorParameter || !isIdentifier(setAccessorDeclaration.name) || !isIdentifier(setAccessorParameter.name)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, sourceFile, program, cancellationToken) ||
|
||||
inferTypeForVariableFromUsage(setAccessorParameter.name, sourceFile, program, cancellationToken);
|
||||
const type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, program, cancellationToken) ||
|
||||
inferTypeForVariableFromUsage(setAccessorParameter.name, program, cancellationToken);
|
||||
return makeFix(setAccessorParameter, setAccessorParameter.name.getEnd(), type, program);
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace ts.codefix {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const type = inferTypeForVariableFromUsage(getAccessorDeclaration.name, sourceFile, program, cancellationToken);
|
||||
const type = inferTypeForVariableFromUsage(getAccessorDeclaration.name, program, cancellationToken);
|
||||
const closeParenToken = findChildOfKind(getAccessorDeclaration, SyntaxKind.CloseParenToken, sourceFile);
|
||||
return makeFix(getAccessorDeclaration, closeParenToken.getEnd(), type, program);
|
||||
}
|
||||
@@ -194,23 +194,14 @@ namespace ts.codefix {
|
||||
return typeString === undefined ? undefined : createTextChangeFromStartLength(start, 0, `: ${typeString}`);
|
||||
}
|
||||
|
||||
function getReferences(token: PropertyName | Token<SyntaxKind.ConstructorKeyword>, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): Identifier[] {
|
||||
const references = FindAllReferences.findReferencedSymbols(
|
||||
program,
|
||||
cancellationToken,
|
||||
program.getSourceFiles(),
|
||||
sourceFile,
|
||||
token.getStart(sourceFile));
|
||||
|
||||
if (!references || references.length !== 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return references[0].references.map(r => <Identifier>getTokenAtPosition(program.getSourceFile(r.fileName), r.textSpan.start, /*includeJsDocComment*/ false));
|
||||
function getReferences(token: PropertyName | Token<SyntaxKind.ConstructorKeyword>, program: Program, cancellationToken: CancellationToken): ReadonlyArray<Identifier> {
|
||||
// Position shouldn't matter since token is not a SourceFile.
|
||||
return mapDefined(FindAllReferences.getReferenceEntriesForNode(-1, token, program, program.getSourceFiles(), cancellationToken), entry =>
|
||||
entry.type === "node" ? tryCast(entry.node, isIdentifier) : undefined);
|
||||
}
|
||||
|
||||
function inferTypeForVariableFromUsage(token: Identifier, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): Type | undefined {
|
||||
return InferFromReference.inferTypeFromReferences(getReferences(token, sourceFile, program, cancellationToken), program.getTypeChecker(), cancellationToken);
|
||||
function inferTypeForVariableFromUsage(token: Identifier, program: Program, cancellationToken: CancellationToken): Type | undefined {
|
||||
return InferFromReference.inferTypeFromReferences(getReferences(token, program, cancellationToken), program.getTypeChecker(), cancellationToken);
|
||||
}
|
||||
|
||||
function inferTypeForParametersFromUsage(containingFunction: FunctionLikeDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): (Type | undefined)[] | undefined {
|
||||
@@ -224,7 +215,7 @@ namespace ts.codefix {
|
||||
findChildOfKind<Token<SyntaxKind.ConstructorKeyword>>(containingFunction, SyntaxKind.ConstructorKeyword, sourceFile) :
|
||||
containingFunction.name;
|
||||
if (searchToken) {
|
||||
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, sourceFile, program, cancellationToken), containingFunction, program.getTypeChecker(), cancellationToken);
|
||||
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program.getTypeChecker(), cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +283,7 @@ namespace ts.codefix {
|
||||
stringIndexContext?: UsageContext;
|
||||
}
|
||||
|
||||
export function inferTypeFromReferences(references: Identifier[], checker: TypeChecker, cancellationToken: CancellationToken): Type | undefined {
|
||||
export function inferTypeFromReferences(references: ReadonlyArray<Identifier>, checker: TypeChecker, cancellationToken: CancellationToken): Type | undefined {
|
||||
const usageContext: UsageContext = {};
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
@@ -301,43 +292,45 @@ namespace ts.codefix {
|
||||
return getTypeFromUsageContext(usageContext, checker);
|
||||
}
|
||||
|
||||
export function inferTypeForParametersFromReferences(references: Identifier[], declaration: FunctionLikeDeclaration, checker: TypeChecker, cancellationToken: CancellationToken): (Type | undefined)[] | undefined {
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, checker: TypeChecker, cancellationToken: CancellationToken): (Type | undefined)[] | undefined {
|
||||
if (references.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (declaration.parameters) {
|
||||
const usageContext: UsageContext = {};
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
inferTypeFromContext(reference, checker, usageContext);
|
||||
}
|
||||
const isConstructor = declaration.kind === SyntaxKind.Constructor;
|
||||
const callContexts = isConstructor ? usageContext.constructContexts : usageContext.callContexts;
|
||||
if (callContexts) {
|
||||
const paramTypes: Type[] = [];
|
||||
for (let parameterIndex = 0; parameterIndex < declaration.parameters.length; parameterIndex++) {
|
||||
let types: Type[] = [];
|
||||
const isRestParameter = ts.isRestParameter(declaration.parameters[parameterIndex]);
|
||||
for (const callContext of callContexts) {
|
||||
if (callContext.argumentTypes.length > parameterIndex) {
|
||||
if (isRestParameter) {
|
||||
types = concatenate(types, map(callContext.argumentTypes.slice(parameterIndex), a => checker.getBaseTypeOfLiteralType(a)));
|
||||
}
|
||||
else {
|
||||
types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex]));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (types.length) {
|
||||
const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
|
||||
paramTypes[parameterIndex] = isRestParameter ? checker.createArrayType(type) : type;
|
||||
if (!declaration.parameters) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const usageContext: UsageContext = {};
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
inferTypeFromContext(reference, checker, usageContext);
|
||||
}
|
||||
const isConstructor = declaration.kind === SyntaxKind.Constructor;
|
||||
const callContexts = isConstructor ? usageContext.constructContexts : usageContext.callContexts;
|
||||
return callContexts && declaration.parameters.map((parameter, parameterIndex) => {
|
||||
const types: Type[] = [];
|
||||
const isRestParameter = ts.isRestParameter(parameter);
|
||||
for (const callContext of callContexts) {
|
||||
if (callContext.argumentTypes.length <= parameterIndex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isRestParameter) {
|
||||
for (let i = parameterIndex; i < callContext.argumentTypes.length; i++) {
|
||||
types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[i]));
|
||||
}
|
||||
}
|
||||
return paramTypes;
|
||||
else {
|
||||
types.push(checker.getBaseTypeOfLiteralType(callContext.argumentTypes[parameterIndex]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
if (!types.length) {
|
||||
return undefined;
|
||||
}
|
||||
const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
|
||||
return isRestParameter ? checker.createArrayType(type) : type;
|
||||
});
|
||||
}
|
||||
|
||||
function inferTypeFromContext(node: Expression, checker: TypeChecker, usageContext: UsageContext): void {
|
||||
|
||||
+36
-25
@@ -42,7 +42,7 @@ namespace ts.Completions {
|
||||
const contextToken = findPrecedingToken(position, sourceFile);
|
||||
|
||||
if (isInString(sourceFile, position, contextToken)) {
|
||||
return !contextToken || !isStringLiteral(contextToken) && !isNoSubstitutionTemplateLiteral(contextToken)
|
||||
return !contextToken || !isStringLiteralLike(contextToken)
|
||||
? undefined
|
||||
: convertStringLiteralCompletions(getStringLiteralCompletionEntries(sourceFile, contextToken, position, typeChecker, compilerOptions, host), sourceFile, typeChecker, log);
|
||||
}
|
||||
@@ -358,8 +358,7 @@ namespace ts.Completions {
|
||||
case SyntaxKind.LiteralType:
|
||||
switch (node.parent.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
// TODO: GH#21168
|
||||
return undefined;
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent as LiteralTypeNode), typeChecker) };
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
@@ -612,7 +611,7 @@ namespace ts.Completions {
|
||||
allSourceFiles,
|
||||
formatContext,
|
||||
getCanonicalFileName,
|
||||
tryCast(previousToken, isIdentifier));
|
||||
previousToken);
|
||||
return { sourceDisplay: [textPart(moduleSpecifier)], codeActions: [codeAction] };
|
||||
}
|
||||
|
||||
@@ -712,7 +711,7 @@ namespace ts.Completions {
|
||||
function getFirstSymbolInChain(symbol: Symbol, enclosingDeclaration: Node, checker: TypeChecker): Symbol | undefined {
|
||||
const chain = checker.getAccessibleSymbolChain(symbol, enclosingDeclaration, /*meaning*/ SymbolFlags.All, /*useOnlyExternalAliasing*/ false);
|
||||
if (chain) return first(chain);
|
||||
return isModuleSymbol(symbol.parent) ? symbol : symbol.parent && getFirstSymbolInChain(symbol.parent, enclosingDeclaration, checker);
|
||||
return symbol.parent && (isModuleSymbol(symbol.parent) ? symbol : getFirstSymbolInChain(symbol.parent, enclosingDeclaration, checker));
|
||||
}
|
||||
|
||||
function isModuleSymbol(symbol: Symbol): boolean {
|
||||
@@ -862,6 +861,23 @@ namespace ts.Completions {
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
// Fix location
|
||||
if (currentToken.parent === location) {
|
||||
switch (currentToken.kind) {
|
||||
case SyntaxKind.GreaterThanToken:
|
||||
if (currentToken.parent.kind === SyntaxKind.JsxElement || currentToken.parent.kind === SyntaxKind.JsxOpeningElement) {
|
||||
location = currentToken;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.SlashToken:
|
||||
if (currentToken.parent.kind === SyntaxKind.JsxSelfClosingElement) {
|
||||
location = currentToken;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
if (contextToken.kind === SyntaxKind.SlashToken) {
|
||||
@@ -912,7 +928,7 @@ namespace ts.Completions {
|
||||
getTypeScriptMemberSymbols();
|
||||
}
|
||||
else if (isRightOfOpenTag) {
|
||||
const tagSymbols = typeChecker.getJsxIntrinsicTagNames();
|
||||
const tagSymbols = Debug.assertEachDefined(typeChecker.getJsxIntrinsicTagNames(), "getJsxIntrinsicTagNames() should all be defined");
|
||||
if (tryGetGlobalSymbols()) {
|
||||
symbols = tagSymbols.concat(symbols.filter(s => !!(s.flags & (SymbolFlags.Value | SymbolFlags.Alias))));
|
||||
}
|
||||
@@ -924,8 +940,7 @@ namespace ts.Completions {
|
||||
else if (isStartingCloseTag) {
|
||||
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
|
||||
const tagSymbol = typeChecker.getSymbolAtLocation(tagName);
|
||||
|
||||
if (!typeChecker.isUnknownSymbol(tagSymbol)) {
|
||||
if (tagSymbol) {
|
||||
symbols = [tagSymbol];
|
||||
}
|
||||
completionKind = CompletionKind.MemberLike;
|
||||
@@ -971,7 +986,7 @@ namespace ts.Completions {
|
||||
|
||||
if (symbol.flags & (SymbolFlags.Module | SymbolFlags.Enum)) {
|
||||
// Extract module or enum members
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
const exportedSymbols = Debug.assertEachDefined(typeChecker.getExportsOfModule(symbol), "getExportsOfModule() should all be defined");
|
||||
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name);
|
||||
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
|
||||
const isValidAccess = isRhsOfImportDeclaration ?
|
||||
@@ -1043,10 +1058,6 @@ namespace ts.Completions {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) {
|
||||
keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords;
|
||||
}
|
||||
|
||||
if (classLikeContainer = tryGetClassLikeCompletionContainer(contextToken)) {
|
||||
// cursor inside class declaration
|
||||
getGetClassLikeCompletionSymbols(classLikeContainer);
|
||||
@@ -1068,6 +1079,10 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) {
|
||||
keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords;
|
||||
}
|
||||
|
||||
// Get all entities in the current scope.
|
||||
completionKind = CompletionKind.None;
|
||||
isNewIdentifierLocation = isNewIdentifierDefinitionLocation(contextToken);
|
||||
@@ -1111,7 +1126,7 @@ namespace ts.Completions {
|
||||
|
||||
const symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias;
|
||||
|
||||
symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings);
|
||||
symbols = Debug.assertEachDefined(typeChecker.getSymbolsInScope(scopeNode, symbolMeanings), "getSymbolsInScope() should all be defined");
|
||||
|
||||
// Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions`
|
||||
if (options.includeInsertTextCompletions && scopeNode.kind !== SyntaxKind.SourceFile) {
|
||||
@@ -1452,7 +1467,7 @@ namespace ts.Completions {
|
||||
|
||||
if (typeMembers && typeMembers.length > 0) {
|
||||
// Add filtered items to the completion list
|
||||
symbols = filterObjectMembersList(typeMembers, existingMembers);
|
||||
symbols = filterObjectMembersList(typeMembers, Debug.assertDefined(existingMembers));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1926,11 +1941,7 @@ namespace ts.Completions {
|
||||
existingImportsOrExports.set(name.escapedText, true);
|
||||
}
|
||||
|
||||
if (existingImportsOrExports.size === 0) {
|
||||
return filter(exportsOfModule, e => e.escapedName !== InternalSymbolName.Default);
|
||||
}
|
||||
|
||||
return filter(exportsOfModule, e => e.escapedName !== InternalSymbolName.Default && !existingImportsOrExports.get(e.escapedName));
|
||||
return exportsOfModule.filter(e => e.escapedName !== InternalSymbolName.Default && !existingImportsOrExports.get(e.escapedName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1940,7 +1951,7 @@ namespace ts.Completions {
|
||||
* do not occur at the current position and have not otherwise been typed.
|
||||
*/
|
||||
function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: ReadonlyArray<Declaration>): Symbol[] {
|
||||
if (!existingMembers || existingMembers.length === 0) {
|
||||
if (existingMembers.length === 0) {
|
||||
return contextualMemberSymbols;
|
||||
}
|
||||
|
||||
@@ -1980,7 +1991,7 @@ namespace ts.Completions {
|
||||
existingMemberNames.set(existingName, true);
|
||||
}
|
||||
|
||||
return filter(contextualMemberSymbols, m => !existingMemberNames.get(m.escapedName));
|
||||
return contextualMemberSymbols.filter(m => !existingMemberNames.get(m.escapedName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2066,7 +2077,7 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
return filter(symbols, a => !seenNames.get(a.escapedName));
|
||||
return symbols.filter(a => !seenNames.get(a.escapedName));
|
||||
}
|
||||
|
||||
function isCurrentlyEditingNode(node: Node): boolean {
|
||||
@@ -2248,13 +2259,13 @@ namespace ts.Completions {
|
||||
*/
|
||||
function getPropertiesForCompletion(type: Type, checker: TypeChecker, isForAccess: boolean): Symbol[] {
|
||||
if (!(type.flags & TypeFlags.Union)) {
|
||||
return type.getApparentProperties();
|
||||
return Debug.assertEachDefined(type.getApparentProperties(), "getApparentProperties() should all be defined");
|
||||
}
|
||||
|
||||
const { types } = type as UnionType;
|
||||
// If we're providing completions for an object literal, skip primitive, array-like, or callable types since those shouldn't be implemented by object literals.
|
||||
const filteredTypes = isForAccess ? types : types.filter(memberType =>
|
||||
!(memberType.flags & TypeFlags.Primitive || checker.isArrayLikeType(memberType) || typeHasCallOrConstructSignatures(memberType, checker)));
|
||||
return checker.getAllPossiblePropertiesOfTypes(filteredTypes);
|
||||
return Debug.assertEachDefined(checker.getAllPossiblePropertiesOfTypes(filteredTypes), "getAllPossiblePropertiesOfTypes() should all be defined");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* @internal */
|
||||
namespace ts.DocumentHighlights {
|
||||
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] | undefined {
|
||||
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: ReadonlyArray<SourceFile>): DocumentHighlights[] | undefined {
|
||||
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
|
||||
if (node.parent && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent))) {
|
||||
@@ -21,12 +21,12 @@ namespace ts.DocumentHighlights {
|
||||
};
|
||||
}
|
||||
|
||||
function getSemanticDocumentHighlights(position: number, node: Node, program: Program, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
|
||||
function getSemanticDocumentHighlights(position: number, node: Node, program: Program, cancellationToken: CancellationToken, sourceFilesToSearch: ReadonlyArray<SourceFile>): DocumentHighlights[] {
|
||||
const referenceEntries = FindAllReferences.getReferenceEntriesForNode(position, node, program, sourceFilesToSearch, cancellationToken);
|
||||
return referenceEntries && convertReferencedSymbols(referenceEntries);
|
||||
}
|
||||
|
||||
function convertReferencedSymbols(referenceEntries: FindAllReferences.Entry[]): DocumentHighlights[] {
|
||||
function convertReferencedSymbols(referenceEntries: ReadonlyArray<FindAllReferences.Entry>): DocumentHighlights[] {
|
||||
const fileNameToDocumentHighlights = createMap<HighlightSpan[]>();
|
||||
for (const entry of referenceEntries) {
|
||||
const { fileName, span } = FindAllReferences.toHighlightSpan(entry);
|
||||
@@ -189,11 +189,6 @@ namespace ts.DocumentHighlights {
|
||||
}
|
||||
|
||||
function getModifierOccurrences(modifier: SyntaxKind, declaration: Node): Node[] {
|
||||
// Make sure we only highlight the keyword when it makes sense to do so.
|
||||
if (!isLegalModifier(modifier, declaration)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const modifierFlag = modifierToFlag(modifier);
|
||||
return mapDefined(getNodesToSearchForModifier(declaration, modifierFlag), node => {
|
||||
if (getModifierFlags(node) & modifierFlag) {
|
||||
@@ -205,7 +200,8 @@ namespace ts.DocumentHighlights {
|
||||
}
|
||||
|
||||
function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): ReadonlyArray<Node> {
|
||||
const container = declaration.parent;
|
||||
// Types of node whose children might have modifiers.
|
||||
const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ClassLikeDeclaration;
|
||||
switch (container.kind) {
|
||||
case SyntaxKind.ModuleBlock:
|
||||
case SyntaxKind.SourceFile:
|
||||
@@ -213,22 +209,25 @@ namespace ts.DocumentHighlights {
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.DefaultClause:
|
||||
// Container is either a class declaration or the declaration is a classDeclaration
|
||||
if (modifierFlag & ModifierFlags.Abstract) {
|
||||
return [...(<ClassDeclaration>declaration).members, declaration];
|
||||
if (modifierFlag & ModifierFlags.Abstract && isClassDeclaration(declaration)) {
|
||||
return [...declaration.members, declaration];
|
||||
}
|
||||
else {
|
||||
return (<ModuleBlock | SourceFile | Block | CaseClause | DefaultClause>container).statements;
|
||||
return container.statements;
|
||||
}
|
||||
case SyntaxKind.Constructor:
|
||||
return [...(<ConstructorDeclaration>container).parameters, ...(<ClassDeclaration>container.parent).members];
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration: {
|
||||
return [...container.parameters, ...(isClassLike(container.parent) ? container.parent.members : [])];
|
||||
}
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
const nodes = (<ClassLikeDeclaration>container).members;
|
||||
const nodes = container.members;
|
||||
|
||||
// If we're an accessibility modifier, we're in an instance member and should search
|
||||
// the constructor's parameter list for instance members as well.
|
||||
if (modifierFlag & ModifierFlags.AccessibilityModifier) {
|
||||
const constructor = find((<ClassLikeDeclaration>container).members, isConstructorDeclaration);
|
||||
const constructor = find(container.members, isConstructorDeclaration);
|
||||
if (constructor) {
|
||||
return [...nodes, ...constructor.parameters];
|
||||
}
|
||||
@@ -238,34 +237,7 @@ namespace ts.DocumentHighlights {
|
||||
}
|
||||
return nodes;
|
||||
default:
|
||||
Debug.fail("Invalid container kind.");
|
||||
}
|
||||
}
|
||||
|
||||
function isLegalModifier(modifier: SyntaxKind, declaration: Node): boolean {
|
||||
const container = declaration.parent;
|
||||
switch (modifier) {
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.PublicKeyword:
|
||||
switch (container.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ClassExpression:
|
||||
return true;
|
||||
case SyntaxKind.Constructor:
|
||||
return declaration.kind === SyntaxKind.Parameter;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case SyntaxKind.StaticKeyword:
|
||||
return container.kind === SyntaxKind.ClassDeclaration || container.kind === SyntaxKind.ClassExpression;
|
||||
case SyntaxKind.ExportKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
return container.kind === SyntaxKind.ModuleBlock || container.kind === SyntaxKind.SourceFile;
|
||||
case SyntaxKind.AbstractKeyword:
|
||||
return container.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.ClassDeclaration;
|
||||
default:
|
||||
return false;
|
||||
Debug.assertNever(container, "Invalid container kind.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
function isModuleReferenceLocation(node: ts.Node): boolean {
|
||||
if (node.kind !== SyntaxKind.StringLiteral && node.kind !== SyntaxKind.NoSubstitutionTemplateLiteral) {
|
||||
if (!isStringLiteralLike(node)) {
|
||||
return false;
|
||||
}
|
||||
switch (node.parent.kind) {
|
||||
@@ -416,10 +416,16 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
// If the symbol is declared as part of a declaration like `{ type: "a" } | { type: "b" }`, use the property on the union type to get more references.
|
||||
return firstDefined(symbol.declarations, decl =>
|
||||
isTypeLiteralNode(decl.parent) && isUnionTypeNode(decl.parent.parent)
|
||||
return firstDefined(symbol.declarations, decl => {
|
||||
if (!decl.parent) {
|
||||
// Assertions for GH#21814. We should be handling SourceFile symbols in `getReferencedSymbolsForModule` instead of getting here.
|
||||
Debug.assert(decl.kind === SyntaxKind.SourceFile);
|
||||
Debug.fail(`Unexpected symbol at ${Debug.showSyntaxKind(node)}: ${Debug.showSymbol(symbol)}`);
|
||||
}
|
||||
return isTypeLiteralNode(decl.parent) && isUnionTypeNode(decl.parent.parent)
|
||||
? checker.getPropertyOfType(checker.getTypeFromTypeNode(decl.parent.parent), symbol.name)
|
||||
: undefined) || symbol;
|
||||
: undefined;
|
||||
}) || symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -703,7 +709,7 @@ namespace ts.FindAllReferences.Core {
|
||||
return exposedByParent ? scope.getSourceFile() : scope;
|
||||
}
|
||||
|
||||
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): number[] {
|
||||
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): ReadonlyArray<number> {
|
||||
const positions: number[] = [];
|
||||
|
||||
/// TODO: Cache symbol existence for files to save text search
|
||||
@@ -914,7 +920,8 @@ namespace ts.FindAllReferences.Core {
|
||||
|
||||
// At `export { x } from "foo"`, also search for the imported symbol `"foo".x`.
|
||||
if (search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName) {
|
||||
searchForImportedSymbol(state.checker.getExportSpecifierLocalTargetSymbol(exportSpecifier), state);
|
||||
const imported = state.checker.getExportSpecifierLocalTargetSymbol(exportSpecifier);
|
||||
if (imported) searchForImportedSymbol(imported, state);
|
||||
}
|
||||
|
||||
function addRef() {
|
||||
@@ -923,7 +930,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
function getLocalSymbolForExportSpecifier(referenceLocation: Identifier, referenceSymbol: Symbol, exportSpecifier: ExportSpecifier, checker: TypeChecker): Symbol {
|
||||
return isExportSpecifierAlias(referenceLocation, exportSpecifier) ? checker.getExportSpecifierLocalTargetSymbol(exportSpecifier) : referenceSymbol;
|
||||
return isExportSpecifierAlias(referenceLocation, exportSpecifier) && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier) || referenceSymbol;
|
||||
}
|
||||
|
||||
function isExportSpecifierAlias(referenceLocation: Identifier, exportSpecifier: ExportSpecifier): boolean {
|
||||
@@ -1344,63 +1351,63 @@ namespace ts.FindAllReferences.Core {
|
||||
|
||||
const references: Entry[] = [];
|
||||
|
||||
let possiblePositions: number[];
|
||||
let possiblePositions: ReadonlyArray<number>;
|
||||
if (searchSpaceNode.kind === SyntaxKind.SourceFile) {
|
||||
forEach(sourceFiles, sourceFile => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this");
|
||||
getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, references);
|
||||
getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, staticFlag, references);
|
||||
});
|
||||
}
|
||||
else {
|
||||
const sourceFile = searchSpaceNode.getSourceFile();
|
||||
possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode);
|
||||
getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, references);
|
||||
getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, staticFlag, references);
|
||||
}
|
||||
|
||||
return [{
|
||||
definition: { type: "this", node: thisOrSuperKeyword },
|
||||
references
|
||||
}];
|
||||
}
|
||||
|
||||
function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: number[], result: Entry[]): void {
|
||||
forEach(possiblePositions, position => {
|
||||
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ false);
|
||||
if (!node || !isThis(node)) {
|
||||
return;
|
||||
}
|
||||
function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: ReadonlyArray<number>, staticFlag: ModifierFlags, result: Push<Entry>): void {
|
||||
forEach(possiblePositions, position => {
|
||||
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ false);
|
||||
if (!node || !isThis(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const container = getThisContainer(node, /* includeArrowFunctions */ false);
|
||||
const container = getThisContainer(node, /* includeArrowFunctions */ false);
|
||||
|
||||
switch (searchSpaceNode.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
if (searchSpaceNode.symbol === container.symbol) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
// Make sure the container belongs to the same class
|
||||
// and has the appropriate static modifier from the original container.
|
||||
if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (getModifierFlags(container) & ModifierFlags.Static) === staticFlag) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.SourceFile:
|
||||
if (container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container)) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
switch (searchSpaceNode.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
if (searchSpaceNode.symbol === container.symbol) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassExpression:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
// Make sure the container belongs to the same class
|
||||
// and has the appropriate static modifier from the original container.
|
||||
if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (getModifierFlags(container) & ModifierFlags.Static) === staticFlag) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.SourceFile:
|
||||
if (container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container)) {
|
||||
result.push(nodeEntry(node));
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getReferencesForStringLiteral(node: StringLiteral, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] {
|
||||
@@ -1417,7 +1424,7 @@ namespace ts.FindAllReferences.Core {
|
||||
references
|
||||
}];
|
||||
|
||||
function getReferencesForStringLiteralInFile(sourceFile: SourceFile, searchText: string, possiblePositions: number[], references: Push<NodeEntry>): void {
|
||||
function getReferencesForStringLiteralInFile(sourceFile: SourceFile, searchText: string, possiblePositions: ReadonlyArray<number>, references: Push<NodeEntry>): void {
|
||||
for (const position of possiblePositions) {
|
||||
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ false);
|
||||
if (node && node.kind === SyntaxKind.StringLiteral && (node as StringLiteral).text === searchText) {
|
||||
|
||||
@@ -92,6 +92,9 @@ namespace ts.formatting {
|
||||
rule("SpaceBetweenCloseBraceAndWhile", SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword, [isNonJsxSameLineTokenContext], RuleAction.Space),
|
||||
rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.Delete),
|
||||
|
||||
// Add a space after control dec context if the next character is an open bracket ex: 'if (false)[a, b] = [1, 2];' -> 'if (false) [a, b] = [1, 2];'
|
||||
rule("SpaceAfterConditionalClosingParen", SyntaxKind.CloseParenToken, SyntaxKind.OpenBracketToken, [isControlDeclContext], RuleAction.Space),
|
||||
|
||||
rule("NoSpaceBetweenFunctionKeywordAndStar", SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken, [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.Delete),
|
||||
rule("SpaceAfterStarInGeneratorDeclaration", SyntaxKind.AsteriskToken, [SyntaxKind.Identifier, SyntaxKind.OpenParenToken], [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.Space),
|
||||
|
||||
@@ -162,6 +165,7 @@ namespace ts.formatting {
|
||||
SyntaxKind.TypeKeyword,
|
||||
SyntaxKind.FromKeyword,
|
||||
SyntaxKind.KeyOfKeyword,
|
||||
SyntaxKind.InferKeyword,
|
||||
],
|
||||
anyToken,
|
||||
[isNonJsxSameLineTokenContext],
|
||||
@@ -409,6 +413,7 @@ namespace ts.formatting {
|
||||
switch (context.contextNode.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
case SyntaxKind.ConditionalType:
|
||||
case SyntaxKind.AsExpression:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
@@ -461,7 +466,8 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function isConditionalOperatorContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind === SyntaxKind.ConditionalExpression;
|
||||
return context.contextNode.kind === SyntaxKind.ConditionalExpression ||
|
||||
context.contextNode.kind === SyntaxKind.ConditionalType;
|
||||
}
|
||||
|
||||
function isSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolean {
|
||||
@@ -469,7 +475,9 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function isBraceWrappedContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind === SyntaxKind.ObjectBindingPattern || isSingleLineBlockContext(context);
|
||||
return context.contextNode.kind === SyntaxKind.ObjectBindingPattern ||
|
||||
context.contextNode.kind === SyntaxKind.MappedType ||
|
||||
isSingleLineBlockContext(context);
|
||||
}
|
||||
|
||||
// This check is done before an open brace in a control construct, a function, or a typescript block declaration
|
||||
|
||||
@@ -149,10 +149,7 @@ namespace ts.GoToDefinition {
|
||||
// Check if position is on triple slash reference.
|
||||
const comment = findReferenceInPosition(sourceFile.referencedFiles, position) || findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
|
||||
if (comment) {
|
||||
return {
|
||||
definitions,
|
||||
textSpan: createTextSpanFromBounds(comment.pos, comment.end)
|
||||
};
|
||||
return { definitions, textSpan: createTextSpanFromRange(comment) };
|
||||
}
|
||||
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
@@ -191,7 +188,7 @@ namespace ts.GoToDefinition {
|
||||
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
|
||||
// Applicable only if we are in a new expression, or we are on a constructor declaration
|
||||
// and in either case the symbol has a construct signature definition, i.e. class
|
||||
if (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword && symbol.flags & SymbolFlags.Class) {
|
||||
if (symbol.flags & SymbolFlags.Class && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword)) {
|
||||
const cls = find(symbol.declarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration");
|
||||
return getSignatureDefinition(cls.members, /*selectConstructors*/ true);
|
||||
}
|
||||
@@ -217,6 +214,7 @@ namespace ts.GoToDefinition {
|
||||
function isSignatureDeclaration(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.Constructor:
|
||||
case ts.SyntaxKind.ConstructSignature:
|
||||
case ts.SyntaxKind.FunctionDeclaration:
|
||||
case ts.SyntaxKind.MethodDeclaration:
|
||||
case ts.SyntaxKind.MethodSignature:
|
||||
@@ -257,7 +255,7 @@ namespace ts.GoToDefinition {
|
||||
return createDefinitionInfo(decl, symbolKind, symbolName, containerName);
|
||||
}
|
||||
|
||||
export function findReferenceInPosition(refs: ReadonlyArray<FileReference>, pos: number): FileReference {
|
||||
export function findReferenceInPosition(refs: ReadonlyArray<FileReference>, pos: number): FileReference | undefined {
|
||||
for (const ref of refs) {
|
||||
if (ref.pos <= pos && pos <= ref.end) {
|
||||
return ref;
|
||||
|
||||
@@ -107,6 +107,11 @@ namespace ts.FindAllReferences {
|
||||
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
|
||||
handleNamespaceImport(direct, namedBindings.name);
|
||||
}
|
||||
else if (isDefaultImport(direct)) {
|
||||
const sourceFileLike = getSourceFileLikeForImportDeclaration(direct);
|
||||
addIndirectUser(sourceFileLike); // Add a check for indirect uses to handle synthetic default imports
|
||||
directImports.push(direct);
|
||||
}
|
||||
else {
|
||||
directImports.push(direct);
|
||||
}
|
||||
@@ -512,29 +517,12 @@ namespace ts.FindAllReferences {
|
||||
const sym = useLhsSymbol ? checker.getSymbolAtLocation(cast(node.left, isPropertyAccessExpression).name) : symbol;
|
||||
// Better detection for GH#20803
|
||||
if (sym && !(checker.getMergedSymbol(sym.parent).flags & SymbolFlags.Module)) {
|
||||
Debug.fail(`Special property assignment kind does not have a module as its parent. Assignment is ${showSymbol(sym)}, parent is ${showSymbol(sym.parent)}`);
|
||||
Debug.fail(`Special property assignment kind does not have a module as its parent. Assignment is ${Debug.showSymbol(sym)}, parent is ${Debug.showSymbol(sym.parent)}`);
|
||||
}
|
||||
return sym && exportInfo(sym, kind);
|
||||
}
|
||||
}
|
||||
|
||||
function showSymbol(s: Symbol): string {
|
||||
const decls = s.declarations.map(d => (ts as any).SyntaxKind[d.kind]).join(",");
|
||||
const flags = showFlags(s.flags, (ts as any).SymbolFlags);
|
||||
return `{ declarations: ${decls}, flags: ${flags} }`;
|
||||
}
|
||||
|
||||
function showFlags(f: number, flags: any) {
|
||||
const out = [];
|
||||
for (let pow = 0; pow <= 30; pow++) {
|
||||
const n = 1 << pow;
|
||||
if (f & n) {
|
||||
out.push(flags[n]);
|
||||
}
|
||||
}
|
||||
return out.join("|");
|
||||
}
|
||||
|
||||
function getImport(): ImportedSymbol | undefined {
|
||||
const isImport = isNodeImport(node);
|
||||
if (!isImport) return undefined;
|
||||
@@ -572,17 +560,17 @@ namespace ts.FindAllReferences {
|
||||
|
||||
function getExportEqualsLocalSymbol(importedSymbol: Symbol, checker: TypeChecker): Symbol {
|
||||
if (importedSymbol.flags & SymbolFlags.Alias) {
|
||||
return checker.getImmediateAliasedSymbol(importedSymbol);
|
||||
return Debug.assertDefined(checker.getImmediateAliasedSymbol(importedSymbol));
|
||||
}
|
||||
|
||||
const decl = importedSymbol.valueDeclaration;
|
||||
if (isExportAssignment(decl)) { // `export = class {}`
|
||||
return decl.expression.symbol;
|
||||
return Debug.assertDefined(decl.expression.symbol);
|
||||
}
|
||||
else if (isBinaryExpression(decl)) { // `module.exports = class {}`
|
||||
return decl.right.symbol;
|
||||
return Debug.assertDefined(decl.right.symbol);
|
||||
}
|
||||
Debug.fail();
|
||||
return Debug.fail();
|
||||
}
|
||||
|
||||
// If a reference is a class expression, the exported node would be its parent.
|
||||
@@ -618,7 +606,9 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function getExportInfo(exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker): ExportInfo | undefined {
|
||||
const exportingModuleSymbol = checker.getMergedSymbol(exportSymbol.parent); // Need to get merged symbol in case there's an augmentation.
|
||||
const moduleSymbol = exportSymbol.parent;
|
||||
if (!moduleSymbol) return undefined; // This can happen if an `export` is not at the top-level (which is a compile error).
|
||||
const exportingModuleSymbol = checker.getMergedSymbol(moduleSymbol); // Need to get merged symbol in case there's an augmentation.
|
||||
// `export` may appear in a namespace. In that case, just rely on global search.
|
||||
return isExternalModuleSymbol(exportingModuleSymbol) ? { exportingModuleSymbol, exportKind } : undefined;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
/// <reference path='../compiler/types.ts' />
|
||||
/// <reference path='../compiler/core.ts' />
|
||||
/// <reference path='../compiler/commandLineParser.ts' />
|
||||
/// <reference path='../services/semver.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.JsTyping {
|
||||
@@ -26,6 +27,17 @@ namespace ts.JsTyping {
|
||||
typings?: string;
|
||||
}
|
||||
|
||||
export interface CachedTyping {
|
||||
typingLocation: string;
|
||||
version: Semver;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isTypingUpToDate(cachedTyping: JsTyping.CachedTyping, availableTypingVersions: MapLike<string>) {
|
||||
const availableVersion = Semver.parse(getProperty(availableTypingVersions, `ts${ts.versionMajorMinor}`) || getProperty(availableTypingVersions, "latest"));
|
||||
return !availableVersion.greaterThan(cachedTyping.version);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const nodeCoreModuleList: ReadonlyArray<string> = [
|
||||
"buffer", "querystring", "events", "http", "cluster",
|
||||
@@ -60,7 +72,7 @@ namespace ts.JsTyping {
|
||||
* @param fileNames are the file names that belong to the same project
|
||||
* @param projectRootPath is the path to the project root directory
|
||||
* @param safeListPath is the path used to retrieve the safe list
|
||||
* @param packageNameToTypingLocation is the map of package names to their cached typing locations
|
||||
* @param packageNameToTypingLocation is the map of package names to their cached typing locations and installed versions
|
||||
* @param typeAcquisition is used to customize the typing acquisition process
|
||||
* @param compilerOptions are used as a source for typing inference
|
||||
*/
|
||||
@@ -70,9 +82,10 @@ namespace ts.JsTyping {
|
||||
fileNames: string[],
|
||||
projectRootPath: Path,
|
||||
safeList: SafeList,
|
||||
packageNameToTypingLocation: ReadonlyMap<string>,
|
||||
packageNameToTypingLocation: ReadonlyMap<CachedTyping>,
|
||||
typeAcquisition: TypeAcquisition,
|
||||
unresolvedImports: ReadonlyArray<string>):
|
||||
unresolvedImports: ReadonlyArray<string>,
|
||||
typesRegistry: ReadonlyMap<MapLike<string>>):
|
||||
{ cachedTypingPaths: string[], newTypingNames: string[], filesToWatch: string[] } {
|
||||
|
||||
if (!typeAcquisition || !typeAcquisition.enable) {
|
||||
@@ -122,9 +135,9 @@ namespace ts.JsTyping {
|
||||
addInferredTypings(module, "Inferred typings from unresolved imports");
|
||||
}
|
||||
// Add the cached typing locations for inferred typings that are already installed
|
||||
packageNameToTypingLocation.forEach((typingLocation, name) => {
|
||||
if (inferredTypings.has(name) && inferredTypings.get(name) === undefined) {
|
||||
inferredTypings.set(name, typingLocation);
|
||||
packageNameToTypingLocation.forEach((typing, name) => {
|
||||
if (inferredTypings.has(name) && inferredTypings.get(name) === undefined && isTypingUpToDate(typing, typesRegistry.get(name))) {
|
||||
inferredTypings.set(name, typing.typingLocation);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -632,9 +632,7 @@ namespace ts.NavigationBar {
|
||||
}
|
||||
|
||||
function getNodeSpan(node: Node): TextSpan {
|
||||
return node.kind === SyntaxKind.SourceFile
|
||||
? createTextSpanFromBounds(node.getFullStart(), node.getEnd())
|
||||
: createTextSpanFromNode(node, curSourceFile);
|
||||
return node.kind === SyntaxKind.SourceFile ? createTextSpanFromRange(node) : createTextSpanFromNode(node, curSourceFile);
|
||||
}
|
||||
|
||||
function getModifiers(node: ts.Node): string {
|
||||
|
||||
@@ -462,7 +462,7 @@ namespace ts.Completions.PathCompletions {
|
||||
}
|
||||
|
||||
function normalizeAndPreserveTrailingSlash(path: string) {
|
||||
if (path === "./") {
|
||||
if (normalizeSlashes(path) === "./") {
|
||||
// normalizePath turns "./" into "". "" + "/" would then be a rooted path instead of a relative one, so avoid this particular case.
|
||||
// There is no problem for adding "/" to a non-empty string -- it's only a problem at the beginning.
|
||||
return "";
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
const changeTracker = textChanges.ChangeTracker.fromContext(context);
|
||||
const declarationWithType = addType(decl, transformJSDocType(jsdocType) as TypeNode);
|
||||
suppressLeadingAndTrailingTrivia(declarationWithType);
|
||||
changeTracker.replaceRange(sourceFile, { pos: decl.getStart(), end: decl.end }, declarationWithType);
|
||||
changeTracker.replaceNode(sourceFile, decl, declarationWithType, textChanges.useNonAdjustedPositions);
|
||||
return {
|
||||
edits: changeTracker.getChanges(),
|
||||
renameFilename: undefined,
|
||||
@@ -91,7 +91,7 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
|
||||
const changeTracker = textChanges.ChangeTracker.fromContext(context);
|
||||
const functionWithType = addTypesToFunctionLike(decl);
|
||||
suppressLeadingAndTrailingTrivia(functionWithType);
|
||||
changeTracker.replaceRange(sourceFile, { pos: decl.getStart(), end: decl.end }, functionWithType);
|
||||
changeTracker.replaceNode(sourceFile, decl, functionWithType, textChanges.useNonAdjustedPositions);
|
||||
return {
|
||||
edits: changeTracker.getChanges(),
|
||||
renameFilename: undefined,
|
||||
|
||||
@@ -33,14 +33,17 @@ namespace ts.refactor {
|
||||
return isExportsOrModuleExportsOrAlias(sourceFile, node as PropertyAccessExpression)
|
||||
|| isExportsOrModuleExportsOrAlias(sourceFile, (node as PropertyAccessExpression).expression);
|
||||
case SyntaxKind.VariableDeclarationList:
|
||||
const decl = (node as VariableDeclarationList).declarations[0];
|
||||
return isExportsOrModuleExportsOrAlias(sourceFile, decl.initializer);
|
||||
return isVariableDeclarationTriggerLocation(firstOrUndefined((node as VariableDeclarationList).declarations));
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return isExportsOrModuleExportsOrAlias(sourceFile, (node as VariableDeclaration).initializer);
|
||||
return isVariableDeclarationTriggerLocation(node as VariableDeclaration);
|
||||
default:
|
||||
return isExpression(node) && isExportsOrModuleExportsOrAlias(sourceFile, node)
|
||||
|| !onSecondTry && isAtTriggerLocation(sourceFile, node.parent, /*onSecondTry*/ true);
|
||||
}
|
||||
|
||||
function isVariableDeclarationTriggerLocation(decl: VariableDeclaration | undefined) {
|
||||
return !!decl && !!decl.initializer && isExportsOrModuleExportsOrAlias(sourceFile, decl.initializer);
|
||||
}
|
||||
}
|
||||
|
||||
function isAtTopLevelRequire(call: CallExpression): boolean {
|
||||
@@ -375,7 +378,14 @@ namespace ts.refactor {
|
||||
function convertExportsDotXEquals(name: string | undefined, exported: Expression): Statement {
|
||||
const modifiers = [createToken(SyntaxKind.ExportKeyword)];
|
||||
switch (exported.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionExpression: {
|
||||
const { name: expressionName } = exported as FunctionExpression;
|
||||
if (expressionName && expressionName.text !== name) {
|
||||
// `exports.f = function g() {}` -> `export const f = function g() {}`
|
||||
return exportConst();
|
||||
}
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.ArrowFunction:
|
||||
// `exports.f = function() {}` --> `export function f() {}`
|
||||
return functionExpressionToDeclaration(name, modifiers, exported as FunctionExpression | ArrowFunction);
|
||||
@@ -383,8 +393,12 @@ namespace ts.refactor {
|
||||
// `exports.C = class {}` --> `export class C {}`
|
||||
return classExpressionToDeclaration(name, modifiers, exported as ClassExpression);
|
||||
default:
|
||||
// `exports.x = 0;` --> `export const x = 0;`
|
||||
return makeConst(modifiers, createIdentifier(name), exported);
|
||||
return exportConst();
|
||||
}
|
||||
|
||||
function exportConst() {
|
||||
// `exports.x = 0;` --> `export const x = 0;`
|
||||
return makeConst(modifiers, createIdentifier(name), exported);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -687,7 +687,7 @@ namespace ts.refactor.extractSymbol {
|
||||
}
|
||||
function getDescriptionForClassLikeDeclaration(scope: ClassLikeDeclaration): string {
|
||||
return scope.kind === SyntaxKind.ClassDeclaration
|
||||
? `class '${scope.name.text}'`
|
||||
? scope.name ? `class '${scope.name.text}'` : "anonymous class declaration"
|
||||
: scope.name ? `class expression '${scope.name.text}'` : "anonymous class expression";
|
||||
}
|
||||
function getDescriptionForModuleLikeDeclaration(scope: SourceFile | ModuleBlock): string | SpecialScope {
|
||||
@@ -968,7 +968,7 @@ namespace ts.refactor.extractSymbol {
|
||||
}
|
||||
|
||||
if (isReadonlyArray(range.range)) {
|
||||
changeTracker.replaceNodesWithNodes(context.file, range.range, newNodes);
|
||||
changeTracker.replaceNodeRangeWithNodes(context.file, first(range.range), last(range.range), newNodes);
|
||||
}
|
||||
else {
|
||||
changeTracker.replaceNodeWithNodes(context.file, range.range, newNodes);
|
||||
@@ -1053,7 +1053,7 @@ namespace ts.refactor.extractSymbol {
|
||||
changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newVariable, /*blankLineBetween*/ true);
|
||||
|
||||
// Consume
|
||||
changeTracker.replaceRange(context.file, { pos: node.getStart(), end: node.end }, localReference);
|
||||
changeTracker.replaceNode(context.file, node, localReference, textChanges.useNonAdjustedPositions);
|
||||
}
|
||||
else {
|
||||
const newVariableDeclaration = createVariableDeclaration(localNameText, variableType, initializer);
|
||||
@@ -1070,7 +1070,7 @@ namespace ts.refactor.extractSymbol {
|
||||
|
||||
// Consume
|
||||
const localReference = createIdentifier(localNameText);
|
||||
changeTracker.replaceRange(context.file, { pos: node.getStart(), end: node.end }, localReference);
|
||||
changeTracker.replaceNode(context.file, node, localReference, textChanges.useNonAdjustedPositions);
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ExpressionStatement && scope === findAncestor(node, isScope)) {
|
||||
// If the parent is an expression statement and the target scope is the immediately enclosing one,
|
||||
@@ -1078,7 +1078,7 @@ namespace ts.refactor.extractSymbol {
|
||||
const newVariableStatement = createVariableStatement(
|
||||
/*modifiers*/ undefined,
|
||||
createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const));
|
||||
changeTracker.replaceRange(context.file, { pos: node.parent.getStart(), end: node.parent.end }, newVariableStatement);
|
||||
changeTracker.replaceNode(context.file, node.parent, newVariableStatement, textChanges.useNonAdjustedPositions);
|
||||
}
|
||||
else {
|
||||
const newVariableStatement = createVariableStatement(
|
||||
@@ -1097,11 +1097,11 @@ namespace ts.refactor.extractSymbol {
|
||||
// Consume
|
||||
if (node.parent.kind === SyntaxKind.ExpressionStatement) {
|
||||
// If the parent is an expression statement, delete it.
|
||||
changeTracker.deleteRange(context.file, { pos: node.parent.getStart(), end: node.parent.end });
|
||||
changeTracker.deleteNode(context.file, node.parent, textChanges.useNonAdjustedPositions);
|
||||
}
|
||||
else {
|
||||
const localReference = createIdentifier(localNameText);
|
||||
changeTracker.replaceRange(context.file, { pos: node.getStart(), end: node.end }, localReference);
|
||||
changeTracker.replaceNode(context.file, node, localReference, textChanges.useNonAdjustedPositions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1689,7 +1689,8 @@ namespace ts.refactor.extractSymbol {
|
||||
return symbolId;
|
||||
}
|
||||
// find first declaration in this file
|
||||
const declInFile = find(symbol.getDeclarations(), d => d.getSourceFile() === sourceFile);
|
||||
const decls = symbol.getDeclarations();
|
||||
const declInFile = decls && find(decls, d => d.getSourceFile() === sourceFile);
|
||||
if (!declInFile) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1782,7 +1783,8 @@ namespace ts.refactor.extractSymbol {
|
||||
if (!symbol) {
|
||||
return undefined;
|
||||
}
|
||||
if (symbol.getDeclarations().some(d => d.parent === scopeDecl)) {
|
||||
const decls = symbol.getDeclarations();
|
||||
if (decls && decls.some(d => d.parent === scopeDecl)) {
|
||||
return createIdentifier(symbol.name);
|
||||
}
|
||||
const prefix = tryReplaceWithQualifiedNameOrPropertyAccess(symbol.parent, scopeDecl, isTypeNode);
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace ts.refactor.installTypesForPackage {
|
||||
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
|
||||
const { file, startPosition, program } = context;
|
||||
|
||||
if (!program.getCompilerOptions().allowSyntheticDefaultImports) {
|
||||
if (!getAllowSyntheticDefaultImports(program.getCompilerOptions())) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace ts.refactor.installTypesForPackage {
|
||||
}
|
||||
|
||||
const module = getResolvedModule(file, importInfo.moduleSpecifier.text);
|
||||
const resolvedFile = program.getSourceFile(module.resolvedFileName);
|
||||
if (!(resolvedFile.externalModuleIndicator && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals)) {
|
||||
const resolvedFile = module && program.getSourceFile(module.resolvedFileName);
|
||||
if (!(resolvedFile && resolvedFile.externalModuleIndicator && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace ts.refactor.installTypesForPackage {
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
const d = node as ImportDeclaration;
|
||||
const { importClause } = d;
|
||||
return !importClause.name && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(d.moduleSpecifier)
|
||||
return importClause && !importClause.name && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(d.moduleSpecifier)
|
||||
? { importStatement: d, name: importClause.namedBindings.name, moduleSpecifier: d.moduleSpecifier }
|
||||
: undefined;
|
||||
// For known child node kinds of convertible imports, try again with parent node.
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
function stringToInt(str: string): number {
|
||||
const n = parseInt(str, 10);
|
||||
if (isNaN(n)) {
|
||||
throw new Error(`Error in parseInt(${JSON.stringify(str)})`);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
const isPrereleaseRegex = /^(.*)-next.\d+/;
|
||||
const prereleaseSemverRegex = /^(\d+)\.(\d+)\.0-next.(\d+)$/;
|
||||
const semverRegex = /^(\d+)\.(\d+)\.(\d+)$/;
|
||||
|
||||
export class Semver {
|
||||
static parse(semver: string): Semver {
|
||||
const isPrerelease = isPrereleaseRegex.test(semver);
|
||||
const result = Semver.tryParse(semver, isPrerelease);
|
||||
if (!result) {
|
||||
throw new Error(`Unexpected semver: ${semver} (isPrerelease: ${isPrerelease})`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static fromRaw({ major, minor, patch, isPrerelease }: Semver): Semver {
|
||||
return new Semver(major, minor, patch, isPrerelease);
|
||||
}
|
||||
|
||||
// This must parse the output of `versionString`.
|
||||
private static tryParse(semver: string, isPrerelease: boolean): Semver | undefined {
|
||||
// Per the semver spec <http://semver.org/#spec-item-2>:
|
||||
// "A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes."
|
||||
const rgx = isPrerelease ? prereleaseSemverRegex : semverRegex;
|
||||
const match = rgx.exec(semver);
|
||||
return match ? new Semver(stringToInt(match[1]), stringToInt(match[2]), stringToInt(match[3]), isPrerelease) : undefined;
|
||||
}
|
||||
|
||||
private constructor(
|
||||
readonly major: number, readonly minor: number, readonly patch: number,
|
||||
/**
|
||||
* If true, this is `major.minor.0-next.patch`.
|
||||
* If false, this is `major.minor.patch`.
|
||||
*/
|
||||
readonly isPrerelease: boolean) { }
|
||||
|
||||
get versionString(): string {
|
||||
return this.isPrerelease ? `${this.major}.${this.minor}.0-next.${this.patch}` : `${this.major}.${this.minor}.${this.patch}`;
|
||||
}
|
||||
|
||||
equals(sem: Semver): boolean {
|
||||
return this.major === sem.major && this.minor === sem.minor && this.patch === sem.patch && this.isPrerelease === sem.isPrerelease;
|
||||
}
|
||||
|
||||
greaterThan(sem: Semver): boolean {
|
||||
return this.major > sem.major || this.major === sem.major
|
||||
&& (this.minor > sem.minor || this.minor === sem.minor
|
||||
&& (!this.isPrerelease && sem.isPrerelease || this.isPrerelease === sem.isPrerelease
|
||||
&& this.patch > sem.patch));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ namespace ts {
|
||||
const textPos = scanner.getTextPos();
|
||||
if (textPos <= end) {
|
||||
if (token === SyntaxKind.Identifier) {
|
||||
Debug.fail(`Did not expect ${(ts as any).SyntaxKind[this.kind]} to have an Identifier in its trivia`);
|
||||
Debug.fail(`Did not expect ${Debug.showSyntaxKind(this)} to have an Identifier in its trivia`);
|
||||
}
|
||||
nodes.push(createNode(token, pos, textPos, this));
|
||||
}
|
||||
@@ -1580,7 +1580,7 @@ namespace ts {
|
||||
return results;
|
||||
}
|
||||
|
||||
function getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] {
|
||||
function getDocumentHighlights(fileName: string, position: number, filesToSearch: ReadonlyArray<string>): DocumentHighlights[] {
|
||||
synchronizeHostData();
|
||||
const sourceFilesToSearch = map(filesToSearch, f => Debug.assertDefined(program.getSourceFile(f)));
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
|
||||
+13
-1
@@ -24,6 +24,17 @@ let debugObjectHost: { CollectGarbage(): void } = (function (this: any) { return
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
interface DiscoverTypingsInfo {
|
||||
fileNames: string[]; // The file names that belong to the same project.
|
||||
projectRootPath: string; // The path to the project root directory
|
||||
safeListPath: string; // The path used to retrieve the safe list
|
||||
packageNameToTypingLocation: Map<JsTyping.CachedTyping>; // The map of package names to their cached typing locations and installed versions
|
||||
typeAcquisition: TypeAcquisition; // Used to customize the type acquisition process
|
||||
compilerOptions: CompilerOptions; // Used as a source for typing inference
|
||||
unresolvedImports: ReadonlyArray<string>; // List of unresolved module ids from imports
|
||||
typesRegistry: ReadonlyMap<MapLike<string>>; // The map of available typings in npm to maps of TS versions to their latest supported versions
|
||||
}
|
||||
|
||||
export interface ScriptSnapshotShim {
|
||||
/** Gets a portion of the script snapshot specified by [start, end). */
|
||||
getText(start: number, end: number): string;
|
||||
@@ -1159,7 +1170,8 @@ namespace ts {
|
||||
this.safeList,
|
||||
info.packageNameToTypingLocation,
|
||||
info.typeAcquisition,
|
||||
info.unresolvedImports);
|
||||
info.unresolvedImports,
|
||||
info.typesRegistry);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace ts.SymbolDisplay {
|
||||
switch (location.parent && location.parent.kind) {
|
||||
// If we've typed a character of the attribute name, will be 'JsxAttribute', else will be 'JsxOpeningElement'.
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
return location.kind === SyntaxKind.Identifier ? ScriptElementKind.memberVariableElement : ScriptElementKind.jsxAttribute;
|
||||
case SyntaxKind.JsxAttribute:
|
||||
return ScriptElementKind.jsxAttribute;
|
||||
|
||||
+44
-49
@@ -28,9 +28,11 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
export interface ConfigurableStart {
|
||||
/** True to use getStart() (NB, not getFullStart()) without adjustment. */
|
||||
useNonAdjustedStartPosition?: boolean;
|
||||
}
|
||||
export interface ConfigurableEnd {
|
||||
/** True to use getEnd() without adjustment. */
|
||||
useNonAdjustedEndPosition?: boolean;
|
||||
}
|
||||
|
||||
@@ -70,6 +72,11 @@ namespace ts.textChanges {
|
||||
*/
|
||||
export type ConfigurableStartEnd = ConfigurableStart & ConfigurableEnd;
|
||||
|
||||
export const useNonAdjustedPositions: ConfigurableStartEnd = {
|
||||
useNonAdjustedStartPosition: true,
|
||||
useNonAdjustedEndPosition: true,
|
||||
};
|
||||
|
||||
export interface InsertNodeOptions {
|
||||
/**
|
||||
* Text to be inserted before the new node
|
||||
@@ -117,13 +124,10 @@ namespace ts.textChanges {
|
||||
readonly options?: never;
|
||||
}
|
||||
|
||||
interface ChangeMultipleNodesOptions extends ChangeNodeOptions {
|
||||
nodeSeparator: string;
|
||||
}
|
||||
interface ReplaceWithMultipleNodes extends BaseChange {
|
||||
readonly kind: ChangeKind.ReplaceWithMultipleNodes;
|
||||
readonly nodes: ReadonlyArray<Node>;
|
||||
readonly options?: ChangeMultipleNodesOptions;
|
||||
readonly options?: ChangeNodeOptions;
|
||||
}
|
||||
|
||||
export function getSeparatorCharacter(separator: Token<SyntaxKind.CommaToken | SyntaxKind.SemicolonToken>) {
|
||||
@@ -132,7 +136,7 @@ namespace ts.textChanges {
|
||||
|
||||
export function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: ConfigurableStart, position: Position) {
|
||||
if (options.useNonAdjustedStartPosition) {
|
||||
return node.getFullStart();
|
||||
return node.getStart();
|
||||
}
|
||||
const fullStart = node.getFullStart();
|
||||
const start = node.getStart(sourceFile);
|
||||
@@ -280,51 +284,41 @@ namespace ts.textChanges {
|
||||
return this;
|
||||
}
|
||||
|
||||
public replaceRange(sourceFile: SourceFile, range: TextRange, newNode: Node, options: InsertNodeOptions = {}) {
|
||||
// TODO (https://github.com/Microsoft/TypeScript/issues/21246): default should probably be useNonAdjustedPositions
|
||||
public replaceRange(sourceFile: SourceFile, range: TextRange, newNode: Node, options: ChangeNodeOptions = {}) {
|
||||
this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, range, options, node: newNode });
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO (https://github.com/Microsoft/TypeScript/issues/21246): default should probably be useNonAdjustedPositions
|
||||
public replaceNode(sourceFile: SourceFile, oldNode: Node, newNode: Node, options: ChangeNodeOptions = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, oldNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, oldNode, options);
|
||||
return this.replaceWithSingle(sourceFile, startPosition, endPosition, newNode, options);
|
||||
const pos = getAdjustedStartPosition(sourceFile, oldNode, options, Position.Start);
|
||||
const end = getAdjustedEndPosition(sourceFile, oldNode, options);
|
||||
return this.replaceRange(sourceFile, { pos, end }, newNode, options);
|
||||
}
|
||||
|
||||
// TODO (https://github.com/Microsoft/TypeScript/issues/21246): default should probably be useNonAdjustedPositions
|
||||
public replaceNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, newNode: Node, options: ChangeNodeOptions = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
return this.replaceWithSingle(sourceFile, startPosition, endPosition, newNode, options);
|
||||
const pos = getAdjustedStartPosition(sourceFile, startNode, options, Position.Start);
|
||||
const end = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
return this.replaceRange(sourceFile, { pos, end }, newNode, options);
|
||||
}
|
||||
|
||||
private replaceWithSingle(sourceFile: SourceFile, startPosition: number, endPosition: number, newNode: Node, options: ChangeNodeOptions): this {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
options,
|
||||
node: newNode,
|
||||
range: { pos: startPosition, end: endPosition }
|
||||
});
|
||||
public replaceRangeWithNodes(sourceFile: SourceFile, range: TextRange, newNodes: ReadonlyArray<Node>, options: ChangeNodeOptions = useNonAdjustedPositions) {
|
||||
this.changes.push({ kind: ChangeKind.ReplaceWithMultipleNodes, sourceFile, range, options, nodes: newNodes });
|
||||
return this;
|
||||
}
|
||||
|
||||
private replaceWithMultiple(sourceFile: SourceFile, startPosition: number, endPosition: number, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions): this {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithMultipleNodes,
|
||||
sourceFile,
|
||||
options,
|
||||
nodes: newNodes,
|
||||
range: { pos: startPosition, end: endPosition }
|
||||
});
|
||||
return this;
|
||||
public replaceNodeWithNodes(sourceFile: SourceFile, oldNode: Node, newNodes: ReadonlyArray<Node>, options: ChangeNodeOptions = useNonAdjustedPositions) {
|
||||
const pos = getAdjustedStartPosition(sourceFile, oldNode, options, Position.Start);
|
||||
const end = getAdjustedEndPosition(sourceFile, oldNode, options);
|
||||
return this.replaceRangeWithNodes(sourceFile, { pos, end }, newNodes, options);
|
||||
}
|
||||
|
||||
public replaceNodeWithNodes(sourceFile: SourceFile, oldNode: Node, newNodes: ReadonlyArray<Node>): void {
|
||||
this.replaceWithMultiple(sourceFile, oldNode.getStart(sourceFile), oldNode.getEnd(), newNodes, { nodeSeparator: this.newLineCharacter });
|
||||
}
|
||||
|
||||
public replaceNodesWithNodes(sourceFile: SourceFile, oldNodes: ReadonlyArray<Node>, newNodes: ReadonlyArray<Node>): void {
|
||||
this.replaceWithMultiple(sourceFile, first(oldNodes).getStart(sourceFile), last(oldNodes).getEnd(), newNodes, { nodeSeparator: this.newLineCharacter });
|
||||
public replaceNodeRangeWithNodes(sourceFile: SourceFile, startNode: Node, endNode: Node, newNodes: ReadonlyArray<Node>, options: ChangeNodeOptions = useNonAdjustedPositions) {
|
||||
const pos = getAdjustedStartPosition(sourceFile, startNode, options, Position.Start);
|
||||
const end = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
return this.replaceRangeWithNodes(sourceFile, { pos, end }, newNodes, options);
|
||||
}
|
||||
|
||||
private insertNodeAt(sourceFile: SourceFile, pos: number, newNode: Node, options: InsertNodeOptions = {}) {
|
||||
@@ -341,18 +335,13 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, blankLineBetween = false) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, before, {}, Position.Start);
|
||||
return this.replaceWithSingle(sourceFile, startPosition, startPosition, newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween));
|
||||
const pos = getAdjustedStartPosition(sourceFile, before, {}, Position.Start);
|
||||
return this.replaceRange(sourceFile, { pos, end: pos }, newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween));
|
||||
}
|
||||
|
||||
public insertModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void {
|
||||
const pos = before.getStart(sourceFile);
|
||||
this.replaceWithSingle(sourceFile, pos, pos, createToken(modifier), { suffix: " " });
|
||||
}
|
||||
|
||||
public changeIdentifierToPropertyAccess(sourceFile: SourceFile, prefix: string, node: Identifier): void {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, node, {}, Position.Start);
|
||||
this.replaceWithSingle(sourceFile, startPosition, startPosition, createPropertyAccess(createIdentifier(prefix), ""), {});
|
||||
this.replaceRange(sourceFile, { pos, end: pos }, createToken(modifier), { suffix: " " });
|
||||
}
|
||||
|
||||
private getOptionsForInsertNodeBefore(before: Node, doubleNewlines: boolean): ChangeNodeOptions {
|
||||
@@ -390,8 +379,8 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
public insertNodeAtEndOfScope(sourceFile: SourceFile, scope: Node, newNode: Node): void {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, scope.getLastToken(), {}, Position.Start);
|
||||
this.replaceWithSingle(sourceFile, startPosition, startPosition, newNode, {
|
||||
const pos = getAdjustedStartPosition(sourceFile, scope.getLastToken(), {}, Position.Start);
|
||||
this.replaceRange(sourceFile, { pos, end: pos }, newNode, {
|
||||
prefix: isLineBreak(sourceFile.text.charCodeAt(scope.getLastToken().pos)) ? this.newLineCharacter : this.newLineCharacter + this.newLineCharacter,
|
||||
suffix: this.newLineCharacter
|
||||
});
|
||||
@@ -433,7 +422,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
}
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, after, {});
|
||||
return this.replaceWithSingle(sourceFile, endPosition, endPosition, newNode, this.getInsertNodeAfterOptions(after));
|
||||
return this.replaceRange(sourceFile, { pos: endPosition, end: endPosition }, newNode, this.getInsertNodeAfterOptions(after));
|
||||
}
|
||||
|
||||
private getInsertNodeAfterOptions(node: Node): InsertNodeOptions {
|
||||
@@ -629,7 +618,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
private computeSpan(change: Change, _sourceFile: SourceFile): TextSpan {
|
||||
return createTextSpanFromBounds(change.range.pos, change.range.end);
|
||||
return createTextSpanFromRange(change.range);
|
||||
}
|
||||
|
||||
private computeNewText(change: Change, sourceFile: SourceFile): string {
|
||||
@@ -643,8 +632,14 @@ namespace ts.textChanges {
|
||||
const pos = change.range.pos;
|
||||
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
|
||||
if (change.kind === ChangeKind.ReplaceWithMultipleNodes) {
|
||||
const parts = change.nodes.map(n => this.getFormattedTextOfNode(n, sourceFile, pos, options));
|
||||
text = parts.join(change.options.nodeSeparator);
|
||||
const lastIndex = change.nodes.length - 1;
|
||||
const parts = change.nodes.map((n, index) => {
|
||||
const formatted = this.getFormattedTextOfNode(n, sourceFile, pos, options);
|
||||
return index === lastIndex || endsWith(formatted, this.newLineCharacter)
|
||||
? formatted
|
||||
: (formatted + this.newLineCharacter);
|
||||
});
|
||||
text = parts.join("");
|
||||
}
|
||||
else {
|
||||
Debug.assert(change.kind === ChangeKind.ReplaceWithSingleNode, "change.kind === ReplaceWithSingleNode");
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
"services.ts",
|
||||
"transform.ts",
|
||||
"transpile.ts",
|
||||
"semver.ts",
|
||||
"shims.ts",
|
||||
"signatureHelp.ts",
|
||||
"symbolDisplay.ts",
|
||||
|
||||
+32
-29
@@ -761,23 +761,12 @@ namespace ts {
|
||||
Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result)));
|
||||
return result;
|
||||
|
||||
function findRightmostToken(n: Node): Node {
|
||||
if (isToken(n)) {
|
||||
function find(n: Node): Node | undefined {
|
||||
if (isNonWhitespaceToken(n)) {
|
||||
return n;
|
||||
}
|
||||
|
||||
const children = n.getChildren();
|
||||
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length);
|
||||
return candidate && findRightmostToken(candidate);
|
||||
|
||||
}
|
||||
|
||||
function find(n: Node): Node {
|
||||
if (isToken(n)) {
|
||||
return n;
|
||||
}
|
||||
|
||||
const children = n.getChildren();
|
||||
const children = n.getChildren(sourceFile);
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
// Note that the span of a node's tokens is [node.getStart(...), node.end).
|
||||
@@ -795,7 +784,7 @@ namespace ts {
|
||||
if (lookInPreviousChild) {
|
||||
// actual start of the node is past the position - previous token should be at the end of previous child
|
||||
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i);
|
||||
return candidate && findRightmostToken(candidate);
|
||||
return candidate && findRightmostToken(candidate, sourceFile);
|
||||
}
|
||||
else {
|
||||
// candidate should be in this node
|
||||
@@ -812,23 +801,37 @@ namespace ts {
|
||||
// Namely we are skipping the check: 'position < node.end'
|
||||
if (children.length) {
|
||||
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length);
|
||||
return candidate && findRightmostToken(candidate);
|
||||
return candidate && findRightmostToken(candidate, sourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens.
|
||||
*/
|
||||
function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node {
|
||||
for (let i = exclusiveStartPosition - 1; i >= 0; i--) {
|
||||
const child = children[i];
|
||||
function isNonWhitespaceToken(n: Node): boolean {
|
||||
return isToken(n) && !isWhiteSpaceOnlyJsxText(n);
|
||||
}
|
||||
|
||||
if (isWhiteSpaceOnlyJsxText(child)) {
|
||||
Debug.assert(i > 0, "`JsxText` tokens should not be the first child of `JsxElement | JsxSelfClosingElement`");
|
||||
}
|
||||
else if (nodeHasTokens(children[i])) {
|
||||
return children[i];
|
||||
}
|
||||
function findRightmostToken(n: Node, sourceFile: SourceFile): Node | undefined {
|
||||
if (isNonWhitespaceToken(n)) {
|
||||
return n;
|
||||
}
|
||||
|
||||
const children = n.getChildren(sourceFile);
|
||||
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length);
|
||||
return candidate && findRightmostToken(candidate, sourceFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens.
|
||||
*/
|
||||
function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node | undefined {
|
||||
for (let i = exclusiveStartPosition - 1; i >= 0; i--) {
|
||||
const child = children[i];
|
||||
|
||||
if (isWhiteSpaceOnlyJsxText(child)) {
|
||||
Debug.assert(i > 0, "`JsxText` tokens should not be the first child of `JsxElement | JsxSelfClosingElement`");
|
||||
}
|
||||
else if (nodeHasTokens(children[i])) {
|
||||
return children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -893,7 +896,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isWhiteSpaceOnlyJsxText(node: Node): node is JsxText {
|
||||
function isWhiteSpaceOnlyJsxText(node: Node): boolean {
|
||||
return isJsxText(node) && node.containsOnlyWhiteSpaces;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,5 +3,8 @@ class C {
|
||||
>C : Symbol(C, Decl(ClassDeclaration21.ts, 0, 0))
|
||||
|
||||
0();
|
||||
>0 : Symbol(C[0], Decl(ClassDeclaration21.ts, 0, 9))
|
||||
|
||||
1() { }
|
||||
>1 : Symbol(C[1], Decl(ClassDeclaration21.ts, 1, 8))
|
||||
}
|
||||
|
||||
@@ -3,5 +3,8 @@ class C {
|
||||
>C : C
|
||||
|
||||
0();
|
||||
>0 : () => any
|
||||
|
||||
1() { }
|
||||
>1 : () => void
|
||||
}
|
||||
|
||||
@@ -3,5 +3,8 @@ class C {
|
||||
>C : Symbol(C, Decl(ClassDeclaration22.ts, 0, 0))
|
||||
|
||||
"foo"();
|
||||
>"foo" : Symbol(C["foo"], Decl(ClassDeclaration22.ts, 0, 9))
|
||||
|
||||
"bar"() { }
|
||||
>"bar" : Symbol(C["bar"], Decl(ClassDeclaration22.ts, 1, 12))
|
||||
}
|
||||
|
||||
@@ -3,5 +3,8 @@ class C {
|
||||
>C : C
|
||||
|
||||
"foo"();
|
||||
>"foo" : () => any
|
||||
|
||||
"bar"() { }
|
||||
>"bar" : () => void
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ export class C {
|
||||
}
|
||||
|
||||
export = B;
|
||||
>B : No type information available!
|
||||
>B : any
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
=== tests/cases/compiler/ExportAssignment8.ts ===
|
||||
export = B;
|
||||
>B : No type information available!
|
||||
>B : any
|
||||
|
||||
export class C {
|
||||
>C : C
|
||||
|
||||
@@ -28,31 +28,31 @@ import beez = foo.bar;
|
||||
|
||||
import m = no;
|
||||
>m : any
|
||||
>no : No type information available!
|
||||
>no : any
|
||||
|
||||
import m2 = no.mod;
|
||||
>m2 : any
|
||||
>no : No type information available!
|
||||
>mod : No type information available!
|
||||
>no : any
|
||||
>mod : any
|
||||
|
||||
import n = 5;
|
||||
>n : any
|
||||
> : No type information available!
|
||||
> : any
|
||||
>5 : 5
|
||||
|
||||
import o = "s";
|
||||
>o : any
|
||||
> : No type information available!
|
||||
> : any
|
||||
>"s" : "s"
|
||||
|
||||
import q = null;
|
||||
>q : any
|
||||
> : No type information available!
|
||||
> : any
|
||||
>null : null
|
||||
|
||||
import r = undefined;
|
||||
>r : any
|
||||
>undefined : No type information available!
|
||||
>undefined : any
|
||||
|
||||
|
||||
var p = new provide.Provide();
|
||||
|
||||
@@ -19,6 +19,7 @@ var x: foo.A = foo.bar("hello"); // foo.A should be ok but foo.bar should be err
|
||||
|
||||
=== tests/cases/compiler/aliasOnMergedModuleInterface_0.ts ===
|
||||
declare module "foo"
|
||||
>"foo" : Symbol("foo", Decl(aliasOnMergedModuleInterface_0.ts, 0, 0))
|
||||
{
|
||||
module B {
|
||||
>B : Symbol(B, Decl(aliasOnMergedModuleInterface_0.ts, 1, 1), Decl(aliasOnMergedModuleInterface_0.ts, 5, 5))
|
||||
|
||||
@@ -26,6 +26,7 @@ var x: foo.A = foo.bar("hello"); // foo.A should be ok but foo.bar should be err
|
||||
|
||||
=== tests/cases/compiler/aliasOnMergedModuleInterface_0.ts ===
|
||||
declare module "foo"
|
||||
>"foo" : typeof "foo"
|
||||
{
|
||||
module B {
|
||||
>B : any
|
||||
|
||||
@@ -160,6 +160,8 @@ var q = M1.fn();
|
||||
// Ambient external module in the global module
|
||||
// Ambient external module with a string literal name that is a top level external module name
|
||||
declare module 'external1' {
|
||||
>'external1' : Symbol('external1', Decl(ambientDeclarations.ts, 67, 16))
|
||||
|
||||
var q;
|
||||
>q : Symbol(q, Decl(ambientDeclarations.ts, 72, 7))
|
||||
}
|
||||
|
||||
@@ -163,6 +163,8 @@ var q = M1.fn();
|
||||
// Ambient external module in the global module
|
||||
// Ambient external module with a string literal name that is a top level external module name
|
||||
declare module 'external1' {
|
||||
>'external1' : typeof 'external1'
|
||||
|
||||
var q;
|
||||
>q : any
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ var n: number;
|
||||
=== tests/cases/conformance/ambient/decls.ts ===
|
||||
// Ambient external module with export assignment
|
||||
declare module 'equ' {
|
||||
>'equ' : Symbol('equ', Decl(decls.ts, 0, 0))
|
||||
|
||||
var x;
|
||||
>x : Symbol(x, Decl(decls.ts, 2, 7))
|
||||
|
||||
@@ -28,6 +30,8 @@ declare module 'equ' {
|
||||
}
|
||||
|
||||
declare module 'equ2' {
|
||||
>'equ2' : Symbol('equ2', Decl(decls.ts, 4, 1))
|
||||
|
||||
var x: number;
|
||||
>x : Symbol(x, Decl(decls.ts, 7, 7))
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ var n: number;
|
||||
=== tests/cases/conformance/ambient/decls.ts ===
|
||||
// Ambient external module with export assignment
|
||||
declare module 'equ' {
|
||||
>'equ' : typeof 'equ'
|
||||
|
||||
var x;
|
||||
>x : any
|
||||
|
||||
@@ -28,6 +30,8 @@ declare module 'equ' {
|
||||
}
|
||||
|
||||
declare module 'equ2' {
|
||||
>'equ2' : typeof 'equ2'
|
||||
|
||||
var x: number;
|
||||
>x : number
|
||||
}
|
||||
|
||||
@@ -25,23 +25,31 @@ foo(fileText);
|
||||
|
||||
=== tests/cases/conformance/ambient/declarations.d.ts ===
|
||||
declare module "foo*baz" {
|
||||
>"foo*baz" : Symbol("foo*baz", Decl(declarations.d.ts, 0, 0), Decl(declarations.d.ts, 2, 1))
|
||||
|
||||
export function foo(s: string): void;
|
||||
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 26))
|
||||
>s : Symbol(s, Decl(declarations.d.ts, 1, 24))
|
||||
}
|
||||
// Augmentations still work
|
||||
declare module "foo*baz" {
|
||||
>"foo*baz" : Symbol("foo*baz", Decl(declarations.d.ts, 0, 0), Decl(declarations.d.ts, 2, 1))
|
||||
|
||||
export const baz: string;
|
||||
>baz : Symbol(baz, Decl(declarations.d.ts, 5, 16))
|
||||
}
|
||||
|
||||
// Longest prefix wins
|
||||
declare module "foos*" {
|
||||
>"foos*" : Symbol("foos*", Decl(declarations.d.ts, 6, 1))
|
||||
|
||||
export const foos: string;
|
||||
>foos : Symbol(foos, Decl(declarations.d.ts, 10, 16))
|
||||
}
|
||||
|
||||
declare module "*!text" {
|
||||
>"*!text" : Symbol("*!text", Decl(declarations.d.ts, 11, 1))
|
||||
|
||||
const x: string;
|
||||
>x : Symbol(x, Decl(declarations.d.ts, 14, 9))
|
||||
|
||||
|
||||
@@ -28,23 +28,31 @@ foo(fileText);
|
||||
|
||||
=== tests/cases/conformance/ambient/declarations.d.ts ===
|
||||
declare module "foo*baz" {
|
||||
>"foo*baz" : typeof "foo*baz"
|
||||
|
||||
export function foo(s: string): void;
|
||||
>foo : (s: string) => void
|
||||
>s : string
|
||||
}
|
||||
// Augmentations still work
|
||||
declare module "foo*baz" {
|
||||
>"foo*baz" : typeof "foo*baz"
|
||||
|
||||
export const baz: string;
|
||||
>baz : string
|
||||
}
|
||||
|
||||
// Longest prefix wins
|
||||
declare module "foos*" {
|
||||
>"foos*" : typeof "foos*"
|
||||
|
||||
export const foos: string;
|
||||
>foos : string
|
||||
}
|
||||
|
||||
declare module "*!text" {
|
||||
>"*!text" : typeof "*!text"
|
||||
|
||||
const x: string;
|
||||
>x : string
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=== tests/cases/conformance/ambient/ambientDeclarationsPatterns_tooManyAsterisks.ts ===
|
||||
declare module "too*many*asterisks" { }
|
||||
No type information for this code.
|
||||
No type information for this code.
|
||||
>"too*many*asterisks" : Symbol("too*many*asterisks", Decl(ambientDeclarationsPatterns_tooManyAsterisks.ts, 0, 0))
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
=== tests/cases/conformance/ambient/ambientDeclarationsPatterns_tooManyAsterisks.ts ===
|
||||
declare module "too*many*asterisks" { }
|
||||
No type information for this code.
|
||||
No type information for this code.
|
||||
>"too*many*asterisks" : typeof "too*many*asterisks"
|
||||
|
||||
|
||||
@@ -90,13 +90,17 @@ module M2 {
|
||||
>M2 : Symbol(M2, Decl(ambientErrors.ts, 42, 1))
|
||||
|
||||
declare module 'nope' { }
|
||||
>'nope' : Symbol('nope', Decl(ambientErrors.ts, 45, 11))
|
||||
}
|
||||
|
||||
// Ambient external module with a string literal name that isn't a top level external module name
|
||||
declare module '../foo' { }
|
||||
>'../foo' : Symbol('../foo', Decl(ambientErrors.ts, 47, 1))
|
||||
|
||||
// Ambient external module with export assignment and other exported members
|
||||
declare module 'bar' {
|
||||
>'bar' : Symbol('bar', Decl(ambientErrors.ts, 50, 27))
|
||||
|
||||
var n;
|
||||
>n : Symbol(n, Decl(ambientErrors.ts, 54, 7))
|
||||
|
||||
|
||||
@@ -97,13 +97,17 @@ module M2 {
|
||||
>M2 : any
|
||||
|
||||
declare module 'nope' { }
|
||||
>'nope' : typeof 'nope'
|
||||
}
|
||||
|
||||
// Ambient external module with a string literal name that isn't a top level external module name
|
||||
declare module '../foo' { }
|
||||
>'../foo' : typeof '../foo'
|
||||
|
||||
// Ambient external module with export assignment and other exported members
|
||||
declare module 'bar' {
|
||||
>'bar' : typeof 'bar'
|
||||
|
||||
var n;
|
||||
>n : any
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ export as namespace Foo2;
|
||||
=== tests/cases/compiler/indirection.d.ts ===
|
||||
/// <reference path="./foo.d.ts" />
|
||||
declare module "indirect" {
|
||||
>"indirect" : Symbol("indirect", Decl(indirection.d.ts, 0, 0))
|
||||
|
||||
export default typeof Foo.default;
|
||||
>Foo.default : Symbol(Foo.default, Decl(foo.d.ts, 0, 0))
|
||||
>Foo : Symbol(Foo, Decl(foo.d.ts, 0, 21))
|
||||
@@ -27,6 +29,8 @@ declare module "indirect" {
|
||||
=== tests/cases/compiler/indirection2.d.ts ===
|
||||
/// <reference path="./foo2.d.ts" />
|
||||
declare module "indirect2" {
|
||||
>"indirect2" : Symbol("indirect2", Decl(indirection2.d.ts, 0, 0))
|
||||
|
||||
export = typeof Foo2;
|
||||
>Foo2 : Symbol(Foo2, Decl(foo2.d.ts, 0, 15))
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ export as namespace Foo2;
|
||||
=== tests/cases/compiler/indirection.d.ts ===
|
||||
/// <reference path="./foo.d.ts" />
|
||||
declare module "indirect" {
|
||||
>"indirect" : typeof "indirect"
|
||||
|
||||
export default typeof Foo.default;
|
||||
>typeof Foo.default : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>Foo.default : number
|
||||
@@ -36,6 +38,8 @@ declare module "indirect" {
|
||||
=== tests/cases/compiler/indirection2.d.ts ===
|
||||
/// <reference path="./foo2.d.ts" />
|
||||
declare module "indirect2" {
|
||||
>"indirect2" : typeof "indirect2"
|
||||
|
||||
export = typeof Foo2;
|
||||
>typeof Foo2 : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>Foo2 : number
|
||||
|
||||
@@ -6,6 +6,8 @@ export = D;
|
||||
>D : Symbol(D, Decl(ambientExternalModuleInAnotherExternalModule.ts, 0, 0))
|
||||
|
||||
declare module "ext" {
|
||||
>"ext" : Symbol("ext", Decl(ambientExternalModuleInAnotherExternalModule.ts, 1, 11))
|
||||
|
||||
export class C { }
|
||||
>C : Symbol(C, Decl(ambientExternalModuleInAnotherExternalModule.ts, 3, 22))
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ export = D;
|
||||
>D : D
|
||||
|
||||
declare module "ext" {
|
||||
>"ext" : typeof "ext"
|
||||
|
||||
export class C { }
|
||||
>C : C
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ module M {
|
||||
>M : Symbol(M, Decl(ambientExternalModuleInsideNonAmbient.ts, 0, 0))
|
||||
|
||||
export declare module "M" { }
|
||||
>"M" : Symbol("M", Decl(ambientExternalModuleInsideNonAmbient.ts, 0, 10))
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ module M {
|
||||
>M : any
|
||||
|
||||
export declare module "M" { }
|
||||
>"M" : typeof "M"
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
=== tests/cases/conformance/ambient/ambientExternalModuleInsideNonAmbientExternalModule.ts ===
|
||||
export declare module "M" { }
|
||||
No type information for this code.
|
||||
>"M" : Symbol("M", Decl(ambientExternalModuleInsideNonAmbientExternalModule.ts, 0, 0))
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user