mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' of https://github.com/Microsoft/TypeScript into feature/eslint
This commit is contained in:
+10
-11
@@ -3229,8 +3229,7 @@ namespace ts {
|
||||
// A ClassDeclaration is ES6 syntax.
|
||||
transformFlags = subtreeFlags | TransformFlags.AssertES2015;
|
||||
|
||||
// A class with a parameter property assignment, property initializer, computed property name, or decorator is
|
||||
// TypeScript syntax.
|
||||
// A class with a parameter property assignment or decorator is TypeScript syntax.
|
||||
// An exported declaration may be TypeScript syntax, but is handled by the visitor
|
||||
// for a namespace declaration.
|
||||
if ((subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax)
|
||||
@@ -3247,8 +3246,7 @@ namespace ts {
|
||||
// A ClassExpression is ES6 syntax.
|
||||
let transformFlags = subtreeFlags | TransformFlags.AssertES2015;
|
||||
|
||||
// A class with a parameter property assignment, property initializer, or decorator is
|
||||
// TypeScript syntax.
|
||||
// A class with a parameter property assignment or decorator is TypeScript syntax.
|
||||
if (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax
|
||||
|| node.typeParameters) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
@@ -3338,7 +3336,6 @@ namespace ts {
|
||||
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
|
||||
|| node.typeParameters
|
||||
|| node.type
|
||||
|| (node.name && isComputedPropertyName(node.name)) // While computed method names aren't typescript, the TS transform must visit them to emit property declarations correctly
|
||||
|| !node.body) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
@@ -3369,7 +3366,6 @@ namespace ts {
|
||||
if (node.decorators
|
||||
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
|
||||
|| node.type
|
||||
|| (node.name && isComputedPropertyName(node.name)) // While computed accessor names aren't typescript, the TS transform must visit them to emit property declarations correctly
|
||||
|| !node.body) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
@@ -3384,12 +3380,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) {
|
||||
// A PropertyDeclaration is TypeScript syntax.
|
||||
let transformFlags = subtreeFlags | TransformFlags.AssertTypeScript;
|
||||
let transformFlags = subtreeFlags | TransformFlags.ContainsClassFields;
|
||||
|
||||
// If the PropertyDeclaration has an initializer or a computed name, we need to inform its ancestor
|
||||
// so that it handle the transformation.
|
||||
if (node.initializer || isComputedPropertyName(node.name)) {
|
||||
// Decorators, TypeScript-specific modifiers, and type annotations are TypeScript syntax.
|
||||
if (some(node.decorators) || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
// Hoisted variables related to class properties should live within the TypeScript class wrapper.
|
||||
if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) {
|
||||
transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax;
|
||||
}
|
||||
|
||||
|
||||
@@ -4990,7 +4990,10 @@
|
||||
"category": "Message",
|
||||
"code": 95079
|
||||
},
|
||||
|
||||
"Infer 'this' type of '{0}' from usage": {
|
||||
"category": "Message",
|
||||
"code": 95080
|
||||
},
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
"code": 18004
|
||||
|
||||
@@ -2204,6 +2204,13 @@ namespace ts {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createJSDocThisTag(typeExpression?: JSDocTypeExpression): JSDocThisTag {
|
||||
const tag = createJSDocTag<JSDocThisTag>(SyntaxKind.JSDocThisTag, "this");
|
||||
tag.typeExpression = typeExpression;
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
|
||||
const tag = createJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param");
|
||||
@@ -3119,6 +3126,18 @@ namespace ts {
|
||||
return node.emitNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets `EmitFlags.NoComments` on a node and removes any leading and trailing synthetic comments.
|
||||
* @internal
|
||||
*/
|
||||
export function removeAllComments<T extends Node>(node: T): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.flags |= EmitFlags.NoComments;
|
||||
emitNode.leadingComments = undefined;
|
||||
emitNode.trailingComments = undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function setTextRange<T extends TextRange>(range: T, location: TextRange | undefined): T {
|
||||
if (location) {
|
||||
range.pos = location.pos;
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace ts {
|
||||
addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory));
|
||||
|
||||
transformers.push(transformTypeScript);
|
||||
transformers.push(transformClassFields);
|
||||
|
||||
if (jsx === JsxEmit.React) {
|
||||
transformers.push(transformJsx);
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
const enum ClassPropertySubstitutionFlags {
|
||||
/**
|
||||
* Enables substitutions for class expressions with static fields
|
||||
* which have initializers that reference the class name.
|
||||
*/
|
||||
ClassAliases = 1 << 0,
|
||||
}
|
||||
/**
|
||||
* Transforms ECMAScript Class Syntax.
|
||||
* TypeScript parameter property syntax is transformed in the TypeScript transformer.
|
||||
* For now, this transforms public field declarations using TypeScript class semantics
|
||||
* (where the declarations get elided and initializers are transformed as assignments in the constructor).
|
||||
* Eventually, this transform will change to the ECMAScript semantics (with Object.defineProperty).
|
||||
*/
|
||||
export function transformClassFields(context: TransformationContext) {
|
||||
const {
|
||||
hoistVariableDeclaration,
|
||||
endLexicalEnvironment,
|
||||
resumeLexicalEnvironment
|
||||
} = context;
|
||||
const resolver = context.getEmitResolver();
|
||||
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
|
||||
let enabledSubstitutions: ClassPropertySubstitutionFlags;
|
||||
|
||||
let classAliases: Identifier[];
|
||||
|
||||
/**
|
||||
* Tracks what computed name expressions originating from elided names must be inlined
|
||||
* at the next execution site, in document order
|
||||
*/
|
||||
let pendingExpressions: Expression[] | undefined;
|
||||
|
||||
/**
|
||||
* Tracks what computed name expression statements and static property initializers must be
|
||||
* emitted at the next execution site, in document order (for decorated classes).
|
||||
*/
|
||||
let pendingStatements: Statement[] | undefined;
|
||||
|
||||
return chainBundle(transformSourceFile);
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
return visited;
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if (!(node.transformFlags & TransformFlags.ContainsClassFields)) return node;
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassExpression:
|
||||
return visitClassExpression(node as ClassExpression);
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return visitClassDeclaration(node as ClassDeclaration);
|
||||
case SyntaxKind.VariableStatement:
|
||||
return visitVariableStatement(node as VariableStatement);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the members of a class that has fields.
|
||||
*
|
||||
* @param node The node to visit.
|
||||
*/
|
||||
function classElementVisitor(node: Node): VisitResult<Node> {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
// Constructors for classes using class fields are transformed in
|
||||
// `visitClassDeclaration` or `visitClassExpression`.
|
||||
return undefined;
|
||||
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
// Visit the name of the member (if it's a computed property name).
|
||||
return visitEachChild(node, classElementVisitor, context);
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return visitPropertyDeclaration(node as PropertyDeclaration);
|
||||
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
return visitComputedPropertyName(node as ComputedPropertyName);
|
||||
|
||||
case SyntaxKind.SemicolonClassElement:
|
||||
return node;
|
||||
|
||||
default:
|
||||
return visitor(node);
|
||||
}
|
||||
}
|
||||
|
||||
function visitVariableStatement(node: VariableStatement) {
|
||||
const savedPendingStatements = pendingStatements;
|
||||
pendingStatements = [];
|
||||
|
||||
const visitedNode = visitEachChild(node, visitor, context);
|
||||
const statement = some(pendingStatements) ?
|
||||
[visitedNode, ...pendingStatements] :
|
||||
visitedNode;
|
||||
|
||||
pendingStatements = savedPendingStatements;
|
||||
return statement;
|
||||
}
|
||||
|
||||
function visitComputedPropertyName(name: ComputedPropertyName) {
|
||||
let node = visitEachChild(name, visitor, context);
|
||||
if (some(pendingExpressions)) {
|
||||
const expressions = pendingExpressions;
|
||||
expressions.push(name.expression);
|
||||
pendingExpressions = [];
|
||||
node = updateComputedPropertyName(
|
||||
node,
|
||||
inlineExpressions(expressions)
|
||||
);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitPropertyDeclaration(node: PropertyDeclaration) {
|
||||
Debug.assert(!some(node.decorators));
|
||||
// Create a temporary variable to store a computed property name (if necessary).
|
||||
// If it's not inlineable, then we emit an expression after the class which assigns
|
||||
// the property name to the temporary variable.
|
||||
const expr = getPropertyNameExpressionIfNeeded(node.name, !!node.initializer);
|
||||
if (expr && !isSimpleInlineableExpression(expr)) {
|
||||
(pendingExpressions || (pendingExpressions = [])).push(expr);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function visitClassDeclaration(node: ClassDeclaration) {
|
||||
if (!forEach(node.members, isPropertyDeclaration)) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined!;
|
||||
|
||||
const extendsClauseElement = getEffectiveBaseTypeNode(node);
|
||||
const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword);
|
||||
|
||||
const statements: Statement[] = [
|
||||
updateClassDeclaration(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
node.modifiers,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node, isDerivedClass)
|
||||
)
|
||||
];
|
||||
|
||||
// Write any pending expressions from elided or moved computed property names
|
||||
if (some(pendingExpressions)) {
|
||||
statements.push(createExpressionStatement(inlineExpressions(pendingExpressions)));
|
||||
}
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
|
||||
// Emit static property assignment. Because classDeclaration is lexically evaluated,
|
||||
// it is safe to emit static property assignment after classDeclaration
|
||||
// From ES6 specification:
|
||||
// HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using
|
||||
// a lexical declaration such as a LexicalDeclaration or a ClassDeclaration.
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
if (some(staticProperties)) {
|
||||
addInitializedPropertyStatements(statements, staticProperties, getInternalName(node));
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
function visitClassExpression(node: ClassExpression): Expression {
|
||||
if (!forEach(node.members, isPropertyDeclaration)) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined;
|
||||
|
||||
// If this class expression is a transformation of a decorated class declaration,
|
||||
// then we want to output the pendingExpressions as statements, not as inlined
|
||||
// expressions with the class statement.
|
||||
//
|
||||
// In this case, we use pendingStatements to produce the same output as the
|
||||
// class declaration transformation. The VariableStatement visitor will insert
|
||||
// these statements after the class expression variable statement.
|
||||
const isDecoratedClassDeclaration = isClassDeclaration(getOriginalNode(node));
|
||||
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const extendsClauseElement = getEffectiveBaseTypeNode(node);
|
||||
const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword);
|
||||
|
||||
const classExpression = updateClassExpression(
|
||||
node,
|
||||
node.modifiers,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node, isDerivedClass)
|
||||
);
|
||||
|
||||
if (some(staticProperties) || some(pendingExpressions)) {
|
||||
if (isDecoratedClassDeclaration) {
|
||||
Debug.assertDefined(pendingStatements, "Decorated classes transformed by TypeScript are expected to be within a variable declaration.");
|
||||
|
||||
// Write any pending expressions from elided or moved computed property names
|
||||
if (pendingStatements && pendingExpressions && some(pendingExpressions)) {
|
||||
pendingStatements.push(createExpressionStatement(inlineExpressions(pendingExpressions)));
|
||||
}
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
|
||||
if (pendingStatements && some(staticProperties)) {
|
||||
addInitializedPropertyStatements(pendingStatements, staticProperties, getInternalName(node));
|
||||
}
|
||||
return classExpression;
|
||||
}
|
||||
else {
|
||||
const expressions: Expression[] = [];
|
||||
const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference;
|
||||
const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference);
|
||||
if (isClassWithConstructorReference) {
|
||||
// record an alias as the class name is not in scope for statics.
|
||||
enableSubstitutionForClassAliases();
|
||||
const alias = getSynthesizedClone(temp);
|
||||
alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes;
|
||||
classAliases[getOriginalNodeId(node)] = alias;
|
||||
}
|
||||
|
||||
// To preserve the behavior of the old emitter, we explicitly indent
|
||||
// the body of a class with static initializers.
|
||||
setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression));
|
||||
expressions.push(startOnNewLine(createAssignment(temp, classExpression)));
|
||||
// Add any pending expressions leftover from elided or relocated computed property names
|
||||
addRange(expressions, map(pendingExpressions, startOnNewLine));
|
||||
addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp));
|
||||
expressions.push(startOnNewLine(temp));
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
return inlineExpressions(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
return classExpression;
|
||||
}
|
||||
|
||||
function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
const members: ClassElement[] = [];
|
||||
const constructor = transformConstructor(node, isDerivedClass);
|
||||
if (constructor) {
|
||||
members.push(constructor);
|
||||
}
|
||||
addRange(members, visitNodes(node.members, classElementVisitor, isClassElement));
|
||||
return setTextRange(createNodeArray(members), /*location*/ node.members);
|
||||
}
|
||||
|
||||
function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
const constructor = visitNode(getFirstConstructorWithBody(node), visitor, isConstructorDeclaration);
|
||||
const containsPropertyInitializer = forEach(node.members, isInitializedProperty);
|
||||
if (!containsPropertyInitializer) {
|
||||
return constructor;
|
||||
}
|
||||
const parameters = visitParameterList(constructor ? constructor.parameters : undefined, visitor, context);
|
||||
const body = transformConstructorBody(node, constructor, isDerivedClass);
|
||||
if (!body) {
|
||||
return undefined;
|
||||
}
|
||||
return startOnNewLine(
|
||||
setOriginalNode(
|
||||
setTextRange(
|
||||
createConstructor(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
parameters,
|
||||
body
|
||||
),
|
||||
constructor || node
|
||||
),
|
||||
constructor
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function transformConstructorBody(node: ClassDeclaration | ClassExpression, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) {
|
||||
const properties = getInitializedProperties(node, /*isStatic*/ false);
|
||||
|
||||
// Only generate synthetic constructor when there are property initializers to move.
|
||||
if (!constructor && !some(properties)) {
|
||||
return visitFunctionBody(/*node*/ undefined, visitor, context);
|
||||
}
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
let indexOfFirstStatement = 0;
|
||||
let statements: Statement[] = [];
|
||||
|
||||
if (!constructor && isDerivedClass) {
|
||||
// Add a synthetic `super` call:
|
||||
//
|
||||
// super(...arguments);
|
||||
//
|
||||
statements.push(
|
||||
createExpressionStatement(
|
||||
createCall(
|
||||
createSuper(),
|
||||
/*typeArguments*/ undefined,
|
||||
[createSpread(createIdentifier("arguments"))]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (constructor) {
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor);
|
||||
}
|
||||
|
||||
// Add the property initializers. Transforms this:
|
||||
//
|
||||
// public x = 1;
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor() {
|
||||
// this.x = 1;
|
||||
// }
|
||||
//
|
||||
if (constructor && constructor.body) {
|
||||
let parameterPropertyDeclarationCount = 0;
|
||||
for (let i = indexOfFirstStatement; i < constructor.body.statements.length; i++) {
|
||||
if (isParameterPropertyDeclaration(getOriginalNode(constructor.body.statements[i]))) {
|
||||
parameterPropertyDeclarationCount++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterPropertyDeclarationCount > 0) {
|
||||
addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, indexOfFirstStatement, parameterPropertyDeclarationCount));
|
||||
indexOfFirstStatement += parameterPropertyDeclarationCount;
|
||||
}
|
||||
}
|
||||
addInitializedPropertyStatements(statements, properties, createThis());
|
||||
|
||||
// Add existing statements, skipping the initial super call.
|
||||
if (constructor) {
|
||||
addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement));
|
||||
}
|
||||
|
||||
statements = mergeLexicalEnvironment(statements, endLexicalEnvironment());
|
||||
|
||||
return setTextRange(
|
||||
createBlock(
|
||||
setTextRange(
|
||||
createNodeArray(statements),
|
||||
/*location*/ constructor ? constructor.body!.statements : node.members
|
||||
),
|
||||
/*multiLine*/ true
|
||||
),
|
||||
/*location*/ constructor ? constructor.body : undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment statements for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
for (const property of properties) {
|
||||
const statement = createExpressionStatement(transformInitializedProperty(property, receiver));
|
||||
setSourceMapRange(statement, moveRangePastModifiers(property));
|
||||
setCommentRange(statement, property);
|
||||
setOriginalNode(statement, property);
|
||||
statements.push(statement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment expressions for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function generateInitializedPropertyExpressions(properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
const expressions: Expression[] = [];
|
||||
for (const property of properties) {
|
||||
const expression = transformInitializedProperty(property, receiver);
|
||||
startOnNewLine(expression);
|
||||
setSourceMapRange(expression, moveRangePastModifiers(property));
|
||||
setCommentRange(expression, property);
|
||||
setOriginalNode(expression, property);
|
||||
expressions.push(expression);
|
||||
}
|
||||
|
||||
return expressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a property initializer into an assignment statement.
|
||||
*
|
||||
* @param property The property declaration.
|
||||
* @param receiver The object receiving the property assignment.
|
||||
*/
|
||||
function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) {
|
||||
// We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name)
|
||||
const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression)
|
||||
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name))
|
||||
: property.name;
|
||||
const initializer = visitNode(property.initializer, visitor, isExpression);
|
||||
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
|
||||
|
||||
return createAssignment(memberAccess, initializer);
|
||||
}
|
||||
|
||||
function enableSubstitutionForClassAliases() {
|
||||
if ((enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) === 0) {
|
||||
enabledSubstitutions |= ClassPropertySubstitutionFlags.ClassAliases;
|
||||
|
||||
// We need to enable substitutions for identifiers. This allows us to
|
||||
// substitute class names inside of a class declaration.
|
||||
context.enableSubstitution(SyntaxKind.Identifier);
|
||||
|
||||
// Keep track of class aliases.
|
||||
classAliases = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks node substitutions.
|
||||
*
|
||||
* @param hint The context for the emitter.
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function onSubstituteNode(hint: EmitHint, node: Node) {
|
||||
node = previousOnSubstituteNode(hint, node);
|
||||
if (hint === EmitHint.Expression) {
|
||||
return substituteExpression(node as Expression);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function substituteExpression(node: Expression) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return substituteExpressionIdentifier(node as Identifier);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||
return trySubstituteClassAlias(node) || node;
|
||||
}
|
||||
|
||||
function trySubstituteClassAlias(node: Identifier): Expression | undefined {
|
||||
if (enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) {
|
||||
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ConstructorReferenceInClass) {
|
||||
// Due to the emit for class decorators, any reference to the class from inside of the class body
|
||||
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
|
||||
// behavior of class names in ES6.
|
||||
// Also, when emitting statics for class expressions, we must substitute a class alias for
|
||||
// constructor references in static property initializers.
|
||||
const declaration = resolver.getReferencedValueDeclaration(node);
|
||||
if (declaration) {
|
||||
const classAlias = classAliases[declaration.id!]; // TODO: GH#18217
|
||||
if (classAlias) {
|
||||
const clone = getSynthesizedClone(classAlias);
|
||||
setSourceMapRange(clone, node);
|
||||
setCommentRange(clone, node);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the name is a computed property, this function transforms it, then either returns an expression which caches the
|
||||
* value of the result or the expression itself if the value is either unused or safe to inline into multiple locations
|
||||
* @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator)
|
||||
*/
|
||||
function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean): Expression | undefined {
|
||||
if (isComputedPropertyName(name)) {
|
||||
const expression = visitNode(name.expression, visitor, isExpression);
|
||||
const innerExpression = skipPartiallyEmittedExpressions(expression);
|
||||
const inlinable = isSimpleInlineableExpression(innerExpression);
|
||||
const alreadyTransformed = isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left);
|
||||
if (!alreadyTransformed && !inlinable && shouldHoist) {
|
||||
const generatedName = getGeneratedNameForNode(name);
|
||||
hoistVariableDeclaration(generatedName);
|
||||
return createAssignment(generatedName, expression);
|
||||
}
|
||||
return (inlinable || isIdentifier(innerExpression)) ? undefined : expression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1567,7 +1567,7 @@ namespace ts {
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.failBadSyntaxKind(node);
|
||||
Debug.failBadSyntaxKind(member, currentSourceFile && currentSourceFile.fileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+146
-446
@@ -64,6 +64,7 @@ namespace ts {
|
||||
let currentLexicalScope: SourceFile | Block | ModuleBlock | CaseBlock;
|
||||
let currentNameScope: ClassDeclaration | undefined;
|
||||
let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap<Node> | undefined;
|
||||
let currentClassHasParameterProperties: boolean | undefined;
|
||||
|
||||
/**
|
||||
* Keeps track of whether expression substitution has been enabled for specific edge cases.
|
||||
@@ -83,12 +84,6 @@ namespace ts {
|
||||
*/
|
||||
let applicableSubstitutions: TypeScriptSubstitutionFlags;
|
||||
|
||||
/**
|
||||
* Tracks what computed name expressions originating from elided names must be inlined
|
||||
* at the next execution site, in document order
|
||||
*/
|
||||
let pendingExpressions: Expression[] | undefined;
|
||||
|
||||
return transformSourceFileOrBundle;
|
||||
|
||||
function transformSourceFileOrBundle(node: SourceFile | Bundle) {
|
||||
@@ -136,6 +131,7 @@ namespace ts {
|
||||
const savedCurrentScope = currentLexicalScope;
|
||||
const savedCurrentNameScope = currentNameScope;
|
||||
const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName;
|
||||
const savedCurrentClassHasParameterProperties = currentClassHasParameterProperties;
|
||||
|
||||
// Handle state changes before visiting a node.
|
||||
onBeforeVisitNode(node);
|
||||
@@ -149,6 +145,7 @@ namespace ts {
|
||||
|
||||
currentLexicalScope = savedCurrentScope;
|
||||
currentNameScope = savedCurrentNameScope;
|
||||
currentClassHasParameterProperties = savedCurrentClassHasParameterProperties;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -315,12 +312,12 @@ namespace ts {
|
||||
function classElementVisitorWorker(node: Node): VisitResult<Node> {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
// TypeScript constructors are transformed in `visitClassDeclaration`.
|
||||
// We elide them here as `visitorWorker` checks transform flags, which could
|
||||
// erronously include an ES6 constructor without TypeScript syntax.
|
||||
return undefined;
|
||||
return visitConstructor(node as ConstructorDeclaration);
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
// Property declarations are not TypeScript syntax, but they must be visited
|
||||
// for the decorator transformation.
|
||||
return visitPropertyDeclaration(node as PropertyDeclaration);
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
@@ -437,7 +434,6 @@ namespace ts {
|
||||
// - decorators
|
||||
// - optional `implements` heritage clause
|
||||
// - parameter property assignments in the constructor
|
||||
// - property declarations
|
||||
// - index signatures
|
||||
// - method overload signatures
|
||||
return visitClassDeclaration(<ClassDeclaration>node);
|
||||
@@ -449,7 +445,6 @@ namespace ts {
|
||||
// - decorators
|
||||
// - optional `implements` heritage clause
|
||||
// - parameter property assignments in the constructor
|
||||
// - property declarations
|
||||
// - index signatures
|
||||
// - method overload signatures
|
||||
return visitClassExpression(<ClassExpression>node);
|
||||
@@ -612,9 +607,6 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined;
|
||||
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const facts = getClassFacts(node, staticProperties);
|
||||
|
||||
@@ -624,25 +616,11 @@ namespace ts {
|
||||
|
||||
const name = node.name || (facts & ClassFacts.NeedsName ? getGeneratedNameForNode(node) : undefined);
|
||||
const classStatement = facts & ClassFacts.HasConstructorDecorators
|
||||
? createClassDeclarationHeadWithDecorators(node, name, facts)
|
||||
? createClassDeclarationHeadWithDecorators(node, name)
|
||||
: createClassDeclarationHeadWithoutDecorators(node, name, facts);
|
||||
|
||||
let statements: Statement[] = [classStatement];
|
||||
|
||||
// Write any pending expressions from elided or moved computed property names
|
||||
if (some(pendingExpressions)) {
|
||||
statements.push(createExpressionStatement(inlineExpressions(pendingExpressions!)));
|
||||
}
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
|
||||
// Emit static property assignment. Because classDeclaration is lexically evaluated,
|
||||
// it is safe to emit static property assignment after classDeclaration
|
||||
// From ES6 specification:
|
||||
// HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using
|
||||
// a lexical declaration such as a LexicalDeclaration or a ClassDeclaration.
|
||||
if (facts & ClassFacts.HasStaticInitializedProperties) {
|
||||
addInitializedPropertyStatements(statements, staticProperties, facts & ClassFacts.UseImmediatelyInvokedFunctionExpression ? getInternalName(node) : getLocalName(node));
|
||||
}
|
||||
|
||||
// Write any decorators of the node.
|
||||
addClassElementDecorationStatements(statements, node, /*isStatic*/ false);
|
||||
@@ -745,7 +723,7 @@ namespace ts {
|
||||
name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0)
|
||||
transformClassMembers(node)
|
||||
);
|
||||
|
||||
// To better align with the old emitter, we should not emit a trailing source map
|
||||
@@ -755,6 +733,7 @@ namespace ts {
|
||||
emitFlags |= EmitFlags.NoTrailingSourceMap;
|
||||
}
|
||||
|
||||
aggregateTransformFlags(classDeclaration);
|
||||
setTextRange(classDeclaration, node);
|
||||
setOriginalNode(classDeclaration, node);
|
||||
setEmitFlags(classDeclaration, emitFlags);
|
||||
@@ -765,7 +744,7 @@ namespace ts {
|
||||
* Transforms a decorated class declaration and appends the resulting statements. If
|
||||
* the class requires an alias to avoid issues with double-binding, the alias is returned.
|
||||
*/
|
||||
function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined, facts: ClassFacts) {
|
||||
function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined) {
|
||||
// When we emit an ES6 class that has a class decorator, we must tailor the
|
||||
// emit to certain specific cases.
|
||||
//
|
||||
@@ -860,8 +839,9 @@ namespace ts {
|
||||
// ${members}
|
||||
// }
|
||||
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
|
||||
const members = transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0);
|
||||
const members = transformClassMembers(node);
|
||||
const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members);
|
||||
aggregateTransformFlags(classExpression);
|
||||
setOriginalNode(classExpression, node);
|
||||
setTextRange(classExpression, location);
|
||||
|
||||
@@ -888,49 +868,18 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined;
|
||||
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
|
||||
const members = transformClassMembers(node, some(heritageClauses, c => c.token === SyntaxKind.ExtendsKeyword));
|
||||
|
||||
const classExpression = createClassExpression(
|
||||
/*modifiers*/ undefined,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
heritageClauses,
|
||||
members
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node)
|
||||
);
|
||||
|
||||
aggregateTransformFlags(classExpression);
|
||||
setOriginalNode(classExpression, node);
|
||||
setTextRange(classExpression, node);
|
||||
|
||||
if (some(staticProperties) || some(pendingExpressions)) {
|
||||
const expressions: Expression[] = [];
|
||||
const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference;
|
||||
const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference);
|
||||
if (isClassWithConstructorReference) {
|
||||
// record an alias as the class name is not in scope for statics.
|
||||
enableSubstitutionForClassAliases();
|
||||
const alias = getSynthesizedClone(temp);
|
||||
alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes;
|
||||
classAliases[getOriginalNodeId(node)] = alias;
|
||||
}
|
||||
|
||||
// To preserve the behavior of the old emitter, we explicitly indent
|
||||
// the body of a class with static initializers.
|
||||
setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression));
|
||||
expressions.push(startOnNewLine(createAssignment(temp, classExpression)));
|
||||
// Add any pending expressions leftover from elided or relocated computed property names
|
||||
addRange(expressions, map(pendingExpressions, startOnNewLine));
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp));
|
||||
expressions.push(startOnNewLine(temp));
|
||||
return inlineExpressions(expressions);
|
||||
}
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
return classExpression;
|
||||
}
|
||||
|
||||
@@ -938,344 +887,31 @@ namespace ts {
|
||||
* Transforms the members of a class.
|
||||
*
|
||||
* @param node The current class.
|
||||
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
|
||||
*/
|
||||
function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
function transformClassMembers(node: ClassDeclaration | ClassExpression) {
|
||||
const members: ClassElement[] = [];
|
||||
const constructor = transformConstructor(node, isDerivedClass);
|
||||
if (constructor) {
|
||||
members.push(constructor);
|
||||
const constructor = getFirstConstructorWithBody(node);
|
||||
const parametersWithPropertyAssignments = constructor &&
|
||||
filter(constructor.parameters, isParameterPropertyDeclaration);
|
||||
|
||||
if (parametersWithPropertyAssignments) {
|
||||
for (const parameter of parametersWithPropertyAssignments) {
|
||||
if (isIdentifier(parameter.name)) {
|
||||
members.push(aggregateTransformFlags(createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
parameter.name,
|
||||
/*questionOrExclamationToken*/ undefined,
|
||||
/*type*/ undefined,
|
||||
/*initializer*/ undefined)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addRange(members, visitNodes(node.members, classElementVisitor, isClassElement));
|
||||
return setTextRange(createNodeArray(members), /*location*/ node.members);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms (or creates) a constructor for a class.
|
||||
*
|
||||
* @param node The current class.
|
||||
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
|
||||
*/
|
||||
function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
// Check if we have property assignment inside class declaration.
|
||||
// If there is a property assignment, we need to emit constructor whether users define it or not
|
||||
// If there is no property assignment, we can omit constructor if users do not define it
|
||||
const constructor = getFirstConstructorWithBody(node);
|
||||
const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty);
|
||||
const hasParameterPropertyAssignments = constructor &&
|
||||
constructor.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax &&
|
||||
forEach(constructor.parameters, isParameterWithPropertyAssignment);
|
||||
|
||||
// If the class does not contain nodes that require a synthesized constructor,
|
||||
// accept the current constructor if it exists.
|
||||
if (!hasInstancePropertyWithInitializer && !hasParameterPropertyAssignments) {
|
||||
return visitEachChild(constructor, visitor, context);
|
||||
}
|
||||
|
||||
const parameters = transformConstructorParameters(constructor);
|
||||
const body = transformConstructorBody(node, constructor, isDerivedClass);
|
||||
|
||||
// constructor(${parameters}) {
|
||||
// ${body}
|
||||
// }
|
||||
return startOnNewLine(
|
||||
setOriginalNode(
|
||||
setTextRange(
|
||||
createConstructor(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
parameters,
|
||||
body
|
||||
),
|
||||
constructor || node
|
||||
),
|
||||
constructor
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms (or creates) the parameters for the constructor of a class with
|
||||
* parameter property assignments or instance property initializers.
|
||||
*
|
||||
* @param constructor The constructor declaration.
|
||||
*/
|
||||
function transformConstructorParameters(constructor: ConstructorDeclaration | undefined) {
|
||||
// The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation:
|
||||
// If constructor is empty, then
|
||||
// If ClassHeritag_eopt is present and protoParent is not null, then
|
||||
// Let constructor be the result of parsing the source text
|
||||
// constructor(...args) { super (...args);}
|
||||
// using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
|
||||
// Else,
|
||||
// Let constructor be the result of parsing the source text
|
||||
// constructor( ){ }
|
||||
// using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
|
||||
//
|
||||
// While we could emit the '...args' rest parameter, certain later tools in the pipeline might
|
||||
// downlevel the '...args' portion less efficiently by naively copying the contents of 'arguments' to an array.
|
||||
// Instead, we'll avoid using a rest parameter and spread into the super call as
|
||||
// 'super(...arguments)' instead of 'super(...args)', as you can see in "transformConstructorBody".
|
||||
return visitParameterList(constructor && constructor.parameters, visitor, context)
|
||||
|| <ParameterDeclaration[]>[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms (or creates) a constructor body for a class with parameter property
|
||||
* assignments or instance property initializers.
|
||||
*
|
||||
* @param node The current class.
|
||||
* @param constructor The current class constructor.
|
||||
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
|
||||
*/
|
||||
function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) {
|
||||
let statements: Statement[] = [];
|
||||
let indexOfFirstStatement = 0;
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
if (constructor) {
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements);
|
||||
|
||||
// Add parameters with property assignments. Transforms this:
|
||||
//
|
||||
// constructor (public x, public y) {
|
||||
// }
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor (x, y) {
|
||||
// this.x = x;
|
||||
// this.y = y;
|
||||
// }
|
||||
//
|
||||
const propertyAssignments = getParametersWithPropertyAssignments(constructor);
|
||||
addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment));
|
||||
}
|
||||
else if (isDerivedClass) {
|
||||
// Add a synthetic `super` call:
|
||||
//
|
||||
// super(...arguments);
|
||||
//
|
||||
statements.push(
|
||||
createExpressionStatement(
|
||||
createCall(
|
||||
createSuper(),
|
||||
/*typeArguments*/ undefined,
|
||||
[createSpread(createIdentifier("arguments"))]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Add the property initializers. Transforms this:
|
||||
//
|
||||
// public x = 1;
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor() {
|
||||
// this.x = 1;
|
||||
// }
|
||||
//
|
||||
const properties = getInitializedProperties(node, /*isStatic*/ false);
|
||||
addInitializedPropertyStatements(statements, properties, createThis());
|
||||
|
||||
if (constructor) {
|
||||
// The class already had a constructor, so we should add the existing statements, skipping the initial super call.
|
||||
addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement));
|
||||
}
|
||||
|
||||
// End the lexical environment.
|
||||
statements = mergeLexicalEnvironment(statements, endLexicalEnvironment());
|
||||
return setTextRange(
|
||||
createBlock(
|
||||
setTextRange(
|
||||
createNodeArray(statements),
|
||||
/*location*/ constructor ? constructor.body!.statements : node.members
|
||||
),
|
||||
/*multiLine*/ true
|
||||
),
|
||||
/*location*/ constructor ? constructor.body : undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds super call and preceding prologue directives into the list of statements.
|
||||
*
|
||||
* @param ctor The constructor node.
|
||||
* @returns index of the statement that follows super call
|
||||
*/
|
||||
function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[]): number {
|
||||
if (ctor.body) {
|
||||
const statements = ctor.body.statements;
|
||||
// add prologue directives to the list (if any)
|
||||
const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor);
|
||||
if (index === statements.length) {
|
||||
// list contains nothing but prologue directives (or empty) - exit
|
||||
return index;
|
||||
}
|
||||
|
||||
const statement = statements[index];
|
||||
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((<ExpressionStatement>statement).expression)) {
|
||||
result.push(visitNode(statement, visitor, isStatement));
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all parameters of a constructor that should be transformed into property assignments.
|
||||
*
|
||||
* @param node The constructor node.
|
||||
*/
|
||||
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray<ParameterDeclaration> {
|
||||
return filter(node.parameters, isParameterWithPropertyAssignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a parameter should be transformed into a property assignment.
|
||||
*
|
||||
* @param parameter The parameter node.
|
||||
*/
|
||||
function isParameterWithPropertyAssignment(parameter: ParameterDeclaration) {
|
||||
return hasModifier(parameter, ModifierFlags.ParameterPropertyModifier)
|
||||
&& isIdentifier(parameter.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a parameter into a property assignment statement.
|
||||
*
|
||||
* @param node The parameter declaration.
|
||||
*/
|
||||
function transformParameterWithPropertyAssignment(node: ParameterDeclaration) {
|
||||
Debug.assert(isIdentifier(node.name));
|
||||
const name = node.name as Identifier;
|
||||
const propertyName = getMutableClone(name);
|
||||
setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap);
|
||||
|
||||
const localName = getMutableClone(name);
|
||||
setEmitFlags(localName, EmitFlags.NoComments);
|
||||
|
||||
return startOnNewLine(
|
||||
setEmitFlags(
|
||||
setTextRange(
|
||||
createExpressionStatement(
|
||||
createAssignment(
|
||||
setTextRange(
|
||||
createPropertyAccess(
|
||||
createThis(),
|
||||
propertyName
|
||||
),
|
||||
node.name
|
||||
),
|
||||
localName
|
||||
)
|
||||
),
|
||||
moveRangePos(node, -1)
|
||||
),
|
||||
EmitFlags.NoComments
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all property declarations with initializers on either the static or instance side of a class.
|
||||
*
|
||||
* @param node The class node.
|
||||
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
|
||||
*/
|
||||
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
|
||||
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is a static property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration {
|
||||
return isInitializedProperty(member, /*isStatic*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration {
|
||||
return isInitializedProperty(member, /*isStatic*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
* @param isStatic A value indicating whether the member should be a static or instance member.
|
||||
*/
|
||||
function isInitializedProperty(member: ClassElement, isStatic: boolean) {
|
||||
return member.kind === SyntaxKind.PropertyDeclaration
|
||||
&& isStatic === hasModifier(member, ModifierFlags.Static)
|
||||
&& (<PropertyDeclaration>member).initializer !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment statements for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
for (const property of properties) {
|
||||
const statement = createExpressionStatement(transformInitializedProperty(property, receiver));
|
||||
setSourceMapRange(statement, moveRangePastModifiers(property));
|
||||
setCommentRange(statement, property);
|
||||
setOriginalNode(statement, property);
|
||||
statements.push(statement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment expressions for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function generateInitializedPropertyExpressions(properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
const expressions: Expression[] = [];
|
||||
for (const property of properties) {
|
||||
const expression = transformInitializedProperty(property, receiver);
|
||||
startOnNewLine(expression);
|
||||
setSourceMapRange(expression, moveRangePastModifiers(property));
|
||||
setCommentRange(expression, property);
|
||||
setOriginalNode(expression, property);
|
||||
expressions.push(expression);
|
||||
}
|
||||
|
||||
return expressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a property initializer into an assignment statement.
|
||||
*
|
||||
* @param property The property declaration.
|
||||
* @param receiver The object receiving the property assignment.
|
||||
*/
|
||||
function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) {
|
||||
// We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name)
|
||||
const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression)
|
||||
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name))
|
||||
: property.name;
|
||||
const initializer = visitNode(property.initializer, visitor, isExpression);
|
||||
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
|
||||
|
||||
return createAssignment(memberAccess, initializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets either the static or instance members of a class that are decorated, or have
|
||||
@@ -2144,16 +1780,6 @@ namespace ts {
|
||||
: createIdentifier("BigInt");
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inlinable expression is an expression which can be copied into multiple locations
|
||||
* without risk of repeating any sideeffects and whose value could not possibly change between
|
||||
* any such locations
|
||||
*/
|
||||
function isSimpleInlineableExpression(expression: Expression) {
|
||||
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
|
||||
isWellKnownSymbolSyntactically(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that represents a property name. For a computed property, a
|
||||
* name is generated for the node.
|
||||
@@ -2175,26 +1801,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the name is a computed property, this function transforms it, then either returns an expression which caches the
|
||||
* value of the result or the expression itself if the value is either unused or safe to inline into multiple locations
|
||||
* @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator)
|
||||
* @param omitSimple Should expressions with no observable side-effects be elided? (ie, the expression is not hoisted for a decorator or initializer and is a literal)
|
||||
*/
|
||||
function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean, omitSimple: boolean): Expression | undefined {
|
||||
if (isComputedPropertyName(name)) {
|
||||
const expression = visitNode(name.expression, visitor, isExpression);
|
||||
const innerExpression = skipPartiallyEmittedExpressions(expression);
|
||||
const inlinable = isSimpleInlineableExpression(innerExpression);
|
||||
if (!inlinable && shouldHoist) {
|
||||
const generatedName = getGeneratedNameForNode(name);
|
||||
hoistVariableDeclaration(generatedName);
|
||||
return createAssignment(generatedName, expression);
|
||||
}
|
||||
return (omitSimple && (inlinable || isIdentifier(innerExpression))) ? undefined : expression;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the property name of a class element, for use when emitting property
|
||||
* initializers. For a computed property on a node with decorators, a temporary
|
||||
@@ -2204,18 +1810,20 @@ namespace ts {
|
||||
*/
|
||||
function visitPropertyNameOfClassElement(member: ClassElement): PropertyName {
|
||||
const name = member.name!;
|
||||
let expr = getPropertyNameExpressionIfNeeded(name, some(member.decorators), /*omitSimple*/ false);
|
||||
if (expr) { // expr only exists if `name` is a computed property name
|
||||
// Inline any pending expressions from previous elided or relocated computed property name expressions in order to preserve execution order
|
||||
if (some(pendingExpressions)) {
|
||||
expr = inlineExpressions([...pendingExpressions, expr]);
|
||||
pendingExpressions.length = 0;
|
||||
// Computed property names need to be transformed into a hoisted variable when they are used more than once.
|
||||
// The names are used more than once when:
|
||||
// - the property is non-static and its initializer is moved to the constructor (when there are parameter property assignments).
|
||||
// - the property has a decorator.
|
||||
if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || some(member.decorators))) {
|
||||
const expression = visitNode(name.expression, visitor, isExpression);
|
||||
const innerExpression = skipPartiallyEmittedExpressions(expression);
|
||||
if (!isSimpleInlineableExpression(innerExpression)) {
|
||||
const generatedName = getGeneratedNameForNode(name);
|
||||
hoistVariableDeclaration(generatedName);
|
||||
return updateComputedPropertyName(name, createAssignment(generatedName, expression));
|
||||
}
|
||||
return updateComputedPropertyName(name as ComputedPropertyName, expr);
|
||||
}
|
||||
else {
|
||||
return name;
|
||||
}
|
||||
return visitNode(name, visitor, isPropertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2257,16 +1865,27 @@ namespace ts {
|
||||
*
|
||||
* @param node The declaration node.
|
||||
*/
|
||||
function shouldEmitFunctionLikeDeclaration(node: FunctionLikeDeclaration) {
|
||||
function shouldEmitFunctionLikeDeclaration<T extends FunctionLikeDeclaration>(node: T): node is T & { body: NonNullable<T["body"]> } {
|
||||
return !nodeIsMissing(node.body);
|
||||
}
|
||||
|
||||
function visitPropertyDeclaration(node: PropertyDeclaration): undefined {
|
||||
const expr = getPropertyNameExpressionIfNeeded(node.name, some(node.decorators) || !!node.initializer, /*omitSimple*/ true);
|
||||
if (expr && !isSimpleInlineableExpression(expr)) {
|
||||
(pendingExpressions || (pendingExpressions = [])).push(expr);
|
||||
function visitPropertyDeclaration(node: PropertyDeclaration) {
|
||||
const updated = updateProperty(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
visitPropertyNameOfClassElement(node),
|
||||
/*questionOrExclamationToken*/ undefined,
|
||||
/*type*/ undefined,
|
||||
visitNode(node.initializer, visitor)
|
||||
);
|
||||
if (updated !== node) {
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setCommentRange(updated, node);
|
||||
setSourceMapRange(updated, moveRangePastDecorators(node));
|
||||
}
|
||||
return undefined;
|
||||
return updated;
|
||||
}
|
||||
|
||||
function visitConstructor(node: ConstructorDeclaration) {
|
||||
@@ -2276,10 +1895,90 @@ namespace ts {
|
||||
|
||||
return updateConstructor(
|
||||
node,
|
||||
visitNodes(node.decorators, visitor, isDecorator),
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
visitFunctionBody(node.body, visitor, context)
|
||||
transformConstructorBody(node.body, node)
|
||||
);
|
||||
}
|
||||
|
||||
function transformConstructorBody(body: Block, constructor: ConstructorDeclaration) {
|
||||
const parametersWithPropertyAssignments = constructor &&
|
||||
filter(constructor.parameters, isParameterPropertyDeclaration);
|
||||
if (!some(parametersWithPropertyAssignments)) {
|
||||
return visitFunctionBody(body, visitor, context);
|
||||
}
|
||||
|
||||
let statements: Statement[] = [];
|
||||
let indexOfFirstStatement = 0;
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor);
|
||||
|
||||
// Add parameters with property assignments. Transforms this:
|
||||
//
|
||||
// constructor (public x, public y) {
|
||||
// }
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor (x, y) {
|
||||
// this.x = x;
|
||||
// this.y = y;
|
||||
// }
|
||||
//
|
||||
addRange(statements, map(parametersWithPropertyAssignments, transformParameterWithPropertyAssignment));
|
||||
|
||||
// Add the existing statements, skipping the initial super call.
|
||||
addRange(statements, visitNodes(body.statements, visitor, isStatement, indexOfFirstStatement));
|
||||
|
||||
// End the lexical environment.
|
||||
statements = mergeLexicalEnvironment(statements, endLexicalEnvironment());
|
||||
const block = createBlock(setTextRange(createNodeArray(statements), body.statements), /*multiLine*/ true);
|
||||
setTextRange(block, /*location*/ body);
|
||||
setOriginalNode(block, body);
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a parameter into a property assignment statement.
|
||||
*
|
||||
* @param node The parameter declaration.
|
||||
*/
|
||||
function transformParameterWithPropertyAssignment(node: ParameterPropertyDeclaration) {
|
||||
const name = node.name;
|
||||
if (!isIdentifier(name)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const propertyName = getMutableClone(name);
|
||||
setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap);
|
||||
|
||||
const localName = getMutableClone(name);
|
||||
setEmitFlags(localName, EmitFlags.NoComments);
|
||||
|
||||
return startOnNewLine(
|
||||
removeAllComments(
|
||||
setTextRange(
|
||||
setOriginalNode(
|
||||
createExpressionStatement(
|
||||
createAssignment(
|
||||
setTextRange(
|
||||
createPropertyAccess(
|
||||
createThis(),
|
||||
propertyName
|
||||
),
|
||||
node.name
|
||||
),
|
||||
localName
|
||||
)
|
||||
),
|
||||
node
|
||||
),
|
||||
moveRangePos(node, -1)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2418,6 +2117,7 @@ namespace ts {
|
||||
if (parameterIsThisKeyword(node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const updated = updateParameter(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
|
||||
@@ -240,6 +240,47 @@ namespace ts {
|
||||
isIdentifier(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inlinable expression is an expression which can be copied into multiple locations
|
||||
* without risk of repeating any sideeffects and whose value could not possibly change between
|
||||
* any such locations
|
||||
*/
|
||||
export function isSimpleInlineableExpression(expression: Expression) {
|
||||
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
|
||||
isWellKnownSymbolSyntactically(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds super call and preceding prologue directives into the list of statements.
|
||||
*
|
||||
* @param ctor The constructor node.
|
||||
* @param result The list of statements.
|
||||
* @param visitor The visitor to apply to each node added to the result array.
|
||||
* @returns index of the statement that follows super call
|
||||
*/
|
||||
export function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[], visitor: Visitor): number {
|
||||
if (ctor.body) {
|
||||
const statements = ctor.body.statements;
|
||||
// add prologue directives to the list (if any)
|
||||
const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor);
|
||||
if (index === statements.length) {
|
||||
// list contains nothing but prologue directives (or empty) - exit
|
||||
return index;
|
||||
}
|
||||
|
||||
const statement = statements[index];
|
||||
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((<ExpressionStatement>statement).expression)) {
|
||||
result.push(visitNode(statement, visitor, isStatement));
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param input Template string input strings
|
||||
* @param args Names which need to be made file-level unique
|
||||
@@ -255,4 +296,43 @@ namespace ts {
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all property declarations with initializers on either the static or instance side of a class.
|
||||
*
|
||||
* @param node The class node.
|
||||
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
|
||||
*/
|
||||
export function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
|
||||
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is a static property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
export function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
|
||||
return isInitializedProperty(member) && hasStaticModifier(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
export function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
|
||||
return isInitializedProperty(member) && !hasStaticModifier(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
* @param isStatic A value indicating whether the member should be a static or instance member.
|
||||
*/
|
||||
export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
|
||||
return member.kind === SyntaxKind.PropertyDeclaration
|
||||
&& (<PropertyDeclaration>member).initializer !== undefined;
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
"transformers/utilities.ts",
|
||||
"transformers/destructuring.ts",
|
||||
"transformers/ts.ts",
|
||||
"transformers/classFields.ts",
|
||||
"transformers/es2017.ts",
|
||||
"transformers/es2018.ts",
|
||||
"transformers/es2019.ts",
|
||||
|
||||
@@ -5197,6 +5197,7 @@ namespace ts {
|
||||
ContainsYield = 1 << 17,
|
||||
ContainsHoistedDeclarationOrCompletion = 1 << 18,
|
||||
ContainsDynamicImport = 1 << 19,
|
||||
ContainsClassFields = 1 << 20,
|
||||
|
||||
// Please leave this as 1 << 29.
|
||||
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.
|
||||
|
||||
@@ -5188,6 +5188,9 @@ namespace ts {
|
||||
return node.parent.left.name;
|
||||
}
|
||||
}
|
||||
else if (isVariableDeclaration(node.parent) && isIdentifier(node.parent.name)) {
|
||||
return node.parent.name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -395,8 +395,15 @@ namespace ts.server {
|
||||
const locations: RenameLocation[] = [];
|
||||
for (const entry of body.locs) {
|
||||
const fileName = entry.file;
|
||||
for (const { start, end, ...prefixSuffixText } of entry.locs) {
|
||||
locations.push({ textSpan: this.decodeSpan({ start, end }, fileName), fileName, ...prefixSuffixText });
|
||||
for (const { start, end, contextStart, contextEnd, ...prefixSuffixText } of entry.locs) {
|
||||
locations.push({
|
||||
textSpan: this.decodeSpan({ start, end }, fileName),
|
||||
fileName,
|
||||
...(contextStart !== undefined ?
|
||||
{ contextSpan: this.decodeSpan({ start: contextStart, end: contextEnd! }, fileName) } :
|
||||
undefined),
|
||||
...prefixSuffixText
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-15
@@ -42,6 +42,7 @@ namespace FourSlash {
|
||||
* is a range with `text in range` "selected".
|
||||
*/
|
||||
ranges: Range[];
|
||||
rangesByText?: ts.MultiMap<Range>;
|
||||
}
|
||||
|
||||
export interface Marker {
|
||||
@@ -955,12 +956,15 @@ namespace FourSlash {
|
||||
const fullExpected = ts.map<FourSlashInterface.ReferenceGroup, ReferenceGroupJson>(parts, ({ definition, ranges }) => ({
|
||||
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 };
|
||||
const { isWriteAccess = false, isDefinition = false, isInString, contextRangeIndex } = (r.marker && r.marker.data || {}) as { isWriteAccess?: boolean, isDefinition?: boolean, isInString?: true, contextRangeIndex?: number };
|
||||
return {
|
||||
fileName: r.fileName,
|
||||
textSpan: ts.createTextSpanFromRange(r),
|
||||
isWriteAccess,
|
||||
isDefinition,
|
||||
...(contextRangeIndex !== undefined ?
|
||||
{ contextSpan: ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]) } :
|
||||
undefined),
|
||||
...(isInString ? { isInString: true } : undefined),
|
||||
};
|
||||
}),
|
||||
@@ -997,8 +1001,8 @@ namespace FourSlash {
|
||||
assert.deepEqual<ReadonlyArray<ts.ReferenceEntry> | undefined>(refs, expected);
|
||||
}
|
||||
|
||||
public verifySingleReferenceGroup(definition: FourSlashInterface.ReferenceGroupDefinition, ranges?: Range[]) {
|
||||
ranges = ranges || this.getRanges();
|
||||
public verifySingleReferenceGroup(definition: FourSlashInterface.ReferenceGroupDefinition, ranges?: Range[] | string) {
|
||||
ranges = ts.isString(ranges) ? this.rangesByText().get(ranges)! : ranges || this.getRanges();
|
||||
this.verifyReferenceGroups(ranges, [{ definition, ranges }]);
|
||||
}
|
||||
|
||||
@@ -1011,7 +1015,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
};
|
||||
|
||||
if ((actual === undefined) !== (expected === undefined)) {
|
||||
fail(`Expected ${expected}, got ${actual}`);
|
||||
fail(`Expected ${stringify(expected)}, got ${stringify(actual)}`);
|
||||
}
|
||||
|
||||
for (const key in actual) {
|
||||
@@ -1021,7 +1025,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
recur(ak, ek, path ? path + "." + key : key);
|
||||
}
|
||||
else if (ak !== ek) {
|
||||
fail(`Expected '${key}' to be '${ek}', got '${ak}'`);
|
||||
fail(`Expected '${key}' to be '${stringify(ek)}', got '${stringify(ak)}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1189,7 +1193,15 @@ Actual: ${stringify(fullActual)}`);
|
||||
locations && ts.sort(locations, (r1, r2) => ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) || r1.textSpan.start - r2.textSpan.start);
|
||||
assert.deepEqual(sort(references), sort(ranges.map((rangeOrOptions): ts.RenameLocation => {
|
||||
const { range, ...prefixSuffixText } = "range" in rangeOrOptions ? rangeOrOptions : { range: rangeOrOptions };
|
||||
return { fileName: range.fileName, textSpan: ts.createTextSpanFromRange(range), ...prefixSuffixText };
|
||||
const { contextRangeIndex } = (range.marker && range.marker.data || {}) as { contextRangeIndex?: number; };
|
||||
return {
|
||||
fileName: range.fileName,
|
||||
textSpan: ts.createTextSpanFromRange(range),
|
||||
...(contextRangeIndex !== undefined ?
|
||||
{ contextSpan: ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]) } :
|
||||
undefined),
|
||||
...prefixSuffixText
|
||||
};
|
||||
})));
|
||||
}
|
||||
}
|
||||
@@ -1844,6 +1856,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
range.end = updatePosition(range.end, editStart, editEnd, newText);
|
||||
}
|
||||
}
|
||||
this.testData.rangesByText = undefined;
|
||||
}
|
||||
|
||||
private removeWhitespace(text: string): string {
|
||||
@@ -2026,7 +2039,9 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public rangesByText(): ts.Map<Range[]> {
|
||||
if (this.testData.rangesByText) return this.testData.rangesByText;
|
||||
const result = ts.createMultiMap<Range>();
|
||||
this.testData.rangesByText = result;
|
||||
for (const range of this.getRanges()) {
|
||||
const text = this.rangeText(range);
|
||||
result.add(text, range);
|
||||
@@ -2714,8 +2729,8 @@ Actual: ${stringify(fullActual)}`);
|
||||
return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch);
|
||||
}
|
||||
|
||||
public verifyRangesAreOccurrences(isWriteAccess?: boolean) {
|
||||
const ranges = this.getRanges();
|
||||
public verifyRangesAreOccurrences(isWriteAccess?: boolean, ranges?: Range[]) {
|
||||
ranges = ranges || this.getRanges();
|
||||
for (const r of ranges) {
|
||||
this.goToRangeStart(r);
|
||||
this.verifyOccurrencesAtPositionListCount(ranges.length);
|
||||
@@ -2725,8 +2740,13 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRangesWithSameTextAreRenameLocations() {
|
||||
this.rangesByText().forEach(ranges => this.verifyRangesAreRenameLocations(ranges));
|
||||
public verifyRangesWithSameTextAreRenameLocations(...texts: string[]) {
|
||||
if (texts.length) {
|
||||
texts.forEach(text => this.verifyRangesAreRenameLocations(this.rangesByText().get(text)));
|
||||
}
|
||||
else {
|
||||
this.rangesByText().forEach(ranges => this.verifyRangesAreRenameLocations(ranges));
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRangesWithSameTextAreDocumentHighlights() {
|
||||
@@ -3971,7 +3991,7 @@ namespace FourSlashInterface {
|
||||
this.state.verifyGetReferencesForServerTest(expected);
|
||||
}
|
||||
|
||||
public singleReferenceGroup(definition: ReferenceGroupDefinition, ranges?: FourSlash.Range[]) {
|
||||
public singleReferenceGroup(definition: ReferenceGroupDefinition, ranges?: FourSlash.Range[] | string) {
|
||||
this.state.verifySingleReferenceGroup(definition, ranges);
|
||||
}
|
||||
|
||||
@@ -4093,12 +4113,12 @@ namespace FourSlashInterface {
|
||||
this.state.verifyOccurrencesAtPositionListCount(expectedCount);
|
||||
}
|
||||
|
||||
public rangesAreOccurrences(isWriteAccess?: boolean) {
|
||||
this.state.verifyRangesAreOccurrences(isWriteAccess);
|
||||
public rangesAreOccurrences(isWriteAccess?: boolean, ranges?: FourSlash.Range[]) {
|
||||
this.state.verifyRangesAreOccurrences(isWriteAccess, ranges);
|
||||
}
|
||||
|
||||
public rangesWithSameTextAreRenameLocations() {
|
||||
this.state.verifyRangesWithSameTextAreRenameLocations();
|
||||
public rangesWithSameTextAreRenameLocations(...texts: string[]) {
|
||||
this.state.verifyRangesWithSameTextAreRenameLocations(...texts);
|
||||
}
|
||||
|
||||
public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: FourSlash.Range[] }) {
|
||||
|
||||
Vendored
+2018
-1804
File diff suppressed because it is too large
Load Diff
Vendored
+94
-30
@@ -2,6 +2,10 @@
|
||||
/// DOM Iterable APIs
|
||||
/////////////////////////////
|
||||
|
||||
interface AudioParam {
|
||||
setValueCurveAtTime(values: Iterable<number>, startTime: number, duration: number): AudioParam;
|
||||
}
|
||||
|
||||
interface AudioParamMap extends ReadonlyMap<string, AudioParam> {
|
||||
}
|
||||
|
||||
@@ -9,6 +13,11 @@ interface AudioTrackList {
|
||||
[Symbol.iterator](): IterableIterator<AudioTrack>;
|
||||
}
|
||||
|
||||
interface BaseAudioContext {
|
||||
createIIRFilter(feedforward: Iterable<number>, feedback: Iterable<number>): IIRFilterNode;
|
||||
createPeriodicWave(real: Iterable<number>, imag: Iterable<number>, constraints?: PeriodicWaveConstraints): PeriodicWave;
|
||||
}
|
||||
|
||||
interface CSSRuleList {
|
||||
[Symbol.iterator](): IterableIterator<CSSRule>;
|
||||
}
|
||||
@@ -17,6 +26,14 @@ interface CSSStyleDeclaration {
|
||||
[Symbol.iterator](): IterableIterator<string>;
|
||||
}
|
||||
|
||||
interface Cache {
|
||||
addAll(requests: Iterable<RequestInfo>): Promise<void>;
|
||||
}
|
||||
|
||||
interface CanvasPathDrawingStyles {
|
||||
setLineDash(segments: Iterable<number>): void;
|
||||
}
|
||||
|
||||
interface ClientRectList {
|
||||
[Symbol.iterator](): IterableIterator<ClientRect>;
|
||||
}
|
||||
@@ -46,16 +63,16 @@ interface FileList {
|
||||
|
||||
interface FormData {
|
||||
[Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list.
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list.
|
||||
*/
|
||||
entries(): IterableIterator<[string, FormDataEntryValue]>;
|
||||
/**
|
||||
* Returns a list of keys in the list.
|
||||
/**
|
||||
* Returns a list of keys in the list.
|
||||
*/
|
||||
keys(): IterableIterator<string>;
|
||||
/**
|
||||
* Returns a list of values in the list.
|
||||
/**
|
||||
* Returns a list of values in the list.
|
||||
*/
|
||||
values(): IterableIterator<FormDataEntryValue>;
|
||||
}
|
||||
@@ -82,20 +99,29 @@ interface HTMLSelectElement {
|
||||
|
||||
interface Headers {
|
||||
[Symbol.iterator](): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns an iterator allowing to go through all key/value pairs contained in this object.
|
||||
/**
|
||||
* Returns an iterator allowing to go through all key/value pairs contained in this object.
|
||||
*/
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object.
|
||||
/**
|
||||
* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object.
|
||||
*/
|
||||
keys(): IterableIterator<string>;
|
||||
/**
|
||||
* Returns an iterator allowing to go through all values of the key/value pairs contained in this object.
|
||||
/**
|
||||
* Returns an iterator allowing to go through all values of the key/value pairs contained in this object.
|
||||
*/
|
||||
values(): IterableIterator<string>;
|
||||
}
|
||||
|
||||
interface IDBObjectStore {
|
||||
/**
|
||||
* Creates a new index in store with the given name, keyPath and options and returns a new IDBIndex. If the keyPath and options define constraints that cannot be satisfied with the data already in store the upgrade transaction will abort with a "ConstraintError" DOMException.
|
||||
*
|
||||
* Throws an "InvalidStateError" DOMException if not called within an upgrade transaction.
|
||||
*/
|
||||
createIndex(name: string, keyPath: string | Iterable<string>, options?: IDBIndexParameters): IDBIndex;
|
||||
}
|
||||
|
||||
interface MediaKeyStatusMap {
|
||||
[Symbol.iterator](): IterableIterator<[BufferSource, MediaKeyStatus]>;
|
||||
entries(): IterableIterator<[BufferSource, MediaKeyStatus]>;
|
||||
@@ -115,34 +141,38 @@ interface NamedNodeMap {
|
||||
[Symbol.iterator](): IterableIterator<Attr>;
|
||||
}
|
||||
|
||||
interface Navigator {
|
||||
requestMediaKeySystemAccess(keySystem: string, supportedConfigurations: Iterable<MediaKeySystemConfiguration>): Promise<MediaKeySystemAccess>;
|
||||
}
|
||||
|
||||
interface NodeList {
|
||||
[Symbol.iterator](): IterableIterator<Node>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list.
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list.
|
||||
*/
|
||||
entries(): IterableIterator<[number, Node]>;
|
||||
/**
|
||||
* Returns an list of keys in the list.
|
||||
/**
|
||||
* Returns an list of keys in the list.
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the list.
|
||||
/**
|
||||
* Returns an list of values in the list.
|
||||
*/
|
||||
values(): IterableIterator<Node>;
|
||||
}
|
||||
|
||||
interface NodeListOf<TNode extends Node> {
|
||||
[Symbol.iterator](): IterableIterator<TNode>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list.
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the list.
|
||||
*/
|
||||
entries(): IterableIterator<[number, TNode]>;
|
||||
/**
|
||||
* Returns an list of keys in the list.
|
||||
/**
|
||||
* Returns an list of keys in the list.
|
||||
*/
|
||||
keys(): IterableIterator<number>;
|
||||
/**
|
||||
* Returns an list of values in the list.
|
||||
/**
|
||||
* Returns an list of values in the list.
|
||||
*/
|
||||
values(): IterableIterator<TNode>;
|
||||
}
|
||||
@@ -155,6 +185,10 @@ interface PluginArray {
|
||||
[Symbol.iterator](): IterableIterator<Plugin>;
|
||||
}
|
||||
|
||||
interface RTCRtpTransceiver {
|
||||
setCodecPreferences(codecs: Iterable<RTCRtpCodecCapability>): void;
|
||||
}
|
||||
|
||||
interface RTCStatsReport extends ReadonlyMap<string, any> {
|
||||
}
|
||||
|
||||
@@ -208,20 +242,50 @@ interface TouchList {
|
||||
|
||||
interface URLSearchParams {
|
||||
[Symbol.iterator](): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the search params.
|
||||
/**
|
||||
* Returns an array of key, value pairs for every entry in the search params.
|
||||
*/
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns a list of keys in the search params.
|
||||
/**
|
||||
* Returns a list of keys in the search params.
|
||||
*/
|
||||
keys(): IterableIterator<string>;
|
||||
/**
|
||||
* Returns a list of values in the search params.
|
||||
/**
|
||||
* Returns a list of values in the search params.
|
||||
*/
|
||||
values(): IterableIterator<string>;
|
||||
}
|
||||
|
||||
interface VRDisplay {
|
||||
requestPresent(layers: Iterable<VRLayer>): Promise<void>;
|
||||
}
|
||||
|
||||
interface VideoTrackList {
|
||||
[Symbol.iterator](): IterableIterator<VideoTrack>;
|
||||
}
|
||||
|
||||
interface WEBGL_draw_buffers {
|
||||
drawBuffersWEBGL(buffers: Iterable<GLenum>): void;
|
||||
}
|
||||
|
||||
interface WebAuthentication {
|
||||
makeCredential(accountInformation: Account, cryptoParameters: Iterable<ScopedCredentialParameters>, attestationChallenge: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer | null, options?: ScopedCredentialOptions): Promise<ScopedCredentialInfo>;
|
||||
}
|
||||
|
||||
interface WebGLRenderingContextBase {
|
||||
uniform1fv(location: WebGLUniformLocation | null, v: Iterable<GLfloat>): void;
|
||||
uniform2fv(location: WebGLUniformLocation | null, v: Iterable<GLfloat>): void;
|
||||
uniform3fv(location: WebGLUniformLocation | null, v: Iterable<GLfloat>): void;
|
||||
uniform4fv(location: WebGLUniformLocation | null, v: Iterable<GLfloat>): void;
|
||||
uniform1iv(location: WebGLUniformLocation | null, v: Iterable<GLint>): void;
|
||||
uniform2iv(location: WebGLUniformLocation | null, v: Iterable<GLint>): void;
|
||||
uniform3iv(location: WebGLUniformLocation | null, v: Iterable<GLint>): void;
|
||||
uniform4iv(location: WebGLUniformLocation | null, v: Iterable<GLint>): void;
|
||||
uniformMatrix2fv(location: WebGLUniformLocation | null, transpose: GLboolean, value: Iterable<GLfloat>): void;
|
||||
uniformMatrix3fv(location: WebGLUniformLocation | null, transpose: GLboolean, value: Iterable<GLfloat>): void;
|
||||
uniformMatrix4fv(location: WebGLUniformLocation | null, transpose: GLboolean, value: Iterable<GLfloat>): void;
|
||||
vertexAttrib1fv(index: GLuint, values: Iterable<GLfloat>): void;
|
||||
vertexAttrib2fv(index: GLuint, values: Iterable<GLfloat>): void;
|
||||
vertexAttrib3fv(index: GLuint, values: Iterable<GLfloat>): void;
|
||||
vertexAttrib4fv(index: GLuint, values: Iterable<GLfloat>): void;
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -373,8 +373,8 @@ interface RegExp {
|
||||
}
|
||||
|
||||
interface RegExpConstructor {
|
||||
new (pattern: RegExp, flags?: string): RegExp;
|
||||
(pattern: RegExp, flags?: string): RegExp;
|
||||
new (pattern: RegExp | string, flags?: string): RegExp;
|
||||
(pattern: RegExp | string, flags?: string): RegExp;
|
||||
}
|
||||
|
||||
interface String {
|
||||
|
||||
Vendored
+395
-319
File diff suppressed because it is too large
Load Diff
+16
-8
@@ -872,8 +872,16 @@ namespace ts.server.protocol {
|
||||
file: string;
|
||||
}
|
||||
|
||||
export interface TextSpanWithContext extends TextSpan {
|
||||
contextStart?: Location;
|
||||
contextEnd?: Location;
|
||||
}
|
||||
|
||||
export interface FileSpanWithContext extends FileSpan, TextSpanWithContext {
|
||||
}
|
||||
|
||||
export interface DefinitionInfoAndBoundSpan {
|
||||
definitions: ReadonlyArray<FileSpan>;
|
||||
definitions: ReadonlyArray<FileSpanWithContext>;
|
||||
textSpan: TextSpan;
|
||||
}
|
||||
|
||||
@@ -881,7 +889,7 @@ namespace ts.server.protocol {
|
||||
* Definition response message. Gives text range for definition.
|
||||
*/
|
||||
export interface DefinitionResponse extends Response {
|
||||
body?: FileSpan[];
|
||||
body?: FileSpanWithContext[];
|
||||
}
|
||||
|
||||
export interface DefinitionInfoAndBoundSpanReponse extends Response {
|
||||
@@ -892,14 +900,14 @@ namespace ts.server.protocol {
|
||||
* Definition response message. Gives text range for definition.
|
||||
*/
|
||||
export interface TypeDefinitionResponse extends Response {
|
||||
body?: FileSpan[];
|
||||
body?: FileSpanWithContext[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation response message. Gives text range for implementations.
|
||||
*/
|
||||
export interface ImplementationResponse extends Response {
|
||||
body?: FileSpan[];
|
||||
body?: FileSpanWithContext[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -942,7 +950,7 @@ namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
export interface OccurrencesResponseItem extends FileSpan {
|
||||
export interface OccurrencesResponseItem extends FileSpanWithContext {
|
||||
/**
|
||||
* True if the occurrence is a write location, false otherwise.
|
||||
*/
|
||||
@@ -972,7 +980,7 @@ namespace ts.server.protocol {
|
||||
/**
|
||||
* Span augmented with extra information that denotes the kind of the highlighting to be used for span.
|
||||
*/
|
||||
export interface HighlightSpan extends TextSpan {
|
||||
export interface HighlightSpan extends TextSpanWithContext {
|
||||
kind: HighlightSpanKind;
|
||||
}
|
||||
|
||||
@@ -1007,7 +1015,7 @@ namespace ts.server.protocol {
|
||||
command: CommandTypes.References;
|
||||
}
|
||||
|
||||
export interface ReferencesResponseItem extends FileSpan {
|
||||
export interface ReferencesResponseItem extends FileSpanWithContext {
|
||||
/** Text of line containing the reference. Including this
|
||||
* with the response avoids latency of editor loading files
|
||||
* to show text of reference line (the server already has
|
||||
@@ -1150,7 +1158,7 @@ namespace ts.server.protocol {
|
||||
locs: RenameTextSpan[];
|
||||
}
|
||||
|
||||
export interface RenameTextSpan extends TextSpan {
|
||||
export interface RenameTextSpan extends TextSpanWithContext {
|
||||
readonly prefixText?: string;
|
||||
readonly suffixText?: string;
|
||||
}
|
||||
|
||||
+136
-125
@@ -354,13 +354,17 @@ namespace ts.server {
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
({ project, location }, getMappedLocation) => {
|
||||
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.pos) || emptyArray) {
|
||||
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.pos) || emptyArray) {
|
||||
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
|
||||
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
|
||||
...outputReferencedSymbol.definition,
|
||||
textSpan: createTextSpan(mappedDefinitionFile.pos, outputReferencedSymbol.definition.textSpan.length),
|
||||
fileName: mappedDefinitionFile.fileName,
|
||||
};
|
||||
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ?
|
||||
outputReferencedSymbol.definition :
|
||||
{
|
||||
...outputReferencedSymbol.definition,
|
||||
textSpan: createTextSpan(mappedDefinitionFile.pos, outputReferencedSymbol.definition.textSpan.length),
|
||||
fileName: mappedDefinitionFile.fileName,
|
||||
contextSpan: getMappedContextSpan(outputReferencedSymbol.definition, project)
|
||||
};
|
||||
|
||||
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
|
||||
if (!symbolToAddTo) {
|
||||
symbolToAddTo = { definition, references: [] };
|
||||
@@ -481,9 +485,39 @@ namespace ts.server {
|
||||
return { fileName, pos: textSpan.start };
|
||||
}
|
||||
|
||||
function getMappedLocation(location: DocumentPosition, projectService: ProjectService, project: Project): DocumentPosition | undefined {
|
||||
function getMappedLocation(location: DocumentPosition, project: Project): DocumentPosition | undefined {
|
||||
const mapsTo = project.getSourceMapper().tryGetSourcePosition(location);
|
||||
return mapsTo && projectService.fileExists(toNormalizedPath(mapsTo.fileName)) ? mapsTo : undefined;
|
||||
return mapsTo && project.projectService.fileExists(toNormalizedPath(mapsTo.fileName)) ? mapsTo : undefined;
|
||||
}
|
||||
|
||||
function getMappedDocumentSpan(documentSpan: DocumentSpan, project: Project): DocumentSpan | undefined {
|
||||
const newPosition = getMappedLocation(documentSpanLocation(documentSpan), project);
|
||||
if (!newPosition) return undefined;
|
||||
return {
|
||||
fileName: newPosition.fileName,
|
||||
textSpan: {
|
||||
start: newPosition.pos,
|
||||
length: documentSpan.textSpan.length
|
||||
},
|
||||
originalFileName: documentSpan.fileName,
|
||||
originalTextSpan: documentSpan.textSpan,
|
||||
contextSpan: getMappedContextSpan(documentSpan, project),
|
||||
originalContextSpan: documentSpan.contextSpan
|
||||
};
|
||||
}
|
||||
|
||||
function getMappedContextSpan(documentSpan: DocumentSpan, project: Project): TextSpan | undefined {
|
||||
const contextSpanStart = documentSpan.contextSpan && getMappedLocation(
|
||||
{ fileName: documentSpan.fileName, pos: documentSpan.contextSpan.start },
|
||||
project
|
||||
);
|
||||
const contextSpanEnd = documentSpan.contextSpan && getMappedLocation(
|
||||
{ fileName: documentSpan.fileName, pos: documentSpan.contextSpan.start + documentSpan.contextSpan.length },
|
||||
project
|
||||
);
|
||||
return contextSpanStart && contextSpanEnd ?
|
||||
{ start: contextSpanStart.pos, length: contextSpanEnd.pos - contextSpanStart.pos } :
|
||||
undefined;
|
||||
}
|
||||
|
||||
export interface SessionOptions {
|
||||
@@ -937,7 +971,7 @@ namespace ts.server {
|
||||
: diagnostics.map(d => formatDiag(file, project, d));
|
||||
}
|
||||
|
||||
private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<DefinitionInfo> {
|
||||
private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpanWithContext> | ReadonlyArray<DefinitionInfo> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
const definitions = this.mapDefinitionInfoLocations(project.getLanguageService().getDefinitionAtPosition(file, position) || emptyArray, project);
|
||||
@@ -946,19 +980,13 @@ namespace ts.server {
|
||||
|
||||
private mapDefinitionInfoLocations(definitions: ReadonlyArray<DefinitionInfo>, project: Project): ReadonlyArray<DefinitionInfo> {
|
||||
return definitions.map((info): DefinitionInfo => {
|
||||
const newLoc = getMappedLocation(documentSpanLocation(info), this.projectService, project);
|
||||
return !newLoc ? info : {
|
||||
const newDocumentSpan = getMappedDocumentSpan(info, project);
|
||||
return !newDocumentSpan ? info : {
|
||||
...newDocumentSpan,
|
||||
containerKind: info.containerKind,
|
||||
containerName: info.containerName,
|
||||
fileName: newLoc.fileName,
|
||||
kind: info.kind,
|
||||
name: info.name,
|
||||
textSpan: {
|
||||
start: newLoc.pos,
|
||||
length: info.textSpan.length
|
||||
},
|
||||
originalFileName: info.fileName,
|
||||
originalTextSpan: info.textSpan,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -983,7 +1011,7 @@ namespace ts.server {
|
||||
if (simplifiedResult) {
|
||||
return {
|
||||
definitions: this.mapDefinitionInfo(definitions, project),
|
||||
textSpan: this.toLocationTextSpan(textSpan, scriptInfo)
|
||||
textSpan: toProcolTextSpan(textSpan, scriptInfo)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -998,8 +1026,8 @@ namespace ts.server {
|
||||
return project.getLanguageService().getEmitOutput(file);
|
||||
}
|
||||
|
||||
private mapDefinitionInfo(definitions: ReadonlyArray<DefinitionInfo>, project: Project): ReadonlyArray<protocol.FileSpan> {
|
||||
return definitions.map(def => this.toFileSpan(def.fileName, def.textSpan, project));
|
||||
private mapDefinitionInfo(definitions: ReadonlyArray<DefinitionInfo>, project: Project): ReadonlyArray<protocol.FileSpanWithContext> {
|
||||
return definitions.map(def => this.toFileSpanWithContext(def.fileName, def.textSpan, def.contextSpan, project));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1017,7 +1045,9 @@ namespace ts.server {
|
||||
fileName: def.originalFileName,
|
||||
textSpan: def.originalTextSpan,
|
||||
targetFileName: def.fileName,
|
||||
targetTextSpan: def.textSpan
|
||||
targetTextSpan: def.textSpan,
|
||||
contextSpan: def.originalContextSpan,
|
||||
targetContextSpan: def.contextSpan
|
||||
};
|
||||
}
|
||||
return def;
|
||||
@@ -1035,7 +1065,15 @@ namespace ts.server {
|
||||
};
|
||||
}
|
||||
|
||||
private getTypeDefinition(args: protocol.FileLocationRequestArgs): ReadonlyArray<protocol.FileSpan> {
|
||||
private toFileSpanWithContext(fileName: string, textSpan: TextSpan, contextSpan: TextSpan | undefined, project: Project): protocol.FileSpanWithContext {
|
||||
const fileSpan = this.toFileSpan(fileName, textSpan, project);
|
||||
const context = contextSpan && this.toFileSpan(fileName, contextSpan, project);
|
||||
return context ?
|
||||
{ ...fileSpan, contextStart: context.start, contextEnd: context.end } :
|
||||
fileSpan;
|
||||
}
|
||||
|
||||
private getTypeDefinition(args: protocol.FileLocationRequestArgs): ReadonlyArray<protocol.FileSpanWithContext> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
|
||||
@@ -1045,58 +1083,40 @@ namespace ts.server {
|
||||
|
||||
private mapImplementationLocations(implementations: ReadonlyArray<ImplementationLocation>, project: Project): ReadonlyArray<ImplementationLocation> {
|
||||
return implementations.map((info): ImplementationLocation => {
|
||||
const newLoc = getMappedLocation(documentSpanLocation(info), this.projectService, project);
|
||||
return !newLoc ? info : {
|
||||
fileName: newLoc.fileName,
|
||||
const newDocumentSpan = getMappedDocumentSpan(info, project);
|
||||
return !newDocumentSpan ? info : {
|
||||
...newDocumentSpan,
|
||||
kind: info.kind,
|
||||
displayParts: info.displayParts,
|
||||
textSpan: {
|
||||
start: newLoc.pos,
|
||||
length: info.textSpan.length
|
||||
},
|
||||
originalFileName: info.fileName,
|
||||
originalTextSpan: info.textSpan,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<ImplementationLocation> {
|
||||
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpanWithContext> | ReadonlyArray<ImplementationLocation> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
const implementations = this.mapImplementationLocations(project.getLanguageService().getImplementationAtPosition(file, position) || emptyArray, project);
|
||||
if (simplifiedResult) {
|
||||
return implementations.map(({ fileName, textSpan }) => this.toFileSpan(fileName, textSpan, project));
|
||||
}
|
||||
|
||||
return implementations.map(Session.mapToOriginalLocation);
|
||||
return simplifiedResult ?
|
||||
implementations.map(({ fileName, textSpan, contextSpan }) => this.toFileSpanWithContext(fileName, textSpan, contextSpan, project)) :
|
||||
implementations.map(Session.mapToOriginalLocation);
|
||||
}
|
||||
|
||||
private getOccurrences(args: protocol.FileLocationRequestArgs): ReadonlyArray<protocol.OccurrencesResponseItem> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
|
||||
const position = this.getPositionInFile(args, file);
|
||||
|
||||
const occurrences = project.getLanguageService().getOccurrencesAtPosition(file, position);
|
||||
|
||||
if (!occurrences) {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return occurrences.map(occurrence => {
|
||||
const { fileName, isWriteAccess, textSpan, isInString } = occurrence;
|
||||
const scriptInfo = project.getScriptInfo(fileName)!;
|
||||
const result: protocol.OccurrencesResponseItem = {
|
||||
start: scriptInfo.positionToLineOffset(textSpan.start),
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)),
|
||||
file: fileName,
|
||||
isWriteAccess,
|
||||
};
|
||||
// no need to serialize the property if it is not true
|
||||
if (isInString) {
|
||||
result.isInString = isInString;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
return occurrences ?
|
||||
occurrences.map<protocol.OccurrencesResponseItem>(occurrence => {
|
||||
const { fileName, isWriteAccess, textSpan, isInString, contextSpan } = occurrence;
|
||||
const scriptInfo = project.getScriptInfo(fileName)!;
|
||||
return {
|
||||
...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo),
|
||||
file: fileName,
|
||||
isWriteAccess,
|
||||
...(isInString ? { isInString } : undefined)
|
||||
};
|
||||
}) :
|
||||
emptyArray;
|
||||
}
|
||||
|
||||
private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
|
||||
@@ -1139,33 +1159,19 @@ namespace ts.server {
|
||||
const position = this.getPositionInFile(args, file);
|
||||
const documentHighlights = project.getLanguageService().getDocumentHighlights(file, position, args.filesToSearch);
|
||||
|
||||
if (!documentHighlights) {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
if (simplifiedResult) {
|
||||
return documentHighlights.map(convertToDocumentHighlightsItem);
|
||||
}
|
||||
else {
|
||||
return documentHighlights;
|
||||
}
|
||||
|
||||
function convertToDocumentHighlightsItem(documentHighlights: DocumentHighlights): protocol.DocumentHighlightsItem {
|
||||
const { fileName, highlightSpans } = documentHighlights;
|
||||
if (!documentHighlights) return emptyArray;
|
||||
if (!simplifiedResult) return documentHighlights;
|
||||
|
||||
return documentHighlights.map<protocol.DocumentHighlightsItem>(({ fileName, highlightSpans }) => {
|
||||
const scriptInfo = project.getScriptInfo(fileName)!;
|
||||
return {
|
||||
file: fileName,
|
||||
highlightSpans: highlightSpans.map(convertHighlightSpan)
|
||||
highlightSpans: highlightSpans.map(({ textSpan, kind, contextSpan }) => ({
|
||||
...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo),
|
||||
kind
|
||||
}))
|
||||
};
|
||||
|
||||
function convertHighlightSpan(highlightSpan: HighlightSpan): protocol.HighlightSpan {
|
||||
const { textSpan, kind } = highlightSpan;
|
||||
const start = scriptInfo.positionToLineOffset(textSpan.start);
|
||||
const end = scriptInfo.positionToLineOffset(textSpanEnd(textSpan));
|
||||
return { start, end, kind };
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private setCompilerOptionsForInferredProjects(args: protocol.SetCompilerOptionsForInferredProjectsArgs): void {
|
||||
@@ -1258,7 +1264,7 @@ namespace ts.server {
|
||||
if (info.canRename) {
|
||||
const { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan } = info;
|
||||
return identity<protocol.RenameInfoSuccess>(
|
||||
{ canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: this.toLocationTextSpan(triggerSpan, scriptInfo) });
|
||||
{ canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: toProcolTextSpan(triggerSpan, scriptInfo) });
|
||||
}
|
||||
else {
|
||||
return info;
|
||||
@@ -1267,11 +1273,11 @@ namespace ts.server {
|
||||
|
||||
private toSpanGroups(locations: ReadonlyArray<RenameLocation>): ReadonlyArray<protocol.SpanGroup> {
|
||||
const map = createMap<protocol.SpanGroup>();
|
||||
for (const { fileName, textSpan, originalTextSpan: _, originalFileName: _1, ...prefixSuffixText } of locations) {
|
||||
for (const { fileName, textSpan, contextSpan, originalContextSpan: _2, originalTextSpan: _, originalFileName: _1, ...prefixSuffixText } of locations) {
|
||||
let group = map.get(fileName);
|
||||
if (!group) map.set(fileName, group = { file: fileName, locs: [] });
|
||||
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
|
||||
group.locs.push({ ...this.toLocationTextSpan(textSpan, scriptInfo), ...prefixSuffixText });
|
||||
group.locs.push({ ...toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo), ...prefixSuffixText });
|
||||
}
|
||||
return arrayFrom(map.values());
|
||||
}
|
||||
@@ -1286,30 +1292,31 @@ namespace ts.server {
|
||||
{ fileName: args.file, pos: position },
|
||||
);
|
||||
|
||||
if (simplifiedResult) {
|
||||
const defaultProject = this.getDefaultProject(args);
|
||||
const scriptInfo = defaultProject.getScriptInfoForNormalizedPath(file)!;
|
||||
const nameInfo = defaultProject.getLanguageService().getQuickInfoAtPosition(file, position);
|
||||
const symbolDisplayString = nameInfo ? displayPartsToString(nameInfo.displayParts) : "";
|
||||
const nameSpan = nameInfo && nameInfo.textSpan;
|
||||
const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
|
||||
const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
|
||||
const refs: ReadonlyArray<protocol.ReferencesResponseItem> = flatMap(references, referencedSymbol =>
|
||||
referencedSymbol.references.map(({ fileName, textSpan, isWriteAccess, isDefinition }): protocol.ReferencesResponseItem => {
|
||||
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
|
||||
const start = scriptInfo.positionToLineOffset(textSpan.start);
|
||||
const lineSpan = scriptInfo.lineToTextSpan(start.line - 1);
|
||||
const lineText = scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, "");
|
||||
return { ...toFileSpan(fileName, textSpan, scriptInfo), lineText, isWriteAccess, isDefinition };
|
||||
}));
|
||||
const result: protocol.ReferencesResponseBody = { refs, symbolName, symbolStartOffset, symbolDisplayString };
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return references;
|
||||
}
|
||||
}
|
||||
if (!simplifiedResult) return references;
|
||||
|
||||
const defaultProject = this.getDefaultProject(args);
|
||||
const scriptInfo = defaultProject.getScriptInfoForNormalizedPath(file)!;
|
||||
const nameInfo = defaultProject.getLanguageService().getQuickInfoAtPosition(file, position);
|
||||
const symbolDisplayString = nameInfo ? displayPartsToString(nameInfo.displayParts) : "";
|
||||
const nameSpan = nameInfo && nameInfo.textSpan;
|
||||
const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
|
||||
const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
|
||||
const refs: ReadonlyArray<protocol.ReferencesResponseItem> = flatMap(references, referencedSymbol =>
|
||||
referencedSymbol.references.map(({ fileName, textSpan, contextSpan, isWriteAccess, isDefinition }): protocol.ReferencesResponseItem => {
|
||||
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
|
||||
const span = toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo);
|
||||
const lineSpan = scriptInfo.lineToTextSpan(span.start.line - 1);
|
||||
const lineText = scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, "");
|
||||
return {
|
||||
file: fileName,
|
||||
...span,
|
||||
lineText,
|
||||
isWriteAccess,
|
||||
isDefinition
|
||||
};
|
||||
}));
|
||||
return { refs, symbolName, symbolStartOffset, symbolDisplayString };
|
||||
}
|
||||
/**
|
||||
* @param fileName is the name of the file to be opened
|
||||
* @param fileContent is a version of the file content that is known to be more up to date than the one on disk
|
||||
@@ -1357,8 +1364,8 @@ namespace ts.server {
|
||||
if (simplifiedResult) {
|
||||
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
|
||||
return spans.map(s => ({
|
||||
textSpan: this.toLocationTextSpan(s.textSpan, scriptInfo),
|
||||
hintSpan: this.toLocationTextSpan(s.hintSpan, scriptInfo),
|
||||
textSpan: toProcolTextSpan(s.textSpan, scriptInfo),
|
||||
hintSpan: toProcolTextSpan(s.hintSpan, scriptInfo),
|
||||
bannerText: s.bannerText,
|
||||
autoCollapse: s.autoCollapse,
|
||||
kind: s.kind
|
||||
@@ -1547,7 +1554,7 @@ namespace ts.server {
|
||||
const entries = mapDefined<CompletionEntry, protocol.CompletionEntry>(completions.entries, entry => {
|
||||
if (completions.isMemberCompletion || startsWith(entry.name.toLowerCase(), prefix.toLowerCase())) {
|
||||
const { name, kind, kindModifiers, sortText, insertText, replacementSpan, hasAction, source, isRecommended } = entry;
|
||||
const convertedSpan = replacementSpan ? this.toLocationTextSpan(replacementSpan, scriptInfo) : undefined;
|
||||
const convertedSpan = replacementSpan ? toProcolTextSpan(replacementSpan, scriptInfo) : undefined;
|
||||
// Use `hasAction || undefined` to avoid serializing `false`.
|
||||
return { name, kind, kindModifiers, sortText, insertText, replacementSpan: convertedSpan, hasAction: hasAction || undefined, source, isRecommended };
|
||||
}
|
||||
@@ -1710,7 +1717,7 @@ namespace ts.server {
|
||||
text: item.text,
|
||||
kind: item.kind,
|
||||
kindModifiers: item.kindModifiers,
|
||||
spans: item.spans.map(span => this.toLocationTextSpan(span, scriptInfo)),
|
||||
spans: item.spans.map(span => toProcolTextSpan(span, scriptInfo)),
|
||||
childItems: this.mapLocationNavigationBarItems(item.childItems, scriptInfo),
|
||||
indent: item.indent
|
||||
}));
|
||||
@@ -1731,19 +1738,12 @@ namespace ts.server {
|
||||
text: tree.text,
|
||||
kind: tree.kind,
|
||||
kindModifiers: tree.kindModifiers,
|
||||
spans: tree.spans.map(span => this.toLocationTextSpan(span, scriptInfo)),
|
||||
nameSpan: tree.nameSpan && this.toLocationTextSpan(tree.nameSpan, scriptInfo),
|
||||
spans: tree.spans.map(span => toProcolTextSpan(span, scriptInfo)),
|
||||
nameSpan: tree.nameSpan && toProcolTextSpan(tree.nameSpan, scriptInfo),
|
||||
childItems: map(tree.childItems, item => this.toLocationNavigationTree(item, scriptInfo))
|
||||
};
|
||||
}
|
||||
|
||||
private toLocationTextSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
|
||||
return {
|
||||
start: scriptInfo.positionToLineOffset(span.start),
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(span))
|
||||
};
|
||||
}
|
||||
|
||||
private getNavigationTree(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.NavigationTree | NavigationTree | undefined {
|
||||
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
|
||||
const tree = languageService.getNavigationTree(file);
|
||||
@@ -2001,7 +2001,7 @@ namespace ts.server {
|
||||
return !spans
|
||||
? undefined
|
||||
: simplifiedResult
|
||||
? spans.map(span => this.toLocationTextSpan(span, scriptInfo))
|
||||
? spans.map(span => toProcolTextSpan(span, scriptInfo))
|
||||
: spans;
|
||||
}
|
||||
|
||||
@@ -2073,7 +2073,7 @@ namespace ts.server {
|
||||
|
||||
private mapSelectionRange(selectionRange: SelectionRange, scriptInfo: ScriptInfo): protocol.SelectionRange {
|
||||
const result: protocol.SelectionRange = {
|
||||
textSpan: this.toLocationTextSpan(selectionRange.textSpan, scriptInfo),
|
||||
textSpan: toProcolTextSpan(selectionRange.textSpan, scriptInfo),
|
||||
};
|
||||
if (selectionRange.parent) {
|
||||
result.parent = this.mapSelectionRange(selectionRange.parent, scriptInfo);
|
||||
@@ -2558,8 +2558,19 @@ namespace ts.server {
|
||||
readonly project: Project;
|
||||
}
|
||||
|
||||
function toFileSpan(fileName: string, textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.FileSpan {
|
||||
return { file: fileName, start: scriptInfo.positionToLineOffset(textSpan.start), end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) };
|
||||
function toProcolTextSpan(textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
|
||||
return {
|
||||
start: scriptInfo.positionToLineOffset(textSpan.start),
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan))
|
||||
};
|
||||
}
|
||||
|
||||
function toProtocolTextSpanWithContext(span: TextSpan, contextSpan: TextSpan | undefined, scriptInfo: ScriptInfo): protocol.TextSpanWithContext {
|
||||
const textSpan = toProcolTextSpan(span, scriptInfo);
|
||||
const contextTextSpan = contextSpan && toProcolTextSpan(contextSpan, scriptInfo);
|
||||
return contextTextSpan ?
|
||||
{ ...textSpan, contextStart: contextTextSpan.start, contextEnd: contextTextSpan.end } :
|
||||
textSpan;
|
||||
}
|
||||
|
||||
function convertTextChangeToCodeEdit(change: TextChange, scriptInfo: ScriptInfoOrConfig): protocol.CodeEdit {
|
||||
|
||||
@@ -42,6 +42,9 @@ namespace ts.codefix {
|
||||
|
||||
// Property declarations
|
||||
Diagnostics.Member_0_implicitly_has_an_1_type_but_a_better_type_may_be_inferred_from_usage.code,
|
||||
|
||||
// Function expressions and declarations
|
||||
Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation.code,
|
||||
];
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
@@ -73,6 +76,8 @@ namespace ts.codefix {
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage.code:
|
||||
return Diagnostics.Infer_parameter_types_from_usage;
|
||||
case Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation.code:
|
||||
return Diagnostics.Infer_this_type_of_0_from_usage;
|
||||
default:
|
||||
return Diagnostics.Infer_type_of_0_from_usage;
|
||||
}
|
||||
@@ -176,6 +181,14 @@ namespace ts.codefix {
|
||||
}
|
||||
return undefined;
|
||||
|
||||
// Function 'this'
|
||||
case Diagnostics.this_implicitly_has_type_any_because_it_does_not_have_a_type_annotation.code:
|
||||
if (textChanges.isThisTypeAnnotatable(containingFunction) && markSeen(containingFunction)) {
|
||||
annotateThis(changes, sourceFile, containingFunction, program, host, cancellationToken);
|
||||
return containingFunction;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
default:
|
||||
return Debug.fail(String(errorCode));
|
||||
}
|
||||
@@ -191,7 +204,9 @@ namespace ts.codefix {
|
||||
if (!isIdentifier(parameterDeclaration.name)) {
|
||||
return;
|
||||
}
|
||||
const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
|
||||
|
||||
const references = inferFunctionReferencesFromUsage(containingFunction, sourceFile, program, cancellationToken);
|
||||
const parameterInferences = InferFromReference.inferTypeForParametersFromReferences(references, containingFunction, program, cancellationToken) ||
|
||||
containingFunction.parameters.map<ParameterInference>(p => ({
|
||||
declaration: p,
|
||||
type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : program.getTypeChecker().getAnyType()
|
||||
@@ -213,6 +228,36 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function annotateThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: textChanges.ThisTypeAnnotatable, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken) {
|
||||
const references = inferFunctionReferencesFromUsage(containingFunction, sourceFile, program, cancellationToken);
|
||||
if (!references) {
|
||||
return;
|
||||
}
|
||||
|
||||
const thisInference = InferFromReference.inferTypeForThisFromReferences(references, program, cancellationToken);
|
||||
if (!thisInference) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeNode = getTypeNodeIfAccessible(thisInference, containingFunction, program, host);
|
||||
if (!typeNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInJSFile(containingFunction)) {
|
||||
annotateJSDocThis(changes, sourceFile, containingFunction, typeNode);
|
||||
}
|
||||
else {
|
||||
changes.tryInsertThisTypeAnnotation(sourceFile, containingFunction, typeNode);
|
||||
}
|
||||
}
|
||||
|
||||
function annotateJSDocThis(changes: textChanges.ChangeTracker, sourceFile: SourceFile, containingFunction: FunctionLike, typeNode: TypeNode) {
|
||||
addJSDocTags(changes, sourceFile, containingFunction, [
|
||||
createJSDocThisTag(createJSDocTypeExpression(typeNode)),
|
||||
]);
|
||||
}
|
||||
|
||||
function annotateSetAccessor(changes: textChanges.ChangeTracker, sourceFile: SourceFile, setAccessorDeclaration: SetAccessorDeclaration, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
|
||||
const param = firstOrUndefined(setAccessorDeclaration.parameters);
|
||||
if (param && isIdentifier(setAccessorDeclaration.name) && isIdentifier(param.name)) {
|
||||
@@ -317,7 +362,7 @@ namespace ts.codefix {
|
||||
return InferFromReference.unifyFromContext(types, checker);
|
||||
}
|
||||
|
||||
function inferTypeForParametersFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
function inferFunctionReferencesFromUsage(containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ReadonlyArray<Identifier> | undefined {
|
||||
let searchToken;
|
||||
switch (containingFunction.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
@@ -335,9 +380,12 @@ namespace ts.codefix {
|
||||
searchToken = containingFunction.name;
|
||||
break;
|
||||
}
|
||||
if (searchToken) {
|
||||
return InferFromReference.inferTypeForParametersFromReferences(getReferences(searchToken, program, cancellationToken), containingFunction, program, cancellationToken);
|
||||
|
||||
if (!searchToken) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getReferences(searchToken, program, cancellationToken);
|
||||
}
|
||||
|
||||
interface ParameterInference {
|
||||
@@ -364,6 +412,7 @@ namespace ts.codefix {
|
||||
constructContexts?: CallContext[];
|
||||
numberIndexContext?: UsageContext;
|
||||
stringIndexContext?: UsageContext;
|
||||
candidateThisTypes?: Type[];
|
||||
}
|
||||
|
||||
export function inferTypesFromReferences(references: ReadonlyArray<Identifier>, checker: TypeChecker, cancellationToken: CancellationToken): Type[] {
|
||||
@@ -375,15 +424,12 @@ namespace ts.codefix {
|
||||
return inferFromContext(usageContext, checker);
|
||||
}
|
||||
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
const checker = program.getTypeChecker();
|
||||
if (references.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!declaration.parameters) {
|
||||
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier> | undefined, declaration: FunctionLike, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
|
||||
if (references === undefined || references.length === 0 || !declaration.parameters) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const usageContext: UsageContext = {};
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
@@ -421,6 +467,22 @@ namespace ts.codefix {
|
||||
});
|
||||
}
|
||||
|
||||
export function inferTypeForThisFromReferences(references: ReadonlyArray<Identifier>, program: Program, cancellationToken: CancellationToken) {
|
||||
if (references.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
const usageContext: UsageContext = {};
|
||||
|
||||
for (const reference of references) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
inferTypeFromContext(reference, checker, usageContext);
|
||||
}
|
||||
|
||||
return unifyFromContext(usageContext.candidateThisTypes || emptyArray, checker);
|
||||
}
|
||||
|
||||
function inferTypeFromContext(node: Expression, checker: TypeChecker, usageContext: UsageContext): void {
|
||||
while (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
|
||||
node = <Expression>node.parent;
|
||||
@@ -455,6 +517,13 @@ namespace ts.codefix {
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
inferTypeFromPropertyElementExpressionContext(<ElementAccessExpression>node.parent, node, checker, usageContext);
|
||||
break;
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
inferTypeFromPropertyAssignment(<PropertyAssignment | ShorthandPropertyAssignment>node.parent, checker, usageContext);
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
inferTypeFromPropertyDeclaration(<PropertyDeclaration>node.parent, checker, usageContext);
|
||||
break;
|
||||
case SyntaxKind.VariableDeclaration: {
|
||||
const { name, initializer } = node.parent as VariableDeclaration;
|
||||
if (node === name) {
|
||||
@@ -647,6 +716,21 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function inferTypeFromPropertyAssignment(assignment: PropertyAssignment | ShorthandPropertyAssignment, checker: TypeChecker, usageContext: UsageContext) {
|
||||
const objectLiteral = isShorthandPropertyAssignment(assignment) ?
|
||||
assignment.parent :
|
||||
assignment.parent.parent;
|
||||
const nodeWithRealType = isVariableDeclaration(objectLiteral.parent) ?
|
||||
objectLiteral.parent :
|
||||
objectLiteral;
|
||||
|
||||
addCandidateThisType(usageContext, checker.getTypeAtLocation(nodeWithRealType));
|
||||
}
|
||||
|
||||
function inferTypeFromPropertyDeclaration(declaration: PropertyDeclaration, checker: TypeChecker, usageContext: UsageContext) {
|
||||
addCandidateThisType(usageContext, checker.getTypeAtLocation(declaration.parent));
|
||||
}
|
||||
|
||||
interface Priority {
|
||||
high: (t: Type) => boolean;
|
||||
low: (t: Type) => boolean;
|
||||
@@ -841,6 +925,12 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
function addCandidateThisType(context: UsageContext, type: Type | undefined) {
|
||||
if (type && !(type.flags & TypeFlags.Any) && !(type.flags & TypeFlags.Never)) {
|
||||
(context.candidateThisTypes || (context.candidateThisTypes = [])).push(type);
|
||||
}
|
||||
}
|
||||
|
||||
function hasCallContext(usageContext: UsageContext | undefined): boolean {
|
||||
return !!usageContext && !!usageContext.callContexts;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,15 @@ namespace ts.FindAllReferences {
|
||||
export const enum EntryKind { Span, Node, StringLiteral, SearchedLocalFoundProperty, SearchedPropertyFoundLocal }
|
||||
export type NodeEntryKind = EntryKind.Node | EntryKind.StringLiteral | EntryKind.SearchedLocalFoundProperty | EntryKind.SearchedPropertyFoundLocal;
|
||||
export type Entry = NodeEntry | SpanEntry;
|
||||
export interface ContextWithStartAndEndNode {
|
||||
start: Node;
|
||||
end: Node;
|
||||
}
|
||||
export type ContextNode = Node | ContextWithStartAndEndNode;
|
||||
export interface NodeEntry {
|
||||
readonly kind: NodeEntryKind;
|
||||
readonly node: Node;
|
||||
readonly context?: ContextNode;
|
||||
}
|
||||
export interface SpanEntry {
|
||||
readonly kind: EntryKind.Span;
|
||||
@@ -26,7 +32,143 @@ namespace ts.FindAllReferences {
|
||||
readonly textSpan: TextSpan;
|
||||
}
|
||||
export function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): NodeEntry {
|
||||
return { kind, node: (node as NamedDeclaration).name || node };
|
||||
return {
|
||||
kind,
|
||||
node: (node as NamedDeclaration).name || node,
|
||||
context: getContextNodeForNodeEntry(node)
|
||||
};
|
||||
}
|
||||
|
||||
export function isContextWithStartAndEndNode(node: ContextNode): node is ContextWithStartAndEndNode {
|
||||
return node && (node as Node).kind === undefined;
|
||||
}
|
||||
|
||||
function getContextNodeForNodeEntry(node: Node): ContextNode | undefined {
|
||||
if (isDeclaration(node)) {
|
||||
return getContextNode(node);
|
||||
}
|
||||
|
||||
if (!node.parent) return undefined;
|
||||
|
||||
if (!isDeclaration(node.parent) && !isExportAssignment(node.parent)) {
|
||||
// Special property assignment in javascript
|
||||
if (isInJSFile(node)) {
|
||||
const binaryExpression = isBinaryExpression(node.parent) ?
|
||||
node.parent :
|
||||
isPropertyAccessExpression(node.parent) &&
|
||||
isBinaryExpression(node.parent.parent) &&
|
||||
node.parent.parent.left === node.parent ?
|
||||
node.parent.parent :
|
||||
undefined;
|
||||
if (binaryExpression && getAssignmentDeclarationKind(binaryExpression) !== AssignmentDeclarationKind.None) {
|
||||
return getContextNode(binaryExpression);
|
||||
}
|
||||
}
|
||||
|
||||
// Jsx Tags
|
||||
if (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) {
|
||||
return node.parent.parent;
|
||||
}
|
||||
else if (isJsxSelfClosingElement(node.parent) ||
|
||||
isLabeledStatement(node.parent) ||
|
||||
isBreakOrContinueStatement(node.parent)) {
|
||||
return node.parent;
|
||||
}
|
||||
else if (isStringLiteralLike(node)) {
|
||||
const validImport = tryGetImportFromModuleSpecifier(node);
|
||||
if (validImport) {
|
||||
const declOrStatement = findAncestor(validImport, node =>
|
||||
isDeclaration(node) ||
|
||||
isStatement(node) ||
|
||||
isJSDocTag(node)
|
||||
)! as NamedDeclaration | Statement | JSDocTag;
|
||||
return isDeclaration(declOrStatement) ?
|
||||
getContextNode(declOrStatement) :
|
||||
declOrStatement;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle computed property name
|
||||
const propertyName = findAncestor(node, isComputedPropertyName);
|
||||
return propertyName ?
|
||||
getContextNode(propertyName.parent) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
if (node.parent.name === node || // node is name of declaration, use parent
|
||||
isConstructorDeclaration(node.parent) ||
|
||||
isExportAssignment(node.parent) ||
|
||||
// Property name of the import export specifier or binding pattern, use parent
|
||||
((isImportOrExportSpecifier(node.parent) || isBindingElement(node.parent))
|
||||
&& node.parent.propertyName === node) ||
|
||||
// Is default export
|
||||
(node.kind === SyntaxKind.DefaultKeyword && hasModifier(node.parent, ModifierFlags.ExportDefault))) {
|
||||
return getContextNode(node.parent);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getContextNode(node: NamedDeclaration | BinaryExpression | ForInOrOfStatement | undefined): ContextNode | undefined {
|
||||
if (!node) return undefined;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return !isVariableDeclarationList(node.parent) || node.parent.declarations.length !== 1 ?
|
||||
node :
|
||||
isVariableStatement(node.parent.parent) ?
|
||||
node.parent.parent :
|
||||
isForInOrOfStatement(node.parent.parent) ?
|
||||
getContextNode(node.parent.parent) :
|
||||
node.parent;
|
||||
|
||||
case SyntaxKind.BindingElement:
|
||||
return getContextNode(node.parent.parent as NamedDeclaration);
|
||||
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
return node.parent.parent.parent;
|
||||
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return node.parent.parent;
|
||||
|
||||
case SyntaxKind.ImportClause:
|
||||
return node.parent;
|
||||
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return isExpressionStatement(node.parent) ?
|
||||
node.parent :
|
||||
node;
|
||||
|
||||
case SyntaxKind.ForOfStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
return {
|
||||
start: (node as ForInOrOfStatement).initializer,
|
||||
end: (node as ForInOrOfStatement).expression
|
||||
};
|
||||
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
return isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent) ?
|
||||
getContextNode(
|
||||
findAncestor(node.parent, node =>
|
||||
isBinaryExpression(node) || isForInOrOfStatement(node)
|
||||
) as BinaryExpression | ForInOrOfStatement
|
||||
) :
|
||||
node;
|
||||
|
||||
default:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
export function toContextSpan(textSpan: TextSpan, sourceFile: SourceFile, context?: ContextNode): { contextSpan: TextSpan } | undefined {
|
||||
if (!context) return undefined;
|
||||
const contextSpan = isContextWithStartAndEndNode(context) ?
|
||||
getTextSpan(context.start, sourceFile, context.end) :
|
||||
getTextSpan(context, sourceFile);
|
||||
return contextSpan.start !== textSpan.start || contextSpan.length !== textSpan.length ?
|
||||
{ contextSpan } :
|
||||
undefined;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
@@ -123,7 +265,16 @@ namespace ts.FindAllReferences {
|
||||
const { symbol } = def;
|
||||
const { displayParts, kind } = getDefinitionKindAndDisplayParts(symbol, checker, originalNode);
|
||||
const name = displayParts.map(p => p.text).join("");
|
||||
return { node: symbol.declarations ? getNameOfDeclaration(first(symbol.declarations)) || first(symbol.declarations) : originalNode, name, kind, displayParts };
|
||||
const declaration = symbol.declarations ? first(symbol.declarations) : undefined;
|
||||
return {
|
||||
node: declaration ?
|
||||
getNameOfDeclaration(declaration) || declaration :
|
||||
originalNode,
|
||||
name,
|
||||
kind,
|
||||
displayParts,
|
||||
context: getContextNode(declaration)
|
||||
};
|
||||
}
|
||||
case DefinitionKind.Label: {
|
||||
const { node } = def;
|
||||
@@ -150,9 +301,19 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
})();
|
||||
|
||||
const { node, name, kind, displayParts } = info;
|
||||
const { node, name, kind, displayParts, context } = info;
|
||||
const sourceFile = node.getSourceFile();
|
||||
return { containerKind: ScriptElementKind.unknown, containerName: "", fileName: sourceFile.fileName, kind, name, textSpan: getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile), displayParts };
|
||||
const textSpan = getTextSpan(isComputedPropertyName(node) ? node.expression : node, sourceFile);
|
||||
return {
|
||||
containerKind: ScriptElementKind.unknown,
|
||||
containerName: "",
|
||||
fileName: sourceFile.fileName,
|
||||
kind,
|
||||
name,
|
||||
textSpan,
|
||||
displayParts,
|
||||
...toContextSpan(textSpan, sourceFile, context)
|
||||
};
|
||||
}
|
||||
|
||||
function getDefinitionKindAndDisplayParts(symbol: Symbol, checker: TypeChecker, node: Node): { displayParts: SymbolDisplayPart[], kind: ScriptElementKind } {
|
||||
@@ -168,14 +329,13 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function toReferenceEntry(entry: Entry): ReferenceEntry {
|
||||
const { textSpan, fileName } = entryToDocumentSpan(entry);
|
||||
const documentSpan = entryToDocumentSpan(entry);
|
||||
if (entry.kind === EntryKind.Span) {
|
||||
return { textSpan, fileName, isWriteAccess: false, isDefinition: false };
|
||||
return { ...documentSpan, isWriteAccess: false, isDefinition: false };
|
||||
}
|
||||
const { kind, node } = entry;
|
||||
return {
|
||||
textSpan,
|
||||
fileName,
|
||||
...documentSpan,
|
||||
isWriteAccess: isWriteAccessForReference(node),
|
||||
isDefinition: node.kind === SyntaxKind.DefaultKeyword
|
||||
|| !!getDeclarationFromName(node)
|
||||
@@ -190,7 +350,12 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
else {
|
||||
const sourceFile = entry.node.getSourceFile();
|
||||
return { textSpan: getTextSpan(entry.node, sourceFile), fileName: sourceFile.fileName };
|
||||
const textSpan = getTextSpan(entry.node, sourceFile);
|
||||
return {
|
||||
textSpan,
|
||||
fileName: sourceFile.fileName,
|
||||
...toContextSpan(textSpan, sourceFile, entry.context)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,14 +388,16 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
function toImplementationLocation(entry: Entry, checker: TypeChecker): ImplementationLocation {
|
||||
const documentSpan = entryToDocumentSpan(entry);
|
||||
if (entry.kind !== EntryKind.Span) {
|
||||
const { node } = entry;
|
||||
const sourceFile = node.getSourceFile();
|
||||
return { textSpan: getTextSpan(node, sourceFile), fileName: sourceFile.fileName, ...implementationKindDisplayParts(node, checker) };
|
||||
return {
|
||||
...documentSpan,
|
||||
...implementationKindDisplayParts(node, checker)
|
||||
};
|
||||
}
|
||||
else {
|
||||
const { textSpan, fileName } = entry;
|
||||
return { textSpan, fileName, kind: ScriptElementKind.unknown, displayParts: [] };
|
||||
return { ...documentSpan, kind: ScriptElementKind.unknown, displayParts: [] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,26 +424,32 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
|
||||
export function toHighlightSpan(entry: Entry): { fileName: string, span: HighlightSpan } {
|
||||
const documentSpan = entryToDocumentSpan(entry);
|
||||
if (entry.kind === EntryKind.Span) {
|
||||
const { fileName, textSpan } = entry;
|
||||
return { fileName, span: { textSpan, kind: HighlightSpanKind.reference } };
|
||||
return {
|
||||
fileName: documentSpan.fileName,
|
||||
span: {
|
||||
textSpan: documentSpan.textSpan,
|
||||
kind: HighlightSpanKind.reference
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const { node, kind } = entry;
|
||||
const sourceFile = node.getSourceFile();
|
||||
const writeAccess = isWriteAccessForReference(node);
|
||||
const writeAccess = isWriteAccessForReference(entry.node);
|
||||
const span: HighlightSpan = {
|
||||
textSpan: getTextSpan(node, sourceFile),
|
||||
textSpan: documentSpan.textSpan,
|
||||
kind: writeAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference,
|
||||
isInString: kind === EntryKind.StringLiteral ? true : undefined,
|
||||
isInString: entry.kind === EntryKind.StringLiteral ? true : undefined,
|
||||
...documentSpan.contextSpan && { contextSpan: documentSpan.contextSpan }
|
||||
};
|
||||
return { fileName: sourceFile.fileName, span };
|
||||
return { fileName: documentSpan.fileName, span };
|
||||
}
|
||||
|
||||
function getTextSpan(node: Node, sourceFile: SourceFile): TextSpan {
|
||||
function getTextSpan(node: Node, sourceFile: SourceFile, endNode?: Node): TextSpan {
|
||||
let start = node.getStart(sourceFile);
|
||||
let end = node.getEnd();
|
||||
let end = (endNode || node).getEnd();
|
||||
if (node.kind === SyntaxKind.StringLiteral) {
|
||||
Debug.assert(endNode === undefined);
|
||||
start += 1;
|
||||
end -= 1;
|
||||
}
|
||||
|
||||
@@ -273,13 +273,19 @@ namespace ts.GoToDefinition {
|
||||
function createDefinitionInfoFromName(declaration: Declaration, symbolKind: ScriptElementKind, symbolName: string, containerName: string): DefinitionInfo {
|
||||
const name = getNameOfDeclaration(declaration) || declaration;
|
||||
const sourceFile = name.getSourceFile();
|
||||
const textSpan = createTextSpanFromNode(name, sourceFile);
|
||||
return {
|
||||
fileName: sourceFile.fileName,
|
||||
textSpan: createTextSpanFromNode(name, sourceFile),
|
||||
textSpan,
|
||||
kind: symbolKind,
|
||||
name: symbolName,
|
||||
containerKind: undefined!, // TODO: GH#18217
|
||||
containerName
|
||||
containerName,
|
||||
...FindAllReferences.toContextSpan(
|
||||
textSpan,
|
||||
sourceFile,
|
||||
FindAllReferences.getContextNode(declaration)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1544,13 +1544,17 @@ namespace ts {
|
||||
|
||||
/// References and Occurrences
|
||||
function getOccurrencesAtPosition(fileName: string, position: number): ReadonlyArray<ReferenceEntry> | undefined {
|
||||
return flatMap(getDocumentHighlights(fileName, position, [fileName]), entry => entry.highlightSpans.map<ReferenceEntry>(highlightSpan => ({
|
||||
fileName: entry.fileName,
|
||||
textSpan: highlightSpan.textSpan,
|
||||
isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference,
|
||||
isDefinition: false,
|
||||
isInString: highlightSpan.isInString,
|
||||
})));
|
||||
return flatMap(
|
||||
getDocumentHighlights(fileName, position, [fileName]),
|
||||
entry => entry.highlightSpans.map<ReferenceEntry>(highlightSpan => ({
|
||||
fileName: entry.fileName,
|
||||
textSpan: highlightSpan.textSpan,
|
||||
isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference,
|
||||
isDefinition: false,
|
||||
...highlightSpan.isInString && { isInString: true },
|
||||
...highlightSpan.contextSpan && { contextSpan: highlightSpan.contextSpan }
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
function getDocumentHighlights(fileName: string, position: number, filesToSearch: ReadonlyArray<string>): DocumentHighlights[] | undefined {
|
||||
@@ -1568,8 +1572,14 @@ namespace ts {
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
if (isIdentifier(node) && (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) && isIntrinsicJsxName(node.escapedText)) {
|
||||
const { openingElement, closingElement } = node.parent.parent;
|
||||
return [openingElement, closingElement].map((node): RenameLocation =>
|
||||
({ fileName: sourceFile.fileName, textSpan: createTextSpanFromNode(node.tagName, sourceFile) }));
|
||||
return [openingElement, closingElement].map((node): RenameLocation => {
|
||||
const textSpan = createTextSpanFromNode(node.tagName, sourceFile);
|
||||
return {
|
||||
fileName: sourceFile.fileName,
|
||||
textSpan,
|
||||
...FindAllReferences.toContextSpan(textSpan, sourceFile, node.parent)
|
||||
};
|
||||
});
|
||||
}
|
||||
else {
|
||||
return getReferencesWorker(node, position, { findInStrings, findInComments, providePrefixAndSuffixTextForRename, isForRename: true },
|
||||
|
||||
@@ -222,6 +222,12 @@ namespace ts.textChanges {
|
||||
|
||||
export type TypeAnnotatable = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature;
|
||||
|
||||
export type ThisTypeAnnotatable = FunctionDeclaration | FunctionExpression;
|
||||
|
||||
export function isThisTypeAnnotatable(containingFunction: FunctionLike): containingFunction is ThisTypeAnnotatable {
|
||||
return isFunctionExpression(containingFunction) || isFunctionDeclaration(containingFunction);
|
||||
}
|
||||
|
||||
export class ChangeTracker {
|
||||
private readonly changes: Change[] = [];
|
||||
private readonly newFiles: { readonly oldFile: SourceFile | undefined, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
|
||||
@@ -393,6 +399,13 @@ namespace ts.textChanges {
|
||||
this.insertNodeAt(sourceFile, endNode.end, type, { prefix: ": " });
|
||||
}
|
||||
|
||||
public tryInsertThisTypeAnnotation(sourceFile: SourceFile, node: ThisTypeAnnotatable, type: TypeNode): void {
|
||||
const start = findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile)!.getStart(sourceFile) + 1;
|
||||
const suffix = node.parameters.length ? ", " : "";
|
||||
|
||||
this.insertNodeAt(sourceFile, start, type, { prefix: "this: ", suffix });
|
||||
}
|
||||
|
||||
public insertTypeParameters(sourceFile: SourceFile, node: SignatureDeclaration, typeParameters: ReadonlyArray<TypeParameterDeclaration>): void {
|
||||
// If no `(`, is an arrow function `x => x`, so use the pos of the first parameter
|
||||
const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart(sourceFile);
|
||||
|
||||
@@ -613,6 +613,13 @@ namespace ts {
|
||||
*/
|
||||
originalTextSpan?: TextSpan;
|
||||
originalFileName?: string;
|
||||
|
||||
/**
|
||||
* If DocumentSpan.textSpan is the span for name of the declaration,
|
||||
* then this is the span for relevant declaration
|
||||
*/
|
||||
contextSpan?: TextSpan;
|
||||
originalContextSpan?: TextSpan;
|
||||
}
|
||||
|
||||
export interface RenameLocation extends DocumentSpan {
|
||||
@@ -647,6 +654,7 @@ namespace ts {
|
||||
fileName?: string;
|
||||
isInString?: true;
|
||||
textSpan: TextSpan;
|
||||
contextSpan?: TextSpan;
|
||||
kind: HighlightSpanKind;
|
||||
}
|
||||
|
||||
|
||||
@@ -1190,8 +1190,8 @@ namespace ts {
|
||||
return !!range && shouldBeReference === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end));
|
||||
}
|
||||
|
||||
export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile): TextSpan {
|
||||
return createTextSpanFromBounds(node.getStart(sourceFile), node.getEnd());
|
||||
export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile, endNode?: Node): TextSpan {
|
||||
return createTextSpanFromBounds(node.getStart(sourceFile), (endNode || node).getEnd());
|
||||
}
|
||||
|
||||
export function createTextRangeFromNode(node: Node, sourceFile: SourceFile): TextRange {
|
||||
|
||||
@@ -1,28 +1,43 @@
|
||||
namespace ts.projectSystem {
|
||||
function protocolFileSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): protocol.FileSpan {
|
||||
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, substring, options) };
|
||||
interface DocumentSpanFromSubstring {
|
||||
file: File;
|
||||
text: string;
|
||||
options?: SpanFromSubstringOptions;
|
||||
contextText?: string;
|
||||
contextOptions?: SpanFromSubstringOptions;
|
||||
}
|
||||
|
||||
function documentSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): DocumentSpan {
|
||||
return { fileName: file.path, textSpan: textSpanFromSubstring(file.content, substring, options) };
|
||||
}
|
||||
|
||||
function renameLocation(file: File, substring: string, options?: SpanFromSubstringOptions): RenameLocation {
|
||||
return documentSpanFromSubstring(file, substring, options);
|
||||
}
|
||||
|
||||
function makeReferenceItem(file: File, isDefinition: boolean, text: string, lineText: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
|
||||
function documentSpanFromSubstring({ file, text, contextText, options, contextOptions }: DocumentSpanFromSubstring): DocumentSpan {
|
||||
const contextSpan = contextText !== undefined ? documentSpanFromSubstring({ file, text: contextText, options: contextOptions }) : undefined;
|
||||
return {
|
||||
...protocolFileSpanFromSubstring(file, text, options),
|
||||
fileName: file.path,
|
||||
textSpan: textSpanFromSubstring(file.content, text, options),
|
||||
...contextSpan && { contextSpan: contextSpan.textSpan }
|
||||
};
|
||||
}
|
||||
|
||||
function renameLocation(input: DocumentSpanFromSubstring): RenameLocation {
|
||||
return documentSpanFromSubstring(input);
|
||||
}
|
||||
|
||||
interface MakeReferenceItem extends DocumentSpanFromSubstring {
|
||||
isDefinition: boolean;
|
||||
lineText: string;
|
||||
}
|
||||
function makeReferenceItem({ isDefinition, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
|
||||
return {
|
||||
...protocolFileSpanWithContextFromSubstring(rest),
|
||||
isDefinition,
|
||||
isWriteAccess: isDefinition,
|
||||
lineText,
|
||||
};
|
||||
}
|
||||
|
||||
function makeReferenceEntry(file: File, isDefinition: boolean, text: string, options?: SpanFromSubstringOptions): ReferenceEntry {
|
||||
interface MakeReferenceEntry extends DocumentSpanFromSubstring {
|
||||
isDefinition: boolean;
|
||||
}
|
||||
function makeReferenceEntry({ isDefinition, ...rest }: MakeReferenceEntry): ReferenceEntry {
|
||||
return {
|
||||
...documentSpanFromSubstring(file, text, options),
|
||||
...documentSpanFromSubstring(rest),
|
||||
isDefinition,
|
||||
isWriteAccess: isDefinition,
|
||||
isInString: undefined,
|
||||
@@ -190,7 +205,13 @@ namespace ts.projectSystem {
|
||||
it("goToDefinition", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]);
|
||||
assert.deepEqual(response, [
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
})
|
||||
]);
|
||||
verifySingleInferredProject(session);
|
||||
});
|
||||
|
||||
@@ -199,7 +220,13 @@ namespace ts.projectSystem {
|
||||
const response = executeSessionRequest<protocol.DefinitionAndBoundSpanRequest, protocol.DefinitionAndBoundSpanResponse>(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, {
|
||||
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
definitions: [protocolFileSpanFromSubstring(aTs, "fnA")],
|
||||
definitions: [
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
})
|
||||
],
|
||||
});
|
||||
verifySingleInferredProject(session);
|
||||
});
|
||||
@@ -209,7 +236,13 @@ namespace ts.projectSystem {
|
||||
const response = executeSessionRequest<protocol.DefinitionAndBoundSpanRequest, protocol.DefinitionAndBoundSpanResponse>(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, {
|
||||
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA"),
|
||||
definitions: [protocolFileSpanFromSubstring(aTs, "fnA")],
|
||||
definitions: [
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
})
|
||||
],
|
||||
});
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
|
||||
verifyUserTsConfigProject(session);
|
||||
@@ -230,14 +263,25 @@ namespace ts.projectSystem {
|
||||
it("goToType", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.TypeDefinitionRequest, protocol.TypeDefinitionResponse>(session, protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA"));
|
||||
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "IfaceA")]);
|
||||
assert.deepEqual(response, [
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "IfaceA",
|
||||
contextText: "export interface IfaceA {}"
|
||||
})
|
||||
]);
|
||||
verifySingleInferredProject(session);
|
||||
});
|
||||
|
||||
it("goToImplementation", () => {
|
||||
const session = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.ImplementationRequest, protocol.ImplementationResponse>(session, protocol.CommandTypes.Implementation, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]);
|
||||
assert.deepEqual(response, [
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
})]);
|
||||
verifySingleInferredProject(session);
|
||||
});
|
||||
|
||||
@@ -245,7 +289,13 @@ namespace ts.projectSystem {
|
||||
const session = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, CommandNames.Definition, protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
// bTs does not exist, so stick with bDts
|
||||
assert.deepEqual(response, [protocolFileSpanFromSubstring(bDts, "fnB")]);
|
||||
assert.deepEqual(response, [
|
||||
protocolFileSpanWithContextFromSubstring({
|
||||
file: bDts,
|
||||
text: "fnB",
|
||||
contextText: "export declare function fnB(): void;"
|
||||
})
|
||||
]);
|
||||
verifySingleInferredProject(session);
|
||||
});
|
||||
|
||||
@@ -254,7 +304,10 @@ namespace ts.projectSystem {
|
||||
const response = executeSessionRequest<protocol.NavtoRequest, protocol.NavtoResponse>(session, CommandNames.Navto, { file: userTs.path, searchValue: "fn" });
|
||||
assert.deepEqual<ReadonlyArray<protocol.NavtoItem> | undefined>(response, [
|
||||
{
|
||||
...protocolFileSpanFromSubstring(bDts, "export declare function fnB(): void;"),
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: bDts,
|
||||
text: "export declare function fnB(): void;"
|
||||
}),
|
||||
name: "fnB",
|
||||
matchKind: "prefix",
|
||||
isCaseSensitive: true,
|
||||
@@ -262,7 +315,10 @@ namespace ts.projectSystem {
|
||||
kindModifiers: "export,declare",
|
||||
},
|
||||
{
|
||||
...protocolFileSpanFromSubstring(userTs, "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"),
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: userTs,
|
||||
text: "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"
|
||||
}),
|
||||
name: "fnUser",
|
||||
matchKind: "prefix",
|
||||
isCaseSensitive: true,
|
||||
@@ -270,7 +326,10 @@ namespace ts.projectSystem {
|
||||
kindModifiers: "export",
|
||||
},
|
||||
{
|
||||
...protocolFileSpanFromSubstring(aTs, "export function fnA() {}"),
|
||||
...protocolFileSpanFromSubstring({
|
||||
file: aTs,
|
||||
text: "export function fnA() {}"
|
||||
}),
|
||||
name: "fnA",
|
||||
matchKind: "prefix",
|
||||
isCaseSensitive: true,
|
||||
@@ -282,9 +341,20 @@ namespace ts.projectSystem {
|
||||
verifyATsConfigOriginalProject(session);
|
||||
});
|
||||
|
||||
const referenceATs = (aTs: File): protocol.ReferencesResponseItem => makeReferenceItem(aTs, /*isDefinition*/ true, "fnA", "export function fnA() {}");
|
||||
const referenceATs = (aTs: File): protocol.ReferencesResponseItem => makeReferenceItem({
|
||||
file: aTs,
|
||||
isDefinition: true,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}",
|
||||
lineText: "export function fnA() {}"
|
||||
});
|
||||
const referencesUserTs = (userTs: File): ReadonlyArray<protocol.ReferencesResponseItem> => [
|
||||
makeReferenceItem(userTs, /*isDefinition*/ false, "fnA", "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"),
|
||||
makeReferenceItem({
|
||||
file: userTs,
|
||||
isDefinition: false,
|
||||
text: "fnA",
|
||||
lineText: "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"
|
||||
}),
|
||||
];
|
||||
|
||||
it("findAllReferences", () => {
|
||||
@@ -325,7 +395,11 @@ namespace ts.projectSystem {
|
||||
assert.deepEqual<ReadonlyArray<ReferencedSymbol>>(responseFull, [
|
||||
{
|
||||
definition: {
|
||||
...documentSpanFromSubstring(aTs, "fnA"),
|
||||
...documentSpanFromSubstring({
|
||||
file: aTs,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
}),
|
||||
kind: ScriptElementKind.functionElement,
|
||||
name: "function fnA(): void",
|
||||
containerKind: ScriptElementKind.unknown,
|
||||
@@ -342,8 +416,8 @@ namespace ts.projectSystem {
|
||||
],
|
||||
},
|
||||
references: [
|
||||
makeReferenceEntry(userTs, /*isDefinition*/ false, "fnA"),
|
||||
makeReferenceEntry(aTs, /*isDefinition*/ true, "fnA"),
|
||||
makeReferenceEntry({ file: userTs, /*isDefinition*/ isDefinition: false, text: "fnA" }),
|
||||
makeReferenceEntry({ file: aTs, /*isDefinition*/ isDefinition: true, text: "fnA", contextText: "export function fnA() {}" }),
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -374,6 +448,12 @@ namespace ts.projectSystem {
|
||||
assert.deepEqual<ReadonlyArray<ReferencedSymbol>>(responseFull, [
|
||||
{
|
||||
definition: {
|
||||
...documentSpanFromSubstring({
|
||||
file: aTs,
|
||||
text: "f",
|
||||
options: { index: 1 },
|
||||
contextText: "function f() {}"
|
||||
}),
|
||||
containerKind: ScriptElementKind.unknown,
|
||||
containerName: "",
|
||||
displayParts: [
|
||||
@@ -386,10 +466,8 @@ namespace ts.projectSystem {
|
||||
spacePart(),
|
||||
keywordPart(SyntaxKind.VoidKeyword),
|
||||
],
|
||||
fileName: aTs.path,
|
||||
kind: ScriptElementKind.functionElement,
|
||||
name: "function f(): void",
|
||||
textSpan: { start: 9, length: 1 },
|
||||
},
|
||||
references: [
|
||||
{
|
||||
@@ -399,13 +477,13 @@ namespace ts.projectSystem {
|
||||
isWriteAccess: false,
|
||||
textSpan: { start: 0, length: 1 },
|
||||
},
|
||||
{
|
||||
fileName: aTs.path,
|
||||
isDefinition: true,
|
||||
isInString: undefined,
|
||||
isWriteAccess: true,
|
||||
textSpan: { start: 9, length: 1 },
|
||||
},
|
||||
makeReferenceEntry({
|
||||
file: aTs,
|
||||
text: "f",
|
||||
options: { index: 1 },
|
||||
contextText: "function f() {}",
|
||||
isDefinition: true
|
||||
})
|
||||
],
|
||||
}
|
||||
]);
|
||||
@@ -417,8 +495,19 @@ namespace ts.projectSystem {
|
||||
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()"));
|
||||
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
|
||||
refs: [
|
||||
makeReferenceItem(bDts, /*isDefinition*/ true, "fnB", "export declare function fnB(): void;"),
|
||||
makeReferenceItem(userTs, /*isDefinition*/ false, "fnB", "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"),
|
||||
makeReferenceItem({
|
||||
file: bDts,
|
||||
isDefinition: true,
|
||||
text: "fnB",
|
||||
contextText: "export declare function fnB(): void;",
|
||||
lineText: "export declare function fnB(): void;"
|
||||
}),
|
||||
makeReferenceItem({
|
||||
file: userTs,
|
||||
isDefinition: false,
|
||||
text: "fnB",
|
||||
lineText: "export function fnUser() { a.fnA(); b.fnB(); a.instanceA; }"
|
||||
}),
|
||||
],
|
||||
symbolName: "fnB",
|
||||
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnB()").offset,
|
||||
@@ -429,11 +518,22 @@ namespace ts.projectSystem {
|
||||
|
||||
const renameATs = (aTs: File): protocol.SpanGroup => ({
|
||||
file: aTs.path,
|
||||
locs: [protocolRenameSpanFromSubstring(aTs.content, "fnA")],
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "fnA",
|
||||
contextText: "export function fnA() {}"
|
||||
})
|
||||
],
|
||||
});
|
||||
const renameUserTs = (userTs: File): protocol.SpanGroup => ({
|
||||
file: userTs.path,
|
||||
locs: [protocolRenameSpanFromSubstring(userTs.content, "fnA")],
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: userTs.content,
|
||||
text: "fnA"
|
||||
})
|
||||
],
|
||||
});
|
||||
|
||||
it("renameLocations", () => {
|
||||
@@ -477,8 +577,8 @@ namespace ts.projectSystem {
|
||||
const session = makeSampleProjects();
|
||||
const response = executeSessionRequest<protocol.RenameFullRequest, protocol.RenameFullResponse>(session, protocol.CommandTypes.RenameLocationsFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
assert.deepEqual<ReadonlyArray<RenameLocation>>(response, [
|
||||
renameLocation(userTs, "fnA"),
|
||||
renameLocation(aTs, "fnA"),
|
||||
renameLocation({ file: userTs, text: "fnA" }),
|
||||
renameLocation({ file: aTs, text: "fnA", contextText: "export function fnA() {}" }),
|
||||
]);
|
||||
verifyATsConfigOriginalProject(session);
|
||||
});
|
||||
@@ -499,11 +599,22 @@ namespace ts.projectSystem {
|
||||
locs: [
|
||||
{
|
||||
file: bDts.path,
|
||||
locs: [protocolRenameSpanFromSubstring(bDts.content, "fnB")],
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: bDts.content,
|
||||
text: "fnB",
|
||||
contextText: "export declare function fnB(): void;"
|
||||
})
|
||||
],
|
||||
},
|
||||
{
|
||||
file: userTs.path,
|
||||
locs: [protocolRenameSpanFromSubstring(userTs.content, "fnB")],
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: userTs.content,
|
||||
text: "fnB"
|
||||
})
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -512,13 +512,68 @@ namespace ts.projectSystem {
|
||||
return { start: toLocation(span.start), end: toLocation(textSpanEnd(span)) };
|
||||
}
|
||||
|
||||
export function protocolRenameSpanFromSubstring(
|
||||
str: string,
|
||||
substring: string,
|
||||
options?: SpanFromSubstringOptions,
|
||||
prefixSuffixText?: { readonly prefixText?: string, readonly suffixText?: string },
|
||||
): protocol.RenameTextSpan {
|
||||
return { ...protocolTextSpanFromSubstring(str, substring, options), ...prefixSuffixText };
|
||||
export interface DocumentSpanFromSubstring {
|
||||
file: File;
|
||||
text: string;
|
||||
options?: SpanFromSubstringOptions;
|
||||
}
|
||||
export function protocolFileSpanFromSubstring({ file, text, options }: DocumentSpanFromSubstring): protocol.FileSpan {
|
||||
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, text, options) };
|
||||
}
|
||||
|
||||
interface FileSpanWithContextFromSubString {
|
||||
file: File;
|
||||
text: string;
|
||||
options?: SpanFromSubstringOptions;
|
||||
contextText?: string;
|
||||
contextOptions?: SpanFromSubstringOptions;
|
||||
}
|
||||
export function protocolFileSpanWithContextFromSubstring({ contextText, contextOptions, ...rest }: FileSpanWithContextFromSubString): protocol.FileSpanWithContext {
|
||||
const result = protocolFileSpanFromSubstring(rest);
|
||||
const contextSpan = contextText !== undefined ?
|
||||
protocolFileSpanFromSubstring({ file: rest.file, text: contextText, options: contextOptions }) :
|
||||
undefined;
|
||||
return contextSpan ?
|
||||
{
|
||||
...result,
|
||||
contextStart: contextSpan.start,
|
||||
contextEnd: contextSpan.end
|
||||
} :
|
||||
result;
|
||||
}
|
||||
|
||||
export interface ProtocolTextSpanWithContextFromString {
|
||||
fileText: string;
|
||||
text: string;
|
||||
options?: SpanFromSubstringOptions;
|
||||
contextText?: string;
|
||||
contextOptions?: SpanFromSubstringOptions;
|
||||
}
|
||||
export function protocolTextSpanWithContextFromSubstring({ fileText, text, options, contextText, contextOptions }: ProtocolTextSpanWithContextFromString): protocol.TextSpanWithContext {
|
||||
const span = textSpanFromSubstring(fileText, text, options);
|
||||
const toLocation = protocolToLocation(fileText);
|
||||
const contextSpan = contextText !== undefined ? textSpanFromSubstring(fileText, contextText, contextOptions) : undefined;
|
||||
return {
|
||||
start: toLocation(span.start),
|
||||
end: toLocation(textSpanEnd(span)),
|
||||
...contextSpan && {
|
||||
contextStart: toLocation(contextSpan.start),
|
||||
contextEnd: toLocation(textSpanEnd(contextSpan))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProtocolRenameSpanFromSubstring extends ProtocolTextSpanWithContextFromString {
|
||||
prefixSuffixText?: {
|
||||
readonly prefixText?: string;
|
||||
readonly suffixText?: string;
|
||||
};
|
||||
}
|
||||
export function protocolRenameSpanFromSubstring({ prefixSuffixText, ...rest }: ProtocolRenameSpanFromSubstring): protocol.RenameTextSpan {
|
||||
return {
|
||||
...protocolTextSpanWithContextFromSubstring(rest),
|
||||
...prefixSuffixText
|
||||
};
|
||||
}
|
||||
|
||||
export function textSpanFromSubstring(str: string, substring: string, options?: SpanFromSubstringOptions): TextSpan {
|
||||
|
||||
@@ -69,21 +69,24 @@ namespace ts.projectSystem {
|
||||
openFilesForSession([containerCompositeExec[1]], session);
|
||||
const service = session.getProjectService();
|
||||
checkNumberOfProjects(service, { configuredProjects: 1 });
|
||||
const locationOfMyConst = protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst");
|
||||
const { file: myConstFile, start: myConstStart, end: myConstEnd } = protocolFileSpanFromSubstring({
|
||||
file: containerCompositeExec[1],
|
||||
text: "myConst",
|
||||
});
|
||||
const response = session.executeCommandSeq<protocol.RenameRequest>({
|
||||
command: protocol.CommandTypes.Rename,
|
||||
arguments: {
|
||||
file: containerCompositeExec[1].path,
|
||||
...locationOfMyConst
|
||||
}
|
||||
arguments: { file: myConstFile, ...myConstStart }
|
||||
}).response as protocol.RenameResponseBody;
|
||||
|
||||
|
||||
const myConstLen = "myConst".length;
|
||||
const locationOfMyConstInLib = protocolLocationFromSubstring(containerLib[1].content, "myConst");
|
||||
const locationOfMyConstInLib = protocolFileSpanWithContextFromSubstring({
|
||||
file: containerLib[1],
|
||||
text: "myConst",
|
||||
contextText: "export const myConst = 30;"
|
||||
});
|
||||
const { file: _, ...renameTextOfMyConstInLib } = locationOfMyConstInLib;
|
||||
assert.deepEqual(response.locs, [
|
||||
{ file: containerCompositeExec[1].path, locs: [{ start: locationOfMyConst, end: { line: locationOfMyConst.line, offset: locationOfMyConst.offset + myConstLen } }] },
|
||||
{ file: containerLib[1].path, locs: [{ start: locationOfMyConstInLib, end: { line: locationOfMyConstInLib.line, offset: locationOfMyConstInLib.offset + myConstLen } }] }
|
||||
{ file: myConstFile, locs: [{ start: myConstStart, end: myConstEnd }] },
|
||||
{ file: locationOfMyConstInLib.file, locs: [renameTextOfMyConstInLib] }
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -169,7 +172,7 @@ fn5();
|
||||
}
|
||||
function gotoDefintinionFromMainTs(fn: number): SessionAction<protocol.DefinitionAndBoundSpanRequest, protocol.DefinitionInfoAndBoundSpan> {
|
||||
const textSpan = usageSpan(fn);
|
||||
const definition: protocol.FileSpan = { file: dependencyTs.path, ...definitionSpan(fn) };
|
||||
const definition: protocol.FileSpan = { file: dependencyTs.path, ...declarationSpan(fn) };
|
||||
const declareSpaceLength = "declare ".length;
|
||||
return {
|
||||
reqName: "goToDef",
|
||||
@@ -184,7 +187,13 @@ fn5();
|
||||
},
|
||||
expectedResponseNoMap: {
|
||||
// To the dts
|
||||
definitions: [{ file: dtsPath, start: { line: fn, offset: definition.start.offset + declareSpaceLength }, end: { line: fn, offset: definition.end.offset + declareSpaceLength } }],
|
||||
definitions: [{
|
||||
file: dtsPath,
|
||||
start: { line: fn, offset: definition.start.offset + declareSpaceLength },
|
||||
end: { line: fn, offset: definition.end.offset + declareSpaceLength },
|
||||
contextStart: { line: fn, offset: 1 },
|
||||
contextEnd: { line: fn, offset: 37 }
|
||||
}],
|
||||
textSpan
|
||||
},
|
||||
expectedResponseNoDts: {
|
||||
@@ -195,18 +204,29 @@ fn5();
|
||||
};
|
||||
}
|
||||
|
||||
function definitionSpan(fn: number): protocol.TextSpan {
|
||||
return { start: { line: fn, offset: 17 }, end: { line: fn, offset: 20 } };
|
||||
function declarationSpan(fn: number): protocol.TextSpanWithContext {
|
||||
return {
|
||||
start: { line: fn, offset: 17 },
|
||||
end: { line: fn, offset: 20 },
|
||||
contextStart: { line: fn, offset: 1 },
|
||||
contextEnd: { line: fn, offset: 26 }
|
||||
};
|
||||
}
|
||||
function importSpan(fn: number): protocol.TextSpan {
|
||||
return { start: { line: fn + 1, offset: 5 }, end: { line: fn + 1, offset: 8 } };
|
||||
function importSpan(fn: number): protocol.TextSpanWithContext {
|
||||
return {
|
||||
start: { line: fn + 1, offset: 5 },
|
||||
end: { line: fn + 1, offset: 8 },
|
||||
contextStart: { line: 1, offset: 1 },
|
||||
contextEnd: { line: 7, offset: 27 }
|
||||
};
|
||||
}
|
||||
function usageSpan(fn: number): protocol.TextSpan {
|
||||
return { start: { line: fn + 8, offset: 1 }, end: { line: fn + 8, offset: 4 } };
|
||||
}
|
||||
|
||||
function renameFromDependencyTs(fn: number): SessionAction<protocol.RenameRequest, protocol.RenameResponseBody> {
|
||||
const triggerSpan = definitionSpan(fn);
|
||||
const defSpan = declarationSpan(fn);
|
||||
const { contextStart: _, contextEnd: _1, ...triggerSpan } = defSpan;
|
||||
return {
|
||||
reqName: "rename",
|
||||
request: {
|
||||
@@ -224,7 +244,7 @@ fn5();
|
||||
triggerSpan
|
||||
},
|
||||
locs: [
|
||||
{ file: dependencyTs.path, locs: [triggerSpan] }
|
||||
{ file: dependencyTs.path, locs: [defSpan] }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,7 +14,16 @@ namespace ts.projectSystem {
|
||||
canRename: false,
|
||||
localizedErrorMessage: "You cannot rename this element."
|
||||
},
|
||||
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
|
||||
locs: [{
|
||||
file: bTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: bTs.content,
|
||||
text: "./a",
|
||||
contextText: bTs.content
|
||||
})
|
||||
]
|
||||
}],
|
||||
});
|
||||
|
||||
// rename succeeds with allowRenameOfImportPath enabled in host
|
||||
@@ -30,7 +39,16 @@ namespace ts.projectSystem {
|
||||
kindModifiers: "",
|
||||
triggerSpan: protocolTextSpanFromSubstring(bTs.content, "a", { index: 1 }),
|
||||
},
|
||||
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
|
||||
locs: [{
|
||||
file: bTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: bTs.content,
|
||||
text: "./a",
|
||||
contextText: bTs.content
|
||||
})
|
||||
]
|
||||
}],
|
||||
});
|
||||
|
||||
// rename succeeds with allowRenameOfImportPath enabled in file
|
||||
@@ -47,7 +65,16 @@ namespace ts.projectSystem {
|
||||
kindModifiers: "",
|
||||
triggerSpan: protocolTextSpanFromSubstring(bTs.content, "a", { index: 1 }),
|
||||
},
|
||||
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
|
||||
locs: [{
|
||||
file: bTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: bTs.content,
|
||||
text: "./a",
|
||||
contextText: bTs.content
|
||||
})
|
||||
]
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,8 +100,16 @@ namespace ts.projectSystem {
|
||||
{
|
||||
file: aTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x"),
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 1 }),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
contextText: "const x = 0;"
|
||||
}),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
options: { index: 1 }
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -97,8 +132,17 @@ namespace ts.projectSystem {
|
||||
{
|
||||
file: aTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x"),
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 1 }, { prefixText: "x: " }),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
contextText: "const x = 0;"
|
||||
}),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
options: { index: 1 },
|
||||
prefixSuffixText: { prefixText: "x: " }
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -122,8 +166,17 @@ namespace ts.projectSystem {
|
||||
{
|
||||
file: aTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x"),
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 1 }, { prefixText: "x: " }),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
contextText: "const x = 0;"
|
||||
}),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
options: { index: 1 },
|
||||
prefixSuffixText: { prefixText: "x: " }
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -154,8 +207,18 @@ namespace ts.projectSystem {
|
||||
{
|
||||
file: aTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x"),
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 2 }, { suffixText: " as x" }),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
contextText: "const x = 1;"
|
||||
}),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
options: { index: 2 },
|
||||
contextText: "export { x };",
|
||||
prefixSuffixText: { suffixText: " as x" }
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -177,15 +240,32 @@ namespace ts.projectSystem {
|
||||
{
|
||||
file: bTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring(bTs.content, "x"),
|
||||
protocolRenameSpanFromSubstring(bTs.content, "x", { index: 1 })
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: bTs.content,
|
||||
text: "x",
|
||||
contextText: `import { x } from "./a";`
|
||||
}),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: bTs.content,
|
||||
text: "x",
|
||||
options: { index: 1 },
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
file: aTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x"),
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 2 }),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
contextText: "const x = 1;"
|
||||
}),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aTs.content,
|
||||
text: "x",
|
||||
options: { index: 2 },
|
||||
contextText: "export { x };",
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -58,10 +58,22 @@ namespace ts.projectSystem {
|
||||
|
||||
assert.equal(aFile.content, bFile.content);
|
||||
const abLocs: protocol.RenameTextSpan[] = [
|
||||
protocolRenameSpanFromSubstring(aFile.content, "C"),
|
||||
protocolRenameSpanFromSubstring(aFile.content, "C", { index: 1 }),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aFile.content,
|
||||
text: "C",
|
||||
contextText: `import {C} from "./c/fc";`
|
||||
}),
|
||||
protocolRenameSpanFromSubstring({
|
||||
fileText: aFile.content,
|
||||
text: "C",
|
||||
options: { index: 1 }
|
||||
}),
|
||||
];
|
||||
const span = protocolRenameSpanFromSubstring(cFile.content, "C");
|
||||
const span = protocolRenameSpanFromSubstring({
|
||||
fileText: cFile.content,
|
||||
text: "C",
|
||||
contextText: "export const C = 8"
|
||||
});
|
||||
const cLocs: protocol.RenameTextSpan[] = [span];
|
||||
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
|
||||
info: {
|
||||
|
||||
+22
-9
@@ -5168,6 +5168,12 @@ declare namespace ts {
|
||||
*/
|
||||
originalTextSpan?: TextSpan;
|
||||
originalFileName?: string;
|
||||
/**
|
||||
* If DocumentSpan.textSpan is the span for name of the declaration,
|
||||
* then this is the span for relevant declaration
|
||||
*/
|
||||
contextSpan?: TextSpan;
|
||||
originalContextSpan?: TextSpan;
|
||||
}
|
||||
interface RenameLocation extends DocumentSpan {
|
||||
readonly prefixText?: string;
|
||||
@@ -5196,6 +5202,7 @@ declare namespace ts {
|
||||
fileName?: string;
|
||||
isInString?: true;
|
||||
textSpan: TextSpan;
|
||||
contextSpan?: TextSpan;
|
||||
kind: HighlightSpanKind;
|
||||
}
|
||||
interface NavigateToItem {
|
||||
@@ -6489,15 +6496,21 @@ declare namespace ts.server.protocol {
|
||||
*/
|
||||
file: string;
|
||||
}
|
||||
interface TextSpanWithContext extends TextSpan {
|
||||
contextStart?: Location;
|
||||
contextEnd?: Location;
|
||||
}
|
||||
interface FileSpanWithContext extends FileSpan, TextSpanWithContext {
|
||||
}
|
||||
interface DefinitionInfoAndBoundSpan {
|
||||
definitions: ReadonlyArray<FileSpan>;
|
||||
definitions: ReadonlyArray<FileSpanWithContext>;
|
||||
textSpan: TextSpan;
|
||||
}
|
||||
/**
|
||||
* Definition response message. Gives text range for definition.
|
||||
*/
|
||||
interface DefinitionResponse extends Response {
|
||||
body?: FileSpan[];
|
||||
body?: FileSpanWithContext[];
|
||||
}
|
||||
interface DefinitionInfoAndBoundSpanReponse extends Response {
|
||||
body?: DefinitionInfoAndBoundSpan;
|
||||
@@ -6506,13 +6519,13 @@ declare namespace ts.server.protocol {
|
||||
* Definition response message. Gives text range for definition.
|
||||
*/
|
||||
interface TypeDefinitionResponse extends Response {
|
||||
body?: FileSpan[];
|
||||
body?: FileSpanWithContext[];
|
||||
}
|
||||
/**
|
||||
* Implementation response message. Gives text range for implementations.
|
||||
*/
|
||||
interface ImplementationResponse extends Response {
|
||||
body?: FileSpan[];
|
||||
body?: FileSpanWithContext[];
|
||||
}
|
||||
/**
|
||||
* Request to get brace completion for a location in the file.
|
||||
@@ -6549,7 +6562,7 @@ declare namespace ts.server.protocol {
|
||||
command: CommandTypes.Occurrences;
|
||||
}
|
||||
/** @deprecated */
|
||||
interface OccurrencesResponseItem extends FileSpan {
|
||||
interface OccurrencesResponseItem extends FileSpanWithContext {
|
||||
/**
|
||||
* True if the occurrence is a write location, false otherwise.
|
||||
*/
|
||||
@@ -6575,7 +6588,7 @@ declare namespace ts.server.protocol {
|
||||
/**
|
||||
* Span augmented with extra information that denotes the kind of the highlighting to be used for span.
|
||||
*/
|
||||
interface HighlightSpan extends TextSpan {
|
||||
interface HighlightSpan extends TextSpanWithContext {
|
||||
kind: HighlightSpanKind;
|
||||
}
|
||||
/**
|
||||
@@ -6605,7 +6618,7 @@ declare namespace ts.server.protocol {
|
||||
interface ReferencesRequest extends FileLocationRequest {
|
||||
command: CommandTypes.References;
|
||||
}
|
||||
interface ReferencesResponseItem extends FileSpan {
|
||||
interface ReferencesResponseItem extends FileSpanWithContext {
|
||||
/** Text of line containing the reference. Including this
|
||||
* with the response avoids latency of editor loading files
|
||||
* to show text of reference line (the server already has
|
||||
@@ -6720,7 +6733,7 @@ declare namespace ts.server.protocol {
|
||||
/** The text spans in this group */
|
||||
locs: RenameTextSpan[];
|
||||
}
|
||||
interface RenameTextSpan extends TextSpan {
|
||||
interface RenameTextSpan extends TextSpanWithContext {
|
||||
readonly prefixText?: string;
|
||||
readonly suffixText?: string;
|
||||
}
|
||||
@@ -9077,6 +9090,7 @@ declare namespace ts.server {
|
||||
private mapDefinitionInfo;
|
||||
private static mapToOriginalLocation;
|
||||
private toFileSpan;
|
||||
private toFileSpanWithContext;
|
||||
private getTypeDefinition;
|
||||
private mapImplementationLocations;
|
||||
private getImplementation;
|
||||
@@ -9134,7 +9148,6 @@ declare namespace ts.server {
|
||||
private mapLocationNavigationBarItems;
|
||||
private getNavigationBarItems;
|
||||
private toLocationNavigationTree;
|
||||
private toLocationTextSpan;
|
||||
private getNavigationTree;
|
||||
private getNavigateToItems;
|
||||
private getFullNavigateToItems;
|
||||
|
||||
@@ -5168,6 +5168,12 @@ declare namespace ts {
|
||||
*/
|
||||
originalTextSpan?: TextSpan;
|
||||
originalFileName?: string;
|
||||
/**
|
||||
* If DocumentSpan.textSpan is the span for name of the declaration,
|
||||
* then this is the span for relevant declaration
|
||||
*/
|
||||
contextSpan?: TextSpan;
|
||||
originalContextSpan?: TextSpan;
|
||||
}
|
||||
interface RenameLocation extends DocumentSpan {
|
||||
readonly prefixText?: string;
|
||||
@@ -5196,6 +5202,7 @@ declare namespace ts {
|
||||
fileName?: string;
|
||||
isInString?: true;
|
||||
textSpan: TextSpan;
|
||||
contextSpan?: TextSpan;
|
||||
kind: HighlightSpanKind;
|
||||
}
|
||||
interface NavigateToItem {
|
||||
|
||||
@@ -128,10 +128,10 @@ function foo3() {
|
||||
}
|
||||
function foo4() {
|
||||
var y = /** @class */ (function () {
|
||||
function class_1() {
|
||||
function y() {
|
||||
}
|
||||
class_1.prototype.m = function () { return x; };
|
||||
return class_1;
|
||||
y.prototype.m = function () { return x; };
|
||||
return y;
|
||||
}());
|
||||
var x;
|
||||
}
|
||||
@@ -156,19 +156,19 @@ function foo7() {
|
||||
}
|
||||
function foo8() {
|
||||
var y = /** @class */ (function () {
|
||||
function class_2() {
|
||||
function class_1() {
|
||||
this.a = x;
|
||||
}
|
||||
return class_2;
|
||||
return class_1;
|
||||
}());
|
||||
var x;
|
||||
}
|
||||
function foo9() {
|
||||
var _a;
|
||||
var y = (_a = /** @class */ (function () {
|
||||
function class_3() {
|
||||
function class_2() {
|
||||
}
|
||||
return class_3;
|
||||
return class_2;
|
||||
}()),
|
||||
_a.a = x,
|
||||
_a);
|
||||
@@ -187,9 +187,9 @@ function foo11() {
|
||||
function f() {
|
||||
var _a;
|
||||
var y = (_a = /** @class */ (function () {
|
||||
function class_4() {
|
||||
function class_3() {
|
||||
}
|
||||
return class_4;
|
||||
return class_3;
|
||||
}()),
|
||||
_a.a = x,
|
||||
_a);
|
||||
@@ -199,10 +199,10 @@ function foo11() {
|
||||
function foo12() {
|
||||
function f() {
|
||||
var y = /** @class */ (function () {
|
||||
function class_5() {
|
||||
function class_4() {
|
||||
this.a = x;
|
||||
}
|
||||
return class_5;
|
||||
return class_4;
|
||||
}());
|
||||
}
|
||||
var x;
|
||||
|
||||
@@ -9,11 +9,11 @@ let x = (new C).foo();
|
||||
|
||||
//// [classExpression4.js]
|
||||
var C = /** @class */ (function () {
|
||||
function class_1() {
|
||||
function C() {
|
||||
}
|
||||
class_1.prototype.foo = function () {
|
||||
C.prototype.foo = function () {
|
||||
return new C();
|
||||
};
|
||||
return class_1;
|
||||
return C;
|
||||
}());
|
||||
var x = (new C).foo();
|
||||
|
||||
@@ -28,9 +28,9 @@ var A = /** @class */ (function () {
|
||||
return A;
|
||||
}());
|
||||
var C = /** @class */ (function (_super) {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
__extends(C, _super);
|
||||
function C() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return class_1;
|
||||
return C;
|
||||
}(A));
|
||||
|
||||
@@ -34,8 +34,8 @@ var C = /** @class */ (function () {
|
||||
}
|
||||
return C;
|
||||
}());
|
||||
_a = a_1.x;
|
||||
exports.C = C;
|
||||
_a = a_1.x;
|
||||
//// [c.js]
|
||||
"use strict";
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
@@ -64,8 +64,8 @@ var D = /** @class */ (function (_super) {
|
||||
}
|
||||
return D;
|
||||
}(b_1.C));
|
||||
_a = a_1.x;
|
||||
exports.D = D;
|
||||
_a = a_1.x;
|
||||
|
||||
|
||||
//// [a.d.ts]
|
||||
|
||||
@@ -196,7 +196,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21;
|
||||
var _a, _b, _c, _d;
|
||||
var _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21;
|
||||
function x(o, k) { }
|
||||
let i = 0;
|
||||
function foo() { return ++i + ""; }
|
||||
@@ -209,11 +210,11 @@ class A {
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_b] = null;
|
||||
this[_d] = null;
|
||||
this[_f] = null;
|
||||
this[_h] = null;
|
||||
}
|
||||
}
|
||||
foo(), _a = foo(), _b = foo(), _c = fieldNameB, _d = fieldNameC;
|
||||
foo(), _e = foo(), _f = foo(), _g = fieldNameB, _h = fieldNameC;
|
||||
__decorate([
|
||||
x
|
||||
], A.prototype, "property", void 0);
|
||||
@@ -228,42 +229,42 @@ __decorate([
|
||||
], A.prototype, Symbol.iterator, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], A.prototype, _a, void 0);
|
||||
], A.prototype, _e, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], A.prototype, _b, void 0);
|
||||
], A.prototype, _f, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], A.prototype, _c, void 0);
|
||||
], A.prototype, _g, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], A.prototype, _d, void 0);
|
||||
void (_j = class B {
|
||||
], A.prototype, _h, void 0);
|
||||
void (_a = class B {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_f] = null;
|
||||
this[_h] = null;
|
||||
this[_k] = null;
|
||||
this[_m] = null;
|
||||
}
|
||||
},
|
||||
foo(),
|
||||
_e = foo(),
|
||||
_f = foo(),
|
||||
_g = fieldNameB,
|
||||
_h = fieldNameC,
|
||||
_j);
|
||||
_j = foo(),
|
||||
_k = foo(),
|
||||
_l = fieldNameB,
|
||||
_m = fieldNameC,
|
||||
_a);
|
||||
class C {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_l] = null;
|
||||
this[_o] = null;
|
||||
this[_p] = null;
|
||||
this[_r] = null;
|
||||
}
|
||||
[(foo(), _k = foo(), _l = foo(), _m = fieldNameB, _o = fieldNameC, "some" + "method")]() { }
|
||||
[(foo(), _o = foo(), _p = foo(), _q = fieldNameB, _r = fieldNameC, "some" + "method")]() { }
|
||||
}
|
||||
__decorate([
|
||||
x
|
||||
@@ -277,28 +278,28 @@ __decorate([
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, Symbol.iterator, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, _k, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, _l, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, _m, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, _o, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, _p, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, _q, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], C.prototype, _r, void 0);
|
||||
void class D {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_q] = null;
|
||||
this[_s] = null;
|
||||
this[_t] = null;
|
||||
this[_v] = null;
|
||||
}
|
||||
[(foo(), _p = foo(), _q = foo(), _r = fieldNameB, _s = fieldNameC, "some" + "method")]() { }
|
||||
[(foo(), _s = foo(), _t = foo(), _u = fieldNameB, _v = fieldNameC, "some" + "method")]() { }
|
||||
};
|
||||
class E {
|
||||
constructor() {
|
||||
@@ -306,12 +307,12 @@ class E {
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_u] = null;
|
||||
this[_w] = null;
|
||||
this[_x] = null;
|
||||
this[_z] = null;
|
||||
}
|
||||
[(foo(), _t = foo(), _u = foo(), "some" + "method")]() { }
|
||||
[(foo(), _w = foo(), _x = foo(), "some" + "method")]() { }
|
||||
}
|
||||
_v = fieldNameB, _w = fieldNameC;
|
||||
_y = fieldNameB, _z = fieldNameC;
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, "property", void 0);
|
||||
@@ -324,45 +325,45 @@ __decorate([
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, Symbol.iterator, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, _t, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, _u, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, _v, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, _w, void 0);
|
||||
void (_1 = class F {
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, _x, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, _y, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], E.prototype, _z, void 0);
|
||||
void (_b = class F {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_y] = null;
|
||||
this[_0] = null;
|
||||
this[_1] = null;
|
||||
this[_3] = null;
|
||||
}
|
||||
[(foo(), _x = foo(), _y = foo(), "some" + "method")]() { }
|
||||
[(foo(), _0 = foo(), _1 = foo(), "some" + "method")]() { }
|
||||
},
|
||||
_z = fieldNameB,
|
||||
_0 = fieldNameC,
|
||||
_1);
|
||||
_2 = fieldNameB,
|
||||
_3 = fieldNameC,
|
||||
_b);
|
||||
class G {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_3] = null;
|
||||
this[_5] = null;
|
||||
this[_7] = null;
|
||||
}
|
||||
[(foo(), _2 = foo(), _3 = foo(), "some" + "method")]() { }
|
||||
[(_4 = fieldNameB, "some" + "method2")]() { }
|
||||
[(foo(), _4 = foo(), _5 = foo(), "some" + "method")]() { }
|
||||
[(_6 = fieldNameB, "some" + "method2")]() { }
|
||||
}
|
||||
_5 = fieldNameC;
|
||||
_7 = fieldNameC;
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, "property", void 0);
|
||||
@@ -375,45 +376,45 @@ __decorate([
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, Symbol.iterator, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, _2, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, _3, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, _4, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, _5, void 0);
|
||||
void (_10 = class H {
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, _6, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], G.prototype, _7, void 0);
|
||||
void (_c = class H {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_7] = null;
|
||||
this[_9] = null;
|
||||
this[_11] = null;
|
||||
}
|
||||
[(foo(), _6 = foo(), _7 = foo(), "some" + "method")]() { }
|
||||
[(_8 = fieldNameB, "some" + "method2")]() { }
|
||||
[(foo(), _8 = foo(), _9 = foo(), "some" + "method")]() { }
|
||||
[(_10 = fieldNameB, "some" + "method2")]() { }
|
||||
},
|
||||
_9 = fieldNameC,
|
||||
_10);
|
||||
_11 = fieldNameC,
|
||||
_c);
|
||||
class I {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_12] = null;
|
||||
this[_15] = null;
|
||||
this[_13] = null;
|
||||
this[_16] = null;
|
||||
}
|
||||
[(foo(), _11 = foo(), _12 = foo(), _13 = "some" + "method")]() { }
|
||||
[(_14 = fieldNameB, "some" + "method2")]() { }
|
||||
[(foo(), _12 = foo(), _13 = foo(), _14 = "some" + "method")]() { }
|
||||
[(_15 = fieldNameB, "some" + "method2")]() { }
|
||||
}
|
||||
_15 = fieldNameC;
|
||||
_16 = fieldNameC;
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, "property", void 0);
|
||||
@@ -426,32 +427,32 @@ __decorate([
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, Symbol.iterator, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, _11, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, _12, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, _13, null);
|
||||
], I.prototype, _13, void 0);
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, _14, void 0);
|
||||
], I.prototype, _14, null);
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, _15, void 0);
|
||||
void (_21 = class J {
|
||||
__decorate([
|
||||
x
|
||||
], I.prototype, _16, void 0);
|
||||
void (_d = class J {
|
||||
constructor() {
|
||||
this["property2"] = 2;
|
||||
this[Symbol.iterator] = null;
|
||||
this["property4"] = 2;
|
||||
this[Symbol.match] = null;
|
||||
this[_17] = null;
|
||||
this[_20] = null;
|
||||
this[_18] = null;
|
||||
this[_21] = null;
|
||||
}
|
||||
[(foo(), _16 = foo(), _17 = foo(), _18 = "some" + "method")]() { }
|
||||
[(_19 = fieldNameB, "some" + "method2")]() { }
|
||||
[(foo(), _17 = foo(), _18 = foo(), _19 = "some" + "method")]() { }
|
||||
[(_20 = fieldNameB, "some" + "method2")]() { }
|
||||
},
|
||||
_20 = fieldNameC,
|
||||
_21);
|
||||
_21 = fieldNameC,
|
||||
_d);
|
||||
|
||||
@@ -47,11 +47,11 @@ var __extends = (this && this.__extends) || (function () {
|
||||
})();
|
||||
exports.__esModule = true;
|
||||
exports.simpleExample = /** @class */ (function () {
|
||||
function class_1() {
|
||||
function simpleExample() {
|
||||
}
|
||||
class_1.getTags = function () { };
|
||||
class_1.prototype.tags = function () { };
|
||||
return class_1;
|
||||
simpleExample.getTags = function () { };
|
||||
simpleExample.prototype.tags = function () { };
|
||||
return simpleExample;
|
||||
}());
|
||||
exports.circularReference = /** @class */ (function () {
|
||||
function C() {
|
||||
@@ -70,13 +70,13 @@ var FooItem = /** @class */ (function () {
|
||||
exports.FooItem = FooItem;
|
||||
function WithTags(Base) {
|
||||
return /** @class */ (function (_super) {
|
||||
__extends(class_2, _super);
|
||||
function class_2() {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
class_2.getTags = function () { };
|
||||
class_2.prototype.tags = function () { };
|
||||
return class_2;
|
||||
class_1.getTags = function () { };
|
||||
class_1.prototype.tags = function () { };
|
||||
return class_1;
|
||||
}(Base));
|
||||
}
|
||||
exports.WithTags = WithTags;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@ tests/cases/compiler/implicitAnyFromCircularInference.ts(5,5): error TS2502: 'b'
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(6,5): error TS2502: 'c' is referenced directly or indirectly in its own type annotation.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(9,5): error TS2502: 'd' is referenced directly or indirectly in its own type annotation.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(14,10): error TS7023: 'g' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(17,10): error TS7024: Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(17,5): error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(22,10): error TS7024: Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(25,10): error TS7023: 'h' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
tests/cases/compiler/implicitAnyFromCircularInference.ts(27,14): error TS7023: 'foo' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
@@ -38,8 +38,8 @@ tests/cases/compiler/implicitAnyFromCircularInference.ts(45,9): error TS7023: 'x
|
||||
|
||||
// Error expected
|
||||
var f1 = function () {
|
||||
~~~~~~~~
|
||||
!!! error TS7024: Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
~~
|
||||
!!! error TS7023: 'f1' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
|
||||
return f1();
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
(async () => {
|
||||
const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString());
|
||||
>response : Symbol(response, Decl(example.ts, 2, 7))
|
||||
>fetch : Symbol(fetch, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>fetch : Symbol(fetch, Decl(lib.dom.d.ts, --, --))
|
||||
>new URL("../hamsters.jpg", import.meta.url).toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
|
||||
>URL : Symbol(URL, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
>response : Response
|
||||
>await fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Response
|
||||
>fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Promise<Response>
|
||||
>fetch : { (input: RequestInfo, init?: RequestInit): Promise<Response>; (input: RequestInfo, init?: RequestInit): Promise<Response>; }
|
||||
>fetch : (input: RequestInfo, init?: RequestInit) => Promise<Response>
|
||||
>new URL("../hamsters.jpg", import.meta.url).toString() : string
|
||||
>new URL("../hamsters.jpg", import.meta.url).toString : () => string
|
||||
>new URL("../hamsters.jpg", import.meta.url) : URL
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
(async () => {
|
||||
const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString());
|
||||
>response : Symbol(response, Decl(example.ts, 2, 7))
|
||||
>fetch : Symbol(fetch, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>fetch : Symbol(fetch, Decl(lib.dom.d.ts, --, --))
|
||||
>new URL("../hamsters.jpg", import.meta.url).toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
|
||||
>URL : Symbol(URL, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>toString : Symbol(Object.toString, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
>response : Response
|
||||
>await fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Response
|
||||
>fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Promise<Response>
|
||||
>fetch : { (input: RequestInfo, init?: RequestInit): Promise<Response>; (input: RequestInfo, init?: RequestInit): Promise<Response>; }
|
||||
>fetch : (input: RequestInfo, init?: RequestInit) => Promise<Response>
|
||||
>new URL("../hamsters.jpg", import.meta.url).toString() : string
|
||||
>new URL("../hamsters.jpg", import.meta.url).toString : () => string
|
||||
>new URL("../hamsters.jpg", import.meta.url) : URL
|
||||
|
||||
@@ -6,7 +6,16 @@ class C {
|
||||
var c = new C();
|
||||
c.x = 3;
|
||||
var c2 = new C();
|
||||
var r = c.x === c2.x;
|
||||
var r = c.x === c2.x;
|
||||
|
||||
// #31792
|
||||
|
||||
|
||||
|
||||
class MyMap<K, V> {
|
||||
constructor(private readonly Map_: { new<K, V>(): any }) {}
|
||||
private readonly store = new this.Map_<K, V>();
|
||||
}
|
||||
|
||||
//// [instanceMemberInitialization.js]
|
||||
var C = /** @class */ (function () {
|
||||
@@ -19,3 +28,11 @@ var c = new C();
|
||||
c.x = 3;
|
||||
var c2 = new C();
|
||||
var r = c.x === c2.x;
|
||||
// #31792
|
||||
var MyMap = /** @class */ (function () {
|
||||
function MyMap(Map_) {
|
||||
this.Map_ = Map_;
|
||||
this.store = new this.Map_();
|
||||
}
|
||||
return MyMap;
|
||||
}());
|
||||
|
||||
@@ -28,3 +28,25 @@ var r = c.x === c2.x;
|
||||
>c2 : Symbol(c2, Decl(instanceMemberInitialization.ts, 6, 3))
|
||||
>x : Symbol(C.x, Decl(instanceMemberInitialization.ts, 0, 9))
|
||||
|
||||
// #31792
|
||||
|
||||
|
||||
|
||||
class MyMap<K, V> {
|
||||
>MyMap : Symbol(MyMap, Decl(instanceMemberInitialization.ts, 7, 21))
|
||||
>K : Symbol(K, Decl(instanceMemberInitialization.ts, 13, 12))
|
||||
>V : Symbol(V, Decl(instanceMemberInitialization.ts, 13, 14))
|
||||
|
||||
constructor(private readonly Map_: { new<K, V>(): any }) {}
|
||||
>Map_ : Symbol(MyMap.Map_, Decl(instanceMemberInitialization.ts, 14, 16))
|
||||
>K : Symbol(K, Decl(instanceMemberInitialization.ts, 14, 45))
|
||||
>V : Symbol(V, Decl(instanceMemberInitialization.ts, 14, 47))
|
||||
|
||||
private readonly store = new this.Map_<K, V>();
|
||||
>store : Symbol(MyMap.store, Decl(instanceMemberInitialization.ts, 14, 63))
|
||||
>this.Map_ : Symbol(MyMap.Map_, Decl(instanceMemberInitialization.ts, 14, 16))
|
||||
>this : Symbol(MyMap, Decl(instanceMemberInitialization.ts, 7, 21))
|
||||
>Map_ : Symbol(MyMap.Map_, Decl(instanceMemberInitialization.ts, 14, 16))
|
||||
>K : Symbol(K, Decl(instanceMemberInitialization.ts, 13, 12))
|
||||
>V : Symbol(V, Decl(instanceMemberInitialization.ts, 13, 14))
|
||||
}
|
||||
|
||||
@@ -34,3 +34,20 @@ var r = c.x === c2.x;
|
||||
>c2 : C
|
||||
>x : number
|
||||
|
||||
// #31792
|
||||
|
||||
|
||||
|
||||
class MyMap<K, V> {
|
||||
>MyMap : MyMap<K, V>
|
||||
|
||||
constructor(private readonly Map_: { new<K, V>(): any }) {}
|
||||
>Map_ : new <K, V>() => any
|
||||
|
||||
private readonly store = new this.Map_<K, V>();
|
||||
>store : any
|
||||
>new this.Map_<K, V>() : any
|
||||
>this.Map_ : new <K, V>() => any
|
||||
>this : this
|
||||
>Map_ : new <K, V>() => any
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ tests/cases/compiler/intersectionsOfLargeUnions2.ts(31,15): error TS2536: Type '
|
||||
interface ElementTagNameMap {
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2300: Duplicate identifier 'ElementTagNameMap'.
|
||||
!!! related TS6203 /.ts/lib.dom.d.ts:18110:6: 'ElementTagNameMap' was also declared here.
|
||||
!!! related TS6203 /.ts/lib.dom.d.ts:18325:6: 'ElementTagNameMap' was also declared here.
|
||||
[index: number]: HTMLElement
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
=== tests/cases/compiler/multiExtendsSplitInterfaces1.ts ===
|
||||
self.cancelAnimationFrame(0);
|
||||
>self.cancelAnimationFrame : Symbol(Window.cancelAnimationFrame, Decl(lib.dom.d.ts, --, --))
|
||||
>self.cancelAnimationFrame : Symbol(AnimationFrameProvider.cancelAnimationFrame, Decl(lib.dom.d.ts, --, --))
|
||||
>self : Symbol(self, Decl(lib.dom.d.ts, --, --))
|
||||
>cancelAnimationFrame : Symbol(Window.cancelAnimationFrame, Decl(lib.dom.d.ts, --, --))
|
||||
>cancelAnimationFrame : Symbol(AnimationFrameProvider.cancelAnimationFrame, Decl(lib.dom.d.ts, --, --))
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ function f1() {
|
||||
var g = _newTarget;
|
||||
var h = function () { return _newTarget; };
|
||||
}
|
||||
var f2 = function _b() {
|
||||
var _newTarget = this && this instanceof _b ? this.constructor : void 0;
|
||||
var f2 = function f2() {
|
||||
var _newTarget = this && this instanceof f2 ? this.constructor : void 0;
|
||||
var i = _newTarget;
|
||||
var j = function () { return _newTarget; };
|
||||
};
|
||||
|
||||
@@ -265,63 +265,63 @@ var StaticName_Anonymous = /** @class */ (function () {
|
||||
return class_1;
|
||||
}());
|
||||
var StaticNameFn_Anonymous = /** @class */ (function () {
|
||||
function class_2() {
|
||||
function StaticNameFn_Anonymous() {
|
||||
}
|
||||
class_2.name = function () { }; // error
|
||||
class_2.prototype.name = function () { }; // ok
|
||||
return class_2;
|
||||
StaticNameFn_Anonymous.name = function () { }; // error
|
||||
StaticNameFn_Anonymous.prototype.name = function () { }; // ok
|
||||
return StaticNameFn_Anonymous;
|
||||
}());
|
||||
// length
|
||||
var StaticLength_Anonymous = /** @class */ (function () {
|
||||
function class_2() {
|
||||
}
|
||||
return class_2;
|
||||
}());
|
||||
var StaticLengthFn_Anonymous = /** @class */ (function () {
|
||||
function StaticLengthFn_Anonymous() {
|
||||
}
|
||||
StaticLengthFn_Anonymous.length = function () { }; // error
|
||||
StaticLengthFn_Anonymous.prototype.length = function () { }; // ok
|
||||
return StaticLengthFn_Anonymous;
|
||||
}());
|
||||
// prototype
|
||||
var StaticPrototype_Anonymous = /** @class */ (function () {
|
||||
function class_3() {
|
||||
}
|
||||
return class_3;
|
||||
}());
|
||||
var StaticLengthFn_Anonymous = /** @class */ (function () {
|
||||
var StaticPrototypeFn_Anonymous = /** @class */ (function () {
|
||||
function StaticPrototypeFn_Anonymous() {
|
||||
}
|
||||
StaticPrototypeFn_Anonymous.prototype = function () { }; // error
|
||||
StaticPrototypeFn_Anonymous.prototype.prototype = function () { }; // ok
|
||||
return StaticPrototypeFn_Anonymous;
|
||||
}());
|
||||
// caller
|
||||
var StaticCaller_Anonymous = /** @class */ (function () {
|
||||
function class_4() {
|
||||
}
|
||||
class_4.length = function () { }; // error
|
||||
class_4.prototype.length = function () { }; // ok
|
||||
return class_4;
|
||||
}());
|
||||
// prototype
|
||||
var StaticPrototype_Anonymous = /** @class */ (function () {
|
||||
var StaticCallerFn_Anonymous = /** @class */ (function () {
|
||||
function StaticCallerFn_Anonymous() {
|
||||
}
|
||||
StaticCallerFn_Anonymous.caller = function () { }; // error
|
||||
StaticCallerFn_Anonymous.prototype.caller = function () { }; // ok
|
||||
return StaticCallerFn_Anonymous;
|
||||
}());
|
||||
// arguments
|
||||
var StaticArguments_Anonymous = /** @class */ (function () {
|
||||
function class_5() {
|
||||
}
|
||||
return class_5;
|
||||
}());
|
||||
var StaticPrototypeFn_Anonymous = /** @class */ (function () {
|
||||
function class_6() {
|
||||
}
|
||||
class_6.prototype = function () { }; // error
|
||||
class_6.prototype.prototype = function () { }; // ok
|
||||
return class_6;
|
||||
}());
|
||||
// caller
|
||||
var StaticCaller_Anonymous = /** @class */ (function () {
|
||||
function class_7() {
|
||||
}
|
||||
return class_7;
|
||||
}());
|
||||
var StaticCallerFn_Anonymous = /** @class */ (function () {
|
||||
function class_8() {
|
||||
}
|
||||
class_8.caller = function () { }; // error
|
||||
class_8.prototype.caller = function () { }; // ok
|
||||
return class_8;
|
||||
}());
|
||||
// arguments
|
||||
var StaticArguments_Anonymous = /** @class */ (function () {
|
||||
function class_9() {
|
||||
}
|
||||
return class_9;
|
||||
}());
|
||||
var StaticArgumentsFn_Anonymous = /** @class */ (function () {
|
||||
function class_10() {
|
||||
function StaticArgumentsFn_Anonymous() {
|
||||
}
|
||||
class_10.arguments = function () { }; // error
|
||||
class_10.prototype.arguments = function () { }; // ok
|
||||
return class_10;
|
||||
StaticArgumentsFn_Anonymous.arguments = function () { }; // error
|
||||
StaticArgumentsFn_Anonymous.prototype.arguments = function () { }; // ok
|
||||
return StaticArgumentsFn_Anonymous;
|
||||
}());
|
||||
// === Static properties on default exported classes ===
|
||||
// name
|
||||
|
||||
@@ -45,11 +45,11 @@ var B = /** @class */ (function (_super) {
|
||||
function B() {
|
||||
var _this = this;
|
||||
var D = /** @class */ (function (_super) {
|
||||
__extends(class_1, _super);
|
||||
function class_1() {
|
||||
__extends(D, _super);
|
||||
function D() {
|
||||
return _super.call(this) || this;
|
||||
}
|
||||
return class_1;
|
||||
return D;
|
||||
}(C));
|
||||
return _this;
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ System.register([], function (exports_1, context_1) {
|
||||
MyClass2 = class MyClass2 {
|
||||
static getInstance() { return MyClass2.value; }
|
||||
};
|
||||
MyClass2.value = 42;
|
||||
exports_1("MyClass2", MyClass2);
|
||||
MyClass2.value = 42;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ Standard output:
|
||||
node_modules/@types/react-native/index.d.ts(3425,42): error TS2583: Cannot find name 'Map'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
node_modules/@types/react-native/index.d.ts(3438,42): error TS2583: Cannot find name 'Map'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
node_modules/@types/react-native/index.d.ts(8745,18): error TS2717: Subsequent property declarations must have the same type. Property 'geolocation' must be of type 'Geolocation', but here has type 'GeolocationStatic'.
|
||||
node_modules/@types/react/index.d.ts(378,23): error TS2583: Cannot find name 'Set'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
node_modules/@types/react/index.d.ts(377,23): error TS2583: Cannot find name 'Set'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@ node_modules/uglify-js/lib/compress.js(4229,45): error TS2554: Expected 0 argume
|
||||
node_modules/uglify-js/lib/compress.js(4340,33): error TS2554: Expected 0 arguments, but got 1.
|
||||
node_modules/uglify-js/lib/compress.js(4638,17): error TS2403: Subsequent variable declarations must have the same type. Variable 'body' must be of type 'any[]', but here has type 'any'.
|
||||
node_modules/uglify-js/lib/compress.js(4722,37): error TS2554: Expected 0 arguments, but got 1.
|
||||
node_modules/uglify-js/lib/compress.js(4930,57): error TS2345: Argument of type 'any[]' is not assignable to parameter of type '[RegExp, (string | undefined)?]'.
|
||||
Property '0' is missing in type 'any[]' but required in type '[RegExp, (string | undefined)?]'.
|
||||
node_modules/uglify-js/lib/compress.js(4930,57): error TS2345: Argument of type 'any[]' is not assignable to parameter of type '[string | RegExp, (string | undefined)?]'.
|
||||
Property '0' is missing in type 'any[]' but required in type '[string | RegExp, (string | undefined)?]'.
|
||||
node_modules/uglify-js/lib/compress.js(5094,45): error TS2554: Expected 0 arguments, but got 1.
|
||||
node_modules/uglify-js/lib/compress.js(5101,25): error TS2403: Subsequent variable declarations must have the same type. Variable 'code' must be of type 'string', but here has type '{ get: () => string; toString: () => string; indent: () => void; indentation: () => number; current_width: () => number; should_break: () => boolean; has_parens: () => boolean; newline: () => void; print: (str: any) => void; ... 24 more ...; parent: (n: any) => any; }'.
|
||||
node_modules/uglify-js/lib/compress.js(5105,36): error TS2532: Object is possibly 'undefined'.
|
||||
|
||||
+1
-1
@@ -16,8 +16,8 @@ var Foo = /** @class */ (function () {
|
||||
}
|
||||
return Foo;
|
||||
}());
|
||||
_a = key;
|
||||
exports.Foo = Foo;
|
||||
_a = key;
|
||||
|
||||
|
||||
//// [variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.d.ts]
|
||||
|
||||
+10
-1
@@ -5,4 +5,13 @@ class C {
|
||||
var c = new C();
|
||||
c.x = 3;
|
||||
var c2 = new C();
|
||||
var r = c.x === c2.x;
|
||||
var r = c.x === c2.x;
|
||||
|
||||
// #31792
|
||||
|
||||
|
||||
|
||||
class MyMap<K, V> {
|
||||
constructor(private readonly Map_: { new<K, V>(): any }) {}
|
||||
private readonly store = new this.Map_<K, V>();
|
||||
}
|
||||
@@ -4,13 +4,12 @@
|
||||
////declare module "jquery";
|
||||
|
||||
// @Filename: user.ts
|
||||
////import {[|{| "isWriteAccess": true, "isDefinition": true |}x|]} from "jquery";
|
||||
////[|import {[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}x|]} from "jquery";|]
|
||||
|
||||
// @Filename: user2.ts
|
||||
////import {[|{| "isWriteAccess": true, "isDefinition": true |}x|]} from "jquery";
|
||||
////[|import {[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}x|]} from "jquery";|]
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
const [r0Def, r0, r1Def, r1] = test.ranges();
|
||||
// TODO: Want these to be in the same group, but that would require creating a symbol for `x`.
|
||||
verify.singleReferenceGroup("(alias) module \"jquery\"\nimport x", [r0]);
|
||||
verify.singleReferenceGroup("(alias) module \"jquery\"\nimport x", [r1]);
|
||||
@@ -7,9 +7,9 @@
|
||||
////
|
||||
//// }
|
||||
////
|
||||
//// public /**/[|{| "isWriteAccess": true, "isDefinition": true |}start|](){
|
||||
//// [|public /**/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}start|](){
|
||||
//// return this;
|
||||
//// }
|
||||
//// }|]
|
||||
////
|
||||
//// public stop(){
|
||||
//// return this;
|
||||
@@ -33,5 +33,5 @@ cancellation.resetCancelled();
|
||||
checkRefs();
|
||||
|
||||
function checkRefs() {
|
||||
verify.singleReferenceGroup("(method) Test.start(): this");
|
||||
verify.singleReferenceGroup("(method) Test.start(): this", "start");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
//// function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// const container: any = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: any ",
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
//// const returnThisMember = function ([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: Container ",
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// let container;
|
||||
//// container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: { member: string; returnThisMember: () => any; } ",
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
/////**
|
||||
//// * @returns {string}
|
||||
//// */
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
////class Container {
|
||||
//// member = "sample";
|
||||
//// returnThisMember = returnThisMember;
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @returns {string}
|
||||
* @this {Container}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
class Container {
|
||||
member = "sample";
|
||||
returnThisMember = returnThisMember;
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
////class Container {
|
||||
//// member = "sample";
|
||||
//// returnThisMember = returnThisMember;
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @this {Container}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
class Container {
|
||||
member = "sample";
|
||||
returnThisMember = returnThisMember;
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
/////**
|
||||
//// * @type {import("/providesType").Container}
|
||||
//// */
|
||||
////const container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
// @Filename: /providesType.ts
|
||||
////interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @this {any}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {import("/providesType").Container}
|
||||
*/
|
||||
const container = {
|
||||
member: "sample",
|
||||
returnThisMember: returnThisMember,
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noImplicitThis: true
|
||||
|
||||
// @Filename: /consumesType.js
|
||||
////function [|returnThisMember|]() {
|
||||
//// return this.member;
|
||||
////}
|
||||
////
|
||||
////const container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
////};
|
||||
////
|
||||
////container.returnThisMember();
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newFileContent: `/**
|
||||
* @this {{ member: string; returnThisMember: () => any; }}
|
||||
*/
|
||||
function returnThisMember() {
|
||||
return this.member;
|
||||
}
|
||||
|
||||
const container = {
|
||||
member: "sample",
|
||||
returnThisMember: returnThisMember,
|
||||
};
|
||||
|
||||
container.returnThisMember();`
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// const container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: { member: string; returnThisMember: () => any; } ",
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
|
||||
verify.codeFix({
|
||||
description: "Infer 'this' type of 'returnThisMember' from usage",
|
||||
index: 0,
|
||||
newRangeContent: "this: any ",
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container");
|
||||
@@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]suffix: string) {
|
||||
//// return this.member + suffix;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(suffix: string): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember: returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember("");
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container, ");
|
||||
@@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]) {
|
||||
//// return this.member;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember();
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container");
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitThis: true
|
||||
////function returnThisMember([| |]suffix: string) {
|
||||
//// return this.member + suffix;
|
||||
//// }
|
||||
////
|
||||
//// interface Container {
|
||||
//// member: string;
|
||||
//// returnThisMember(suffix: string): string;
|
||||
//// }
|
||||
////
|
||||
//// const container: Container = {
|
||||
//// member: "sample",
|
||||
//// returnThisMember,
|
||||
//// };
|
||||
////
|
||||
//// container.returnThisMember("");
|
||||
|
||||
verify.rangeAfterCodeFix("this: Container, ");
|
||||
@@ -1,12 +1,12 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: fileA.ts
|
||||
//// export function [|__foo|]() {
|
||||
//// }
|
||||
//// [|export function [|{| "contextRangeIndex": 0 |}__foo|]() {
|
||||
//// }|]
|
||||
////
|
||||
// @Filename: fileB.ts
|
||||
//// import { [|__foo|] as bar } from "./fileA";
|
||||
//// [|import { [|{| "contextRangeIndex": 2 |}__foo|] as bar } from "./fileA";|]
|
||||
////
|
||||
//// bar();
|
||||
|
||||
verify.rangesAreRenameLocations();
|
||||
verify.rangesWithSameTextAreRenameLocations("__foo");
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
// @noImplicitReferences: true
|
||||
|
||||
// @Filename: /node_modules/a/index.d.ts
|
||||
////import [|{| "name": "useAX", "isWriteAccess": true, "isDefinition": true |}X|] from "x";
|
||||
////[|import [|{| "name": "useAX", "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}X|] from "x";|]
|
||||
////export function a(x: [|X|]): void;
|
||||
|
||||
// @Filename: /node_modules/a/node_modules/x/index.d.ts
|
||||
////export default class /*defAX*/[|{| "isWriteAccess": true, "isDefinition": true |}X|] {
|
||||
////[|export default class /*defAX*/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 3 |}X|] {
|
||||
//// private x: number;
|
||||
////}
|
||||
////}|]
|
||||
|
||||
// @Filename: /node_modules/a/node_modules/x/package.json
|
||||
////{ "name": "x", "version": "1.2.3" }
|
||||
|
||||
// @Filename: /node_modules/b/index.d.ts
|
||||
////import [|{| "name": "useBX", "isWriteAccess": true, "isDefinition": true |}X|] from "x";
|
||||
////[|import [|{| "name": "useBX", "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 5 |}X|] from "x";|]
|
||||
////export const b: [|X|];
|
||||
|
||||
// @Filename: /node_modules/b/node_modules/x/index.d.ts
|
||||
////export default class /*defBX*/[|{| "isWriteAccess": true, "isDefinition": true |}X|] {
|
||||
////[|export default class /*defBX*/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 8 |}X|] {
|
||||
//// private x: number;
|
||||
////}
|
||||
////}|]
|
||||
|
||||
// @Filename: /node_modules/b/node_modules/x/package.json
|
||||
////{ "name": "x", "version": "1.2.3" }
|
||||
@@ -35,7 +35,7 @@ verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.goToDefinition("useAX", "defAX");
|
||||
verify.goToDefinition("useBX", "defAX");
|
||||
|
||||
const [r0, r1, r2, r3, r4, r5] = test.ranges();
|
||||
const [r0Def, r0, r1, r2Def, r2, r3Def, r3, r4, r5Def, r5] = test.ranges();
|
||||
const aImport = { definition: "(alias) class X\nimport X", ranges: [r0, r1] };
|
||||
const def = { definition: "class X", ranges: [r2] };
|
||||
const bImport = { definition: "(alias) class X\nimport X", ranges: [r3, r4] };
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
// @Filename: /abc.d.ts
|
||||
////declare module "a" {
|
||||
//// export const [|{| "isWriteAccess": true, "isDefinition": true |}x|]: number;
|
||||
//// [|export const [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}x|]: number;|]
|
||||
////}
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import a from "a";
|
||||
////a.[|x|];
|
||||
|
||||
verify.singleReferenceGroup("const x: number");
|
||||
verify.singleReferenceGroup("const x: number", "x");
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
// @Filename: /a.d.ts
|
||||
////export as namespace abc;
|
||||
////export const [|{| "isWriteAccess": true, "isDefinition": true |}x|]: number;
|
||||
////[|export const [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}x|]: number;|]
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import a from "./a";
|
||||
////a.[|x|];
|
||||
|
||||
verify.singleReferenceGroup('const x: number');
|
||||
verify.singleReferenceGroup('const x: number', "x");
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
//// class B {}
|
||||
//// function foo() {
|
||||
//// return {[|{| "isWriteAccess": true, "isDefinition": true |}B|]: B};
|
||||
//// return {[|[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}B|]: B|]};
|
||||
//// }
|
||||
//// class C extends (foo()).[|B|] {}
|
||||
//// class C1 extends foo().[|B|] {}
|
||||
|
||||
verify.singleReferenceGroup("(property) B: typeof B");
|
||||
verify.singleReferenceGroup("(property) B: typeof B", "B");
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// @Filename: foo.ts
|
||||
//// export function foo() { return "foo"; }
|
||||
|
||||
//// import("[|./foo|]")
|
||||
//// var x = import("[|./foo|]")
|
||||
//// [|import("[|{| "contextRangeIndex": 0 |}./foo|]")|]
|
||||
//// [|var x = import("[|{| "contextRangeIndex": 2 |}./foo|]")|]
|
||||
|
||||
verify.singleReferenceGroup('module "/tests/cases/fourslash/foo"');
|
||||
verify.singleReferenceGroup('module "/tests/cases/fourslash/foo"', "./foo");
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: foo.ts
|
||||
//// export function [|{| "isWriteAccess": true, "isDefinition": true |}bar|]() { return "bar"; }
|
||||
//// [|export function [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}bar|]() { return "bar"; }|]
|
||||
|
||||
//// var x = import("./foo");
|
||||
//// x.then(foo => {
|
||||
//// foo.[|bar|]();
|
||||
//// })
|
||||
|
||||
verify.singleReferenceGroup("function bar(): string");
|
||||
verify.rangesAreRenameLocations();
|
||||
verify.singleReferenceGroup("function bar(): string", "bar");
|
||||
verify.rangesWithSameTextAreRenameLocations("bar");
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: foo.ts
|
||||
////export function [|{| "isWriteAccess": true, "isDefinition": true |}bar|]() { return "bar"; }
|
||||
////import('./foo').then(({ [|{| "isWriteAccess": true, "isDefinition": true |}bar|] }) => undefined);
|
||||
////[|export function [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}bar|]() { return "bar"; }|]
|
||||
////import('./foo').then(([|{ [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}bar|] }|]) => undefined);
|
||||
|
||||
const [r0, r1] = test.ranges();
|
||||
const [r0Def, r0, r1Def, r1] = test.ranges();
|
||||
verify.referenceGroups(r0, [{ definition: "function bar(): string", ranges: [r0, r1] }]);
|
||||
verify.referenceGroups(r1, [
|
||||
{ definition: "function bar(): string", ranges: [r0] },
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
// @allowJs: true
|
||||
// @Filename: Foo.js
|
||||
/////** @type {function ([|{|"isWriteAccess": true, "isDefinition": true|}new|]: string, string): string} */
|
||||
/////** @type {function ([|[|{|"isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0|}new|]: string|], string): string} */
|
||||
////var f;
|
||||
|
||||
const [a0] = test.ranges();
|
||||
const [a0Def, a0] = test.ranges();
|
||||
verify.singleReferenceGroup("(parameter) new: string", [a0]);
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
// @Filename: a.ts
|
||||
////export class C {
|
||||
//// [|constructor|](n: number);
|
||||
//// [|constructor|]();
|
||||
//// [|constructor|](n?: number){}
|
||||
//// [|[|{| "contextRangeIndex": 0 |}constructor|](n: number);|]
|
||||
//// [|[|{| "contextRangeIndex": 2 |}constructor|]();|]
|
||||
//// [|[|{| "contextRangeIndex": 4 |}constructor|](n?: number){}|]
|
||||
//// static f() {
|
||||
//// this.f();
|
||||
//// new [|this|]();
|
||||
@@ -40,8 +40,7 @@
|
||||
////new a.[|C|]();
|
||||
////class d extends a.C { constructor() { [|super|](); }
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [a0, a1, a2, a3, a4, b0, c0, d0, d1] = ranges;
|
||||
const [a0Def, a0, a1Def, a1, a2Def, a2, a3, a4, b0, c0, d0, d1] = test.ranges();
|
||||
verify.referenceGroups([a0, a2], defs("class C"));
|
||||
verify.referenceGroups(a1, defs("class C"));
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////class C {
|
||||
//// [|constructor|](n: number);
|
||||
//// [|constructor|](){}
|
||||
//// [|[|{| "contextRangeIndex": 0 |}constructor|](n: number);|]
|
||||
//// [|[|{| "contextRangeIndex": 2 |}constructor|](){}|]
|
||||
////}
|
||||
|
||||
verify.singleReferenceGroup("class C");
|
||||
verify.singleReferenceGroup("class C", "constructor");
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
// @esModuleInterop: true
|
||||
|
||||
// @Filename: /foo.ts
|
||||
////import [|{| "isWriteAccess": true, "isDefinition": true |}settings|] from "./settings.json";
|
||||
////[|import [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}settings|] from "./settings.json";|]
|
||||
////[|settings|];
|
||||
|
||||
// @Filename: /settings.json
|
||||
//// {}
|
||||
|
||||
verify.singleReferenceGroup("import settings");
|
||||
verify.singleReferenceGroup("import settings", "settings");
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
|
||||
// @Filename: /node_modules/@types/three/index.d.ts
|
||||
////export * from "./three-core";
|
||||
////export as namespace [|{| "isWriteAccess": true, "isDefinition": true |}THREE|];
|
||||
////[|export as namespace [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}THREE|];|]
|
||||
|
||||
// @Filename: /typings/global.d.ts
|
||||
////import * as _THREE from '[|three|]';
|
||||
////[|import * as _THREE from '[|{| "contextRangeIndex": 2 |}three|]';|]
|
||||
////declare global {
|
||||
//// const [|{| "isWriteAccess": true, "isDefinition": true |}THREE|]: typeof _THREE;
|
||||
//// [|const [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 4 |}THREE|]: typeof _THREE;|]
|
||||
////}
|
||||
|
||||
// @Filename: /src/index.ts
|
||||
@@ -38,7 +38,8 @@
|
||||
//// "files": ["/src/index.ts", "typings/global.d.ts"]
|
||||
////}
|
||||
|
||||
const [r0Def, r0, r1Def, r1, r2Def, ...rest] = test.ranges();
|
||||
// GH#29533
|
||||
// TODO:: this should be var THREE: typeof import instead of module name as var but thats existing issue and repros with quickInfo too.
|
||||
verify.singleReferenceGroup(`module "/node_modules/@types/three/index"
|
||||
var "/node_modules/@types/three/index": typeof import("/node_modules/@types/three/index")`);
|
||||
var "/node_modules/@types/three/index": typeof import("/node_modules/@types/three/index")`, [r0, r1, ...rest]);
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////import { [|ab|] as [|{| "isWriteAccess": true, "isDefinition": true |}cd|] } from "doesNotExist";
|
||||
////[|import { [|{| "contextRangeIndex": 0 |}ab|] as [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}cd|] } from "doesNotExist";|]
|
||||
|
||||
const [r0, r1] = test.ranges();
|
||||
const [r0Def, r0, r1] = test.ranges();
|
||||
verify.referenceGroups(r0, undefined);
|
||||
verify.singleReferenceGroup("import cd", [r1]);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {
|
||||
////export = [|class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}A|] {
|
||||
//// m() { [|A|]; }
|
||||
////};
|
||||
////}|];
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
|
||||
////[|import [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 3 |}A|] = require("./a");|]
|
||||
////[|A|];
|
||||
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
const [r0Def, r0, r1, r2Def, r2, r3] = test.ranges();
|
||||
const defs = { definition: "(local class) A", ranges: [r0, r1] };
|
||||
const imports = { definition: '(alias) (local class) A\nimport A = require("./a")', ranges: [r2, r3] };
|
||||
verify.referenceGroups([r0, r1], [defs, imports]);
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: /a.js
|
||||
////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {};
|
||||
////module.exports = [|class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}A|] {}|];
|
||||
|
||||
// @Filename: /b.js
|
||||
////import [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
|
||||
////[|import [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}A|] = require("./a");|]
|
||||
////[|A|];
|
||||
|
||||
const [r0, r1, r2] = test.ranges();
|
||||
const [r0Def, r0, r1Def, r1, r2] = test.ranges();
|
||||
const defs = { definition: "(local class) A", ranges: [r0] };
|
||||
const imports = { definition: '(alias) (local class) A\nimport A = require("./a")', ranges: [r1, r2] };
|
||||
verify.referenceGroups([r0], [defs, imports]);
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: /a.js
|
||||
////exports.[|{| "isWriteAccess": true, "isDefinition": true |}A|] = class {};
|
||||
////[|exports.[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}A|] = class {};|]
|
||||
|
||||
// @Filename: /b.js
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}A|] } from "./a";
|
||||
////[|import { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}A|] } from "./a";|]
|
||||
////[|A|];
|
||||
|
||||
const [r0, r1, r2] = test.ranges();
|
||||
const [r0Def, r0, r1Def, r1, r2] = test.ranges();
|
||||
const defs = { definition: "class A\n(property) A: typeof A", ranges: [r0] };
|
||||
const imports = { definition: "(alias) class A\n(alias) (property) A: typeof A\nimport A", ranges: [r1, r2] };
|
||||
verify.referenceGroups([r0], [defs, imports]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////class [|{| "isWriteAccess": true, "isDefinition": true |}C|] {
|
||||
////[|class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}C|] {
|
||||
//// static s() {
|
||||
//// [|this|];
|
||||
//// }
|
||||
@@ -10,9 +10,9 @@
|
||||
//// function inner() { this; }
|
||||
//// class Inner { x = this; }
|
||||
//// }
|
||||
////}
|
||||
////}|]
|
||||
|
||||
const [r0, r1, r2] = test.ranges();
|
||||
const [r0Def, r0, r1, r2] = test.ranges();
|
||||
verify.referenceGroups(r0, [{ definition: "class C", ranges: [r0, r1, r2] }]);
|
||||
verify.singleReferenceGroup("this: typeof C", [r1, r2]);
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
// @Filename: /a.js
|
||||
////function f() {
|
||||
//// this.[|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0;
|
||||
//// [|this.[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}x|] = 0;|]
|
||||
////}
|
||||
////f.prototype.setX = function() {
|
||||
//// this.[|{| "isWriteAccess": true, "isDefinition": true |}x|] = 1;
|
||||
//// [|this.[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}x|] = 1;|]
|
||||
////}
|
||||
////f.prototype.useX = function() { this.[|x|]; }
|
||||
|
||||
verify.singleReferenceGroup("(property) f.x: number");
|
||||
verify.singleReferenceGroup("(property) f.x: number", "x");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////declare class [|{| "isWriteAccess": true, "isDefinition": true |}C|] {
|
||||
////[|declare class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}C|] {
|
||||
//// static m(): void;
|
||||
////}
|
||||
////}|]
|
||||
|
||||
verify.singleReferenceGroup("class C");
|
||||
verify.singleReferenceGroup("class C", "C");
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export default function [|{| "isWriteAccess": true, "isDefinition": true |}a|]() {}
|
||||
////[|export default function [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}a|]() {}|]
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import [|{| "isWriteAccess": true, "isDefinition": true |}a|], * as ns from "./a";
|
||||
////[|import [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}a|], * as ns from "./a";|]
|
||||
|
||||
const [r0, r1] = test.ranges();
|
||||
const [r0Def, r0, r1Def, r1] = test.ranges();
|
||||
const a: FourSlashInterface.ReferenceGroup = { definition: "function a(): void", ranges: [r0] };
|
||||
const b: FourSlashInterface.ReferenceGroup = { definition: "(alias) function a(): void\nimport a", ranges: [r1] };
|
||||
verify.referenceGroups(r0, [a, b]);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export [|{| "isWriteAccess": true, "isDefinition": true |}default|] function [|{| "isWriteAccess": true, "isDefinition": true |}f|]() {}
|
||||
////[|export [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}default|] function [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}f|]() {}|]
|
||||
|
||||
// @Filename: /b.ts
|
||||
////export import a = require("./a");
|
||||
@@ -10,10 +10,10 @@
|
||||
////import { a } from "./b";
|
||||
////a.[|default|]();
|
||||
////
|
||||
////declare const x: { [|{| "isWriteAccess": true, "isDefinition": true |}default|]: number };
|
||||
////declare const x: { [|[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 4 |}default|]: number|] };
|
||||
////x.[|default|];
|
||||
|
||||
const [r0, r1, r2, r3, r4] = test.ranges();
|
||||
const [r0Def, r0, r1, r2, r3Def, r3, r4] = test.ranges();
|
||||
|
||||
verify.referenceGroups([r0], [{ definition: "function f(): void", ranges: [r0, r2] }]);
|
||||
verify.singleReferenceGroup("function f(): void", [r1, r2]);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////const [|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0;
|
||||
////[|const [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}x|] = 0;|]
|
||||
////[|x|];
|
||||
|
||||
const ranges = test.ranges();
|
||||
const ranges = test.rangesByText().get("x");
|
||||
verify.referenceGroups(ranges, [
|
||||
{
|
||||
definition: { text: "const x: 0", range: ranges[0] },
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I<T> {
|
||||
//// [|{| "isDefinition": true |}x|]: boolean;
|
||||
//// [|[|{| "isDefinition": true, "contextRangeIndex": 0 |}x|]: boolean;|]
|
||||
////}
|
||||
////declare const i: I<number>;
|
||||
////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } = i;
|
||||
////[|const { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}x|] } = i;|]
|
||||
|
||||
const [r0, r1] = test.ranges();
|
||||
const [r0Def, r0, r1Def, r1] = test.ranges();
|
||||
|
||||
verify.referenceGroups(r0, [{ definition: "(property) I<T>.x: boolean", ranges: [r0, r1] }]);
|
||||
verify.referenceGroups(r1, [
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////class Test {
|
||||
//// get [|{| "isDefinition": true, "isWriteAccess": true |}x|]() { return 0; }
|
||||
//// [|get [|{| "isDefinition": true, "isWriteAccess": true, "contextRangeIndex": 0 |}x|]() { return 0; }|]
|
||||
////
|
||||
//// set [|{| "isDefinition": true, "isWriteAccess": true |}y|](a: number) {}
|
||||
//// [|set [|{| "isDefinition": true, "isWriteAccess": true, "contextRangeIndex": 2 |}y|](a: number) {}|]
|
||||
////}
|
||||
////const { [|{| "isDefinition": true, "isWriteAccess": true |}x|], [|{| "isDefinition": true, "isWriteAccess": true |}y|] } = new Test();
|
||||
////[|const { [|{| "isDefinition": true, "isWriteAccess": true, "contextRangeIndex": 4 |}x|], [|{| "isDefinition": true, "isWriteAccess": true, "contextRangeIndex": 4 |}y|] } = new Test();|]
|
||||
////[|x|]; [|y|];
|
||||
|
||||
const [x0, y0, x1, y1, x2, y2] = test.ranges();
|
||||
const [x0Def, x0, y0Def, y0, xy1Def, x1, y1, x2, y2] = test.ranges();
|
||||
verify.referenceGroups(x0, [{ definition: "(property) Test.x: number", ranges: [x0, x1] }]);
|
||||
verify.referenceGroups(x1, [
|
||||
{ definition: "(property) Test.x: number", ranges: [x0] },
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user