Improving completions for computed properties

This commit is contained in:
Pranav Senthilnathan (from Dev Box) 2023-10-20 13:31:23 -07:00
parent b4787652d2
commit b2b138fe2f
12 changed files with 4081 additions and 291 deletions

View File

@ -240,6 +240,7 @@ import {
isStringLiteralOrTemplate,
isStringTextContainingNode,
isSyntaxList,
isTransientSymbol,
isTypeKeyword,
isTypeKeywordTokenOrIdentifier,
isTypeLiteralNode,
@ -3663,71 +3664,129 @@ function getCompletionData(
}
function addPropertySymbol(symbol: Symbol, insertAwait: boolean, insertQuestionDot: boolean) {
// For a computed property with an accessible name like `Symbol.iterator`,
// we'll add a completion for the *name* `Symbol` instead of for the property.
// If this is e.g. [Symbol.iterator], add a completion for `Symbol`.
const computedPropertyName = firstDefined(symbol.declarations, decl => tryCast(getNameOfDeclaration(decl), isComputedPropertyName));
if (computedPropertyName) {
const leftMostName = getLeftMostName(computedPropertyName.expression); // The completion is for `Symbol`, not `iterator`.
const nameSymbol = leftMostName && typeChecker.getSymbolAtLocation(leftMostName);
// If this is nested like for `namespace N { export const sym = Symbol(); }`, we'll add the completion for `N`.
const firstAccessibleSymbol = nameSymbol && getFirstSymbolInChain(nameSymbol, contextToken, typeChecker);
const firstAccessibleSymbolId = firstAccessibleSymbol && getSymbolId(firstAccessibleSymbol);
if (firstAccessibleSymbolId && addToSeen(seenPropertySymbols, firstAccessibleSymbolId)) {
const index = symbols.length;
symbols.push(firstAccessibleSymbol);
const moduleSymbol = firstAccessibleSymbol.parent;
if (
!moduleSymbol ||
!isExternalModuleSymbol(moduleSymbol) ||
typeChecker.tryGetMemberInModuleExportsAndProperties(firstAccessibleSymbol.name, moduleSymbol) !== firstAccessibleSymbol
) {
symbolToOriginInfoMap[index] = { kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberNoExport) };
}
else {
const fileName = isExternalModuleNameRelative(stripQuotes(moduleSymbol.name)) ? getSourceFileOfModule(moduleSymbol)?.fileName : undefined;
const { moduleSpecifier } = (importSpecifierResolver ||= codefix.createImportSpecifierResolver(sourceFile, program, host, preferences)).getModuleSpecifierForBestExportInfo(
[{
exportKind: ExportKind.Named,
moduleFileName: fileName,
isFromPackageJson: false,
moduleSymbol,
symbol: firstAccessibleSymbol,
targetFlags: skipAlias(firstAccessibleSymbol, typeChecker).flags,
}],
position,
isValidTypeOnlyAliasUseSite(location),
) || {};
// For a computed property `x.y` in an exported namespace `n` that is imported
// in another file as `m`, we can access `y` as `m.n.x.y`. To form this access chain, first
// we follow `x` up it symbol parents until we find a symbol that is accessible from the completion
// location. This gives us a property access chain (`m.n.x`) which we can then combine with the original
// computed property expression (`x.y`) by substitution of `m.n.x` for `x` in `x.y` to get `m.n.x.y`.
// If this fails, we will fall back to the literal value of `y`.
if (moduleSpecifier) {
const origin: SymbolOriginInfoResolvedExport = {
kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberExport),
moduleSymbol,
isDefaultExport: false,
symbolName: firstAccessibleSymbol.name,
exportName: firstAccessibleSymbol.name,
fileName,
moduleSpecifier,
};
symbolToOriginInfoMap[index] = origin;
}
const computedPropertyName = firstDefined(symbol.declarations, decl => tryCast(getNameOfDeclaration(decl), isComputedPropertyName));
if (!computedPropertyName) {
addLiteralSymbol();
return;
}
const computedPropertyNameExpression = computedPropertyName.expression;
const name = isEntityName(computedPropertyNameExpression)
? computedPropertyNameExpression
: isPropertyAccessExpression(computedPropertyNameExpression)
? computedPropertyNameExpression.name
: undefined;
const nameSymbol = name && typeChecker.getSymbolAtLocation(name);
const nameSymbolId = nameSymbol && getSymbolId(nameSymbol);
if (!nameSymbolId) {
addLiteralSymbol();
return;
}
if (addToSeen(seenPropertySymbols, nameSymbolId)) {
const leftMostName = getLeftMostName(computedPropertyNameExpression); // The completion is for `Symbol`, not `iterator`.
const leftMostNameSymbol = leftMostName && typeChecker.getSymbolAtLocation(leftMostName);
// If this is nested like for `namespace N { export const sym = Symbol(); }`, we'll add the completion for `N`.
const firstAccessibleSymbol = leftMostNameSymbol && getFirstSymbolInChain(leftMostNameSymbol, contextToken, typeChecker);
if (!firstAccessibleSymbol) {
addLiteralSymbol();
return;
}
const index = symbols.length;
symbols.push(nameSymbol);
const moduleSymbol = firstAccessibleSymbol.parent;
if (
!moduleSymbol ||
!isExternalModuleSymbol(moduleSymbol) ||
typeChecker.tryGetMemberInModuleExportsAndProperties(firstAccessibleSymbol.name, moduleSymbol) !== firstAccessibleSymbol
) {
// If preferences allow insert text, add completion for [<QualifiedSymbolName>]
const node = preferences.includeCompletionsWithInsertText
? createComputedPropertyAccess(nameSymbol, leftMostNameSymbol, computedPropertyNameExpression)
: undefined;
if (!node) {
// Switch to literal symbol if user doesn't want insert text
symbols[index] = symbol;
} else {
const printer = createPrinter({
removeComments: true,
module: compilerOptions.module,
target: compilerOptions.target,
omitTrailingSemicolon: true,
});
const origin: SymbolOriginInfoComputedPropertyName = {
kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberNoExport) | SymbolOriginInfoKind.ComputedPropertyName,
symbolName: printer.printNode(EmitHint.Unspecified, node, contextToken.getSourceFile())
};
symbolToOriginInfoMap[index] = origin;
}
}
else if (preferences.includeCompletionsWithInsertText) {
if (firstAccessibleSymbolId && seenPropertySymbols.has(firstAccessibleSymbolId)) {
return;
else {
const fileName = isExternalModuleNameRelative(stripQuotes(moduleSymbol.name)) ? getSourceFileOfModule(moduleSymbol)?.fileName : undefined;
const { moduleSpecifier } = (importSpecifierResolver ||= codefix.createImportSpecifierResolver(sourceFile, program, host, preferences)).getModuleSpecifierForBestExportInfo(
[{
exportKind: ExportKind.Named,
moduleFileName: fileName,
isFromPackageJson: false,
moduleSymbol,
symbol: firstAccessibleSymbol,
targetFlags: skipAlias(firstAccessibleSymbol, typeChecker).flags,
}],
position,
isValidTypeOnlyAliasUseSite(location),
) || {};
if (moduleSpecifier) {
const origin: SymbolOriginInfoResolvedExport = {
kind: getNullableSymbolOriginInfoKind(SymbolOriginInfoKind.SymbolMemberExport),
moduleSymbol,
isDefaultExport: false,
symbolName: firstAccessibleSymbol.name,
exportName: firstAccessibleSymbol.name,
fileName,
moduleSpecifier,
};
symbolToOriginInfoMap[index] = origin;
}
addSymbolOriginInfo(symbol);
addSymbolSortInfo(symbol);
symbols.push(symbol);
}
}
else {
function addLiteralSymbol() {
addSymbolOriginInfo(symbol);
addSymbolSortInfo(symbol);
symbols.push(symbol);
}
function createComputedPropertyAccess(nameSymbol: Symbol, leftMostNameSymbol: Symbol, computedPropertyNameExpression: Expression) {
let node: Node | undefined;
if (!isTransientSymbol(nameSymbol)) {
node = typeChecker.symbolToEntityName(nameSymbol, /*meaning*/ undefined!, contextToken, NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope);
}
else {
// Object literals assigned as const
const leftMostNodeAccessExpression = typeChecker.symbolToNode(leftMostNameSymbol, /*meaning*/ undefined!, contextToken, NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope);
type OnlyPropertyAccess = Identifier | (PropertyAccessExpression & { expression: OnlyPropertyAccess; });
node = createPropertyAccess(computedPropertyNameExpression as OnlyPropertyAccess);
function createPropertyAccess(n: OnlyPropertyAccess): Expression {
if (isIdentifier(n)) {
return leftMostNodeAccessExpression! as Expression; //TODO ! and cast
}
return factory.createPropertyAccessExpression(createPropertyAccess(n.expression), n.name);
}
}
return node;
}
function addSymbolSortInfo(symbol: Symbol) {
if (isStaticProperty(symbol)) {
symbolToSortTextMap[getSymbolId(symbol)] = SortText.LocalDeclarationPriority;
@ -4535,7 +4594,7 @@ function getCompletionData(
if (declaration && isClassElement(declaration) && declaration.name && isComputedPropertyName(declaration.name)) {
const origin: SymbolOriginInfoComputedPropertyName = {
kind: SymbolOriginInfoKind.ComputedPropertyName,
symbolName: typeChecker.symbolToString(symbol),
symbolName: typeChecker.symbolToString(symbol)
};
symbolToOriginInfoMap[index] = origin;
}
@ -5175,7 +5234,7 @@ function getCompletionEntryDisplayNameForSymbol(
case CompletionKind.PropertyAccess:
case CompletionKind.Global: // For a 'this.' completion it will be in a global context, but may have a non-identifier name.
// Don't add a completion for a name starting with a space. See https://github.com/Microsoft/TypeScript/pull/20547
return name.charCodeAt(0) === CharacterCodes.space ? undefined : { name, needsConvertPropertyAccess: true };
return name.charCodeAt(0) === CharacterCodes.space ? undefined : { name, needsConvertPropertyAccess: !originIsComputedPropertyName(origin) };
case CompletionKind.None:
case CompletionKind.String:
return validNameResult;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,902 @@
=== /n.ts ===
// namespace N {
// export const InnerObjectExported = {
// A: "a"
// } as const
// const InnerObjectNotExported = {
// B: "b"
// } as const
// export type InnerObjectType = {
// [InnerObjectExported.A]: number
// [InnerObjectNotExported.B]: number
// }
// }
// const OuterObject = {
// C: "c"
// } as const
// type OuterObjectType = N.InnerObjectType & {
// [OuterObject.C]: number
// }
// import * as mu from './m'
// declare const x1: N.InnerObjectType;
// declare const x2: OuterObjectType;
// declare const x3: mu.M.InnerObjectType;
// declare const x4: mu.OuterObjectType;
// declare const x5: mu.omega.O.InnerObjectType;
// declare const x6: mu.omega.OuterObjectType;
// x1.;
// ^
// | ----------------------------------------------------------------------
// | (property) [InnerObjectNotExported.B]: number
// | (property) A: "a"
// | ----------------------------------------------------------------------
// x2.;
// ^
// | ----------------------------------------------------------------------
// | (property) [InnerObjectNotExported.B]: number
// | (property) A: "a"
// | (property) C: "c"
// | ----------------------------------------------------------------------
// x3.;
// ^
// | ----------------------------------------------------------------------
// | (property) [InnerObjectNotExported.B]: number
// | (property) A: "a"
// | ----------------------------------------------------------------------
// x4.;
// ^
// | ----------------------------------------------------------------------
// | (property) [InnerObjectNotExported.B]: number
// | (property) [OuterObjectNotExported.D]: number
// | (property) A: "a"
// | (property) C: "c"
// | ----------------------------------------------------------------------
// x5.;
// ^
// | ----------------------------------------------------------------------
// | (property) [InnerObjectNotExported.B]: number
// | (property) A: "a"
// | ----------------------------------------------------------------------
// x6.;
// ^
// | ----------------------------------------------------------------------
// | (property) [InnerObjectNotExported.B]: number
// | (property) [OuterObjectNotExported.D]: number
// | (property) A: "a"
// | (property) C: "c"
// | ----------------------------------------------------------------------
[
{
"marker": {
"fileName": "/n.ts",
"position": 667,
"name": "a"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "N.InnerObjectExported.A",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[N.InnerObjectExported.A]",
"replacementSpan": {
"start": 666,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"a\"",
"kind": "stringLiteral"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 672,
"name": "b"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "N.InnerObjectExported.A",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[N.InnerObjectExported.A]",
"replacementSpan": {
"start": 671,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"a\"",
"kind": "stringLiteral"
}
],
"documentation": []
},
{
"name": "OuterObject.C",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[OuterObject.C]",
"replacementSpan": {
"start": 671,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "C",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"c\"",
"kind": "stringLiteral"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 677,
"name": "c"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "mu.M.InnerObjectExported.A",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[mu.M.InnerObjectExported.A]",
"replacementSpan": {
"start": 676,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"a\"",
"kind": "stringLiteral"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 682,
"name": "d"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "d",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[OuterObjectNotExported.D]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "mu.M.InnerObjectExported.A",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[mu.M.InnerObjectExported.A]",
"replacementSpan": {
"start": 681,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"a\"",
"kind": "stringLiteral"
}
],
"documentation": []
},
{
"name": "mu.OuterObjectExported.C",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[mu.OuterObjectExported.C]",
"replacementSpan": {
"start": 681,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "C",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"c\"",
"kind": "stringLiteral"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 687,
"name": "e"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "mu.omega.O.InnerObjectExported.A",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[mu.omega.O.InnerObjectExported.A]",
"replacementSpan": {
"start": 686,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"a\"",
"kind": "stringLiteral"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 692,
"name": "f"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "d",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[OuterObjectNotExported.D]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "mu.omega.O.InnerObjectExported.A",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[mu.omega.O.InnerObjectExported.A]",
"replacementSpan": {
"start": 691,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "A",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"a\"",
"kind": "stringLiteral"
}
],
"documentation": []
},
{
"name": "mu.omega.OuterObjectExported.C",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[mu.omega.OuterObjectExported.C]",
"replacementSpan": {
"start": 691,
"length": 1
},
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "C",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"c\"",
"kind": "stringLiteral"
}
],
"documentation": []
}
]
}
}
]

View File

@ -0,0 +1,542 @@
=== /n.ts ===
// namespace N {
// export const InnerObjectExported = {
// A: "a"
// } as const
// const InnerObjectNotExported = {
// B: "b"
// } as const
// export type InnerObjectType = {
// [InnerObjectExported.A]: number
// [InnerObjectNotExported.B]: number
// }
// }
// const OuterObject = {
// C: "c"
// } as const
// type OuterObjectType = N.InnerObjectType & {
// [OuterObject.C]: number
// }
// import * as mu from './m'
// declare const x1: N.InnerObjectType;
// declare const x2: OuterObjectType;
// declare const x3: mu.M.InnerObjectType;
// declare const x4: mu.OuterObjectType;
// declare const x5: mu.omega.O.InnerObjectType;
// declare const x6: mu.omega.OuterObjectType;
// x1.;
// ^
// | ----------------------------------------------------------------------
// | (property) a
// | (property) [InnerObjectNotExported.B]: number
// | ----------------------------------------------------------------------
// x2.;
// ^
// | ----------------------------------------------------------------------
// | (property) a
// | (property) [InnerObjectNotExported.B]: number
// | (property) c
// | ----------------------------------------------------------------------
// x3.;
// ^
// | ----------------------------------------------------------------------
// | (property) a
// | (property) [InnerObjectNotExported.B]: number
// | ----------------------------------------------------------------------
// x4.;
// ^
// | ----------------------------------------------------------------------
// | (property) a
// | (property) [InnerObjectNotExported.B]: number
// | (property) c
// | (property) [OuterObjectNotExported.D]: number
// | ----------------------------------------------------------------------
// x5.;
// ^
// | ----------------------------------------------------------------------
// | (property) a
// | (property) [InnerObjectNotExported.B]: number
// | ----------------------------------------------------------------------
// x6.;
// ^
// | ----------------------------------------------------------------------
// | (property) a
// | (property) [InnerObjectNotExported.B]: number
// | (property) c
// | (property) [OuterObjectNotExported.D]: number
// | ----------------------------------------------------------------------
[
{
"marker": {
"fileName": "/n.ts",
"position": 667,
"name": "a"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "a",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 672,
"name": "b"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "a",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "c",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 677,
"name": "c"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "a",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 682,
"name": "d"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "a",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "c",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "d",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[OuterObjectNotExported.D]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 687,
"name": "e"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "a",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
}
]
}
},
{
"marker": {
"fileName": "/n.ts",
"position": 692,
"name": "f"
},
"item": {
"flags": 0,
"isGlobalCompletion": false,
"isMemberCompletion": true,
"isNewIdentifierLocation": false,
"entries": [
{
"name": "a",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "b",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[InnerObjectNotExported.B]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
},
{
"name": "c",
"kind": "property",
"kindModifiers": "",
"sortText": "11"
},
{
"name": "d",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "property",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "[OuterObjectNotExported.D]",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "number",
"kind": "keyword"
}
],
"documentation": []
}
]
}
}
]

View File

@ -26,16 +26,9 @@
// foo.
// ^
// | ----------------------------------------------------------------------
// | const a: {
// | readonly KEY_1: "key_1";
// | readonly KEY_2: "key_2";
// | readonly KEY_3: "key_3";
// | }
// | const b: {
// | readonly KEY_1: "key_1";
// | readonly KEY_2: "key_2";
// | readonly KEY_3: "key_3";
// | }
// | (property) KEY_2: "key_2"
// | (property) KEY_3: "key_3"
// | (property) KEY_1: "key_1"
// | ----------------------------------------------------------------------
[
@ -52,88 +45,28 @@
"isNewIdentifierLocation": false,
"entries": [
{
"name": "a",
"kind": "const",
"name": "a.KEY_2",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[a]",
"insertText": "[a.KEY_2]",
"replacementSpan": {
"start": 344,
"length": 1
},
"displayParts": [
{
"text": "const",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "a",
"kind": "localName"
},
{
"text": ":",
"text": "(",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
"text": "property",
"kind": "text"
},
{
"text": "{",
"text": ")",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": " ",
"kind": "space"
},
{
"text": "readonly",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "KEY_1",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"key_1\"",
"kind": "stringLiteral"
},
{
"text": ";",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": " ",
"kind": "space"
},
{
"text": "readonly",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
@ -153,177 +86,33 @@
{
"text": "\"key_2\"",
"kind": "stringLiteral"
},
{
"text": ";",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": " ",
"kind": "space"
},
{
"text": "readonly",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "KEY_3",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"key_3\"",
"kind": "stringLiteral"
},
{
"text": ";",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": "}",
"kind": "punctuation"
}
],
"documentation": []
},
{
"name": "b",
"kind": "const",
"name": "a.KEY_3",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[b]",
"insertText": "[a.KEY_3]",
"replacementSpan": {
"start": 344,
"length": 1
},
"displayParts": [
{
"text": "const",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "b",
"kind": "localName"
},
{
"text": ":",
"text": "(",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
"text": "property",
"kind": "text"
},
{
"text": "{",
"text": ")",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": " ",
"kind": "space"
},
{
"text": "readonly",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "KEY_1",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"key_1\"",
"kind": "stringLiteral"
},
{
"text": ";",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": " ",
"kind": "space"
},
{
"text": "readonly",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "KEY_2",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"key_2\"",
"kind": "stringLiteral"
},
{
"text": ";",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
},
{
"text": " ",
"kind": "space"
},
{
"text": "readonly",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
@ -343,18 +132,52 @@
{
"text": "\"key_3\"",
"kind": "stringLiteral"
},
}
],
"documentation": []
},
{
"name": "b.KEY_1",
"kind": "property",
"kindModifiers": "",
"sortText": "11",
"insertText": "[b.KEY_1]",
"replacementSpan": {
"start": 344,
"length": 1
},
"displayParts": [
{
"text": ";",
"text": "(",
"kind": "punctuation"
},
{
"text": "\n",
"kind": "lineBreak"
"text": "property",
"kind": "text"
},
{
"text": "}",
"text": ")",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "KEY_1",
"kind": "propertyName"
},
{
"text": ":",
"kind": "punctuation"
},
{
"text": " ",
"kind": "space"
},
{
"text": "\"key_1\"",
"kind": "stringLiteral"
}
],
"documentation": []

View File

@ -0,0 +1,87 @@
/// <reference path="fourslash.ts" />
// @Filename: /o.ts
////export namespace O {
//// export enum InnerEnumExported {
//// A = "a"
//// }
//// enum InnerEnumNotExported {
//// B = "b"
//// }
//// export type InnerObjectType = {
//// [InnerEnumExported.A]: number
//// [InnerEnumNotExported.B]: number
//// }
//// }
//// export enum OuterEnumExported {
//// C = "c"
//// }
//// enum OuterEnumNotExported {
//// D = "d"
//// }
//// export type OuterObjectType = O.InnerObjectType & {
//// [OuterEnumExported.C]: number
//// [OuterEnumNotExported.D]: number
//// }
// @Filename: /m.ts
////export namespace M {
//// export enum InnerEnumExported {
//// A = "a"
//// }
//// enum InnerEnumNotExported {
//// B = "b"
//// }
//// export type InnerObjectType = {
//// [InnerEnumExported.A]: number
//// [InnerEnumNotExported.B]: number
//// }
////}
////export enum OuterEnumExported {
//// C = "c"
////}
////enum OuterEnumNotExported {
//// D = "d"
////}
////export type OuterObjectType = M.InnerObjectType & {
//// [OuterEnumExported.C]: number
//// [OuterEnumNotExported.D]: number
////}
////export * as omega from './o'
// @Filename: /n.ts
////namespace N {
//// export enum InnerEnumExported {
//// A = "a"
//// }
//// enum InnerEnumNotExported {
//// B = "b"
//// }
//// export type InnerObjectType = {
//// [InnerEnumExported.A]: number
//// [InnerEnumNotExported.B]: number
//// }
////}
////enum OuterEnum {
//// C = "c"
////}
////type OuterObjectType = N.InnerObjectType & {
//// [OuterEnum.C]: number
////}
////import * as mu from './m'
////declare const x1: N.InnerObjectType;
////declare const x2: OuterObjectType;
////declare const x3: mu.M.InnerObjectType;
////declare const x4: mu.OuterObjectType;
////declare const x5: mu.omega.O.InnerObjectType;
////declare const x6: mu.omega.OuterObjectType;
////x1./*a*/;
////x2./*b*/;
////x3./*c*/;
////x4./*d*/;
////x5./*e*/;
////x6./*f*/;
verify.baselineCompletions({
includeCompletionsWithInsertText: true,
});

View File

@ -0,0 +1,87 @@
/// <reference path="fourslash.ts" />
// @Filename: /o.ts
////export namespace O {
//// export enum InnerEnumExported {
//// A = "a"
//// }
//// enum InnerEnumNotExported {
//// B = "b"
//// }
//// export type InnerObjectType = {
//// [InnerEnumExported.A]: number
//// [InnerEnumNotExported.B]: number
//// }
//// }
//// export enum OuterEnumExported {
//// C = "c"
//// }
//// enum OuterEnumNotExported {
//// D = "d"
//// }
//// export type OuterObjectType = O.InnerObjectType & {
//// [OuterEnumExported.C]: number
//// [OuterEnumNotExported.D]: number
//// }
// @Filename: /m.ts
////export namespace M {
//// export enum InnerEnumExported {
//// A = "a"
//// }
//// enum InnerEnumNotExported {
//// B = "b"
//// }
//// export type InnerObjectType = {
//// [InnerEnumExported.A]: number
//// [InnerEnumNotExported.B]: number
//// }
////}
////export enum OuterEnumExported {
//// C = "c"
////}
////enum OuterEnumNotExported {
//// D = "d"
////}
////export type OuterObjectType = M.InnerObjectType & {
//// [OuterEnumExported.C]: number
//// [OuterEnumNotExported.D]: number
////}
////export * as omega from './o'
// @Filename: /n.ts
////namespace N {
//// export enum InnerEnumExported {
//// A = "a"
//// }
//// enum InnerEnumNotExported {
//// B = "b"
//// }
//// export type InnerObjectType = {
//// [InnerEnumExported.A]: number
//// [InnerEnumNotExported.B]: number
//// }
////}
////enum OuterEnum {
//// C = "c"
////}
////type OuterObjectType = N.InnerObjectType & {
//// [OuterEnum.C]: number
////}
////import * as mu from './m'
////declare const x1: N.InnerObjectType;
////declare const x2: OuterObjectType;
////declare const x3: mu.M.InnerObjectType;
////declare const x4: mu.OuterObjectType;
////declare const x5: mu.omega.O.InnerObjectType;
////declare const x6: mu.omega.OuterObjectType;
////x1./*a*/;
////x2./*b*/;
////x3./*c*/;
////x4./*d*/;
////x5./*e*/;
////x6./*f*/;
verify.baselineCompletions({
includeCompletionsWithInsertText: true,
});

View File

@ -0,0 +1,87 @@
/// <reference path="fourslash.ts" />
// @Filename: /o.ts
////export namespace O {
//// export const InnerObjectExported = {
//// A: "a"
//// } as const
//// const InnerObjectNotExported = {
//// B: "b"
//// } as const
//// export type InnerObjectType = {
//// [InnerObjectExported.A]: number
//// [InnerObjectNotExported.B]: number
//// }
//// }
//// export const OuterObjectExported = {
//// C: "c"
//// } as const
//// const OuterObjectNotExported = {
//// D: "d"
//// } as const
//// export type OuterObjectType = O.InnerObjectType & {
//// [OuterObjectExported.C]: number
//// [OuterObjectNotExported.D]: number
//// }
// @Filename: /m.ts
////export namespace M {
//// export const InnerObjectExported = {
//// A: "a"
//// } as const
//// const InnerObjectNotExported = {
//// B: "b"
//// } as const
//// export type InnerObjectType = {
//// [InnerObjectExported.A]: number
//// [InnerObjectNotExported.B]: number
//// }
////}
////export const OuterObjectExported = {
//// C: "c"
////} as const
////const OuterObjectNotExported = {
//// D: "d"
////} as const
////export type OuterObjectType = M.InnerObjectType & {
//// [OuterObjectExported.C]: number
//// [OuterObjectNotExported.D]: number
////}
////export * as omega from './o'
// @Filename: /n.ts
////namespace N {
//// export const InnerObjectExported = {
//// A: "a"
//// } as const
//// const InnerObjectNotExported = {
//// B: "b"
//// } as const
//// export type InnerObjectType = {
//// [InnerObjectExported.A]: number
//// [InnerObjectNotExported.B]: number
//// }
////}
////const OuterObject = {
//// C: "c"
////} as const
////type OuterObjectType = N.InnerObjectType & {
//// [OuterObject.C]: number
////}
////import * as mu from './m'
////declare const x1: N.InnerObjectType;
////declare const x2: OuterObjectType;
////declare const x3: mu.M.InnerObjectType;
////declare const x4: mu.OuterObjectType;
////declare const x5: mu.omega.O.InnerObjectType;
////declare const x6: mu.omega.OuterObjectType;
////x1./*a*/;
////x2./*b*/;
////x3./*c*/;
////x4./*d*/;
////x5./*e*/;
////x6./*f*/;
verify.baselineCompletions({
includeCompletionsWithInsertText: true,
});

View File

@ -0,0 +1,87 @@
/// <reference path="fourslash.ts" />
// @Filename: /o.ts
////export namespace O {
//// export const InnerObjectExported = {
//// A: "a"
//// } as const
//// const InnerObjectNotExported = {
//// B: "b"
//// } as const
//// export type InnerObjectType = {
//// [InnerObjectExported.A]: number
//// [InnerObjectNotExported.B]: number
//// }
//// }
//// export const OuterObjectExported = {
//// C: "c"
//// } as const
//// const OuterObjectNotExported = {
//// D: "d"
//// } as const
//// export type OuterObjectType = O.InnerObjectType & {
//// [OuterObjectExported.C]: number
//// [OuterObjectNotExported.D]: number
//// }
// @Filename: /m.ts
////export namespace M {
//// export const InnerObjectExported = {
//// A: "a"
//// } as const
//// const InnerObjectNotExported = {
//// B: "b"
//// } as const
//// export type InnerObjectType = {
//// [InnerObjectExported.A]: number
//// [InnerObjectNotExported.B]: number
//// }
////}
////export const OuterObjectExported = {
//// C: "c"
////} as const
////const OuterObjectNotExported = {
//// D: "d"
////} as const
////export type OuterObjectType = M.InnerObjectType & {
//// [OuterObjectExported.C]: number
//// [OuterObjectNotExported.D]: number
////}
////export * as omega from './o'
// @Filename: /n.ts
////namespace N {
//// export const InnerObjectExported = {
//// A: "a"
//// } as const
//// const InnerObjectNotExported = {
//// B: "b"
//// } as const
//// export type InnerObjectType = {
//// [InnerObjectExported.A]: number
//// [InnerObjectNotExported.B]: number
//// }
////}
////const OuterObject = {
//// C: "c"
////} as const
////type OuterObjectType = N.InnerObjectType & {
//// [OuterObject.C]: number
////}
////import * as mu from './m'
////declare const x1: N.InnerObjectType;
////declare const x2: OuterObjectType;
////declare const x3: mu.M.InnerObjectType;
////declare const x4: mu.OuterObjectType;
////declare const x5: mu.omega.O.InnerObjectType;
////declare const x6: mu.omega.OuterObjectType;
////x1./*a*/;
////x2./*b*/;
////x3./*c*/;
////x4./*d*/;
////x5./*e*/;
////x6./*f*/;
verify.baselineCompletions({
includeCompletionsWithInsertText: false,
});

View File

@ -19,7 +19,7 @@ verify.completions(
},
{
marker: "j",
exact: { name: "N", insertText: "[N]", replacementSpan: test.ranges()[1] },
exact: { name: "N.s2", insertText: "[N.s2]", replacementSpan: test.ranges()[1] },
preferences: { includeInsertTextCompletions: true },
}
);

View File

@ -17,6 +17,6 @@
verify.completions({
marker: "",
exact: { name: "M", insertText: "[M]", replacementSpan: test.ranges()[0] },
exact: { name: "M.sym", insertText: "[M.sym]", replacementSpan: test.ranges()[0] },
preferences: { includeInsertTextCompletions: true },
});