mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into watchImprovements
This commit is contained in:
@@ -416,9 +416,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue,
|
||||
// ExportType, or ExportContainer flag, and an associated export symbol with all the correct flags set
|
||||
// on it. There are 2 main reasons:
|
||||
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue flag,
|
||||
// and an associated export symbol with all the correct flags set on it. There are 2 main reasons:
|
||||
//
|
||||
// 1. We treat locals and exports of the same name as mutually exclusive within a container.
|
||||
// That means the binder will issue a Duplicate Identifier error if you mix locals and exports
|
||||
@@ -438,10 +437,7 @@ namespace ts {
|
||||
(node as JSDocTypedefTag).name.kind === SyntaxKind.Identifier &&
|
||||
((node as JSDocTypedefTag).name as Identifier).isInJSDocNamespace;
|
||||
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefInJSDocNamespace) {
|
||||
const exportKind =
|
||||
(symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) |
|
||||
(symbolFlags & SymbolFlags.Type ? SymbolFlags.ExportType : 0) |
|
||||
(symbolFlags & SymbolFlags.Namespace ? SymbolFlags.ExportNamespace : 0);
|
||||
const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
|
||||
const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
|
||||
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
|
||||
node.localSymbol = local;
|
||||
@@ -2288,7 +2284,7 @@ namespace ts {
|
||||
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
|
||||
// expression is the declaration
|
||||
setCommonJsModuleIndicator(node);
|
||||
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None);
|
||||
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
|
||||
}
|
||||
|
||||
function isExportsOrModuleExportsOrAlias(node: Node): boolean {
|
||||
@@ -2329,7 +2325,7 @@ namespace ts {
|
||||
|
||||
// 'module.exports = expr' assignment
|
||||
setCommonJsModuleIndicator(node);
|
||||
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
|
||||
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule, SymbolFlags.None);
|
||||
}
|
||||
|
||||
function bindThisPropertyAssignment(node: BinaryExpression) {
|
||||
|
||||
+50
-45
@@ -2010,7 +2010,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getAccessibleSymbolChainFromSymbolTableWorker(symbols: SymbolTable, visitedSymbolTables: SymbolTable[]): Symbol[] {
|
||||
if (contains(visitedSymbolTables, symbols)) {
|
||||
if (contains<SymbolTable>(visitedSymbolTables, symbols)) {
|
||||
return undefined;
|
||||
}
|
||||
visitedSymbolTables.push(symbols);
|
||||
@@ -2285,21 +2285,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string {
|
||||
const writer = getSingleLineStringWriter();
|
||||
getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning);
|
||||
const result = writer.string();
|
||||
releaseStringWriter(writer);
|
||||
|
||||
return result;
|
||||
return usingSingleLineStringWriter(writer => {
|
||||
getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning);
|
||||
});
|
||||
}
|
||||
|
||||
function signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string {
|
||||
const writer = getSingleLineStringWriter();
|
||||
getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags, kind);
|
||||
const result = writer.string();
|
||||
releaseStringWriter(writer);
|
||||
|
||||
return result;
|
||||
return usingSingleLineStringWriter(writer => {
|
||||
getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags, kind);
|
||||
});
|
||||
}
|
||||
|
||||
function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
|
||||
@@ -2996,12 +2990,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
|
||||
const writer = getSingleLineStringWriter();
|
||||
getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags);
|
||||
const result = writer.string();
|
||||
releaseStringWriter(writer);
|
||||
|
||||
return result;
|
||||
return usingSingleLineStringWriter(writer => {
|
||||
getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags);
|
||||
});
|
||||
}
|
||||
|
||||
function formatUnionTypes(types: Type[]): Type[] {
|
||||
@@ -4239,7 +4230,7 @@ namespace ts {
|
||||
return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
|
||||
}
|
||||
|
||||
if ((noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) &&
|
||||
if ((noImplicitAny || isInJavaScriptFile(declaration)) &&
|
||||
declaration.kind === SyntaxKind.VariableDeclaration && !isBindingPattern(declaration.name) &&
|
||||
!(getCombinedModifierFlags(declaration) & ModifierFlags.Export) && !isInAmbientContext(declaration)) {
|
||||
// If --noImplicitAny is on or the declaration is in a Javascript file,
|
||||
@@ -4493,7 +4484,7 @@ namespace ts {
|
||||
if (declaration.kind === SyntaxKind.ExportAssignment) {
|
||||
return links.type = checkExpression((<ExportAssignment>declaration).expression);
|
||||
}
|
||||
if (declaration.flags & NodeFlags.JavaScriptFile && declaration.kind === SyntaxKind.JSDocPropertyTag && (<JSDocPropertyTag>declaration).typeExpression) {
|
||||
if (isInJavaScriptFile(declaration) && declaration.kind === SyntaxKind.JSDocPropertyTag && (<JSDocPropertyTag>declaration).typeExpression) {
|
||||
return links.type = getTypeFromTypeNode((<JSDocPropertyTag>declaration).typeExpression.type);
|
||||
}
|
||||
// Handle variable, parameter or property
|
||||
@@ -4552,7 +4543,7 @@ namespace ts {
|
||||
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
|
||||
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
|
||||
|
||||
if (getter && getter.flags & NodeFlags.JavaScriptFile) {
|
||||
if (getter && isInJavaScriptFile(getter)) {
|
||||
const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
|
||||
if (jsDocType) {
|
||||
return links.type = jsDocType;
|
||||
@@ -6206,7 +6197,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isJSDocOptionalParameter(node: ParameterDeclaration) {
|
||||
if (node.flags & NodeFlags.JavaScriptFile) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
if (node.type && node.type.kind === SyntaxKind.JSDocOptionalType) {
|
||||
return true;
|
||||
}
|
||||
@@ -6892,6 +6883,7 @@ namespace ts {
|
||||
case "Null":
|
||||
return nullType;
|
||||
case "Object":
|
||||
case "object":
|
||||
return anyType;
|
||||
case "Function":
|
||||
case "function":
|
||||
@@ -11065,8 +11057,14 @@ namespace ts {
|
||||
if (!links.switchTypes) {
|
||||
// If all case clauses specify expressions that have unit types, we return an array
|
||||
// of those unit types. Otherwise we return an empty array.
|
||||
const types = map(switchStatement.caseBlock.clauses, getTypeOfSwitchClause);
|
||||
links.switchTypes = !contains(types, undefined) ? types : emptyArray;
|
||||
links.switchTypes = [];
|
||||
for (const clause of switchStatement.caseBlock.clauses) {
|
||||
const type = getTypeOfSwitchClause(clause);
|
||||
if (type === undefined) {
|
||||
return links.switchTypes = emptyArray;
|
||||
}
|
||||
links.switchTypes.push(type);
|
||||
}
|
||||
}
|
||||
return links.switchTypes;
|
||||
}
|
||||
@@ -11875,6 +11873,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getTypeOfSymbolAtLocation(symbol: Symbol, location: Node) {
|
||||
symbol = symbol.exportSymbol || symbol;
|
||||
|
||||
// If we have an identifier or a property access at the given location, if the location is
|
||||
// an dotted name expression, and if the location is not an assignment target, obtain the type
|
||||
// of the expression (which will reflect control flow analysis). If the expression indeed
|
||||
@@ -18800,7 +18800,7 @@ namespace ts {
|
||||
// local symbol is undefined => this declaration is non-exported.
|
||||
// however symbol might contain other declarations that are exported
|
||||
symbol = getSymbolOfNode(node);
|
||||
if (!(symbol.flags & SymbolFlags.Export)) {
|
||||
if (!symbol.exportSymbol) {
|
||||
// this is a pure local symbol (all declarations are non-exported) - no need to check anything
|
||||
return;
|
||||
}
|
||||
@@ -18811,11 +18811,9 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
// we use SymbolFlags.ExportValue, SymbolFlags.ExportType and SymbolFlags.ExportNamespace
|
||||
// to denote disjoint declarationSpaces (without making new enum type).
|
||||
let exportedDeclarationSpaces = SymbolFlags.None;
|
||||
let nonExportedDeclarationSpaces = SymbolFlags.None;
|
||||
let defaultExportedDeclarationSpaces = SymbolFlags.None;
|
||||
let exportedDeclarationSpaces = DeclarationSpaces.None;
|
||||
let nonExportedDeclarationSpaces = DeclarationSpaces.None;
|
||||
let defaultExportedDeclarationSpaces = DeclarationSpaces.None;
|
||||
for (const d of symbol.declarations) {
|
||||
const declarationSpaces = getDeclarationSpaces(d);
|
||||
const effectiveDeclarationFlags = getEffectiveDeclarationFlags(d, ModifierFlags.Export | ModifierFlags.Default);
|
||||
@@ -18855,24 +18853,36 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getDeclarationSpaces(d: Declaration): SymbolFlags {
|
||||
const enum DeclarationSpaces {
|
||||
None = 0,
|
||||
ExportValue = 1 << 0,
|
||||
ExportType = 1 << 1,
|
||||
ExportNamespace = 1 << 2,
|
||||
}
|
||||
function getDeclarationSpaces(d: Declaration): DeclarationSpaces {
|
||||
switch (d.kind) {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return SymbolFlags.ExportType;
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return DeclarationSpaces.ExportType;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return isAmbientModule(d) || getModuleInstanceState(d) !== ModuleInstanceState.NonInstantiated
|
||||
? SymbolFlags.ExportNamespace | SymbolFlags.ExportValue
|
||||
: SymbolFlags.ExportNamespace;
|
||||
? DeclarationSpaces.ExportNamespace | DeclarationSpaces.ExportValue
|
||||
: DeclarationSpaces.ExportNamespace;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return SymbolFlags.ExportType | SymbolFlags.ExportValue;
|
||||
return DeclarationSpaces.ExportType | DeclarationSpaces.ExportValue;
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
let result: SymbolFlags = 0;
|
||||
let result = DeclarationSpaces.None;
|
||||
const target = resolveAlias(getSymbolOfNode(d));
|
||||
forEach(target.declarations, d => { result |= getDeclarationSpaces(d); });
|
||||
return result;
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ImportSpecifier: // https://github.com/Microsoft/TypeScript/pull/7591
|
||||
return DeclarationSpaces.ExportValue;
|
||||
default:
|
||||
return SymbolFlags.ExportValue;
|
||||
Debug.fail((ts as any).SyntaxKind[d.kind]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20909,7 +20919,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function areTypeParametersIdentical(declarations: (ClassDeclaration | InterfaceDeclaration)[], typeParameters: TypeParameter[]) {
|
||||
function areTypeParametersIdentical(declarations: ReadonlyArray<ClassDeclaration | InterfaceDeclaration>, typeParameters: TypeParameter[]) {
|
||||
const maxTypeArgumentCount = length(typeParameters);
|
||||
const minTypeArgumentCount = getMinTypeArgumentCount(typeParameters);
|
||||
|
||||
@@ -22281,11 +22291,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
switch (location.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
if (!isExternalOrCommonJsModule(<SourceFile>location)) {
|
||||
break;
|
||||
}
|
||||
// falls through
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember);
|
||||
break;
|
||||
@@ -22337,7 +22342,7 @@ namespace ts {
|
||||
* @param meaning meaning of symbol to filter by before adding to symbol table
|
||||
*/
|
||||
function copySymbol(symbol: Symbol, meaning: SymbolFlags): void {
|
||||
if (symbol.flags & meaning) {
|
||||
if (getCombinedLocalAndExportSymbolFlags(symbol) & meaning) {
|
||||
const id = symbol.name;
|
||||
// We will copy all symbol regardless of its reserved name because
|
||||
// symbolsToArray will check whether the key is a reserved name and
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace ts {
|
||||
paramType: Diagnostics.KIND,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_es2015_or_ESNext,
|
||||
description: Diagnostics.Specify_module_code_generation_Colon_none_commonjs_amd_system_umd_es2015_or_ESNext,
|
||||
},
|
||||
{
|
||||
name: "lib",
|
||||
@@ -2162,7 +2162,7 @@ namespace ts {
|
||||
* @param extensionPriority The priority of the extension.
|
||||
* @param context The expansion context.
|
||||
*/
|
||||
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
|
||||
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: ReadonlyArray<string>, keyMapper: (value: string) => string) {
|
||||
const extensionPriority = getExtensionPriority(file, extensions);
|
||||
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority, extensions);
|
||||
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
|
||||
@@ -2184,7 +2184,7 @@ namespace ts {
|
||||
* @param extensionPriority The priority of the extension.
|
||||
* @param context The expansion context.
|
||||
*/
|
||||
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
|
||||
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: ReadonlyArray<string>, keyMapper: (value: string) => string) {
|
||||
const extensionPriority = getExtensionPriority(file, extensions);
|
||||
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority, extensions);
|
||||
for (let i = nextExtensionPriority; i < extensions.length; i++) {
|
||||
|
||||
+94
-69
@@ -53,7 +53,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createSymbolTable(symbols?: Symbol[]): SymbolTable {
|
||||
export function createSymbolTable(symbols?: ReadonlyArray<Symbol>): SymbolTable {
|
||||
const result = createMap<Symbol>() as SymbolTable;
|
||||
if (symbols) {
|
||||
for (const symbol of symbols) {
|
||||
@@ -88,7 +88,7 @@ namespace ts {
|
||||
|
||||
class MapIterator<T, U extends (string | T | [string, T])> {
|
||||
private data: MapLike<T>;
|
||||
private keys: string[];
|
||||
private keys: ReadonlyArray<string>;
|
||||
private index = 0;
|
||||
private selector: (data: MapLike<T>, key: string) => U;
|
||||
constructor(data: MapLike<T>, selector: (data: MapLike<T>, key: string) => U) {
|
||||
@@ -175,7 +175,7 @@ namespace ts {
|
||||
GreaterThan = 1
|
||||
}
|
||||
|
||||
export function length(array: any[]) {
|
||||
export function length(array: ReadonlyArray<any>) {
|
||||
return array ? array.length : 0;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace ts {
|
||||
* returns a truthy value, then returns that value.
|
||||
* If no such value is found, the callback is applied to each element of array and undefined is returned.
|
||||
*/
|
||||
export function forEach<T, U>(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
|
||||
export function forEach<T, U>(array: ReadonlyArray<T> | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const result = callback(array[i], i);
|
||||
@@ -217,14 +217,14 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function zipWith<T, U>(arrayA: T[], arrayB: U[], callback: (a: T, b: U, index: number) => void): void {
|
||||
export function zipWith<T, U>(arrayA: ReadonlyArray<T>, arrayB: ReadonlyArray<U>, callback: (a: T, b: U, index: number) => void): void {
|
||||
Debug.assert(arrayA.length === arrayB.length);
|
||||
for (let i = 0; i < arrayA.length; i++) {
|
||||
callback(arrayA[i], arrayB[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
export function zipToMap<T>(keys: string[], values: T[]): Map<T> {
|
||||
export function zipToMap<T>(keys: ReadonlyArray<string>, values: ReadonlyArray<T>): Map<T> {
|
||||
Debug.assert(keys.length === values.length);
|
||||
const map = createMap<T>();
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
@@ -238,7 +238,7 @@ namespace ts {
|
||||
* returns a falsey value, then returns false.
|
||||
* If no such value is found, the callback is applied to each element of array and `true` is returned.
|
||||
*/
|
||||
export function every<T>(array: T[], callback: (element: T, index: number) => boolean): boolean {
|
||||
export function every<T>(array: ReadonlyArray<T>, callback: (element: T, index: number) => boolean): boolean {
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (!callback(array[i], i)) {
|
||||
@@ -251,7 +251,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Works like Array.prototype.find, returning `undefined` if no element satisfying the predicate is found. */
|
||||
export function find<T>(array: T[], predicate: (element: T, index: number) => boolean): T | undefined {
|
||||
export function find<T>(array: ReadonlyArray<T>, predicate: (element: T, index: number) => boolean): T | undefined {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const value = array[i];
|
||||
if (predicate(value, i)) {
|
||||
@@ -262,7 +262,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Works like Array.prototype.findIndex, returning `-1` if no element satisfying the predicate is found. */
|
||||
export function findIndex<T>(array: T[], predicate: (element: T, index: number) => boolean): number {
|
||||
export function findIndex<T>(array: ReadonlyArray<T>, predicate: (element: T, index: number) => boolean): number {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (predicate(array[i], i)) {
|
||||
return i;
|
||||
@@ -275,7 +275,7 @@ namespace ts {
|
||||
* Returns the first truthy result of `callback`, or else fails.
|
||||
* This is like `forEach`, but never returns undefined.
|
||||
*/
|
||||
export function findMap<T, U>(array: T[], callback: (element: T, index: number) => U | undefined): U {
|
||||
export function findMap<T, U>(array: ReadonlyArray<T>, callback: (element: T, index: number) => U | undefined): U {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const result = callback(array[i], i);
|
||||
if (result) {
|
||||
@@ -285,7 +285,7 @@ namespace ts {
|
||||
Debug.fail();
|
||||
}
|
||||
|
||||
export function contains<T>(array: T[], value: T): boolean {
|
||||
export function contains<T>(array: ReadonlyArray<T>, value: T): boolean {
|
||||
if (array) {
|
||||
for (const v of array) {
|
||||
if (v === value) {
|
||||
@@ -296,7 +296,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function indexOf<T>(array: T[], value: T): number {
|
||||
export function indexOf<T>(array: ReadonlyArray<T>, value: T): number {
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (array[i] === value) {
|
||||
@@ -307,7 +307,7 @@ namespace ts {
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function indexOfAnyCharCode(text: string, charCodes: number[], start?: number): number {
|
||||
export function indexOfAnyCharCode(text: string, charCodes: ReadonlyArray<number>, start?: number): number {
|
||||
for (let i = start || 0; i < text.length; i++) {
|
||||
if (contains(charCodes, text.charCodeAt(i))) {
|
||||
return i;
|
||||
@@ -316,7 +316,7 @@ namespace ts {
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function countWhere<T>(array: T[], predicate: (x: T, i: number) => boolean): number {
|
||||
export function countWhere<T>(array: ReadonlyArray<T>, predicate: (x: T, i: number) => boolean): number {
|
||||
let count = 0;
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
@@ -335,6 +335,8 @@ namespace ts {
|
||||
*/
|
||||
export function filter<T, U extends T>(array: T[], f: (x: T) => x is U): U[];
|
||||
export function filter<T>(array: T[], f: (x: T) => boolean): T[];
|
||||
export function filter<T, U extends T>(array: ReadonlyArray<T>, f: (x: T) => x is U): ReadonlyArray<U>;
|
||||
export function filter<T, U extends T>(array: ReadonlyArray<T>, f: (x: T) => boolean): ReadonlyArray<T>;
|
||||
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
|
||||
if (array) {
|
||||
const len = array.length;
|
||||
@@ -382,7 +384,7 @@ namespace ts {
|
||||
array.length = outIndex;
|
||||
}
|
||||
|
||||
export function map<T, U>(array: T[], f: (x: T, i: number) => U): U[] {
|
||||
export function map<T, U>(array: ReadonlyArray<T>, f: (x: T, i: number) => U): U[] {
|
||||
let result: U[];
|
||||
if (array) {
|
||||
result = [];
|
||||
@@ -394,6 +396,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Maps from T to T and avoids allocation if all elements map to themselves
|
||||
export function sameMap<T>(array: T[], f: (x: T, i: number) => T): T[];
|
||||
export function sameMap<T>(array: ReadonlyArray<T>, f: (x: T, i: number) => T): ReadonlyArray<T>;
|
||||
export function sameMap<T>(array: T[], f: (x: T, i: number) => T): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
@@ -419,7 +423,7 @@ namespace ts {
|
||||
*
|
||||
* @param array The array to flatten.
|
||||
*/
|
||||
export function flatten<T>(array: (T | T[])[]): T[] {
|
||||
export function flatten<T>(array: ReadonlyArray<T | ReadonlyArray<T>>): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
result = [];
|
||||
@@ -444,7 +448,7 @@ namespace ts {
|
||||
* @param array The array to map.
|
||||
* @param mapfn The callback used to map the result into one or more values.
|
||||
*/
|
||||
export function flatMap<T, U>(array: T[] | undefined, mapfn: (x: T, i: number) => U | U[] | undefined): U[] | undefined {
|
||||
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] | undefined {
|
||||
let result: U[];
|
||||
if (array) {
|
||||
result = [];
|
||||
@@ -463,6 +467,17 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function flatMapIter<T, U>(iter: Iterator<T>, mapfn: (x: T) => U[] | undefined): U[] {
|
||||
const result: U[] = [];
|
||||
while (true) {
|
||||
const { value, done } = iter.next();
|
||||
if (done) break;
|
||||
const res = mapfn(value);
|
||||
if (res) result.push(...res);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an array. If the mapped value is an array, it is spread into the result.
|
||||
* Avoids allocation if all elements map to themselves.
|
||||
@@ -470,6 +485,8 @@ namespace ts {
|
||||
* @param array The array to map.
|
||||
* @param mapfn The callback used to map the result into one or more values.
|
||||
*/
|
||||
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | ReadonlyArray<T>): T[];
|
||||
export function sameFlatMap<T>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => T | ReadonlyArray<T>): ReadonlyArray<T>;
|
||||
export function sameFlatMap<T>(array: T[], mapfn: (x: T, i: number) => T | T[]): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
@@ -508,7 +525,7 @@ namespace ts {
|
||||
* Computes the first matching span of elements and returns a tuple of the first span
|
||||
* and the remaining elements.
|
||||
*/
|
||||
export function span<T>(array: T[], f: (x: T, i: number) => boolean): [T[], T[]] {
|
||||
export function span<T>(array: ReadonlyArray<T>, f: (x: T, i: number) => boolean): [T[], T[]] {
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (!f(array[i], i)) {
|
||||
@@ -528,7 +545,7 @@ namespace ts {
|
||||
* @param keyfn A callback used to select the key for an element.
|
||||
* @param mapfn A callback used to map a contiguous chunk of values to a single value.
|
||||
*/
|
||||
export function spanMap<T, K, U>(array: T[], keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] {
|
||||
export function spanMap<T, K, U>(array: ReadonlyArray<T>, keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] {
|
||||
let result: U[];
|
||||
if (array) {
|
||||
result = [];
|
||||
@@ -581,7 +598,7 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function some<T>(array: T[], predicate?: (value: T) => boolean): boolean {
|
||||
export function some<T>(array: ReadonlyArray<T>, predicate?: (value: T) => boolean): boolean {
|
||||
if (array) {
|
||||
if (predicate) {
|
||||
for (const v of array) {
|
||||
@@ -597,6 +614,8 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function concatenate<T>(array1: T[], array2: T[]): T[];
|
||||
export function concatenate<T>(array1: ReadonlyArray<T>, array2: ReadonlyArray<T>): ReadonlyArray<T>;
|
||||
export function concatenate<T>(array1: T[], array2: T[]): T[] {
|
||||
if (!some(array2)) return array1;
|
||||
if (!some(array1)) return array2;
|
||||
@@ -604,7 +623,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// TODO: fixme (N^2) - add optional comparer so collection can be sorted before deduplication.
|
||||
export function deduplicate<T>(array: T[], areEqual?: (a: T, b: T) => boolean): T[] {
|
||||
export function deduplicate<T>(array: ReadonlyArray<T>, areEqual?: (a: T, b: T) => boolean): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
result = [];
|
||||
@@ -661,6 +680,8 @@ namespace ts {
|
||||
/**
|
||||
* Compacts an array, removing any falsey elements.
|
||||
*/
|
||||
export function compact<T>(array: T[]): T[];
|
||||
export function compact<T>(array: ReadonlyArray<T>): ReadonlyArray<T>;
|
||||
export function compact<T>(array: T[]): T[] {
|
||||
let result: T[];
|
||||
if (array) {
|
||||
@@ -700,10 +721,11 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function sum(array: any[], prop: string): number {
|
||||
export function sum<T extends Record<K, number>, K extends string>(array: T[], prop: K): number {
|
||||
let result = 0;
|
||||
for (const v of array) {
|
||||
result += v[prop];
|
||||
// Note: we need the following type assertion because of GH #17069
|
||||
result += v[prop] as number;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -727,7 +749,7 @@ namespace ts {
|
||||
* Gets the actual offset into an array for a relative offset. Negative offsets indicate a
|
||||
* position offset from the end of the array.
|
||||
*/
|
||||
function toOffset(array: any[], offset: number) {
|
||||
function toOffset(array: ReadonlyArray<any>, offset: number) {
|
||||
return offset < 0 ? array.length + offset : offset;
|
||||
}
|
||||
|
||||
@@ -741,7 +763,7 @@ namespace ts {
|
||||
* @param start The offset in `from` at which to start copying values.
|
||||
* @param end The offset in `from` at which to stop copying values (non-inclusive).
|
||||
*/
|
||||
export function addRange<T>(to: T[] | undefined, from: T[] | undefined, start?: number, end?: number): T[] | undefined {
|
||||
export function addRange<T>(to: T[] | undefined, from: ReadonlyArray<T> | undefined, start?: number, end?: number): T[] | undefined {
|
||||
if (from === undefined) return to;
|
||||
if (to === undefined) return from.slice(start, end);
|
||||
start = start === undefined ? 0 : toOffset(from, start);
|
||||
@@ -758,14 +780,14 @@ namespace ts {
|
||||
/**
|
||||
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
|
||||
*/
|
||||
export function stableSort<T>(array: T[], comparer: (x: T, y: T) => Comparison = compareValues) {
|
||||
export function stableSort<T>(array: ReadonlyArray<T>, comparer: (x: T, y: T) => Comparison = compareValues) {
|
||||
return array
|
||||
.map((_, i) => i) // create array of indices
|
||||
.sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y)) // sort indices by value then position
|
||||
.map(i => array[i]); // get sorted array
|
||||
}
|
||||
|
||||
export function rangeEquals<T>(array1: T[], array2: T[], pos: number, end: number) {
|
||||
export function rangeEquals<T>(array1: ReadonlyArray<T>, array2: ReadonlyArray<T>, pos: number, end: number) {
|
||||
while (pos < end) {
|
||||
if (array1[pos] !== array2[pos]) {
|
||||
return false;
|
||||
@@ -779,7 +801,7 @@ namespace ts {
|
||||
* Returns the element at a specific offset in an array if non-empty, `undefined` otherwise.
|
||||
* A negative offset indicates the element should be retrieved from the end of the array.
|
||||
*/
|
||||
export function elementAt<T>(array: T[] | undefined, offset: number): T | undefined {
|
||||
export function elementAt<T>(array: ReadonlyArray<T> | undefined, offset: number): T | undefined {
|
||||
if (array) {
|
||||
offset = toOffset(array, offset);
|
||||
if (offset < array.length) {
|
||||
@@ -792,21 +814,21 @@ namespace ts {
|
||||
/**
|
||||
* Returns the first element of an array if non-empty, `undefined` otherwise.
|
||||
*/
|
||||
export function firstOrUndefined<T>(array: T[]): T | undefined {
|
||||
export function firstOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
|
||||
return elementAt(array, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element of an array if non-empty, `undefined` otherwise.
|
||||
*/
|
||||
export function lastOrUndefined<T>(array: T[]): T | undefined {
|
||||
export function lastOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
|
||||
return elementAt(array, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the only element of an array if it contains only one element, `undefined` otherwise.
|
||||
*/
|
||||
export function singleOrUndefined<T>(array: T[]): T | undefined {
|
||||
export function singleOrUndefined<T>(array: ReadonlyArray<T>): T | undefined {
|
||||
return array && array.length === 1
|
||||
? array[0]
|
||||
: undefined;
|
||||
@@ -816,13 +838,15 @@ namespace ts {
|
||||
* Returns the only element of an array if it contains only one element; otheriwse, returns the
|
||||
* array.
|
||||
*/
|
||||
export function singleOrMany<T>(array: T[]): T | T[];
|
||||
export function singleOrMany<T>(array: ReadonlyArray<T>): T | ReadonlyArray<T>;
|
||||
export function singleOrMany<T>(array: T[]): T | T[] {
|
||||
return array && array.length === 1
|
||||
? array[0]
|
||||
: array;
|
||||
}
|
||||
|
||||
export function replaceElement<T>(array: T[], index: number, value: T): T[] {
|
||||
export function replaceElement<T>(array: ReadonlyArray<T>, index: number, value: T): T[] {
|
||||
const result = array.slice(0);
|
||||
result[index] = value;
|
||||
return result;
|
||||
@@ -835,7 +859,7 @@ namespace ts {
|
||||
* @param array A sorted array whose first element must be no larger than number
|
||||
* @param number The value to be searched for in the array.
|
||||
*/
|
||||
export function binarySearch<T>(array: T[], value: T, comparer?: (v1: T, v2: T) => number, offset?: number): number {
|
||||
export function binarySearch<T>(array: ReadonlyArray<T>, value: T, comparer?: (v1: T, v2: T) => number, offset?: number): number {
|
||||
if (!array || array.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -864,8 +888,8 @@ namespace ts {
|
||||
return ~low;
|
||||
}
|
||||
|
||||
export function reduceLeft<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
|
||||
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
|
||||
export function reduceLeft<T, U>(array: ReadonlyArray<T>, f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
|
||||
export function reduceLeft<T>(array: ReadonlyArray<T>, f: (memo: T, value: T, i: number) => T): T;
|
||||
export function reduceLeft<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T {
|
||||
if (array && array.length > 0) {
|
||||
const size = array.length;
|
||||
@@ -890,8 +914,8 @@ namespace ts {
|
||||
return initial;
|
||||
}
|
||||
|
||||
export function reduceRight<T, U>(array: T[], f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
|
||||
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T): T;
|
||||
export function reduceRight<T, U>(array: ReadonlyArray<T>, f: (memo: U, value: T, i: number) => U, initial: U, start?: number, count?: number): U;
|
||||
export function reduceRight<T>(array: ReadonlyArray<T>, f: (memo: T, value: T, i: number) => T): T;
|
||||
export function reduceRight<T>(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T {
|
||||
if (array) {
|
||||
const size = array.length;
|
||||
@@ -1058,9 +1082,9 @@ namespace ts {
|
||||
* the same key with the given 'makeKey' function, then the element with the higher
|
||||
* index in the array will be the one associated with the produced key.
|
||||
*/
|
||||
export function arrayToMap<T>(array: T[], makeKey: (value: T) => string): Map<T>;
|
||||
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue: (value: T) => U): Map<U>;
|
||||
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue?: (value: T) => U): Map<T | U> {
|
||||
export function arrayToMap<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string): Map<T>;
|
||||
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string, makeValue: (value: T) => U): Map<U>;
|
||||
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string, makeValue?: (value: T) => U): Map<T | U> {
|
||||
const result = createMap<T | U>();
|
||||
for (const value of array) {
|
||||
result.set(makeKey(value), makeValue ? makeValue(value) : value);
|
||||
@@ -1073,9 +1097,9 @@ namespace ts {
|
||||
*
|
||||
* @param array the array of input elements.
|
||||
*/
|
||||
export function arrayToSet(array: string[]): Map<true>;
|
||||
export function arrayToSet<T>(array: T[], makeKey: (value: T) => string): Map<true>;
|
||||
export function arrayToSet(array: any[], makeKey?: (value: any) => string): Map<true> {
|
||||
export function arrayToSet(array: ReadonlyArray<string>): Map<true>;
|
||||
export function arrayToSet<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string): Map<true>;
|
||||
export function arrayToSet(array: ReadonlyArray<any>, makeKey?: (value: any) => string): Map<true> {
|
||||
return arrayToMap<any, true>(array, makeKey || (s => s), () => true);
|
||||
}
|
||||
|
||||
@@ -1158,7 +1182,7 @@ namespace ts {
|
||||
/**
|
||||
* Tests whether a value is an array.
|
||||
*/
|
||||
export function isArray(value: any): value is any[] {
|
||||
export function isArray(value: any): value is ReadonlyArray<any> {
|
||||
return Array.isArray ? Array.isArray(value) : value instanceof Array;
|
||||
}
|
||||
|
||||
@@ -1628,7 +1652,7 @@ namespace ts {
|
||||
return getNormalizedPathFromPathComponents(getNormalizedPathComponents(fileName, currentDirectory));
|
||||
}
|
||||
|
||||
export function getNormalizedPathFromPathComponents(pathComponents: string[]) {
|
||||
export function getNormalizedPathFromPathComponents(pathComponents: ReadonlyArray<string>) {
|
||||
if (pathComponents && pathComponents.length) {
|
||||
return pathComponents[0] + pathComponents.slice(1).join(directorySeparator);
|
||||
}
|
||||
@@ -1830,7 +1854,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function fileExtensionIsOneOf(path: string, extensions: string[]): boolean {
|
||||
export function fileExtensionIsOneOf(path: string, extensions: ReadonlyArray<string>): boolean {
|
||||
for (const extension of extensions) {
|
||||
if (fileExtensionIs(path, extension)) {
|
||||
return true;
|
||||
@@ -1855,7 +1879,7 @@ namespace ts {
|
||||
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
|
||||
const singleAsteriskRegexFragmentOther = "[^/]*";
|
||||
|
||||
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
|
||||
export function getRegularExpressionForWildcard(specs: ReadonlyArray<string>, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
|
||||
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
|
||||
if (!patterns || !patterns.length) {
|
||||
return undefined;
|
||||
@@ -1867,7 +1891,7 @@ namespace ts {
|
||||
return `^(${pattern})${terminator}`;
|
||||
}
|
||||
|
||||
function getRegularExpressionsForWildcards(specs: string[], basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
|
||||
function getRegularExpressionsForWildcards(specs: ReadonlyArray<string>, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
|
||||
if (specs === undefined || specs.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1972,21 +1996,21 @@ namespace ts {
|
||||
}
|
||||
|
||||
export interface FileSystemEntries {
|
||||
files: string[];
|
||||
directories: string[];
|
||||
files: ReadonlyArray<string>;
|
||||
directories: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
export interface FileMatcherPatterns {
|
||||
/** One pattern for each "include" spec. */
|
||||
includeFilePatterns: string[];
|
||||
includeFilePatterns: ReadonlyArray<string>;
|
||||
/** One pattern matching one of any of the "include" specs. */
|
||||
includeFilePattern: string;
|
||||
includeDirectoryPattern: string;
|
||||
excludePattern: string;
|
||||
basePaths: string[];
|
||||
basePaths: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
export function getFileMatcherPatterns(path: string, excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
|
||||
export function getFileMatcherPatterns(path: string, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
const absolutePath = combinePaths(currentDirectory, path);
|
||||
@@ -2000,7 +2024,7 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function matchFiles(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
|
||||
export function matchFiles(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
|
||||
@@ -2020,7 +2044,7 @@ namespace ts {
|
||||
visitDirectory(basePath, combinePaths(currentDirectory, basePath), depth);
|
||||
}
|
||||
|
||||
return flatten(results);
|
||||
return flatten<string>(results);
|
||||
|
||||
function visitDirectory(path: string, absolutePath: string, depth: number | undefined) {
|
||||
let { files, directories } = getFileSystemEntries(path);
|
||||
@@ -2064,7 +2088,7 @@ namespace ts {
|
||||
/**
|
||||
* Computes the unique non-wildcard base paths amongst the provided include patterns.
|
||||
*/
|
||||
function getBasePaths(path: string, includes: string[], useCaseSensitiveFileNames: boolean) {
|
||||
function getBasePaths(path: string, includes: ReadonlyArray<string>, useCaseSensitiveFileNames: boolean) {
|
||||
// Storage for our results in the form of literal paths (e.g. the paths as written by the user).
|
||||
const basePaths: string[] = [path];
|
||||
|
||||
@@ -2136,13 +2160,13 @@ namespace ts {
|
||||
/**
|
||||
* List of supported extensions in order of file resolution precedence.
|
||||
*/
|
||||
export const supportedTypeScriptExtensions = [Extension.Ts, Extension.Tsx, Extension.Dts];
|
||||
export const supportedTypeScriptExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
|
||||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions = [Extension.Js, Extension.Jsx];
|
||||
const allSupportedExtensions = supportedTypeScriptExtensions.concat(supportedJavascriptExtensions);
|
||||
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
const allSupportedExtensions = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: JsFileExtensionInfo[]): string[] {
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>): ReadonlyArray<string> {
|
||||
const needAllExtensions = options && options.allowJs;
|
||||
if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) {
|
||||
return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
|
||||
@@ -2164,7 +2188,7 @@ namespace ts {
|
||||
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: JsFileExtensionInfo[]) {
|
||||
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>) {
|
||||
if (!fileName) { return false; }
|
||||
|
||||
for (const extension of getSupportedExtensions(compilerOptions, extraFileExtensions)) {
|
||||
@@ -2188,7 +2212,7 @@ namespace ts {
|
||||
Lowest = DeclarationAndJavaScriptFiles,
|
||||
}
|
||||
|
||||
export function getExtensionPriority(path: string, supportedExtensions: string[]): ExtensionPriority {
|
||||
export function getExtensionPriority(path: string, supportedExtensions: ReadonlyArray<string>): ExtensionPriority {
|
||||
for (let i = supportedExtensions.length - 1; i >= 0; i--) {
|
||||
if (fileExtensionIs(path, supportedExtensions[i])) {
|
||||
return adjustExtensionPriority(<ExtensionPriority>i, supportedExtensions);
|
||||
@@ -2203,7 +2227,7 @@ namespace ts {
|
||||
/**
|
||||
* Adjusts an extension priority to be the highest priority within the same range.
|
||||
*/
|
||||
export function adjustExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: string[]): ExtensionPriority {
|
||||
export function adjustExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: ReadonlyArray<string>): ExtensionPriority {
|
||||
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
|
||||
return ExtensionPriority.TypeScriptFiles;
|
||||
}
|
||||
@@ -2212,12 +2236,13 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
return supportedExtensions.length;
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next lowest extension priority for a given priority.
|
||||
*/
|
||||
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: string[]): ExtensionPriority {
|
||||
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority, supportedExtensions: ReadonlyArray<string>): ExtensionPriority {
|
||||
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
|
||||
return ExtensionPriority.DeclarationAndJavaScriptFiles;
|
||||
}
|
||||
@@ -2406,7 +2431,7 @@ namespace ts {
|
||||
* (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.)
|
||||
*/
|
||||
/* @internal */
|
||||
export function matchPatternOrExact(patternStrings: string[], candidate: string): string | Pattern | undefined {
|
||||
export function matchPatternOrExact(patternStrings: ReadonlyArray<string>, candidate: string): string | Pattern | undefined {
|
||||
const patterns: Pattern[] = [];
|
||||
for (const patternString of patternStrings) {
|
||||
const pattern = tryParsePattern(patternString);
|
||||
@@ -2439,7 +2464,7 @@ namespace ts {
|
||||
|
||||
/** Return the object corresponding to the best pattern to match `candidate`. */
|
||||
/* @internal */
|
||||
export function findBestPatternMatch<T>(values: T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined {
|
||||
export function findBestPatternMatch<T>(values: ReadonlyArray<T>, getPattern: (value: T) => Pattern, candidate: string): T | undefined {
|
||||
let matchedValue: T | undefined = undefined;
|
||||
// use length of prefix as betterness criteria
|
||||
let longestMatchPrefixLength = -1;
|
||||
@@ -2495,7 +2520,7 @@ namespace ts {
|
||||
Debug.fail(`File ${path} has unknown extension.`);
|
||||
}
|
||||
export function tryGetExtensionFromPath(path: string): Extension | undefined {
|
||||
return find(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e));
|
||||
return find<Extension>(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e));
|
||||
}
|
||||
|
||||
export function isCheckJsEnabledForFile(sourceFile: SourceFile, compilerOptions: CompilerOptions) {
|
||||
|
||||
@@ -2658,7 +2658,7 @@
|
||||
"category": "Message",
|
||||
"code": 6015
|
||||
},
|
||||
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
|
||||
"Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.": {
|
||||
"category": "Message",
|
||||
"code": 6016
|
||||
},
|
||||
|
||||
+57
-41
@@ -2,6 +2,15 @@
|
||||
/// <reference path="scanner.ts"/>
|
||||
|
||||
namespace ts {
|
||||
const enum SignatureFlags {
|
||||
None = 0,
|
||||
Yield = 1 << 0,
|
||||
Await = 1 << 1,
|
||||
Type = 1 << 2,
|
||||
RequireCompleteParameterList = 1 << 3,
|
||||
IgnoreMissingOpenBrace = 1 << 4,
|
||||
}
|
||||
|
||||
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
|
||||
@@ -2218,15 +2227,12 @@ namespace ts {
|
||||
|
||||
function fillSignature(
|
||||
returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
|
||||
yieldContext: boolean,
|
||||
awaitContext: boolean,
|
||||
requireCompleteParameterList: boolean,
|
||||
flags: SignatureFlags,
|
||||
signature: SignatureDeclaration): void {
|
||||
signature.typeParameters = parseTypeParameters();
|
||||
signature.parameters = parseParameterList(flags);
|
||||
|
||||
const returnTokenRequired = returnToken === SyntaxKind.EqualsGreaterThanToken;
|
||||
signature.typeParameters = parseTypeParameters();
|
||||
signature.parameters = parseParameterList(yieldContext, awaitContext, requireCompleteParameterList);
|
||||
|
||||
if (returnTokenRequired) {
|
||||
parseExpected(returnToken);
|
||||
signature.type = parseTypeOrTypePredicate();
|
||||
@@ -2234,9 +2240,19 @@ namespace ts {
|
||||
else if (parseOptional(returnToken)) {
|
||||
signature.type = parseTypeOrTypePredicate();
|
||||
}
|
||||
else if (flags & SignatureFlags.Type) {
|
||||
const start = scanner.getTokenPos();
|
||||
const length = scanner.getTextPos() - start;
|
||||
const backwardToken = parseOptional(returnToken === SyntaxKind.ColonToken ? SyntaxKind.EqualsGreaterThanToken : SyntaxKind.ColonToken);
|
||||
if (backwardToken) {
|
||||
// This is easy to get backward, especially in type contexts, so parse the type anyway
|
||||
signature.type = parseTypeOrTypePredicate();
|
||||
parseErrorAtPosition(start, length, Diagnostics._0_expected, tokenToString(returnToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseParameterList(yieldContext: boolean, awaitContext: boolean, requireCompleteParameterList: boolean) {
|
||||
function parseParameterList(flags: SignatureFlags) {
|
||||
// FormalParameters [Yield,Await]: (modified)
|
||||
// [empty]
|
||||
// FormalParameterList[?Yield,Await]
|
||||
@@ -2254,15 +2270,15 @@ namespace ts {
|
||||
const savedYieldContext = inYieldContext();
|
||||
const savedAwaitContext = inAwaitContext();
|
||||
|
||||
setYieldContext(yieldContext);
|
||||
setAwaitContext(awaitContext);
|
||||
setYieldContext(!!(flags & SignatureFlags.Yield));
|
||||
setAwaitContext(!!(flags & SignatureFlags.Await));
|
||||
|
||||
const result = parseDelimitedList(ParsingContext.Parameters, parseParameter);
|
||||
|
||||
setYieldContext(savedYieldContext);
|
||||
setAwaitContext(savedAwaitContext);
|
||||
|
||||
if (!parseExpected(SyntaxKind.CloseParenToken) && requireCompleteParameterList) {
|
||||
if (!parseExpected(SyntaxKind.CloseParenToken) && (flags & SignatureFlags.RequireCompleteParameterList)) {
|
||||
// Caller insisted that we had to end with a ) We didn't. So just return
|
||||
// undefined here.
|
||||
return undefined;
|
||||
@@ -2274,7 +2290,7 @@ namespace ts {
|
||||
// We didn't even have an open paren. If the caller requires a complete parameter list,
|
||||
// we definitely can't provide that. However, if they're ok with an incomplete one,
|
||||
// then just return an empty set of parameters.
|
||||
return requireCompleteParameterList ? undefined : createMissingList<ParameterDeclaration>();
|
||||
return (flags & SignatureFlags.RequireCompleteParameterList) ? undefined : createMissingList<ParameterDeclaration>();
|
||||
}
|
||||
|
||||
function parseTypeMemberSemicolon() {
|
||||
@@ -2293,7 +2309,7 @@ namespace ts {
|
||||
if (kind === SyntaxKind.ConstructSignature) {
|
||||
parseExpected(SyntaxKind.NewKeyword);
|
||||
}
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node);
|
||||
fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, node);
|
||||
parseTypeMemberSemicolon();
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
@@ -2383,7 +2399,7 @@ namespace ts {
|
||||
|
||||
// Method signatures don't exist in expression contexts. So they have neither
|
||||
// [Yield] nor [Await]
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, method);
|
||||
fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type, method);
|
||||
parseTypeMemberSemicolon();
|
||||
return addJSDocComment(finishNode(method));
|
||||
}
|
||||
@@ -2527,7 +2543,7 @@ namespace ts {
|
||||
if (kind === SyntaxKind.ConstructorType) {
|
||||
parseExpected(SyntaxKind.NewKeyword);
|
||||
}
|
||||
fillSignature(SyntaxKind.EqualsGreaterThanToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node);
|
||||
fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type, node);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -3254,7 +3270,7 @@ namespace ts {
|
||||
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
|
||||
node.modifiers = parseModifiersForArrowFunction();
|
||||
const isAsync = !!(getModifierFlags(node) & ModifierFlags.Async);
|
||||
const isAsync = (getModifierFlags(node) & ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
|
||||
// Arrow functions are never generators.
|
||||
//
|
||||
@@ -3263,7 +3279,7 @@ namespace ts {
|
||||
// a => (b => c)
|
||||
// And think that "(b =>" was actually a parenthesized arrow function with a missing
|
||||
// close paren.
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ !allowAmbiguity, node);
|
||||
fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? SignatureFlags.None : SignatureFlags.RequireCompleteParameterList), node);
|
||||
|
||||
// If we couldn't get parameters, we definitely could not parse out an arrow function.
|
||||
if (!node.parameters) {
|
||||
@@ -3288,7 +3304,7 @@ namespace ts {
|
||||
|
||||
function parseArrowFunctionExpressionBody(isAsync: boolean): Block | Expression {
|
||||
if (token() === SyntaxKind.OpenBraceToken) {
|
||||
return parseFunctionBlock(/*allowYield*/ false, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false);
|
||||
return parseFunctionBlock(isAsync ? SignatureFlags.Await : SignatureFlags.None);
|
||||
}
|
||||
|
||||
if (token() !== SyntaxKind.SemicolonToken &&
|
||||
@@ -3309,8 +3325,8 @@ namespace ts {
|
||||
// try to recover better. If we don't do this, then the next close curly we see may end
|
||||
// up preemptively closing the containing construct.
|
||||
//
|
||||
// Note: even when 'ignoreMissingOpenBrace' is passed as true, parseBody will still error.
|
||||
return parseFunctionBlock(/*allowYield*/ false, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ true);
|
||||
// Note: even when 'IgnoreMissingOpenBrace' is passed, parseBody will still error.
|
||||
return parseFunctionBlock(SignatureFlags.IgnoreMissingOpenBrace | (isAsync ? SignatureFlags.Await : SignatureFlags.None));
|
||||
}
|
||||
|
||||
return isAsync
|
||||
@@ -4386,16 +4402,16 @@ namespace ts {
|
||||
parseExpected(SyntaxKind.FunctionKeyword);
|
||||
node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
|
||||
|
||||
const isGenerator = !!node.asteriskToken;
|
||||
const isAsync = !!(getModifierFlags(node) & ModifierFlags.Async);
|
||||
const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
|
||||
const isAsync = (getModifierFlags(node) & ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
node.name =
|
||||
isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) :
|
||||
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
|
||||
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
|
||||
parseOptionalIdentifier();
|
||||
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node);
|
||||
node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false);
|
||||
fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node);
|
||||
node.body = parseFunctionBlock(isGenerator | isAsync);
|
||||
|
||||
if (saveDecoratorContext) {
|
||||
setDecoratorContext(/*val*/ true);
|
||||
@@ -4444,12 +4460,12 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseFunctionBlock(allowYield: boolean, allowAwait: boolean, ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block {
|
||||
function parseFunctionBlock(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block {
|
||||
const savedYieldContext = inYieldContext();
|
||||
setYieldContext(allowYield);
|
||||
setYieldContext(!!(flags & SignatureFlags.Yield));
|
||||
|
||||
const savedAwaitContext = inAwaitContext();
|
||||
setAwaitContext(allowAwait);
|
||||
setAwaitContext(!!(flags & SignatureFlags.Await));
|
||||
|
||||
// We may be in a [Decorator] context when parsing a function expression or
|
||||
// arrow function. The body of the function is not in [Decorator] context.
|
||||
@@ -4458,7 +4474,7 @@ namespace ts {
|
||||
setDecoratorContext(/*val*/ false);
|
||||
}
|
||||
|
||||
const block = parseBlock(ignoreMissingOpenBrace, diagnosticMessage);
|
||||
const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage);
|
||||
|
||||
if (saveDecoratorContext) {
|
||||
setDecoratorContext(/*val*/ true);
|
||||
@@ -5005,13 +5021,13 @@ namespace ts {
|
||||
return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral);
|
||||
}
|
||||
|
||||
function parseFunctionBlockOrSemicolon(isGenerator: boolean, isAsync: boolean, diagnosticMessage?: DiagnosticMessage): Block {
|
||||
function parseFunctionBlockOrSemicolon(flags: SignatureFlags, diagnosticMessage?: DiagnosticMessage): Block {
|
||||
if (token() !== SyntaxKind.OpenBraceToken && canParseSemicolon()) {
|
||||
parseSemicolon();
|
||||
return;
|
||||
}
|
||||
|
||||
return parseFunctionBlock(isGenerator, isAsync, /*ignoreMissingOpenBrace*/ false, diagnosticMessage);
|
||||
return parseFunctionBlock(flags, diagnosticMessage);
|
||||
}
|
||||
|
||||
// DECLARATIONS
|
||||
@@ -5146,10 +5162,10 @@ namespace ts {
|
||||
parseExpected(SyntaxKind.FunctionKeyword);
|
||||
node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
|
||||
node.name = hasModifier(node, ModifierFlags.Default) ? parseOptionalIdentifier() : parseIdentifier();
|
||||
const isGenerator = !!node.asteriskToken;
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async);
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node);
|
||||
node.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, Diagnostics.or_expected);
|
||||
const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node);
|
||||
node.body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, Diagnostics.or_expected);
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
|
||||
@@ -5158,8 +5174,8 @@ namespace ts {
|
||||
node.decorators = decorators;
|
||||
node.modifiers = modifiers;
|
||||
parseExpected(SyntaxKind.ConstructorKeyword);
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node);
|
||||
node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false, Diagnostics.or_expected);
|
||||
fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
|
||||
node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected);
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
|
||||
@@ -5170,10 +5186,10 @@ namespace ts {
|
||||
method.asteriskToken = asteriskToken;
|
||||
method.name = name;
|
||||
method.questionToken = questionToken;
|
||||
const isGenerator = !!asteriskToken;
|
||||
const isAsync = hasModifier(method, ModifierFlags.Async);
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, method);
|
||||
method.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, diagnosticMessage);
|
||||
const isGenerator = asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
|
||||
const isAsync = hasModifier(method, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, method);
|
||||
method.body = parseFunctionBlockOrSemicolon(isGenerator | isAsync, diagnosticMessage);
|
||||
return addJSDocComment(finishNode(method));
|
||||
}
|
||||
|
||||
@@ -5226,8 +5242,8 @@ namespace ts {
|
||||
node.decorators = decorators;
|
||||
node.modifiers = modifiers;
|
||||
node.name = parsePropertyName();
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node);
|
||||
node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false);
|
||||
fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node);
|
||||
node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None);
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ namespace ts {
|
||||
let moduleResolutionCache: ModuleResolutionCache;
|
||||
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[];
|
||||
if (host.resolveModuleNames) {
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(resolved => {
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile).map(resolved => {
|
||||
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
|
||||
if (!resolved || (resolved as ResolvedModuleFull).extension !== undefined) {
|
||||
return resolved as ResolvedModuleFull;
|
||||
@@ -460,16 +460,16 @@ namespace ts {
|
||||
else {
|
||||
moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x));
|
||||
const loader = (moduleName: string, containingFile: string) => resolveModuleName(moduleName, containingFile, options, host, moduleResolutionCache).resolvedModule;
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => loadWithLocalCache(moduleNames, containingFile, loader);
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => loadWithLocalCache(checkAllDefined(moduleNames), containingFile, loader);
|
||||
}
|
||||
|
||||
let resolveTypeReferenceDirectiveNamesWorker: (typeDirectiveNames: string[], containingFile: string) => ResolvedTypeReferenceDirective[];
|
||||
if (host.resolveTypeReferenceDirectives) {
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile) => host.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile);
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeDirectiveNames, containingFile) => host.resolveTypeReferenceDirectives(checkAllDefined(typeDirectiveNames), containingFile);
|
||||
}
|
||||
else {
|
||||
const loader = (typesRef: string, containingFile: string) => resolveTypeReferenceDirective(typesRef, containingFile, options, host).resolvedTypeReferenceDirective;
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(typeReferenceDirectiveNames, containingFile, loader);
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(checkAllDefined(typeReferenceDirectiveNames), containingFile, loader);
|
||||
}
|
||||
|
||||
const filesByName = createMap<SourceFile | undefined>();
|
||||
@@ -2127,4 +2127,9 @@ namespace ts {
|
||||
return options.allowJs ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_allowJs_is_not_set;
|
||||
}
|
||||
}
|
||||
|
||||
function checkAllDefined(names: string[]): string[] {
|
||||
Debug.assert(names.every(name => name !== undefined), "A name is undefined.", () => JSON.stringify(names));
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-3
@@ -326,13 +326,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getPositionOfLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number {
|
||||
return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character);
|
||||
return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function computePositionOfLineAndCharacter(lineStarts: number[], line: number, character: number): number {
|
||||
export function computePositionOfLineAndCharacter(lineStarts: number[], line: number, character: number, debugText?: string): number {
|
||||
Debug.assert(line >= 0 && line < lineStarts.length);
|
||||
return lineStarts[line] + character;
|
||||
const res = lineStarts[line] + character;
|
||||
if (line < lineStarts.length - 1) {
|
||||
Debug.assert(res < lineStarts[line + 1]);
|
||||
}
|
||||
else if (debugText !== undefined) {
|
||||
Debug.assert(res < debugText.length);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
+3
-3
@@ -39,7 +39,7 @@ namespace ts {
|
||||
getExecutingFilePath(): string;
|
||||
getCurrentDirectory(): string;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[];
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
getModifiedTime?(path: string): Date;
|
||||
/**
|
||||
* This should be cryptographically secure.
|
||||
@@ -100,7 +100,7 @@ namespace ts {
|
||||
readFile(path: string): string;
|
||||
writeFile(path: string, contents: string): void;
|
||||
getDirectories(path: string): string[];
|
||||
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, basePaths?: ReadonlyArray<string>, excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
|
||||
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
realpath(path: string): string;
|
||||
@@ -287,7 +287,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[], depth?: number): string[] {
|
||||
function readDirectory(path: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), depth, getAccessibleFileSystemEntries);
|
||||
}
|
||||
|
||||
|
||||
@@ -3579,7 +3579,7 @@ namespace ts {
|
||||
// Map spans of spread expressions into their expressions and spans of other
|
||||
// expressions into an array literal.
|
||||
const numElements = elements.length;
|
||||
const segments = flatten(
|
||||
const segments = flatten<Expression>(
|
||||
spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) =>
|
||||
visitPartition(partition, multiLine, hasTrailingComma && end === numElements)
|
||||
)
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace ts {
|
||||
else {
|
||||
// Map spans of JsxAttribute nodes into object literals and spans
|
||||
// of JsxSpreadAttribute nodes into expressions.
|
||||
const segments = flatten(
|
||||
const segments = flatten<Expression | ObjectLiteralExpression>(
|
||||
spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread
|
||||
? map(attrs, transformJsxSpreadAttributeToExpression)
|
||||
: createObjectLiteral(map(attrs, transformJsxAttributeToObjectLiteralElement))
|
||||
|
||||
@@ -1377,7 +1377,7 @@ namespace ts {
|
||||
|
||||
const decoratorExpressions: Expression[] = [];
|
||||
addRange(decoratorExpressions, map(allDecorators.decorators, transformDecorator));
|
||||
addRange(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter));
|
||||
addRange(decoratorExpressions, flatMap<Decorator[], Expression>(allDecorators.parameters, transformDecoratorsOfParameter));
|
||||
addTypeMetadata(node, container, decoratorExpressions);
|
||||
return decoratorExpressions;
|
||||
}
|
||||
|
||||
+7
-10
@@ -2406,7 +2406,7 @@ namespace ts {
|
||||
export interface ParseConfigHost {
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
|
||||
readDirectory(rootDir: string, extensions: string[], excludes: string[], includes: string[], depth: number): string[];
|
||||
readDirectory(rootDir: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, depth: number): string[];
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the specified path exists and is a file.
|
||||
@@ -2890,13 +2890,11 @@ namespace ts {
|
||||
TypeParameter = 1 << 18, // Type parameter
|
||||
TypeAlias = 1 << 19, // Type alias
|
||||
ExportValue = 1 << 20, // Exported value marker (see comment in declareModuleMember in binder)
|
||||
ExportType = 1 << 21, // Exported type marker (see comment in declareModuleMember in binder)
|
||||
ExportNamespace = 1 << 22, // Exported namespace marker (see comment in declareModuleMember in binder)
|
||||
Alias = 1 << 23, // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
|
||||
Prototype = 1 << 24, // Prototype property (no source representation)
|
||||
ExportStar = 1 << 25, // Export * declaration
|
||||
Optional = 1 << 26, // Optional property
|
||||
Transient = 1 << 27, // Transient symbol (created during type check)
|
||||
Alias = 1 << 21, // An alias for another symbol (see comment in isAliasSymbolDeclaration in checker)
|
||||
Prototype = 1 << 22, // Prototype property (no source representation)
|
||||
ExportStar = 1 << 23, // Export * declaration
|
||||
Optional = 1 << 24, // Optional property
|
||||
Transient = 1 << 25, // Transient symbol (created during type check)
|
||||
|
||||
Enum = RegularEnum | ConstEnum,
|
||||
Variable = FunctionScopedVariable | BlockScopedVariable,
|
||||
@@ -2941,7 +2939,6 @@ namespace ts {
|
||||
BlockScoped = BlockScopedVariable | Class | Enum,
|
||||
|
||||
PropertyOrAccessor = Property | Accessor,
|
||||
Export = ExportNamespace | ExportType | ExportValue,
|
||||
|
||||
ClassMember = Method | Accessor | Property,
|
||||
|
||||
@@ -4354,7 +4351,7 @@ namespace ts {
|
||||
*/
|
||||
export type Visitor = (node: Node) => VisitResult<Node>;
|
||||
|
||||
export type VisitResult<T extends Node> = T | T[];
|
||||
export type VisitResult<T extends Node> = T | T[] | undefined;
|
||||
|
||||
export interface Printer {
|
||||
/**
|
||||
|
||||
+49
-34
@@ -44,42 +44,47 @@ namespace ts {
|
||||
string(): string;
|
||||
}
|
||||
|
||||
// Pool writers to avoid needing to allocate them for every symbol we write.
|
||||
const stringWriters: StringSymbolWriter[] = [];
|
||||
export function getSingleLineStringWriter(): StringSymbolWriter {
|
||||
if (stringWriters.length === 0) {
|
||||
let str = "";
|
||||
const stringWriter = createSingleLineStringWriter();
|
||||
let stringWriterAcquired = false;
|
||||
|
||||
const writeText: (text: string) => void = text => str += text;
|
||||
return {
|
||||
string: () => str,
|
||||
writeKeyword: writeText,
|
||||
writeOperator: writeText,
|
||||
writePunctuation: writeText,
|
||||
writeSpace: writeText,
|
||||
writeStringLiteral: writeText,
|
||||
writeParameter: writeText,
|
||||
writeProperty: writeText,
|
||||
writeSymbol: writeText,
|
||||
function createSingleLineStringWriter(): StringSymbolWriter {
|
||||
let str = "";
|
||||
|
||||
// Completely ignore indentation for string writers. And map newlines to
|
||||
// a single space.
|
||||
writeLine: () => str += " ",
|
||||
increaseIndent: noop,
|
||||
decreaseIndent: noop,
|
||||
clear: () => str = "",
|
||||
trackSymbol: noop,
|
||||
reportInaccessibleThisError: noop,
|
||||
reportPrivateInBaseOfClassExpression: noop,
|
||||
};
|
||||
}
|
||||
const writeText: (text: string) => void = text => str += text;
|
||||
return {
|
||||
string: () => str,
|
||||
writeKeyword: writeText,
|
||||
writeOperator: writeText,
|
||||
writePunctuation: writeText,
|
||||
writeSpace: writeText,
|
||||
writeStringLiteral: writeText,
|
||||
writeParameter: writeText,
|
||||
writeProperty: writeText,
|
||||
writeSymbol: writeText,
|
||||
|
||||
return stringWriters.pop();
|
||||
// Completely ignore indentation for string writers. And map newlines to
|
||||
// a single space.
|
||||
writeLine: () => str += " ",
|
||||
increaseIndent: noop,
|
||||
decreaseIndent: noop,
|
||||
clear: () => str = "",
|
||||
trackSymbol: noop,
|
||||
reportInaccessibleThisError: noop,
|
||||
reportPrivateInBaseOfClassExpression: noop,
|
||||
};
|
||||
}
|
||||
|
||||
export function releaseStringWriter(writer: StringSymbolWriter) {
|
||||
writer.clear();
|
||||
stringWriters.push(writer);
|
||||
export function usingSingleLineStringWriter(action: (writer: StringSymbolWriter) => void): string {
|
||||
try {
|
||||
Debug.assert(!stringWriterAcquired);
|
||||
stringWriterAcquired = true;
|
||||
action(stringWriter);
|
||||
return stringWriter.string();
|
||||
}
|
||||
finally {
|
||||
stringWriter.clear();
|
||||
stringWriterAcquired = false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getFullWidth(node: Node) {
|
||||
@@ -1619,7 +1624,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isRestParameter(node: ParameterDeclaration) {
|
||||
if (node && (node.flags & NodeFlags.JavaScriptFile)) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType ||
|
||||
forEach(getJSDocParameterTags(node),
|
||||
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
|
||||
@@ -2743,7 +2748,7 @@ namespace ts {
|
||||
if (node.typeParameters) {
|
||||
return node.typeParameters;
|
||||
}
|
||||
if (node.flags & NodeFlags.JavaScriptFile) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const templateTag = getJSDocTemplateTag(node);
|
||||
return templateTag && templateTag.typeParameters;
|
||||
}
|
||||
@@ -3334,7 +3339,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
return stableSort(result, (x, y) => compareValues(x[0], y[0]));
|
||||
return stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0]));
|
||||
}
|
||||
|
||||
export function formatSyntaxKind(kind: SyntaxKind): string {
|
||||
@@ -3598,6 +3603,15 @@ namespace ts {
|
||||
}
|
||||
return previous[previous.length - 1];
|
||||
}
|
||||
|
||||
export function skipAlias(symbol: Symbol, checker: TypeChecker) {
|
||||
return symbol.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
||||
}
|
||||
|
||||
/** See comment on `declareModuleMember` in `binder.ts`. */
|
||||
export function getCombinedLocalAndExportSymbolFlags(symbol: Symbol): SymbolFlags {
|
||||
return symbol.exportSymbol ? symbol.exportSymbol.flags | symbol.flags : symbol.flags;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
@@ -5116,6 +5130,7 @@ namespace ts {
|
||||
|| kind === SyntaxKind.ThisKeyword
|
||||
|| kind === SyntaxKind.TrueKeyword
|
||||
|| kind === SyntaxKind.SuperKeyword
|
||||
|| kind === SyntaxKind.ImportKeyword
|
||||
|| kind === SyntaxKind.NonNullExpression
|
||||
|| kind === SyntaxKind.MetaProperty;
|
||||
}
|
||||
|
||||
+47
-26
@@ -219,7 +219,7 @@ namespace FourSlash {
|
||||
|
||||
// Add input file which has matched file name with the given reference-file path.
|
||||
// This is necessary when resolveReference flag is specified
|
||||
private addMatchedInputFile(referenceFilePath: string, extensions: string[]) {
|
||||
private addMatchedInputFile(referenceFilePath: string, extensions: ReadonlyArray<string>) {
|
||||
const inputFiles = this.inputFiles;
|
||||
const languageServiceAdapterHost = this.languageServiceAdapterHost;
|
||||
if (!extensions) {
|
||||
@@ -605,7 +605,7 @@ namespace FourSlash {
|
||||
this.verifyGoToXPlain(arg0, endMarkerNames, getDefs);
|
||||
}
|
||||
else if (ts.isArray(arg0)) {
|
||||
const pairs: [string | string[], string | string[]][] = arg0;
|
||||
const pairs: ReadonlyArray<[string | string[], string | string[]]> = arg0;
|
||||
for (const [start, end] of pairs) {
|
||||
this.verifyGoToXPlain(start, end, getDefs);
|
||||
}
|
||||
@@ -949,6 +949,22 @@ namespace FourSlash {
|
||||
this.verifySymbol(symbol, declarationRanges);
|
||||
}
|
||||
|
||||
public symbolsInScope(range: Range): ts.Symbol[] {
|
||||
const node = this.goToAndGetNode(range);
|
||||
return this.getChecker().getSymbolsInScope(node, ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace);
|
||||
}
|
||||
|
||||
public verifyTypeOfSymbolAtLocation(range: Range, symbol: ts.Symbol, expected: string): void {
|
||||
const node = this.goToAndGetNode(range);
|
||||
const checker = this.getChecker();
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, node);
|
||||
|
||||
const actual = checker.typeToString(type);
|
||||
if (actual !== expected) {
|
||||
this.raiseError(`Expected: '${expected}', actual: '${actual}'`);
|
||||
}
|
||||
}
|
||||
|
||||
private verifyReferencesAre(expectedReferences: Range[]) {
|
||||
const actualReferences = this.getReferencesAtCaret() || [];
|
||||
|
||||
@@ -1790,7 +1806,14 @@ namespace FourSlash {
|
||||
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
|
||||
const editDelta = edit.newText.length - edit.span.length;
|
||||
if (offsetStart <= this.currentCaretPosition) {
|
||||
this.currentCaretPosition += editDelta;
|
||||
if (offsetEnd <= this.currentCaretPosition) {
|
||||
// The entirety of the edit span falls before the caret position, shift the caret accordingly
|
||||
this.currentCaretPosition += editDelta;
|
||||
}
|
||||
else {
|
||||
// The span being replaced includes the caret position, place the caret at the beginning of the span
|
||||
this.currentCaretPosition = offsetStart;
|
||||
}
|
||||
}
|
||||
runningOffset += editDelta;
|
||||
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
|
||||
@@ -2320,35 +2343,25 @@ namespace FourSlash {
|
||||
* @param fileName Path to file where error should be retrieved from.
|
||||
*/
|
||||
private getCodeFixActions(fileName: string, errorCode?: number): ts.CodeAction[] {
|
||||
const diagnosticsForCodeFix = this.getDiagnostics(fileName).map(diagnostic => {
|
||||
return {
|
||||
start: diagnostic.start,
|
||||
length: diagnostic.length,
|
||||
code: diagnostic.code
|
||||
};
|
||||
});
|
||||
const dedupedDiagnositcs = ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties);
|
||||
|
||||
let actions: ts.CodeAction[] = undefined;
|
||||
|
||||
for (const diagnostic of dedupedDiagnositcs) {
|
||||
const diagnosticsForCodeFix = this.getDiagnostics(fileName).map(diagnostic => ({
|
||||
start: diagnostic.start,
|
||||
length: diagnostic.length,
|
||||
code: diagnostic.code
|
||||
}));
|
||||
|
||||
return ts.flatMap(ts.deduplicate(diagnosticsForCodeFix, ts.equalOwnProperties), diagnostic => {
|
||||
if (errorCode && errorCode !== diagnostic.code) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code], this.formatCodeSettings);
|
||||
if (newActions && newActions.length) {
|
||||
actions = actions ? actions.concat(newActions) : newActions;
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.start + diagnostic.length, [diagnostic.code], this.formatCodeSettings);
|
||||
});
|
||||
}
|
||||
|
||||
private applyCodeActions(actions: ts.CodeAction[], index?: number): void {
|
||||
if (index === undefined) {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`);
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" }`);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
@@ -2373,7 +2386,7 @@ namespace FourSlash {
|
||||
|
||||
const codeFixes = this.getCodeFixActions(this.activeFile.fileName, errorCode);
|
||||
|
||||
if (!codeFixes || codeFixes.length === 0) {
|
||||
if (codeFixes.length === 0) {
|
||||
if (expectedTextArray.length !== 0) {
|
||||
this.raiseError("No codefixes returned.");
|
||||
}
|
||||
@@ -2702,11 +2715,11 @@ namespace FourSlash {
|
||||
public verifyCodeFixAvailable(negative: boolean) {
|
||||
const codeFix = this.getCodeFixActions(this.activeFile.fileName);
|
||||
|
||||
if (negative && codeFix) {
|
||||
if (negative && codeFix.length) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found one.`);
|
||||
}
|
||||
|
||||
if (!(negative || codeFix)) {
|
||||
if (!(negative || codeFix.length)) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes but none found.`);
|
||||
}
|
||||
}
|
||||
@@ -3426,6 +3439,10 @@ namespace FourSlashInterface {
|
||||
public markerByName(s: string): FourSlash.Marker {
|
||||
return this.state.getMarkerByName(s);
|
||||
}
|
||||
|
||||
public symbolsInScope(range: FourSlash.Range): ts.Symbol[] {
|
||||
return this.state.symbolsInScope(range);
|
||||
}
|
||||
}
|
||||
|
||||
export class GoTo {
|
||||
@@ -3694,6 +3711,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifySymbolAtLocation(startRange, declarationRanges);
|
||||
}
|
||||
|
||||
public typeOfSymbolAtLocation(range: FourSlash.Range, symbol: ts.Symbol, expected: string) {
|
||||
this.state.verifyTypeOfSymbolAtLocation(range, symbol, expected);
|
||||
}
|
||||
|
||||
public referencesOf(start: FourSlash.Range, references: FourSlash.Range[]) {
|
||||
this.state.verifyReferencesOf(start, references);
|
||||
}
|
||||
|
||||
@@ -493,7 +493,7 @@ namespace Harness {
|
||||
args(): string[];
|
||||
getExecutingFilePath(): string;
|
||||
exit(exitCode?: number): void;
|
||||
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[], depth?: number): string[];
|
||||
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
tryEnableSourceMapsForHost?(): void;
|
||||
getEnvironmentVariable?(name: string): string;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace Harness.LanguageService {
|
||||
const script = this.getScriptSnapshot(fileName);
|
||||
return script !== undefined;
|
||||
}
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return ts.matchFiles(path, extensions, exclude, include,
|
||||
/*useCaseSensitiveFileNames*/ false,
|
||||
this.getCurrentDirectory(),
|
||||
|
||||
@@ -64,11 +64,11 @@ interface IOLog {
|
||||
}[];
|
||||
directoriesRead: {
|
||||
path: string,
|
||||
extensions: string[],
|
||||
exclude: string[],
|
||||
include: string[],
|
||||
extensions: ReadonlyArray<string>,
|
||||
exclude: ReadonlyArray<string>,
|
||||
include: ReadonlyArray<string>,
|
||||
depth: number,
|
||||
result: string[]
|
||||
result: ReadonlyArray<string>,
|
||||
}[];
|
||||
}
|
||||
|
||||
|
||||
@@ -585,27 +585,25 @@ namespace ts.projectSystem {
|
||||
return [];
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return ts.matchFiles(this.toFullPath(path), extensions, exclude, include, this.useCaseSensitiveFileNames, this.getCurrentDirectory(), depth, (dir) => {
|
||||
const result: FileSystemEntries = {
|
||||
directories: [],
|
||||
files: []
|
||||
};
|
||||
const directories: string[] = [];
|
||||
const files: string[] = [];
|
||||
const dirEntry = this.fs.get(this.toPath(dir));
|
||||
if (isFolder(dirEntry)) {
|
||||
dirEntry.entries.forEach((entry) => {
|
||||
if (isFolder(entry)) {
|
||||
result.directories.push(getBaseFileName(entry.fullPath));
|
||||
directories.push(getBaseFileName(entry.fullPath));
|
||||
}
|
||||
else if (isFile(entry)) {
|
||||
result.files.push(getBaseFileName(entry.fullPath));
|
||||
files.push(getBaseFileName(entry.fullPath));
|
||||
}
|
||||
else {
|
||||
Debug.fail("Unknown entry");
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
return { directories, files };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,18 @@ namespace ts.projectSystem {
|
||||
});
|
||||
}
|
||||
|
||||
function trackingLogger(): { log(message: string): void, finish(): string[] } {
|
||||
const logs: string[] = [];
|
||||
return {
|
||||
log(message) {
|
||||
logs.push(message);
|
||||
},
|
||||
finish() {
|
||||
return logs;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
import typingsName = TI.typingsName;
|
||||
|
||||
describe("local module", () => {
|
||||
@@ -1038,7 +1050,12 @@ namespace ts.projectSystem {
|
||||
const cache = createMap<string>();
|
||||
|
||||
const host = createServerHost([app, jquery, chroma]);
|
||||
const result = JsTyping.discoverTypings(host, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), /*safeListPath*/ undefined, cache, { enable: true }, []);
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), /*safeListPath*/ undefined, cache, { enable: true }, []);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from file names: ["jquery","chroma-js"]',
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["jquery","chroma-js"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result.newTypingNames, ["jquery", "chroma-js"]);
|
||||
});
|
||||
|
||||
@@ -1051,7 +1068,12 @@ namespace ts.projectSystem {
|
||||
const cache = createMap<string>();
|
||||
|
||||
for (const name of JsTyping.nodeCoreModuleList) {
|
||||
const result = JsTyping.discoverTypings(host, [f.path], getDirectoryPath(<Path>f.path), /*safeListPath*/ undefined, cache, { enable: true }, [name, "somename"]);
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), /*safeListPath*/ undefined, cache, { enable: true }, [name, "somename"]);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from unresolved imports: ["node","somename"]',
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["node","somename"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result.newTypingNames.sort(), ["node", "somename"]);
|
||||
}
|
||||
});
|
||||
@@ -1067,7 +1089,12 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([f, node]);
|
||||
const cache = createMapFromTemplate<string>({ "node": node.path });
|
||||
const result = JsTyping.discoverTypings(host, [f.path], getDirectoryPath(<Path>f.path), /*safeListPath*/ undefined, cache, { enable: true }, ["fs", "bar"]);
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), /*safeListPath*/ undefined, cache, { enable: true }, ["fs", "bar"]);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Inferred typings from unresolved imports: ["node","bar"]',
|
||||
'Result: {"cachedTypingPaths":["/a/b/node.d.ts"],"newTypingNames":["bar"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result.cachedTypingPaths, [node.path]);
|
||||
assert.deepEqual(result.newTypingNames, ["bar"]);
|
||||
});
|
||||
@@ -1087,7 +1114,12 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([app, a, b]);
|
||||
const cache = createMap<string>();
|
||||
const result = JsTyping.discoverTypings(host, [app.path], getDirectoryPath(<Path>app.path), /*safeListPath*/ undefined, cache, { enable: true }, /*unresolvedImports*/ []);
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [app.path], getDirectoryPath(<Path>app.path), /*safeListPath*/ undefined, cache, { enable: true }, /*unresolvedImports*/ []);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
'Searching for typing names in /node_modules; all files: ["/node_modules/a/package.json"]',
|
||||
'Result: {"cachedTypingPaths":[],"newTypingNames":["a"],"filesToWatch":["/bower_components","/node_modules"]}',
|
||||
]);
|
||||
assert.deepEqual(result, {
|
||||
cachedTypingPaths: [],
|
||||
newTypingNames: ["a"], // But not "b"
|
||||
|
||||
@@ -7,8 +7,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function lineColToPosition(lineIndex: server.LineIndex, line: number, col: number) {
|
||||
const lineInfo = lineIndex.lineNumberToInfo(line);
|
||||
return (lineInfo.offset + col - 1);
|
||||
return lineIndex.absolutePositionOfStartOfLine(line) + (col - 1);
|
||||
}
|
||||
|
||||
function validateEdit(lineIndex: server.LineIndex, sourceText: string, position: number, deleteLength: number, insertString: string): void {
|
||||
@@ -298,20 +297,17 @@ and grew 1cm per day`;
|
||||
|
||||
it("Line/offset from pos", () => {
|
||||
for (let i = 0; i < iterationCount; i++) {
|
||||
const lp = lineIndex.charOffsetToLineNumberAndPos(rsa[i]);
|
||||
const lp = lineIndex.positionToLineOffset(rsa[i]);
|
||||
const lac = ts.computeLineAndCharacterOfPosition(lineMap, rsa[i]);
|
||||
assert.equal(lac.line + 1, lp.line, "Line number mismatch " + (lac.line + 1) + " " + lp.line + " " + i);
|
||||
assert.equal(lac.character, (lp.offset), "Charachter offset mismatch " + lac.character + " " + lp.offset + " " + i);
|
||||
assert.equal(lac.character, lp.offset - 1, "Character offset mismatch " + lac.character + " " + (lp.offset - 1) + " " + i);
|
||||
}
|
||||
});
|
||||
|
||||
it("Start pos from line", () => {
|
||||
for (let i = 0; i < iterationCount; i++) {
|
||||
for (let j = 0; j < lines.length; j++) {
|
||||
const lineInfo = lineIndex.lineNumberToInfo(j + 1);
|
||||
const lineIndexOffset = lineInfo.offset;
|
||||
const lineMapOffset = lineMap[j];
|
||||
assert.equal(lineIndexOffset, lineMapOffset);
|
||||
assert.equal(lineIndex.absolutePositionOfStartOfLine(j + 1), lineMap[j]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Utils {
|
||||
}
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions: string[], excludes: string[], includes: string[], depth: number) {
|
||||
readDirectory(path: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, depth: number) {
|
||||
return ts.matchFiles(path, extensions, excludes, includes, this.useCaseSensitiveFileNames, this.currentDirectory, depth, (path: string) => this.getAccessibleFileSystemEntries(path));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace ts.server {
|
||||
|
||||
const referencedFilePaths = this.project.getReferencedFiles(fileInfo.scriptInfo.path);
|
||||
if (referencedFilePaths.length > 0) {
|
||||
return map(referencedFilePaths, f => this.getOrCreateFileInfo(f)).sort(ModuleBuilderFileInfo.compareFileInfos);
|
||||
return map<Path, ModuleBuilderFileInfo>(referencedFilePaths, f => this.getOrCreateFileInfo(f)).sort(ModuleBuilderFileInfo.compareFileInfos);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace ts.server {
|
||||
}));
|
||||
}
|
||||
|
||||
getFormattingEditsForRange(file: string, start: number, end: number, _options: ts.FormatCodeOptions): ts.TextChange[] {
|
||||
getFormattingEditsForRange(file: string, start: number, end: number, _options: FormatCodeOptions): ts.TextChange[] {
|
||||
const args: protocol.FormatRequestArgs = this.createFileLocationRequestArgsWithEndLineAndOffset(file, start, end);
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace ts.server {
|
||||
* Any compiler options that might contain paths will be taken out.
|
||||
* Enum compiler options will be converted to strings.
|
||||
*/
|
||||
readonly compilerOptions: ts.CompilerOptions;
|
||||
readonly compilerOptions: CompilerOptions;
|
||||
// "extends", "files", "include", or "exclude" will be undefined if an external config is used.
|
||||
// Otherwise, we will use "true" if the property is present and "false" if it is missing.
|
||||
readonly extends: boolean | undefined;
|
||||
@@ -201,7 +201,7 @@ namespace ts.server {
|
||||
* This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
|
||||
*/
|
||||
export function combineProjectOutput<T>(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) {
|
||||
const result = projects.reduce<T[]>((previous, current) => concatenate(previous, action(current)), []).sort(comparer);
|
||||
const result = flatMap(projects, action).sort(comparer);
|
||||
return projects.length > 1 ? deduplicate(result, areEqual) : result;
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ namespace ts.server {
|
||||
getFileName: x => x,
|
||||
getScriptKind: _ => undefined,
|
||||
hasMixedContent: (fileName, extraFileExtensions) => {
|
||||
const mixedContentExtensions = ts.map(ts.filter(extraFileExtensions, item => item.isMixedContent), item => item.extension);
|
||||
const mixedContentExtensions = map(filter(extraFileExtensions, item => item.isMixedContent), item => item.extension);
|
||||
return forEach(mixedContentExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
};
|
||||
@@ -663,7 +663,7 @@ namespace ts.server {
|
||||
// If a change was made inside "folder/file", node will trigger the callback twice:
|
||||
// one with the fileName being "folder/file", and the other one with "folder".
|
||||
// We don't respond to the second one.
|
||||
if (fileName && !ts.isSupportedSourceFileName(fileName, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) {
|
||||
if (fileName && !isSupportedSourceFileName(fileName, project.getCompilerOptions(), this.hostConfiguration.extraFileExtensions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1120,7 +1120,7 @@ namespace ts.server {
|
||||
configFileName: configFileName(),
|
||||
projectType: project instanceof server.ExternalProject ? "external" : "configured",
|
||||
languageServiceEnabled: project.languageServiceEnabled,
|
||||
version: ts.version,
|
||||
version,
|
||||
};
|
||||
this.eventHandler({ eventName: ProjectInfoTelemetryEvent, data });
|
||||
|
||||
@@ -1130,7 +1130,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
const configFilePath = project instanceof server.ConfiguredProject && project.getConfigFilePath();
|
||||
const base = ts.getBaseFileName(configFilePath);
|
||||
const base = getBaseFileName(configFilePath);
|
||||
return base === "tsconfig.json" || base === "jsconfig.json" ? base : "other";
|
||||
}
|
||||
|
||||
|
||||
+28
-24
@@ -3,8 +3,6 @@
|
||||
/// <reference path="scriptInfo.ts" />
|
||||
|
||||
namespace ts.server {
|
||||
type NameResolutionWithFailedLookupLocations = { failedLookupLocations: string[], isInvalidated?: boolean };
|
||||
|
||||
export class CachedServerHost implements ServerHost {
|
||||
args: string[];
|
||||
newLine: string;
|
||||
@@ -32,7 +30,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private getFileSystemEntries(rootDir: string) {
|
||||
const path = ts.toPath(rootDir, this.currentDirectory, this.getCanonicalFileName);
|
||||
const path = toPath(rootDir, this.currentDirectory, this.getCanonicalFileName);
|
||||
const cachedResult = this.cachedReadDirectoryResult.get(path);
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
@@ -49,7 +47,7 @@ namespace ts.server {
|
||||
|
||||
private canWorkWithCacheForDir(rootDir: string) {
|
||||
// Some of the hosts might not be able to handle read directory or getDirectories
|
||||
const path = ts.toPath(rootDir, this.currentDirectory, this.getCanonicalFileName);
|
||||
const path = toPath(rootDir, this.currentDirectory, this.getCanonicalFileName);
|
||||
if (this.cachedReadDirectoryResult.get(path)) {
|
||||
return true;
|
||||
}
|
||||
@@ -66,11 +64,11 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
writeFile(fileName: string, data: string, writeByteOrderMark?: boolean) {
|
||||
const path = ts.toPath(fileName, this.currentDirectory, this.getCanonicalFileName);
|
||||
const path = toPath(fileName, this.currentDirectory, this.getCanonicalFileName);
|
||||
const result = this.cachedReadDirectoryResult.get(getDirectoryPath(path));
|
||||
const baseFileName = getBaseFileName(toNormalizedPath(fileName));
|
||||
if (result && !some(result.files, file => this.fileNameEqual(file, baseFileName))) {
|
||||
result.files.push(baseFileName);
|
||||
if (result) {
|
||||
result.files = this.updateFileSystemEntry(result.files, baseFileName, /*isValid*/ true);
|
||||
}
|
||||
return this.host.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
@@ -102,7 +100,7 @@ namespace ts.server {
|
||||
|
||||
getDirectories(rootDir: string) {
|
||||
if (this.canWorkWithCacheForDir(rootDir)) {
|
||||
return this.getFileSystemEntries(rootDir).directories;
|
||||
return this.getFileSystemEntries(rootDir).directories.slice();
|
||||
}
|
||||
return this.host.getDirectories(rootDir);
|
||||
}
|
||||
@@ -115,14 +113,14 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
fileExists(fileName: string): boolean {
|
||||
const path = ts.toPath(fileName, this.currentDirectory, this.getCanonicalFileName);
|
||||
const path = toPath(fileName, this.currentDirectory, this.getCanonicalFileName);
|
||||
const result = this.cachedReadDirectoryResult.get(getDirectoryPath(path));
|
||||
const baseName = getBaseFileName(toNormalizedPath(fileName));
|
||||
return (result && some(result.files, file => this.fileNameEqual(file, baseName))) || this.host.fileExists(fileName);
|
||||
return (result && this.hasEntry(result.files, baseName)) || this.host.fileExists(fileName);
|
||||
}
|
||||
|
||||
directoryExists(dirPath: string) {
|
||||
const path = ts.toPath(dirPath, this.currentDirectory, this.getCanonicalFileName);
|
||||
const path = toPath(dirPath, this.currentDirectory, this.getCanonicalFileName);
|
||||
return this.cachedReadDirectoryResult.has(path) || this.host.directoryExists(dirPath);
|
||||
}
|
||||
|
||||
@@ -134,15 +132,20 @@ namespace ts.server {
|
||||
return this.getCanonicalFileName(name1) === this.getCanonicalFileName(name2);
|
||||
}
|
||||
|
||||
private updateFileSystemEntry(entries: string[], baseName: string, isValid: boolean) {
|
||||
if (some(entries, entry => this.fileNameEqual(entry, baseName))) {
|
||||
private hasEntry(entries: ReadonlyArray<string>, name: string) {
|
||||
return some(entries, file => this.fileNameEqual(file, name));
|
||||
}
|
||||
|
||||
private updateFileSystemEntry(entries: ReadonlyArray<string>, baseName: string, isValid: boolean) {
|
||||
if (this.hasEntry(entries, baseName)) {
|
||||
if (!isValid) {
|
||||
filterMutate(entries, entry => !this.fileNameEqual(entry, baseName));
|
||||
return filter(entries, entry => !this.fileNameEqual(entry, baseName));
|
||||
}
|
||||
}
|
||||
else if (isValid) {
|
||||
entries.push(baseName);
|
||||
return entries.concat(baseName);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
addOrDeleteFileOrFolder(fileOrFolder: NormalizedPath) {
|
||||
@@ -159,8 +162,8 @@ namespace ts.server {
|
||||
if (parentResult) {
|
||||
const baseName = getBaseFileName(fileOrFolder);
|
||||
if (parentResult) {
|
||||
this.updateFileSystemEntry(parentResult.files, baseName, this.host.fileExists(path));
|
||||
this.updateFileSystemEntry(parentResult.directories, baseName, this.host.directoryExists(path));
|
||||
parentResult.files = this.updateFileSystemEntry(parentResult.files, baseName, this.host.fileExists(path));
|
||||
parentResult.directories = this.updateFileSystemEntry(parentResult.directories, baseName, this.host.directoryExists(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,8 +188,9 @@ namespace ts.server {
|
||||
|
||||
}
|
||||
|
||||
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost {
|
||||
private compilationSettings: ts.CompilerOptions;
|
||||
type NameResolutionWithFailedLookupLocations = { failedLookupLocations: string[], isInvalidated?: boolean };
|
||||
export class LSHost implements LanguageServiceHost, ModuleResolutionHost {
|
||||
private compilationSettings: CompilerOptions;
|
||||
private readonly resolvedModuleNames = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
private readonly resolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
|
||||
/* @internal */
|
||||
@@ -203,7 +207,7 @@ namespace ts.server {
|
||||
constructor(host: ServerHost, private project: Project, private readonly cancellationToken: HostCancellationToken) {
|
||||
this.host = host;
|
||||
this.cancellationToken = new ThrottledCancellationToken(cancellationToken, project.projectService.throttleWaitMilliseconds);
|
||||
this.getCanonicalFileName = ts.createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
|
||||
|
||||
if (host.trace) {
|
||||
this.trace = s => host.trace(s);
|
||||
@@ -285,7 +289,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
ts.Debug.assert(resolution !== undefined);
|
||||
Debug.assert(resolution !== undefined);
|
||||
|
||||
resolvedModules.push(getResult(resolution));
|
||||
}
|
||||
@@ -363,7 +367,7 @@ namespace ts.server {
|
||||
return combinePaths(nodeModuleBinDir, getDefaultLibFileName(this.compilationSettings));
|
||||
}
|
||||
|
||||
getScriptSnapshot(filename: string): ts.IScriptSnapshot {
|
||||
getScriptSnapshot(filename: string): IScriptSnapshot {
|
||||
const scriptInfo = this.project.getScriptInfoLSHost(filename);
|
||||
if (scriptInfo) {
|
||||
return scriptInfo.getSnapshot();
|
||||
@@ -411,7 +415,7 @@ namespace ts.server {
|
||||
return this.host.directoryExists(path);
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
|
||||
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
|
||||
return this.host.readDirectory(path, extensions, exclude, include, depth);
|
||||
}
|
||||
|
||||
@@ -450,7 +454,7 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
setCompilationSettings(opt: ts.CompilerOptions) {
|
||||
setCompilationSettings(opt: CompilerOptions) {
|
||||
if (changesAffectModuleResolution(this.compilationSettings, opt)) {
|
||||
this.resolvedModuleNames.clear();
|
||||
this.resolvedTypeReferenceDirectives.clear();
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace ts.server {
|
||||
export abstract class Project {
|
||||
private rootFiles: ScriptInfo[] = [];
|
||||
private rootFilesMap: Map<ProjectRoot> = createMap<ProjectRoot>();
|
||||
private program: ts.Program;
|
||||
private program: Program;
|
||||
private externalFiles: SortedReadonlyArray<string>;
|
||||
private missingFilesMap: Map<FileWatcher> = createMap<FileWatcher>();
|
||||
|
||||
@@ -191,7 +191,7 @@ namespace ts.server {
|
||||
private readonly projectName: string,
|
||||
readonly projectKind: ProjectKind,
|
||||
readonly projectService: ProjectService,
|
||||
private documentRegistry: ts.DocumentRegistry,
|
||||
private documentRegistry: DocumentRegistry,
|
||||
hasExplicitListOfFiles: boolean,
|
||||
languageServiceEnabled: boolean,
|
||||
private compilerOptions: CompilerOptions,
|
||||
@@ -199,7 +199,7 @@ namespace ts.server {
|
||||
host: ServerHost) {
|
||||
|
||||
if (!this.compilerOptions) {
|
||||
this.compilerOptions = ts.getDefaultCompilerOptions();
|
||||
this.compilerOptions = getDefaultCompilerOptions();
|
||||
this.compilerOptions.allowNonTsExtensions = true;
|
||||
this.compilerOptions.allowJs = true;
|
||||
}
|
||||
@@ -213,7 +213,7 @@ namespace ts.server {
|
||||
this.lsHost = new LSHost(host, this, this.projectService.cancellationToken);
|
||||
this.lsHost.setCompilationSettings(this.compilerOptions);
|
||||
|
||||
this.languageService = ts.createLanguageService(this.lsHost, this.documentRegistry);
|
||||
this.languageService = createLanguageService(this.lsHost, this.documentRegistry);
|
||||
|
||||
if (!languageServiceEnabled) {
|
||||
this.disableLanguageService();
|
||||
@@ -729,7 +729,7 @@ namespace ts.server {
|
||||
}
|
||||
let strBuilder = "";
|
||||
for (const file of this.program.getSourceFiles()) {
|
||||
strBuilder += `${file.fileName}\n`;
|
||||
strBuilder += `\t${file.fileName}\n`;
|
||||
}
|
||||
return strBuilder;
|
||||
}
|
||||
@@ -914,7 +914,7 @@ namespace ts.server {
|
||||
// Used to keep track of what directories are watched for this project
|
||||
directoriesWatchedForTsconfig: string[] = [];
|
||||
|
||||
constructor(projectService: ProjectService, documentRegistry: ts.DocumentRegistry, compilerOptions: CompilerOptions) {
|
||||
constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions) {
|
||||
super(InferredProject.newName(),
|
||||
ProjectKind.Inferred,
|
||||
projectService,
|
||||
@@ -995,7 +995,7 @@ namespace ts.server {
|
||||
|
||||
constructor(configFileName: NormalizedPath,
|
||||
projectService: ProjectService,
|
||||
documentRegistry: ts.DocumentRegistry,
|
||||
documentRegistry: DocumentRegistry,
|
||||
hasExplicitListOfFiles: boolean,
|
||||
compilerOptions: CompilerOptions,
|
||||
languageServiceEnabled: boolean,
|
||||
@@ -1232,7 +1232,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getEffectiveTypeRoots() {
|
||||
return ts.getEffectiveTypeRoots(this.getCompilerOptions(), this.lsHost.host) || [];
|
||||
return getEffectiveTypeRoots(this.getCompilerOptions(), this.lsHost.host) || [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1244,7 +1244,7 @@ namespace ts.server {
|
||||
private typeAcquisition: TypeAcquisition;
|
||||
constructor(public externalProjectName: string,
|
||||
projectService: ProjectService,
|
||||
documentRegistry: ts.DocumentRegistry,
|
||||
documentRegistry: DocumentRegistry,
|
||||
compilerOptions: CompilerOptions,
|
||||
languageServiceEnabled: boolean,
|
||||
public compileOnSaveEnabled: boolean,
|
||||
|
||||
@@ -640,7 +640,7 @@ namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
/**
|
||||
* Location in source code expressed as (one-based) line and character offset.
|
||||
* Location in source code expressed as (one-based) line and (one-based) column offset.
|
||||
*/
|
||||
export interface Location {
|
||||
line: number;
|
||||
|
||||
+12
-31
@@ -61,7 +61,7 @@ namespace ts.server {
|
||||
: ScriptSnapshot.fromString(this.getOrLoadText());
|
||||
}
|
||||
|
||||
public getLineInfo(line: number) {
|
||||
public getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this.switchToScriptVersionCache().getSnapshot().index.lineNumberToInfo(line);
|
||||
}
|
||||
/**
|
||||
@@ -72,19 +72,12 @@ namespace ts.server {
|
||||
const lineMap = this.getLineMap();
|
||||
const start = lineMap[line]; // -1 since line is 1-based
|
||||
const end = line + 1 < lineMap.length ? lineMap[line + 1] : this.text.length;
|
||||
return ts.createTextSpanFromBounds(start, end);
|
||||
return createTextSpanFromBounds(start, end);
|
||||
}
|
||||
const index = this.svc.getSnapshot().index;
|
||||
const lineInfo = index.lineNumberToInfo(line + 1);
|
||||
let len: number;
|
||||
if (lineInfo.leaf) {
|
||||
len = lineInfo.leaf.text.length;
|
||||
}
|
||||
else {
|
||||
const nextLineInfo = index.lineNumberToInfo(line + 2);
|
||||
len = nextLineInfo.offset - lineInfo.offset;
|
||||
}
|
||||
return ts.createTextSpan(lineInfo.offset, len);
|
||||
const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1);
|
||||
const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition;
|
||||
return createTextSpan(absolutePosition, len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,27 +86,19 @@ namespace ts.server {
|
||||
*/
|
||||
lineOffsetToPosition(line: number, offset: number): number {
|
||||
if (!this.svc) {
|
||||
return computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1);
|
||||
return computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1, this.text);
|
||||
}
|
||||
const index = this.svc.getSnapshot().index;
|
||||
|
||||
const lineInfo = index.lineNumberToInfo(line);
|
||||
// TODO: assert this offset is actually on the line
|
||||
return (lineInfo.offset + offset - 1);
|
||||
return this.svc.getSnapshot().index.absolutePositionOfStartOfLine(line) + (offset - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 1-based index
|
||||
* @param offset 1-based index
|
||||
*/
|
||||
positionToLineOffset(position: number): ILineInfo {
|
||||
positionToLineOffset(position: number): protocol.Location {
|
||||
if (!this.svc) {
|
||||
const { line, character } = computeLineAndCharacterOfPosition(this.getLineMap(), position);
|
||||
return { line: line + 1, offset: character + 1 };
|
||||
}
|
||||
const index = this.svc.getSnapshot().index;
|
||||
const lineOffset = index.charOffsetToLineNumberAndPos(position);
|
||||
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
|
||||
return this.svc.getSnapshot().index.positionToLineOffset(position);
|
||||
}
|
||||
|
||||
private getFileText(tempFileName?: string) {
|
||||
@@ -162,7 +147,7 @@ namespace ts.server {
|
||||
* All projects that include this file
|
||||
*/
|
||||
readonly containingProjects: Project[] = [];
|
||||
private formatCodeSettings: ts.FormatCodeSettings;
|
||||
private formatCodeSettings: FormatCodeSettings;
|
||||
readonly path: Path;
|
||||
|
||||
private fileWatcher: FileWatcher;
|
||||
@@ -343,7 +328,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
getLineInfo(line: number) {
|
||||
getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this.textStorage.getLineInfo(line);
|
||||
}
|
||||
|
||||
@@ -373,11 +358,7 @@ namespace ts.server {
|
||||
return this.textStorage.lineOffsetToPosition(line, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 1-based index
|
||||
* @param offset 1-based index
|
||||
*/
|
||||
positionToLineOffset(position: number): ILineInfo {
|
||||
positionToLineOffset(position: number): protocol.Location {
|
||||
return this.textStorage.positionToLineOffset(position);
|
||||
}
|
||||
|
||||
|
||||
+105
-126
@@ -8,15 +8,13 @@ namespace ts.server {
|
||||
export interface LineCollection {
|
||||
charCount(): number;
|
||||
lineCount(): number;
|
||||
isLeaf(): boolean;
|
||||
isLeaf(): this is LineLeaf;
|
||||
walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker): void;
|
||||
}
|
||||
|
||||
export interface ILineInfo {
|
||||
line: number;
|
||||
offset: number;
|
||||
text?: string;
|
||||
leaf?: LineLeaf;
|
||||
export interface AbsolutePositionAndLineText {
|
||||
absolutePosition: number;
|
||||
lineText: string | undefined;
|
||||
}
|
||||
|
||||
export enum CharRangeSection {
|
||||
@@ -97,22 +95,20 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// path at least length two (root and leaf)
|
||||
let insertionNode = <LineNode>this.startPath[this.startPath.length - 2];
|
||||
const leafNode = <LineLeaf>this.startPath[this.startPath.length - 1];
|
||||
const len = lines.length;
|
||||
|
||||
if (len > 0) {
|
||||
if (lines.length > 0) {
|
||||
leafNode.text = lines[0];
|
||||
|
||||
if (len > 1) {
|
||||
let insertedNodes = <LineCollection[]>new Array(len - 1);
|
||||
if (lines.length > 1) {
|
||||
let insertedNodes = <LineCollection[]>new Array(lines.length - 1);
|
||||
let startNode = <LineCollection>leafNode;
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
insertedNodes[i - 1] = new LineLeaf(lines[i]);
|
||||
}
|
||||
let pathIndex = this.startPath.length - 2;
|
||||
while (pathIndex >= 0) {
|
||||
insertionNode = <LineNode>this.startPath[pathIndex];
|
||||
const insertionNode = <LineNode>this.startPath[pathIndex];
|
||||
insertedNodes = insertionNode.insertAt(startNode, insertedNodes);
|
||||
pathIndex--;
|
||||
startNode = insertionNode;
|
||||
@@ -134,6 +130,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const insertionNode = <LineNode>this.startPath[this.startPath.length - 2];
|
||||
// no content for leaf node, so delete it
|
||||
insertionNode.remove(leafNode);
|
||||
for (let j = this.startPath.length - 2; j >= 0; j--) {
|
||||
@@ -251,7 +248,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
getTextChangeRange() {
|
||||
return ts.createTextChangeRange(ts.createTextSpan(this.pos, this.deleteLen),
|
||||
return createTextChangeRange(createTextSpan(this.pos, this.deleteLen),
|
||||
this.insertedText ? this.insertedText.length : 0);
|
||||
}
|
||||
}
|
||||
@@ -281,9 +278,9 @@ namespace ts.server {
|
||||
// REVIEW: can optimize by coalescing simple edits
|
||||
edit(pos: number, deleteLen: number, insertedText?: string) {
|
||||
this.changes.push(new TextChange(pos, deleteLen, insertedText));
|
||||
if ((this.changes.length > ScriptVersionCache.changeNumberThreshold) ||
|
||||
(deleteLen > ScriptVersionCache.changeLengthThreshold) ||
|
||||
(insertedText && (insertedText.length > ScriptVersionCache.changeLengthThreshold))) {
|
||||
if (this.changes.length > ScriptVersionCache.changeNumberThreshold ||
|
||||
deleteLen > ScriptVersionCache.changeLengthThreshold ||
|
||||
insertedText && insertedText.length > ScriptVersionCache.changeLengthThreshold) {
|
||||
this.getSnapshot();
|
||||
}
|
||||
}
|
||||
@@ -340,21 +337,21 @@ namespace ts.server {
|
||||
getTextChangesBetweenVersions(oldVersion: number, newVersion: number) {
|
||||
if (oldVersion < newVersion) {
|
||||
if (oldVersion >= this.minVersion) {
|
||||
const textChangeRanges: ts.TextChangeRange[] = [];
|
||||
const textChangeRanges: TextChangeRange[] = [];
|
||||
for (let i = oldVersion + 1; i <= newVersion; i++) {
|
||||
const snap = this.versions[this.versionToIndex(i)];
|
||||
for (const textChange of snap.changesSincePreviousVersion) {
|
||||
textChangeRanges.push(textChange.getTextChangeRange());
|
||||
}
|
||||
}
|
||||
return ts.collapseTextChangeRangesAcrossMultipleVersions(textChangeRanges);
|
||||
return collapseTextChangeRangesAcrossMultipleVersions(textChangeRanges);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ts.unchangedTextChangeRange;
|
||||
return unchangedTextChangeRange;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +365,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
export class LineIndexSnapshot implements ts.IScriptSnapshot {
|
||||
export class LineIndexSnapshot implements IScriptSnapshot {
|
||||
constructor(readonly version: number, readonly cache: ScriptVersionCache, readonly index: LineIndex, readonly changesSincePreviousVersion: ReadonlyArray<TextChange> = emptyArray) {
|
||||
}
|
||||
|
||||
@@ -380,10 +377,10 @@ namespace ts.server {
|
||||
return this.index.root.charCount();
|
||||
}
|
||||
|
||||
getChangeRange(oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange {
|
||||
getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange {
|
||||
if (oldSnapshot instanceof LineIndexSnapshot && this.cache === oldSnapshot.cache) {
|
||||
if (this.version <= oldSnapshot.version) {
|
||||
return ts.unchangedTextChangeRange;
|
||||
return unchangedTextChangeRange;
|
||||
}
|
||||
else {
|
||||
return this.cache.getTextChangesBetweenVersions(oldSnapshot.version, this.version);
|
||||
@@ -397,22 +394,27 @@ namespace ts.server {
|
||||
// set this to true to check each edit for accuracy
|
||||
checkEdits = false;
|
||||
|
||||
charOffsetToLineNumberAndPos(charOffset: number) {
|
||||
return this.root.charOffsetToLineNumberAndPos(1, charOffset);
|
||||
absolutePositionOfStartOfLine(oneBasedLine: number): number {
|
||||
return this.lineNumberToInfo(oneBasedLine).absolutePosition;
|
||||
}
|
||||
|
||||
lineNumberToInfo(lineNumber: number): ILineInfo {
|
||||
positionToLineOffset(position: number): protocol.Location {
|
||||
const { oneBasedLine, zeroBasedColumn } = this.root.charOffsetToLineInfo(1, position);
|
||||
return { line: oneBasedLine, offset: zeroBasedColumn + 1 };
|
||||
}
|
||||
|
||||
private positionToColumnAndLineText(position: number): { zeroBasedColumn: number, lineText: string } {
|
||||
return this.root.charOffsetToLineInfo(1, position);
|
||||
}
|
||||
|
||||
lineNumberToInfo(oneBasedLine: number): AbsolutePositionAndLineText {
|
||||
const lineCount = this.root.lineCount();
|
||||
if (lineNumber <= lineCount) {
|
||||
const lineInfo = this.root.lineNumberToInfo(lineNumber, 0);
|
||||
lineInfo.line = lineNumber;
|
||||
return lineInfo;
|
||||
if (oneBasedLine <= lineCount) {
|
||||
const { position, leaf } = this.root.lineNumberToInfo(oneBasedLine, 0);
|
||||
return { absolutePosition: position, lineText: leaf && leaf.text };
|
||||
}
|
||||
else {
|
||||
return {
|
||||
line: lineNumber,
|
||||
offset: this.root.charCount()
|
||||
};
|
||||
return { absolutePosition: this.root.charCount(), lineText: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,12 +470,9 @@ namespace ts.server {
|
||||
return !walkFns.done;
|
||||
}
|
||||
|
||||
edit(pos: number, deleteLength: number, newText?: string) {
|
||||
function editFlat(source: string, s: number, dl: number, nt = "") {
|
||||
return source.substring(0, s) + nt + source.substring(s + dl, source.length);
|
||||
}
|
||||
edit(pos: number, deleteLength: number, newText?: string): LineIndex {
|
||||
if (this.root.charCount() === 0) {
|
||||
// TODO: assert deleteLength === 0
|
||||
Debug.assert(deleteLength === 0); // Can't delete from empty document
|
||||
if (newText !== undefined) {
|
||||
this.load(LineIndex.linesFromText(newText).lines);
|
||||
return this;
|
||||
@@ -482,7 +481,8 @@ namespace ts.server {
|
||||
else {
|
||||
let checkText: string;
|
||||
if (this.checkEdits) {
|
||||
checkText = editFlat(this.getText(0, this.root.charCount()), pos, deleteLength, newText);
|
||||
const source = this.getText(0, this.root.charCount());
|
||||
checkText = source.slice(0, pos) + newText + source.slice(pos + deleteLength);
|
||||
}
|
||||
const walker = new EditWalker();
|
||||
let suppressTrailingText = false;
|
||||
@@ -502,63 +502,44 @@ namespace ts.server {
|
||||
else if (deleteLength > 0) {
|
||||
// check whether last characters deleted are line break
|
||||
const e = pos + deleteLength;
|
||||
const lineInfo = this.charOffsetToLineNumberAndPos(e);
|
||||
if ((lineInfo && (lineInfo.offset === 0))) {
|
||||
const { zeroBasedColumn, lineText } = this.positionToColumnAndLineText(e);
|
||||
if (zeroBasedColumn === 0) {
|
||||
// move range end just past line that will merge with previous line
|
||||
deleteLength += lineInfo.text.length;
|
||||
deleteLength += lineText.length;
|
||||
// store text by appending to end of insertedText
|
||||
if (newText) {
|
||||
newText = newText + lineInfo.text;
|
||||
}
|
||||
else {
|
||||
newText = lineInfo.text;
|
||||
}
|
||||
newText = newText ? newText + lineText : lineText;
|
||||
}
|
||||
}
|
||||
if (pos < this.root.charCount()) {
|
||||
this.root.walk(pos, deleteLength, walker);
|
||||
walker.insertLines(newText, suppressTrailingText);
|
||||
}
|
||||
|
||||
this.root.walk(pos, deleteLength, walker);
|
||||
walker.insertLines(newText, suppressTrailingText);
|
||||
|
||||
if (this.checkEdits) {
|
||||
const updatedText = this.getText(0, this.root.charCount());
|
||||
const updatedText = walker.lineIndex.getText(0, walker.lineIndex.getLength());
|
||||
Debug.assert(checkText === updatedText, "buffer edit mismatch");
|
||||
}
|
||||
|
||||
return walker.lineIndex;
|
||||
}
|
||||
}
|
||||
|
||||
static buildTreeFromBottom(nodes: LineCollection[]): LineNode {
|
||||
const nodeCount = Math.ceil(nodes.length / lineCollectionCapacity);
|
||||
const interiorNodes: LineNode[] = [];
|
||||
private static buildTreeFromBottom(nodes: LineCollection[]): LineNode {
|
||||
if (nodes.length < lineCollectionCapacity) {
|
||||
return new LineNode(nodes);
|
||||
}
|
||||
|
||||
const interiorNodes = new Array<LineNode>(Math.ceil(nodes.length / lineCollectionCapacity));
|
||||
let nodeIndex = 0;
|
||||
for (let i = 0; i < nodeCount; i++) {
|
||||
interiorNodes[i] = new LineNode();
|
||||
let charCount = 0;
|
||||
let lineCount = 0;
|
||||
for (let j = 0; j < lineCollectionCapacity; j++) {
|
||||
if (nodeIndex < nodes.length) {
|
||||
interiorNodes[i].add(nodes[nodeIndex]);
|
||||
charCount += nodes[nodeIndex].charCount();
|
||||
lineCount += nodes[nodeIndex].lineCount();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
nodeIndex++;
|
||||
}
|
||||
interiorNodes[i].totalChars = charCount;
|
||||
interiorNodes[i].totalLines = lineCount;
|
||||
}
|
||||
if (interiorNodes.length === 1) {
|
||||
return interiorNodes[0];
|
||||
}
|
||||
else {
|
||||
return this.buildTreeFromBottom(interiorNodes);
|
||||
for (let i = 0; i < interiorNodes.length; i++) {
|
||||
const end = Math.min(nodeIndex + lineCollectionCapacity, nodes.length);
|
||||
interiorNodes[i] = new LineNode(nodes.slice(nodeIndex, end));
|
||||
nodeIndex = end;
|
||||
}
|
||||
return this.buildTreeFromBottom(interiorNodes);
|
||||
}
|
||||
|
||||
static linesFromText(text: string) {
|
||||
const lineMap = ts.computeLineStarts(text);
|
||||
const lineMap = computeLineStarts(text);
|
||||
|
||||
if (lineMap.length === 0) {
|
||||
return { lines: <string[]>[], lineMap };
|
||||
@@ -583,7 +564,10 @@ namespace ts.server {
|
||||
export class LineNode implements LineCollection {
|
||||
totalChars = 0;
|
||||
totalLines = 0;
|
||||
children: LineCollection[] = [];
|
||||
|
||||
constructor(private readonly children: LineCollection[] = []) {
|
||||
if (children.length) this.updateCounts();
|
||||
}
|
||||
|
||||
isLeaf() {
|
||||
return false;
|
||||
@@ -598,7 +582,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
execWalk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker, childIndex: number, nodeType: CharRangeSection) {
|
||||
private execWalk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker, childIndex: number, nodeType: CharRangeSection) {
|
||||
if (walkFns.pre) {
|
||||
walkFns.pre(rangeStart, rangeLength, this.children[childIndex], this, nodeType);
|
||||
}
|
||||
@@ -614,7 +598,7 @@ namespace ts.server {
|
||||
return walkFns.done;
|
||||
}
|
||||
|
||||
skipChild(relativeStart: number, relativeLength: number, childIndex: number, walkFns: ILineIndexWalker, nodeType: CharRangeSection) {
|
||||
private skipChild(relativeStart: number, relativeLength: number, childIndex: number, walkFns: ILineIndexWalker, nodeType: CharRangeSection) {
|
||||
if (walkFns.pre && (!walkFns.done)) {
|
||||
walkFns.pre(relativeStart, relativeLength, this.children[childIndex], this, nodeType);
|
||||
walkFns.goSubtree = true;
|
||||
@@ -624,16 +608,14 @@ namespace ts.server {
|
||||
walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker) {
|
||||
// assume (rangeStart < this.totalChars) && (rangeLength <= this.totalChars)
|
||||
let childIndex = 0;
|
||||
let child = this.children[0];
|
||||
let childCharCount = child.charCount();
|
||||
let childCharCount = this.children[childIndex].charCount();
|
||||
// find sub-tree containing start
|
||||
let adjustedStart = rangeStart;
|
||||
while (adjustedStart >= childCharCount) {
|
||||
this.skipChild(adjustedStart, rangeLength, childIndex, walkFns, CharRangeSection.PreStart);
|
||||
adjustedStart -= childCharCount;
|
||||
childIndex++;
|
||||
child = this.children[childIndex];
|
||||
childCharCount = child.charCount();
|
||||
childCharCount = this.children[childIndex].charCount();
|
||||
}
|
||||
// Case I: both start and end of range in same subtree
|
||||
if ((adjustedStart + rangeLength) <= childCharCount) {
|
||||
@@ -648,7 +630,7 @@ namespace ts.server {
|
||||
}
|
||||
let adjustedLength = rangeLength - (childCharCount - adjustedStart);
|
||||
childIndex++;
|
||||
child = this.children[childIndex];
|
||||
const child = this.children[childIndex];
|
||||
childCharCount = child.charCount();
|
||||
while (adjustedLength > childCharCount) {
|
||||
if (this.execWalk(0, childCharCount, walkFns, childIndex, CharRangeSection.Mid)) {
|
||||
@@ -656,8 +638,7 @@ namespace ts.server {
|
||||
}
|
||||
adjustedLength -= childCharCount;
|
||||
childIndex++;
|
||||
child = this.children[childIndex];
|
||||
childCharCount = child.charCount();
|
||||
childCharCount = this.children[childIndex].charCount();
|
||||
}
|
||||
if (adjustedLength > 0) {
|
||||
if (this.execWalk(0, adjustedLength, walkFns, childIndex, CharRangeSection.End)) {
|
||||
@@ -676,90 +657,88 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
charOffsetToLineNumberAndPos(lineNumber: number, charOffset: number): ILineInfo {
|
||||
const childInfo = this.childFromCharOffset(lineNumber, charOffset);
|
||||
// Input position is relative to the start of this node.
|
||||
// Output line number is absolute.
|
||||
charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number, zeroBasedColumn: number, lineText: string | undefined } {
|
||||
const childInfo = this.childFromCharOffset(lineNumberAccumulator, relativePosition);
|
||||
if (!childInfo.child) {
|
||||
return {
|
||||
line: lineNumber,
|
||||
offset: charOffset,
|
||||
oneBasedLine: lineNumberAccumulator,
|
||||
zeroBasedColumn: relativePosition,
|
||||
lineText: undefined,
|
||||
};
|
||||
}
|
||||
else if (childInfo.childIndex < this.children.length) {
|
||||
if (childInfo.child.isLeaf()) {
|
||||
return {
|
||||
line: childInfo.lineNumber,
|
||||
offset: childInfo.charOffset,
|
||||
text: (<LineLeaf>(childInfo.child)).text,
|
||||
leaf: (<LineLeaf>(childInfo.child))
|
||||
oneBasedLine: childInfo.lineNumberAccumulator,
|
||||
zeroBasedColumn: childInfo.relativePosition,
|
||||
lineText: childInfo.child.text,
|
||||
};
|
||||
}
|
||||
else {
|
||||
const lineNode = <LineNode>(childInfo.child);
|
||||
return lineNode.charOffsetToLineNumberAndPos(childInfo.lineNumber, childInfo.charOffset);
|
||||
return lineNode.charOffsetToLineInfo(childInfo.lineNumberAccumulator, childInfo.relativePosition);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const lineInfo = this.lineNumberToInfo(this.lineCount(), 0);
|
||||
return { line: this.lineCount(), offset: lineInfo.leaf.charCount() };
|
||||
return { oneBasedLine: this.lineCount(), zeroBasedColumn: lineInfo.leaf.charCount(), lineText: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
lineNumberToInfo(lineNumber: number, charOffset: number): ILineInfo {
|
||||
const childInfo = this.childFromLineNumber(lineNumber, charOffset);
|
||||
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
|
||||
const childInfo = this.childFromLineNumber(relativeOneBasedLine, positionAccumulator);
|
||||
if (!childInfo.child) {
|
||||
return {
|
||||
line: lineNumber,
|
||||
offset: charOffset
|
||||
};
|
||||
return { position: positionAccumulator, leaf: undefined };
|
||||
}
|
||||
else if (childInfo.child.isLeaf()) {
|
||||
return {
|
||||
line: lineNumber,
|
||||
offset: childInfo.charOffset,
|
||||
text: (<LineLeaf>(childInfo.child)).text,
|
||||
leaf: (<LineLeaf>(childInfo.child))
|
||||
};
|
||||
return { position: childInfo.positionAccumulator, leaf: childInfo.child };
|
||||
}
|
||||
else {
|
||||
const lineNode = <LineNode>(childInfo.child);
|
||||
return lineNode.lineNumberToInfo(childInfo.relativeLineNumber, childInfo.charOffset);
|
||||
return lineNode.lineNumberToInfo(childInfo.relativeOneBasedLine, childInfo.positionAccumulator);
|
||||
}
|
||||
}
|
||||
|
||||
childFromLineNumber(lineNumber: number, charOffset: number) {
|
||||
/**
|
||||
* Input line number is relative to the start of this node.
|
||||
* Output line number is relative to the child.
|
||||
* positionAccumulator will be an absolute position once relativeLineNumber reaches 0.
|
||||
*/
|
||||
private childFromLineNumber(relativeOneBasedLine: number, positionAccumulator: number): { child: LineCollection, relativeOneBasedLine: number, positionAccumulator: number } {
|
||||
let child: LineCollection;
|
||||
let relativeLineNumber = lineNumber;
|
||||
let i: number;
|
||||
let len: number;
|
||||
for (i = 0, len = this.children.length; i < len; i++) {
|
||||
for (i = 0; i < this.children.length; i++) {
|
||||
child = this.children[i];
|
||||
const childLineCount = child.lineCount();
|
||||
if (childLineCount >= relativeLineNumber) {
|
||||
if (childLineCount >= relativeOneBasedLine) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
relativeLineNumber -= childLineCount;
|
||||
charOffset += child.charCount();
|
||||
relativeOneBasedLine -= childLineCount;
|
||||
positionAccumulator += child.charCount();
|
||||
}
|
||||
}
|
||||
return { child, childIndex: i, relativeLineNumber, charOffset };
|
||||
return { child, relativeOneBasedLine, positionAccumulator };
|
||||
}
|
||||
|
||||
childFromCharOffset(lineNumber: number, charOffset: number) {
|
||||
private childFromCharOffset(lineNumberAccumulator: number, relativePosition: number
|
||||
): { child: LineCollection, childIndex: number, relativePosition: number, lineNumberAccumulator: number } {
|
||||
let child: LineCollection;
|
||||
let i: number;
|
||||
let len: number;
|
||||
for (i = 0, len = this.children.length; i < len; i++) {
|
||||
child = this.children[i];
|
||||
if (child.charCount() > charOffset) {
|
||||
if (child.charCount() > relativePosition) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
charOffset -= child.charCount();
|
||||
lineNumber += child.lineCount();
|
||||
relativePosition -= child.charCount();
|
||||
lineNumberAccumulator += child.lineCount();
|
||||
}
|
||||
}
|
||||
return { child, childIndex: i, charOffset, lineNumber };
|
||||
return { child, childIndex: i, relativePosition, lineNumberAccumulator };
|
||||
}
|
||||
|
||||
private splitAfter(childIndex: number) {
|
||||
|
||||
+13
-7
@@ -138,7 +138,7 @@ namespace ts.server {
|
||||
terminal: false,
|
||||
});
|
||||
|
||||
class Logger implements ts.server.Logger {
|
||||
class Logger implements server.Logger {
|
||||
private fd = -1;
|
||||
private seq = 0;
|
||||
private inGroup = false;
|
||||
@@ -526,12 +526,18 @@ namespace ts.server {
|
||||
if (err) {
|
||||
watchedFile.callback(watchedFile.fileName, FileWatcherEventKind.Changed);
|
||||
}
|
||||
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
|
||||
watchedFile.mtime = stats.mtime;
|
||||
const eventKind = watchedFile.mtime.getTime() === 0
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
watchedFile.callback(watchedFile.fileName, eventKind);
|
||||
else {
|
||||
const oldTime = watchedFile.mtime.getTime();
|
||||
const newTime = stats.mtime.getTime();
|
||||
if (oldTime !== newTime) {
|
||||
watchedFile.mtime = stats.mtime;
|
||||
const eventKind = oldTime === 0
|
||||
? FileWatcherEventKind.Created
|
||||
: newTime === 0
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
watchedFile.callback(watchedFile.fileName, eventKind);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+77
-89
@@ -49,7 +49,7 @@ namespace ts.server {
|
||||
|
||||
interface FileStart {
|
||||
file: string;
|
||||
start: ILineInfo;
|
||||
start: protocol.Location;
|
||||
}
|
||||
|
||||
function compareNumber(a: number, b: number) {
|
||||
@@ -72,28 +72,28 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
function formatDiag(fileName: NormalizedPath, project: Project, diag: ts.Diagnostic): protocol.Diagnostic {
|
||||
function formatDiag(fileName: NormalizedPath, project: Project, diag: Diagnostic): protocol.Diagnostic {
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(fileName);
|
||||
return {
|
||||
start: scriptInfo.positionToLineOffset(diag.start),
|
||||
end: scriptInfo.positionToLineOffset(diag.start + diag.length),
|
||||
text: ts.flattenDiagnosticMessageText(diag.messageText, "\n"),
|
||||
text: flattenDiagnosticMessageText(diag.messageText, "\n"),
|
||||
code: diag.code,
|
||||
category: DiagnosticCategory[diag.category].toLowerCase(),
|
||||
source: diag.source
|
||||
};
|
||||
}
|
||||
|
||||
function convertToILineInfo(lineAndCharacter: LineAndCharacter): ILineInfo {
|
||||
function convertToLocation(lineAndCharacter: LineAndCharacter): protocol.Location {
|
||||
return { line: lineAndCharacter.line + 1, offset: lineAndCharacter.character + 1 };
|
||||
}
|
||||
|
||||
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: true): protocol.DiagnosticWithFileName;
|
||||
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: false): protocol.Diagnostic;
|
||||
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName {
|
||||
const start = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start));
|
||||
const end = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
|
||||
const text = ts.flattenDiagnosticMessageText(diag.messageText, "\n");
|
||||
function formatConfigFileDiag(diag: Diagnostic, includeFileName: true): protocol.DiagnosticWithFileName;
|
||||
function formatConfigFileDiag(diag: Diagnostic, includeFileName: false): protocol.Diagnostic;
|
||||
function formatConfigFileDiag(diag: Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName {
|
||||
const start = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start));
|
||||
const end = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
|
||||
const text = flattenDiagnosticMessageText(diag.messageText, "\n");
|
||||
const { code, source } = diag;
|
||||
const category = DiagnosticCategory[diag.category].toLowerCase();
|
||||
return includeFileName ? { start, end, text, code, category, source, fileName: diag.file && diag.file.fileName } :
|
||||
@@ -389,8 +389,8 @@ namespace ts.server {
|
||||
this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine));
|
||||
}
|
||||
|
||||
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: ts.Diagnostic[]) {
|
||||
const bakedDiags = ts.map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
|
||||
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: Diagnostic[]) {
|
||||
const bakedDiags = map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
|
||||
const ev: protocol.ConfigFileDiagnosticEvent = {
|
||||
seq: 0,
|
||||
type: "event",
|
||||
@@ -547,8 +547,8 @@ namespace ts.server {
|
||||
length: d.length,
|
||||
category: DiagnosticCategory[d.category].toLowerCase(),
|
||||
code: d.code,
|
||||
startLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start)),
|
||||
endLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start + d.length))
|
||||
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
|
||||
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -607,7 +607,7 @@ namespace ts.server {
|
||||
return {
|
||||
file: def.fileName,
|
||||
start: defScriptInfo.positionToLineOffset(def.textSpan.start),
|
||||
end: defScriptInfo.positionToLineOffset(ts.textSpanEnd(def.textSpan))
|
||||
end: defScriptInfo.positionToLineOffset(textSpanEnd(def.textSpan))
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -631,7 +631,7 @@ namespace ts.server {
|
||||
return {
|
||||
file: def.fileName,
|
||||
start: defScriptInfo.positionToLineOffset(def.textSpan.start),
|
||||
end: defScriptInfo.positionToLineOffset(ts.textSpanEnd(def.textSpan))
|
||||
end: defScriptInfo.positionToLineOffset(textSpanEnd(def.textSpan))
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -649,7 +649,7 @@ namespace ts.server {
|
||||
return {
|
||||
file: fileName,
|
||||
start: scriptInfo.positionToLineOffset(textSpan.start),
|
||||
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan))
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan))
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -673,7 +673,7 @@ namespace ts.server {
|
||||
const { fileName, isWriteAccess, textSpan, isInString } = occurrence;
|
||||
const scriptInfo = project.getScriptInfo(fileName);
|
||||
const start = scriptInfo.positionToLineOffset(textSpan.start);
|
||||
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan));
|
||||
const end = scriptInfo.positionToLineOffset(textSpanEnd(textSpan));
|
||||
const result: protocol.OccurrencesResponseItem = {
|
||||
start,
|
||||
end,
|
||||
@@ -723,7 +723,7 @@ namespace ts.server {
|
||||
return documentHighlights;
|
||||
}
|
||||
|
||||
function convertToDocumentHighlightsItem(documentHighlights: ts.DocumentHighlights): ts.server.protocol.DocumentHighlightsItem {
|
||||
function convertToDocumentHighlightsItem(documentHighlights: DocumentHighlights): protocol.DocumentHighlightsItem {
|
||||
const { fileName, highlightSpans } = documentHighlights;
|
||||
|
||||
const scriptInfo = project.getScriptInfo(fileName);
|
||||
@@ -732,10 +732,10 @@ namespace ts.server {
|
||||
highlightSpans: highlightSpans.map(convertHighlightSpan)
|
||||
};
|
||||
|
||||
function convertHighlightSpan(highlightSpan: ts.HighlightSpan): ts.server.protocol.HighlightSpan {
|
||||
function convertHighlightSpan(highlightSpan: HighlightSpan): protocol.HighlightSpan {
|
||||
const { textSpan, kind } = highlightSpan;
|
||||
const start = scriptInfo.positionToLineOffset(textSpan.start);
|
||||
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan));
|
||||
const end = scriptInfo.positionToLineOffset(textSpanEnd(textSpan));
|
||||
return { start, end, kind };
|
||||
}
|
||||
}
|
||||
@@ -778,7 +778,7 @@ namespace ts.server {
|
||||
const scriptInfo = this.projectService.getScriptInfo(args.file);
|
||||
projects = scriptInfo.containingProjects;
|
||||
}
|
||||
// ts.filter handles case when 'projects' is undefined
|
||||
// filter handles case when 'projects' is undefined
|
||||
projects = filter(projects, p => p.languageServiceEnabled);
|
||||
if (!projects || !projects.length) {
|
||||
return Errors.ThrowNoProject();
|
||||
@@ -831,28 +831,29 @@ namespace ts.server {
|
||||
return <protocol.FileSpan>{
|
||||
file: location.fileName,
|
||||
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
|
||||
end: locationScriptInfo.positionToLineOffset(ts.textSpanEnd(location.textSpan)),
|
||||
end: locationScriptInfo.positionToLineOffset(textSpanEnd(location.textSpan)),
|
||||
};
|
||||
});
|
||||
},
|
||||
compareRenameLocation,
|
||||
(a, b) => a.file === b.file && a.start.line === b.start.line && a.start.offset === b.start.offset
|
||||
);
|
||||
const locs = fileSpans.reduce<protocol.SpanGroup[]>((accum, cur) => {
|
||||
|
||||
const locs: protocol.SpanGroup[] = [];
|
||||
for (const cur of fileSpans) {
|
||||
let curFileAccum: protocol.SpanGroup;
|
||||
if (accum.length > 0) {
|
||||
curFileAccum = accum[accum.length - 1];
|
||||
if (locs.length > 0) {
|
||||
curFileAccum = locs[locs.length - 1];
|
||||
if (curFileAccum.file !== cur.file) {
|
||||
curFileAccum = undefined;
|
||||
}
|
||||
}
|
||||
if (!curFileAccum) {
|
||||
curFileAccum = { file: cur.file, locs: [] };
|
||||
accum.push(curFileAccum);
|
||||
locs.push(curFileAccum);
|
||||
}
|
||||
curFileAccum.locs.push({ start: cur.start, end: cur.end });
|
||||
return accum;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return { info: renameInfo, locs };
|
||||
}
|
||||
@@ -912,10 +913,10 @@ namespace ts.server {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const displayString = ts.displayPartsToString(nameInfo.displayParts);
|
||||
const displayString = displayPartsToString(nameInfo.displayParts);
|
||||
const nameSpan = nameInfo.textSpan;
|
||||
const nameColStart = scriptInfo.positionToLineOffset(nameSpan.start).offset;
|
||||
const nameText = scriptInfo.getSnapshot().getText(nameSpan.start, ts.textSpanEnd(nameSpan));
|
||||
const nameText = scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan));
|
||||
const refs = combineProjectOutput<protocol.ReferencesResponseItem>(
|
||||
projects,
|
||||
(project: Project) => {
|
||||
@@ -928,12 +929,12 @@ namespace ts.server {
|
||||
const refScriptInfo = project.getScriptInfo(ref.fileName);
|
||||
const start = refScriptInfo.positionToLineOffset(ref.textSpan.start);
|
||||
const refLineSpan = refScriptInfo.lineToTextSpan(start.line - 1);
|
||||
const lineText = refScriptInfo.getSnapshot().getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
|
||||
const lineText = refScriptInfo.getSnapshot().getText(refLineSpan.start, textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
|
||||
return {
|
||||
file: ref.fileName,
|
||||
start,
|
||||
lineText,
|
||||
end: refScriptInfo.positionToLineOffset(ts.textSpanEnd(ref.textSpan)),
|
||||
end: refScriptInfo.positionToLineOffset(textSpanEnd(ref.textSpan)),
|
||||
isWriteAccess: ref.isWriteAccess,
|
||||
isDefinition: ref.isDefinition
|
||||
};
|
||||
@@ -1056,14 +1057,14 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
if (simplifiedResult) {
|
||||
const displayString = ts.displayPartsToString(quickInfo.displayParts);
|
||||
const docString = ts.displayPartsToString(quickInfo.documentation);
|
||||
const displayString = displayPartsToString(quickInfo.displayParts);
|
||||
const docString = displayPartsToString(quickInfo.documentation);
|
||||
|
||||
return {
|
||||
kind: quickInfo.kind,
|
||||
kindModifiers: quickInfo.kindModifiers,
|
||||
start: scriptInfo.positionToLineOffset(quickInfo.textSpan.start),
|
||||
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(quickInfo.textSpan)),
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(quickInfo.textSpan)),
|
||||
displayString,
|
||||
documentation: docString,
|
||||
tags: quickInfo.tags || []
|
||||
@@ -1123,32 +1124,29 @@ namespace ts.server {
|
||||
// only to the previous line. If all this is true, then
|
||||
// add edits necessary to properly indent the current line.
|
||||
if ((args.key === "\n") && ((!edits) || (edits.length === 0) || allEditsBeforePos(edits, position))) {
|
||||
const lineInfo = scriptInfo.getLineInfo(args.line);
|
||||
if (lineInfo && (lineInfo.leaf) && (lineInfo.leaf.text)) {
|
||||
const lineText = lineInfo.leaf.text;
|
||||
if (lineText.search("\\S") < 0) {
|
||||
const preferredIndent = project.getLanguageService(/*ensureSynchronized*/ false).getIndentationAtPosition(file, position, formatOptions);
|
||||
let hasIndent = 0;
|
||||
let i: number, len: number;
|
||||
for (i = 0, len = lineText.length; i < len; i++) {
|
||||
if (lineText.charAt(i) === " ") {
|
||||
hasIndent++;
|
||||
}
|
||||
else if (lineText.charAt(i) === "\t") {
|
||||
hasIndent += formatOptions.tabSize;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
const { lineText, absolutePosition } = scriptInfo.getLineInfo(args.line);
|
||||
if (lineText && lineText.search("\\S") < 0) {
|
||||
const preferredIndent = project.getLanguageService(/*ensureSynchronized*/ false).getIndentationAtPosition(file, position, formatOptions);
|
||||
let hasIndent = 0;
|
||||
let i: number, len: number;
|
||||
for (i = 0, len = lineText.length; i < len; i++) {
|
||||
if (lineText.charAt(i) === " ") {
|
||||
hasIndent++;
|
||||
}
|
||||
// i points to the first non whitespace character
|
||||
if (preferredIndent !== hasIndent) {
|
||||
const firstNoWhiteSpacePosition = lineInfo.offset + i;
|
||||
edits.push({
|
||||
span: ts.createTextSpanFromBounds(lineInfo.offset, firstNoWhiteSpacePosition),
|
||||
newText: formatting.getIndentationString(preferredIndent, formatOptions)
|
||||
});
|
||||
else if (lineText.charAt(i) === "\t") {
|
||||
hasIndent += formatOptions.tabSize;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// i points to the first non whitespace character
|
||||
if (preferredIndent !== hasIndent) {
|
||||
const firstNoWhiteSpacePosition = absolutePosition + i;
|
||||
edits.push({
|
||||
span: createTextSpanFromBounds(absolutePosition, firstNoWhiteSpacePosition),
|
||||
newText: formatting.getIndentationString(preferredIndent, formatOptions)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1160,7 +1158,7 @@ namespace ts.server {
|
||||
return edits.map((edit) => {
|
||||
return {
|
||||
start: scriptInfo.positionToLineOffset(edit.span.start),
|
||||
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(edit.span)),
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(edit.span)),
|
||||
newText: edit.newText ? edit.newText : ""
|
||||
};
|
||||
});
|
||||
@@ -1178,15 +1176,13 @@ namespace ts.server {
|
||||
return undefined;
|
||||
}
|
||||
if (simplifiedResult) {
|
||||
return completions.entries.reduce((result: protocol.CompletionEntry[], entry: ts.CompletionEntry) => {
|
||||
return mapDefined(completions.entries, entry => {
|
||||
if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) {
|
||||
const { name, kind, kindModifiers, sortText, replacementSpan } = entry;
|
||||
const convertedSpan: protocol.TextSpan =
|
||||
replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined;
|
||||
result.push({ name, kind, kindModifiers, sortText, replacementSpan: convertedSpan });
|
||||
const convertedSpan = replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined;
|
||||
return { name, kind, kindModifiers, sortText, replacementSpan: convertedSpan };
|
||||
}
|
||||
return result;
|
||||
}, []).sort((a, b) => ts.compareStrings(a.name, b.name));
|
||||
}).sort((a, b) => compareStrings(a.name, b.name));
|
||||
}
|
||||
else {
|
||||
return completions;
|
||||
@@ -1198,13 +1194,8 @@ namespace ts.server {
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
return args.entryNames.reduce((accum: protocol.CompletionEntryDetails[], entryName: string) => {
|
||||
const details = project.getLanguageService().getCompletionEntryDetails(file, position, entryName);
|
||||
if (details) {
|
||||
accum.push(details);
|
||||
}
|
||||
return accum;
|
||||
}, []);
|
||||
return mapDefined(args.entryNames, entryName =>
|
||||
project.getLanguageService().getCompletionEntryDetails(file, position, entryName));
|
||||
}
|
||||
|
||||
private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): protocol.CompileOnSaveAffectedFileListSingleProject[] {
|
||||
@@ -1269,14 +1260,11 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private getDiagnostics(next: NextStep, delay: number, fileNames: string[]): void {
|
||||
const checkList = fileNames.reduce((accum: PendingErrorCheck[], uncheckedFileName: string) => {
|
||||
const checkList = mapDefined(fileNames, uncheckedFileName => {
|
||||
const fileName = toNormalizedPath(uncheckedFileName);
|
||||
const project = this.projectService.getDefaultProjectForFile(fileName, /*refreshInferredProjects*/ true);
|
||||
if (project) {
|
||||
accum.push({ fileName, project });
|
||||
}
|
||||
return accum;
|
||||
}, []);
|
||||
return project && { fileName, project };
|
||||
});
|
||||
|
||||
if (checkList.length > 0) {
|
||||
this.updateErrorCheck(next, checkList, this.changeSeq, (n) => n === this.changeSeq, delay);
|
||||
@@ -1321,11 +1309,11 @@ namespace ts.server {
|
||||
if (!fileName) {
|
||||
return;
|
||||
}
|
||||
const file = ts.normalizePath(fileName);
|
||||
const file = normalizePath(fileName);
|
||||
this.projectService.closeClientFile(file);
|
||||
}
|
||||
|
||||
private decorateNavigationBarItems(items: ts.NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] {
|
||||
private decorateNavigationBarItems(items: NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] {
|
||||
return map(items, item => ({
|
||||
text: item.text,
|
||||
kind: item.kind,
|
||||
@@ -1346,7 +1334,7 @@ namespace ts.server {
|
||||
: items;
|
||||
}
|
||||
|
||||
private decorateNavigationTree(tree: ts.NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree {
|
||||
private decorateNavigationTree(tree: NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree {
|
||||
return {
|
||||
text: tree.text,
|
||||
kind: tree.kind,
|
||||
@@ -1359,7 +1347,7 @@ namespace ts.server {
|
||||
private decorateSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
|
||||
return {
|
||||
start: scriptInfo.positionToLineOffset(span.start),
|
||||
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(span))
|
||||
end: scriptInfo.positionToLineOffset(textSpanEnd(span))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1389,7 +1377,7 @@ namespace ts.server {
|
||||
return navItems.map((navItem) => {
|
||||
const scriptInfo = project.getScriptInfo(navItem.fileName);
|
||||
const start = scriptInfo.positionToLineOffset(navItem.textSpan.start);
|
||||
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(navItem.textSpan));
|
||||
const end = scriptInfo.positionToLineOffset(textSpanEnd(navItem.textSpan));
|
||||
const bakedItem: protocol.NavtoItem = {
|
||||
name: navItem.name,
|
||||
kind: navItem.kind,
|
||||
@@ -1454,7 +1442,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private getSupportedCodeFixes(): string[] {
|
||||
return ts.getSupportedCodeFixes();
|
||||
return getSupportedCodeFixes();
|
||||
}
|
||||
|
||||
private isLocation(locationOrSpan: protocol.FileLocationOrRangeRequestArgs): locationOrSpan is protocol.FileLocationRequestArgs {
|
||||
@@ -1485,7 +1473,7 @@ namespace ts.server {
|
||||
return project.getLanguageService().getApplicableRefactors(file, position || textRange);
|
||||
}
|
||||
|
||||
private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): ts.RefactorEditInfo | protocol.RefactorEditInfo {
|
||||
private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): RefactorEditInfo | protocol.RefactorEditInfo {
|
||||
const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const { position, textRange } = this.extractPositionAndRange(args, scriptInfo);
|
||||
@@ -1506,7 +1494,7 @@ namespace ts.server {
|
||||
|
||||
if (simplifiedResult) {
|
||||
const file = result.renameFilename;
|
||||
let location: ILineInfo | undefined = undefined;
|
||||
let location: protocol.Location | undefined;
|
||||
if (file !== undefined && result.renameLocation !== undefined) {
|
||||
const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(file));
|
||||
location = renameScriptInfo.positionToLineOffset(result.renameLocation);
|
||||
@@ -1654,7 +1642,7 @@ namespace ts.server {
|
||||
|
||||
getCanonicalFileName(fileName: string) {
|
||||
const name = this.host.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return ts.normalizePath(name);
|
||||
return normalizePath(name);
|
||||
}
|
||||
|
||||
exit() {
|
||||
|
||||
+5
-5
@@ -31,9 +31,9 @@ declare namespace ts.server {
|
||||
|
||||
export interface DiscoverTypings extends TypingInstallerRequest {
|
||||
readonly fileNames: string[];
|
||||
readonly projectRootPath: ts.Path;
|
||||
readonly compilerOptions: ts.CompilerOptions;
|
||||
readonly typeAcquisition: ts.TypeAcquisition;
|
||||
readonly projectRootPath: Path;
|
||||
readonly compilerOptions: CompilerOptions;
|
||||
readonly typeAcquisition: TypeAcquisition;
|
||||
readonly unresolvedImports: SortedReadonlyArray<string>;
|
||||
readonly cachePath?: string;
|
||||
readonly kind: "discover";
|
||||
@@ -63,8 +63,8 @@ declare namespace ts.server {
|
||||
}
|
||||
|
||||
export interface SetTypings extends ProjectResponse {
|
||||
readonly typeAcquisition: ts.TypeAcquisition;
|
||||
readonly compilerOptions: ts.CompilerOptions;
|
||||
readonly typeAcquisition: TypeAcquisition;
|
||||
readonly compilerOptions: CompilerOptions;
|
||||
readonly typings: string[];
|
||||
readonly unresolvedImports: SortedReadonlyArray<string>;
|
||||
readonly kind: ActionSet;
|
||||
|
||||
@@ -145,6 +145,7 @@ namespace ts.server.typingsInstaller {
|
||||
|
||||
const discoverTypingsResult = JsTyping.discoverTypings(
|
||||
this.installTypingHost,
|
||||
this.log.isEnabled() ? this.log.writeLine : undefined,
|
||||
req.fileNames,
|
||||
req.projectRootPath,
|
||||
this.safeListPath,
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace ts.server {
|
||||
tabSize: 4,
|
||||
newLineCharacter: host.newLine || "\n",
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
indentStyle: IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
@@ -196,7 +196,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
export function enumerateInsertsAndDeletes<T>(a: SortedReadonlyArray<T>, b: SortedReadonlyArray<T>, inserted: (item: T) => void, deleted: (item: T) => void, compare?: (a: T, b: T) => Comparison) {
|
||||
compare = compare || ts.compareValues;
|
||||
compare = compare || compareValues;
|
||||
let aIndex = 0;
|
||||
let bIndex = 0;
|
||||
const aLen = a.length;
|
||||
|
||||
@@ -25,15 +25,15 @@ namespace ts.codefix {
|
||||
return [deleteNode(token.parent)];
|
||||
|
||||
default:
|
||||
return [deleteDefault()];
|
||||
return deleteDefault();
|
||||
}
|
||||
|
||||
function deleteDefault() {
|
||||
function deleteDefault(): CodeAction[] | undefined {
|
||||
if (isDeclarationName(token)) {
|
||||
return deleteNode(token.parent);
|
||||
return [deleteNode(token.parent)];
|
||||
}
|
||||
else if (isLiteralComputedPropertyDeclarationName(token)) {
|
||||
return deleteNode(token.parent.parent);
|
||||
return [deleteNode(token.parent.parent)];
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
@@ -87,20 +87,16 @@ namespace ts.codefix {
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
const namedImports = <NamedImports>parent.parent;
|
||||
if (namedImports.elements.length === 1) {
|
||||
// Only 1 import and it is unused. So the entire declaration should be removed.
|
||||
const importSpec = getAncestor(identifier, SyntaxKind.ImportDeclaration);
|
||||
return [deleteNode(importSpec)];
|
||||
return deleteNamedImportBinding(namedImports);
|
||||
}
|
||||
else {
|
||||
// delete import specifier
|
||||
return [deleteNodeInList(parent)];
|
||||
}
|
||||
|
||||
// handle case where "import d, * as ns from './file'"
|
||||
// or "'import {a, b as ns} from './file'"
|
||||
case SyntaxKind.ImportClause: // this covers both 'import |d|' and 'import |d,| *'
|
||||
const importClause = <ImportClause>parent;
|
||||
if (!importClause.namedBindings) { // |import d from './file'| or |import * as ns from './file'|
|
||||
if (!importClause.namedBindings) { // |import d from './file'|
|
||||
const importDecl = getAncestor(importClause, SyntaxKind.ImportDeclaration);
|
||||
return [deleteNode(importDecl)];
|
||||
}
|
||||
@@ -118,22 +114,30 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
case SyntaxKind.NamespaceImport:
|
||||
const namespaceImport = <NamespaceImport>parent;
|
||||
if (namespaceImport.name === identifier && !(<ImportClause>namespaceImport.parent).name) {
|
||||
const importDecl = getAncestor(namespaceImport, SyntaxKind.ImportDeclaration);
|
||||
return [deleteNode(importDecl)];
|
||||
}
|
||||
else {
|
||||
const previousToken = getTokenAtPosition(sourceFile, namespaceImport.pos - 1, /*includeJsDocComment*/ false);
|
||||
if (previousToken && previousToken.kind === SyntaxKind.CommaToken) {
|
||||
const startPosition = textChanges.getAdjustedStartPosition(sourceFile, previousToken, {}, textChanges.Position.FullStart);
|
||||
return [deleteRange({ pos: startPosition, end: namespaceImport.end })];
|
||||
}
|
||||
return [deleteRange(namespaceImport)];
|
||||
}
|
||||
return deleteNamedImportBinding(<NamespaceImport>parent);
|
||||
|
||||
default:
|
||||
return [deleteDefault()];
|
||||
return deleteDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function deleteNamedImportBinding(namedBindings: NamedImportBindings): CodeAction[] | undefined {
|
||||
if ((<ImportClause>namedBindings.parent).name) {
|
||||
// Delete named imports while preserving the default import
|
||||
// import d|, * as ns| from './file'
|
||||
// import d|, { a }| from './file'
|
||||
const previousToken = getTokenAtPosition(sourceFile, namedBindings.pos - 1, /*includeJsDocComment*/ false);
|
||||
if (previousToken && previousToken.kind === SyntaxKind.CommaToken) {
|
||||
return [deleteRange({ pos: previousToken.getStart(), end: namedBindings.end })];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
// Delete the entire import declaration
|
||||
// |import * as ns from './file'|
|
||||
// |import { a } from './file'|
|
||||
const importDecl = getAncestor(namedBindings, SyntaxKind.ImportDeclaration);
|
||||
return [deleteNode(importDecl)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,10 +222,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
function getUniqueSymbolId(symbol: Symbol) {
|
||||
if (symbol.flags & SymbolFlags.Alias) {
|
||||
return getSymbolId(checker.getAliasedSymbol(symbol));
|
||||
}
|
||||
return getSymbolId(symbol);
|
||||
return getSymbolId(skipAlias(symbol, checker));
|
||||
}
|
||||
|
||||
function checkSymbolHasMeaning(symbol: Symbol, meaning: SemanticMeaning) {
|
||||
|
||||
+91
-105
@@ -57,11 +57,11 @@ namespace ts.Completions {
|
||||
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log);
|
||||
addRange(entries, getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames, compilerOptions.target));
|
||||
getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames, compilerOptions.target, entries);
|
||||
}
|
||||
else {
|
||||
if ((!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) {
|
||||
return undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log);
|
||||
@@ -79,40 +79,41 @@ namespace ts.Completions {
|
||||
return { isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, entries };
|
||||
}
|
||||
|
||||
function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map<true>, target: ScriptTarget): CompletionEntry[] {
|
||||
const entries: CompletionEntry[] = [];
|
||||
|
||||
const nameTable = getNameTable(sourceFile);
|
||||
nameTable.forEach((pos, name) => {
|
||||
function getJavaScriptCompletionEntries(
|
||||
sourceFile: SourceFile,
|
||||
position: number,
|
||||
uniqueNames: Map<true>,
|
||||
target: ScriptTarget,
|
||||
entries: Push<CompletionEntry>): void {
|
||||
getNameTable(sourceFile).forEach((pos, name) => {
|
||||
// Skip identifiers produced only from the current location
|
||||
if (pos === position) {
|
||||
return;
|
||||
}
|
||||
const realName = unescapeLeadingUnderscores(name);
|
||||
|
||||
if (!uniqueNames.get(realName)) {
|
||||
uniqueNames.set(realName, true);
|
||||
const displayName = getCompletionEntryDisplayName(realName, target, /*performCharacterChecks*/ true);
|
||||
if (displayName) {
|
||||
const entry = {
|
||||
name: displayName,
|
||||
kind: ScriptElementKind.warning,
|
||||
kindModifiers: "",
|
||||
sortText: "1"
|
||||
};
|
||||
entries.push(entry);
|
||||
}
|
||||
if (uniqueNames.has(realName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uniqueNames.set(realName, true);
|
||||
const displayName = getCompletionEntryDisplayName(realName, target, /*performCharacterChecks*/ true);
|
||||
if (displayName) {
|
||||
entries.push({
|
||||
name: displayName,
|
||||
kind: ScriptElementKind.warning,
|
||||
kindModifiers: "",
|
||||
sortText: "1"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
function createCompletionEntry(symbol: Symbol, location: Node, performCharacterChecks: boolean, typeChecker: TypeChecker, target: ScriptTarget): CompletionEntry {
|
||||
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
|
||||
// We would like to only show things that can be added after a dot, so for instance numeric properties can
|
||||
// not be accessed with a dot (a.1 <- invalid)
|
||||
const displayName = getCompletionEntryDisplayNameForSymbol(typeChecker, symbol, target, performCharacterChecks, location);
|
||||
const displayName = getCompletionEntryDisplayNameForSymbol(symbol, target, performCharacterChecks);
|
||||
if (!displayName) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -141,7 +142,7 @@ namespace ts.Completions {
|
||||
const entry = createCompletionEntry(symbol, location, performCharacterChecks, typeChecker, target);
|
||||
if (entry) {
|
||||
const id = entry.name;
|
||||
if (!uniqueNames.get(id)) {
|
||||
if (!uniqueNames.has(id)) {
|
||||
entries.push(entry);
|
||||
uniqueNames.set(id, true);
|
||||
}
|
||||
@@ -307,7 +308,7 @@ namespace ts.Completions {
|
||||
// We don't need to perform character checks here because we're only comparing the
|
||||
// name against 'entryName' (which is known to be good), not building a new
|
||||
// completion entry.
|
||||
const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined);
|
||||
const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false) === entryName ? s : undefined);
|
||||
|
||||
if (symbol) {
|
||||
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
|
||||
@@ -341,20 +342,14 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getCompletionEntrySymbol(typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number, entryName: string): Symbol {
|
||||
export function getCompletionEntrySymbol(typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number, entryName: string): Symbol | undefined {
|
||||
// Compute all the completion symbols again.
|
||||
const completionData = getCompletionData(typeChecker, log, sourceFile, position);
|
||||
if (completionData) {
|
||||
const { symbols, location } = completionData;
|
||||
|
||||
// Find the symbol with the matching entry name.
|
||||
// We don't need to perform character checks here because we're only comparing the
|
||||
// name against 'entryName' (which is known to be good), not building a new
|
||||
// completion entry.
|
||||
return forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
// Find the symbol with the matching entry name.
|
||||
// We don't need to perform character checks here because we're only comparing the
|
||||
// name against 'entryName' (which is known to be good), not building a new
|
||||
// completion entry.
|
||||
return completionData && forEach(completionData.symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false) === entryName ? s : undefined);
|
||||
}
|
||||
|
||||
interface CompletionData {
|
||||
@@ -369,7 +364,7 @@ namespace ts.Completions {
|
||||
}
|
||||
type Request = { kind: "JsDocTagName" } | { kind: "JsDocTag" } | { kind: "JsDocParameterName", tag: JSDocParameterTag };
|
||||
|
||||
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number): CompletionData {
|
||||
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number): CompletionData | undefined {
|
||||
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
|
||||
|
||||
let request: Request | undefined;
|
||||
@@ -601,58 +596,60 @@ namespace ts.Completions {
|
||||
isNewIdentifierLocation = false;
|
||||
|
||||
// Since this is qualified name check its a type node location
|
||||
const isTypeLocation = isPartOfTypeNode(node.parent) || insideJsDocTagTypeExpression;
|
||||
const isTypeLocation = insideJsDocTagTypeExpression || isPartOfTypeNode(node.parent);
|
||||
const isRhsOfImportDeclaration = isInRightSideOfInternalImportEqualsDeclaration(node);
|
||||
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
if (isEntityName(node)) {
|
||||
let symbol = typeChecker.getSymbolAtLocation(node);
|
||||
if (symbol) {
|
||||
symbol = skipAlias(symbol, typeChecker);
|
||||
|
||||
// This is an alias, follow what it aliases
|
||||
if (symbol && symbol.flags & SymbolFlags.Alias) {
|
||||
symbol = typeChecker.getAliasedSymbol(symbol);
|
||||
}
|
||||
|
||||
if (symbol && symbol.flags & SymbolFlags.HasExports) {
|
||||
// Extract module or enum members
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName());
|
||||
const isValidTypeAccess = (symbol: Symbol) => symbolCanbeReferencedAtTypeLocation(symbol);
|
||||
const isValidAccess = isRhsOfImportDeclaration ?
|
||||
// Any kind is allowed when dotting off namespace in internal import equals declaration
|
||||
(symbol: Symbol) => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
|
||||
isTypeLocation ? isValidTypeAccess : isValidValueAccess;
|
||||
forEach(exportedSymbols, symbol => {
|
||||
if (isValidAccess(symbol)) {
|
||||
symbols.push(symbol);
|
||||
if (symbol.flags & (SymbolFlags.Module | SymbolFlags.Enum)) {
|
||||
// Extract module or enum members
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName());
|
||||
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
|
||||
const isValidAccess = isRhsOfImportDeclaration ?
|
||||
// Any kind is allowed when dotting off namespace in internal import equals declaration
|
||||
(symbol: Symbol) => isValidTypeAccess(symbol) || isValidValueAccess(symbol) :
|
||||
isTypeLocation ? isValidTypeAccess : isValidValueAccess;
|
||||
for (const symbol of exportedSymbols) {
|
||||
if (isValidAccess(symbol)) {
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// If the module is merged with a value, we must get the type of the class and add its propertes (for inherited static methods).
|
||||
if (!isTypeLocation && symbol.declarations.some(d => d.kind !== SyntaxKind.SourceFile && d.kind !== SyntaxKind.ModuleDeclaration && d.kind !== SyntaxKind.EnumDeclaration)) {
|
||||
addTypeProperties(typeChecker.getTypeOfSymbolAtLocation(symbol, node));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTypeLocation) {
|
||||
const type = typeChecker.getTypeAtLocation(node);
|
||||
addTypeProperties(type);
|
||||
addTypeProperties(typeChecker.getTypeAtLocation(node));
|
||||
}
|
||||
}
|
||||
|
||||
function addTypeProperties(type: Type) {
|
||||
if (type) {
|
||||
// Filter private properties
|
||||
for (const symbol of type.getApparentProperties()) {
|
||||
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName())) {
|
||||
symbols.push(symbol);
|
||||
}
|
||||
// Filter private properties
|
||||
for (const symbol of type.getApparentProperties()) {
|
||||
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.getUnescapedName())) {
|
||||
symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
if (isJavaScriptFile && type.flags & TypeFlags.Union) {
|
||||
// In javascript files, for union types, we don't just get the members that
|
||||
// the individual types have in common, we also include all the members that
|
||||
// each individual type has. This is because we're going to add all identifiers
|
||||
// anyways. So we might as well elevate the members that were at least part
|
||||
// of the individual types to a higher status since we know what they are.
|
||||
const unionType = <UnionType>type;
|
||||
for (const elementType of unionType.types) {
|
||||
addTypeProperties(elementType);
|
||||
}
|
||||
if (isJavaScriptFile && type.flags & TypeFlags.Union) {
|
||||
// In javascript files, for union types, we don't just get the members that
|
||||
// the individual types have in common, we also include all the members that
|
||||
// each individual type has. This is because we're going to add all identifiers
|
||||
// anyways. So we might as well elevate the members that were at least part
|
||||
// of the individual types to a higher status since we know what they are.
|
||||
const unionType = <UnionType>type;
|
||||
for (const elementType of unionType.types) {
|
||||
addTypeProperties(elementType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -777,12 +774,12 @@ namespace ts.Completions {
|
||||
(!isContextTokenValueLocation(contextToken) &&
|
||||
(isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken)))) {
|
||||
// Its a type, but you can reach it by namespace.type as well
|
||||
return symbolCanbeReferencedAtTypeLocation(symbol);
|
||||
return symbolCanBeReferencedAtTypeLocation(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
// expressions are value space (which includes the value namespaces)
|
||||
return !!(symbol.flags & SymbolFlags.Value);
|
||||
return !!(getCombinedLocalAndExportSymbolFlags(symbol) & SymbolFlags.Value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -812,21 +809,21 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function symbolCanbeReferencedAtTypeLocation(symbol: Symbol): boolean {
|
||||
function symbolCanBeReferencedAtTypeLocation(symbol: Symbol): boolean {
|
||||
symbol = symbol.exportSymbol || symbol;
|
||||
|
||||
// This is an alias, follow what it aliases
|
||||
if (symbol && symbol.flags & SymbolFlags.Alias) {
|
||||
symbol = typeChecker.getAliasedSymbol(symbol);
|
||||
}
|
||||
symbol = skipAlias(symbol, typeChecker);
|
||||
|
||||
if (symbol.flags & SymbolFlags.Type) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule)) {
|
||||
if (symbol.flags & SymbolFlags.Module) {
|
||||
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
|
||||
// If the exported symbols contains type,
|
||||
// symbol can be referenced at locations where type is allowed
|
||||
return forEach(exportedSymbols, symbolCanbeReferencedAtTypeLocation);
|
||||
return forEach(exportedSymbols, symbolCanBeReferencedAtTypeLocation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1598,22 +1595,23 @@ namespace ts.Completions {
|
||||
/**
|
||||
* Get the name to be display in completion from a given symbol.
|
||||
*
|
||||
* @return undefined if the name is of external module otherwise a name with striped of any quote
|
||||
* @return undefined if the name is of external module
|
||||
*/
|
||||
function getCompletionEntryDisplayNameForSymbol(typeChecker: TypeChecker, symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean, location: Node): string {
|
||||
const displayName: string = getDeclaredName(typeChecker, symbol, location);
|
||||
function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string | undefined {
|
||||
const name = symbol.getUnescapedName();
|
||||
if (!name) return undefined;
|
||||
|
||||
if (displayName) {
|
||||
const firstCharCode = displayName.charCodeAt(0);
|
||||
// First check of the displayName is not external module; if it is an external module, it is not valid entry
|
||||
if ((symbol.flags & SymbolFlags.Namespace) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
|
||||
// First check of the displayName is not external module; if it is an external module, it is not valid entry
|
||||
if (symbol.flags & SymbolFlags.Namespace) {
|
||||
const firstCharCode = name.charCodeAt(0);
|
||||
if (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote) {
|
||||
// If the symbol is external module, don't show it in the completion list
|
||||
// (i.e declare module "http" { const x; } | // <= request completion here, "http" should not be there)
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return getCompletionEntryDisplayName(displayName, target, performCharacterChecks);
|
||||
return getCompletionEntryDisplayName(name, target, performCharacterChecks);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1621,24 +1619,12 @@ namespace ts.Completions {
|
||||
* and checking whether the name is valid identifier name.
|
||||
*/
|
||||
function getCompletionEntryDisplayName(name: string, target: ScriptTarget, performCharacterChecks: boolean): string {
|
||||
if (!name) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
name = stripQuotes(name);
|
||||
|
||||
if (!name) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
|
||||
// invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
|
||||
// e.g "b a" is valid quoted name but when we strip off the quotes, it is invalid.
|
||||
// We, thus, need to check if whatever was inside the quotes is actually a valid identifier name.
|
||||
if (performCharacterChecks) {
|
||||
if (!isIdentifierText(name, target)) {
|
||||
return undefined;
|
||||
}
|
||||
if (performCharacterChecks && !isIdentifierText(name, target)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return name;
|
||||
|
||||
@@ -440,7 +440,7 @@ namespace ts.FindAllReferences {
|
||||
|
||||
function getExport(): ExportedSymbol | ImportedSymbol | undefined {
|
||||
const parent = node.parent!;
|
||||
if (symbol.flags & SymbolFlags.Export) {
|
||||
if (symbol.exportSymbol) {
|
||||
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
// When accessing an export of a JS module, there's no alias. The symbol will still be flagged as an export even though we're at the use.
|
||||
// So check that we are at the declaration.
|
||||
@@ -449,9 +449,7 @@ namespace ts.FindAllReferences {
|
||||
: undefined;
|
||||
}
|
||||
else {
|
||||
const { exportSymbol } = symbol;
|
||||
Debug.assert(!!exportSymbol);
|
||||
return exportInfo(exportSymbol, getExportKindForDeclaration(parent));
|
||||
return exportInfo(symbol.exportSymbol, getExportKindForDeclaration(parent));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace ts.JsTyping {
|
||||
directoryExists: (path: string) => boolean;
|
||||
fileExists: (fileName: string) => boolean;
|
||||
readFile: (path: string, encoding?: string) => string;
|
||||
readDirectory: (rootDir: string, extensions: string[], excludes: string[], includes: string[], depth?: number) => string[];
|
||||
readDirectory: (rootDir: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string>, includes: ReadonlyArray<string>, depth?: number) => string[];
|
||||
}
|
||||
|
||||
interface PackageJson {
|
||||
@@ -51,6 +51,7 @@ namespace ts.JsTyping {
|
||||
*/
|
||||
export function discoverTypings(
|
||||
host: TypingResolutionHost,
|
||||
log: ((message: string) => void) | undefined,
|
||||
fileNames: string[],
|
||||
projectRootPath: Path,
|
||||
safeListPath: Path,
|
||||
@@ -107,8 +108,9 @@ namespace ts.JsTyping {
|
||||
|
||||
// add typings for unresolved imports
|
||||
if (unresolvedImports) {
|
||||
for (const moduleId of unresolvedImports) {
|
||||
const typingName = nodeCoreModules.has(moduleId) ? "node" : moduleId;
|
||||
const x = unresolvedImports.map(moduleId => nodeCoreModules.has(moduleId) ? "node" : moduleId);
|
||||
if (x.length && log) log(`Inferred typings from unresolved imports: ${JSON.stringify(x)}`);
|
||||
for (const typingName of x) {
|
||||
if (!inferredTypings.has(typingName)) {
|
||||
inferredTypings.set(typingName, undefined);
|
||||
}
|
||||
@@ -136,7 +138,9 @@ namespace ts.JsTyping {
|
||||
newTypingNames.push(typing);
|
||||
}
|
||||
});
|
||||
return { cachedTypingPaths, newTypingNames, filesToWatch };
|
||||
const result = { cachedTypingPaths, newTypingNames, filesToWatch };
|
||||
if (log) log(`Result: ${JSON.stringify(result)}`);
|
||||
return result;
|
||||
|
||||
function addInferredTyping(typingName: string) {
|
||||
if (!inferredTypings.has(typingName)) {
|
||||
@@ -153,6 +157,7 @@ namespace ts.JsTyping {
|
||||
}
|
||||
|
||||
filesToWatch.push(jsonPath);
|
||||
if (log) log(`Searching for typing names in '${jsonPath}' dependencies`);
|
||||
const jsonConfig: PackageJson = readConfigFile(jsonPath, (path: string) => host.readFile(path)).config;
|
||||
addInferredTypingsFromKeys(jsonConfig.dependencies);
|
||||
addInferredTypingsFromKeys(jsonConfig.devDependencies);
|
||||
@@ -175,19 +180,23 @@ namespace ts.JsTyping {
|
||||
* @param fileNames are the names for source files in the project
|
||||
*/
|
||||
function getTypingNamesFromSourceFileNames(fileNames: string[]) {
|
||||
for (const j of fileNames) {
|
||||
if (!hasJavaScriptFileExtension(j)) continue;
|
||||
const fromFileNames = mapDefined(fileNames, j => {
|
||||
if (!hasJavaScriptFileExtension(j)) return undefined;
|
||||
|
||||
const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase()));
|
||||
const cleanedTypingName = inferredTypingName.replace(/((?:\.|-)min(?=\.|$))|((?:-|\.)\d+)/g, "");
|
||||
const safe = safeList.get(cleanedTypingName);
|
||||
if (safe !== undefined) {
|
||||
return safeList.get(cleanedTypingName);
|
||||
});
|
||||
if (fromFileNames.length) {
|
||||
if (log) log(`Inferred typings from file names: ${JSON.stringify(fromFileNames)}`);
|
||||
for (const safe of fromFileNames) {
|
||||
addInferredTyping(safe);
|
||||
}
|
||||
}
|
||||
|
||||
const hasJsxFile = some(fileNames, f => fileExtensionIs(f, Extension.Jsx));
|
||||
if (hasJsxFile) {
|
||||
if (log) log(`Inferred 'react' typings due to presence of '.jsx' extension`);
|
||||
addInferredTyping("react");
|
||||
}
|
||||
}
|
||||
@@ -206,6 +215,7 @@ namespace ts.JsTyping {
|
||||
|
||||
// depth of 2, so we access `node_modules/foo` but not `node_modules/foo/bar`
|
||||
const fileNames = host.readDirectory(packagesFolderPath, [".json"], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 2);
|
||||
if (log) log(`Searching for typing names in ${packagesFolderPath}; all files: ${JSON.stringify(fileNames)}`);
|
||||
for (const fileName of fileNames) {
|
||||
const normalizedFileName = normalizePath(fileName);
|
||||
const baseFileName = getBaseFileName(normalizedFileName);
|
||||
|
||||
@@ -40,19 +40,14 @@ namespace ts.Completions.PathCompletions {
|
||||
rootDirs = map(rootDirs, rootDirectory => normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory)));
|
||||
|
||||
// Determine the path to the directory containing the script relative to the root directory it is contained within
|
||||
let relativeDirectory: string;
|
||||
for (const rootDirectory of rootDirs) {
|
||||
if (containsPath(rootDirectory, scriptPath, basePath, ignoreCase)) {
|
||||
relativeDirectory = scriptPath.substr(rootDirectory.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const relativeDirectory = forEach(rootDirs, rootDirectory =>
|
||||
containsPath(rootDirectory, scriptPath, basePath, ignoreCase) ? scriptPath.substr(rootDirectory.length) : undefined);
|
||||
|
||||
// Now find a path for each potential directory that is to be merged with the one containing the script
|
||||
return deduplicate(map(rootDirs, rootDirectory => combinePaths(rootDirectory, relativeDirectory)));
|
||||
}
|
||||
|
||||
function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptPath: string, extensions: string[], includeExtensions: boolean, span: TextSpan, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude?: string): CompletionEntry[] {
|
||||
function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptPath: string, extensions: ReadonlyArray<string>, includeExtensions: boolean, span: TextSpan, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude?: string): CompletionEntry[] {
|
||||
const basePath = compilerOptions.project || host.getCurrentDirectory();
|
||||
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
|
||||
const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptPath, ignoreCase);
|
||||
@@ -69,7 +64,7 @@ namespace ts.Completions.PathCompletions {
|
||||
/**
|
||||
* Given a path ending at a directory, gets the completions for the path, and filters for those entries containing the basename.
|
||||
*/
|
||||
function getCompletionEntriesForDirectoryFragment(fragment: string, scriptPath: string, extensions: string[], includeExtensions: boolean, span: TextSpan, host: LanguageServiceHost, exclude?: string, result: CompletionEntry[] = []): CompletionEntry[] {
|
||||
function getCompletionEntriesForDirectoryFragment(fragment: string, scriptPath: string, extensions: ReadonlyArray<string>, includeExtensions: boolean, span: TextSpan, host: LanguageServiceHost, exclude?: string, result: CompletionEntry[] = []): CompletionEntry[] {
|
||||
if (fragment === undefined) {
|
||||
fragment = "";
|
||||
}
|
||||
@@ -190,7 +185,7 @@ namespace ts.Completions.PathCompletions {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: string[], host: LanguageServiceHost): string[] {
|
||||
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: ReadonlyArray<string>, host: LanguageServiceHost): string[] {
|
||||
if (host.readDirectory) {
|
||||
const parsed = hasZeroOrOneAsteriskCharacter(pattern) ? tryParsePattern(pattern) : undefined;
|
||||
if (parsed) {
|
||||
@@ -505,7 +500,7 @@ namespace ts.Completions.PathCompletions {
|
||||
return tryIOAndConsumeErrors(host, host.getDirectories, directoryName);
|
||||
}
|
||||
|
||||
function tryReadDirectory(host: LanguageServiceHost, path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
|
||||
function tryReadDirectory(host: LanguageServiceHost, path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>): string[] {
|
||||
return tryIOAndConsumeErrors(host, host.readDirectory, path, extensions, exclude, include);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,22 +33,9 @@ namespace ts {
|
||||
refactors.set(refactor.name, refactor);
|
||||
}
|
||||
|
||||
export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
|
||||
let results: ApplicableRefactorInfo[];
|
||||
const refactorList: Refactor[] = [];
|
||||
refactors.forEach(refactor => {
|
||||
refactorList.push(refactor);
|
||||
});
|
||||
for (const refactor of refactorList) {
|
||||
if (context.cancellationToken && context.cancellationToken.isCancellationRequested()) {
|
||||
return results;
|
||||
}
|
||||
const infos = refactor.getAvailableActions(context);
|
||||
if (infos && infos.length) {
|
||||
(results || (results = [])).push(...infos);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] {
|
||||
return flatMapIter(refactors.values(), refactor =>
|
||||
context.cancellationToken && context.cancellationToken.isCancellationRequested() ? [] : refactor.getAvailableActions(context));
|
||||
}
|
||||
|
||||
export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined {
|
||||
|
||||
+29
-45
@@ -1760,21 +1760,14 @@ namespace ts {
|
||||
function getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[] {
|
||||
synchronizeHostData();
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const span = { start, length: end - start };
|
||||
const span = createTextSpanFromBounds(start, end);
|
||||
const newLineCharacter = getNewLineOrDefaultFromHost(host);
|
||||
const rulesProvider = getRuleProvider(formatOptions);
|
||||
|
||||
let allFixes: CodeAction[] = [];
|
||||
|
||||
forEach(deduplicate(errorCodes), errorCode => {
|
||||
return flatMap(deduplicate(errorCodes), errorCode => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
const rulesProvider = getRuleProvider(formatOptions);
|
||||
const fixes = codefix.getFixes({ errorCode, sourceFile, span, program, newLineCharacter, host, cancellationToken, rulesProvider });
|
||||
if (fixes) {
|
||||
allFixes = allFixes.concat(fixes);
|
||||
}
|
||||
return codefix.getFixes({ errorCode, sourceFile, span, program, newLineCharacter, host, cancellationToken, rulesProvider });
|
||||
});
|
||||
|
||||
return allFixes;
|
||||
}
|
||||
|
||||
function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion {
|
||||
@@ -2055,42 +2048,33 @@ namespace ts {
|
||||
}
|
||||
|
||||
function initializeNameTable(sourceFile: SourceFile): void {
|
||||
const nameTable = createUnderscoreEscapedMap<number>();
|
||||
|
||||
walk(sourceFile);
|
||||
sourceFile.nameTable = nameTable;
|
||||
|
||||
function walk(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
setNameTable((<Identifier>node).text, node);
|
||||
break;
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
// We want to store any numbers/strings if they were a name that could be
|
||||
// related to a declaration. So, if we have 'import x = require("something")'
|
||||
// then we want 'something' to be in the name table. Similarly, if we have
|
||||
// "a['propname']" then we want to store "propname" in the name table.
|
||||
if (isDeclarationName(node) ||
|
||||
node.parent.kind === SyntaxKind.ExternalModuleReference ||
|
||||
isArgumentOfElementAccessExpression(node) ||
|
||||
isLiteralComputedPropertyDeclarationName(node)) {
|
||||
setNameTable(getEscapedTextOfIdentifierOrLiteral((<LiteralExpression>node)), node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
forEachChild(node, walk);
|
||||
if (node.jsDoc) {
|
||||
for (const jsDoc of node.jsDoc) {
|
||||
forEachChild(jsDoc, walk);
|
||||
}
|
||||
}
|
||||
const nameTable = sourceFile.nameTable = createUnderscoreEscapedMap<number>();
|
||||
sourceFile.forEachChild(function walk(node) {
|
||||
if ((isIdentifier(node) || isStringOrNumericLiteral(node) && literalIsName(node)) && node.text) {
|
||||
const text = getEscapedTextOfIdentifierOrLiteral(node);
|
||||
nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1);
|
||||
}
|
||||
}
|
||||
|
||||
function setNameTable(text: __String, node: ts.Node): void {
|
||||
nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1);
|
||||
}
|
||||
forEachChild(node, walk);
|
||||
if (node.jsDoc) {
|
||||
for (const jsDoc of node.jsDoc) {
|
||||
forEachChild(jsDoc, walk);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to store any numbers/strings if they were a name that could be
|
||||
* related to a declaration. So, if we have 'import x = require("something")'
|
||||
* then we want 'something' to be in the name table. Similarly, if we have
|
||||
* "a['propname']" then we want to store "propname" in the name table.
|
||||
*/
|
||||
function literalIsName(node: ts.StringLiteral | ts.NumericLiteral): boolean {
|
||||
return isDeclarationName(node) ||
|
||||
node.parent.kind === SyntaxKind.ExternalModuleReference ||
|
||||
isArgumentOfElementAccessExpression(node) ||
|
||||
isLiteralComputedPropertyDeclarationName(node);
|
||||
}
|
||||
|
||||
function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
|
||||
|
||||
@@ -444,7 +444,7 @@ namespace ts {
|
||||
return this.shimHost.getDefaultLibFileName(JSON.stringify(options));
|
||||
}
|
||||
|
||||
public readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
|
||||
public readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: string[], include?: string[], depth?: number): string[] {
|
||||
const pattern = getFileMatcherPatterns(path, exclude, include,
|
||||
this.shimHost.useCaseSensitiveFileNames(), this.shimHost.getCurrentDirectory());
|
||||
return JSON.parse(this.shimHost.readDirectory(
|
||||
@@ -483,7 +483,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
public readDirectory(rootDir: string, extensions: string[], exclude: string[], include: string[], depth?: number): string[] {
|
||||
public readDirectory(rootDir: string, extensions: ReadonlyArray<string>, exclude: ReadonlyArray<string>, include: ReadonlyArray<string>, depth?: number): string[] {
|
||||
const pattern = getFileMatcherPatterns(rootDir, exclude, include,
|
||||
this.shimHost.useCaseSensitiveFileNames(), this.shimHost.getCurrentDirectory());
|
||||
return JSON.parse(this.shimHost.readDirectory(
|
||||
@@ -1116,6 +1116,7 @@ namespace ts {
|
||||
const info = <DiscoverTypingsInfo>JSON.parse(discoverTypingsJson);
|
||||
return ts.JsTyping.discoverTypings(
|
||||
this.host,
|
||||
msg => this.logger.log(msg),
|
||||
info.fileNames,
|
||||
toPath(info.projectRootPath, info.projectRootPath, getCanonicalFileName),
|
||||
toPath(info.safeListPath, info.safeListPath, getCanonicalFileName),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace ts.SymbolDisplay {
|
||||
// TODO(drosen): use contextual SemanticMeaning.
|
||||
export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind {
|
||||
const { flags } = symbol;
|
||||
const flags = getCombinedLocalAndExportSymbolFlags(symbol);
|
||||
|
||||
if (flags & SymbolFlags.Class) {
|
||||
return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ?
|
||||
@@ -34,7 +34,7 @@ namespace ts.SymbolDisplay {
|
||||
if (location.kind === SyntaxKind.ThisKeyword && isExpression(location)) {
|
||||
return ScriptElementKind.parameterElement;
|
||||
}
|
||||
const { flags } = symbol;
|
||||
const flags = getCombinedLocalAndExportSymbolFlags(symbol);
|
||||
if (flags & SymbolFlags.Variable) {
|
||||
if (isFirstDeclarationOfSymbolParameter(symbol)) {
|
||||
return ScriptElementKind.parameterElement;
|
||||
@@ -96,7 +96,7 @@ namespace ts.SymbolDisplay {
|
||||
const displayParts: SymbolDisplayPart[] = [];
|
||||
let documentation: SymbolDisplayPart[];
|
||||
let tags: JSDocTagInfo[];
|
||||
const symbolFlags = symbol.flags;
|
||||
const symbolFlags = ts.getCombinedLocalAndExportSymbolFlags(symbol);
|
||||
let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location);
|
||||
let hasAddedSymbolInfo: boolean;
|
||||
const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isExpression(location);
|
||||
@@ -110,7 +110,7 @@ namespace ts.SymbolDisplay {
|
||||
}
|
||||
|
||||
let signature: Signature;
|
||||
type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol, location);
|
||||
type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol.exportSymbol || symbol, location);
|
||||
if (type) {
|
||||
if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
const right = (<PropertyAccessExpression>location.parent).name;
|
||||
@@ -198,7 +198,7 @@ namespace ts.SymbolDisplay {
|
||||
hasAddedSymbolInfo = true;
|
||||
}
|
||||
}
|
||||
else if ((isNameOfFunctionDeclaration(location) && !(symbol.flags & SymbolFlags.Accessor)) || // name of function declaration
|
||||
else if ((isNameOfFunctionDeclaration(location) && !(symbolFlags & SymbolFlags.Accessor)) || // name of function declaration
|
||||
(location.kind === SyntaxKind.ConstructorKeyword && location.parent.kind === SyntaxKind.Constructor)) { // At constructor keyword of constructor declaration
|
||||
// get the signature from the declaration and write it
|
||||
const functionDeclaration = <FunctionLike>location.parent;
|
||||
@@ -429,7 +429,7 @@ namespace ts.SymbolDisplay {
|
||||
if (!documentation) {
|
||||
documentation = symbol.getDocumentationComment();
|
||||
tags = symbol.getJsDocTags();
|
||||
if (documentation.length === 0 && symbol.flags & SymbolFlags.Property) {
|
||||
if (documentation.length === 0 && symbolFlags & SymbolFlags.Property) {
|
||||
// For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo`
|
||||
// there documentation comments might be attached to the right hand side symbol of their declarations.
|
||||
// The pattern of such special property access is that the parent symbol is the symbol of the file.
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace ts {
|
||||
* LS host can optionally implement these methods to support completions for module specifiers.
|
||||
* Without these methods, only completions for ambient modules will be provided.
|
||||
*/
|
||||
readDirectory?(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[];
|
||||
readDirectory?(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
|
||||
readFile?(path: string, encoding?: string): string;
|
||||
fileExists?(path: string): boolean;
|
||||
|
||||
|
||||
@@ -1240,10 +1240,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
|
||||
writeDisplayParts(displayPartWriter);
|
||||
const result = displayPartWriter.displayParts();
|
||||
displayPartWriter.clear();
|
||||
return result;
|
||||
try {
|
||||
writeDisplayParts(displayPartWriter);
|
||||
return displayPartWriter.displayParts();
|
||||
}
|
||||
finally {
|
||||
displayPartWriter.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
|
||||
|
||||
@@ -28,7 +28,17 @@ x1(0);
|
||||
|
||||
/** @type {function (number): number} */
|
||||
const x2 = (a) => a + 1;
|
||||
x2(0);
|
||||
x2(0);
|
||||
|
||||
/**
|
||||
* @type {object}
|
||||
*/
|
||||
var props = {};
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
var props = {};
|
||||
|
||||
//// [0.js]
|
||||
// @ts-check
|
||||
@@ -54,3 +64,11 @@ x1(0);
|
||||
/** @type {function (number): number} */
|
||||
var x2 = function (a) { return a + 1; };
|
||||
x2(0);
|
||||
/**
|
||||
* @type {object}
|
||||
*/
|
||||
var props = {};
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
var props = {};
|
||||
|
||||
@@ -58,3 +58,15 @@ const x2 = (a) => a + 1;
|
||||
x2(0);
|
||||
>x2 : Symbol(x2, Decl(0.js, 28, 5))
|
||||
|
||||
/**
|
||||
* @type {object}
|
||||
*/
|
||||
var props = {};
|
||||
>props : Symbol(props, Decl(0.js, 34, 3), Decl(0.js, 39, 3))
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
var props = {};
|
||||
>props : Symbol(props, Decl(0.js, 34, 3), Decl(0.js, 39, 3))
|
||||
|
||||
|
||||
@@ -86,3 +86,17 @@ x2(0);
|
||||
>x2 : (arg0: number) => number
|
||||
>0 : 0
|
||||
|
||||
/**
|
||||
* @type {object}
|
||||
*/
|
||||
var props = {};
|
||||
>props : any
|
||||
>{} : {}
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
var props = {};
|
||||
>props : any
|
||||
>{} : {}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//// [importCallExpressionShouldNotGetParen.ts]
|
||||
const localeName = "zh-CN";
|
||||
import(`./locales/${localeName}.js`).then(bar => {
|
||||
let x = bar;
|
||||
});
|
||||
|
||||
import("./locales/" + localeName + ".js").then(bar => {
|
||||
let x = bar;
|
||||
});
|
||||
|
||||
//// [importCallExpressionShouldNotGetParen.js]
|
||||
const localeName = "zh-CN";
|
||||
import(`./locales/${localeName}.js`).then(bar => {
|
||||
let x = bar;
|
||||
});
|
||||
import("./locales/" + localeName + ".js").then(bar => {
|
||||
let x = bar;
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
=== tests/cases/conformance/dynamicImport/importCallExpressionShouldNotGetParen.ts ===
|
||||
const localeName = "zh-CN";
|
||||
>localeName : Symbol(localeName, Decl(importCallExpressionShouldNotGetParen.ts, 0, 5))
|
||||
|
||||
import(`./locales/${localeName}.js`).then(bar => {
|
||||
>import(`./locales/${localeName}.js`).then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
|
||||
>localeName : Symbol(localeName, Decl(importCallExpressionShouldNotGetParen.ts, 0, 5))
|
||||
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
|
||||
>bar : Symbol(bar, Decl(importCallExpressionShouldNotGetParen.ts, 1, 42))
|
||||
|
||||
let x = bar;
|
||||
>x : Symbol(x, Decl(importCallExpressionShouldNotGetParen.ts, 2, 7))
|
||||
>bar : Symbol(bar, Decl(importCallExpressionShouldNotGetParen.ts, 1, 42))
|
||||
|
||||
});
|
||||
|
||||
import("./locales/" + localeName + ".js").then(bar => {
|
||||
>import("./locales/" + localeName + ".js").then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
|
||||
>localeName : Symbol(localeName, Decl(importCallExpressionShouldNotGetParen.ts, 0, 5))
|
||||
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
|
||||
>bar : Symbol(bar, Decl(importCallExpressionShouldNotGetParen.ts, 5, 47))
|
||||
|
||||
let x = bar;
|
||||
>x : Symbol(x, Decl(importCallExpressionShouldNotGetParen.ts, 6, 7))
|
||||
>bar : Symbol(bar, Decl(importCallExpressionShouldNotGetParen.ts, 5, 47))
|
||||
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
=== tests/cases/conformance/dynamicImport/importCallExpressionShouldNotGetParen.ts ===
|
||||
const localeName = "zh-CN";
|
||||
>localeName : "zh-CN"
|
||||
>"zh-CN" : "zh-CN"
|
||||
|
||||
import(`./locales/${localeName}.js`).then(bar => {
|
||||
>import(`./locales/${localeName}.js`).then(bar => { let x = bar;}) : Promise<void>
|
||||
>import(`./locales/${localeName}.js`).then : <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
|
||||
>import(`./locales/${localeName}.js`) : Promise<any>
|
||||
>`./locales/${localeName}.js` : string
|
||||
>localeName : "zh-CN"
|
||||
>then : <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
|
||||
>bar => { let x = bar;} : (bar: any) => void
|
||||
>bar : any
|
||||
|
||||
let x = bar;
|
||||
>x : any
|
||||
>bar : any
|
||||
|
||||
});
|
||||
|
||||
import("./locales/" + localeName + ".js").then(bar => {
|
||||
>import("./locales/" + localeName + ".js").then(bar => { let x = bar;}) : Promise<void>
|
||||
>import("./locales/" + localeName + ".js").then : <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
|
||||
>import("./locales/" + localeName + ".js") : Promise<any>
|
||||
>"./locales/" + localeName + ".js" : string
|
||||
>"./locales/" + localeName : string
|
||||
>"./locales/" : "./locales/"
|
||||
>localeName : "zh-CN"
|
||||
>".js" : ".js"
|
||||
>then : <TResult1 = any, TResult2 = never>(onfulfilled?: (value: any) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>) => Promise<TResult1 | TResult2>
|
||||
>bar => { let x = bar;} : (bar: any) => void
|
||||
>bar : any
|
||||
|
||||
let x = bar;
|
||||
>x : any
|
||||
>bar : any
|
||||
|
||||
});
|
||||
@@ -18,5 +18,5 @@ function foo() { return "foo"; }
|
||||
exports.foo = foo;
|
||||
//// [1.js]
|
||||
"use strict";
|
||||
var p1 = (import)("./0"); // error
|
||||
var p2 = (import)("./0"); // error
|
||||
var p1 = Promise.resolve().then(function () { return require("./0"); }); // error
|
||||
var p2 = Promise.resolve().then(function () { return require("./0"); }); // error
|
||||
|
||||
@@ -55,6 +55,9 @@ var nullable;
|
||||
/** @type {Object} */
|
||||
var Obj;
|
||||
|
||||
/** @type {object} */
|
||||
var obj;
|
||||
|
||||
/** @type {Function} */
|
||||
var Func;
|
||||
|
||||
@@ -77,6 +80,7 @@ var P: Promise<any>;
|
||||
var p: Promise<any>;
|
||||
var nullable: number | null;
|
||||
var Obj: any;
|
||||
var obj: any;
|
||||
var Func: Function;
|
||||
|
||||
|
||||
@@ -117,6 +121,8 @@ var p;
|
||||
var nullable;
|
||||
/** @type {Object} */
|
||||
var Obj;
|
||||
/** @type {object} */
|
||||
var obj;
|
||||
/** @type {Function} */
|
||||
var Func;
|
||||
//// [b.js]
|
||||
@@ -138,4 +144,5 @@ var P;
|
||||
var p;
|
||||
var nullable;
|
||||
var Obj;
|
||||
var obj;
|
||||
var Func;
|
||||
|
||||
@@ -71,9 +71,13 @@ var nullable;
|
||||
var Obj;
|
||||
>Obj : Symbol(Obj, Decl(a.js, 52, 3), Decl(b.ts, 17, 3))
|
||||
|
||||
/** @type {object} */
|
||||
var obj;
|
||||
>obj : Symbol(obj, Decl(a.js, 55, 3), Decl(b.ts, 18, 3))
|
||||
|
||||
/** @type {Function} */
|
||||
var Func;
|
||||
>Func : Symbol(Func, Decl(a.js, 55, 3), Decl(b.ts, 18, 3))
|
||||
>Func : Symbol(Func, Decl(a.js, 58, 3), Decl(b.ts, 19, 3))
|
||||
|
||||
=== tests/cases/conformance/jsdoc/b.ts ===
|
||||
var S: string;
|
||||
@@ -132,7 +136,10 @@ var nullable: number | null;
|
||||
var Obj: any;
|
||||
>Obj : Symbol(Obj, Decl(a.js, 52, 3), Decl(b.ts, 17, 3))
|
||||
|
||||
var obj: any;
|
||||
>obj : Symbol(obj, Decl(a.js, 55, 3), Decl(b.ts, 18, 3))
|
||||
|
||||
var Func: Function;
|
||||
>Func : Symbol(Func, Decl(a.js, 55, 3), Decl(b.ts, 18, 3))
|
||||
>Func : Symbol(Func, Decl(a.js, 58, 3), Decl(b.ts, 19, 3))
|
||||
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
|
||||
|
||||
|
||||
@@ -71,6 +71,10 @@ var nullable;
|
||||
var Obj;
|
||||
>Obj : any
|
||||
|
||||
/** @type {object} */
|
||||
var obj;
|
||||
>obj : any
|
||||
|
||||
/** @type {Function} */
|
||||
var Func;
|
||||
>Func : Function
|
||||
@@ -135,6 +139,9 @@ var nullable: number | null;
|
||||
var Obj: any;
|
||||
>Obj : any
|
||||
|
||||
var obj: any;
|
||||
>obj : any
|
||||
|
||||
var Func: Function;
|
||||
>Func : Function
|
||||
>Function : Function
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
tests/cases/compiler/mergedDeclarationExports.ts(13,11): error TS2395: Individual declarations in merged declaration 'c' must be all exported or all local.
|
||||
tests/cases/compiler/mergedDeclarationExports.ts(14,18): error TS2395: Individual declarations in merged declaration 'c' must be all exported or all local.
|
||||
tests/cases/compiler/mergedDeclarationExports.ts(17,11): error TS2395: Individual declarations in merged declaration 'd' must be all exported or all local.
|
||||
tests/cases/compiler/mergedDeclarationExports.ts(18,14): error TS2395: Individual declarations in merged declaration 'd' must be all exported or all local.
|
||||
tests/cases/compiler/mergedDeclarationExports.ts(21,11): error TS2395: Individual declarations in merged declaration 'N' must be all exported or all local.
|
||||
tests/cases/compiler/mergedDeclarationExports.ts(22,18): error TS2395: Individual declarations in merged declaration 'N' must be all exported or all local.
|
||||
|
||||
|
||||
==== tests/cases/compiler/mergedDeclarationExports.ts (6 errors) ====
|
||||
// OK -- one is type, one is value
|
||||
interface b {}
|
||||
export const b = 1;
|
||||
|
||||
// OK -- one is a type, one is a namespace, one is a value.
|
||||
type t = 0;
|
||||
namespace t { interface I {} }
|
||||
export const t = 0;
|
||||
|
||||
// Should get errors if they have some meaning in common.
|
||||
|
||||
// both types
|
||||
interface c {}
|
||||
~
|
||||
!!! error TS2395: Individual declarations in merged declaration 'c' must be all exported or all local.
|
||||
export interface c {}
|
||||
~
|
||||
!!! error TS2395: Individual declarations in merged declaration 'c' must be all exported or all local.
|
||||
|
||||
// both types (class is also value, but that doesn't matter)
|
||||
interface d {}
|
||||
~
|
||||
!!! error TS2395: Individual declarations in merged declaration 'd' must be all exported or all local.
|
||||
export class d {}
|
||||
~
|
||||
!!! error TS2395: Individual declarations in merged declaration 'd' must be all exported or all local.
|
||||
|
||||
// both namespaces
|
||||
namespace N { }
|
||||
~
|
||||
!!! error TS2395: Individual declarations in merged declaration 'N' must be all exported or all local.
|
||||
export namespace N {}
|
||||
~
|
||||
!!! error TS2395: Individual declarations in merged declaration 'N' must be all exported or all local.
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//// [mergedDeclarationExports.ts]
|
||||
// OK -- one is type, one is value
|
||||
interface b {}
|
||||
export const b = 1;
|
||||
|
||||
// OK -- one is a type, one is a namespace, one is a value.
|
||||
type t = 0;
|
||||
namespace t { interface I {} }
|
||||
export const t = 0;
|
||||
|
||||
// Should get errors if they have some meaning in common.
|
||||
|
||||
// both types
|
||||
interface c {}
|
||||
export interface c {}
|
||||
|
||||
// both types (class is also value, but that doesn't matter)
|
||||
interface d {}
|
||||
export class d {}
|
||||
|
||||
// both namespaces
|
||||
namespace N { }
|
||||
export namespace N {}
|
||||
|
||||
|
||||
//// [mergedDeclarationExports.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.b = 1;
|
||||
exports.t = 0;
|
||||
var d = (function () {
|
||||
function d() {
|
||||
}
|
||||
return d;
|
||||
}());
|
||||
exports.d = d;
|
||||
@@ -0,0 +1,37 @@
|
||||
tests/cases/compiler/parseErrorIncorrectReturnToken.ts(2,17): error TS1005: ':' expected.
|
||||
tests/cases/compiler/parseErrorIncorrectReturnToken.ts(4,22): error TS1005: '=>' expected.
|
||||
tests/cases/compiler/parseErrorIncorrectReturnToken.ts(4,24): error TS2693: 'string' only refers to a type, but is being used as a value here.
|
||||
tests/cases/compiler/parseErrorIncorrectReturnToken.ts(9,18): error TS1005: '{' expected.
|
||||
tests/cases/compiler/parseErrorIncorrectReturnToken.ts(9,21): error TS2693: 'string' only refers to a type, but is being used as a value here.
|
||||
tests/cases/compiler/parseErrorIncorrectReturnToken.ts(9,28): error TS1005: ';' expected.
|
||||
tests/cases/compiler/parseErrorIncorrectReturnToken.ts(12,1): error TS1128: Declaration or statement expected.
|
||||
|
||||
|
||||
==== tests/cases/compiler/parseErrorIncorrectReturnToken.ts (7 errors) ====
|
||||
type F1 = {
|
||||
(n: number) => string; // should be : not =>
|
||||
~~
|
||||
!!! error TS1005: ':' expected.
|
||||
}
|
||||
type F2 = (n: number): string; // should be => not :
|
||||
~
|
||||
!!! error TS1005: '=>' expected.
|
||||
~~~~~~
|
||||
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
|
||||
|
||||
// doesn't work in non-type contexts, where the return type is optional
|
||||
let f = (n: number) => string => n.toString();
|
||||
let o = {
|
||||
m(n: number) => string {
|
||||
~~
|
||||
!!! error TS1005: '{' expected.
|
||||
~~~~~~
|
||||
!!! error TS2693: 'string' only refers to a type, but is being used as a value here.
|
||||
~
|
||||
!!! error TS1005: ';' expected.
|
||||
return n.toString();
|
||||
}
|
||||
};
|
||||
~
|
||||
!!! error TS1128: Declaration or statement expected.
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//// [parseErrorIncorrectReturnToken.ts]
|
||||
type F1 = {
|
||||
(n: number) => string; // should be : not =>
|
||||
}
|
||||
type F2 = (n: number): string; // should be => not :
|
||||
|
||||
// doesn't work in non-type contexts, where the return type is optional
|
||||
let f = (n: number) => string => n.toString();
|
||||
let o = {
|
||||
m(n: number) => string {
|
||||
return n.toString();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//// [parseErrorIncorrectReturnToken.js]
|
||||
string; // should be => not :
|
||||
// doesn't work in non-type contexts, where the return type is optional
|
||||
var f = function (n) { return function (string) { return n.toString(); }; };
|
||||
var o = {
|
||||
m: function (n) { }
|
||||
};
|
||||
string;
|
||||
{
|
||||
return n.toString();
|
||||
}
|
||||
;
|
||||
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"lib": ["es5","es2015.promise"], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"lib": ["es5","es2015.core"], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation: */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// OK -- one is type, one is value
|
||||
interface b {}
|
||||
export const b = 1;
|
||||
|
||||
// OK -- one is a type, one is a namespace, one is a value.
|
||||
type t = 0;
|
||||
namespace t { interface I {} }
|
||||
export const t = 0;
|
||||
|
||||
// Should get errors if they have some meaning in common.
|
||||
|
||||
// both types
|
||||
interface c {}
|
||||
export interface c {}
|
||||
|
||||
// both types (class is also value, but that doesn't matter)
|
||||
interface d {}
|
||||
export class d {}
|
||||
|
||||
// both namespaces
|
||||
namespace N { }
|
||||
export namespace N {}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
type F1 = {
|
||||
(n: number) => string; // should be : not =>
|
||||
}
|
||||
type F2 = (n: number): string; // should be => not :
|
||||
|
||||
// doesn't work in non-type contexts, where the return type is optional
|
||||
let f = (n: number) => string => n.toString();
|
||||
let o = {
|
||||
m(n: number) => string {
|
||||
return n.toString();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
// @module: esnext
|
||||
// @target: es6
|
||||
// @noImplicitAny: true
|
||||
const localeName = "zh-CN";
|
||||
import(`./locales/${localeName}.js`).then(bar => {
|
||||
let x = bar;
|
||||
});
|
||||
|
||||
import("./locales/" + localeName + ".js").then(bar => {
|
||||
let x = bar;
|
||||
});
|
||||
@@ -31,4 +31,14 @@ x1(0);
|
||||
|
||||
/** @type {function (number): number} */
|
||||
const x2 = (a) => a + 1;
|
||||
x2(0);
|
||||
x2(0);
|
||||
|
||||
/**
|
||||
* @type {object}
|
||||
*/
|
||||
var props = {};
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
var props = {};
|
||||
@@ -57,6 +57,9 @@ var nullable;
|
||||
/** @type {Object} */
|
||||
var Obj;
|
||||
|
||||
/** @type {object} */
|
||||
var obj;
|
||||
|
||||
/** @type {Function} */
|
||||
var Func;
|
||||
|
||||
@@ -79,4 +82,5 @@ var P: Promise<any>;
|
||||
var p: Promise<any>;
|
||||
var nullable: number | null;
|
||||
var Obj: any;
|
||||
var obj: any;
|
||||
var Func: Function;
|
||||
|
||||
@@ -35,7 +35,7 @@ goTo.file("commentsExternalModules_file0.ts");
|
||||
verify.quickInfoAt("1", "namespace m1", "Namespace comment");
|
||||
|
||||
goTo.marker('2');
|
||||
verify.completionListContains("b", "var m1.b: number", "b's comment");
|
||||
verify.completionListContains("b", "var b: number", "b's comment");
|
||||
verify.completionListContains("foo", "function foo(): number", "foo's comment");
|
||||
|
||||
goTo.marker('3');
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
verify.quickInfoAt("1", "namespace m1", "Namespace comment");
|
||||
|
||||
goTo.marker('2');
|
||||
verify.completionListContains("b", "var m1.b: number", "b's comment");
|
||||
verify.completionListContains("b", "var b: number", "b's comment");
|
||||
verify.completionListContains("foo", "function foo(): number", "foo's comment");
|
||||
|
||||
goTo.marker('3');
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
/////*3*/
|
||||
|
||||
goTo.marker("0");
|
||||
verify.not.completionListContains("B");
|
||||
verify.not.completionListContains("\u0042");
|
||||
verify.completionListContains("B");
|
||||
verify.completionListContains("\u0042");
|
||||
|
||||
goTo.marker("2");
|
||||
verify.not.completionListContains("C");
|
||||
@@ -18,10 +18,9 @@ verify.not.completionListContains("A");
|
||||
verify.not.completionListContains("\u0041");
|
||||
|
||||
goTo.marker("3");
|
||||
verify.not.completionListContains("B");
|
||||
verify.not.completionListContains("\u0042");
|
||||
verify.not.completionListContains("A");
|
||||
verify.not.completionListContains("\u0041");
|
||||
verify.not.completionListContains("C");
|
||||
verify.not.completionListContains("\u0043");
|
||||
|
||||
verify.completionListContains("B");
|
||||
verify.completionListContains("\u0042");
|
||||
verify.completionListContains("A");
|
||||
verify.completionListContains("\u0041");
|
||||
verify.completionListContains("C");
|
||||
verify.completionListContains("\u0043");
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import * as self from "./a";
|
||||
////
|
||||
////declare module "a" {
|
||||
//// export const a: number;
|
||||
////}
|
||||
////
|
||||
/////**/
|
||||
|
||||
goTo.marker();
|
||||
verify.not.completionListContains("a");
|
||||
@@ -19,6 +19,7 @@ verify.completionListContains("bar");
|
||||
verify.completionListContains("break");
|
||||
verify.completionListContains("any");
|
||||
verify.completionListContains("$");
|
||||
verify.completionListContains("b");
|
||||
|
||||
// Nothing else should show up
|
||||
verify.completionListCount(4);
|
||||
verify.completionListCount(5);
|
||||
|
||||
@@ -41,19 +41,16 @@ function getVerify(isTypeLocation?: boolean) {
|
||||
verifyValueOrType: verify
|
||||
};
|
||||
}
|
||||
function typeLocationVerify(valueMarker: string, verify: (typeMarker: string) => void) {
|
||||
verify(valueMarker + "Type");
|
||||
return valueMarker;
|
||||
}
|
||||
|
||||
function verifyModuleM(marker: string) {
|
||||
const isTypeLocation = marker.indexOf("Type") !== -1;
|
||||
const { verifyValue, verifyType, verifyValueOrType } = getVerify(isTypeLocation);
|
||||
if (!isTypeLocation) {
|
||||
marker = typeLocationVerify(marker, verifyModuleM);
|
||||
}
|
||||
verifyModuleMWorker(marker, /*isTypeLocation*/ false);
|
||||
verifyModuleMWorker(`${marker}Type`, /*isTypeLocation*/ true);
|
||||
}
|
||||
|
||||
function verifyModuleMWorker(marker: string, isTypeLocation: boolean): void {
|
||||
goTo.marker(marker);
|
||||
|
||||
const { verifyValue, verifyType, verifyValueOrType } = getVerify(isTypeLocation);
|
||||
verifyType.completionListContains("I");
|
||||
verifyValueOrType.completionListContains("C");
|
||||
verifyValueOrType.completionListContains("E");
|
||||
@@ -63,8 +60,9 @@ function verifyModuleM(marker: string) {
|
||||
verifyValueOrType.completionListContains("A");
|
||||
}
|
||||
|
||||
|
||||
// Module m
|
||||
goTo.marker("1");
|
||||
verify.completionListContains("A");
|
||||
verifyModuleM("1");
|
||||
|
||||
// Class C
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
interface GotoMarkVerifyOptions {
|
||||
isClassScope?: boolean;
|
||||
isTypeLocation?: boolean;
|
||||
insideMod1?: boolean;
|
||||
}
|
||||
|
||||
function getVerify(isTypeLocation: boolean) {
|
||||
@@ -243,30 +244,30 @@ function getVerify(isTypeLocation: boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
function goToMarkAndGeneralVerify(marker: string, { isClassScope, isTypeLocation }: GotoMarkVerifyOptions = {})
|
||||
{
|
||||
function goToMarkAndGeneralVerify(marker: string, { isClassScope, isTypeLocation, insideMod1 }: GotoMarkVerifyOptions = {}) {
|
||||
goTo.marker(marker);
|
||||
|
||||
const mod1Dot = insideMod1 ? "" : "mod1.";
|
||||
const verifyValueInModule = isClassScope || isTypeLocation ? verify.not : verify;
|
||||
const verifyValueOrTypeInModule = isClassScope ? verify.not : verify;
|
||||
const verifyTypeInModule = isTypeLocation ? verify : verify.not;
|
||||
verifyValueInModule.completionListContains('mod1var', 'var mod1var: number');
|
||||
verifyValueInModule.completionListContains('mod1fn', 'function mod1fn(): void');
|
||||
verifyValueInModule.completionListContains('mod1evar', 'var mod1.mod1evar: number');
|
||||
verifyValueInModule.completionListContains('mod1efn', 'function mod1.mod1efn(): void');
|
||||
verifyValueInModule.completionListContains('mod1eexvar', 'var mod1.mod1eexvar: number');
|
||||
verifyValueInModule.completionListContains('mod1evar', `var ${mod1Dot}mod1evar: number`);
|
||||
verifyValueInModule.completionListContains('mod1efn', `function ${mod1Dot}mod1efn(): void`);
|
||||
verifyValueInModule.completionListContains('mod1eexvar', `var mod1.mod1eexvar: number`);
|
||||
verifyValueInModule.completionListContains('mod3', 'namespace mod3');
|
||||
verifyValueInModule.completionListContains('shwvar', 'var shwvar: number');
|
||||
verifyValueInModule.completionListContains('shwfn', 'function shwfn(): void');
|
||||
|
||||
verifyTypeInModule.completionListContains('mod1int', 'interface mod1int');
|
||||
verifyTypeInModule.completionListContains('mod1eint', 'interface mod1.mod1eint');
|
||||
verifyTypeInModule.completionListContains('mod1eint', `interface ${mod1Dot}mod1eint`);
|
||||
verifyTypeInModule.completionListContains('shwint', 'interface shwint');
|
||||
|
||||
verifyValueOrTypeInModule.completionListContains('mod1cls', 'class mod1cls');
|
||||
verifyValueOrTypeInModule.completionListContains('mod1mod', 'namespace mod1mod');
|
||||
verifyValueOrTypeInModule.completionListContains('mod1ecls', 'class mod1.mod1ecls');
|
||||
verifyValueOrTypeInModule.completionListContains('mod1emod', 'namespace mod1.mod1emod');
|
||||
verifyValueOrTypeInModule.completionListContains('mod1ecls', `class ${mod1Dot}mod1ecls`);
|
||||
verifyValueOrTypeInModule.completionListContains('mod1emod', `namespace ${mod1Dot}mod1emod`);
|
||||
verifyValueOrTypeInModule.completionListContains('mod2', 'namespace mod2');
|
||||
verifyValueOrTypeInModule.completionListContains('shwcls', 'class shwcls');
|
||||
|
||||
@@ -295,12 +296,12 @@ function goToMarkAndGeneralVerify(marker: string, { isClassScope, isTypeLocation
|
||||
}
|
||||
|
||||
// from mod1
|
||||
goToMarkAndGeneralVerify('mod1');
|
||||
goToMarkAndGeneralVerify('mod1', { insideMod1: true });
|
||||
// from mod1 in type position
|
||||
goToMarkAndGeneralVerify('mod1Type', { isTypeLocation: true });
|
||||
goToMarkAndGeneralVerify('mod1Type', { isTypeLocation: true, insideMod1: true });
|
||||
|
||||
// from function in mod1
|
||||
goToMarkAndGeneralVerify('function');
|
||||
goToMarkAndGeneralVerify('function', { insideMod1: true });
|
||||
verify.completionListContains('bar', '(local var) bar: number');
|
||||
verify.completionListContains('foob', '(local function) foob(): void');
|
||||
|
||||
@@ -310,34 +311,34 @@ goToMarkAndGeneralVerify('class', { isClassScope: true });
|
||||
//verify.not.completionListContains('ceVar');
|
||||
|
||||
// from interface in mod1
|
||||
goToMarkAndGeneralVerify('interface');
|
||||
goToMarkAndGeneralVerify('interface', { insideMod1: true });
|
||||
|
||||
// from namespace in mod1
|
||||
verifyNamespaceInMod1('namespace');
|
||||
verifyNamespaceInMod1('namespaceType', /*isTypeLocation*/ true);
|
||||
|
||||
function verifyNamespaceInMod1(marker: string, isTypeLocation?: boolean) {
|
||||
goToMarkAndGeneralVerify(marker, { isTypeLocation });
|
||||
goToMarkAndGeneralVerify(marker, { isTypeLocation, insideMod1: true });
|
||||
|
||||
const { verifyValue, verifyType, verifyValueOrType, verifyNotValueOrType } = getVerify(isTypeLocation);
|
||||
|
||||
verifyValue.completionListContains('m1X', 'var m1X: number');
|
||||
verifyValue.completionListContains('m1Func', 'function m1Func(): void');
|
||||
verifyValue.completionListContains('m1eX', 'var mod1mod.m1eX: number');
|
||||
verifyValue.completionListContains('m1eFunc', 'function mod1mod.m1eFunc(): void');
|
||||
verifyValue.completionListContains('m1eX', 'var m1eX: number');
|
||||
verifyValue.completionListContains('m1eFunc', 'function m1eFunc(): void');
|
||||
|
||||
verifyType.completionListContains('m1Int', 'interface m1Int');
|
||||
verifyType.completionListContains('m1eInt', 'interface mod1mod.m1eInt');
|
||||
verifyType.completionListContains('m1eInt', 'interface m1eInt');
|
||||
|
||||
verifyValueOrType.completionListContains('m1Class', 'class m1Class');
|
||||
verifyValueOrType.completionListContains('m1eClass', 'class mod1mod.m1eClass');
|
||||
verifyValueOrType.completionListContains('m1eClass', 'class m1eClass');
|
||||
|
||||
verifyNotValueOrType.completionListContains('m1Mod', 'namespace m1Mod');
|
||||
verifyNotValueOrType.completionListContains('m1eMod', 'namespace mod1mod.m1eMod');
|
||||
verifyNotValueOrType.completionListContains('m1eMod', 'namespace m1eMod');
|
||||
}
|
||||
|
||||
// from exported function in mod1
|
||||
goToMarkAndGeneralVerify('exportedFunction');
|
||||
goToMarkAndGeneralVerify('exportedFunction', { insideMod1: true });
|
||||
verify.completionListContains('bar', '(local var) bar: number');
|
||||
verify.completionListContains('foob', '(local function) foob(): void');
|
||||
|
||||
@@ -347,27 +348,27 @@ verify.not.completionListContains('ceFunc');
|
||||
verify.not.completionListContains('ceVar');
|
||||
|
||||
// from exported interface in mod1
|
||||
goToMarkAndGeneralVerify('exportedInterface');
|
||||
goToMarkAndGeneralVerify('exportedInterface', { insideMod1: true });
|
||||
|
||||
// from exported namespace in mod1
|
||||
verifyExportedNamespace('exportedNamespace');
|
||||
verifyExportedNamespace('exportedNamespaceType', /*isTypeLocation*/ true);
|
||||
function verifyExportedNamespace(marker: string, isTypeLocation?: boolean) {
|
||||
goToMarkAndGeneralVerify(marker, { isTypeLocation });
|
||||
goToMarkAndGeneralVerify(marker, { isTypeLocation, insideMod1: true });
|
||||
const { verifyValue, verifyType, verifyValueOrType, verifyNotValueOrType } = getVerify(isTypeLocation);
|
||||
verifyValue.completionListContains('mX', 'var mX: number');
|
||||
verifyValue.completionListContains('mFunc', 'function mFunc(): void');
|
||||
verifyValue.completionListContains('meX', 'var mod1.mod1emod.meX: number');
|
||||
verifyValue.completionListContains('meFunc', 'function mod1.mod1emod.meFunc(): void');
|
||||
verifyValue.completionListContains('meX', 'var meX: number');
|
||||
verifyValue.completionListContains('meFunc', 'function meFunc(): void');
|
||||
|
||||
verifyType.completionListContains('mInt', 'interface mInt');
|
||||
verifyType.completionListContains('meInt', 'interface mod1.mod1emod.meInt');
|
||||
verifyType.completionListContains('meInt', 'interface meInt');
|
||||
|
||||
verifyValueOrType.completionListContains('mClass', 'class mClass');
|
||||
verifyValueOrType.completionListContains('meClass', 'class mod1.mod1emod.meClass');
|
||||
verifyValueOrType.completionListContains('meClass', 'class meClass');
|
||||
|
||||
verifyNotValueOrType.completionListContains('mMod', 'namespace mMod');
|
||||
verifyNotValueOrType.completionListContains('meMod', 'namespace mod1.mod1emod.meMod');
|
||||
verifyNotValueOrType.completionListContains('meMod', 'namespace meMod');
|
||||
}
|
||||
|
||||
// from extended namespace
|
||||
@@ -380,7 +381,7 @@ function verifyExtendedNamespace(marker: string, isTypeLocation?: boolean) {
|
||||
|
||||
verifyValue.completionListContains('mod1evar', 'var mod1.mod1evar: number');
|
||||
verifyValue.completionListContains('mod1efn', 'function mod1.mod1efn(): void');
|
||||
verifyValue.completionListContains('mod1eexvar', 'var mod1.mod1eexvar: number');
|
||||
verifyValue.completionListContains('mod1eexvar', 'var mod1eexvar: number');
|
||||
verifyValue.completionListContains('mod3', 'namespace mod3');
|
||||
verifyValue.completionListContains('shwvar', 'var shwvar: number');
|
||||
verifyValue.completionListContains('shwfn', 'function shwfn(): void');
|
||||
@@ -415,4 +416,4 @@ function verifyExtendedNamespace(marker: string, isTypeLocation?: boolean) {
|
||||
verify.not.completionListContains('sivar');
|
||||
verify.not.completionListContains('sifn');
|
||||
verify.not.completionListContains('mod2eexvar');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export default function f() {}
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import * as a from "./a";
|
||||
////a./**/;
|
||||
|
||||
goTo.marker();
|
||||
verify.completionListContains("default", "function f(): void");
|
||||
@@ -0,0 +1,21 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////class C {
|
||||
//// static m() { }
|
||||
////}
|
||||
////
|
||||
////class D extends C {}
|
||||
////namespace D {
|
||||
//// export type T = number;
|
||||
////}
|
||||
////
|
||||
////let x: D./*type*/;
|
||||
////D./*value*/
|
||||
|
||||
goTo.marker("type");
|
||||
verify.completionListContains("T");
|
||||
verify.not.completionListContains("m");
|
||||
|
||||
goTo.marker("value");
|
||||
verify.not.completionListContains("T");
|
||||
verify.completionListContains("m");
|
||||
@@ -0,0 +1,16 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////namespace N {
|
||||
//// export type T = number;
|
||||
////}
|
||||
////const N = { m() {} };
|
||||
////let x: N./*type*/;
|
||||
////N./*value*/;
|
||||
|
||||
goTo.marker("type");
|
||||
verify.completionListContains("T");
|
||||
verify.not.completionListContains("m");
|
||||
|
||||
goTo.marker("value");
|
||||
verify.not.completionListContains("T");
|
||||
verify.completionListContains("m");
|
||||
@@ -9,4 +9,4 @@ goTo.marker('1');
|
||||
verify.completionListContains("func", "function func(): void", /*documentation*/ undefined, "function");
|
||||
|
||||
goTo.marker('2');
|
||||
verify.completionListContains("func", "function func(): void", /*documentation*/ undefined, "function");
|
||||
verify.completionListContains("func", "function func(): void", /*documentation*/ undefined, "function");
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2, r3, r4] = ranges;
|
||||
const fnRanges = [r0, r1, r2, r3];
|
||||
verify.singleReferenceGroup("function DefaultExportedFunction(): () => typeof DefaultExportedFunction", fnRanges);
|
||||
const fn = "function DefaultExportedFunction(): () => typeof DefaultExportedFunction";
|
||||
verify.singleReferenceGroup(fn, fnRanges);
|
||||
|
||||
// The namespace and function do not merge,
|
||||
// so the namespace should be all alone.
|
||||
verify.singleReferenceGroup("namespace DefaultExportedFunction", [r4]);
|
||||
verify.singleReferenceGroup(`namespace DefaultExportedFunction\n${fn}`, [r4]);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
////namespace [|{| "isWriteAccess": true, "isDefinition": true |}DefaultExportedClass|] {
|
||||
////}
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
// The namespace and class do not merge,
|
||||
// so the namespace should be all alone.
|
||||
verify.singleReferenceGroup("namespace DefaultExportedClass");
|
||||
verify.singleReferenceGroup("class DefaultExportedClass\nnamespace DefaultExportedClass");
|
||||
|
||||
@@ -6,4 +6,8 @@
|
||||
|
||||
goTo.marker();
|
||||
edit.insertLine("");
|
||||
verify.currentLineContentIs('class bar {');
|
||||
verify.currentFileContentIs(
|
||||
`class foo { }
|
||||
class bar {
|
||||
}
|
||||
// new line here`);
|
||||
|
||||
@@ -116,6 +116,7 @@ declare namespace FourSlashInterface {
|
||||
ranges(): Range[];
|
||||
rangesByText(): ts.Map<Range[]>;
|
||||
markerByName(s: string): Marker;
|
||||
symbolsInScope(range: Range): any[];
|
||||
}
|
||||
class goTo {
|
||||
marker(name?: string | Marker): void;
|
||||
@@ -192,6 +193,7 @@ declare namespace FourSlashInterface {
|
||||
verifyGetEmitOutputContentsForCurrentFile(expected: ts.OutputFile[]): void;
|
||||
noReferences(markerNameOrRange?: string | Range): void;
|
||||
symbolAtLocation(startRange: Range, ...declarationRanges: Range[]): void;
|
||||
typeOfSymbolAtLocation(range: Range, symbol: any, expected: string): void;
|
||||
/**
|
||||
* @deprecated, prefer 'referenceGroups'
|
||||
* Like `referencesAre`, but goes to `start` first.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//// var num: number;
|
||||
//// var str: string;
|
||||
//// if (typeof /*1*/nonExportedStrOrNum === "number") {
|
||||
//// num = /*2*/nonExportedStrOrNum;
|
||||
//// num = /*2*/nonExportedStrOrNum;
|
||||
//// }
|
||||
//// else {
|
||||
//// str = /*3*/nonExportedStrOrNum.length;
|
||||
@@ -40,15 +40,15 @@ verify.completionListContains("nonExportedStrOrNum", "var nonExportedStrOrNum: s
|
||||
|
||||
goTo.marker('4');
|
||||
verify.quickInfoIs('var m.exportedStrOrNum: string | number');
|
||||
verify.completionListContains("exportedStrOrNum", "var m.exportedStrOrNum: string | number");
|
||||
verify.completionListContains("exportedStrOrNum", "var exportedStrOrNum: string | number");
|
||||
|
||||
goTo.marker('5');
|
||||
verify.quickInfoIs('var m.exportedStrOrNum: number');
|
||||
verify.completionListContains("exportedStrOrNum", "var m.exportedStrOrNum: number");
|
||||
verify.completionListContains("exportedStrOrNum", "var exportedStrOrNum: number");
|
||||
|
||||
goTo.marker('6');
|
||||
verify.quickInfoIs('var m.exportedStrOrNum: string');
|
||||
verify.completionListContains("exportedStrOrNum", "var m.exportedStrOrNum: string");
|
||||
verify.completionListContains("exportedStrOrNum", "var exportedStrOrNum: string");
|
||||
|
||||
goTo.marker('7');
|
||||
verify.quickInfoIs('var m.exportedStrOrNum: string | number');
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////export function f() {}
|
||||
////[|1|];
|
||||
|
||||
const ranges = test.ranges();
|
||||
const symbolsInScope = test.symbolsInScope(ranges[0]);
|
||||
const f = symbolsInScope.find(s => s.name === "f");
|
||||
if (f === undefined) throw new Error("'f' not in scope");
|
||||
if (f.exportSymbol === undefined) throw new Error("Expected to get the local symbol");
|
||||
|
||||
verify.typeOfSymbolAtLocation(ranges[0], f, "() => void");
|
||||
@@ -0,0 +1,12 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noUnusedLocals: true
|
||||
// @Filename: file2.ts
|
||||
//// [| import A, { x } from './a'; |]
|
||||
//// console.log(A);
|
||||
|
||||
// @Filename: file1.ts
|
||||
//// export default 10;
|
||||
//// export var x = 10;
|
||||
|
||||
verify.rangeAfterCodeFix("import A from './a';");
|
||||
@@ -0,0 +1,15 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noUnusedLocals: true
|
||||
// @Filename: file2.ts
|
||||
//// [| import /* 1 */ A /* 2 */, /* 3 */ { /* 4 */ x /* 5 */ } /* 6 */ from './a'; |]
|
||||
//// console.log(A);
|
||||
|
||||
// @Filename: file1.ts
|
||||
//// export default 10;
|
||||
//// export var x = 10;
|
||||
|
||||
|
||||
// It's ambiguous which token comment /* 6 */ applies to or whether it should be removed.
|
||||
// In the current implementation the comment is left behind, but this behavior isn't a requirement.
|
||||
verify.rangeAfterCodeFix("import /* 1 */ A /* 2 */ /* 6 */ from './a';");
|
||||
Reference in New Issue
Block a user