Merge branch 'master' into stricterGenericChecks

This commit is contained in:
Anders Hejlsberg
2017-06-08 11:26:22 -07:00
85 changed files with 1996 additions and 547 deletions
+20 -1
View File
@@ -248,4 +248,23 @@ rdosanjh <me@rajdeep.io> # Raj Dosanjh
gdh1995 <gdh1995@qq.com> # Dahan Gong
cedvdb <cedvandenbosch@gmail.com> # @cedvdb
kpreisser <kpreisser@users.noreply.github.com> # K. Preißer
e-cloud <saintscott119@gmail.com> # @e-cloud
e-cloud <saintscott119@gmail.com> # @e-cloud
Andrew Casey <amcasey@users.noreply.github.com> Andrew Casey <andrew.casey@microsoft.com>
Andrew Stegmaier <andrew.stegmaier@gmail.com>
Benny Neugebauer <bn@bennyn.de>
Blaine Bublitz <blaine.bublitz@gmail.com>
Charles Pierce <cpierce.grad@gmail.com>
Daniel Król <daniel@krol.me>
Diogo Franco (Kovensky) <diogomfranco@gmail.com>
Donald Pipowitch <pipo@senaeh.de>
Halasi Tamás <trusted.tomato@gmail.com>
Ika <ikatyang@gmail.com>
Joe Chung <joechung@microsoft.com>
Kate Miháliková <kate@katemihalikova.cz>
Mohsen Azimi <mazimi@lyft.com>
Noel Varanda <ncwvaranda@gmail.com>
Reiner Dolp <reiner-dolp@users.noreply.github.com>
t_ <t-mrt@users.noreply.github.com> # @t_
TravCav <xurrux@gmail.com> # @TravCav
Vladimir Kurchatkin <vladimir.kurchatkin@gmail.com>
William Orr <will@worrbase.com>
+19
View File
@@ -15,7 +15,9 @@ TypeScript is authored by:
* Anders Hejlsberg
* Andreas Martin
* Andrej Baran
* Andrew Casey
* Andrew Ochsner
* Andrew Stegmaier
* Andrew Z Allen
* András Parditka
* Andy Hanson
@@ -31,7 +33,9 @@ TypeScript is authored by:
* Ben Duffield
* Ben Mosher
* Benjamin Bock
* Benny Neugebauer
* Bill Ticehurst
* Blaine Bublitz
* Blake Embrey
* @bootstraponline
* Bowden Kelly
@@ -39,6 +43,7 @@ TypeScript is authored by:
* Bryan Forbes
* Caitlin Potter
* @cedvdb
* Charles Pierce
* Charly POLY
* Chris Bubernak
* Christophe Vidal
@@ -52,6 +57,7 @@ TypeScript is authored by:
* Dan Corder
* Dan Quirk
* Daniel Hollocher
* Daniel Król
* Daniel Lehenbauer
* Daniel Rosenwasser
* David Kmenta
@@ -60,9 +66,11 @@ TypeScript is authored by:
* David Souther
* Denis Nedelyaev
* Dick van den Brink
* Diogo Franco (Kovensky)
* Dirk Bäumer
* Dirk Holtwick
* Dom Chen
* Donald Pipowitch
* Doug Ilijev
* @e-cloud
* Elisée Maurer
@@ -89,12 +97,14 @@ TypeScript is authored by:
* Guilherme Oenning
* Guillaume Salles
* Guy Bedford
* Halasi Tamás
* Harald Niesche
* Hendrik Liebau
* Herrington Darkholme
* Homa Wong
* Iain Monro
* Igor Novozhilov
* Ika
* Ingvar Stepanyan
* Isiah Meadows
* Ivo Gabe de Wolff
@@ -111,6 +121,7 @@ TypeScript is authored by:
* Jeffrey Morlan
* Jesse Schalken
* Jiri Tobisek
* Joe Chung
* Joel Day
* Joey Wilson
* Johannes Rieken
@@ -131,6 +142,7 @@ TypeScript is authored by:
* K. Preißer
* Kagami Sascha Rosylight
* Kanchalai Tanglertsampan
* Kate Miháliková
* Keith Mashinter
* Ken Howard
* Kenji Imamula
@@ -159,6 +171,7 @@ TypeScript is authored by:
* Mike Busyrev
* Mine Starks
* Mohamed Hegazy
* Mohsen Azimi
* Myles Megyesi
* Natalie Coley
* Nathan Shively-Sanders
@@ -166,6 +179,7 @@ TypeScript is authored by:
* Nicolas Henry
* Nima Zahedi
* Noah Chen
* Noel Varanda
* Noj Vek
* Oleg Mihailik
* Oleksandr Chekhovskyi
@@ -186,6 +200,7 @@ TypeScript is authored by:
* Punya Biswal
* Rado Kirov
* Raj Dosanjh
* Reiner Dolp
* Richard Karmazín
* Richard Knoll
* Richard Sentino
@@ -213,6 +228,7 @@ TypeScript is authored by:
* Sudheesh Singanamalla
* Sébastien Arod
* @T18970237136
* @t_
* Tarik Ozket
* Tetsuharu Ohzeki
* Thomas Loubiou
@@ -225,13 +241,16 @@ TypeScript is authored by:
* togru
* Tomas Grubliauskas
* Torben Fitschen
* @TravCav
* TruongSinh Tran-Nguyen
* Vadi Taslim
* Vidar Tonaas Fauske
* Viktor Zozulyak
* Vilic Vane
* Vladimir Kurchatkin
* Vladimir Matveev
* Wesley Wigham
* William Orr
* York Yao
* @yortus
* Yuichi Nukiyama
+6 -4
View File
@@ -113,7 +113,7 @@ class DeclarationsWalker {
}
}
function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string): string {
function writeProtocolFile(outputFile: string, protocolTs: string, typeScriptServicesDts: string) {
const options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: true, types: <string[]>[], stripInternal: true };
/**
@@ -163,14 +163,17 @@ function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string)
protocolDts += "\nimport protocol = ts.server.protocol;";
protocolDts += "\nexport = protocol;";
protocolDts += "\nexport as namespace protocol;";
// do sanity check and try to compile generated text as standalone program
const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false);
const diagnostics = [...sanityCheckProgram.getSyntacticDiagnostics(), ...sanityCheckProgram.getSemanticDiagnostics(), ...sanityCheckProgram.getGlobalDiagnostics()];
ts.sys.writeFile(outputFile, protocolDts);
if (diagnostics.length) {
const flattenedDiagnostics = diagnostics.map(d => `${ts.flattenDiagnosticMessageText(d.messageText, "\n")} at ${d.file.fileName} line ${d.start}`).join("\n");
throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`);
}
return protocolDts;
}
if (process.argv.length < 5) {
@@ -181,5 +184,4 @@ if (process.argv.length < 5) {
const protocolTs = process.argv[2];
const typeScriptServicesDts = process.argv[3];
const outputFile = process.argv[4];
const generatedProtocolDts = generateProtocolFile(protocolTs, typeScriptServicesDts);
ts.sys.writeFile(outputFile, generatedProtocolDts);
writeProtocolFile(outputFile, protocolTs, typeScriptServicesDts);
+74 -46
View File
@@ -2832,6 +2832,17 @@ namespace ts {
function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext): ParameterDeclaration {
const parameterDeclaration = getDeclarationOfKind<ParameterDeclaration>(parameterSymbol, SyntaxKind.Parameter);
if (isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) {
// special-case synthetic rest parameters in JS files
return createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
parameterSymbol.isRestParameter ? createToken(SyntaxKind.DotDotDotToken) : undefined,
"args",
/*questionToken*/ undefined,
typeToTypeNodeHelper(anyArrayType, context),
/*initializer*/ undefined);
}
const modifiers = parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedClone);
const dotDotDotToken = isRestParameter(parameterDeclaration) ? createToken(SyntaxKind.DotDotDotToken) : undefined;
const name = parameterDeclaration.name ?
@@ -6391,8 +6402,17 @@ namespace ts {
const typePredicate = declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ?
createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) :
undefined;
// JS functions get a free rest parameter if they reference `arguments`
let hasRestLikeParameter = hasRestParameter(declaration);
if (!hasRestLikeParameter && isInJavaScriptFile(declaration) && !hasJSDocParameterTags(declaration) && containsArgumentsReference(declaration)) {
hasRestLikeParameter = true;
const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args");
syntheticArgsSymbol.type = anyArrayType;
syntheticArgsSymbol.isRestParameter = true;
parameters.push(syntheticArgsSymbol);
}
links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, hasRestParameter(declaration), hasLiteralTypes);
links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, hasRestLikeParameter, hasLiteralTypes);
}
return links.resolvedSignature;
}
@@ -6427,14 +6447,14 @@ namespace ts {
}
}
function containsArgumentsReference(declaration: FunctionLikeDeclaration): boolean {
function containsArgumentsReference(declaration: SignatureDeclaration): boolean {
const links = getNodeLinks(declaration);
if (links.containsArgumentsReference === undefined) {
if (links.flags & NodeCheckFlags.CaptureArguments) {
links.containsArgumentsReference = true;
}
else {
links.containsArgumentsReference = traverse(declaration.body);
links.containsArgumentsReference = traverse((declaration as FunctionLikeDeclaration).body);
}
}
return links.containsArgumentsReference;
@@ -6821,21 +6841,46 @@ namespace ts {
return undefined;
}
function resolveTypeReferenceName(typeReferenceName: EntityNameExpression | EntityName) {
function resolveTypeReferenceName(typeReferenceName: EntityNameExpression | EntityName, meaning: SymbolFlags) {
if (!typeReferenceName) {
return unknownSymbol;
}
return resolveEntityName(typeReferenceName, SymbolFlags.Type) || unknownSymbol;
return resolveEntityName(typeReferenceName, meaning) || unknownSymbol;
}
function getTypeReferenceType(node: TypeReferenceType, symbol: Symbol) {
const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced.
if (symbol === unknownSymbol) {
return unknownType;
}
const type = getTypeReferenceTypeWorker(node, symbol, typeArguments);
if (type) {
return type;
}
if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
// A JSDocTypeReference may have resolved to a value (as opposed to a type). If
// the symbol is a constructor function, return the inferred class type; otherwise,
// the type of this reference is just the type of the value we resolved to.
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType)) {
const referenceType = getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
if (referenceType) {
return referenceType;
}
}
// Resolve the type reference as a Type for the purpose of reporting errors.
resolveTypeReferenceName(getTypeReferenceName(node), SymbolFlags.Type);
return valueType;
}
return getTypeFromNonGenericTypeReference(node, symbol);
}
function getTypeReferenceTypeWorker(node: TypeReferenceType, symbol: Symbol, typeArguments: Type[]): Type | undefined {
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
}
@@ -6844,14 +6889,9 @@ namespace ts {
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
}
if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
// A JSDocTypeReference may have resolved to a value (as opposed to a type). In
// that case, the type of this reference is just the type of the value we resolved
// to.
return getTypeOfSymbol(symbol);
if (symbol.flags & SymbolFlags.Function && node.kind === SyntaxKind.JSDocTypeReference && (symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
return getInferredClassType(symbol);
}
return getTypeFromNonGenericTypeReference(node, symbol);
}
function getPrimitiveTypeFromJSDocTypeReference(node: JSDocTypeReference): Type {
@@ -6894,22 +6934,13 @@ namespace ts {
if (!links.resolvedType) {
let symbol: Symbol;
let type: Type;
let meaning = SymbolFlags.Type;
if (node.kind === SyntaxKind.JSDocTypeReference) {
type = getPrimitiveTypeFromJSDocTypeReference(<JSDocTypeReference>node);
if (!type) {
const typeReferenceName = getTypeReferenceName(node);
symbol = resolveTypeReferenceName(typeReferenceName);
type = getTypeReferenceType(node, symbol);
}
type = getPrimitiveTypeFromJSDocTypeReference(node);
meaning |= SymbolFlags.Value;
}
else {
// We only support expressions that are simple qualified names. For other expressions this produces undefined.
const typeNameOrExpression: EntityNameOrEntityNameExpression = node.kind === SyntaxKind.TypeReference
? (<TypeReferenceNode>node).typeName
: isEntityNameExpression((<ExpressionWithTypeArguments>node).expression)
? <EntityNameExpression>(<ExpressionWithTypeArguments>node).expression
: undefined;
symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol;
if (!type) {
symbol = resolveTypeReferenceName(getTypeReferenceName(node), meaning);
type = getTypeReferenceType(node, symbol);
}
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
@@ -15513,21 +15544,6 @@ namespace ts {
}
}
if (signatures.length === 1) {
const declaration = signatures[0].declaration;
if (declaration && isInJavaScriptFile(declaration) && !hasJSDocParameterTags(declaration)) {
if (containsArgumentsReference(<FunctionLikeDeclaration>declaration)) {
const signatureWithRest = cloneSignature(signatures[0]);
const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args");
syntheticArgsSymbol.type = anyArrayType;
syntheticArgsSymbol.isRestParameter = true;
signatureWithRest.parameters = concatenate(signatureWithRest.parameters, [syntheticArgsSymbol]);
signatureWithRest.hasRestParameter = true;
signatures = [signatureWithRest];
}
}
}
const candidates = candidatesOutArray || [];
// reorderCandidates fills up the candidates array directly
reorderCandidates(signatures, candidates);
@@ -16176,6 +16192,12 @@ namespace ts {
return links.inferredClassType;
}
function isInferredClassType(type: Type) {
return type.symbol
&& getObjectFlags(type) & ObjectFlags.Anonymous
&& getSymbolLinks(type.symbol).inferredClassType === type;
}
/**
* Syntactically and semantically checks a call or new expression.
* @param node The call/new expression to be checked.
@@ -16812,8 +16834,9 @@ namespace ts {
(expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword) {
// Look for if this is the constructor for the class that `symbol` is a property of.
const func = getContainingFunction(expr);
if (!(func && func.kind === SyntaxKind.Constructor))
if (!(func && func.kind === SyntaxKind.Constructor)) {
return true;
}
// If func.parent is a class and symbol is a (readonly) property of that class, or
// if func is a constructor and symbol is a (readonly) parameter property declared in it,
// then symbol is writeable here.
@@ -19367,8 +19390,8 @@ namespace ts {
function checkFunctionDeclaration(node: FunctionDeclaration): void {
if (produceDiagnostics) {
checkFunctionOrMethodDeclaration(node) || checkGrammarForGenerator(node);
checkFunctionOrMethodDeclaration(node);
checkGrammarForGenerator(node);
checkCollisionWithCapturedSuperVariable(node, node.name);
checkCollisionWithCapturedThisVariable(node, node.name);
checkCollisionWithCapturedNewTargetVariable(node, node.name);
@@ -21845,6 +21868,10 @@ namespace ts {
if (moduleSymbol && hasExportAssignmentSymbol(moduleSymbol)) {
error(node.moduleSpecifier, Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol));
}
if (modulekind !== ModuleKind.System && modulekind !== ModuleKind.ES2015) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.ExportStar);
}
}
}
}
@@ -23519,7 +23546,8 @@ namespace ts {
case ExternalEmitHelpers.AsyncGenerator: return "__asyncGenerator";
case ExternalEmitHelpers.AsyncDelegator: return "__asyncDelegator";
case ExternalEmitHelpers.AsyncValues: return "__asyncValues";
default: Debug.fail("Unrecognized helper.");
case ExternalEmitHelpers.ExportStar: return "__exportStar";
default: Debug.fail("Unrecognized helper");
}
}
+12 -8
View File
@@ -1626,10 +1626,12 @@ namespace ts {
}
// Remove any subpaths under an existing recursively watched directory.
for (const key in wildcardDirectories) if (hasProperty(wildcardDirectories, key)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
for (const key in wildcardDirectories) {
if (hasProperty(wildcardDirectories, key)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
}
}
}
}
@@ -1717,10 +1719,12 @@ namespace ts {
/* @internal */
export function convertCompilerOptionsForTelemetry(opts: ts.CompilerOptions): ts.CompilerOptions {
const out: ts.CompilerOptions = {};
for (const key in opts) if (opts.hasOwnProperty(key)) {
const type = getOptionFromName(key);
if (type !== undefined) { // Ignore unknown options
out[key] = getOptionValueWithEmptyStrings(opts[key], type);
for (const key in opts) {
if (opts.hasOwnProperty(key)) {
const type = getOptionFromName(key);
if (type !== undefined) { // Ignore unknown options
out[key] = getOptionValueWithEmptyStrings(opts[key], type);
}
}
}
return out;
+45 -18
View File
@@ -51,8 +51,10 @@ namespace ts {
// Copies keys/values from template. Note that for..in will not throw if
// template is undefined, and instead will just exit the loop.
for (const key in template) if (hasOwnProperty.call(template, key)) {
map.set(key, template[key]);
for (const key in template) {
if (hasOwnProperty.call(template, key)) {
map.set(key, template[key]);
}
}
return map;
@@ -521,8 +523,8 @@ namespace ts {
return result || array;
}
export function mapDefined<T>(array: ReadonlyArray<T>, mapFn: (x: T, i: number) => T | undefined): ReadonlyArray<T> {
const result: T[] = [];
export function mapDefined<T, U>(array: ReadonlyArray<T>, mapFn: (x: T, i: number) => U | undefined): U[] {
const result: U[] = [];
for (let i = 0; i < array.length; i++) {
const item = array[i];
const mapped = mapFn(item, i);
@@ -977,9 +979,12 @@ namespace ts {
*/
export function getOwnKeys<T>(map: MapLike<T>): string[] {
const keys: string[] = [];
for (const key in map) if (hasOwnProperty.call(map, key)) {
keys.push(key);
for (const key in map) {
if (hasOwnProperty.call(map, key)) {
keys.push(key);
}
}
return keys;
}
@@ -1042,8 +1047,10 @@ namespace ts {
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]): any;
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]) {
for (const arg of args) {
for (const p in arg) if (hasProperty(arg, p)) {
t[p] = arg[p];
for (const p in arg) {
if (hasProperty(arg, p)) {
t[p] = arg[p];
}
}
}
return t;
@@ -1058,13 +1065,19 @@ namespace ts {
export function equalOwnProperties<T>(left: MapLike<T>, right: MapLike<T>, equalityComparer?: (left: T, right: T) => boolean) {
if (left === right) return true;
if (!left || !right) return false;
for (const key in left) if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false;
for (const key in left) {
if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false;
}
}
for (const key in right) if (hasOwnProperty.call(right, key)) {
if (!hasOwnProperty.call(left, key)) return false;
for (const key in right) {
if (hasOwnProperty.call(right, key)) {
if (!hasOwnProperty.call(left, key)) return false;
}
}
return true;
}
@@ -1106,12 +1119,18 @@ namespace ts {
export function extend<T1, T2>(first: T1, second: T2): T1 & T2 {
const result: T1 & T2 = <any>{};
for (const id in second) if (hasOwnProperty.call(second, id)) {
(result as any)[id] = (second as any)[id];
for (const id in second) {
if (hasOwnProperty.call(second, id)) {
(result as any)[id] = (second as any)[id];
}
}
for (const id in first) if (hasOwnProperty.call(first, id)) {
(result as any)[id] = (first as any)[id];
for (const id in first) {
if (hasOwnProperty.call(first, id)) {
(result as any)[id] = (first as any)[id];
}
}
return result;
}
@@ -2249,6 +2268,7 @@ namespace ts {
getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol;
getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type;
getSignatureConstructor(): new (checker: TypeChecker) => Signature;
getSourceMapSourceConstructor(): new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource;
}
function Symbol(this: Symbol, flags: SymbolFlags, name: string) {
@@ -2279,6 +2299,12 @@ namespace ts {
this.original = undefined;
}
function SourceMapSource(this: SourceMapSource, fileName: string, text: string, skipTrivia?: (pos: number) => number) {
this.fileName = fileName;
this.text = text;
this.skipTrivia = skipTrivia || (pos => pos);
}
export let objectAllocator: ObjectAllocator = {
getNodeConstructor: () => <any>Node,
getTokenConstructor: () => <any>Node,
@@ -2286,7 +2312,8 @@ namespace ts {
getSourceFileConstructor: () => <any>Node,
getSymbolConstructor: () => <any>Symbol,
getTypeConstructor: () => <any>Type,
getSignatureConstructor: () => <any>Signature
getSignatureConstructor: () => <any>Signature,
getSourceMapSourceConstructor: () => <any>SourceMapSource,
};
export const enum AssertionLevel {
+20 -6
View File
@@ -959,7 +959,7 @@ namespace ts {
function emitConstructorType(node: ConstructorTypeNode) {
write("new ");
emitTypeParameters(node, node.typeParameters);
emitParametersForArrow(node, node.parameters);
emitParameters(node, node.parameters);
write(" => ");
emit(node.type);
}
@@ -2283,11 +2283,25 @@ namespace ts {
emitList(parentNode, parameters, ListFormat.Parameters);
}
function emitParametersForArrow(parentNode: Node, parameters: NodeArray<ParameterDeclaration>) {
if (parameters &&
parameters.length === 1 &&
parameters[0].type === undefined &&
parameters[0].pos === parentNode.pos) {
function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
const parameter = singleOrUndefined(parameters);
return parameter
&& parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
&& !(isArrowFunction(parentNode) && parentNode.type) // arrow function may not have return type annotation
&& !some(parentNode.decorators) // parent may not have decorators
&& !some(parentNode.modifiers) // parent may not have modifiers
&& !some(parentNode.typeParameters) // parent may not have type parameters
&& !some(parameter.decorators) // parameter may not have decorators
&& !some(parameter.modifiers) // parameter may not have modifiers
&& !parameter.dotDotDotToken // parameter may not be rest
&& !parameter.questionToken // parameter may not be optional
&& !parameter.type // parameter may not have a type annotation
&& !parameter.initializer // parameter may not have an initializer
&& isIdentifier(parameter.name); // parameter name must be identifier
}
function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray<ParameterDeclaration>) {
if (canEmitSimpleArrowHead(parentNode, parameters)) {
emit(parameters[0]);
}
else {
+44 -24
View File
@@ -228,7 +228,7 @@ namespace ts {
// Signature elements
export function createTypeParameterDeclaration(name: string | Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
export function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration;
node.name = asName(name);
node.constraint = constraint;
@@ -2314,15 +2314,24 @@ namespace ts {
/**
* Sets a custom text range to use when emitting source maps.
*/
export function setSourceMapRange<T extends Node>(node: T, range: TextRange | undefined) {
export function setSourceMapRange<T extends Node>(node: T, range: SourceMapRange | undefined) {
getOrCreateEmitNode(node).sourceMapRange = range;
return node;
}
let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource;
/**
* Create an external source map source file reference
*/
export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource {
return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia);
}
/**
* Gets the TextRange to use for source maps for a token of a node.
*/
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): TextRange | undefined {
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): SourceMapRange | undefined {
const emitNode = node.emitNode;
const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges;
return tokenSourceMapRanges && tokenSourceMapRanges[token];
@@ -2331,7 +2340,7 @@ namespace ts {
/**
* Sets the TextRange to use for source maps for a token of a node.
*/
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange | undefined) {
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: SourceMapRange | undefined) {
const emitNode = getOrCreateEmitNode(node);
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []);
tokenSourceMapRanges[token] = range;
@@ -3841,23 +3850,34 @@ namespace ts {
return emitNode && emitNode.externalHelpersModuleName;
}
export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions) {
if (compilerOptions.importHelpers && (isExternalModule(node) || compilerOptions.isolatedModules)) {
export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean) {
if (compilerOptions.importHelpers && isEffectiveExternalModule(node, compilerOptions)) {
const externalHelpersModuleName = getExternalHelpersModuleName(node);
if (externalHelpersModuleName) {
return externalHelpersModuleName;
}
const helpers = getEmitHelpers(node);
if (helpers) {
for (const helper of helpers) {
if (!helper.scoped) {
const parseNode = getOriginalNode(node, isSourceFile);
const emitNode = getOrCreateEmitNode(parseNode);
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
const moduleKind = getEmitModuleKind(compilerOptions);
let create = hasExportStarsToExportValues
&& moduleKind !== ModuleKind.System
&& moduleKind !== ModuleKind.ES2015;
if (!create) {
const helpers = getEmitHelpers(node);
if (helpers) {
for (const helper of helpers) {
if (!helper.scoped) {
create = true;
break;
}
}
}
}
if (create) {
const parseNode = getOriginalNode(node, isSourceFile);
const emitNode = getOrCreateEmitNode(parseNode);
return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText));
}
}
}
@@ -4240,17 +4260,6 @@ namespace ts {
let exportEquals: ExportAssignment = undefined;
let hasExportStarsToExportValues = false;
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions);
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText));
if (externalHelpersImportDeclaration) {
externalImports.push(externalHelpersImportDeclaration);
}
for (const node of sourceFile.statements) {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
@@ -4361,6 +4370,17 @@ namespace ts {
}
}
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues);
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText));
if (externalHelpersImportDeclaration) {
externalImports.unshift(externalHelpersImportDeclaration);
}
return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration };
}
+15 -19
View File
@@ -6663,14 +6663,12 @@ namespace ts {
});
}
function parseBracketNameInPropertyAndParamTag() {
let name: Identifier;
let isBracketed: boolean;
function parseBracketNameInPropertyAndParamTag(): { name: Identifier, isBracketed: boolean } {
// Looking for something like '[foo]' or 'foo'
if (parseOptionalToken(SyntaxKind.OpenBracketToken)) {
name = parseJSDocIdentifierName();
const isBracketed = parseOptional(SyntaxKind.OpenBracketToken);
const name = parseJSDocIdentifierName(/*createIfMissing*/ true);
if (isBracketed) {
skipWhitespace();
isBracketed = true;
// May have an optional default, e.g. '[foo = 42]'
if (parseOptionalToken(SyntaxKind.EqualsToken)) {
@@ -6679,9 +6677,7 @@ namespace ts {
parseExpected(SyntaxKind.CloseBracketToken);
}
else if (tokenIsIdentifierOrKeyword(token())) {
name = parseJSDocIdentifierName();
}
return { name, isBracketed };
}
@@ -6692,11 +6688,6 @@ namespace ts {
const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
skipWhitespace();
if (!name) {
parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected);
return undefined;
}
let preName: Identifier, postName: Identifier;
if (typeExpression) {
postName = name;
@@ -6947,14 +6938,19 @@ namespace ts {
return currentToken = scanner.scanJSDocToken();
}
function parseJSDocIdentifierName(): Identifier {
return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token()));
function parseJSDocIdentifierName(createIfMissing = false): Identifier {
return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token()), createIfMissing);
}
function createJSDocIdentifier(isIdentifier: boolean): Identifier {
function createJSDocIdentifier(isIdentifier: boolean, createIfMissing: boolean): Identifier {
if (!isIdentifier) {
parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
return undefined;
if (createIfMissing) {
return <Identifier>createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
}
else {
parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
return undefined;
}
}
const pos = scanner.getTokenPos();
+1 -1
View File
@@ -363,7 +363,7 @@ namespace ts {
};
}
export function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter {
export function getLineAndCharacterOfPosition(sourceFile: SourceFileLike, position: number): LineAndCharacter {
return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position);
}
+33 -14
View File
@@ -22,7 +22,7 @@ namespace ts {
*
* @param sourceFile The source file.
*/
setSourceFile(sourceFile: SourceFile): void;
setSourceFile(sourceFile: SourceMapSource): void;
/**
* Emits a mapping.
@@ -81,7 +81,7 @@ namespace ts {
export function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter): SourceMapWriter {
const compilerOptions = host.getCompilerOptions();
const extendedDiagnostics = compilerOptions.extendedDiagnostics;
let currentSourceFile: SourceFile;
let currentSource: SourceMapSource;
let currentSourceText: string;
let sourceMapDir: string; // The directory in which sourcemap will be
@@ -109,6 +109,13 @@ namespace ts {
getSourceMappingURL,
};
/**
* Skips trivia such as comments and white-space that can optionally overriden by the source map source
*/
function skipSourceTrivia(pos: number): number {
return currentSource.skipTrivia ? currentSource.skipTrivia(pos) : skipTrivia(currentSourceText, pos);
}
/**
* Initialize the SourceMapWriter for a new output file.
*
@@ -125,7 +132,7 @@ namespace ts {
reset();
}
currentSourceFile = undefined;
currentSource = undefined;
currentSourceText = undefined;
// Current source map file and its index in the sources list
@@ -192,7 +199,7 @@ namespace ts {
return;
}
currentSourceFile = undefined;
currentSource = undefined;
sourceMapDir = undefined;
sourceMapSourceIndex = undefined;
lastRecordedSourceMapSpan = undefined;
@@ -263,7 +270,7 @@ namespace ts {
performance.mark("beforeSourcemap");
}
const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos);
const sourceLinePos = getLineAndCharacterOfPosition(currentSource, pos);
// Convert the location to be one-based.
sourceLinePos.line++;
@@ -320,14 +327,22 @@ namespace ts {
if (node) {
const emitNode = node.emitNode;
const emitFlags = emitNode && emitNode.flags;
const { pos, end } = emitNode && emitNode.sourceMapRange || node;
const range = emitNode && emitNode.sourceMapRange;
const { pos, end } = range || node;
let source = range && range.source;
const oldSource = currentSource;
if (source === oldSource) source = undefined;
if (source) setSourceFile(source);
if (node.kind !== SyntaxKind.NotEmittedStatement
&& (emitFlags & EmitFlags.NoLeadingSourceMap) === 0
&& pos >= 0) {
emitPos(skipTrivia(currentSourceText, pos));
emitPos(skipSourceTrivia(pos));
}
if (source) setSourceFile(oldSource);
if (emitFlags & EmitFlags.NoNestedSourceMaps) {
disabled = true;
emitCallback(hint, node);
@@ -337,11 +352,15 @@ namespace ts {
emitCallback(hint, node);
}
if (source) setSourceFile(source);
if (node.kind !== SyntaxKind.NotEmittedStatement
&& (emitFlags & EmitFlags.NoTrailingSourceMap) === 0
&& end >= 0) {
emitPos(end);
}
if (source) setSourceFile(oldSource);
}
}
@@ -362,7 +381,7 @@ namespace ts {
const emitFlags = emitNode && emitNode.flags;
const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges[token];
tokenPos = skipTrivia(currentSourceText, range ? range.pos : tokenPos);
tokenPos = skipSourceTrivia(range ? range.pos : tokenPos);
if ((emitFlags & EmitFlags.NoTokenLeadingSourceMaps) === 0 && tokenPos >= 0) {
emitPos(tokenPos);
}
@@ -382,13 +401,13 @@ namespace ts {
*
* @param sourceFile The source file.
*/
function setSourceFile(sourceFile: SourceFile) {
function setSourceFile(sourceFile: SourceMapSource) {
if (disabled) {
return;
}
currentSourceFile = sourceFile;
currentSourceText = currentSourceFile.text;
currentSource = sourceFile;
currentSourceText = currentSource.text;
// Add the file to tsFilePaths
// If sourceroot option: Use the relative path corresponding to the common directory path
@@ -396,7 +415,7 @@ namespace ts {
const sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir;
const source = getRelativePathToDirectoryOrUrl(sourcesDirectoryPath,
currentSourceFile.fileName,
currentSource.fileName,
host.getCurrentDirectory(),
host.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ true);
@@ -407,10 +426,10 @@ namespace ts {
sourceMapData.sourceMapSources.push(source);
// The one that can be used from program to get the actual source file
sourceMapData.inputSourceFileNames.push(currentSourceFile.fileName);
sourceMapData.inputSourceFileNames.push(currentSource.fileName);
if (compilerOptions.inlineSources) {
sourceMapData.sourceMapSourcesContent.push(currentSourceFile.text);
sourceMapData.sourceMapSourcesContent.push(currentSource.text);
}
}
}
+12 -12
View File
@@ -103,7 +103,7 @@ namespace ts {
addRange(statements, endLexicalEnvironment());
const updated = updateSourceFileNode(node, setTextRange(createNodeArray(statements), node.statements));
if (currentModuleInfo.hasExportStarsToExportValues) {
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {
// If we have any `export * from ...` declarations
// we need to inform the emitter to add the __export helper.
addEmitHelper(updated, exportStarHelper);
@@ -408,7 +408,7 @@ namespace ts {
addRange(statements, endLexicalEnvironment());
const body = createBlock(statements, /*multiLine*/ true);
if (currentModuleInfo.hasExportStarsToExportValues) {
if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) {
// If we have any `export * from ...` declarations
// we need to inform the emitter to add the __export helper.
addEmitHelper(body, exportStarHelper);
@@ -833,15 +833,7 @@ namespace ts {
// export * from "mod";
return setTextRange(
createStatement(
createCall(
createIdentifier("__export"),
/*typeArguments*/ undefined,
[
moduleKind !== ModuleKind.AMD
? createRequireCall(node)
: generatedName
]
)
createExportStarHelper(context, moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName)
),
node
);
@@ -1598,9 +1590,17 @@ namespace ts {
text: `
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}`
}
`
};
function createExportStarHelper(context: TransformationContext, module: Expression) {
const compilerOptions = context.getCompilerOptions();
return compilerOptions.importHelpers
? createCall(getHelperName("__exportStar"), /*typeArguments*/ undefined, [module, createIdentifier("exports")])
: createCall(createIdentifier("__export"), /*typeArguments*/ undefined, [module]);
}
// emit helper for dynamic import
const dynamicImportUMDHelper: EmitHelper = {
name: "typescript:dynamicimport-sync-require",
+23 -11
View File
@@ -425,7 +425,7 @@ namespace ts {
FirstNode = QualifiedName,
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocLiteralType,
FirstJSDocTagNode = JSDocComment,
FirstJSDocTagNode = JSDocTag,
LastJSDocTagNode = JSDocLiteralType
}
@@ -4013,18 +4013,29 @@ namespace ts {
ES2015FunctionSyntaxMask = ContainsCapturedLexicalThis | ContainsDefaultValueAssignments,
}
export interface SourceMapRange extends TextRange {
source?: SourceMapSource;
}
export interface SourceMapSource {
fileName: string;
text: string;
/* @internal */ lineMap: number[];
skipTrivia?: (pos: number) => number;
}
/* @internal */
export interface EmitNode {
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
flags?: EmitFlags; // Flags that customize emit
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
flags?: EmitFlags; // Flags that customize emit
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
trailingComments?: SynthesizedComment[]; // Synthesized trailing comments
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
sourceMapRange?: TextRange; // The text range to use when emitting leading or trailing source mappings
tokenSourceMapRanges?: TextRange[]; // The text range to use when emitting source mappings for tokens
constantValue?: string | number; // The constant value of an expression
externalHelpersModuleName?: Identifier; // The local name for an imported helpers module
helpers?: EmitHelper[]; // Emit helpers for the node
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
sourceMapRange?: SourceMapRange; // The text range to use when emitting leading or trailing source mappings
tokenSourceMapRanges?: SourceMapRange[]; // The text range to use when emitting source mappings for tokens
constantValue?: string | number; // The constant value of an expression
externalHelpersModuleName?: Identifier; // The local name for an imported helpers module
helpers?: EmitHelper[]; // Emit helpers for the node
}
export const enum EmitFlags {
@@ -4086,6 +4097,7 @@ namespace ts {
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation)
// Helpers included by ES2015 for..of
ForOfIncludes = Values,
@@ -4103,7 +4115,7 @@ namespace ts {
SpreadIncludes = Read | Spread,
FirstEmitHelper = Extends,
LastEmitHelper = AsyncValues
LastEmitHelper = ExportStar
}
export const enum EmitHint {
+47 -32
View File
@@ -1036,21 +1036,27 @@ namespace FourSlash {
fail(`Expected ${expected}, got ${actual}`);
}
for (const key in actual) if (ts.hasProperty(actual as any, key)) {
const ak = actual[key], ek = expected[key];
if (typeof ak === "object" && typeof ek === "object") {
recur(ak, ek, path ? path + "." + key : key);
}
else if (ak !== ek) {
fail(`Expected '${key}' to be '${ek}', got '${ak}'`);
for (const key in actual) {
if (ts.hasProperty(actual as any, key)) {
const ak = actual[key], ek = expected[key];
if (typeof ak === "object" && typeof ek === "object") {
recur(ak, ek, path ? path + "." + key : key);
}
else if (ak !== ek) {
fail(`Expected '${key}' to be '${ek}', got '${ak}'`);
}
}
}
for (const key in expected) if (ts.hasProperty(expected as any, key)) {
if (!ts.hasProperty(actual as any, key)) {
fail(`${msgPrefix}Missing property '${key}'`);
for (const key in expected) {
if (ts.hasProperty(expected as any, key)) {
if (!ts.hasProperty(actual as any, key)) {
fail(`${msgPrefix}Missing property '${key}'`);
}
}
}
};
if (fullActual === undefined || fullExpected === undefined) {
if (fullActual === fullExpected) {
return;
@@ -1132,15 +1138,17 @@ namespace FourSlash {
}
public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) {
for (const name in namesAndTexts) if (ts.hasProperty(namesAndTexts, name)) {
const text = namesAndTexts[name];
if (ts.isArray(text)) {
assert(text.length === 2);
const [expectedText, expectedDocumentation] = text;
this.verifyQuickInfoAt(name, expectedText, expectedDocumentation);
}
else {
this.verifyQuickInfoAt(name, text);
for (const name in namesAndTexts) {
if (ts.hasProperty(namesAndTexts, name)) {
const text = namesAndTexts[name];
if (ts.isArray(text)) {
assert(text.length === 2);
const [expectedText, expectedDocumentation] = text;
this.verifyQuickInfoAt(name, expectedText, expectedDocumentation);
}
else {
this.verifyQuickInfoAt(name, text);
}
}
}
}
@@ -1149,7 +1157,6 @@ namespace FourSlash {
if (expectedDocumentation === "") {
throw new Error("Use 'undefined' instead");
}
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
const actualQuickInfoText = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.displayParts) : "";
const actualQuickInfoDocumentation = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.documentation) : "";
@@ -1595,16 +1602,19 @@ namespace FourSlash {
}
private printMembersOrCompletions(info: ts.CompletionInfo) {
if (info === undefined) { return "No completion info."; }
const { entries } = info;
function pad(s: string, length: number) {
return s + new Array(length - s.length + 1).join(" ");
}
function max<T>(arr: T[], selector: (x: T) => number): number {
return arr.reduce((prev, x) => Math.max(prev, selector(x)), 0);
}
const longestNameLength = max(info.entries, m => m.name.length);
const longestKindLength = max(info.entries, m => m.kind.length);
info.entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0);
const membersString = info.entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers}`).join("\n");
const longestNameLength = max(entries, m => m.name.length);
const longestKindLength = max(entries, m => m.kind.length);
entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0);
const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers}`).join("\n");
Harness.IO.log(membersString);
}
@@ -2156,7 +2166,7 @@ namespace FourSlash {
Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos), "**"));
}
private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[]) {
private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) {
if (actual.length !== expected.length) {
this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length +
", but was " + actual.length +
@@ -2196,9 +2206,11 @@ namespace FourSlash {
});
function jsonMismatchString() {
const showActual = actual.map(({ classificationType, textSpan }) =>
({ classificationType, text: sourceFileText.slice(textSpan.start, textSpan.start + textSpan.length) }));
return Harness.IO.newLine() +
"expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() +
"actual: '" + Harness.IO.newLine() + stringify(actual) + "'";
"actual: '" + Harness.IO.newLine() + stringify(showActual) + "'";
}
}
@@ -2221,14 +2233,14 @@ namespace FourSlash {
const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
ts.createTextSpan(0, this.activeFile.content.length));
this.verifyClassifications(expected, actual);
this.verifyClassifications(expected, actual, this.activeFile.content);
}
public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) {
const actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
ts.createTextSpan(0, this.activeFile.content.length));
this.verifyClassifications(expected, actual);
this.verifyClassifications(expected, actual, this.activeFile.content);
}
public verifyOutliningSpans(spans: TextSpan[]) {
@@ -2741,6 +2753,7 @@ namespace FourSlash {
markerName: string,
expectedContent: string,
refactorNameToApply: string,
actionName: string,
formattingOptions?: ts.FormatCodeSettings) {
formattingOptions = formattingOptions || this.formatCodeSettings;
@@ -2753,9 +2766,11 @@ namespace FourSlash {
this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`);
}
const codeActions = this.languageService.getRefactorCodeActions(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply);
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName);
this.applyCodeActions(codeActions);
for (const edit of editInfo.edits) {
this.applyEdits(edit.fileName, edit.textChanges);
}
const actualContent = this.getFileContent(this.activeFile.fileName);
if (this.normalizeNewlines(actualContent) !== this.normalizeNewlines(expectedContent)) {
@@ -3798,8 +3813,8 @@ namespace FourSlashInterface {
this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index);
}
public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: ts.FormatCodeSettings): void {
this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, formattingOptions);
public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: ts.FormatCodeSettings): void {
this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, actionName, formattingOptions);
}
public rangeIs(expectedText: string, includeWhiteSpace?: boolean): void {
+2 -1
View File
@@ -259,8 +259,9 @@ namespace Utils {
return true;
}
else if ((f & v) > 0) {
if (result.length)
if (result.length) {
result += " | ";
}
result += flags[v];
return false;
}
+1 -1
View File
@@ -492,7 +492,7 @@ namespace Harness.LanguageService {
getCodeFixDiagnostics(): ts.Diagnostic[] {
throw new Error("Not supported on the shim.");
}
getRefactorCodeActions(): ts.CodeAction[] {
getEditsForRefactor(): ts.RefactorEditInfo {
throw new Error("Not supported on the shim.");
}
getApplicableRefactors(): ts.ApplicableRefactorInfo[] {
+124 -51
View File
@@ -81,63 +81,136 @@ namespace ts {
describe("printNode", () => {
const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly");
let sourceFile: SourceFile;
before(() => sourceFile = createSourceFile("source.ts", "", ScriptTarget.ES2015));
// tslint:disable boolean-trivia
const syntheticNode = createClassDeclaration(
undefined,
undefined,
/*name*/ createIdentifier("C"),
undefined,
undefined,
createNodeArray([
createProperty(
undefined,
printsCorrectly("class", {}, printer => printer.printNode(
EmitHint.Unspecified,
createClassDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*name*/ createIdentifier("C"),
/*typeParameters*/ undefined,
/*heritageClauses*/ undefined,
[createProperty(
/*decorators*/ undefined,
createNodeArray([createToken(SyntaxKind.PublicKeyword)]),
createIdentifier("prop"),
undefined,
undefined,
undefined
)
])
);
/*questionToken*/ undefined,
/*type*/ undefined,
/*initializer*/ undefined
)]
),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(
EmitHint.Unspecified,
createNamespaceExportDeclaration("B"),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
// https://github.com/Microsoft/TypeScript/issues/15971
const classWithOptionalMethodAndProperty = createClassDeclaration(
undefined,
/* modifiers */ createNodeArray([createToken(SyntaxKind.DeclareKeyword)]),
/* name */ createIdentifier("X"),
undefined,
undefined,
createNodeArray([
createMethod(
undefined,
undefined,
undefined,
/* name */ createIdentifier("method"),
/* questionToken */ createToken(SyntaxKind.QuestionToken),
undefined,
undefined,
/* type */ createKeywordTypeNode(SyntaxKind.VoidKeyword),
undefined
printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(
EmitHint.Unspecified,
createClassDeclaration(
/*decorators*/ undefined,
/*modifiers*/ [createToken(SyntaxKind.DeclareKeyword)],
/*name*/ createIdentifier("X"),
/*typeParameters*/ undefined,
/*heritageClauses*/ undefined,
[
createMethod(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ createIdentifier("method"),
/*questionToken*/ createToken(SyntaxKind.QuestionToken),
/*typeParameters*/ undefined,
[],
/*type*/ createKeywordTypeNode(SyntaxKind.VoidKeyword),
/*body*/ undefined
),
createProperty(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*name*/ createIdentifier("property"),
/*questionToken*/ createToken(SyntaxKind.QuestionToken),
/*type*/ createKeywordTypeNode(SyntaxKind.StringKeyword),
/*initializer*/ undefined
),
]
),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
// https://github.com/Microsoft/TypeScript/issues/15651
printsCorrectly("functionTypes", {}, printer => printer.printNode(
EmitHint.Unspecified,
createTupleTypeNode([
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args")
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createProperty(
undefined,
undefined,
/* name */ createIdentifier("property"),
/* questionToken */ createToken(SyntaxKind.QuestionToken),
/* type */ createKeywordTypeNode(SyntaxKind.StringKeyword),
undefined
createFunctionTypeNode(
[createTypeParameterDeclaration("T")],
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args")
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
])
);
// tslint:enable boolean-trivia
printsCorrectly("class", {}, printer => printer.printNode(EmitHint.Unspecified, syntheticNode, sourceFile));
printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(EmitHint.Unspecified, createNamespaceExportDeclaration("B"), sourceFile));
printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(EmitHint.Unspecified, classWithOptionalMethodAndProperty, sourceFile));
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createToken(SyntaxKind.DotDotDotToken),
createIdentifier("args")
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args"),
createToken(SyntaxKind.QuestionToken)
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createIdentifier("args"),
/*questionToken*/ undefined,
createKeywordTypeNode(SyntaxKind.AnyKeyword)
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
createFunctionTypeNode(
/*typeArguments*/ undefined,
[createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
createObjectBindingPattern([])
)],
createKeywordTypeNode(SyntaxKind.AnyKeyword)
),
]),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
});
});
}
+2 -2
View File
@@ -240,8 +240,8 @@ namespace ts.server {
CommandNames.GetCodeFixesFull,
CommandNames.GetSupportedCodeFixes,
CommandNames.GetApplicableRefactors,
CommandNames.GetRefactorCodeActions,
CommandNames.GetRefactorCodeActionsFull,
CommandNames.GetEditsForRefactor,
CommandNames.GetEditsForRefactorFull,
];
it("should not throw when commands are executed with invalid arguments", () => {
+2 -1
View File
@@ -3483,7 +3483,7 @@ interface DragEvent extends MouseEvent {
declare var DragEvent: {
prototype: DragEvent;
new(): DragEvent;
new(type: "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart" | "drop", dragEventInit?: { dataTransfer?: DataTransfer }): DragEvent;
};
interface DynamicsCompressorNode extends AudioNode {
@@ -8224,6 +8224,7 @@ interface Navigator extends Object, NavigatorID, NavigatorOnLine, NavigatorConte
readonly serviceWorker: ServiceWorkerContainer;
readonly webdriver: boolean;
readonly hardwareConcurrency: number;
readonly languages: string[];
getGamepads(): Gamepad[];
javaEnabled(): boolean;
msLaunchUri(uri: string, successCallback?: MSLaunchUriCallback, noHandlerCallback?: MSLaunchUriCallback): void;
+37 -8
View File
@@ -719,20 +719,49 @@ namespace ts.server {
return response.body;
}
getRefactorCodeActions(
getEditsForRefactor(
fileName: string,
_formatOptions: FormatCodeSettings,
positionOrRange: number | TextRange,
refactorName: string) {
refactorName: string,
actionName: string): RefactorEditInfo {
const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetRefactorCodeActionsRequestArgs;
args.refactorName = refactorName;
const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetEditsForRefactorRequestArgs;
args.refactor = refactorName;
args.action = actionName;
const request = this.processRequest<protocol.GetRefactorCodeActionsRequest>(CommandNames.GetRefactorCodeActions, args);
const response = this.processResponse<protocol.GetRefactorCodeActionsResponse>(request);
const codeActions = response.body.actions;
const request = this.processRequest<protocol.GetEditsForRefactorRequest>(CommandNames.GetEditsForRefactor, args);
const response = this.processResponse<protocol.GetEditsForRefactorResponse>(request);
return map(codeActions, codeAction => this.convertCodeActions(codeAction, fileName));
if (!response.body) {
return {
edits: []
};
}
const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits);
const renameFilename: string | undefined = response.body.renameFilename;
let renameLocation: number | undefined = undefined;
if (renameFilename !== undefined) {
renameLocation = this.lineOffsetToPosition(renameFilename, response.body.renameLocation);
}
return {
edits,
renameFilename,
renameLocation
};
}
private convertCodeEditsToTextChanges(edits: ts.server.protocol.FileCodeEdits[]): FileTextChanges[] {
return edits.map(edit => {
const fileName = edit.fileName;
return {
fileName,
textChanges: edit.textChanges.map(t => this.convertTextChangeToCodeEdit(t, fileName))
};
});
}
convertCodeActions(entry: protocol.CodeAction, fileName: string): CodeAction {
+79 -30
View File
@@ -98,8 +98,11 @@ namespace ts.server.protocol {
GetSupportedCodeFixes = "getSupportedCodeFixes",
GetApplicableRefactors = "getApplicableRefactors",
GetRefactorCodeActions = "getRefactorCodeActions",
GetRefactorCodeActionsFull = "getRefactorCodeActions-full",
GetEditsForRefactor = "getEditsForRefactor",
/* @internal */
GetEditsForRefactorFull = "getEditsForRefactor-full",
// NOTE: If updating this, be sure to also update `allCommandNames` in `harness/unittests/session.ts`.
}
/**
@@ -401,52 +404,98 @@ namespace ts.server.protocol {
export type FileLocationOrRangeRequestArgs = FileLocationRequestArgs | FileRangeRequestArgs;
/**
* Request refactorings at a given position or selection area.
*/
export interface GetApplicableRefactorsRequest extends Request {
command: CommandTypes.GetApplicableRefactors;
arguments: GetApplicableRefactorsRequestArgs;
}
export type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs;
export interface ApplicableRefactorInfo {
name: string;
description: string;
}
/**
* Response is a list of available refactorings.
* Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring
*/
export interface GetApplicableRefactorsResponse extends Response {
body?: ApplicableRefactorInfo[];
}
export interface GetRefactorCodeActionsRequest extends Request {
command: CommandTypes.GetRefactorCodeActions;
arguments: GetRefactorCodeActionsRequestArgs;
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
export interface ApplicableRefactorInfo {
/**
* The programmatic name of the refactoring
*/
name: string;
/**
* A description of this refactoring category to show to the user.
* If the refactoring gets inlined (see below), this text will not be visible.
*/
description: string;
/**
* Inlineable refactorings can have their actions hoisted out to the top level
* of a context menu. Non-inlineanable refactorings should always be shown inside
* their parent grouping.
*
* If not specified, this value is assumed to be 'true'
*/
inlineable?: boolean;
actions: RefactorActionInfo[];
}
export type GetRefactorCodeActionsRequestArgs = FileLocationOrRangeRequestArgs & {
/* The kind of the applicable refactor */
refactorName: string;
/**
* Represents a single refactoring action - for example, the "Extract Method..." refactor might
* offer several actions, each corresponding to a surround class or closure to extract into.
*/
export type RefactorActionInfo = {
/**
* The programmatic name of the refactoring action
*/
name: string;
/**
* A description of this refactoring action to show to the user.
* If the parent refactoring is inlined away, this will be the only text shown,
* so this description should make sense by itself if the parent is inlineable=true
*/
description: string;
};
export type RefactorCodeActions = {
actions: protocol.CodeAction[];
renameLocation?: number
};
/* @internal */
export type RefactorCodeActionsFull = {
actions: ts.CodeAction[];
renameLocation?: number
};
export interface GetRefactorCodeActionsResponse extends Response {
body: RefactorCodeActions;
export interface GetEditsForRefactorRequest extends Request {
command: CommandTypes.GetEditsForRefactor;
arguments: GetEditsForRefactorRequestArgs;
}
/* @internal */
export interface GetRefactorCodeActionsFullResponse extends Response {
body: RefactorCodeActionsFull;
/**
* Request the edits that a particular refactoring action produces.
* Callers must specify the name of the refactor and the name of the action.
*/
export type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & {
/* The 'name' property from the refactoring that offered this action */
refactor: string;
/* The 'name' property from the refactoring action */
action: string;
};
export interface GetEditsForRefactorResponse extends Response {
body?: RefactorEditInfo;
}
export type RefactorEditInfo = {
edits: FileCodeEdits[];
/**
* An optional location where the editor should start a rename operation once
* the refactoring edits have been applied
*/
renameLocation?: Location;
renameFilename?: string;
};
/**
* Request for the available codefixes at a specific position.
*/
+1 -1
View File
@@ -526,7 +526,7 @@ namespace ts.server {
watchedFile.callback(watchedFile.fileName);
}
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
watchedFile.mtime = getModifiedTime(watchedFile.fileName);
watchedFile.mtime = stats.mtime;
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
}
});
+41 -18
View File
@@ -1425,29 +1425,40 @@ namespace ts.server {
return project.getLanguageService().getApplicableRefactors(file, position || textRange);
}
private getRefactorCodeActions(args: protocol.GetRefactorCodeActionsRequestArgs, simplifiedResult: boolean): protocol.RefactorCodeActions | protocol.RefactorCodeActionsFull {
private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): ts.RefactorEditInfo | protocol.RefactorEditInfo {
const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
const { position, textRange } = this.extractPositionAndRange(args, scriptInfo);
const result: ts.CodeAction[] = project.getLanguageService().getRefactorCodeActions(
const result = project.getLanguageService().getEditsForRefactor(
file,
this.projectService.getFormatCodeOptions(),
position || textRange,
args.refactorName
args.refactor,
args.action
);
if (simplifiedResult) {
// Not full
if (result === undefined) {
return {
actions: result.map(action => this.mapCodeAction(action, scriptInfo))
edits: []
};
}
if (simplifiedResult) {
const file = result.renameFilename;
let location: ILineInfo | undefined = undefined;
if (file !== undefined && result.renameLocation !== undefined) {
const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(file));
location = renameScriptInfo.positionToLineOffset(result.renameLocation);
}
return {
renameLocation: location,
renameFilename: file,
edits: result.edits.map(change => this.mapTextChangesToCodeEdits(project, change))
};
}
else {
// Full
return {
actions: result
};
return result;
}
}
@@ -1505,6 +1516,14 @@ namespace ts.server {
};
}
private mapTextChangesToCodeEdits(project: Project, textChanges: FileTextChanges): protocol.FileCodeEdits {
const scriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(textChanges.fileName));
return {
fileName: textChanges.fileName,
textChanges: textChanges.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo))
};
}
private convertTextChangeToCodeEdit(change: ts.TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
return {
start: scriptInfo.positionToLineOffset(change.span.start),
@@ -1544,18 +1563,22 @@ namespace ts.server {
const normalizedFileName = toNormalizedPath(fileName);
const project = this.projectService.getDefaultProjectForFile(normalizedFileName, /*refreshInferredProjects*/ true);
for (const fileNameInProject of fileNamesInProject) {
if (this.getCanonicalFileName(fileNameInProject) === this.getCanonicalFileName(fileName))
if (this.getCanonicalFileName(fileNameInProject) === this.getCanonicalFileName(fileName)) {
highPriorityFiles.push(fileNameInProject);
}
else {
const info = this.projectService.getScriptInfo(fileNameInProject);
if (!info.isScriptOpen()) {
if (fileNameInProject.indexOf(".d.ts") > 0)
if (fileNameInProject.indexOf(".d.ts") > 0) {
veryLowPriorityFiles.push(fileNameInProject);
else
}
else {
lowPriorityFiles.push(fileNameInProject);
}
}
else
else {
mediumPriorityFiles.push(fileNameInProject);
}
}
}
@@ -1833,11 +1856,11 @@ namespace ts.server {
[CommandNames.GetApplicableRefactors]: (request: protocol.GetApplicableRefactorsRequest) => {
return this.requiredResponse(this.getApplicableRefactors(request.arguments));
},
[CommandNames.GetRefactorCodeActions]: (request: protocol.GetRefactorCodeActionsRequest) => {
return this.requiredResponse(this.getRefactorCodeActions(request.arguments, /*simplifiedResult*/ true));
[CommandNames.GetEditsForRefactor]: (request: protocol.GetEditsForRefactorRequest) => {
return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ true));
},
[CommandNames.GetRefactorCodeActionsFull]: (request: protocol.GetRefactorCodeActionsRequest) => {
return this.requiredResponse(this.getRefactorCodeActions(request.arguments, /*simplifiedResult*/ false));
[CommandNames.GetEditsForRefactorFull]: (request: protocol.GetEditsForRefactorRequest) => {
return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ false));
}
});
+1 -1
View File
@@ -814,7 +814,7 @@ namespace ts {
* False will mean that node is not classified and traverse routine should recurse into node contents.
*/
function tryClassifyNode(node: Node): boolean {
if (isJSDocTag(node)) {
if (isJSDocNode(node)) {
return true;
}
+74 -27
View File
@@ -18,7 +18,7 @@ namespace ts.Completions {
return undefined;
}
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords } = completionData;
const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, request, hasFilteredClassMemberKeywords } = completionData;
if (sourceFile.languageVariant === LanguageVariant.JSX &&
location && location.parent && location.parent.kind === SyntaxKind.JsxClosingElement) {
@@ -36,14 +36,15 @@ namespace ts.Completions {
}]};
}
if (requestJsDocTagName) {
// If the current position is a jsDoc tag name, only tag names should be provided for completion
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagNameCompletions() };
}
if (requestJsDocTag) {
// If the current position is a jsDoc tag, only tags should be provided for completion
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagCompletions() };
if (request) {
const entries = request.kind === "JsDocTagName"
// If the current position is a jsDoc tag name, only tag names should be provided for completion
? JsDoc.getJSDocTagNameCompletions()
: request.kind === "JsDocTag"
// If the current position is a jsDoc tag, only tags should be provided for completion
? JsDoc.getJSDocTagCompletions()
: JsDoc.getJSDocParameterNameCompletions(request.tag);
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries };
}
const entries: CompletionEntry[] = [];
@@ -66,7 +67,7 @@ namespace ts.Completions {
addRange(entries, classMemberKeywordCompletions);
}
// Add keywords if this is not a member completion list
else if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) {
else if (!isMemberCompletion) {
addRange(entries, keywordCompletions);
}
@@ -347,16 +348,27 @@ namespace ts.Completions {
return undefined;
}
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number) {
interface CompletionData {
symbols: Symbol[];
isGlobalCompletion: boolean;
isMemberCompletion: boolean;
isNewIdentifierLocation: boolean;
location: Node;
isRightOfDot: boolean;
request?: Request;
hasFilteredClassMemberKeywords: boolean;
}
type Request = { kind: "JsDocTagName" } | { kind: "JsDocTag" } | { kind: "JsDocParameterName", tag: JSDocParameterTag };
function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number): CompletionData {
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
// JsDoc tag-name is just the name of the JSDoc tagname (exclude "@")
let requestJsDocTagName = false;
// JsDoc tag includes both "@" and tag-name
let requestJsDocTag = false;
let request: Request | undefined;
let start = timestamp();
const currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); // TODO: GH#15853
const currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false);
// We will check for jsdoc comments with insideComment and getJsDocTagAtPosition. (TODO: that seems rather inefficient to check the same thing so many times.)
log("getCompletionData: Get current token: " + (timestamp() - start));
start = timestamp();
@@ -366,10 +378,10 @@ namespace ts.Completions {
if (insideComment) {
if (hasDocComment(sourceFile, position)) {
// The current position is next to the '@' sign, when no tag name being provided yet.
// Provide a full list of tag names
if (sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) {
requestJsDocTagName = true;
// The current position is next to the '@' sign, when no tag name being provided yet.
// Provide a full list of tag names
request = { kind: "JsDocTagName" };
}
else {
// When completion is requested without "@", we will have check to make sure that
@@ -389,7 +401,9 @@ namespace ts.Completions {
// * |c|
// */
const lineStart = getLineStartPositionForPosition(position, sourceFile);
requestJsDocTag = !(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/));
if (!(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/))) {
request = { kind: "JsDocTag" };
}
}
}
@@ -397,10 +411,10 @@ namespace ts.Completions {
// /** @type {number | string} */
// Completion should work in the brackets
let insideJsDocTagExpression = false;
const tag = getJsDocTagAtPosition(sourceFile, position);
const tag = getJsDocTagAtPosition(currentToken, position);
if (tag) {
if (tag.tagName.pos <= position && position <= tag.tagName.end) {
requestJsDocTagName = true;
request = { kind: "JsDocTagName" };
}
switch (tag.kind) {
@@ -408,15 +422,18 @@ namespace ts.Completions {
case SyntaxKind.JSDocParameterTag:
case SyntaxKind.JSDocReturnTag:
const tagWithExpression = <JSDocTypeTag | JSDocParameterTag | JSDocReturnTag>tag;
if (tagWithExpression.typeExpression) {
insideJsDocTagExpression = tagWithExpression.typeExpression.pos < position && position < tagWithExpression.typeExpression.end;
if (tagWithExpression.typeExpression && tagWithExpression.typeExpression.pos < position && position < tagWithExpression.typeExpression.end) {
insideJsDocTagExpression = true;
}
else if (isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) {
request = { kind: "JsDocParameterName", tag };
}
break;
}
}
if (requestJsDocTagName || requestJsDocTag) {
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords: false };
if (request) {
return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, request, hasFilteredClassMemberKeywords: false };
}
if (!insideJsDocTagExpression) {
@@ -553,7 +570,7 @@ namespace ts.Completions {
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords };
return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), request, hasFilteredClassMemberKeywords };
function getTypeScriptMemberSymbols(): void {
// Right of dot member completion list
@@ -1518,4 +1535,34 @@ namespace ts.Completions {
kind === SyntaxKind.EqualsEqualsEqualsToken ||
kind === SyntaxKind.ExclamationEqualsEqualsToken;
}
/** Get the corresponding JSDocTag node if the position is in a jsDoc comment */
function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined {
const { jsDoc } = getJsDocHavingNode(node);
if (!jsDoc) return undefined;
for (const { pos, end, tags } of jsDoc) {
if (!tags || position < pos || position > end) continue;
for (let i = tags.length - 1; i >= 0; i--) {
const tag = tags[i];
if (position >= tag.pos) {
return tag;
}
}
}
}
function getJsDocHavingNode(node: Node): Node {
if (!isToken(node)) return node;
switch (node.kind) {
case SyntaxKind.VarKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
// if the current token is var, let or const, skip the VariableDeclarationList
return node.parent.parent;
default:
return node.parent;
}
}
}
+4 -5
View File
@@ -496,11 +496,10 @@ namespace ts.FindAllReferences.Core {
const { text = stripQuotes(getDeclaredName(this.checker, symbol, location)), allSearchSymbols = undefined } = searchOptions;
const escapedText = escapeIdentifier(text);
const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker);
return { location, symbol, comingFrom, text, escapedText, parents, includes };
function includes(referenceSymbol: Symbol): boolean {
return allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol;
}
return {
location, symbol, comingFrom, text, escapedText, parents,
includes: referenceSymbol => allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol,
};
}
private readonly symbolIdToReferences: Entry[][] = [];
+125 -90
View File
@@ -73,54 +73,56 @@ namespace ts.FindAllReferences {
function handleDirectImports(exportingModuleSymbol: Symbol): void {
const theseDirectImports = getDirectImports(exportingModuleSymbol);
if (theseDirectImports) for (const direct of theseDirectImports) {
if (!markSeenDirectImport(direct)) {
continue;
}
if (theseDirectImports) {
for (const direct of theseDirectImports) {
if (!markSeenDirectImport(direct)) {
continue;
}
cancellationToken.throwIfCancellationRequested();
cancellationToken.throwIfCancellationRequested();
switch (direct.kind) {
case SyntaxKind.CallExpression:
if (!isAvailableThroughGlobal) {
const parent = direct.parent!;
if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) {
const { name } = parent as ts.VariableDeclaration;
if (name.kind === SyntaxKind.Identifier) {
directImports.push(name);
break;
switch (direct.kind) {
case SyntaxKind.CallExpression:
if (!isAvailableThroughGlobal) {
const parent = direct.parent!;
if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) {
const { name } = parent as ts.VariableDeclaration;
if (name.kind === SyntaxKind.Identifier) {
directImports.push(name);
break;
}
}
// Don't support re-exporting 'require()' calls, so just add a single indirect user.
addIndirectUser(direct.getSourceFile());
}
break;
// Don't support re-exporting 'require()' calls, so just add a single indirect user.
addIndirectUser(direct.getSourceFile());
}
break;
case SyntaxKind.ImportEqualsDeclaration:
handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export));
break;
case SyntaxKind.ImportEqualsDeclaration:
handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export));
break;
case SyntaxKind.ImportDeclaration:
const namedBindings = direct.importClause && direct.importClause.namedBindings;
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
handleNamespaceImport(direct, namedBindings.name);
}
else {
directImports.push(direct);
}
break;
case SyntaxKind.ImportDeclaration:
const namedBindings = direct.importClause && direct.importClause.namedBindings;
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
handleNamespaceImport(direct, namedBindings.name);
}
else {
directImports.push(direct);
}
break;
case SyntaxKind.ExportDeclaration:
if (!direct.exportClause) {
// This is `export * from "foo"`, so imports of this module may import the export too.
handleDirectImports(getContainingModuleSymbol(direct, checker));
}
else {
// This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports.
directImports.push(direct);
}
break;
case SyntaxKind.ExportDeclaration:
if (!direct.exportClause) {
// This is `export * from "foo"`, so imports of this module may import the export too.
handleDirectImports(getContainingModuleSymbol(direct, checker));
}
else {
// This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports.
directImports.push(direct);
}
break;
}
}
}
}
@@ -160,8 +162,10 @@ namespace ts.FindAllReferences {
const moduleSymbol = checker.getMergedSymbol(sourceFileLike.symbol);
Debug.assert(!!(moduleSymbol.flags & SymbolFlags.Module));
const directImports = getDirectImports(moduleSymbol);
if (directImports) for (const directImport of directImports) {
addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport));
if (directImports) {
for (const directImport of directImports) {
addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport));
}
}
}
@@ -183,8 +187,10 @@ namespace ts.FindAllReferences {
importSearches.push([location, symbol]);
}
if (directImports) for (const decl of directImports) {
handleImport(decl);
if (directImports) {
for (const decl of directImports) {
handleImport(decl);
}
}
return { importSearches, singleReferences };
@@ -258,25 +264,27 @@ namespace ts.FindAllReferences {
}
function searchForNamedImport(namedBindings: NamedImportsOrExports | undefined): void {
if (namedBindings) for (const element of namedBindings.elements) {
const { name, propertyName } = element;
if ((propertyName || name).text !== exportName) {
continue;
}
if (namedBindings) {
for (const element of namedBindings.elements) {
const { name, propertyName } = element;
if ((propertyName || name).text !== exportName) {
continue;
}
if (propertyName) {
// This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference.
singleReferences.push(propertyName);
if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`.
// Search locally for `bar`.
addSearch(name, checker.getSymbolAtLocation(name));
if (propertyName) {
// This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference.
singleReferences.push(propertyName);
if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`.
// Search locally for `bar`.
addSearch(name, checker.getSymbolAtLocation(name));
}
}
else {
const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName
? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol.
: checker.getSymbolAtLocation(name);
addSearch(name, localSymbol);
}
}
else {
const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName
? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol.
: checker.getSymbolAtLocation(name);
addSearch(name, localSymbol);
}
}
}
@@ -436,8 +444,8 @@ namespace ts.FindAllReferences {
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.
return symbol.declarations.some(d => d === parent) && parent.parent.kind === ts.SyntaxKind.BinaryExpression
? getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ false)
return symbol.declarations.some(d => d === parent) && isBinaryExpression(parent.parent)
? getSpecialPropertyExport(parent.parent, /*useLhsSymbol*/ false)
: undefined;
}
else {
@@ -449,31 +457,41 @@ namespace ts.FindAllReferences {
else {
const exportNode = getExportNode(parent);
if (exportNode && hasModifier(exportNode, ModifierFlags.Export)) {
if (exportNode.kind === SyntaxKind.ImportEqualsDeclaration && (exportNode as ImportEqualsDeclaration).moduleReference === node) {
if (isImportEqualsDeclaration(exportNode) && exportNode.moduleReference === node) {
// We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement.
if (comingFromExport) {
return undefined;
}
const lhsSymbol = checker.getSymbolAtLocation((exportNode as ImportEqualsDeclaration).name);
const lhsSymbol = checker.getSymbolAtLocation(exportNode.name);
return { kind: ImportExport.Import, symbol: lhsSymbol, isNamedImport: false };
}
else {
return exportInfo(symbol, getExportKindForDeclaration(exportNode));
}
}
else if (parent.kind === SyntaxKind.ExportAssignment) {
// Get the symbol for the `export =` node; its parent is the module it's the export of.
const exportingModuleSymbol = parent.symbol.parent;
Debug.assert(!!exportingModuleSymbol);
return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } };
// If we are in `export = a;`, `parent` is the export assignment.
else if (isExportAssignment(parent)) {
return getExportAssignmentExport(parent);
}
else if (parent.kind === ts.SyntaxKind.BinaryExpression) {
return getSpecialPropertyExport(parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
// If we are in `export = class A {};` at `A`, `parent.parent` is the export assignment.
else if (isExportAssignment(parent.parent)) {
return getExportAssignmentExport(parent.parent);
}
else if (parent.parent.kind === SyntaxKind.BinaryExpression) {
return getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
// Similar for `module.exports =` and `exports.A =`.
else if (isBinaryExpression(parent)) {
return getSpecialPropertyExport(parent, /*useLhsSymbol*/ true);
}
else if (isBinaryExpression(parent.parent)) {
return getSpecialPropertyExport(parent.parent, /*useLhsSymbol*/ true);
}
}
function getExportAssignmentExport(ex: ExportAssignment): ExportedSymbol {
// Get the symbol for the `export =` node; its parent is the module it's the export of.
const exportingModuleSymbol = ex.symbol.parent;
Debug.assert(!!exportingModuleSymbol);
return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } };
}
function getSpecialPropertyExport(node: ts.BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined {
@@ -496,21 +514,21 @@ namespace ts.FindAllReferences {
function getImport(): ImportedSymbol | undefined {
const isImport = isNodeImport(node);
if (!isImport) return;
if (!isImport) return undefined;
// A symbol being imported is always an alias. So get what that aliases to find the local symbol.
let importedSymbol = checker.getImmediateAliasedSymbol(symbol);
if (importedSymbol) {
// Search on the local symbol in the exporting module, not the exported symbol.
importedSymbol = skipExportSpecifierSymbol(importedSymbol, checker);
// Similarly, skip past the symbol for 'export ='
if (importedSymbol.name === "export=") {
importedSymbol = checker.getImmediateAliasedSymbol(importedSymbol);
}
if (!importedSymbol) return undefined;
if (symbolName(importedSymbol) === symbol.name) { // If this is a rename import, do not continue searching.
return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport };
}
// Search on the local symbol in the exporting module, not the exported symbol.
importedSymbol = skipExportSpecifierSymbol(importedSymbol, checker);
// Similarly, skip past the symbol for 'export ='
if (importedSymbol.name === "export=") {
importedSymbol = getExportEqualsLocalSymbol(importedSymbol, checker);
}
if (symbolName(importedSymbol) === symbol.name) { // If this is a rename import, do not continue searching.
return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport };
}
}
@@ -525,6 +543,22 @@ namespace ts.FindAllReferences {
}
}
function getExportEqualsLocalSymbol(importedSymbol: Symbol, checker: TypeChecker): Symbol {
if (importedSymbol.flags & SymbolFlags.Alias) {
return checker.getImmediateAliasedSymbol(importedSymbol);
}
const decl = importedSymbol.valueDeclaration;
if (isExportAssignment(decl)) { // `export = class {}`
return decl.expression.symbol;
}
else if (isBinaryExpression(decl)) { // `module.exports = class {}`
return decl.right.symbol;
}
Debug.fail();
}
// If a reference is a class expression, the exported node would be its parent.
// If a reference is a variable declaration, the exported node would be the variable statement.
function getExportNode(parent: Node): Node | undefined {
if (parent.kind === SyntaxKind.VariableDeclaration) {
@@ -578,12 +612,13 @@ namespace ts.FindAllReferences {
/** If at an export specifier, go to the symbol it refers to. */
function skipExportSpecifierSymbol(symbol: Symbol, checker: TypeChecker): Symbol {
// For `export { foo } from './bar", there's nothing to skip, because it does not create a new alias. But `export { foo } does.
if (symbol.declarations) for (const declaration of symbol.declarations) {
if (isExportSpecifier(declaration) && !(declaration as ExportSpecifier).propertyName && !(declaration as ExportSpecifier).parent.parent.moduleSpecifier) {
return checker.getExportSpecifierLocalTargetSymbol(declaration);
if (symbol.declarations) {
for (const declaration of symbol.declarations) {
if (isExportSpecifier(declaration) && !(declaration as ExportSpecifier).propertyName && !(declaration as ExportSpecifier).parent.parent.moduleSpecifier) {
return checker.getExportSpecifierLocalTargetSymbol(declaration);
}
}
}
return symbol;
}
+19
View File
@@ -132,6 +132,25 @@ namespace ts.JsDoc {
}));
}
export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): CompletionEntry[] {
const nameThusFar = tag.name.text;
const jsdoc = tag.parent;
const fn = jsdoc.parent;
if (!ts.isFunctionLike(fn)) return [];
return mapDefined(fn.parameters, param => {
if (!isIdentifier(param.name)) return undefined;
const name = param.name.text;
if (jsdoc.tags.some(t => t !== tag && isJSDocParameterTag(t) && t.name.text === name)
|| nameThusFar !== undefined && !startsWith(name, nameThusFar)) {
return undefined;
}
return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: "0" };
});
}
/**
* Checks if position points to a valid position to add JSDoc comments, and if so,
* returns the appropriate template. Otherwise returns an empty string.
+8 -8
View File
@@ -8,10 +8,10 @@ namespace ts {
description: string;
/** Compute the associated code actions */
getCodeActions(context: RefactorContext): CodeAction[];
getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined;
/** A fast syntactic check to see if the refactor is applicable at given position. */
isApplicable(context: RefactorContext): boolean;
/** Compute (quickly) which actions are available here */
getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined;
}
export interface RefactorContext {
@@ -34,7 +34,6 @@ namespace ts {
}
export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
let results: ApplicableRefactorInfo[];
const refactorList: Refactor[] = [];
refactors.forEach(refactor => {
@@ -44,16 +43,17 @@ namespace ts {
if (context.cancellationToken && context.cancellationToken.isCancellationRequested()) {
return results;
}
if (refactor.isApplicable(context)) {
(results || (results = [])).push({ name: refactor.name, description: refactor.description });
const infos = refactor.getAvailableActions(context);
if (infos && infos.length) {
(results || (results = [])).push(...infos);
}
}
return results;
}
export function getRefactorCodeActions(context: RefactorContext, refactorName: string): CodeAction[] | undefined {
export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined {
const refactor = refactors.get(refactorName);
return refactor && refactor.getCodeActions(context);
return refactor && refactor.getEditsForAction(context, actionName);
}
}
}
@@ -1,16 +1,18 @@
/* @internal */
namespace ts.refactor {
const actionName = "convert";
const convertFunctionToES6Class: Refactor = {
name: "Convert to ES2015 class",
description: Diagnostics.Convert_function_to_an_ES2015_class.message,
getCodeActions,
isApplicable
getEditsForAction,
getAvailableActions
};
registerRefactor(convertFunctionToES6Class);
function isApplicable(context: RefactorContext): boolean {
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] {
const start = context.startPosition;
const node = getTokenAtPosition(context.file, start, /*includeJsDocComment*/ false);
const checker = context.program.getTypeChecker();
@@ -20,10 +22,28 @@ namespace ts.refactor {
symbol = (symbol.valueDeclaration as VariableDeclaration).initializer.symbol;
}
return symbol && symbol.flags & SymbolFlags.Function && symbol.members && symbol.members.size > 0;
if (symbol && (symbol.flags & SymbolFlags.Function) && symbol.members && (symbol.members.size > 0)) {
return [
{
name: convertFunctionToES6Class.name,
description: convertFunctionToES6Class.description,
actions: [
{
description: convertFunctionToES6Class.description,
name: actionName
}
]
}
];
}
}
function getCodeActions(context: RefactorContext): CodeAction[] | undefined {
function getEditsForAction(context: RefactorContext, action: string): RefactorEditInfo | undefined {
// Somehow wrong action got invoked?
if (actionName !== action) {
return undefined;
}
const start = context.startPosition;
const sourceFile = context.file;
const checker = context.program.getTypeChecker();
@@ -35,7 +55,7 @@ namespace ts.refactor {
const deletes: (() => any)[] = [];
if (!(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) {
return [];
return undefined;
}
const ctorDeclaration = ctorSymbol.valueDeclaration;
@@ -63,7 +83,7 @@ namespace ts.refactor {
}
if (!newClassDeclaration) {
return [];
return undefined;
}
// Because the preceding node could be touched, we need to insert nodes before delete nodes.
@@ -72,10 +92,9 @@ namespace ts.refactor {
deleteCallback();
}
return [{
description: formatStringFromArgs(Diagnostics.Convert_function_0_to_class.message, [ctorSymbol.name]),
changes: changeTracker.getChanges()
}];
return {
edits: changeTracker.getChanges()
};
function deleteNode(node: Node, inList = false) {
if (deletedNodes.some(n => isNodeDescendantOf(node, n))) {
+22 -10
View File
@@ -136,7 +136,7 @@ namespace ts {
}
private createChildren(sourceFile?: SourceFileLike) {
if (isJSDocTag(this)) {
if (this.kind === SyntaxKind.JSDocComment || isJSDocTag(this)) {
/** Don't add trivia for "tokens" since this is in a comment. */
const children: Node[] = [];
this.forEachChild(child => { children.push(child); });
@@ -146,9 +146,9 @@ namespace ts {
const children: Node[] = [];
scanner.setText((sourceFile || this.getSourceFile()).text);
let pos = this.pos;
const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode;
const useJSDocScanner = isJSDocNode(this);
const processNode = (node: Node) => {
const isJSDocTagNode = isJSDocTag(node);
const isJSDocTagNode = isJSDocNode(node);
if (!isJSDocTagNode && pos < node.pos) {
pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner);
}
@@ -684,8 +684,9 @@ namespace ts {
forEachChild(decl.name, visit);
break;
}
if (decl.initializer)
if (decl.initializer) {
visit(decl.initializer);
}
}
// falls through
case SyntaxKind.EnumMember:
@@ -732,6 +733,15 @@ namespace ts {
}
}
class SourceMapSourceObject implements SourceMapSource {
lineMap: number[];
constructor (public fileName: string, public text: string, public skipTrivia?: (pos: number) => number) {}
public getLineAndCharacterOfPosition(pos: number): LineAndCharacter {
return ts.getLineAndCharacterOfPosition(this, pos);
}
}
function getServicesObjectAllocator(): ObjectAllocator {
return {
getNodeConstructor: () => NodeObject,
@@ -742,6 +752,7 @@ namespace ts {
getSymbolConstructor: () => SymbolObject,
getTypeConstructor: () => TypeObject,
getSignatureConstructor: () => SignatureObject,
getSourceMapSourceConstructor: () => SourceMapSourceObject,
};
}
@@ -1989,15 +2000,16 @@ namespace ts {
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange));
}
function getRefactorCodeActions(
function getEditsForRefactor(
fileName: string,
formatOptions: FormatCodeSettings,
positionOrRange: number | TextRange,
refactorName: string): CodeAction[] | undefined {
refactorName: string,
actionName: string): RefactorEditInfo {
synchronizeHostData();
const file = getValidSourceFile(fileName);
return refactor.getRefactorCodeActions(getRefactorContext(file, positionOrRange, formatOptions), refactorName);
return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, formatOptions), refactorName, actionName);
}
return {
@@ -2005,8 +2017,6 @@ namespace ts {
cleanupSemanticCache,
getSyntacticDiagnostics,
getSemanticDiagnostics,
getApplicableRefactors,
getRefactorCodeActions,
getCompilerOptionsDiagnostics,
getSyntacticClassifications,
getSemanticClassifications,
@@ -2044,7 +2054,9 @@ namespace ts {
getEmitOutput,
getNonBoundSourceFile,
getSourceFile,
getProgram
getProgram,
getApplicableRefactors,
getEditsForRefactor,
};
}
+3 -1
View File
@@ -4,8 +4,10 @@ namespace ts.SymbolDisplay {
export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind {
const { flags } = symbol;
if (flags & SymbolFlags.Class) return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ?
if (flags & SymbolFlags.Class) {
return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ?
ScriptElementKind.localClassElement : ScriptElementKind.classElement;
}
if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement;
if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement;
if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement;
+55 -1
View File
@@ -71,6 +71,10 @@ namespace ts {
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
}
export interface SourceMapSource {
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
}
/**
* Represents an immutable snapshot of a script at a specified time.Once acquired, the
* snapshot is observably immutable. i.e. the same calls with the same parameters will return
@@ -261,8 +265,9 @@ namespace ts {
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[];
getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[];
getRefactorCodeActions(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string): CodeAction[] | undefined;
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined;
getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean): EmitOutput;
@@ -353,11 +358,60 @@ namespace ts {
changes: FileTextChanges[];
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
export interface ApplicableRefactorInfo {
/**
* The programmatic name of the refactoring
*/
name: string;
/**
* A description of this refactoring category to show to the user.
* If the refactoring gets inlined (see below), this text will not be visible.
*/
description: string;
/**
* Inlineable refactorings can have their actions hoisted out to the top level
* of a context menu. Non-inlineanable refactorings should always be shown inside
* their parent grouping.
*
* If not specified, this value is assumed to be 'true'
*/
inlineable?: boolean;
actions: RefactorActionInfo[];
}
/**
* Represents a single refactoring action - for example, the "Extract Method..." refactor might
* offer several actions, each corresponding to a surround class or closure to extract into.
*/
export type RefactorActionInfo = {
/**
* The programmatic name of the refactoring action
*/
name: string;
/**
* A description of this refactoring action to show to the user.
* If the parent refactoring is inlined away, this will be the only text shown,
* so this description should make sense by itself if the parent is inlineable=true
*/
description: string;
};
/**
* A set of edits to make in response to a refactor action, plus an optional
* location where renaming should be invoked from
*/
export type RefactorEditInfo = {
edits: FileTextChanges[];
renameFilename?: string;
renameLocation?: number;
};
export interface TextInsertion {
newText: string;
/** The position in newText the caret should point to after the insertion. */
+13 -46
View File
@@ -615,18 +615,21 @@ namespace ts {
return getTouchingToken(sourceFile, position, includeJsDocComment, n => isPropertyName(n.kind));
}
/** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
export function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeItemAtEndPosition?: (n: Node) => boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition, includeJsDocComment);
/**
* Returns the token if position is in [start, end).
* If position === end, returns the preceding token if includeItemAtEndPosition(previousToken) === true
*/
export function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includePrecedingTokenAtEndPosition, /*includeEndPosition*/ false, includeJsDocComment);
}
/** Returns a token if position is in [start-of-leading-trivia, end) */
export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined, includeJsDocComment);
export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeEndPosition?: boolean): Node {
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, includeEndPosition, includeJsDocComment);
}
/** Get the token whose text contains the position */
function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean, includeJsDocComment: boolean): Node {
function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includePrecedingTokenAtEndPosition: (n: Node) => boolean, includeEndPosition: boolean, includeJsDocComment: boolean): Node {
let current: Node = sourceFile;
outer: while (true) {
if (isToken(current)) {
@@ -636,7 +639,7 @@ namespace ts {
// find the child that contains 'position'
for (const child of current.getChildren()) {
if (isJSDocNode(child) && !includeJsDocComment) {
if (!includeJsDocComment && isJSDocNode(child)) {
continue;
}
@@ -646,13 +649,13 @@ namespace ts {
}
const end = child.getEnd();
if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) {
if (position < end || (position === end && (child.kind === SyntaxKind.EndOfFileToken || includeEndPosition))) {
current = child;
continue outer;
}
else if (includeItemAtEndPosition && end === position) {
else if (includePrecedingTokenAtEndPosition && end === position) {
const previousToken = findPrecedingToken(position, sourceFile, child);
if (previousToken && includeItemAtEndPosition(previousToken)) {
if (previousToken && includePrecedingTokenAtEndPosition(previousToken)) {
return previousToken;
}
}
@@ -901,42 +904,6 @@ namespace ts {
}
}
/**
* Get the corresponding JSDocTag node if the position is in a jsDoc comment
*/
export function getJsDocTagAtPosition(sourceFile: SourceFile, position: number): JSDocTag {
let node = ts.getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false);
if (isToken(node)) {
switch (node.kind) {
case SyntaxKind.VarKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
// if the current token is var, let or const, skip the VariableDeclarationList
node = node.parent === undefined ? undefined : node.parent.parent;
break;
default:
node = node.parent;
break;
}
}
if (node) {
if (node.jsDoc) {
for (const jsDoc of node.jsDoc) {
if (jsDoc.tags) {
for (const tag of jsDoc.tags) {
if (tag.pos <= position && position <= tag.end) {
return tag;
}
}
}
}
}
}
return undefined;
}
function nodeHasTokens(n: Node): boolean {
// If we have a token or node that has a non-zero width, it must have tokens.
// Note, that getWidth() does not take trivia into account.
@@ -40,6 +40,7 @@
"end": 27,
"text": "name1"
},
"isBracketed": false,
"comment": "Description"
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 32,
"text": "name1"
},
"isBracketed": false,
"comment": "Description"
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": "Description text follows"
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 20,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 20,
"text": "name1"
},
"isBracketed": false,
"comment": "Description"
},
"length": 1,
@@ -30,6 +30,7 @@
"end": 18,
"text": "foo"
},
"isBracketed": false,
"comment": ""
},
"length": 1,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"1": {
@@ -79,6 +80,7 @@
"end": 55,
"text": "name2"
},
"isBracketed": false,
"comment": ""
},
"length": 2,
@@ -40,6 +40,7 @@
"end": 29,
"text": "name1"
},
"isBracketed": false,
"comment": ""
},
"1": {
@@ -79,6 +80,7 @@
"end": 51,
"text": "name2"
},
"isBracketed": false,
"comment": ""
},
"length": 2,
@@ -103,7 +103,8 @@
"pos": 66,
"end": 69,
"text": "age"
}
},
"isBracketed": false
},
{
"kind": "JSDocPropertyTag",
@@ -141,7 +142,8 @@
"pos": 93,
"end": 97,
"text": "name"
}
},
"isBracketed": false
}
]
},
@@ -0,0 +1,44 @@
=== tests/cases/compiler/main.js ===
function allRest() { arguments; }
>allRest : Symbol(allRest, Decl(main.js, 0, 0))
>arguments : Symbol(arguments)
allRest();
>allRest : Symbol(allRest, Decl(main.js, 0, 0))
allRest(1, 2, 3);
>allRest : Symbol(allRest, Decl(main.js, 0, 0))
function someRest(x, y) { arguments; }
>someRest : Symbol(someRest, Decl(main.js, 2, 17))
>x : Symbol(x, Decl(main.js, 3, 18))
>y : Symbol(y, Decl(main.js, 3, 20))
>arguments : Symbol(arguments)
someRest(); // x and y are still optional because they are in a JS file
>someRest : Symbol(someRest, Decl(main.js, 2, 17))
someRest(1, 2, 3);
>someRest : Symbol(someRest, Decl(main.js, 2, 17))
/**
* @param {number} x - a thing
*/
function jsdocced(x) { arguments; }
>jsdocced : Symbol(jsdocced, Decl(main.js, 5, 18))
>x : Symbol(x, Decl(main.js, 10, 18))
>arguments : Symbol(arguments)
jsdocced(1);
>jsdocced : Symbol(jsdocced, Decl(main.js, 5, 18))
function dontDoubleRest(x, ...y) { arguments; }
>dontDoubleRest : Symbol(dontDoubleRest, Decl(main.js, 11, 12))
>x : Symbol(x, Decl(main.js, 13, 24))
>y : Symbol(y, Decl(main.js, 13, 26))
>arguments : Symbol(arguments)
dontDoubleRest(1, 2, 3);
>dontDoubleRest : Symbol(dontDoubleRest, Decl(main.js, 11, 12))
@@ -0,0 +1,60 @@
=== tests/cases/compiler/main.js ===
function allRest() { arguments; }
>allRest : (...args: any[]) => void
>arguments : IArguments
allRest();
>allRest() : void
>allRest : (...args: any[]) => void
allRest(1, 2, 3);
>allRest(1, 2, 3) : void
>allRest : (...args: any[]) => void
>1 : 1
>2 : 2
>3 : 3
function someRest(x, y) { arguments; }
>someRest : (x: any, y: any, ...args: any[]) => void
>x : any
>y : any
>arguments : IArguments
someRest(); // x and y are still optional because they are in a JS file
>someRest() : void
>someRest : (x: any, y: any, ...args: any[]) => void
someRest(1, 2, 3);
>someRest(1, 2, 3) : void
>someRest : (x: any, y: any, ...args: any[]) => void
>1 : 1
>2 : 2
>3 : 3
/**
* @param {number} x - a thing
*/
function jsdocced(x) { arguments; }
>jsdocced : (x: number) => void
>x : number
>arguments : IArguments
jsdocced(1);
>jsdocced(1) : void
>jsdocced : (x: number) => void
>1 : 1
function dontDoubleRest(x, ...y) { arguments; }
>dontDoubleRest : (x: any, ...y: any[]) => void
>x : any
>y : any[]
>arguments : IArguments
dontDoubleRest(1, 2, 3);
>dontDoubleRest(1, 2, 3) : void
>dontDoubleRest : (x: any, ...y: any[]) => void
>1 : 1
>2 : 2
>3 : 3
@@ -5,16 +5,19 @@ export class A { }
//// [b.ts]
import { A } from "./a";
export * from "./a";
export class B extends A { }
//// [tslib.d.ts]
export declare function __extends(d: Function, b: Function): void;
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __rest(t: any, propertyNames: string[]): any;
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
export declare function __param(paramIndex: number, decorator: Function): Function;
export declare function __metadata(metadataKey: any, metadataValue: any): Function;
export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any;
export declare function __generator(thisArg: any, body: Function): any;
export declare function __exportStar(m: any, exports: any): void;
//// [a.js]
define(["require", "exports"], function (require, exports) {
@@ -28,9 +31,10 @@ define(["require", "exports"], function (require, exports) {
exports.A = A;
});
//// [b.js]
define(["require", "exports", "tslib", "./a"], function (require, exports, tslib_1, a_1) {
define(["require", "exports", "tslib", "./a", "./a"], function (require, exports, tslib_1, a_1, a_2) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
tslib_1.__exportStar(a_2, exports);
var B = (function (_super) {
tslib_1.__extends(B, _super);
function B() {
@@ -6,8 +6,9 @@ export class A { }
import { A } from "./a";
>A : Symbol(A, Decl(b.ts, 0, 8))
export * from "./a";
export class B extends A { }
>B : Symbol(B, Decl(b.ts, 0, 24))
>B : Symbol(B, Decl(b.ts, 1, 20))
>A : Symbol(A, Decl(b.ts, 0, 8))
=== tests/cases/compiler/tslib.d.ts ===
@@ -23,6 +24,11 @@ export declare function __assign(t: any, ...sources: any[]): any;
>t : Symbol(t, Decl(tslib.d.ts, --, --))
>sources : Symbol(sources, Decl(tslib.d.ts, --, --))
export declare function __rest(t: any, propertyNames: string[]): any;
>__rest : Symbol(__rest, Decl(tslib.d.ts, --, --))
>t : Symbol(t, Decl(tslib.d.ts, --, --))
>propertyNames : Symbol(propertyNames, Decl(tslib.d.ts, --, --))
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
>__decorate : Symbol(__decorate, Decl(tslib.d.ts, --, --))
>decorators : Symbol(decorators, Decl(tslib.d.ts, --, --))
@@ -53,3 +59,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge
>generator : Symbol(generator, Decl(tslib.d.ts, --, --))
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
export declare function __generator(thisArg: any, body: Function): any;
>__generator : Symbol(__generator, Decl(tslib.d.ts, --, --))
>thisArg : Symbol(thisArg, Decl(tslib.d.ts, --, --))
>body : Symbol(body, Decl(tslib.d.ts, --, --))
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
export declare function __exportStar(m: any, exports: any): void;
>__exportStar : Symbol(__exportStar, Decl(tslib.d.ts, --, --))
>m : Symbol(m, Decl(tslib.d.ts, --, --))
>exports : Symbol(exports, Decl(tslib.d.ts, --, --))
@@ -6,6 +6,7 @@ export class A { }
import { A } from "./a";
>A : typeof A
export * from "./a";
export class B extends A { }
>B : B
>A : A
@@ -23,6 +24,11 @@ export declare function __assign(t: any, ...sources: any[]): any;
>t : any
>sources : any[]
export declare function __rest(t: any, propertyNames: string[]): any;
>__rest : (t: any, propertyNames: string[]) => any
>t : any
>propertyNames : string[]
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
>__decorate : (decorators: Function[], target: any, key?: string | symbol, desc?: any) => any
>decorators : Function[]
@@ -53,3 +59,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge
>generator : Function
>Function : Function
export declare function __generator(thisArg: any, body: Function): any;
>__generator : (thisArg: any, body: Function) => any
>thisArg : any
>body : Function
>Function : Function
export declare function __exportStar(m: any, exports: any): void;
>__exportStar : (m: any, exports: any) => void
>m : any
>exports : any
@@ -48,11 +48,13 @@ declare namespace N {
//// [tslib.d.ts]
export declare function __extends(d: Function, b: Function): void;
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __rest(t: any, propertyNames: string[]): any;
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
export declare function __param(paramIndex: number, decorator: Function): Function;
export declare function __metadata(metadataKey: any, metadataValue: any): Function;
export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any;
export declare function __generator(thisArg: any, body: Function): any;
export declare function __exportStar(m: any, exports: any): void;
//// [b.js]
"use strict";
@@ -98,6 +98,11 @@ export declare function __assign(t: any, ...sources: any[]): any;
>t : Symbol(t, Decl(tslib.d.ts, --, --))
>sources : Symbol(sources, Decl(tslib.d.ts, --, --))
export declare function __rest(t: any, propertyNames: string[]): any;
>__rest : Symbol(__rest, Decl(tslib.d.ts, --, --))
>t : Symbol(t, Decl(tslib.d.ts, --, --))
>propertyNames : Symbol(propertyNames, Decl(tslib.d.ts, --, --))
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
>__decorate : Symbol(__decorate, Decl(tslib.d.ts, --, --))
>decorators : Symbol(decorators, Decl(tslib.d.ts, --, --))
@@ -128,3 +133,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge
>generator : Symbol(generator, Decl(tslib.d.ts, --, --))
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
export declare function __generator(thisArg: any, body: Function): any;
>__generator : Symbol(__generator, Decl(tslib.d.ts, --, --))
>thisArg : Symbol(thisArg, Decl(tslib.d.ts, --, --))
>body : Symbol(body, Decl(tslib.d.ts, --, --))
>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
export declare function __exportStar(m: any, exports: any): void;
>__exportStar : Symbol(__exportStar, Decl(tslib.d.ts, --, --))
>m : Symbol(m, Decl(tslib.d.ts, --, --))
>exports : Symbol(exports, Decl(tslib.d.ts, --, --))
@@ -98,6 +98,11 @@ export declare function __assign(t: any, ...sources: any[]): any;
>t : any
>sources : any[]
export declare function __rest(t: any, propertyNames: string[]): any;
>__rest : (t: any, propertyNames: string[]) => any
>t : any
>propertyNames : string[]
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
>__decorate : (decorators: Function[], target: any, key?: string | symbol, desc?: any) => any
>decorators : Function[]
@@ -128,3 +133,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge
>generator : Function
>Function : Function
export declare function __generator(thisArg: any, body: Function): any;
>__generator : (thisArg: any, body: Function) => any
>thisArg : any
>body : Function
>Function : Function
export declare function __exportStar(m: any, exports: any): void;
>__exportStar : (m: any, exports: any) => void
>m : any
>exports : any
@@ -1,12 +1,16 @@
tests/cases/compiler/external.ts(2,16): error TS2343: This syntax requires an imported helper named '__extends', but module 'tslib' has no exported member '__extends'.
tests/cases/compiler/external.ts(6,1): error TS2343: This syntax requires an imported helper named '__decorate', but module 'tslib' has no exported member '__decorate'.
tests/cases/compiler/external.ts(6,1): error TS2343: This syntax requires an imported helper named '__metadata', but module 'tslib' has no exported member '__metadata'.
tests/cases/compiler/external.ts(8,12): error TS2343: This syntax requires an imported helper named '__param', but module 'tslib' has no exported member '__param'.
tests/cases/compiler/external.ts(13,13): error TS2343: This syntax requires an imported helper named '__assign', but module 'tslib' has no exported member '__assign'.
tests/cases/compiler/external.ts(14,12): error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'.
tests/cases/compiler/external.ts(1,1): error TS2343: This syntax requires an imported helper named '__exportStar', but module 'tslib' has no exported member '__exportStar'.
tests/cases/compiler/external.ts(3,16): error TS2343: This syntax requires an imported helper named '__extends', but module 'tslib' has no exported member '__extends'.
tests/cases/compiler/external.ts(7,1): error TS2343: This syntax requires an imported helper named '__decorate', but module 'tslib' has no exported member '__decorate'.
tests/cases/compiler/external.ts(7,1): error TS2343: This syntax requires an imported helper named '__metadata', but module 'tslib' has no exported member '__metadata'.
tests/cases/compiler/external.ts(9,12): error TS2343: This syntax requires an imported helper named '__param', but module 'tslib' has no exported member '__param'.
tests/cases/compiler/external.ts(14,13): error TS2343: This syntax requires an imported helper named '__assign', but module 'tslib' has no exported member '__assign'.
tests/cases/compiler/external.ts(15,12): error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'.
==== tests/cases/compiler/external.ts (6 errors) ====
==== tests/cases/compiler/external.ts (7 errors) ====
export * from "./other";
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2343: This syntax requires an imported helper named '__exportStar', but module 'tslib' has no exported member '__exportStar'.
export class A { }
export class B extends A { }
~~~~~~~~~
@@ -34,6 +38,9 @@ tests/cases/compiler/external.ts(14,12): error TS2343: This syntax requires an i
~
!!! error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'.
==== tests/cases/compiler/other.ts (0 errors) ====
export const x = 1;
==== tests/cases/compiler/script.ts (0 errors) ====
class A { }
class B extends A { }
@@ -1,6 +1,7 @@
//// [tests/cases/compiler/importHelpersNoHelpers.ts] ////
//// [external.ts]
export * from "./other";
export class A { }
export class B extends A { }
@@ -16,6 +17,9 @@ const o = { a: 1 };
const y = { ...o };
const { ...x } = y;
//// [other.ts]
export const x = 1;
//// [script.ts]
class A { }
class B extends A { }
@@ -32,10 +36,15 @@ class C {
export {}
//// [other.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.x = 1;
//// [external.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
tslib_1.__exportStar(require("./other"), exports);
var A = (function () {
function A() {
}
@@ -5,6 +5,7 @@ export class A { }
//// [b.ts]
import { A } from "./a";
export * from "./a";
export class B extends A { }
//// [tslib.d.ts]
@@ -38,6 +39,16 @@ System.register(["tslib", "./a"], function (exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var tslib_1, a_1, B;
var exportedNames_1 = {
"B": true
};
function exportStar_1(m) {
var exports = {};
for (var n in m) {
if (n !== "default" && !exportedNames_1.hasOwnProperty(n)) exports[n] = m[n];
}
exports_1(exports);
}
return {
setters: [
function (tslib_1_1) {
@@ -45,6 +56,7 @@ System.register(["tslib", "./a"], function (exports_1, context_1) {
},
function (a_1_1) {
a_1 = a_1_1;
exportStar_1(a_1_1);
}
],
execute: function () {
@@ -6,8 +6,9 @@ export class A { }
import { A } from "./a";
>A : Symbol(A, Decl(b.ts, 0, 8))
export * from "./a";
export class B extends A { }
>B : Symbol(B, Decl(b.ts, 0, 24))
>B : Symbol(B, Decl(b.ts, 1, 20))
>A : Symbol(A, Decl(b.ts, 0, 8))
=== tests/cases/compiler/tslib.d.ts ===
@@ -6,6 +6,7 @@ export class A { }
import { A } from "./a";
>A : typeof A
export * from "./a";
export class B extends A { }
>B : B
>A : A
@@ -0,0 +1,12 @@
=== tests/cases/compiler/foo.js ===
// Test #16139
function Foo() {
>Foo : Symbol(Foo, Decl(foo.js, 0, 0))
arguments;
>arguments : Symbol(arguments)
return new Foo();
>Foo : Symbol(Foo, Decl(foo.js, 0, 0))
}
@@ -0,0 +1,13 @@
=== tests/cases/compiler/foo.js ===
// Test #16139
function Foo() {
>Foo : (...args: any[]) => any
arguments;
>arguments : IArguments
return new Foo();
>new Foo() : any
>Foo : (...args: any[]) => any
}
@@ -0,0 +1 @@
[args => any, <T>(args) => any, (...args) => any, (args?) => any, (args: any) => any, ({}) => any]
@@ -0,0 +1,15 @@
//// [returnInfiniteIntersection.ts]
function recursive() {
let x = <T>(subkey: T) => recursive();
return x as typeof x & { p };
}
let result = recursive()(1)
//// [returnInfiniteIntersection.js]
function recursive() {
var x = function (subkey) { return recursive(); };
return x;
}
var result = recursive()(1);
@@ -0,0 +1,21 @@
=== tests/cases/compiler/returnInfiniteIntersection.ts ===
function recursive() {
>recursive : Symbol(recursive, Decl(returnInfiniteIntersection.ts, 0, 0))
let x = <T>(subkey: T) => recursive();
>x : Symbol(x, Decl(returnInfiniteIntersection.ts, 1, 7))
>T : Symbol(T, Decl(returnInfiniteIntersection.ts, 1, 13))
>subkey : Symbol(subkey, Decl(returnInfiniteIntersection.ts, 1, 16))
>T : Symbol(T, Decl(returnInfiniteIntersection.ts, 1, 13))
>recursive : Symbol(recursive, Decl(returnInfiniteIntersection.ts, 0, 0))
return x as typeof x & { p };
>x : Symbol(x, Decl(returnInfiniteIntersection.ts, 1, 7))
>x : Symbol(x, Decl(returnInfiniteIntersection.ts, 1, 7))
>p : Symbol(p, Decl(returnInfiniteIntersection.ts, 2, 28))
}
let result = recursive()(1)
>result : Symbol(result, Decl(returnInfiniteIntersection.ts, 5, 3))
>recursive : Symbol(recursive, Decl(returnInfiniteIntersection.ts, 0, 0))
@@ -0,0 +1,27 @@
=== tests/cases/compiler/returnInfiniteIntersection.ts ===
function recursive() {
>recursive : () => (<T>(subkey: T) => any & { p: any; }) & { p: any; }
let x = <T>(subkey: T) => recursive();
>x : <T>(subkey: T) => any & { p: any; }
><T>(subkey: T) => recursive() : <T>(subkey: T) => any & { p: any; }
>T : T
>subkey : T
>T : T
>recursive() : (<T>(subkey: T) => any & { p: any; }) & { p: any; }
>recursive : () => (<T>(subkey: T) => any & { p: any; }) & { p: any; }
return x as typeof x & { p };
>x as typeof x & { p } : (<T>(subkey: T) => any & { p: any; }) & { p: any; }
>x : <T>(subkey: T) => any & { p: any; }
>x : <T>(subkey: T) => any & { p: any; }
>p : any
}
let result = recursive()(1)
>result : (<T>(subkey: T) => any & { p: any; }) & { p: any; }
>recursive()(1) : (<T>(subkey: T) => any & { p: any; }) & { p: any; }
>recursive() : (<T>(subkey: T) => any & { p: any; }) & { p: any; }
>recursive : () => (<T>(subkey: T) => any & { p: any; }) & { p: any; }
>1 : 1
@@ -0,0 +1,184 @@
=== tests/cases/conformance/salsa/node.d.ts ===
declare function require(id: string): any;
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>id : Symbol(id, Decl(node.d.ts, 0, 25))
declare var module: any, exports: any;
>module : Symbol(module, Decl(node.d.ts, 1, 11))
>exports : Symbol(exports, Decl(node.d.ts, 1, 24))
=== tests/cases/conformance/salsa/a-ext.js ===
exports.A = function () {
>exports : Symbol(A, Decl(a-ext.js, 0, 0))
>A : Symbol(A, Decl(a-ext.js, 0, 0))
this.x = 1;
>x : Symbol((Anonymous function).x, Decl(a-ext.js, 0, 25))
};
=== tests/cases/conformance/salsa/a.js ===
const { A } = require("./a-ext");
>A : Symbol(A, Decl(a.js, 0, 7))
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>"./a-ext" : Symbol("tests/cases/conformance/salsa/a-ext", Decl(a-ext.js, 0, 0))
/** @param {A} p */
function a(p) { p.x; }
>a : Symbol(a, Decl(a.js, 0, 33))
>p : Symbol(p, Decl(a.js, 3, 11))
>p.x : Symbol((Anonymous function).x, Decl(a-ext.js, 0, 25))
>p : Symbol(p, Decl(a.js, 3, 11))
>x : Symbol((Anonymous function).x, Decl(a-ext.js, 0, 25))
=== tests/cases/conformance/salsa/b-ext.js ===
exports.B = class {
>exports : Symbol(B, Decl(b-ext.js, 0, 0))
>B : Symbol(B, Decl(b-ext.js, 0, 0))
constructor() {
this.x = 1;
>this.x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
>this : Symbol((Anonymous class), Decl(b-ext.js, 0, 11))
>x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
}
};
=== tests/cases/conformance/salsa/b.js ===
const { B } = require("./b-ext");
>B : Symbol(B, Decl(b.js, 0, 7))
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>"./b-ext" : Symbol("tests/cases/conformance/salsa/b-ext", Decl(b-ext.js, 0, 0))
/** @param {B} p */
function b(p) { p.x; }
>b : Symbol(b, Decl(b.js, 0, 33))
>p : Symbol(p, Decl(b.js, 3, 11))
>p.x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
>p : Symbol(p, Decl(b.js, 3, 11))
>x : Symbol((Anonymous class).x, Decl(b-ext.js, 1, 19))
=== tests/cases/conformance/salsa/c-ext.js ===
export function C() {
>C : Symbol(C, Decl(c-ext.js, 0, 0))
this.x = 1;
>x : Symbol(C.x, Decl(c-ext.js, 0, 21))
}
=== tests/cases/conformance/salsa/c.js ===
const { C } = require("./c-ext");
>C : Symbol(C, Decl(c.js, 0, 7))
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>"./c-ext" : Symbol("tests/cases/conformance/salsa/c-ext", Decl(c-ext.js, 0, 0))
/** @param {C} p */
function c(p) { p.x; }
>c : Symbol(c, Decl(c.js, 0, 33))
>p : Symbol(p, Decl(c.js, 3, 11))
>p.x : Symbol(C.x, Decl(c-ext.js, 0, 21))
>p : Symbol(p, Decl(c.js, 3, 11))
>x : Symbol(C.x, Decl(c-ext.js, 0, 21))
=== tests/cases/conformance/salsa/d-ext.js ===
export var D = function() {
>D : Symbol(D, Decl(d-ext.js, 0, 10))
this.x = 1;
>x : Symbol(D.x, Decl(d-ext.js, 0, 27))
};
=== tests/cases/conformance/salsa/d.js ===
const { D } = require("./d-ext");
>D : Symbol(D, Decl(d.js, 0, 7))
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>"./d-ext" : Symbol("tests/cases/conformance/salsa/d-ext", Decl(d-ext.js, 0, 0))
/** @param {D} p */
function d(p) { p.x; }
>d : Symbol(d, Decl(d.js, 0, 33))
>p : Symbol(p, Decl(d.js, 3, 11))
>p.x : Symbol(D.x, Decl(d-ext.js, 0, 27))
>p : Symbol(p, Decl(d.js, 3, 11))
>x : Symbol(D.x, Decl(d-ext.js, 0, 27))
=== tests/cases/conformance/salsa/e-ext.js ===
export class E {
>E : Symbol(E, Decl(e-ext.js, 0, 0))
constructor() {
this.x = 1;
>this.x : Symbol(E.x, Decl(e-ext.js, 1, 19))
>this : Symbol(E, Decl(e-ext.js, 0, 0))
>x : Symbol(E.x, Decl(e-ext.js, 1, 19))
}
}
=== tests/cases/conformance/salsa/e.js ===
const { E } = require("./e-ext");
>E : Symbol(E, Decl(e.js, 0, 7))
>require : Symbol(require, Decl(node.d.ts, 0, 0))
>"./e-ext" : Symbol("tests/cases/conformance/salsa/e-ext", Decl(e-ext.js, 0, 0))
/** @param {E} p */
function e(p) { p.x; }
>e : Symbol(e, Decl(e.js, 0, 33))
>p : Symbol(p, Decl(e.js, 3, 11))
>p.x : Symbol(E.x, Decl(e-ext.js, 1, 19))
>p : Symbol(p, Decl(e.js, 3, 11))
>x : Symbol(E.x, Decl(e-ext.js, 1, 19))
=== tests/cases/conformance/salsa/f.js ===
var F = function () {
>F : Symbol(F, Decl(f.js, 0, 3))
this.x = 1;
>x : Symbol(F.x, Decl(f.js, 0, 21))
};
/** @param {F} p */
function f(p) { p.x; }
>f : Symbol(f, Decl(f.js, 2, 2))
>p : Symbol(p, Decl(f.js, 5, 11))
>p.x : Symbol(F.x, Decl(f.js, 0, 21))
>p : Symbol(p, Decl(f.js, 5, 11))
>x : Symbol(F.x, Decl(f.js, 0, 21))
=== tests/cases/conformance/salsa/g.js ===
function G() {
>G : Symbol(G, Decl(g.js, 0, 0))
this.x = 1;
>x : Symbol(G.x, Decl(g.js, 0, 14))
}
/** @param {G} p */
function g(p) { p.x; }
>g : Symbol(g, Decl(g.js, 2, 1))
>p : Symbol(p, Decl(g.js, 5, 11))
>p.x : Symbol(G.x, Decl(g.js, 0, 14))
>p : Symbol(p, Decl(g.js, 5, 11))
>x : Symbol(G.x, Decl(g.js, 0, 14))
=== tests/cases/conformance/salsa/h.js ===
class H {
>H : Symbol(H, Decl(h.js, 0, 0))
constructor() {
this.x = 1;
>this.x : Symbol(H.x, Decl(h.js, 1, 19))
>this : Symbol(H, Decl(h.js, 0, 0))
>x : Symbol(H.x, Decl(h.js, 1, 19))
}
}
/** @param {H} p */
function h(p) { p.x; }
>h : Symbol(h, Decl(h.js, 4, 1))
>p : Symbol(p, Decl(h.js, 7, 11))
>p.x : Symbol(H.x, Decl(h.js, 1, 19))
>p : Symbol(p, Decl(h.js, 7, 11))
>x : Symbol(H.x, Decl(h.js, 1, 19))
@@ -0,0 +1,223 @@
=== tests/cases/conformance/salsa/node.d.ts ===
declare function require(id: string): any;
>require : (id: string) => any
>id : string
declare var module: any, exports: any;
>module : any
>exports : any
=== tests/cases/conformance/salsa/a-ext.js ===
exports.A = function () {
>exports.A = function () { this.x = 1;} : () => void
>exports.A : any
>exports : any
>A : any
>function () { this.x = 1;} : () => void
this.x = 1;
>this.x = 1 : 1
>this.x : any
>this : any
>x : any
>1 : 1
};
=== tests/cases/conformance/salsa/a.js ===
const { A } = require("./a-ext");
>A : () => void
>require("./a-ext") : typeof "tests/cases/conformance/salsa/a-ext"
>require : (id: string) => any
>"./a-ext" : "./a-ext"
/** @param {A} p */
function a(p) { p.x; }
>a : (p: { x: number; }) => void
>p : { x: number; }
>p.x : number
>p : { x: number; }
>x : number
=== tests/cases/conformance/salsa/b-ext.js ===
exports.B = class {
>exports.B = class { constructor() { this.x = 1; }} : typeof (Anonymous class)
>exports.B : any
>exports : any
>B : any
>class { constructor() { this.x = 1; }} : typeof (Anonymous class)
constructor() {
this.x = 1;
>this.x = 1 : 1
>this.x : number
>this : this
>x : number
>1 : 1
}
};
=== tests/cases/conformance/salsa/b.js ===
const { B } = require("./b-ext");
>B : typeof (Anonymous class)
>require("./b-ext") : typeof "tests/cases/conformance/salsa/b-ext"
>require : (id: string) => any
>"./b-ext" : "./b-ext"
/** @param {B} p */
function b(p) { p.x; }
>b : (p: (Anonymous class)) => void
>p : (Anonymous class)
>p.x : number
>p : (Anonymous class)
>x : number
=== tests/cases/conformance/salsa/c-ext.js ===
export function C() {
>C : () => void
this.x = 1;
>this.x = 1 : 1
>this.x : any
>this : any
>x : any
>1 : 1
}
=== tests/cases/conformance/salsa/c.js ===
const { C } = require("./c-ext");
>C : () => void
>require("./c-ext") : typeof "tests/cases/conformance/salsa/c-ext"
>require : (id: string) => any
>"./c-ext" : "./c-ext"
/** @param {C} p */
function c(p) { p.x; }
>c : (p: { x: number; }) => void
>p : { x: number; }
>p.x : number
>p : { x: number; }
>x : number
=== tests/cases/conformance/salsa/d-ext.js ===
export var D = function() {
>D : () => void
>function() { this.x = 1;} : () => void
this.x = 1;
>this.x = 1 : 1
>this.x : any
>this : any
>x : any
>1 : 1
};
=== tests/cases/conformance/salsa/d.js ===
const { D } = require("./d-ext");
>D : () => void
>require("./d-ext") : typeof "tests/cases/conformance/salsa/d-ext"
>require : (id: string) => any
>"./d-ext" : "./d-ext"
/** @param {D} p */
function d(p) { p.x; }
>d : (p: { x: number; }) => void
>p : { x: number; }
>p.x : number
>p : { x: number; }
>x : number
=== tests/cases/conformance/salsa/e-ext.js ===
export class E {
>E : E
constructor() {
this.x = 1;
>this.x = 1 : 1
>this.x : number
>this : this
>x : number
>1 : 1
}
}
=== tests/cases/conformance/salsa/e.js ===
const { E } = require("./e-ext");
>E : typeof E
>require("./e-ext") : typeof "tests/cases/conformance/salsa/e-ext"
>require : (id: string) => any
>"./e-ext" : "./e-ext"
/** @param {E} p */
function e(p) { p.x; }
>e : (p: E) => void
>p : E
>p.x : number
>p : E
>x : number
=== tests/cases/conformance/salsa/f.js ===
var F = function () {
>F : () => void
>function () { this.x = 1;} : () => void
this.x = 1;
>this.x = 1 : 1
>this.x : any
>this : any
>x : any
>1 : 1
};
/** @param {F} p */
function f(p) { p.x; }
>f : (p: { x: number; }) => void
>p : { x: number; }
>p.x : number
>p : { x: number; }
>x : number
=== tests/cases/conformance/salsa/g.js ===
function G() {
>G : () => void
this.x = 1;
>this.x = 1 : 1
>this.x : any
>this : any
>x : any
>1 : 1
}
/** @param {G} p */
function g(p) { p.x; }
>g : (p: { x: number; }) => void
>p : { x: number; }
>p.x : number
>p : { x: number; }
>x : number
=== tests/cases/conformance/salsa/h.js ===
class H {
>H : H
constructor() {
this.x = 1;
>this.x = 1 : 1
>this.x : number
>this : this
>x : number
>1 : 1
}
}
/** @param {H} p */
function h(p) { p.x; }
>h : (p: H) => void
>p : H
>p.x : number
>p : H
>x : number
@@ -0,0 +1,20 @@
// @checkJs: true
// @allowJs: true
// @Filename: main.js
// @noemit: true
function allRest() { arguments; }
allRest();
allRest(1, 2, 3);
function someRest(x, y) { arguments; }
someRest(); // x and y are still optional because they are in a JS file
someRest(1, 2, 3);
/**
* @param {number} x - a thing
*/
function jsdocced(x) { arguments; }
jsdocced(1);
function dontDoubleRest(x, ...y) { arguments; }
dontDoubleRest(1, 2, 3);
+4
View File
@@ -6,12 +6,16 @@ export class A { }
// @filename: b.ts
import { A } from "./a";
export * from "./a";
export class B extends A { }
// @filename: tslib.d.ts
export declare function __extends(d: Function, b: Function): void;
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __rest(t: any, propertyNames: string[]): any;
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
export declare function __param(paramIndex: number, decorator: Function): Function;
export declare function __metadata(metadataKey: any, metadataValue: any): Function;
export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any;
export declare function __generator(thisArg: any, body: Function): any;
export declare function __exportStar(m: any, exports: any): void;
@@ -49,7 +49,10 @@ declare namespace N {
// @filename: tslib.d.ts
export declare function __extends(d: Function, b: Function): void;
export declare function __assign(t: any, ...sources: any[]): any;
export declare function __rest(t: any, propertyNames: string[]): any;
export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any;
export declare function __param(paramIndex: number, decorator: Function): Function;
export declare function __metadata(metadataKey: any, metadataValue: any): Function;
export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any;
export declare function __generator(thisArg: any, body: Function): any;
export declare function __exportStar(m: any, exports: any): void;
@@ -5,6 +5,7 @@
// @experimentalDecorators: true
// @emitDecoratorMetadata: true
// @filename: external.ts
export * from "./other";
export class A { }
export class B extends A { }
@@ -20,6 +21,9 @@ const o = { a: 1 };
const y = { ...o };
const { ...x } = y;
// @filename: other.ts
export const x = 1;
// @filename: script.ts
class A { }
class B extends A { }
@@ -6,6 +6,7 @@ export class A { }
// @filename: b.ts
import { A } from "./a";
export * from "./a";
export class B extends A { }
// @filename: tslib.d.ts
@@ -0,0 +1,8 @@
// @Filename: foo.js
// @noEmit: true
// @allowJs: true
// Test #16139
function Foo() {
arguments;
return new Foo();
}
@@ -0,0 +1,6 @@
function recursive() {
let x = <T>(subkey: T) => recursive();
return x as typeof x & { p };
}
let result = recursive()(1)
@@ -0,0 +1,92 @@
// @allowJs: true
// @checkJs: true
// @noEmit: true
// @module: commonjs
// @filename: node.d.ts
declare function require(id: string): any;
declare var module: any, exports: any;
// @filename: a-ext.js
exports.A = function () {
this.x = 1;
};
// @filename: a.js
const { A } = require("./a-ext");
/** @param {A} p */
function a(p) { p.x; }
// @filename: b-ext.js
exports.B = class {
constructor() {
this.x = 1;
}
};
// @filename: b.js
const { B } = require("./b-ext");
/** @param {B} p */
function b(p) { p.x; }
// @filename: c-ext.js
export function C() {
this.x = 1;
}
// @filename: c.js
const { C } = require("./c-ext");
/** @param {C} p */
function c(p) { p.x; }
// @filename: d-ext.js
export var D = function() {
this.x = 1;
};
// @filename: d.js
const { D } = require("./d-ext");
/** @param {D} p */
function d(p) { p.x; }
// @filename: e-ext.js
export class E {
constructor() {
this.x = 1;
}
}
// @filename: e.js
const { E } = require("./e-ext");
/** @param {E} p */
function e(p) { p.x; }
// @filename: f.js
var F = function () {
this.x = 1;
};
/** @param {F} p */
function f(p) { p.x; }
// @filename: g.js
function G() {
this.x = 1;
}
/** @param {G} p */
function g(p) { p.x; }
// @filename: h.js
class H {
constructor() {
this.x = 1;
}
}
/** @param {H} p */
function h(p) { p.x; }
+14 -13
View File
@@ -160,8 +160,8 @@
////fo/*37q*/oBar(/*37*/"foo",/*38*/"bar");
/////** This is a comment */
////var x;
/////**
//// * This is a comment
/////**
//// * This is a comment
//// */
////var y;
/////** this is jsdoc style function with param tag as well as inline parameter help
@@ -173,7 +173,7 @@
////}
/////*44*/jsD/*40q*/ocParamTest(/*40*/30, /*41*/40, /*42*/50, /*43*/60);
/////** This is function comment
//// * And properly aligned comment
//// * And properly aligned comment
//// */
////function jsDocCommentAlignmentTest1() {
////}
@@ -334,39 +334,40 @@ goTo.marker('27');
verify.completionListContains("multiply", "function multiply(a: number, b: number, c?: number, d?: any, e?: any): void", "This is multiplication function");
verify.completionListContains("f1", "function f1(a: number): any (+1 overload)", "fn f1 with number");
const subtractDoc = "This is subtract function";
goTo.marker('28');
verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f");
verify.currentSignatureHelpDocCommentIs(subtractDoc);
verify.currentParameterHelpArgumentDocCommentIs("");
verify.quickInfos({
"28q": [
"function subtract(a: number, b: number, c?: () => string, d?: () => string, e?: () => string, f?: () => string): void",
"This is subtract function{ () => string; } } f this is optional param f"
subtractDoc,
],
"28aq": "(parameter) a: number"
});
goTo.marker('29');
verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f");
verify.currentSignatureHelpDocCommentIs(subtractDoc);
verify.currentParameterHelpArgumentDocCommentIs("this is about b");
verify.quickInfoAt("29aq", "(parameter) b: number", "this is about b");
goTo.marker('30');
verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f");
verify.currentSignatureHelpDocCommentIs(subtractDoc);
verify.currentParameterHelpArgumentDocCommentIs("this is optional param c");
verify.quickInfoAt("30aq", "(parameter) c: () => string", "this is optional param c");
goTo.marker('31');
verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f");
verify.currentSignatureHelpDocCommentIs(subtractDoc);
verify.currentParameterHelpArgumentDocCommentIs("this is optional param d");
verify.quickInfoAt("31aq", "(parameter) d: () => string", "this is optional param d");
goTo.marker('32');
verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f");
verify.currentSignatureHelpDocCommentIs(subtractDoc);
verify.currentParameterHelpArgumentDocCommentIs("this is optional param e");
verify.quickInfoAt("32aq", "(parameter) e: () => string", "this is optional param e");
goTo.marker('33');
verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f");
verify.currentSignatureHelpDocCommentIs(subtractDoc);
verify.currentParameterHelpArgumentDocCommentIs("");
verify.quickInfoAt("33aq", "(parameter) f: () => string");
@@ -454,11 +455,11 @@ verify.quickInfoAt("43aq", "(parameter) d: number");
goTo.marker('44');
verify.completionListContains("jsDocParamTest", "function jsDocParamTest(a: number, b: number, c: number, d: number): number", "this is jsdoc style function with param tag as well as inline parameter help");
verify.completionListContains("x", "var x: any", "This is a comment ");
verify.completionListContains("y", "var y: any", "This is a comment ");
verify.completionListContains("y", "var y: any", "This is a comment");
goTo.marker('45');
verify.currentSignatureHelpDocCommentIs("This is function comment\nAnd properly aligned comment ");
verify.quickInfoAt("45q", "function jsDocCommentAlignmentTest1(): void", "This is function comment\nAnd properly aligned comment ");
verify.currentSignatureHelpDocCommentIs("This is function comment\nAnd properly aligned comment");
verify.quickInfoAt("45q", "function jsDocCommentAlignmentTest1(): void", "This is function comment\nAnd properly aligned comment");
goTo.marker('46');
verify.currentSignatureHelpDocCommentIs("This is function comment\n And aligned with 4 space char margin");
@@ -23,4 +23,4 @@ verify.fileAfterApplyingRefactorAtMarker('1',
foo.prototype.instanceProp1 = "hello";
foo.prototype.instanceProp2 = undefined;
foo.staticProp = "world";
`, 'Convert to ES2015 class');
`, 'Convert to ES2015 class', 'convert');
@@ -24,4 +24,4 @@ verify.fileAfterApplyingRefactorAtMarker('4',
foo.instanceProp1 = "hello";
foo.instanceProp2 = undefined;
foo.staticProp = "world";
`, 'Convert to ES2015 class');
`, 'Convert to ES2015 class', 'convert');
@@ -25,4 +25,4 @@ class foo {
foo.prototype.instanceProp1 = "hello";
foo.prototype.instanceProp2 = undefined;
foo.staticProp = "world";
`, 'Convert to ES2015 class');
`, 'Convert to ES2015 class', 'convert');
@@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
// @Filename: /a.ts
////export = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {
//// m() { [|A|]; }
////};
// @Filename: /b.ts
////import [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
////[|A|];
const [r0, r1, r2, r3] = test.ranges();
const defs = { definition: "(local class) A", ranges: [r0, r1] };
const imports = { definition: 'import A = require("./a")', ranges: [r2, r3] };
verify.referenceGroups([r0, r1], [defs, imports]);
verify.referenceGroups([r2, r3], [imports, defs]);
@@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {};
// @Filename: /b.js
////import [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a");
////[|A|];
const [r0, r1, r2] = test.ranges();
const defs = { definition: "(local class) A", ranges: [r0] };
const imports = { definition: 'import A = require("./a")', ranges: [r1, r2] };
verify.referenceGroups([r0], [defs, imports]);
verify.referenceGroups([r1, r2], [imports, defs]);
@@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////exports.[|{| "isWriteAccess": true, "isDefinition": true |}A|] = class {};
// @Filename: /b.js
////import { [|{| "isWriteAccess": true, "isDefinition": true |}A|] } from "./a";
////[|A|];
const [r0, r1, r2] = test.ranges();
const defs = { definition: "(property) A: typeof (Anonymous class)", ranges: [r0] };
const imports = { definition: "import A", ranges: [r1, r2] };
verify.referenceGroups([r0], [defs, imports]);
verify.referenceGroups([r1, r2], [imports, defs]);
+2 -2
View File
@@ -236,8 +236,8 @@ declare namespace FourSlashInterface {
noMatchingBracePositionInCurrentFile(bracePosition: number): void;
DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void;
noDocCommentTemplate(): void;
rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void
getAndApplyCodeFix(errorCode?: number, index?: number): void;
rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void;
fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: FormatCodeOptions): void;
rangeIs(expectedText: string, includeWhiteSpace?: boolean): void;
fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: FormatCodeOptions): void;
importFixAtPosition(expectedTextArray: string[], errorCode?: number): void;
@@ -0,0 +1,29 @@
///<reference path="fourslash.ts" />
/////**
//// * @param /*0*/
//// */
////function f(foo, bar) {}
/////**
//// * @param foo
//// * @param /*1*/
//// */
////function g(foo, bar) {}
/////**
//// * @param can/*2*/
//// * @param cantaloupe
//// */
////function h(cat, canary, canoodle, cantaloupe, zebra) {}
/////**
//// * @param /*3*/ {string} /*4*/
//// */
////function i(foo, bar) {}
verify.completionsAt("0", ["foo", "bar"]);
verify.completionsAt("1", ["bar"]);
verify.completionsAt("2", ["canary", "canoodle"]);
verify.completionsAt("3", ["foo", "bar"]);
verify.completionsAt("4", ["foo", "bar"]);
@@ -22,4 +22,4 @@ class fn {
console.log('hello world');
}
}
`, 'Convert to ES2015 class');
`, 'Convert to ES2015 class', 'convert');
@@ -4,14 +4,25 @@
// @allowJs: true
// @Filename: main.js
////function fnTest() { arguments; }
////fnTest(/*1*/);
////fnTest(1, 2, 3);
////function allOptional() { arguments; }
////allOptional(/*1*/);
////allOptional(1, 2, 3);
////function someOptional(x, y) { arguments; }
////someOptional(/*2*/);
////someOptional(1, 2, 3);
////someOptional(); // no error here; x and y are optional in JS
goTo.marker('1');
verify.signatureHelpCountIs(1);
verify.currentSignatureParameterCountIs(1);
verify.currentSignatureHelpIs('fnTest(...args: any[]): void');
verify.currentSignatureHelpIs('allOptional(...args: any[]): void');
verify.currentParameterHelpArgumentNameIs('args');
verify.currentParameterSpanIs("...args: any[]");
verify.numberOfErrorsInCurrentFile(0);
goTo.marker('2');
verify.signatureHelpCountIs(1);
verify.currentSignatureParameterCountIs(3);
verify.currentSignatureHelpIs('someOptional(x: any, y: any, ...args: any[]): void');
verify.currentParameterHelpArgumentNameIs('x');
verify.currentParameterSpanIs("x: any");
verify.numberOfErrorsInCurrentFile(0);
+1
View File
@@ -6,6 +6,7 @@
"comment-format": [true,
"check-space"
],
"curly":[true, "ignore-same-line"],
"indent": [true,
"spaces"
],