Merge pull request #22442 from Microsoft/mergeMaster3-9

Merge master into release-2.8
This commit is contained in:
Mohamed Hegazy
2018-03-09 09:19:55 -08:00
committed by GitHub
186 changed files with 25797 additions and 26835 deletions
+1
View File
@@ -65,6 +65,7 @@ workflows:
base: &base
environment:
- workerCount: 4
- timeout: 400000
steps:
- checkout
- run: |
+125 -80
View File
@@ -315,7 +315,7 @@ namespace ts {
}
function getDisplayName(node: Declaration): string {
return (node as NamedDeclaration).name ? declarationNameToString((node as NamedDeclaration).name) : unescapeLeadingUnderscores(getDeclarationName(node));
return isNamedDeclaration(node) ? declarationNameToString(node.name) : unescapeLeadingUnderscores(getDeclarationName(node));
}
/**
@@ -383,8 +383,8 @@ namespace ts {
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
}
else {
if ((node as NamedDeclaration).name) {
(node as NamedDeclaration).name.parent = node;
if (isNamedDeclaration(node)) {
node.name.parent = node;
}
// Report errors every position with duplicate declaration
@@ -1996,7 +1996,7 @@ namespace ts {
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
function isUseStrictPrologueDirective(node: ExpressionStatement): boolean {
const nodeText = getTextOfNodeFromSourceText(file.text, node.expression);
const nodeText = getSourceTextOfNodeFromSourceFile(file, node.expression);
// Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the
// string to contain unicode escapes (as per ES5).
@@ -2036,19 +2036,22 @@ namespace ts {
const specialKind = getSpecialPropertyAssignmentKind(node as BinaryExpression);
switch (specialKind) {
case SpecialPropertyAssignmentKind.ExportsProperty:
bindExportsPropertyAssignment(<BinaryExpression>node);
bindExportsPropertyAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.ModuleExports:
bindModuleExportsAssignment(<BinaryExpression>node);
bindModuleExportsAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.PrototypeProperty:
bindPrototypePropertyAssignment(<BinaryExpression>node);
bindPrototypePropertyAssignment((node as BinaryExpression).left as PropertyAccessEntityNameExpression, node);
break;
case SpecialPropertyAssignmentKind.Prototype:
bindPrototypeAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.ThisProperty:
bindThisPropertyAssignment(<BinaryExpression>node);
bindThisPropertyAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.Property:
bindStaticPropertyAssignment(<BinaryExpression>node);
bindSpecialPropertyAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.None:
// Nothing to do
@@ -2291,7 +2294,18 @@ namespace ts {
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
// expression is the declaration
setCommonJsModuleIndicator(node);
declareSymbol(file.symbol.exports, file.symbol, <PropertyAccessExpression>node.left, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
const lhs = node.left as PropertyAccessEntityNameExpression;
const symbol = forEachIdentifierInEntityName(lhs.expression, (id, original) => {
if (!original) {
return undefined;
}
const s = getJSInitializerSymbol(original);
addDeclarationToSymbol(s, id, SymbolFlags.Module | SymbolFlags.JSContainer);
return s;
});
if (symbol) {
declareSymbol(symbol.exports, symbol, lhs, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None);
}
}
function bindModuleExportsAssignment(node: BinaryExpression) {
@@ -2338,103 +2352,134 @@ namespace ts {
}
function bindSpecialPropertyDeclaration(node: PropertyAccessExpression) {
Debug.assert(isInJavaScriptFile(node));
if (node.expression.kind === SyntaxKind.ThisKeyword) {
bindThisPropertyAssignment(node);
}
else if ((node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression) &&
node.parent.parent.kind === SyntaxKind.SourceFile) {
bindStaticPropertyAssignment(node);
else if (isEntityNameExpression(node) && node.parent.parent.kind === SyntaxKind.SourceFile) {
if (isPropertyAccessExpression(node.expression) && node.expression.name.escapedText === "prototype") {
bindPrototypePropertyAssignment(node as PropertyAccessEntityNameExpression, node.parent);
}
else {
bindStaticPropertyAssignment(node as PropertyAccessEntityNameExpression);
}
}
}
function bindPrototypePropertyAssignment(node: BinaryExpression) {
// We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x is a function or class, or not declared.
// Look up the function in the local scope, since prototype assignments should
// follow the function declaration
const leftSideOfAssignment = node.left as PropertyAccessExpression;
const classPrototype = leftSideOfAssignment.expression as PropertyAccessExpression;
const constructorFunction = classPrototype.expression as Identifier;
// Fix up parent pointers since we're going to use these nodes before we bind into them
leftSideOfAssignment.parent = node;
constructorFunction.parent = classPrototype;
classPrototype.parent = leftSideOfAssignment;
bindPropertyAssignment(constructorFunction.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ true);
/** For `x.prototype = { p, ... }`, declare members p,... if `x` is function/class/{}, or not declared. */
function bindPrototypeAssignment(node: BinaryExpression) {
node.left.parent = node;
node.right.parent = node;
const lhs = node.left as PropertyAccessEntityNameExpression;
bindPropertyAssignment(lhs, lhs, /*isPrototypeProperty*/ false);
}
/**
* For nodes like `x.y = z`, declare a member 'y' on 'x' if x is a function or class, or not declared.
* Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y;
* For `x.prototype.y = z`, declare a member `y` on `x` if `x` is a function or class, or not declared.
* Note that jsdoc preceding an ExpressionStatement like `x.prototype.y;` is also treated as a declaration.
*/
function bindStaticPropertyAssignment(node: BinaryExpression | PropertyAccessExpression) {
// Look up the function in the local scope, since static assignments should
function bindPrototypePropertyAssignment(lhs: PropertyAccessEntityNameExpression, parent: Node) {
// Look up the function in the local scope, since prototype assignments should
// follow the function declaration
const leftSideOfAssignment = node.kind === SyntaxKind.PropertyAccessExpression ? node : node.left as PropertyAccessExpression;
const target = leftSideOfAssignment.expression;
const classPrototype = lhs.expression as PropertyAccessEntityNameExpression;
const constructorFunction = classPrototype.expression;
if (isIdentifier(target)) {
// Fix up parent pointers since we're going to use these nodes before we bind into them
target.parent = leftSideOfAssignment;
if (node.kind === SyntaxKind.BinaryExpression) {
leftSideOfAssignment.parent = node;
}
if (container === file && isNameOfExportsOrModuleExportsAliasDeclaration(file, target)) {
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
// var util = module.exports;
// util.property = function ...
bindExportsPropertyAssignment(node as BinaryExpression);
}
else {
bindPropertyAssignment(target.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ false);
}
}
// Fix up parent pointers since we're going to use these nodes before we bind into them
lhs.parent = parent;
constructorFunction.parent = classPrototype;
classPrototype.parent = lhs;
bindPropertyAssignment(constructorFunction, lhs, /*isPrototypeProperty*/ true);
}
function lookupSymbolForName(name: __String) {
return lookupSymbolForNameWorker(container, name);
}
function bindPropertyAssignment(functionName: __String, propertyAccess: PropertyAccessExpression, isPrototypeProperty: boolean) {
const symbol = lookupSymbolForName(functionName);
let targetSymbol = symbol && isDeclarationOfFunctionOrClassExpression(symbol) ?
(symbol.valueDeclaration as VariableDeclaration).initializer.symbol :
symbol;
Debug.assert(propertyAccess.parent.kind === SyntaxKind.BinaryExpression || propertyAccess.parent.kind === SyntaxKind.ExpressionStatement);
let isLegalPosition: boolean;
if (propertyAccess.parent.kind === SyntaxKind.BinaryExpression) {
const initializerKind = (propertyAccess.parent as BinaryExpression).right.kind;
isLegalPosition = (initializerKind === SyntaxKind.ClassExpression || initializerKind === SyntaxKind.FunctionExpression) &&
propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile;
function bindSpecialPropertyAssignment(node: BinaryExpression) {
const lhs = node.left as PropertyAccessEntityNameExpression;
// Fix up parent pointers since we're going to use these nodes before we bind into them
node.left.parent = node;
node.right.parent = node;
if (isIdentifier(lhs.expression) && container === file && isNameOfExportsOrModuleExportsAliasDeclaration(file, lhs.expression)) {
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
// var util = module.exports;
// util.property = function ...
bindExportsPropertyAssignment(node);
}
else {
isLegalPosition = propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
bindStaticPropertyAssignment(lhs);
}
if (!isPrototypeProperty && (!targetSymbol || !(targetSymbol.flags & SymbolFlags.Namespace)) && isLegalPosition) {
Debug.assert(isIdentifier(propertyAccess.expression));
const identifier = propertyAccess.expression as Identifier;
}
/**
* For nodes like `x.y = z`, declare a member 'y' on 'x' if x is a function (or IIFE) or class or {}, or not declared.
* Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y;
*/
function bindStaticPropertyAssignment(node: PropertyAccessEntityNameExpression) {
node.expression.parent = node;
bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false);
}
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) {
let symbol = getJSInitializerSymbol(lookupSymbolForPropertyAccess(name));
let isToplevelNamespaceableInitializer: boolean;
if (isBinaryExpression(propertyAccess.parent)) {
const isPrototypeAssignment = isPropertyAccessExpression(propertyAccess.parent.left) && propertyAccess.parent.left.name.escapedText === "prototype";
isToplevelNamespaceableInitializer = propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile &&
!!getJavascriptInitializer(propertyAccess.parent.right, isPrototypeAssignment);
}
else {
isToplevelNamespaceableInitializer = propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
}
if (!isPrototypeProperty && (!symbol || !(symbol.flags & SymbolFlags.Namespace)) && isToplevelNamespaceableInitializer) {
// make symbols or add declarations for intermediate containers
const flags = SymbolFlags.Module | SymbolFlags.JSContainer;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer;
if (targetSymbol) {
addDeclarationToSymbol(symbol, identifier, flags);
}
else {
targetSymbol = declareSymbol(container.locals, /*parent*/ undefined, identifier, flags, excludeFlags);
}
forEachIdentifierInEntityName(propertyAccess.expression, (id, original) => {
if (original) {
// Note: add declaration to original symbol, not the special-syntax's symbol, so that namespaces work for type lookup
addDeclarationToSymbol(original, id, flags);
return original;
}
else {
return symbol = declareSymbol(symbol ? symbol.exports : container.locals, symbol, id, flags, excludeFlags);
}
});
}
if (!targetSymbol || !(targetSymbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule))) {
if (!symbol || !(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule | SymbolFlags.ObjectLiteral))) {
return;
}
// Set up the members collection if it doesn't exist already
const symbolTable = isPrototypeProperty ?
(targetSymbol.members || (targetSymbol.members = createSymbolTable())) :
(targetSymbol.exports || (targetSymbol.exports = createSymbolTable()));
(symbol.members || (symbol.members = createSymbolTable())) :
(symbol.exports || (symbol.exports = createSymbolTable()));
// Declare the method/property
declareSymbol(symbolTable, targetSymbol, propertyAccess, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
const symbolFlags = SymbolFlags.Property | (isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
const symbolExcludes = SymbolFlags.PropertyExcludes & ~(isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0);
declareSymbol(symbolTable, symbol, propertyAccess, symbolFlags, symbolExcludes);
}
function lookupSymbolForPropertyAccess(node: EntityNameExpression): Symbol | undefined {
if (isIdentifier(node)) {
return lookupSymbolForNameWorker(container, node.escapedText);
}
else {
const symbol = getJSInitializerSymbol(lookupSymbolForPropertyAccess(node.expression));
return symbol && symbol.exports && symbol.exports.get(node.name.escapedText);
}
}
function forEachIdentifierInEntityName(e: EntityNameExpression, action: (e: Identifier, symbol: Symbol) => Symbol): Symbol {
if (isExportsOrModuleExportsOrAlias(file, e)) {
return file.symbol;
}
else if (isIdentifier(e)) {
return action(e, lookupSymbolForPropertyAccess(e));
}
else {
const s = getJSInitializerSymbol(forEachIdentifierInEntityName(e.expression, action));
Debug.assert(!!s && !!s.exports);
return action(e.name, s.exports.get(e.name.escapedText));
}
}
function bindCallExpression(node: CallExpression) {
@@ -2665,7 +2710,7 @@ namespace ts {
function isExportsOrModuleExportsOrAliasOrAssignment(sourceFile: SourceFile, node: Expression): boolean {
return isExportsOrModuleExportsOrAlias(sourceFile, node) ||
(isAssignmentExpression(node, /*excludeCompoundAssignements*/ true) && (
(isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) && (
isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.left) || isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.right)));
}
+234 -137
View File
@@ -870,7 +870,7 @@ namespace ts {
function mergeSymbol(target: Symbol, source: Symbol) {
if (!(target.flags & getExcludedSymbolFlags(source.flags)) ||
source.flags & SymbolFlags.JSContainer || target.flags & SymbolFlags.JSContainer) {
(source.flags | target.flags) & SymbolFlags.JSContainer) {
// Javascript static-property-assignment declarations always merge, even though they are also values
if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) {
// reset flag when merging instantiated module into value module that has only const enums
@@ -892,6 +892,13 @@ namespace ts {
if (!target.exports) target.exports = createSymbolTable();
mergeSymbolTable(target.exports, source.exports);
}
if ((source.flags | target.flags) & SymbolFlags.JSContainer) {
const sourceInitializer = getJSInitializerSymbol(source);
const targetInitializer = getJSInitializerSymbol(target);
if (sourceInitializer !== source || targetInitializer !== target) {
mergeSymbol(targetInitializer, sourceInitializer);
}
}
recordMergedSymbol(target, source);
}
else if (target.flags & SymbolFlags.NamespaceModule) {
@@ -904,10 +911,12 @@ namespace ts {
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
: Diagnostics.Duplicate_identifier_0;
forEach(source.declarations, node => {
error(getNameOfDeclaration(node) || node, message, symbolToString(source));
const errorNode = (getJavascriptInitializer(node, /*isPrototypeAssignment*/ false) ? getOuterNameOfJsInitializer(node) : getNameOfDeclaration(node)) || node;
error(errorNode, message, symbolToString(source));
});
forEach(target.declarations, node => {
error(getNameOfDeclaration(node) || node, message, symbolToString(source));
const errorNode = (getJavascriptInitializer(node, /*isPrototypeAssignment*/ false) ? getOuterNameOfJsInitializer(node) : getNameOfDeclaration(node)) || node;
error(errorNode, message, symbolToString(source));
});
}
}
@@ -1599,8 +1608,9 @@ namespace ts {
}
function checkAndReportErrorForUsingTypeAsNamespace(errorLocation: Node, name: __String, meaning: SymbolFlags): boolean {
if (meaning === SymbolFlags.Namespace) {
const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~SymbolFlags.Namespace, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false));
const namespaceMeaning = SymbolFlags.Namespace | (isInJavaScriptFile(errorLocation) ? SymbolFlags.Value : 0);
if (meaning === namespaceMeaning) {
const symbol = resolveSymbol(resolveName(errorLocation, name, SymbolFlags.Type & ~namespaceMeaning, /*nameNotFoundMessage*/undefined, /*nameArg*/ undefined, /*isUse*/ false));
const parent = errorLocation.parent;
if (symbol) {
if (isQualifiedName(parent)) {
@@ -2014,9 +2024,10 @@ namespace ts {
return undefined;
}
const namespaceMeaning = SymbolFlags.Namespace | (isInJavaScriptFile(name) ? meaning & SymbolFlags.Value : 0);
let symbol: Symbol;
if (name.kind === SyntaxKind.Identifier) {
const message = meaning === SymbolFlags.Namespace ? Diagnostics.Cannot_find_namespace_0 : Diagnostics.Cannot_find_name_0;
const message = meaning === namespaceMeaning ? Diagnostics.Cannot_find_namespace_0 : Diagnostics.Cannot_find_name_0;
symbol = resolveName(location || name, name.escapedText, meaning, ignoreErrors ? undefined : message, name, /*isUse*/ true);
if (!symbol) {
@@ -2024,31 +2035,32 @@ namespace ts {
}
}
else if (name.kind === SyntaxKind.QualifiedName || name.kind === SyntaxKind.PropertyAccessExpression) {
let left: EntityNameOrEntityNameExpression;
if (name.kind === SyntaxKind.QualifiedName) {
left = name.left;
}
else if (name.kind === SyntaxKind.PropertyAccessExpression) {
left = name.expression;
}
else {
// If the expression in property-access expression is not entity-name or parenthsizedExpression (e.g. it is a call expression), it won't be able to successfully resolve the name.
// This is the case when we are trying to do any language service operation in heritage clauses. By return undefined, the getSymbolOfEntityNameOrPropertyAccessExpression
// will attempt to checkPropertyAccessExpression to resolve symbol.
// i.e class C extends foo()./*do language service operation here*/B {}
return undefined;
}
const left = name.kind === SyntaxKind.QualifiedName ? name.left : name.expression;
const right = name.kind === SyntaxKind.QualifiedName ? name.right : name.name;
let namespace = resolveEntityName(left, SymbolFlags.Namespace, ignoreErrors, /*dontResolveAlias*/ false, location);
let namespace = resolveEntityName(left, namespaceMeaning, ignoreErrors, /*dontResolveAlias*/ false, location);
if (!namespace || nodeIsMissing(right)) {
return undefined;
}
else if (namespace === unknownSymbol) {
return namespace;
}
if (isInJavaScriptFile(name) && isDeclarationOfFunctionOrClassExpression(namespace)) {
namespace = getSymbolOfNode((namespace.valueDeclaration as VariableDeclaration).initializer);
if (isInJavaScriptFile(name)) {
const initializer = getDeclaredJavascriptInitializer(namespace.valueDeclaration) || getAssignedJavascriptInitializer(namespace.valueDeclaration);
if (initializer) {
namespace = getSymbolOfNode(initializer);
}
if (namespace.valueDeclaration &&
isVariableDeclaration(namespace.valueDeclaration) &&
isCommonJsRequire(namespace.valueDeclaration.initializer)) {
const moduleName = (namespace.valueDeclaration.initializer as CallExpression).arguments[0] as StringLiteral;
const moduleSym = resolveExternalModuleName(moduleName, moduleName);
if (moduleSym) {
const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym);
if (resolvedModuleSymbol) {
namespace = resolvedModuleSymbol;
}
}
}
}
symbol = getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning);
if (!symbol) {
@@ -4227,6 +4239,11 @@ namespace ts {
}
function getWidenedTypeFromJSSpecialPropertyDeclarations(symbol: Symbol) {
// function/class/{} assignments are fresh declarations, not property assignments, so only add prototype assignments
const specialDeclaration = getAssignedJavascriptInitializer(symbol.valueDeclaration);
if (specialDeclaration) {
return getWidenedLiteralType(checkExpressionCached(specialDeclaration));
}
const types: Type[] = [];
let definedInConstructor = false;
let definedInMethod = false;
@@ -6959,7 +6976,10 @@ namespace ts {
}
function createSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature {
return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), /*eraseTypeParameters*/ true);
return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true);
}
function createSignatureTypeMapper(signature: Signature, typeArguments: Type[]): TypeMapper {
return createTypeMapper(signature.typeParameters, typeArguments);
}
function getErasedSignature(signature: Signature): Signature {
@@ -7303,12 +7323,11 @@ namespace ts {
// A jsdoc TypeReference 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 assignedType = getAssignedClassType(symbol);
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType)) {
const referenceType = getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
if (referenceType) {
return referenceType;
}
const referenceType = valueType.symbol && !isInferredClassType(valueType) && getTypeReferenceTypeWorker(node, valueType.symbol, typeArguments);
if (referenceType || assignedType) {
return referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType;
}
// Resolve the type reference as a Type for the purpose of reporting errors.
@@ -8005,10 +8024,10 @@ namespace ts {
}
function getLiteralTypeFromPropertyName(prop: Symbol) {
const links = getSymbolLinks(prop);
const links = getSymbolLinks(getLateBoundSymbol(prop));
if (!links.nameType) {
if (links.target) {
Debug.assert(links.target.escapedName === prop.escapedName, "Target symbol and symbol do not have the same name");
if (links.target && links.target !== unknownSymbol && links.target !== resolvingSymbol) {
Debug.assert(links.target.escapedName === prop.escapedName || links.target.escapedName === InternalSymbolName.Computed, "Target symbol and symbol do not have the same name");
links.nameType = getLiteralTypeFromPropertyName(links.target);
}
else {
@@ -10555,6 +10574,11 @@ namespace ts {
if (isIgnoredJsxProperty(source, prop, /*targetMemberType*/ undefined)) {
continue;
}
// Skip over symbol-named members
const nameType = getLiteralTypeFromPropertyName(prop);
if (nameType !== undefined && !(isRelatedTo(nameType, stringType) || isRelatedTo(nameType, numberType))) {
continue;
}
if (kind === IndexKind.String || isNumericLiteralName(prop.escapedName)) {
const related = isRelatedTo(getTypeOfSymbol(prop), target, reportErrors);
if (!related) {
@@ -11419,8 +11443,8 @@ namespace ts {
}
}
function createInferenceContext(typeParameters: TypeParameter[], signature: Signature, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext {
const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(typeParameters, createInferenceInfo);
function createInferenceContext(typeParameters: TypeParameter[], signature: Signature | undefined, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext {
const inferences = baseInferences ? baseInferences.map(cloneInferenceInfo) : typeParameters.map(createInferenceInfo);
const context = mapper as InferenceContext;
context.typeParameters = typeParameters;
context.signature = signature;
@@ -14086,7 +14110,7 @@ namespace ts {
}
}
function getContainingObjectLiteral(func: FunctionLike): ObjectLiteralExpression | undefined {
function getContainingObjectLiteral(func: SignatureDeclaration): ObjectLiteralExpression | undefined {
return (func.kind === SyntaxKind.MethodDeclaration ||
func.kind === SyntaxKind.GetAccessor ||
func.kind === SyntaxKind.SetAccessor) && func.parent.kind === SyntaxKind.ObjectLiteralExpression ? func.parent :
@@ -14104,7 +14128,7 @@ namespace ts {
});
}
function getContextualThisParameterType(func: FunctionLike): Type {
function getContextualThisParameterType(func: SignatureDeclaration): Type {
if (func.kind === SyntaxKind.ArrowFunction) {
return undefined;
}
@@ -14301,7 +14325,7 @@ namespace ts {
return false;
}
function getContextualReturnType(functionDecl: FunctionLike): Type {
function getContextualReturnType(functionDecl: SignatureDeclaration): Type {
// If the containing function has a return type annotation, is a constructor, or is a get accessor whose
// corresponding set accessor has a type annotation, return statements in the function are contextually typed
if (functionDecl.kind === SyntaxKind.Constructor ||
@@ -14350,9 +14374,11 @@ namespace ts {
return node === right && isContextSensitiveAssignment(binaryExpression) ? getTypeOfExpression(left) : undefined;
case SyntaxKind.BarBarToken:
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand.
// expression has no contextual type, the right operand is contextually typed by the type of the left operand,
// except for the special case of Javascript declarations of the form `namespace.prop = namespace.prop || {}`
const type = getContextualType(binaryExpression);
return !type && node === right ? getTypeOfExpression(left, /*cache*/ true) : type;
return !type && node === right && !getDeclaredJavascriptInitializer(binaryExpression.parent) && !getAssignedJavascriptInitializer(binaryExpression) ?
getTypeOfExpression(left, /*cache*/ true) : type;
case SyntaxKind.AmpersandAmpersandToken:
case SyntaxKind.CommaToken:
return node === right ? getContextualType(binaryExpression) : undefined;
@@ -14375,6 +14401,7 @@ namespace ts {
case SpecialPropertyAssignmentKind.ModuleExports:
case SpecialPropertyAssignmentKind.PrototypeProperty:
case SpecialPropertyAssignmentKind.ThisProperty:
case SpecialPropertyAssignmentKind.Prototype:
return false;
default:
Debug.assertNever(kind);
@@ -14976,7 +15003,7 @@ namespace ts {
// Grammar checking
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
let propertiesTable = createSymbolTable();
let propertiesTable: SymbolTable;
let propertiesArray: Symbol[] = [];
let spread: Type = emptyObjectType;
let propagatedFlags: TypeFlags = TypeFlags.FreshLiteral;
@@ -14984,12 +15011,22 @@ namespace ts {
const contextualType = getApparentTypeOfContextualType(node);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
const isJSObjectLiteral = !contextualType && isInJavaScriptFile(node);
const isInJSFile = isInJavaScriptFile(node);
const isJSObjectLiteral = !contextualType && isInJSFile;
let typeFlags: TypeFlags = 0;
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
let hasComputedNumberProperty = false;
const isInJSFile = isInJavaScriptFile(node);
if (isInJSFile && node.properties.length === 0) {
// an empty JS object literal that nonetheless has members is a JS namespace
const symbol = getSymbolOfNode(node);
if (symbol.exports) {
propertiesTable = symbol.exports;
symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol)));
return createObjectLiteralType();
}
}
propertiesTable = createSymbolTable();
let offset = 0;
for (let i = 0; i < node.properties.length; i++) {
@@ -16409,15 +16446,23 @@ namespace ts {
return isValidPropertyAccessWithType(node, node.expression, property.escapedName, type)
&& (!(property.flags & SymbolFlags.Method) || isValidMethodAccess(property, type));
}
function isValidMethodAccess(method: Symbol, type: Type) {
function isValidMethodAccess(method: Symbol, actualThisType: Type): boolean {
const propType = getTypeOfFuncClassEnumModule(method);
const signatures = getSignaturesOfType(getNonNullableType(propType), SignatureKind.Call);
Debug.assert(signatures.length !== 0);
return signatures.some(sig => {
const thisType = getThisTypeOfSignature(sig);
return !thisType || isTypeAssignableTo(type, thisType);
const signatureThisType = getThisTypeOfSignature(sig);
return !signatureThisType || isTypeAssignableTo(actualThisType, getInstantiatedSignatureThisType(sig, signatureThisType, actualThisType));
});
}
function getInstantiatedSignatureThisType(sig: Signature, signatureThisType: Type, actualThisType: Type): Type {
if (!sig.typeParameters) {
return signatureThisType;
}
const context = createInferenceContext(sig.typeParameters, sig, InferenceFlags.None);
inferTypes(context.inferences, actualThisType, signatureThisType);
return instantiateType(signatureThisType, createSignatureTypeMapper(sig, getInferredTypes(context)));
}
function isValidPropertyAccessWithType(
node: PropertyAccessExpression | QualifiedName,
@@ -17993,20 +18038,54 @@ namespace ts {
}
function getJavaScriptClassType(symbol: Symbol): Type | undefined {
if (isDeclarationOfFunctionOrClassExpression(symbol)) {
symbol = getSymbolOfNode((<VariableDeclaration>symbol.valueDeclaration).initializer);
const initializer = getDeclaredJavascriptInitializer(symbol.valueDeclaration);
if (initializer) {
symbol = getSymbolOfNode(initializer);
}
let inferred: Type | undefined;
if (isJavaScriptConstructor(symbol.valueDeclaration)) {
return getInferredClassType(symbol);
inferred = getInferredClassType(symbol);
}
if (symbol.flags & SymbolFlags.Variable) {
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType) && isJavaScriptConstructor(valueType.symbol.valueDeclaration)) {
return getInferredClassType(valueType.symbol);
const assigned = getAssignedClassType(symbol);
const valueType = getTypeOfSymbol(symbol);
if (valueType.symbol && !isInferredClassType(valueType) && isJavaScriptConstructor(valueType.symbol.valueDeclaration)) {
inferred = getInferredClassType(valueType.symbol);
}
return assigned && inferred ?
getIntersectionType([inferred, assigned]) :
assigned || inferred;
}
function getAssignedClassType(symbol: Symbol) {
const decl = symbol.valueDeclaration;
const assignmentSymbol = decl && decl.parent &&
(isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent));
if (assignmentSymbol) {
const prototype = forEach(assignmentSymbol.declarations, getAssignedJavascriptPrototype);
if (prototype) {
return checkExpression(prototype);
}
}
}
function getAssignedJavascriptPrototype(node: Node) {
if (!node.parent) {
return false;
}
let parent: Node = node.parent;
while (parent && parent.kind === SyntaxKind.PropertyAccessExpression) {
parent = parent.parent;
}
return parent && isBinaryExpression(parent) &&
isPropertyAccessExpression(parent.left) &&
parent.left.name.escapedText === "prototype" &&
parent.operatorToken.kind === SyntaxKind.EqualsToken &&
isObjectLiteralExpression(parent.right) &&
parent.right;
}
function getInferredClassType(symbol: Symbol) {
const links = getSymbolLinks(symbol);
if (!links.inferredClassType) {
@@ -18066,7 +18145,7 @@ namespace ts {
// In JavaScript files, calls to any identifier 'require' are treated as external module imports
if (isInJavaScriptFile(node) && isCommonJsRequire(node)) {
return resolveExternalModuleTypeByLiteral(<StringLiteral>node.arguments[0]);
return resolveExternalModuleTypeByLiteral(node.arguments[0] as StringLiteral);
}
const returnType = getReturnTypeOfSignature(signature);
@@ -18444,27 +18523,23 @@ namespace ts {
function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode): Type[] {
const aggregatedTypes: Type[] = [];
const functionFlags = getFunctionFlags(func);
const isAsync = (getFunctionFlags(func) & FunctionFlags.Async) !== 0;
forEachYieldExpression(<Block>func.body, yieldExpression => {
const expr = yieldExpression.expression;
if (expr) {
let type = checkExpressionCached(expr, checkMode);
if (yieldExpression.asteriskToken) {
// A yield* expression effectively yields everything that its operand yields
type = checkIteratedTypeOrElementType(type, yieldExpression.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
}
if (functionFlags & FunctionFlags.Async) {
type = checkAwaitedType(type, expr, yieldExpression.asteriskToken
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
}
pushIfUnique(aggregatedTypes, type);
}
pushIfUnique(aggregatedTypes, getYieldedTypeOfYieldExpression(yieldExpression, isAsync, checkMode));
});
return aggregatedTypes;
}
function getYieldedTypeOfYieldExpression(node: YieldExpression, isAsync: boolean, checkMode?: CheckMode): Type {
const errorNode = node.expression || node;
const expressionType = node.expression ? checkExpressionCached(node.expression, checkMode) : undefinedWideningType;
// A `yield*` expression effectively yields everything that its operand yields
const yieldedType = node.asteriskToken ? checkIteratedTypeOrElementType(expressionType, errorNode, /*allowStringInput*/ false, isAsync) : expressionType;
return !isAsync ? yieldedType : getAwaitedType(yieldedType, errorNode, node.asteriskToken
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
}
function isExhaustiveSwitchStatement(node: SwitchStatement): boolean {
if (!node.possiblyExhaustive) {
return false;
@@ -19186,6 +19261,9 @@ namespace ts {
}
function checkBinaryExpression(node: BinaryExpression, checkMode?: CheckMode) {
if (isInJavaScriptFile(node) && getAssignedJavascriptInitializer(node)) {
return checkExpression(node.right, checkMode);
}
return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, checkMode, node);
}
@@ -19417,62 +19495,40 @@ namespace ts {
}
}
if (node.expression) {
const func = getContainingFunction(node);
// If the user's code is syntactically correct, the func should always have a star. After all,
// we are in a yield context.
const functionFlags = func && getFunctionFlags(func);
if (node.asteriskToken) {
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
// and __asyncValues helpers
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
languageVersion < ScriptTarget.ESNext) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
}
const func = getContainingFunction(node);
const functionFlags = func ? getFunctionFlags(func) : FunctionFlags.Normal;
// Generator functions prior to ES2015 require the __values helper
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
}
if (!(functionFlags & FunctionFlags.Generator)) {
// If the user's code is syntactically correct, the func should always have a star. After all, we are in a yield context.
return anyType;
}
if (node.asteriskToken) {
// Async generator functions prior to ESNext require the __await, __asyncDelegator,
// and __asyncValues helpers
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.AsyncGenerator &&
languageVersion < ScriptTarget.ESNext) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.AsyncDelegatorIncludes);
}
if (functionFlags & FunctionFlags.Generator) {
const expressionType = checkExpressionCached(node.expression);
let expressionElementType: Type;
const nodeIsYieldStar = !!node.asteriskToken;
if (nodeIsYieldStar) {
expressionElementType = checkIteratedTypeOrElementType(expressionType, node.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
}
// There is no point in doing an assignability check if the function
// has no explicit return type because the return type is directly computed
// from the yield expressions.
const returnType = getEffectiveReturnTypeNode(func);
if (returnType) {
const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(returnType), (functionFlags & FunctionFlags.Async) !== 0) || anyType;
if (nodeIsYieldStar) {
checkTypeAssignableTo(
functionFlags & FunctionFlags.Async
? getAwaitedType(expressionElementType, node.expression, Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)
: expressionElementType,
signatureElementType,
node.expression,
/*headMessage*/ undefined);
}
else {
checkTypeAssignableTo(
functionFlags & FunctionFlags.Async
? getAwaitedType(expressionType, node.expression, Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member)
: expressionType,
signatureElementType,
node.expression,
/*headMessage*/ undefined);
}
}
// Generator functions prior to ES2015 require the __values helper
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Generator &&
languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
checkExternalEmitHelpers(node, ExternalEmitHelpers.Values);
}
}
const isAsync = (functionFlags & FunctionFlags.Async) !== 0;
const yieldedType = getYieldedTypeOfYieldExpression(node, isAsync);
// There is no point in doing an assignability check if the function
// has no explicit return type because the return type is directly computed
// from the yield expressions.
const returnType = getEffectiveReturnTypeNode(func);
if (returnType) {
const signatureElementType = getIteratedTypeOfGenerator(getTypeFromTypeNode(returnType), isAsync) || anyType;
checkTypeAssignableTo(yieldedType, signatureElementType, node.expression || node, /*headMessage*/ undefined);
}
// Both yield and yield* expressions have type 'any'
return anyType;
}
@@ -19541,10 +19597,11 @@ namespace ts {
}
function checkDeclarationInitializer(declaration: HasExpressionInitializer) {
const type = getTypeOfExpression(declaration.initializer, /*cache*/ true);
const initializer = isInJavaScriptFile(declaration) && getDeclaredJavascriptInitializer(declaration) || declaration.initializer;
const type = getTypeOfExpression(initializer, /*cache*/ true);
return getCombinedNodeFlags(declaration) & NodeFlags.Const ||
(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration)) ||
isTypeAssertion(declaration.initializer) ? type : getWidenedLiteralType(type);
isTypeAssertion(initializer) ? type : getWidenedLiteralType(type);
}
function isLiteralOfContextualType(candidateType: Type, contextualType: Type): boolean {
@@ -20623,12 +20680,12 @@ namespace ts {
let hasOverloads = false;
let bodyDeclaration: FunctionLikeDeclaration;
let lastSeenNonAmbientDeclaration: FunctionLikeDeclaration;
let previousDeclaration: FunctionLike;
let previousDeclaration: SignatureDeclaration;
const declarations = symbol.declarations;
const isConstructor = (symbol.flags & SymbolFlags.Constructor) !== 0;
function reportImplementationExpectedError(node: FunctionLike): void {
function reportImplementationExpectedError(node: SignatureDeclaration): void {
if (node.name && nodeIsMissing(node.name)) {
return;
}
@@ -20690,7 +20747,7 @@ namespace ts {
let duplicateFunctionDeclaration = false;
let multipleConstructorImplementation = false;
for (const current of declarations) {
const node = <FunctionLike>current;
const node = <SignatureDeclaration>current;
const inAmbientContext = node.flags & NodeFlags.Ambient;
const inAmbientContextOrInterface = node.parent.kind === SyntaxKind.InterfaceDeclaration || node.parent.kind === SyntaxKind.TypeLiteral || inAmbientContext;
if (inAmbientContextOrInterface) {
@@ -21603,7 +21660,7 @@ namespace ts {
}
if (!isRemovedPropertyFromObjectSpread(node.kind === SyntaxKind.Identifier ? node.parent : node)) {
error(node, Diagnostics._0_is_declared_but_its_value_is_never_read, name);
diagnostics.add(createDiagnosticForNodeSpan(getSourceFileOfNode(declaration), declaration, node, Diagnostics._0_is_declared_but_its_value_is_never_read, name));
}
}
@@ -21612,7 +21669,7 @@ namespace ts {
}
function isIdentifierThatStartsWithUnderScore(node: Node) {
return node.kind === SyntaxKind.Identifier && idText(<Identifier>node).charCodeAt(0) === CharacterCodes._;
return isIdentifier(node) && idText(node).charCodeAt(0) === CharacterCodes._;
}
function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression): void {
@@ -21671,18 +21728,58 @@ namespace ts {
function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile): void {
if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) {
// Ideally we could use the ImportClause directly as a key, but must wait until we have full ES6 maps. So must store key along with value.
const unusedImports = createMap<[ImportClause, ImportedDeclaration[]]>();
node.locals.forEach(local => {
if (!local.isReferenced && !local.exportSymbol) {
for (const declaration of local.declarations) {
if (!isAmbientModule(declaration)) {
errorUnusedLocal(declaration, symbolName(local));
if (local.isReferenced || local.exportSymbol) return;
for (const declaration of local.declarations) {
if (isAmbientModule(declaration)) continue;
if (isImportedDeclaration(declaration)) {
const importClause = importClauseFromImported(declaration);
const key = String(getNodeId(importClause));
const group = unusedImports.get(key);
if (group) {
group[1].push(declaration);
}
else {
unusedImports.set(key, [importClause, [declaration]]);
}
}
else {
errorUnusedLocal(declaration, symbolName(local));
}
}
});
unusedImports.forEach(([importClause, unuseds]) => {
const importDecl = importClause.parent;
if (forEachImportedDeclaration(importClause, d => !contains(unuseds, d))) {
for (const unused of unuseds) errorUnusedLocal(unused, idText(unused.name));
}
else if (unuseds.length === 1) {
error(importDecl, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(first(unuseds).name));
}
else {
error(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused, showModuleSpecifier(importDecl));
}
});
}
}
type ImportedDeclaration = ImportClause | ImportSpecifier | NamespaceImport;
function isImportedDeclaration(node: Node): node is ImportedDeclaration {
return node.kind === SyntaxKind.ImportClause || node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.NamespaceImport;
}
function importClauseFromImported(decl: ImportedDeclaration): ImportClause {
return decl.kind === SyntaxKind.ImportClause ? decl : decl.kind === SyntaxKind.NamespaceImport ? decl.parent : decl.parent.parent;
}
function forEachImportedDeclaration<T>(importClause: ImportClause, cb: (im: ImportedDeclaration) => T | undefined): T | undefined {
const { name: defaultName, namedBindings } = importClause;
return (defaultName && cb(importClause)) ||
namedBindings && (namedBindings.kind === SyntaxKind.NamespaceImport ? cb(namedBindings) : forEach(namedBindings.elements, cb));
}
function checkBlock(node: Block) {
// Grammar checking for SyntaxKind.Block
if (node.kind === SyntaxKind.Block) {
@@ -22076,7 +22173,8 @@ namespace ts {
// Node is the primary declaration of the symbol, just validate the initializer
// Don't validate for-in initializer as it is already an error
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined);
const initializer = isInJavaScriptFile(node) && getDeclaredJavascriptInitializer(node) || node.initializer;
checkTypeAssignableTo(checkExpressionCached(initializer), type, node, /*headMessage*/ undefined);
checkParameterInitializer(node);
}
}
@@ -22657,12 +22755,12 @@ namespace ts {
// TODO: Check that target label is valid
}
function isGetAccessorWithAnnotatedSetAccessor(node: FunctionLike) {
function isGetAccessorWithAnnotatedSetAccessor(node: SignatureDeclaration) {
return node.kind === SyntaxKind.GetAccessor
&& getEffectiveSetAccessorTypeAnnotationNode(getDeclarationOfKind<SetAccessorDeclaration>(node.symbol, SyntaxKind.SetAccessor)) !== undefined;
}
function isUnwrappedReturnTypeVoidOrAny(func: FunctionLike, returnType: Type): boolean {
function isUnwrappedReturnTypeVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean {
const unwrappedReturnType = (getFunctionFlags(func) & FunctionFlags.AsyncGenerator) === FunctionFlags.Async
? getPromisedTypeOfPromise(returnType) // Async function
: returnType; // AsyncGenerator function, Generator function, or normal function
@@ -22800,8 +22898,7 @@ namespace ts {
return "quit";
}
if (current.kind === SyntaxKind.LabeledStatement && (<LabeledStatement>current).label.escapedText === node.label.escapedText) {
const sourceFile = getSourceFileOfNode(node);
grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNodeFromSourceText(sourceFile.text, node.label));
grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNode(node.label));
return true;
}
});
@@ -25384,7 +25481,7 @@ namespace ts {
return false;
}
function isImplementationOfOverload(node: FunctionLike) {
function isImplementationOfOverload(node: SignatureDeclaration) {
if (nodeIsPresent((node as FunctionLikeDeclaration).body)) {
const symbol = getSymbolOfNode(node);
const signaturesOfSymbol = getSignaturesOfSymbol(symbol);
+1 -19
View File
@@ -2029,7 +2029,7 @@ namespace ts {
export function getFileNamesFromConfigSpecs(spec: ConfigFileSpecs, basePath: string, options: CompilerOptions, host: ParseConfigHost, extraFileExtensions: ReadonlyArray<JsFileExtensionInfo> = []): ExpandResult {
basePath = normalizePath(basePath);
const keyMapper = host.useCaseSensitiveFileNames ? caseSensitiveKeyMapper : caseInsensitiveKeyMapper;
const keyMapper = host.useCaseSensitiveFileNames ? identity : toLowerCase;
// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map later when when including
@@ -2233,24 +2233,6 @@ namespace ts {
}
}
/**
* Gets a case sensitive key.
*
* @param key The original key.
*/
function caseSensitiveKeyMapper(key: string) {
return key;
}
/**
* Gets a case insensitive key.
*
* @param key The original key.
*/
function caseInsensitiveKeyMapper(key: string) {
return key.toLowerCase();
}
/**
* Produces a cleaned version of compiler options with personally identifiying info (aka, paths) removed.
* Also converts enum values back to strings.
+38 -3
View File
@@ -25,6 +25,10 @@ namespace ts {
/* @internal */
namespace ts {
export const emptyArray: never[] = [] as never[];
export function closeFileWatcher(watcher: FileWatcher) {
watcher.close();
}
/** Create a MapLike with good performance. */
function createDictionaryObject<T>(): MapLike<T> {
const map = Object.create(/*prototype*/ null); // tslint:disable-line:no-null-keyword
@@ -2539,7 +2543,6 @@ namespace ts {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);
const comparer = useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
@@ -2560,7 +2563,7 @@ namespace ts {
function visitDirectory(path: string, absolutePath: string, depth: number | undefined) {
const { files, directories } = getFileSystemEntries(path);
for (const current of sort(files, comparer)) {
for (const current of sort(files, compareStringsCaseSensitive)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (extensions && !fileExtensionIsOneOf(name, extensions)) continue;
@@ -2583,7 +2586,7 @@ namespace ts {
}
}
for (const current of sort(directories, comparer)) {
for (const current of sort(directories, compareStringsCaseSensitive)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
@@ -3143,4 +3146,36 @@ namespace ts {
export function singleElementArray<T>(t: T | undefined): T[] | undefined {
return t === undefined ? undefined : [t];
}
export function enumerateInsertsAndDeletes<T, U>(newItems: ReadonlyArray<T>, oldItems: ReadonlyArray<U>, comparer: (a: T, b: U) => Comparison, inserted: (newItem: T) => void, deleted: (oldItem: U) => void, unchanged?: (oldItem: U, newItem: T) => void) {
unchanged = unchanged || noop;
let newIndex = 0;
let oldIndex = 0;
const newLen = newItems.length;
const oldLen = oldItems.length;
while (newIndex < newLen && oldIndex < oldLen) {
const newItem = newItems[newIndex];
const oldItem = oldItems[oldIndex];
const compareResult = comparer(newItem, oldItem);
if (compareResult === Comparison.LessThan) {
inserted(newItem);
newIndex++;
}
else if (compareResult === Comparison.GreaterThan) {
deleted(oldItem);
oldIndex++;
}
else {
unchanged(oldItem, newItem);
newIndex++;
oldIndex++;
}
}
while (newIndex < newLen) {
inserted(newItems[newIndex++]);
}
while (oldIndex < oldLen) {
deleted(oldItems[oldIndex++]);
}
}
}
+8
View File
@@ -3480,6 +3480,10 @@
"category": "Message",
"code": 6191
},
"All imports in import declaration are unused.": {
"category": "Error",
"code": 6192
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
@@ -3851,6 +3855,10 @@
"category": "Message",
"code": 90004
},
"Remove import from '{0}'": {
"category": "Message",
"code": 90005
},
"Implement interface '{0}'": {
"category": "Message",
"code": 90006
-10
View File
@@ -4266,16 +4266,6 @@ namespace ts {
return node;
}
export function skipParentheses(node: Expression): Expression;
export function skipParentheses(node: Node): Node;
export function skipParentheses(node: Node): Node {
while (node.kind === SyntaxKind.ParenthesizedExpression) {
node = (<ParenthesizedExpression>node).expression;
}
return node;
}
export function skipAssertions(node: Expression): Expression;
export function skipAssertions(node: Node): Node;
export function skipAssertions(node: Node): Node {
+728 -248
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1780,7 +1780,7 @@ namespace ts {
return createArrayLiteral(expressions);
}
function getParametersOfDecoratedDeclaration(node: FunctionLike, container: ClassLikeDeclaration) {
function getParametersOfDecoratedDeclaration(node: SignatureDeclaration, container: ClassLikeDeclaration) {
if (container && node.kind === SyntaxKind.GetAccessor) {
const { setAccessor } = getAllAccessorDeclarations(container.members, <AccessorDeclaration>node);
if (setAccessor) {
+4
View File
@@ -399,4 +399,8 @@ if (ts.Debug.isDebugging) {
if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) {
ts.sys.tryEnableSourceMapsForHost();
}
declare var process: any;
if (process && process.stdout && process.stdout._handle && process.stdout._handle.setBlocking) {
process.stdout._handle.setBlocking(true);
}
ts.executeCommandLine(ts.sys.args);
+12 -27
View File
@@ -967,15 +967,8 @@ namespace ts {
| SetAccessorDeclaration
| FunctionExpression
| ArrowFunction;
export type FunctionLike =
| FunctionLikeDeclaration
| FunctionTypeNode
| ConstructorTypeNode
| IndexSignatureDeclaration
| MethodSignature
| ConstructSignatureDeclaration
| CallSignatureDeclaration
| JSDocFunctionType;
/** @deprecated Use SignatureDeclaration */
export type FunctionLike = SignatureDeclaration;
export interface FunctionDeclaration extends FunctionLikeDeclarationBase, DeclarationStatement {
kind: SyntaxKind.FunctionDeclaration;
@@ -2793,6 +2786,7 @@ namespace ts {
/** Note that the resulting nodes cannot be checked. */
typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode;
/* @internal */ typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker): TypeNode; // tslint:disable-line unified-signatures
/** Note that the resulting nodes cannot be checked. */
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration & {typeArguments?: NodeArray<TypeNode>} | undefined;
/** Note that the resulting nodes cannot be checked. */
@@ -2855,7 +2849,7 @@ namespace ts {
*/
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature;
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature | undefined;
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined;
isUndefinedSymbol(symbol: Symbol): boolean;
isArgumentsSymbol(symbol: Symbol): boolean;
isUnknownSymbol(symbol: Symbol): boolean;
@@ -3259,8 +3253,8 @@ namespace ts {
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias | JSContainer,
Namespace = ValueModule | NamespaceModule | Enum,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
@@ -3999,7 +3993,9 @@ namespace ts {
/// this.name = expr
ThisProperty,
// F.name = expr
Property
Property,
// F.prototype = { ... }
Prototype,
}
export interface JsFileExtensionInfo {
@@ -5003,12 +4999,9 @@ namespace ts {
}
/* @internal */
export interface EmitTextWriter extends SymbolTracker, SymbolWriter {
export interface EmitTextWriter extends SymbolWriter {
write(s: string): void;
writeTextOfNode(text: string, node: Node): void;
writeLine(): void;
increaseIndent(): void;
decreaseIndent(): void;
getText(): string;
rawWrite(s: string): void;
writeLiteral(s: string): void;
@@ -5017,18 +5010,10 @@ namespace ts {
getColumn(): number;
getIndent(): number;
isAtStartOfLine(): boolean;
clear(): void;
writeKeyword(text: string): void;
writeOperator(text: string): void;
writePunctuation(text: string): void;
writeSpace(text: string): void;
writeStringLiteral(text: string): void;
writeParameter(text: string): void;
writeProperty(text: string): void;
writeSymbol(text: string, symbol: Symbol): void;
}
/** @deprecated See comment on SymbolWriter */
// Note: this has non-deprecated internal uses.
export interface SymbolTracker {
// Called when the symbol writer encounters a symbol to write. Currently only used by the
// declaration emitter to help determine if it should patch up the final declaration file
+208 -87
View File
@@ -314,20 +314,15 @@ namespace ts {
}
export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node, includeTrivia = false): string {
if (nodeIsMissing(node)) {
return "";
}
const text = sourceFile.text;
return text.substring(includeTrivia ? node.pos : skipTrivia(text, node.pos), node.end);
return getTextOfNodeFromSourceText(sourceFile.text, node, includeTrivia);
}
export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string {
export function getTextOfNodeFromSourceText(sourceText: string, node: Node, includeTrivia = false): string {
if (nodeIsMissing(node)) {
return "";
}
return sourceText.substring(skipTrivia(sourceText, node.pos), node.end);
return sourceText.substring(includeTrivia ? node.pos : skipTrivia(sourceText, node.pos), node.end);
}
export function getTextOfNode(node: Node, includeTrivia = false): string {
@@ -607,6 +602,11 @@ namespace ts {
return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeSpan(sourceFile: SourceFile, startNode: Node, endNode: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic {
const start = skipTrivia(sourceFile.text, startNode.pos);
return createFileDiagnostic(sourceFile, start, endNode.end - start, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic {
const sourceFile = getSourceFileOfNode(node);
const span = getErrorSpanForNode(sourceFile, node);
@@ -1035,7 +1035,7 @@ namespace ts {
});
}
export function getContainingFunction(node: Node): FunctionLike {
export function getContainingFunction(node: Node): SignatureDeclaration {
return findAncestor(node.parent, isFunctionLike);
}
@@ -1199,7 +1199,7 @@ namespace ts {
&& (<PropertyAccessExpression | ElementAccessExpression>node).expression.kind === SyntaxKind.ThisKeyword;
}
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression {
export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression {
switch (node.kind) {
case SyntaxKind.TypeReference:
return (<TypeReferenceNode>node).typeName;
@@ -1472,13 +1472,115 @@ namespace ts {
}
/**
* Returns true if the node is a variable declaration whose initializer is a function or class expression.
* This function does not test if the node is in a JavaScript file or not.
* Given the symbol of a declaration, find the symbol of its Javascript container-like initializer,
* if it has one. Otherwise just return the original symbol.
*
* Container-like initializer behave like namespaces, so the binder needs to add contained symbols
* to their exports. An example is a function with assignments to `this` inside.
*/
export function isDeclarationOfFunctionOrClassExpression(s: Symbol) {
if (s.valueDeclaration && s.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
const declaration = s.valueDeclaration as VariableDeclaration;
return declaration.initializer && (declaration.initializer.kind === SyntaxKind.FunctionExpression || declaration.initializer.kind === SyntaxKind.ClassExpression);
export function getJSInitializerSymbol(symbol: Symbol) {
if (!symbol || !symbol.valueDeclaration) {
return symbol;
}
const declaration = symbol.valueDeclaration;
const e = getDeclaredJavascriptInitializer(declaration) || getAssignedJavascriptInitializer(declaration);
return e && e.symbol ? e.symbol : symbol;
}
/** Get the declaration initializer, when the initializer is container-like (See getJavascriptInitializer) */
export function getDeclaredJavascriptInitializer(node: Node) {
if (node && isVariableDeclaration(node) && node.initializer) {
return getJavascriptInitializer(node.initializer, /*isPrototypeAssignment*/ false) ||
isIdentifier(node.name) && getDefaultedJavascriptInitializer(node.name, node.initializer, /*isPrototypeAssignment*/ false);
}
}
/**
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getJavascriptInitializer).
* We treat the right hand side of assignments with container-like initalizers as declarations.
*/
export function getAssignedJavascriptInitializer(node: Node) {
if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
const isPrototypeAssignment = isPropertyAccessExpression(node.parent.left) && node.parent.left.name.escapedText === "prototype";
return getJavascriptInitializer(node.parent.right, isPrototypeAssignment) ||
getDefaultedJavascriptInitializer(node.parent.left as EntityNameExpression, node.parent.right, isPrototypeAssignment);
}
}
/**
* Recognized Javascript container-like initializers are:
* 1. (function() {})() -- IIFEs
* 2. function() { } -- Function expressions
* 3. class { } -- Class expressions
* 4. {} -- Empty object literals
* 5. { ... } -- Non-empty object literals, when used to initialize a prototype, like `C.prototype = { m() { } }`
*
* This function returns the provided initializer, or undefined if it is not valid.
*/
export function getJavascriptInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression {
if (isCallExpression(initializer)) {
const e = skipParentheses(initializer.expression);
return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined;
}
if (initializer.kind === SyntaxKind.FunctionExpression || initializer.kind === SyntaxKind.ClassExpression) {
return initializer as Expression;
}
if (isObjectLiteralExpression(initializer) && (initializer.properties.length === 0 || isPrototypeAssignment)) {
return initializer;
}
}
/**
* A defaulted Javascript initializer matches the pattern
* `Lhs = Lhs || JavascriptInitializer`
* or `var Lhs = Lhs || JavascriptInitializer`
*
* The second Lhs is required to be the same as the first except that it may be prefixed with
* 'window.', 'global.' or 'self.' The second Lhs is otherwise ignored by the binder and checker.
*/
function getDefaultedJavascriptInitializer(name: EntityNameExpression, initializer: Expression, isPrototypeAssignment: boolean) {
const e = isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.BarBarToken && getJavascriptInitializer(initializer.right, isPrototypeAssignment);
if (e && isSameEntityName(name, (initializer as BinaryExpression).left as EntityNameExpression)) {
return e;
}
}
/** Given a Javascript initializer, return the outer name. That is, the lhs of the assignment or the declaration name. */
export function getOuterNameOfJsInitializer(node: Declaration): DeclarationName | undefined {
if (isBinaryExpression(node.parent)) {
const parent = (node.parent.operatorToken.kind === SyntaxKind.BarBarToken && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent;
if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) {
return parent.left;
}
}
else if (isVariableDeclaration(node.parent)) {
return node.parent.name;
}
}
/**
* Is the 'declared' name the same as the one in the initializer?
* @return true for identical entity names, as well as ones where the initializer is prefixed with
* 'window', 'self' or 'global'. For example:
*
* var my = my || {}
* var min = window.min || {}
* my.app = self.my.app || class { }
*/
function isSameEntityName(name: EntityNameExpression, initializer: EntityNameExpression): boolean {
if (isIdentifier(name) && isIdentifier(initializer)) {
return name.escapedText === initializer.escapedText;
}
if (isIdentifier(name) && isPropertyAccessExpression(initializer)) {
return (initializer.expression.kind as SyntaxKind.ThisKeyword === SyntaxKind.ThisKeyword ||
isIdentifier(initializer.expression) &&
(initializer.expression.escapedText === "window" as __String ||
initializer.expression.escapedText === "self" as __String ||
initializer.expression.escapedText === "global" as __String)) &&
isSameEntityName(name, initializer.name);
}
if (isPropertyAccessExpression(name) && isPropertyAccessExpression(initializer)) {
return name.name.escapedText === initializer.name.escapedText && isSameEntityName(name.expression, initializer.expression);
}
return false;
}
@@ -1501,46 +1603,43 @@ namespace ts {
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
/// assignments we treat as special in the binder
export function getSpecialPropertyAssignmentKind(expr: BinaryExpression): SpecialPropertyAssignmentKind {
if (!isInJavaScriptFile(expr)) {
if (!isInJavaScriptFile(expr) ||
expr.operatorToken.kind !== SyntaxKind.EqualsToken ||
!isPropertyAccessExpression(expr.left)) {
return SpecialPropertyAssignmentKind.None;
}
if (expr.operatorToken.kind !== SyntaxKind.EqualsToken || expr.left.kind !== SyntaxKind.PropertyAccessExpression) {
return SpecialPropertyAssignmentKind.None;
}
const lhs = <PropertyAccessExpression>expr.left;
if (lhs.expression.kind === SyntaxKind.Identifier) {
const lhsId = <Identifier>lhs.expression;
if (lhsId.escapedText === "exports") {
// exports.name = expr
return SpecialPropertyAssignmentKind.ExportsProperty;
}
else if (lhsId.escapedText === "module" && lhs.name.escapedText === "exports") {
// module.exports = expr
return SpecialPropertyAssignmentKind.ModuleExports;
}
else {
// F.x = expr
return SpecialPropertyAssignmentKind.Property;
}
}
else if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
const lhs = expr.left;
if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
return SpecialPropertyAssignmentKind.ThisProperty;
}
else if (lhs.expression.kind === SyntaxKind.PropertyAccessExpression) {
// chained dot, e.g. x.y.z = expr; this var is the 'x.y' part
const innerPropertyAccess = <PropertyAccessExpression>lhs.expression;
if (innerPropertyAccess.expression.kind === SyntaxKind.Identifier) {
// module.exports.name = expr
const innerPropertyAccessIdentifier = <Identifier>innerPropertyAccess.expression;
if (innerPropertyAccessIdentifier.escapedText === "module" && innerPropertyAccess.name.escapedText === "exports") {
return SpecialPropertyAssignmentKind.ExportsProperty;
}
if (innerPropertyAccess.name.escapedText === "prototype") {
return SpecialPropertyAssignmentKind.PrototypeProperty;
}
}
else if (isIdentifier(lhs.expression) && lhs.expression.escapedText === "module" && lhs.name.escapedText === "exports") {
// module.exports = expr
return SpecialPropertyAssignmentKind.ModuleExports;
}
else if (isEntityNameExpression(lhs.expression)) {
if (lhs.name.escapedText === "prototype" && isObjectLiteralExpression(expr.right)) {
// F.prototype = { ... }
return SpecialPropertyAssignmentKind.Prototype;
}
else if (isPropertyAccessExpression(lhs.expression) && lhs.expression.name.escapedText === "prototype") {
// F.G....prototype.x = expr
return SpecialPropertyAssignmentKind.PrototypeProperty;
}
let nextToLast = lhs;
while (isPropertyAccessExpression(nextToLast.expression)) {
nextToLast = nextToLast.expression;
}
Debug.assert(isIdentifier(nextToLast.expression));
const id = nextToLast.expression as Identifier;
if (id.escapedText === "exports" ||
id.escapedText === "module" && nextToLast.name.escapedText === "exports") {
// exports.name = expr OR module.exports.name = expr
return SpecialPropertyAssignmentKind.ExportsProperty;
}
// F.G...x = expr
return SpecialPropertyAssignmentKind.Property;
}
return SpecialPropertyAssignmentKind.None;
}
@@ -1617,6 +1716,15 @@ namespace ts {
node.expression.right;
}
function getSourceOfDefaultedAssignment(node: Node): Node {
return isExpressionStatement(node) &&
isBinaryExpression(node.expression) &&
getSpecialPropertyAssignmentKind(node.expression) !== SpecialPropertyAssignmentKind.None &&
isBinaryExpression(node.expression.right) &&
node.expression.right.operatorToken.kind === SyntaxKind.BarBarToken &&
node.expression.right.right;
}
function getSingleInitializerOfVariableStatementOrPropertyDeclaration(node: Node): Expression | undefined {
switch (node.kind) {
case SyntaxKind.VariableStatement:
@@ -1660,7 +1768,8 @@ namespace ts {
(getSingleVariableOfVariableStatement(parent.parent) === node || getSourceOfAssignment(parent.parent))) {
getJSDocCommentsAndTagsWorker(parent.parent);
}
if (parent && parent.parent && parent.parent.parent && getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node) {
if (parent && parent.parent && parent.parent.parent &&
(getSingleInitializerOfVariableStatementOrPropertyDeclaration(parent.parent.parent) === node || getSourceOfDefaultedAssignment(parent.parent.parent))) {
getJSDocCommentsAndTagsWorker(parent.parent.parent);
}
if (isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) !== SpecialPropertyAssignmentKind.None ||
@@ -1700,9 +1809,10 @@ namespace ts {
return parameter && parameter.symbol;
}
export function getHostSignatureFromJSDoc(node: JSDocParameterTag): FunctionLike | undefined {
export function getHostSignatureFromJSDoc(node: JSDocParameterTag): SignatureDeclaration | undefined {
const host = getJSDocHost(node);
const decl = getSourceOfAssignment(host) ||
const decl = getSourceOfDefaultedAssignment(host) ||
getSourceOfAssignment(host) ||
getSingleInitializerOfVariableStatementOrPropertyDeclaration(host) ||
getSingleVariableOfVariableStatement(host) ||
getNestedModuleDeclaration(host) ||
@@ -1843,6 +1953,16 @@ namespace ts {
return walkUp(node, SyntaxKind.ParenthesizedExpression);
}
export function skipParentheses(node: Expression): Expression;
export function skipParentheses(node: Node): Node;
export function skipParentheses(node: Node): Node {
while (node.kind === SyntaxKind.ParenthesizedExpression) {
node = (<ParenthesizedExpression>node).expression;
}
return node;
}
// a node is delete target iff. it is PropertyAccessExpression/ElementAccessExpression with parentheses skipped
export function isDeleteTarget(node: Node): boolean {
if (node.kind !== SyntaxKind.PropertyAccessExpression && node.kind !== SyntaxKind.ElementAccessExpression) {
@@ -2024,7 +2144,7 @@ namespace ts {
AsyncGenerator = Async | Generator, // Function is an async generator function
}
export function getFunctionFlags(node: FunctionLike | undefined) {
export function getFunctionFlags(node: SignatureDeclaration | undefined) {
if (!node) {
return FunctionFlags.Invalid;
}
@@ -2466,7 +2586,6 @@ namespace ts {
const singleQuoteEscapedCharsRegExp = /[\\\'\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
const backtickQuoteEscapedCharsRegExp = /[\\\`\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
const escapedCharsMap = createMapFromTemplate({
"\0": "\\0",
"\t": "\\t",
"\v": "\\v",
"\f": "\\f",
@@ -2481,7 +2600,6 @@ namespace ts {
"\u2029": "\\u2029", // paragraphSeparator
"\u0085": "\\u0085" // nextLine
});
const escapedNullRegExp = /\\0[0-9]/g;
/**
* Based heavily on the abstract 'Quote'/'QuoteJSONString' operation from ECMA-262 (24.3.2.2),
@@ -2493,14 +2611,19 @@ namespace ts {
quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp :
quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp :
doubleQuoteEscapedCharsRegExp;
return s.replace(escapedCharsRegExp, getReplacement).replace(escapedNullRegExp, nullReplacement);
return s.replace(escapedCharsRegExp, getReplacement);
}
function nullReplacement(c: string) {
return "\\x00" + c.charAt(c.length - 1);
}
function getReplacement(c: string) {
function getReplacement(c: string, offset: number, input: string) {
if (c.charCodeAt(0) === CharacterCodes.nullCharacter) {
const lookAhead = input.charCodeAt(offset + c.length);
if (lookAhead >= CharacterCodes._0 && lookAhead <= CharacterCodes._9) {
// If the null character is followed by digits, print as a hex escape to prevent the result from parsing as an octal (which is forbidden in strict mode)
return "\\x00";
}
// Otherwise, keep printing a literal \0 for the null character
return "\\0";
}
return escapedCharsMap.get(c) || get16BitUnicodeEscapeSequence(c.charCodeAt(0));
}
@@ -2834,49 +2957,38 @@ namespace ts {
* Gets the effective type annotation of a variable, parameter, or property. If the node was
* parsed in a JavaScript file, gets the type annotation from JSDoc.
*/
export function getEffectiveTypeAnnotationNode(node: Node, checkJSDoc?: boolean): TypeNode | undefined {
if (hasType(node)) {
return node.type;
}
if (checkJSDoc || isInJavaScriptFile(node)) {
return getJSDocType(node);
}
export function getEffectiveTypeAnnotationNode(node: Node): TypeNode | undefined {
return (node as HasType).type || (isInJavaScriptFile(node) ? getJSDocType(node) : undefined);
}
/**
* Gets the effective return type annotation of a signature. If the node was parsed in a
* JavaScript file, gets the return type annotation from JSDoc.
*/
export function getEffectiveReturnTypeNode(node: SignatureDeclaration, checkJSDoc?: boolean): TypeNode | undefined {
if (node.type) {
return node.type;
}
if (checkJSDoc || isInJavaScriptFile(node)) {
return getJSDocReturnType(node);
}
export function getEffectiveReturnTypeNode(node: SignatureDeclaration): TypeNode | undefined {
return node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined);
}
/**
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters, checkJSDoc?: boolean): ReadonlyArray<TypeParameterDeclaration> {
if (node.typeParameters) {
return node.typeParameters;
}
if (checkJSDoc || isInJavaScriptFile(node)) {
const templateTag = getJSDocTemplateTag(node);
return templateTag && templateTag.typeParameters;
}
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> | undefined {
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined);
}
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
const templateTag = getJSDocTemplateTag(node);
return templateTag && templateTag.typeParameters;
}
/**
* Gets the effective type annotation of the value parameter of a set accessor. If the node
* was parsed in a JavaScript file, gets the type annotation from JSDoc.
*/
export function getEffectiveSetAccessorTypeAnnotationNode(node: SetAccessorDeclaration, checkJSDoc?: boolean): TypeNode {
export function getEffectiveSetAccessorTypeAnnotationNode(node: SetAccessorDeclaration): TypeNode {
const parameter = getSetAccessorValueParameter(node);
return parameter && getEffectiveTypeAnnotationNode(parameter, checkJSDoc);
return parameter && getEffectiveTypeAnnotationNode(parameter);
}
export function emitNewLineBeforeLeadingComments(lineMap: ReadonlyArray<number>, writer: EmitTextWriter, node: TextRange, leadingComments: ReadonlyArray<CommentRange>) {
@@ -3723,6 +3835,10 @@ namespace ts {
export function isUMDExportSymbol(symbol: Symbol) {
return symbol && symbol.declarations && symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]);
}
export function showModuleSpecifier({ moduleSpecifier }: ImportDeclaration): string {
return isStringLiteral(moduleSpecifier) ? moduleSpecifier.text : getTextOfNode(moduleSpecifier);
}
}
namespace ts {
@@ -4238,6 +4354,11 @@ namespace ts {
return declaration.name || nameForNamelessJSDocTypedef(declaration);
}
/** @internal */
export function isNamedDeclaration(node: Node): node is NamedDeclaration & { name: DeclarationName } {
return !!(node as NamedDeclaration).name; // A 'name' property should always be a DeclarationName.
}
export function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined {
if (!declaration) {
return undefined;
@@ -5188,7 +5309,7 @@ namespace ts {
// Functions
export function isFunctionLike(node: Node): node is FunctionLike {
export function isFunctionLike(node: Node): node is SignatureDeclaration {
return node && isFunctionLikeKind(node.kind);
}
+11 -12
View File
@@ -483,18 +483,17 @@ namespace ts {
}
const trace = host.trace && ((s: string) => { host.trace(s + newLine); });
const loggingEnabled = trace && (compilerOptions.diagnostics || compilerOptions.extendedDiagnostics);
const writeLog = loggingEnabled ? trace : noop;
const watchFile = compilerOptions.extendedDiagnostics ? addFileWatcherWithLogging : loggingEnabled ? addFileWatcherWithOnlyTriggerLogging : addFileWatcher;
const watchFilePath = compilerOptions.extendedDiagnostics ? addFilePathWatcherWithLogging : addFilePathWatcher;
const watchDirectoryWorker = compilerOptions.extendedDiagnostics ? addDirectoryWatcherWithLogging : addDirectoryWatcher;
const watchLogLevel = trace ? compilerOptions.extendedDiagnostics ? WatchLogLevel.Verbose :
compilerOptions.diagnostis ? WatchLogLevel.TriggerOnly : WatchLogLevel.None : WatchLogLevel.None;
const writeLog: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? trace : noop;
const { watchFile, watchFilePath, watchDirectory: watchDirectoryWorker } = getWatchFactory(watchLogLevel, writeLog);
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
let newLine = updateNewLine();
writeLog(`Current directory: ${currentDirectory} CaseSensitiveFileNames: ${useCaseSensitiveFileNames}`);
if (configFileName) {
watchFile(host, configFileName, scheduleProgramReload, writeLog);
watchFile(host, configFileName, scheduleProgramReload, PollingInterval.High);
}
const compilerHost: CompilerHost & ResolutionCacheHost = {
@@ -583,8 +582,8 @@ namespace ts {
}
// Compile the program
if (loggingEnabled) {
writeLog(`CreatingProgramWith::`);
if (watchLogLevel !== WatchLogLevel.None) {
writeLog("CreatingProgramWith::");
writeLog(` roots: ${JSON.stringify(rootFileNames)}`);
writeLog(` options: ${JSON.stringify(compilerOptions)}`);
}
@@ -677,7 +676,7 @@ namespace ts {
(hostSourceFile as FilePresentOnHost).sourceFile = sourceFile;
sourceFile.version = hostSourceFile.version.toString();
if (!(hostSourceFile as FilePresentOnHost).fileWatcher) {
(hostSourceFile as FilePresentOnHost).fileWatcher = watchFilePath(host, fileName, onSourceFileChange, path, writeLog);
(hostSourceFile as FilePresentOnHost).fileWatcher = watchFilePath(host, fileName, onSourceFileChange, PollingInterval.Low, path);
}
}
else {
@@ -691,7 +690,7 @@ namespace ts {
else {
if (sourceFile) {
sourceFile.version = initialVersion.toString();
const fileWatcher = watchFilePath(host, fileName, onSourceFileChange, path, writeLog);
const fileWatcher = watchFilePath(host, fileName, onSourceFileChange, PollingInterval.Low, path);
sourceFilesCache.set(path, { sourceFile, version: initialVersion, fileWatcher });
}
else {
@@ -854,11 +853,11 @@ namespace ts {
}
function watchDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) {
return watchDirectoryWorker(host, directory, cb, flags, writeLog);
return watchDirectoryWorker(host, directory, cb, flags);
}
function watchMissingFilePath(missingFilePath: Path) {
return watchFilePath(host, missingFilePath, onMissingFileChange, missingFilePath, writeLog);
return watchFilePath(host, missingFilePath, onMissingFileChange, PollingInterval.Medium, missingFilePath);
}
function onMissingFileChange(fileName: string, eventKind: FileWatcherEventKind, missingFilePath: Path) {
+75 -59
View File
@@ -331,85 +331,101 @@ namespace ts {
return program.isEmittedFile(file);
}
export enum WatchLogLevel {
None,
TriggerOnly,
Verbose
}
export interface WatchFileHost {
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
}
export function addFileWatcher(host: WatchFileHost, file: string, cb: FileWatcherCallback): FileWatcher {
return host.watchFile(file, cb);
}
export function addFileWatcherWithLogging(host: WatchFileHost, file: string, cb: FileWatcherCallback, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ false, host, file, cb);
}
export function addFileWatcherWithOnlyTriggerLogging(host: WatchFileHost, file: string, cb: FileWatcherCallback, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ true, host, file, cb);
}
export type FilePathWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void;
export function addFilePathWatcher(host: WatchFileHost, file: string, cb: FilePathWatcherCallback, path: Path): FileWatcher {
return host.watchFile(file, (fileName, eventKind) => cb(fileName, eventKind, path));
}
export function addFilePathWatcherWithLogging(host: WatchFileHost, file: string, cb: FilePathWatcherCallback, path: Path, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ false, host, file, cb, path);
}
export function addFilePathWatcherWithOnlyTriggerLogging(host: WatchFileHost, file: string, cb: FilePathWatcherCallback, path: Path, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ true, host, file, cb, path);
}
export interface WatchDirectoryHost {
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
}
export type WatchFile<X, Y> = (host: WatchFileHost, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
export type FilePathWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void;
export type WatchFilePath<X, Y> = (host: WatchFileHost, file: string, callback: FilePathWatcherCallback, pollingInterval: PollingInterval, path: Path, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
export type WatchDirectory<X, Y> = (host: WatchDirectoryHost, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags, detailInfo1?: X, detailInfo2?: Y) => FileWatcher;
export function addDirectoryWatcher(host: WatchDirectoryHost, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher {
const recursive = (flags & WatchDirectoryFlags.Recursive) !== 0;
return host.watchDirectory(directory, cb, recursive);
export interface WatchFactory<X, Y> {
watchFile: WatchFile<X, Y>;
watchFilePath: WatchFilePath<X, Y>;
watchDirectory: WatchDirectory<X, Y>;
}
export function addDirectoryWatcherWithLogging(host: WatchDirectoryHost, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, log: (s: string) => void): FileWatcher {
const watcherCaption = `DirectoryWatcher ${(flags & WatchDirectoryFlags.Recursive) !== 0 ? "recursive" : ""}:: `;
return createWatcherWithLogging(addDirectoryWatcher, watcherCaption, log, /*logOnlyTrigger*/ false, host, directory, cb, flags);
export function getWatchFactory<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo?: GetDetailWatchInfo<X, Y>): WatchFactory<X, Y> {
return getWatchFactoryWith(watchLogLevel, log, getDetailWatchInfo, watchFile, watchDirectory);
}
export function addDirectoryWatcherWithOnlyTriggerLogging(host: WatchDirectoryHost, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, log: (s: string) => void): FileWatcher {
const watcherCaption = `DirectoryWatcher ${(flags & WatchDirectoryFlags.Recursive) !== 0 ? "recursive" : ""}:: `;
return createWatcherWithLogging(addDirectoryWatcher, watcherCaption, log, /*logOnlyTrigger*/ true, host, directory, cb, flags);
}
function getWatchFactoryWith<X = undefined, Y = undefined>(watchLogLevel: WatchLogLevel, log: (s: string) => void, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined,
watchFile: (host: WatchFileHost, file: string, callback: FileWatcherCallback, watchPriority: PollingInterval) => FileWatcher,
watchDirectory: (host: WatchDirectoryHost, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags) => FileWatcher): WatchFactory<X, Y> {
const createFileWatcher: CreateFileWatcher<WatchFileHost, PollingInterval, FileWatcherEventKind, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchFile);
const createFilePathWatcher: CreateFileWatcher<WatchFileHost, PollingInterval, FileWatcherEventKind, Path, X, Y> = watchLogLevel === WatchLogLevel.None ? watchFilePath : createFileWatcher;
const createDirectoryWatcher: CreateFileWatcher<WatchDirectoryHost, WatchDirectoryFlags, undefined, undefined, X, Y> = getCreateFileWatcher(watchLogLevel, watchDirectory);
return {
watchFile: (host, file, callback, pollingInterval, detailInfo1, detailInfo2) =>
createFileWatcher(host, file, callback, pollingInterval, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo),
watchFilePath: (host, file, callback, pollingInterval, path, detailInfo1, detailInfo2) =>
createFilePathWatcher(host, file, callback, pollingInterval, path, detailInfo1, detailInfo2, watchFile, log, "FileWatcher", getDetailWatchInfo),
watchDirectory: (host, directory, callback, flags, detailInfo1, detailInfo2) =>
createDirectoryWatcher(host, directory, callback, flags, /*passThrough*/ undefined, detailInfo1, detailInfo2, watchDirectory, log, "DirectoryWatcher", getDetailWatchInfo)
};
type WatchCallback<T, U> = (fileName: string, cbOptional1?: T, optional?: U) => void;
type AddWatch<H, T, U> = (host: H, file: string, cb: WatchCallback<T, U>, optional?: U) => FileWatcher;
function createWatcherWithLogging<H, T, U>(addWatch: AddWatch<H, T, U>, watcherCaption: string, log: (s: string) => void, logOnlyTrigger: boolean, host: H, file: string, cb: WatchCallback<T, U>, optional?: U): FileWatcher {
const info = `PathInfo: ${file}`;
if (!logOnlyTrigger) {
log(`${watcherCaption}Added: ${info}`);
function watchFilePath(host: WatchFileHost, file: string, callback: FilePathWatcherCallback, pollingInterval: PollingInterval, path: Path): FileWatcher {
return watchFile(host, file, (fileName, eventKind) => callback(fileName, eventKind, path), pollingInterval);
}
const watcher = addWatch(host, file, (fileName, cbOptional1?) => {
const optionalInfo = cbOptional1 !== undefined ? ` ${cbOptional1}` : "";
log(`${watcherCaption}Trigger: ${fileName}${optionalInfo} ${info}`);
const start = timestamp();
cb(fileName, cbOptional1, optional);
const elapsed = timestamp() - start;
log(`${watcherCaption}Elapsed: ${elapsed}ms Trigger: ${fileName}${optionalInfo} ${info}`);
}, optional);
}
function watchFile(host: WatchFileHost, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval): FileWatcher {
return host.watchFile(file, callback, pollingInterval);
}
function watchDirectory(host: WatchDirectoryHost, directory: string, callback: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher {
return host.watchDirectory(directory, callback, (flags & WatchDirectoryFlags.Recursive) !== 0);
}
type WatchCallback<T, U> = (fileName: string, cbOptional?: T, passThrough?: U) => void;
type AddWatch<H, T, U, V> = (host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough?: V, detailInfo1?: undefined, detailInfo2?: undefined) => FileWatcher;
export type GetDetailWatchInfo<X, Y> = (detailInfo1: X, detailInfo2: Y) => string;
type CreateFileWatcher<H, T, U, V, X, Y> = (host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<H, T, U, V>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined) => FileWatcher;
function getCreateFileWatcher<H, T, U, V, X, Y>(watchLogLevel: WatchLogLevel, addWatch: AddWatch<H, T, U, V>): CreateFileWatcher<H, T, U, V, X, Y> {
switch (watchLogLevel) {
case WatchLogLevel.None:
return addWatch;
case WatchLogLevel.TriggerOnly:
return createFileWatcherWithTriggerLogging;
case WatchLogLevel.Verbose:
return createFileWatcherWithLogging;
}
}
function createFileWatcherWithLogging<H, T, U, V, X, Y>(host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<H, T, U, undefined>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined): FileWatcher {
log(`${watchCaption}:: Added:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`);
const watcher = createFileWatcherWithTriggerLogging(host, file, cb, flags, passThrough, detailInfo1, detailInfo2, addWatch, log, watchCaption, getDetailWatchInfo);
return {
close: () => {
if (!logOnlyTrigger) {
log(`${watcherCaption}Close: ${info}`);
}
log(`${watchCaption}:: Close:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`);
watcher.close();
}
};
}
export function closeFileWatcher(watcher: FileWatcher) {
watcher.close();
function createFileWatcherWithTriggerLogging<H, T, U, V, X, Y>(host: H, file: string, cb: WatchCallback<U, V>, flags: T, passThrough: V | undefined, detailInfo1: X | undefined, detailInfo2: Y | undefined, addWatch: AddWatch<H, T, U, undefined>, log: (s: string) => void, watchCaption: string, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined): FileWatcher {
return addWatch(host, file, (fileName, cbOptional) => {
const triggerredInfo = `${watchCaption}:: Triggered with ${fileName}${cbOptional !== undefined ? cbOptional : ""}:: ${getWatchInfo(file, flags, detailInfo1, detailInfo2, getDetailWatchInfo)}`;
log(triggerredInfo);
const start = timestamp();
cb(fileName, cbOptional, passThrough);
const elapsed = timestamp() - start;
log(`Elapsed:: ${elapsed}ms ${triggerredInfo}`);
}, flags);
}
function getWatchInfo<T, X, Y>(file: string, flags: T, detailInfo1: X | undefined, detailInfo2: Y | undefined, getDetailWatchInfo: GetDetailWatchInfo<X, Y> | undefined) {
return `WatchInfo: ${file} ${flags} ${getDetailWatchInfo ? getDetailWatchInfo(detailInfo1, detailInfo2) : ""}`;
}
export function closeFileWatcherOf<T extends { watcher: FileWatcher; }>(objWithWatcher: T) {
+5 -1
View File
@@ -848,7 +848,7 @@ namespace FourSlash {
const actual = actualCompletions.entries;
if (actual.length !== expected.length) {
this.raiseError(`Expected ${expected.length} completions, got ${actual.map(a => a.name)}.`);
this.raiseError(`Expected ${expected.length} completions, got ${actual.length} (${actual.map(a => a.name)}).`);
}
ts.zipWith(actual, expected, (completion, expectedCompletion, index) => {
@@ -2923,6 +2923,10 @@ Actual: ${stringify(fullActual)}`);
if (!codeFixes.length) {
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes but none found.`);
}
codeFixes.forEach(fix => fix.changes.forEach(change => {
assert.isObject(change, `Invalid change in code fix: ${JSON.stringify(fix)}`);
change.textChanges.forEach(textChange => assert.isObject(textChange, `Invalid textChange in codeFix: ${JSON.stringify(fix)}`));
}));
if (info) {
assert.equal(info.length, codeFixes.length);
ts.zipWith(codeFixes, info, (fix, info) => {
+1 -2
View File
@@ -72,8 +72,7 @@ class TypeWriterWalker {
private writeTypeOrSymbol(node: ts.Node, isSymbolWalk: boolean): TypeWriterResult {
const actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos);
const lineAndCharacter = this.currentSourceFile.getLineAndCharacterOfPosition(actualPos);
const sourceText = ts.getTextOfNodeFromSourceText(this.currentSourceFile.text, node);
const sourceText = ts.getSourceTextOfNodeFromSourceFile(this.currentSourceFile, node);
if (!isSymbolWalk) {
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
+32
View File
@@ -91,6 +91,18 @@ namespace ts {
"c:/dev/g.min.js/.g/g.ts"
]);
const caseInsensitiveOrderingDiffersWithCaseHost = new Utils.MockParseConfigHost(caseInsensitiveBasePath, /*useCaseSensitiveFileNames*/ false, [
"c:/dev/xylophone.ts",
"c:/dev/Yosemite.ts",
"c:/dev/zebra.ts",
]);
const caseSensitiveOrderingDiffersWithCaseHost = new Utils.MockParseConfigHost(caseSensitiveBasePath, /*useCaseSensitiveFileNames*/ true, [
"/dev/xylophone.ts",
"/dev/Yosemite.ts",
"/dev/zebra.ts",
]);
function assertParsed(actual: ParsedCommandLine, expected: ParsedCommandLine): void {
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
@@ -1482,5 +1494,25 @@ namespace ts {
validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath);
});
});
it("can include files in the same order on multiple platforms", () => {
function getExpected(basePath: string): ParsedCommandLine {
return {
options: {},
errors: [],
fileNames: [
`${basePath}Yosemite.ts`, // capital always comes before lowercase letters
`${basePath}xylophone.ts`,
`${basePath}zebra.ts`
],
wildcardDirectories: {
[basePath.slice(0, basePath.length - 1)]: WatchDirectoryFlags.Recursive
},
};
}
const json = {};
validateMatches(getExpected(caseSensitiveBasePath), json, caseSensitiveOrderingDiffersWithCaseHost, caseSensitiveBasePath);
validateMatches(getExpected(caseInsensitiveBasePath), json, caseInsensitiveOrderingDiffersWithCaseHost, caseInsensitiveBasePath);
});
});
}
+225 -99
View File
@@ -3,11 +3,10 @@
/// <reference path="..\virtualFileSystemWithWatch.ts" />
namespace ts.tscWatch {
import WatchedSystem = TestFSWithWatch.TestServerHost;
type FileOrFolder = TestFSWithWatch.FileOrFolder;
import createWatchedSystem = TestFSWithWatch.createWatchedSystem;
import checkFileNames = TestFSWithWatch.checkFileNames;
import checkArray = TestFSWithWatch.checkArray;
import libFile = TestFSWithWatch.libFile;
import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
@@ -15,11 +14,11 @@ namespace ts.tscWatch {
import checkOutputDoesNotContain = TestFSWithWatch.checkOutputDoesNotContain;
export function checkProgramActualFiles(program: Program, expectedFiles: string[]) {
checkFileNames(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);
checkArray(`Program actual files`, program.getSourceFiles().map(file => file.fileName), expectedFiles);
}
export function checkProgramRootFiles(program: Program, expectedFiles: string[]) {
checkFileNames(`Program rootFileNames`, program.getRootFileNames(), expectedFiles);
checkArray(`Program rootFileNames`, program.getRootFileNames(), expectedFiles);
}
function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
@@ -73,64 +72,60 @@ namespace ts.tscWatch {
checkOutputDoesNotContain(host, expectedNonAffectedFiles);
}
enum ExpectedOutputErrorsPosition {
BeforeCompilationStarts,
AfterCompilationStarting,
AfterFileChangeDetected
}
function checkOutputErrors(
host: WatchedSystem,
preErrorsWatchDiagnostic: DiagnosticMessage | undefined,
errors: ReadonlyArray<Diagnostic>,
errorsPosition: ExpectedOutputErrorsPosition,
skipWaiting?: true
...postErrorsWatchDiagnostics: DiagnosticMessage[]
) {
const outputs = host.getOutput();
const expectedOutputCount = errors.length + (skipWaiting ? 0 : 1) + 1;
assert.equal(outputs.length, expectedOutputCount, "Outputs = " + outputs.toString());
let index: number;
switch (errorsPosition) {
case ExpectedOutputErrorsPosition.AfterCompilationStarting:
assertWatchDiagnosticAt(host, 0, Diagnostics.Starting_compilation_in_watch_mode);
index = 1;
break;
case ExpectedOutputErrorsPosition.AfterFileChangeDetected:
assertWatchDiagnosticAt(host, 0, Diagnostics.File_change_detected_Starting_incremental_compilation);
index = 1;
break;
case ExpectedOutputErrorsPosition.BeforeCompilationStarts:
assertWatchDiagnosticAt(host, errors.length, Diagnostics.Starting_compilation_in_watch_mode);
index = 0;
break;
}
forEach(errors, error => {
assertDiagnosticAt(host, index, error);
index++;
});
if (!skipWaiting) {
if (errorsPosition === ExpectedOutputErrorsPosition.BeforeCompilationStarts) {
assertWatchDiagnosticAt(host, index, Diagnostics.Starting_compilation_in_watch_mode);
index += 1;
}
assertWatchDiagnosticAt(host, index, Diagnostics.Compilation_complete_Watching_for_file_changes);
const expectedOutputCount = (preErrorsWatchDiagnostic ? 1 : 0) + errors.length + postErrorsWatchDiagnostics.length;
assert.equal(outputs.length, expectedOutputCount);
let index = 0;
if (preErrorsWatchDiagnostic) {
assertWatchDiagnostic(preErrorsWatchDiagnostic);
}
// Verify errors
forEach(errors, assertDiagnostic);
forEach(postErrorsWatchDiagnostics, assertWatchDiagnostic);
host.clearOutput();
function assertDiagnostic(diagnostic: Diagnostic) {
const expected = formatDiagnostic(diagnostic, host);
assert.equal(outputs[index], expected, getOutputAtFailedMessage("Diagnostic", expected));
index++;
}
function assertWatchDiagnostic(diagnosticMessage: DiagnosticMessage) {
const expected = getWatchDiagnosticWithoutDate(diagnosticMessage);
assert.isTrue(endsWith(outputs[index], expected), getOutputAtFailedMessage("Watch diagnostic", expected));
index++;
}
function getOutputAtFailedMessage(caption: string, expectedOutput: string) {
return `Expected ${caption}: ${expectedOutput} at ${index} in ${JSON.stringify(outputs)}`;
}
function getWatchDiagnosticWithoutDate(diagnosticMessage: DiagnosticMessage) {
return ` - ${flattenDiagnosticMessageText(getLocaleSpecificMessage(diagnosticMessage), host.newLine)}${host.newLine + host.newLine + host.newLine}`;
}
}
function assertDiagnosticAt(host: WatchedSystem, outputAt: number, diagnostic: Diagnostic) {
const output = host.getOutput()[outputAt];
assert.equal(output, formatDiagnostic(diagnostic, host), "outputs[" + outputAt + "] is " + output);
function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>) {
checkOutputErrors(host, Diagnostics.Starting_compilation_in_watch_mode, errors, Diagnostics.Compilation_complete_Watching_for_file_changes);
}
function assertWatchDiagnosticAt(host: WatchedSystem, outputAt: number, diagnosticMessage: DiagnosticMessage) {
const output = host.getOutput()[outputAt];
assert.isTrue(endsWith(output, getWatchDiagnosticWithoutDate(host, diagnosticMessage)), "outputs[" + outputAt + "] is " + output);
function checkOutputErrorsInitialWithConfigErrors(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>) {
checkOutputErrors(host, /*preErrorsWatchDiagnostic*/ undefined, errors, Diagnostics.Starting_compilation_in_watch_mode, Diagnostics.Compilation_complete_Watching_for_file_changes);
}
function getWatchDiagnosticWithoutDate(host: WatchedSystem, diagnosticMessage: DiagnosticMessage) {
return ` - ${flattenDiagnosticMessageText(getLocaleSpecificMessage(diagnosticMessage), host.newLine)}${host.newLine + host.newLine + host.newLine}`;
function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>) {
checkOutputErrors(host, Diagnostics.File_change_detected_Starting_incremental_compilation, errors, Diagnostics.Compilation_complete_Watching_for_file_changes);
}
function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, expectedExitCode: ExitStatus) {
checkOutputErrors(host, Diagnostics.File_change_detected_Starting_incremental_compilation, errors);
assert.equal(host.exitCode, expectedExitCode);
}
function getDiagnosticOfFileFrom(file: SourceFile, text: string, start: number, length: number, message: DiagnosticMessage): Diagnostic {
@@ -346,16 +341,16 @@ namespace ts.tscWatch {
checkProgramRootFiles(watch(), [file1.path]);
checkProgramActualFiles(watch(), [file1.path, libFile.path]);
checkOutputErrors(host, [
checkOutputErrorsInitial(host, [
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf(commonFile2Name), commonFile2Name.length, Diagnostics.File_0_not_found, commonFile2.path),
getDiagnosticOfFileFromProgram(watch(), file1.path, file1.content.indexOf("y"), 1, Diagnostics.Cannot_find_name_0, "y")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
]);
host.reloadFS([file1, commonFile2, libFile]);
host.runQueuedTimeoutCallbacks();
checkProgramRootFiles(watch(), [file1.path]);
checkProgramActualFiles(watch(), [file1.path, libFile.path, commonFile2.path]);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
});
it("should reflect change in config file", () => {
@@ -683,15 +678,14 @@ namespace ts.tscWatch {
const watch = createWatchOfConfigFile(config.path, host);
checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, emptyArray);
host.reloadFS([file1, file2, libFile]);
host.checkTimeoutQueueLengthAndRun(1);
assert.equal(host.exitCode, ExitStatus.DiagnosticsPresent_OutputsSkipped);
checkOutputErrors(host, [
checkOutputErrorsIncrementalWithExit(host, [
getDiagnosticWithoutFile(Diagnostics.File_0_not_found, config.path)
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected, /*skipWaiting*/ true);
], ExitStatus.DiagnosticsPresent_OutputsSkipped);
});
it("Proper errors: document is not contained in project", () => {
@@ -794,21 +788,21 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([moduleFile, file1, libFile]);
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, emptyArray);
const moduleFileOldPath = moduleFile.path;
const moduleFileNewPath = "/a/b/moduleFile1.ts";
moduleFile.path = moduleFileNewPath;
host.reloadFS([moduleFile, file1, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [
checkOutputErrorsIncremental(host, [
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
]);
moduleFile.path = moduleFileOldPath;
host.reloadFS([moduleFile, file1, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
});
it("rename a module file and rename back should restore the states for configured projects", () => {
@@ -826,21 +820,21 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([moduleFile, file1, configFile, libFile]);
const watch = createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, emptyArray);
const moduleFileOldPath = moduleFile.path;
const moduleFileNewPath = "/a/b/moduleFile1.ts";
moduleFile.path = moduleFileNewPath;
host.reloadFS([moduleFile, file1, configFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [
checkOutputErrorsIncremental(host, [
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
]);
moduleFile.path = moduleFileOldPath;
host.reloadFS([moduleFile, file1, configFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
});
it("types should load from config file path if config exists", () => {
@@ -877,13 +871,13 @@ namespace ts.tscWatch {
const host = createWatchedSystem([file1, libFile]);
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkOutputErrors(host, [
checkOutputErrorsInitial(host, [
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
]);
host.reloadFS([file1, moduleFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
});
it("Configure file diagnostics events are generated when the config file has errors", () => {
@@ -903,10 +897,10 @@ namespace ts.tscWatch {
const host = createWatchedSystem([file, configFile, libFile]);
const watch = createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, [
checkOutputErrorsInitialWithConfigErrors(host, [
getUnknownCompilerOption(watch(), configFile, "foo"),
getUnknownCompilerOption(watch(), configFile, "allowJS")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.BeforeCompilationStarts);
]);
});
it("If config file doesnt have errors, they are not reported", () => {
@@ -923,7 +917,7 @@ namespace ts.tscWatch {
const host = createWatchedSystem([file, configFile, libFile]);
createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, emptyArray);
});
it("Reports errors when the config file changes", () => {
@@ -940,7 +934,7 @@ namespace ts.tscWatch {
const host = createWatchedSystem([file, configFile, libFile]);
const watch = createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, emptyArray);
configFile.content = `{
"compilerOptions": {
@@ -949,16 +943,16 @@ namespace ts.tscWatch {
}`;
host.reloadFS([file, configFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [
checkOutputErrorsIncremental(host, [
getUnknownCompilerOption(watch(), configFile, "haha")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
]);
configFile.content = `{
"compilerOptions": {}
}`;
host.reloadFS([file, configFile, libFile]);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
});
it("non-existing directories listed in config file input array should be tolerated without crashing the server", () => {
@@ -1046,13 +1040,13 @@ namespace ts.tscWatch {
getDiagnosticOfFile(watch().getCompilerOptions().configFile, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
];
const intialErrors = errors();
checkOutputErrors(host, intialErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, intialErrors);
configFile.content = configFileContentWithoutCommentLine;
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
const nowErrors = errors();
checkOutputErrors(host, nowErrors, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, nowErrors);
assert.equal(nowErrors[0].start, intialErrors[0].start - configFileContentComment.length);
assert.equal(nowErrors[1].start, intialErrors[1].start - configFileContentComment.length);
});
@@ -1105,13 +1099,13 @@ namespace ts.tscWatch {
noUnusedLocals: true
});
checkProgramActualFiles(watch(), files.map(file => file.path));
checkOutputErrors(host, [], ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, []);
file.content = getFileContent(/*asModule*/ true);
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
checkProgramActualFiles(watch(), files.map(file => file.path));
checkOutputErrors(host, [], ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, []);
});
it("watched files when file is deleted and new file is added as part of change", () => {
@@ -1800,7 +1794,7 @@ namespace ts.tscWatch {
const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo");
// ensure that imported file was found
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, [f1IsNotModule, cannotFindFoo]);
const originalFileExists = host.fileExists;
{
@@ -1816,11 +1810,11 @@ namespace ts.tscWatch {
host.runQueuedTimeoutCallbacks();
// ensure file has correct number of errors after edit
checkOutputErrors(host, [
checkOutputErrorsIncremental(host, [
f1IsNotModule,
getDiagnosticOfFileFromProgram(watch(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"),
cannotFindFoo
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
]);
}
{
let fileExistsIsCalled = false;
@@ -1840,9 +1834,9 @@ namespace ts.tscWatch {
host.runQueuedTimeoutCallbacks();
// ensure file has correct number of errors after edit
checkOutputErrors(host, [
checkOutputErrorsIncremental(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "f2")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
]);
assert.isTrue(fileExistsIsCalled);
}
@@ -1863,7 +1857,7 @@ namespace ts.tscWatch {
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, [f1IsNotModule, cannotFindFoo], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, [f1IsNotModule, cannotFindFoo]);
assert.isTrue(fileExistsCalled);
}
});
@@ -1898,16 +1892,16 @@ namespace ts.tscWatch {
const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { module: ModuleKind.AMD });
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
checkOutputErrors(host, [
checkOutputErrorsInitial(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
]);
fileExistsCalledForBar = false;
root.content = `import {y} from "bar"`;
host.reloadFS(files.concat(imported));
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
});
@@ -1940,20 +1934,20 @@ namespace ts.tscWatch {
const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { module: ModuleKind.AMD });
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, emptyArray);
fileExistsCalledForBar = false;
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
checkOutputErrors(host, [
checkOutputErrorsIncremental(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "bar")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
]);
fileExistsCalledForBar = false;
host.reloadFS(filesWithImported);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called.");
});
@@ -1988,13 +1982,13 @@ declare module "fs" {
const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { });
checkOutputErrors(host, [
checkOutputErrorsInitial(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
]);
host.reloadFS(filesWithNodeType);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
});
it("works when included file with ambient module changes", () => {
@@ -2030,14 +2024,14 @@ declare module "fs" {
const watch = createWatchOfFilesAndCompilerOptions([root.path, file.path], host, {});
checkOutputErrors(host, [
checkOutputErrorsInitial(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
], /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
]);
file.content += fileContentWithFS;
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
});
it("works when reusing program with files from external library", () => {
@@ -2072,7 +2066,7 @@ declare module "fs" {
const host = createWatchedSystem(programFiles.concat(configFile), { currentDirectory: "/a/b/projects/myProject/" });
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
checkOutputErrorsInitial(host, emptyArray);
const expectedFiles: ExpectedFile[] = [
createExpectedEmittedFile(file1),
createExpectedEmittedFile(file2),
@@ -2091,7 +2085,7 @@ declare module "fs" {
host.reloadFS(programFiles.concat(configFile));
host.runQueuedTimeoutCallbacks();
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterFileChangeDetected);
checkOutputErrorsIncremental(host, emptyArray);
verifyExpectedFiles(expectedFiles);
@@ -2212,4 +2206,136 @@ declare module "fs" {
});
});
});
describe("tsc-watch with different polling/non polling options", () => {
it("watchFile using dynamic priority polling", () => {
const projectFolder = "/a/username/project";
const file1: FileOrFolder = {
path: `${projectFolder}/typescript.ts`,
content: "var z = 10;"
};
const files = [file1, libFile];
const environmentVariables = createMap<string>();
environmentVariables.set("TSC_WATCHFILE", "DynamicPriorityPolling");
const host = createWatchedSystem(files, { environmentVariables });
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
const initialProgram = watch();
verifyProgram();
const mediumPollingIntervalThreshold = unchangedPollThresholds[PollingInterval.Medium];
for (let index = 0; index < mediumPollingIntervalThreshold; index++) {
// Transition libFile and file1 to low priority queue
host.checkTimeoutQueueLengthAndRun(1);
assert.deepEqual(watch(), initialProgram);
}
// Make a change to file
file1.content = "var zz30 = 100;";
host.reloadFS(files);
// This should detect change in the file
host.checkTimeoutQueueLengthAndRun(1);
assert.deepEqual(watch(), initialProgram);
// Callbacks: medium priority + high priority queue and scheduled program update
host.checkTimeoutQueueLengthAndRun(3);
// During this timeout the file would be detected as unchanged
let fileUnchangeDetected = 1;
const newProgram = watch();
assert.notStrictEqual(newProgram, initialProgram);
verifyProgram();
const outputFile1 = changeExtension(file1.path, ".js");
assert.isTrue(host.fileExists(outputFile1));
assert.equal(host.readFile(outputFile1), file1.content + host.newLine);
const newThreshold = unchangedPollThresholds[PollingInterval.Low] + mediumPollingIntervalThreshold;
for (; fileUnchangeDetected < newThreshold; fileUnchangeDetected++) {
// For high + Medium/low polling interval
host.checkTimeoutQueueLengthAndRun(2);
assert.deepEqual(watch(), newProgram);
}
// Everything goes in high polling interval queue
host.checkTimeoutQueueLengthAndRun(1);
assert.deepEqual(watch(), newProgram);
function verifyProgram() {
checkProgramActualFiles(watch(), files.map(f => f.path));
checkWatchedFiles(host, []);
checkWatchedDirectories(host, [], /*recursive*/ false);
checkWatchedDirectories(host, [], /*recursive*/ true);
}
});
describe("tsc-watch when watchDirectories implementation", () => {
function verifyRenamingFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) {
const projectFolder = "/a/username/project";
const projectSrcFolder = `${projectFolder}/src`;
const configFile: FileOrFolder = {
path: `${projectFolder}/tsconfig.json`,
content: "{}"
};
const file: FileOrFolder = {
path: `${projectSrcFolder}/file1.ts`,
content: ""
};
const programFiles = [file, libFile];
const files = [file, configFile, libFile];
const environmentVariables = createMap<string>();
environmentVariables.set("TSC_WATCHDIRECTORY", tscWatchDirectory);
const host = createWatchedSystem(files, { environmentVariables });
const watch = createWatchOfConfigFile(configFile.path, host);
const projectFolders = [projectFolder, projectSrcFolder, `${projectFolder}/node_modules/@types`];
// Watching files config file, file, lib file
const expectedWatchedFiles = files.map(f => f.path);
const expectedWatchedDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ? projectFolders : emptyArray;
if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile) {
expectedWatchedFiles.push(...projectFolders);
}
verifyProgram(checkOutputErrorsInitial);
// Rename the file:
file.path = file.path.replace("file1.ts", "file2.ts");
expectedWatchedFiles[0] = file.path;
host.reloadFS(files);
if (tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling) {
// With dynamic polling the fs change would be detected only by running timeouts
host.runQueuedTimeoutCallbacks();
}
// Delayed update program
host.runQueuedTimeoutCallbacks();
verifyProgram(checkOutputErrorsIncremental);
function verifyProgram(checkOutputErrors: (host: WatchedSystem, errors: ReadonlyArray<Diagnostic>) => void) {
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
checkOutputErrors(host, emptyArray);
const outputFile = changeExtension(file.path, ".js");
assert(host.fileExists(outputFile));
assert.equal(host.readFile(outputFile), file.content);
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
// Watching config file, file, lib file and directories
TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedFiles", host.watchedFiles, expectedWatchedFiles, 1);
TestFSWithWatch.checkMultiMapEachKeyWithCount("watchedDirectories", host.watchedDirectories, expectedWatchedDirectories, 1);
}
}
it("uses watchFile when renaming file in subfolder", () => {
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile);
});
it("uses non recursive watchDirectory when renaming file in subfolder", () => {
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory);
});
it("uses non recursive dynamic polling when renaming file in subfolder", () => {
verifyRenamingFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
});
});
});
}
+93 -15
View File
@@ -10,7 +10,7 @@ namespace ts.projectSystem {
export import TestServerHost = TestFSWithWatch.TestServerHost;
export type FileOrFolder = TestFSWithWatch.FileOrFolder;
export import createServerHost = TestFSWithWatch.createServerHost;
export import checkFileNames = TestFSWithWatch.checkFileNames;
export import checkArray = TestFSWithWatch.checkArray;
export import libFile = TestFSWithWatch.libFile;
export import checkWatchedFiles = TestFSWithWatch.checkWatchedFiles;
import checkWatchedDirectories = TestFSWithWatch.checkWatchedDirectories;
@@ -355,11 +355,11 @@ namespace ts.projectSystem {
}
export function checkProjectActualFiles(project: server.Project, expectedFiles: string[]) {
checkFileNames(`${server.ProjectKind[project.projectKind]} project, actual files`, project.getFileNames(), expectedFiles);
checkArray(`${server.ProjectKind[project.projectKind]} project, actual files`, project.getFileNames(), expectedFiles);
}
function checkProjectRootFiles(project: server.Project, expectedFiles: string[]) {
checkFileNames(`${server.ProjectKind[project.projectKind]} project, rootFileNames`, project.getRootFiles(), expectedFiles);
checkArray(`${server.ProjectKind[project.projectKind]} project, rootFileNames`, project.getRootFiles(), expectedFiles);
}
function mapCombinedPathsInAncestor(dir: string, path2: string, mapAncestor: (ancestor: string) => boolean) {
@@ -392,7 +392,7 @@ namespace ts.projectSystem {
}
function checkOpenFiles(projectService: server.ProjectService, expectedFiles: FileOrFolder[]) {
checkFileNames("Open files", arrayFrom(projectService.openFiles.keys(), path => projectService.getScriptInfoForPath(path as Path).fileName), expectedFiles.map(file => file.path));
checkArray("Open files", arrayFrom(projectService.openFiles.keys(), path => projectService.getScriptInfoForPath(path as Path).fileName), expectedFiles.map(file => file.path));
}
/**
@@ -531,7 +531,7 @@ namespace ts.projectSystem {
const project = projectService.inferredProjects[0];
checkFileNames("inferred project", project.getFileNames(), [appFile.path, libFile.path, moduleFile.path]);
checkArray("inferred project", project.getFileNames(), [appFile.path, libFile.path, moduleFile.path]);
const configFileLocations = ["/a/b/c/", "/a/b/", "/a/", "/"];
const configFiles = flatMap(configFileLocations, location => [location + "tsconfig.json", location + "jsconfig.json"]);
checkWatchedFiles(host, configFiles.concat(libFile.path, moduleFile.path));
@@ -5350,13 +5350,13 @@ namespace ts.projectSystem {
});
// send outlining spans request (normal priority)
session.executeCommandSeq(<protocol.OutliningSpansRequest>{
session.executeCommandSeq(<protocol.OutliningSpansRequestFull>{
command: "outliningSpans",
arguments: { file: f1.path }
});
// ensure the outlining spans request can be canceled
verifyExecuteCommandSeqIsCancellable(<protocol.OutliningSpansRequest>{
verifyExecuteCommandSeqIsCancellable(<protocol.OutliningSpansRequestFull>{
command: "outliningSpans",
arguments: { file: f1.path }
});
@@ -5663,16 +5663,11 @@ namespace ts.projectSystem {
}
function verifyCalledOnEachEntry(callback: CalledMaps, expectedKeys: Map<number>) {
const calledMap = calledMaps[callback];
TestFSWithWatch.verifyMapSize(callback, calledMap, arrayFrom(expectedKeys.keys()));
expectedKeys.forEach((called, name) => {
assert.isTrue(calledMap.has(name), `${callback} is expected to contain ${name}, actual keys: ${arrayFrom(calledMap.keys())}`);
assert.equal(calledMap.get(name).length, called, `${callback} is expected to be called ${called} times with ${name}. Actual entry: ${calledMap.get(name)}`);
});
TestFSWithWatch.checkMultiMapKeyCount(callback, calledMaps[callback], expectedKeys);
}
function verifyCalledOnEachEntryNTimes(callback: CalledMaps, expectedKeys: string[], nTimes: number) {
return verifyCalledOnEachEntry(callback, zipToMap(expectedKeys, expectedKeys.map(() => nTimes)));
TestFSWithWatch.checkMultiMapEachKeyWithCount(callback, calledMaps[callback], expectedKeys, nTimes);
}
function verifyNoHostCalls() {
@@ -7009,7 +7004,6 @@ namespace ts.projectSystem {
assert.isDefined(projectService.configuredProjects.get(aTsconfig.path));
assert.isDefined(projectService.configuredProjects.get(bTsconfig.path));
debugger;
verifyRenameResponse(session.executeCommandSeq<protocol.RenameRequest>({
command: protocol.CommandTypes.Rename,
arguments: {
@@ -7438,4 +7432,88 @@ namespace ts.projectSystem {
});
});
});
describe("watchDirectories implementation", () => {
function verifyCompletionListWithNewFileInSubFolder(tscWatchDirectory: TestFSWithWatch.Tsc_WatchDirectory) {
const projectFolder = "/a/username/project";
const projectSrcFolder = `${projectFolder}/src`;
const configFile: FileOrFolder = {
path: `${projectFolder}/tsconfig.json`,
content: "{}"
};
const index: FileOrFolder = {
path: `${projectSrcFolder}/index.ts`,
content: `import {} from "./"`
};
const file1: FileOrFolder = {
path: `${projectSrcFolder}/file1.ts`,
content: ""
};
const files = [index, file1, configFile, libFile];
const fileNames = files.map(file => file.path);
// All closed files(files other than index), project folder, project/src folder and project/node_modules/@types folder
const expectedWatchedFiles = arrayToMap(fileNames.slice(1), s => s, () => 1);
const expectedWatchedDirectories = createMap<number>();
const mapOfDirectories = tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory ?
expectedWatchedDirectories :
tscWatchDirectory === TestFSWithWatch.Tsc_WatchDirectory.WatchFile ?
expectedWatchedFiles :
createMap();
// For failed resolution lookup and tsconfig files
mapOfDirectories.set(projectFolder, 2);
// Through above recursive watches
mapOfDirectories.set(projectSrcFolder, 2);
// node_modules/@types folder
mapOfDirectories.set(`${projectFolder}/${nodeModulesAtTypes}`, 1);
const expectedCompletions = ["file1"];
const completionPosition = index.content.lastIndexOf('"');
const environmentVariables = createMap<string>();
environmentVariables.set("TSC_WATCHDIRECTORY", tscWatchDirectory);
const host = createServerHost(files, { environmentVariables });
const projectService = createProjectService(host);
projectService.openClientFile(index.path);
const project = projectService.configuredProjects.get(configFile.path);
assert.isDefined(project);
verifyProjectAndCompletions();
// Add file2
const file2: FileOrFolder = {
path: `${projectSrcFolder}/file2.ts`,
content: ""
};
files.push(file2);
fileNames.push(file2.path);
expectedWatchedFiles.set(file2.path, 1);
expectedCompletions.push("file2");
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
assert.equal(projectService.configuredProjects.get(configFile.path), project);
verifyProjectAndCompletions();
function verifyProjectAndCompletions() {
const completions = project.getLanguageService().getCompletionsAtPosition(index.path, completionPosition, { includeExternalModuleExports: false, includeInsertTextCompletions: false });
checkArray("Completion Entries", completions.entries.map(e => e.name), expectedCompletions);
checkWatchedDirectories(host, emptyArray, /*recursive*/ true);
TestFSWithWatch.checkMultiMapKeyCount("watchedFiles", host.watchedFiles, expectedWatchedFiles);
TestFSWithWatch.checkMultiMapKeyCount("watchedDirectories", host.watchedDirectories, expectedWatchedDirectories);
checkProjectActualFiles(project, fileNames);
}
}
it("uses watchFile when file is added to subfolder, completion list has new file", () => {
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.WatchFile);
});
it("uses non recursive watchDirectory when file is added to subfolder, completion list has new file", () => {
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.NonRecursiveWatchDirectory);
});
it("uses dynamic polling when file is added to subfolder, completion list has new file", () => {
verifyCompletionListWithNewFileInSubFolder(TestFSWithWatch.Tsc_WatchDirectory.DynamicPolling);
});
});
}
+115 -41
View File
@@ -36,6 +36,7 @@ interface Array<T> {}`
currentDirectory?: string;
newLine?: string;
useWindowsStylePaths?: boolean;
environmentVariables?: Map<string>;
}
export function createWatchedSystem(fileOrFolderList: ReadonlyArray<FileOrFolder>, params?: TestServerHostCreationParameters): TestServerHost {
@@ -48,7 +49,8 @@ interface Array<T> {}`
params.currentDirectory || "/",
fileOrFolderList,
params.newLine,
params.useWindowsStylePaths);
params.useWindowsStylePaths,
params.environmentVariables);
return host;
}
@@ -62,7 +64,8 @@ interface Array<T> {}`
params.currentDirectory || "/",
fileOrFolderList,
params.newLine,
params.useWindowsStylePaths);
params.useWindowsStylePaths,
params.environmentVariables);
return host;
}
@@ -76,6 +79,7 @@ interface Array<T> {}`
interface FSEntry {
path: Path;
fullPath: string;
modifiedTime: Date;
}
interface File extends FSEntry {
@@ -152,10 +156,22 @@ interface Array<T> {}`
}
}
export function checkFileNames(caption: string, actualFileNames: ReadonlyArray<string>, expectedFileNames: string[]) {
assert.equal(actualFileNames.length, expectedFileNames.length, `${caption}: incorrect actual number of files, expected:\r\n${expectedFileNames.join("\r\n")}\r\ngot: ${actualFileNames.join("\r\n")}`);
for (const f of expectedFileNames) {
assert.equal(true, contains(actualFileNames, f), `${caption}: expected to find ${f} in ${actualFileNames}`);
export function checkMultiMapKeyCount(caption: string, actual: MultiMap<any>, expectedKeys: Map<number>) {
verifyMapSize(caption, actual, arrayFrom(expectedKeys.keys()));
expectedKeys.forEach((count, name) => {
assert.isTrue(actual.has(name), `${caption}: expected to contain ${name}, actual keys: ${arrayFrom(actual.keys())}`);
assert.equal(actual.get(name).length, count, `${caption}: Expected to be have ${count} entries for ${name}. Actual entry: ${JSON.stringify(actual.get(name))}`);
});
}
export function checkMultiMapEachKeyWithCount(caption: string, actual: MultiMap<any>, expectedKeys: ReadonlyArray<string>, count: number) {
return checkMultiMapKeyCount(caption, actual, arrayToMap(expectedKeys, s => s, () => count));
}
export function checkArray(caption: string, actual: ReadonlyArray<string>, expected: ReadonlyArray<string>) {
assert.equal(actual.length, expected.length, `${caption}: incorrect actual number of files, expected:\r\n${expected.join("\r\n")}\r\ngot: ${actual.join("\r\n")}`);
for (const f of expected) {
assert.equal(true, contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
}
}
@@ -254,6 +270,12 @@ interface Array<T> {}`
invokeFileDeleteCreateAsPartInsteadOfChange: boolean;
}
export enum Tsc_WatchDirectory {
WatchFile = "RecursiveDirectoryUsingFsWatchFile",
NonRecursiveWatchDirectory = "RecursiveDirectoryUsingNonRecursiveWatchDirectory",
DynamicPolling = "RecursiveDirectoryUsingDynamicPriorityPolling"
}
export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost {
args: string[] = [];
@@ -271,13 +293,47 @@ interface Array<T> {}`
readonly watchedFiles = createMultiMap<TestFileWatcher>();
private readonly executingFilePath: string;
private readonly currentDirectory: string;
private readonly dynamicPriorityWatchFile: HostWatchFile;
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderList: ReadonlyArray<FileOrFolder>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean) {
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderList: ReadonlyArray<FileOrFolder>, public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
this.reloadFS(fileOrFolderList);
this.dynamicPriorityWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") === "DynamicPriorityPolling" ?
createDynamicPriorityPollingWatchFile(this) :
undefined;
const tscWatchDirectory = this.environmentVariables && this.environmentVariables.get("TSC_WATCHDIRECTORY") as Tsc_WatchDirectory;
if (tscWatchDirectory === Tsc_WatchDirectory.WatchFile) {
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchFile(directory, () => cb(directory), PollingInterval.Medium);
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
directoryExists: path => this.directoryExists(path),
getAccessileSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory
});
}
else if (tscWatchDirectory === Tsc_WatchDirectory.NonRecursiveWatchDirectory) {
const watchDirectory: HostWatchDirectory = (directory, cb) => this.watchDirectory(directory, fileName => cb(fileName), /*recursive*/ false);
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
directoryExists: path => this.directoryExists(path),
getAccessileSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory
});
}
else if (tscWatchDirectory === Tsc_WatchDirectory.DynamicPolling) {
const watchFile = createDynamicPriorityPollingWatchFile(this);
const watchDirectory: HostWatchDirectory = (directory, cb) => watchFile(directory, () => cb(directory), PollingInterval.Medium);
this.customRecursiveWatchDirectory = createRecursiveDirectoryWatcher({
directoryExists: path => this.directoryExists(path),
getAccessileSortedChildDirectories: path => this.getDirectories(path),
filePathComparer: this.useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
watchDirectory
});
}
}
getNewLine() {
@@ -325,6 +381,8 @@ interface Array<T> {}`
}
else {
currentEntry.content = fileOrDirectory.content;
currentEntry.modifiedTime = new Date();
this.fs.get(getDirectoryPath(currentEntry.path)).modifiedTime = new Date();
if (options && options.invokeDirectoryWatcherInsteadOfFileChanged) {
this.invokeDirectoryWatcher(getDirectoryPath(currentEntry.fullPath), currentEntry.fullPath);
}
@@ -348,6 +406,7 @@ interface Array<T> {}`
}
else {
// Folder update: Nothing to do.
currentEntry.modifiedTime = new Date();
}
}
}
@@ -446,14 +505,13 @@ interface Array<T> {}`
private addFileOrFolderInFolder(folder: Folder, fileOrDirectory: File | Folder | SymLink, ignoreWatch?: boolean) {
folder.entries.push(fileOrDirectory);
folder.modifiedTime = new Date();
this.fs.set(fileOrDirectory.path, fileOrDirectory);
if (ignoreWatch) {
return;
}
if (isFile(fileOrDirectory) || isSymLink(fileOrDirectory)) {
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Created);
}
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Created);
this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath);
}
@@ -462,14 +520,13 @@ interface Array<T> {}`
const baseFolder = this.fs.get(basePath) as Folder;
if (basePath !== fileOrDirectory.path) {
Debug.assert(!!baseFolder);
baseFolder.modifiedTime = new Date();
filterMutate(baseFolder.entries, entry => entry !== fileOrDirectory);
}
this.fs.delete(fileOrDirectory.path);
if (isFile(fileOrDirectory) || isSymLink(fileOrDirectory)) {
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted);
}
else {
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted);
if (isFolder(fileOrDirectory)) {
Debug.assert(fileOrDirectory.entries.length === 0 || isRenaming);
const relativePath = this.getRelativePathToDirectory(fileOrDirectory.fullPath, fileOrDirectory.fullPath);
// Invoke directory and recursive directory watcher for the folder
@@ -503,6 +560,8 @@ interface Array<T> {}`
*/
private invokeDirectoryWatcher(folderFullPath: string, fileName: string) {
const relativePath = this.getRelativePathToDirectory(folderFullPath, fileName);
// Folder is changed when the directory watcher is invoked
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(folderFullPath)), ({ cb, fileName }) => cb(fileName, FileWatcherEventKind.Changed));
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath)), cb => this.directoryCallback(cb, relativePath));
this.invokeRecursiveDirectoryWatcher(folderFullPath, fileName);
}
@@ -523,34 +582,34 @@ interface Array<T> {}`
}
}
private toFile(fileOrDirectory: FileOrFolder): File {
const fullPath = getNormalizedAbsolutePath(fileOrDirectory.path, this.currentDirectory);
return {
path: this.toPath(fullPath),
content: fileOrDirectory.content,
fullPath,
fileSize: fileOrDirectory.fileSize
};
}
private toSymLink(fileOrDirectory: FileOrFolder): SymLink {
const fullPath = getNormalizedAbsolutePath(fileOrDirectory.path, this.currentDirectory);
return {
path: this.toPath(fullPath),
fullPath,
symLink: getNormalizedAbsolutePath(fileOrDirectory.symLink, getDirectoryPath(fullPath))
};
}
private toFolder(path: string): Folder {
private toFsEntry(path: string): FSEntry {
const fullPath = getNormalizedAbsolutePath(path, this.currentDirectory);
return {
path: this.toPath(fullPath),
entries: [],
fullPath
fullPath,
modifiedTime: new Date()
};
}
private toFile(fileOrDirectory: FileOrFolder): File {
const file = this.toFsEntry(fileOrDirectory.path) as File;
file.content = fileOrDirectory.content;
file.fileSize = fileOrDirectory.fileSize;
return file;
}
private toSymLink(fileOrDirectory: FileOrFolder): SymLink {
const symLink = this.toFsEntry(fileOrDirectory.path) as SymLink;
symLink.symLink = getNormalizedAbsolutePath(fileOrDirectory.symLink, getDirectoryPath(symLink.fullPath));
return symLink;
}
private toFolder(path: string): Folder {
const folder = this.toFsEntry(path) as Folder;
folder.entries = [];
return folder;
}
private getRealFsEntry<T extends FSEntry>(isFsEntry: (fsEntry: FSEntry) => fsEntry is T, path: Path, fsEntry = this.fs.get(path)): T | undefined {
if (isFsEntry(fsEntry)) {
return fsEntry;
@@ -594,6 +653,12 @@ interface Array<T> {}`
return !!this.getRealFile(path);
}
getModifiedTime(s: string) {
const path = this.toFullPath(s);
const fsEntry = this.fs.get(path);
return fsEntry && fsEntry.modifiedTime;
}
readFile(s: string): string {
const fsEntry = this.getRealFile(this.toFullPath(s));
return fsEntry ? fsEntry.content : undefined;
@@ -646,6 +711,9 @@ interface Array<T> {}`
}
watchDirectory(directoryName: string, cb: DirectoryWatcherCallback, recursive: boolean): FileWatcher {
if (recursive && this.customRecursiveWatchDirectory) {
return this.customRecursiveWatchDirectory(directoryName, cb, /*recursive*/ true);
}
const path = this.toFullPath(directoryName);
const map = recursive ? this.watchedDirectoriesRecursive : this.watchedDirectories;
const callback: TestDirectoryWatcher = {
@@ -662,7 +730,11 @@ interface Array<T> {}`
return Harness.mockHash(s);
}
watchFile(fileName: string, cb: FileWatcherCallback) {
watchFile(fileName: string, cb: FileWatcherCallback, pollingInterval: number) {
if (this.dynamicPriorityWatchFile) {
return this.dynamicPriorityWatchFile(fileName, cb, pollingInterval);
}
const path = this.toFullPath(fileName);
const callback: TestFileWatcher = { fileName, cb };
this.watchedFiles.add(path, callback);
@@ -701,7 +773,7 @@ interface Array<T> {}`
this.timeoutCallbacks.invoke(timeoutId);
}
catch (e) {
if (e.message === this.existMessage) {
if (e.message === this.exitMessage) {
return;
}
throw e;
@@ -779,15 +851,17 @@ interface Array<T> {}`
return realFullPath;
}
readonly existMessage = "System Exit";
readonly exitMessage = "System Exit";
exitCode: number;
readonly resolvePath = (s: string) => s;
readonly getExecutingFilePath = () => this.executingFilePath;
readonly getCurrentDirectory = () => this.currentDirectory;
exit(exitCode?: number) {
this.exitCode = exitCode;
throw new Error(this.existMessage);
throw new Error(this.exitMessage);
}
getEnvironmentVariable(name: string) {
return this.environmentVariables && this.environmentVariables.get(name);
}
readonly getEnvironmentVariable = notImplemented;
}
}
+15062 -14535
View File
File diff suppressed because it is too large Load Diff
+1757 -1930
View File
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -522,8 +522,16 @@ namespace ts.server {
}));
}
getOutliningSpans(_fileName: string): OutliningSpan[] {
return notImplemented();
getOutliningSpans(file: string): OutliningSpan[] {
const request = this.processRequest<protocol.OutliningSpansRequest>(CommandNames.GetOutliningSpans, { file });
const response = this.processResponse<protocol.OutliningSpansResponse>(request);
return response.body.map<OutliningSpan>(item => ({
textSpan: this.decodeSpan(item.textSpan, file),
hintSpan: this.decodeSpan(item.hintSpan, file),
bannerText: item.bannerText,
autoCollapse: item.autoCollapse
}));
}
getTodoComments(_fileName: string, _descriptors: TodoCommentDescriptor[]): TodoComment[] {
+19 -35
View File
@@ -311,9 +311,9 @@ namespace ts.server {
typesMapLocation?: string;
}
type WatchFile = (host: ServerHost, file: string, cb: FileWatcherCallback, watchType: WatchType, project?: Project) => FileWatcher;
type WatchFilePath = (host: ServerHost, file: string, cb: FilePathWatcherCallback, path: Path, watchType: WatchType, project?: Project) => FileWatcher;
type WatchDirectory = (host: ServerHost, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, watchType: WatchType, project?: Project) => FileWatcher;
function getDetailWatchInfo(watchType: WatchType, project: Project | undefined) {
return `Project: ${project ? project.getProjectName() : ""} WatchType: ${watchType}`;
}
export class ProjectService {
@@ -401,11 +401,7 @@ namespace ts.server {
private readonly seenProjects = createMap<true>();
/*@internal*/
readonly watchFile: WatchFile;
/*@internal*/
readonly watchFilePath: WatchFilePath;
/*@internal*/
readonly watchDirectory: WatchDirectory;
readonly watchFactory: WatchFactory<WatchType, Project>;
constructor(opts: ProjectServiceOptions) {
this.host = opts.host;
@@ -447,26 +443,10 @@ namespace ts.server {
};
this.documentRegistry = createDocumentRegistry(this.host.useCaseSensitiveFileNames, this.currentDirectory);
if (this.logger.hasLevel(LogLevel.verbose)) {
this.watchFile = (host, file, cb, watchType, project) => addFileWatcherWithLogging(host, file, cb, this.createWatcherLog(watchType, project));
this.watchFilePath = (host, file, cb, path, watchType, project) => addFilePathWatcherWithLogging(host, file, cb, path, this.createWatcherLog(watchType, project));
this.watchDirectory = (host, dir, cb, flags, watchType, project) => addDirectoryWatcherWithLogging(host, dir, cb, flags, this.createWatcherLog(watchType, project));
}
else if (this.logger.loggingEnabled()) {
this.watchFile = (host, file, cb, watchType, project) => addFileWatcherWithOnlyTriggerLogging(host, file, cb, this.createWatcherLog(watchType, project));
this.watchFilePath = (host, file, cb, path, watchType, project) => addFilePathWatcherWithOnlyTriggerLogging(host, file, cb, path, this.createWatcherLog(watchType, project));
this.watchDirectory = (host, dir, cb, flags, watchType, project) => addDirectoryWatcherWithOnlyTriggerLogging(host, dir, cb, flags, this.createWatcherLog(watchType, project));
}
else {
this.watchFile = addFileWatcher;
this.watchFilePath = addFilePathWatcher;
this.watchDirectory = addDirectoryWatcher;
}
}
private createWatcherLog(watchType: WatchType, project: Project | undefined): (s: string) => void {
const detailedInfo = ` Project: ${project ? project.getProjectName() : ""} WatchType: ${watchType}`;
return s => this.logger.info(s + detailedInfo);
const watchLogLevel = this.logger.hasLevel(LogLevel.verbose) ? WatchLogLevel.Verbose :
this.logger.loggingEnabled() ? WatchLogLevel.TriggerOnly : WatchLogLevel.None;
const log: (s: string) => void = watchLogLevel !== WatchLogLevel.None ? (s => this.logger.info(s)) : noop;
this.watchFactory = getWatchFactory(watchLogLevel, log, getDetailWatchInfo);
}
toPath(fileName: string) {
@@ -714,8 +694,8 @@ namespace ts.server {
return formatCodeSettings || this.hostConfiguration.formatCodeOptions;
}
private onSourceFileChanged(fileName: NormalizedPath, eventKind: FileWatcherEventKind) {
const info = this.getScriptInfoForNormalizedPath(fileName);
private onSourceFileChanged(fileName: string, eventKind: FileWatcherEventKind, path: Path) {
const info = this.getScriptInfoForPath(path);
if (!info) {
this.logger.msg(`Error: got watch notification for unknown file: ${fileName}`);
}
@@ -759,7 +739,7 @@ namespace ts.server {
*/
/*@internal*/
watchWildcardDirectory(directory: Path, flags: WatchDirectoryFlags, project: ConfiguredProject) {
return this.watchDirectory(
return this.watchFactory.watchDirectory(
this.host,
directory,
fileOrDirectory => {
@@ -1097,10 +1077,11 @@ namespace ts.server {
canonicalConfigFilePath: string,
configFileExistenceInfo: ConfigFileExistenceInfo
) {
configFileExistenceInfo.configFileWatcherForRootOfInferredProject = this.watchFile(
configFileExistenceInfo.configFileWatcherForRootOfInferredProject = this.watchFactory.watchFile(
this.host,
configFileName,
(_filename, eventKind) => this.onConfigFileChangeForOpenScriptInfo(configFileName, eventKind),
PollingInterval.High,
WatchType.ConfigFileForInferredRoot
);
this.logConfigFileWatchUpdate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.UpdatedCallback);
@@ -1481,10 +1462,11 @@ namespace ts.server {
project.configFileSpecs = configFileSpecs;
// TODO: We probably should also watch the configFiles that are extended
project.configFileWatcher = this.watchFile(
project.configFileWatcher = this.watchFactory.watchFile(
this.host,
configFileName,
(_fileName, eventKind) => this.onConfigChangedForConfiguredProject(project, eventKind),
PollingInterval.High,
WatchType.ConfigFilePath,
project
);
@@ -1745,10 +1727,12 @@ namespace ts.server {
// do not watch files with mixed content - server doesn't know how to interpret it
if (!info.isDynamicOrHasMixedContent()) {
const { fileName } = info;
info.fileWatcher = this.watchFile(
info.fileWatcher = this.watchFactory.watchFilePath(
this.host,
fileName,
(_fileName, eventKind) => this.onSourceFileChanged(fileName, eventKind),
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
PollingInterval.Medium,
info.path,
WatchType.ClosedScriptInfo
);
}
+6 -6
View File
@@ -398,7 +398,7 @@ namespace ts.server {
/*@internal*/
watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) {
return this.projectService.watchDirectory(
return this.projectService.watchFactory.watchDirectory(
this.projectService.host,
directory,
cb,
@@ -415,7 +415,7 @@ namespace ts.server {
/*@internal*/
watchTypeRootsDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags) {
return this.projectService.watchDirectory(
return this.projectService.watchFactory.watchDirectory(
this.projectService.host,
directory,
cb,
@@ -907,7 +907,7 @@ namespace ts.server {
const oldExternalFiles = this.externalFiles || emptyArray as SortedReadonlyArray<string>;
this.externalFiles = this.getExternalFiles();
enumerateInsertsAndDeletes(this.externalFiles, oldExternalFiles,
enumerateInsertsAndDeletes(this.externalFiles, oldExternalFiles, compareStringsCaseSensitive,
// Ensure a ScriptInfo is created for new external files. This is performed indirectly
// by the LSHost for files in the program when the program is retrieved above but
// the program doesn't contain external files so this must be done explicitly.
@@ -915,8 +915,7 @@ namespace ts.server {
const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost);
scriptInfo.attachToProject(this);
},
removed => this.detachScriptInfoFromProject(removed),
compareStringsCaseSensitive
removed => this.detachScriptInfoFromProject(removed)
);
const elapsed = timestamp() - start;
this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasChanges} Elapsed: ${elapsed}ms`);
@@ -932,7 +931,7 @@ namespace ts.server {
}
private addMissingFileWatcher(missingFilePath: Path) {
const fileWatcher = this.projectService.watchFile(
const fileWatcher = this.projectService.watchFactory.watchFile(
this.projectService.host,
missingFilePath,
(fileName, eventKind) => {
@@ -948,6 +947,7 @@ namespace ts.server {
this.projectService.delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(this);
}
},
PollingInterval.Medium,
WatchType.MissingFilePath,
this
);
+37 -5
View File
@@ -91,8 +91,9 @@ namespace ts.server.protocol {
EncodedSemanticClassificationsFull = "encodedSemanticClassifications-full",
/* @internal */
Cleanup = "cleanup",
GetOutliningSpans = "getOutliningSpans",
/* @internal */
OutliningSpans = "outliningSpans",
GetOutliningSpansFull = "outliningSpans", // Full command name is different for backward compatibility purposes
TodoComments = "todoComments",
Indentation = "indentation",
DocCommentTemplate = "docCommentTemplate",
@@ -303,17 +304,48 @@ namespace ts.server.protocol {
/**
* Request to obtain outlining spans in file.
*/
/* @internal */
export interface OutliningSpansRequest extends FileRequest {
command: CommandTypes.OutliningSpans;
command: CommandTypes.GetOutliningSpans;
}
export interface OutliningSpan {
/** The span of the document to actually collapse. */
textSpan: TextSpan;
/** The span of the document to display when the user hovers over the collapsed span. */
hintSpan: TextSpan;
/** The text to display in the editor for the collapsed region. */
bannerText: string;
/**
* Whether or not this region should be automatically collapsed when
* the 'Collapse to Definitions' command is invoked.
*/
autoCollapse: boolean;
}
/**
* Response to OutliningSpansRequest request.
*/
export interface OutliningSpansResponse extends Response {
body?: OutliningSpan[];
}
/**
* Request to obtain outlining spans in file.
*/
/* @internal */
export interface OutliningSpansRequestFull extends FileRequest {
command: CommandTypes.GetOutliningSpansFull;
}
/**
* Response to OutliningSpansRequest request.
*/
/* @internal */
export interface OutliningSpansResponse extends Response {
body?: OutliningSpan[];
export interface OutliningSpansResponseFull extends Response {
body?: ts.OutliningSpan[];
}
/**
+7 -16
View File
@@ -128,7 +128,7 @@ namespace ts.server {
const fs: {
openSync(path: string, options: string): number;
close(fd: number): void;
close(fd: number, callback: (err: NodeJS.ErrnoException) => void): void;
writeSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number;
writeSync(fd: number, data: any, position?: number, enconding?: string): number;
statSync(path: string): Stats;
@@ -167,7 +167,7 @@ namespace ts.server {
close() {
if (this.fd >= 0) {
fs.close(this.fd);
fs.close(this.fd, noop);
}
}
@@ -685,11 +685,11 @@ namespace ts.server {
return;
}
fs.stat(watchedFile.fileName, (err: any, stats: any) => {
fs.stat(watchedFile.fileName, (err, stats) => {
if (err) {
if (err.code === "ENOENT") {
if (watchedFile.mtime.getTime() !== 0) {
watchedFile.mtime = new Date(0);
watchedFile.mtime = missingFileModifiedTime;
watchedFile.callback(watchedFile.fileName, FileWatcherEventKind.Deleted);
}
}
@@ -698,17 +698,7 @@ namespace ts.server {
}
}
else {
const oldTime = watchedFile.mtime.getTime();
const newTime = stats.mtime.getTime();
if (oldTime !== newTime) {
watchedFile.mtime = stats.mtime;
const eventKind = oldTime === 0
? FileWatcherEventKind.Created
: newTime === 0
? FileWatcherEventKind.Deleted
: FileWatcherEventKind.Changed;
watchedFile.callback(watchedFile.fileName, eventKind);
}
onWatchedFileStat(watchedFile, stats.mtime);
}
});
}
@@ -742,7 +732,7 @@ namespace ts.server {
callback,
mtime: sys.fileExists(fileName)
? getModifiedTime(fileName)
: new Date(0) // Any subsequent modification will occur after this time
: missingFileModifiedTime // Any subsequent modification will occur after this time
};
watchedFiles.push(file);
@@ -991,6 +981,7 @@ namespace ts.server {
ioSession.logError(err, "unknown");
});
// See https://github.com/Microsoft/TypeScript/issues/11348
// tslint:disable-next-line no-unnecessary-type-assertion-2
(process as any).noAsar = true;
// Start listening
ioSession.listen();
+19 -4
View File
@@ -1087,9 +1087,21 @@ namespace ts.server {
return { file, project };
}
private getOutliningSpans(args: protocol.FileRequestArgs) {
private getOutliningSpans(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.OutliningSpan[] | OutliningSpan[] {
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
return languageService.getOutliningSpans(file);
const spans = languageService.getOutliningSpans(file);
if (simplifiedResult) {
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
return spans.map(s => ({
textSpan: this.toLocationTextSpan(s.textSpan, scriptInfo),
hintSpan: this.toLocationTextSpan(s.hintSpan, scriptInfo),
bannerText: s.bannerText,
autoCollapse: s.autoCollapse
}));
}
else {
return spans;
}
}
private getTodoComments(args: protocol.TodoCommentRequestArgs) {
@@ -1893,8 +1905,11 @@ namespace ts.server {
[CommandNames.QuickinfoFull]: (request: protocol.QuickInfoRequest) => {
return this.requiredResponse(this.getQuickInfoWorker(request.arguments, /*simplifiedResult*/ false));
},
[CommandNames.OutliningSpans]: (request: protocol.FileRequest) => {
return this.requiredResponse(this.getOutliningSpans(request.arguments));
[CommandNames.GetOutliningSpans]: (request: protocol.FileRequest) => {
return this.requiredResponse(this.getOutliningSpans(request.arguments, /*simplifiedResult*/ true));
},
[CommandNames.GetOutliningSpansFull]: (request: protocol.FileRequest) => {
return this.requiredResponse(this.getOutliningSpans(request.arguments, /*simplifiedResult*/ false));
},
[CommandNames.TodoComments]: (request: protocol.TodoCommentRequest) => {
return this.requiredResponse(this.getTodoComments(request.arguments));
-30
View File
@@ -264,36 +264,6 @@ namespace ts.server {
return index === 0 || value !== array[index - 1];
}
export function enumerateInsertsAndDeletes<T>(newItems: SortedReadonlyArray<T>, oldItems: SortedReadonlyArray<T>, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, comparer: Comparer<T>) {
let newIndex = 0;
let oldIndex = 0;
const newLen = newItems.length;
const oldLen = oldItems.length;
while (newIndex < newLen && oldIndex < oldLen) {
const newItem = newItems[newIndex];
const oldItem = oldItems[oldIndex];
const compareResult = comparer(newItem, oldItem);
if (compareResult === Comparison.LessThan) {
inserted(newItem);
newIndex++;
}
else if (compareResult === Comparison.GreaterThan) {
deleted(oldItem);
oldIndex++;
}
else {
newIndex++;
oldIndex++;
}
}
while (newIndex < newLen) {
inserted(newItems[newIndex++]);
}
while (oldIndex < oldLen) {
deleted(oldItems[oldIndex++]);
}
}
/* @internal */
export function indent(str: string): string {
return "\n " + str;
-7
View File
@@ -88,13 +88,6 @@ namespace ts {
return createCombinedCodeActions(changes, commands.length === 0 ? undefined : commands);
}
export function codeFixAllWithTextChanges(context: CodeFixAllContext, errorCodes: number[], use: (changes: Push<TextChange>, error: Diagnostic) => void): CombinedCodeActions {
const changes: TextChange[] = [];
eachDiagnostic(context, errorCodes, diag => use(changes, diag));
changes.sort((a, b) => b.span.start - a.span.start);
return createCombinedCodeActions([createFileTextChanges(context.sourceFile.fileName, changes)]);
}
function eachDiagnostic({ program, sourceFile }: CodeFixAllContext, errorCodes: number[], cb: (diag: Diagnostic) => void): void {
for (const diag of program.getSemanticDiagnostics(sourceFile).concat(computeSuggestionDiagnostics(sourceFile, program))) {
if (contains(errorCodes, diag.code)) {
@@ -42,19 +42,28 @@ namespace ts.codefix {
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, decl: DeclarationWithType): void {
if (isFunctionLikeDeclaration(decl) && (getJSDocReturnType(decl) || decl.parameters.some(p => !!getJSDocType(p)))) {
findAncestor(decl, isFunctionLike);
const fn = findAncestor(decl, isFunctionLikeDeclaration);
const functionWithType = addTypesToFunctionLike(fn);
suppressLeadingAndTrailingTrivia(functionWithType);
changes.replaceNode(sourceFile, fn, functionWithType, textChanges.useNonAdjustedPositions);
return;
if (!decl.typeParameters) {
const typeParameters = getJSDocTypeParameterDeclarations(decl);
if (typeParameters) changes.insertTypeParameters(sourceFile, decl, typeParameters);
}
const needParens = isArrowFunction(decl) && !findChildOfKind(decl, SyntaxKind.OpenParenToken, sourceFile);
if (needParens) changes.insertNodeBefore(sourceFile, first(decl.parameters), createToken(SyntaxKind.OpenParenToken));
for (const param of decl.parameters) {
if (!param.type) {
const paramType = getJSDocType(param);
if (paramType) changes.insertTypeAnnotation(sourceFile, param, transformJSDocType(paramType));
}
}
if (needParens) changes.insertNodeAfter(sourceFile, last(decl.parameters), createToken(SyntaxKind.CloseParenToken));
if (!decl.type) {
const returnType = getJSDocReturnType(decl);
if (returnType) changes.insertTypeAnnotation(sourceFile, decl, transformJSDocType(returnType));
}
}
else {
const jsdocType = Debug.assertDefined(getJSDocType(decl)); // If not defined, shouldn't have been an error to fix
Debug.assert(!decl.type); // If defined, shouldn't have been an error to fix.
const declarationWithType = addType(decl, transformJSDocType(jsdocType) as TypeNode);
suppressLeadingAndTrailingTrivia(declarationWithType);
changes.replaceNode(sourceFile, decl, declarationWithType, textChanges.useNonAdjustedPositions);
changes.insertTypeAnnotation(sourceFile, decl, transformJSDocType(jsdocType));
}
}
@@ -65,48 +74,7 @@ namespace ts.codefix {
node.kind === SyntaxKind.PropertyDeclaration;
}
function addTypesToFunctionLike(decl: FunctionLikeDeclaration) {
const typeParameters = getEffectiveTypeParameterDeclarations(decl, /*checkJSDoc*/ true);
const parameters = decl.parameters.map(
p => createParameter(p.decorators, p.modifiers, p.dotDotDotToken, p.name, p.questionToken, transformJSDocType(getEffectiveTypeAnnotationNode(p, /*checkJSDoc*/ true)) as TypeNode, p.initializer));
const returnType = transformJSDocType(getEffectiveReturnTypeNode(decl, /*checkJSDoc*/ true)) as TypeNode;
switch (decl.kind) {
case SyntaxKind.FunctionDeclaration:
return createFunctionDeclaration(decl.decorators, decl.modifiers, decl.asteriskToken, decl.name, typeParameters, parameters, returnType, decl.body);
case SyntaxKind.Constructor:
return createConstructor(decl.decorators, decl.modifiers, parameters, decl.body);
case SyntaxKind.FunctionExpression:
return createFunctionExpression(decl.modifiers, decl.asteriskToken, decl.name, typeParameters, parameters, returnType, decl.body);
case SyntaxKind.ArrowFunction:
return createArrowFunction(decl.modifiers, typeParameters, parameters, returnType, decl.equalsGreaterThanToken, decl.body);
case SyntaxKind.MethodDeclaration:
return createMethod(decl.decorators, decl.modifiers, decl.asteriskToken, decl.name, decl.questionToken, typeParameters, parameters, returnType, decl.body);
case SyntaxKind.GetAccessor:
return createGetAccessor(decl.decorators, decl.modifiers, decl.name, decl.parameters, returnType, decl.body);
case SyntaxKind.SetAccessor:
return createSetAccessor(decl.decorators, decl.modifiers, decl.name, parameters, decl.body);
default:
return Debug.assertNever(decl, `Unexpected SyntaxKind: ${(decl as any).kind}`);
}
}
function addType(decl: DeclarationWithType, jsdocType: TypeNode) {
switch (decl.kind) {
case SyntaxKind.VariableDeclaration:
return createVariableDeclaration(decl.name, jsdocType, decl.initializer);
case SyntaxKind.PropertySignature:
return createPropertySignature(decl.modifiers, decl.name, decl.questionToken, jsdocType, decl.initializer);
case SyntaxKind.PropertyDeclaration:
return createProperty(decl.decorators, decl.modifiers, decl.name, decl.questionToken, jsdocType, decl.initializer);
default:
return Debug.fail(`Unexpected SyntaxKind: ${decl.kind}`);
}
}
function transformJSDocType(node: Node): Node | undefined {
if (node === undefined) {
return undefined;
}
function transformJSDocType(node: TypeNode): TypeNode | undefined {
switch (node.kind) {
case SyntaxKind.JSDocAllType:
case SyntaxKind.JSDocUnknownType:
@@ -121,12 +89,10 @@ namespace ts.codefix {
return transformJSDocVariadicType(node as JSDocVariadicType);
case SyntaxKind.JSDocFunctionType:
return transformJSDocFunctionType(node as JSDocFunctionType);
case SyntaxKind.Parameter:
return transformJSDocParameter(node as ParameterDeclaration);
case SyntaxKind.TypeReference:
return transformJSDocTypeReference(node as TypeReferenceNode);
default:
const visited = visitEachChild(node, transformJSDocType, /*context*/ undefined) as TypeNode;
const visited = visitEachChild(node, transformJSDocType, /*context*/ undefined);
setEmitFlags(visited, EmitFlags.SingleLine);
return visited;
}
@@ -145,8 +111,7 @@ namespace ts.codefix {
}
function transformJSDocFunctionType(node: JSDocFunctionType) {
const parameters = node.parameters && node.parameters.map(transformJSDocType);
return createFunctionTypeNode(emptyArray, parameters as ParameterDeclaration[], node.type);
return createFunctionTypeNode(emptyArray, node.parameters.map(transformJSDocParameter), node.type);
}
function transformJSDocParameter(node: ParameterDeclaration) {
@@ -221,4 +221,4 @@ namespace ts.codefix {
function getModifierKindFromSource(source: Node, kind: SyntaxKind): ReadonlyArray<Modifier> {
return filter(source.modifiers, modifier => modifier.kind === kind);
}
}
}
+43 -34
View File
@@ -9,60 +9,69 @@ namespace ts.codefix {
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile, program, span } = context;
const { sourceFile, program, span, host, formatContext } = context;
if (!isInJavaScriptFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) {
return undefined;
}
const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options);
const fixes: CodeFixAction[] = [
{
description: getLocaleSpecificMessage(Diagnostics.Disable_checking_for_this_file),
changes: [createFileTextChanges(sourceFile.fileName, [
createTextChange(sourceFile.checkJsDirective
? createTextSpanFromBounds(sourceFile.checkJsDirective.pos, sourceFile.checkJsDirective.end)
: createTextSpan(0, 0), `// @ts-nocheck${getNewLineOrDefaultFromHost(host, formatContext.options)}`),
])],
// fixId unnecessary because adding `// @ts-nocheck` even once will ignore every error in the file.
fixId: undefined,
}];
return [{
description: getLocaleSpecificMessage(Diagnostics.Ignore_this_error_message),
changes: [createFileTextChanges(sourceFile.fileName, [getIgnoreCommentLocationForLocation(sourceFile, span.start, newLineCharacter).change])],
fixId,
},
{
description: getLocaleSpecificMessage(Diagnostics.Disable_checking_for_this_file),
changes: [createFileTextChanges(sourceFile.fileName, [
createTextChange(sourceFile.checkJsDirective ? createTextSpanFromBounds(sourceFile.checkJsDirective.pos, sourceFile.checkJsDirective.end) : createTextSpan(0, 0), `// @ts-nocheck${newLineCharacter}`),
])],
// fixId unnecessary because adding `// @ts-nocheck` even once will ignore every error in the file.
fixId: undefined,
}];
if (isValidSuppressLocation(sourceFile, span.start)) {
fixes.unshift({
description: getLocaleSpecificMessage(Diagnostics.Ignore_this_error_message),
changes: textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start)),
fixId,
});
}
return fixes;
},
fixIds: [fixId],
getAllCodeActions: context => {
const seenLines = createMap<true>(); // Only need to add `// @ts-ignore` for a line once.
return codeFixAllWithTextChanges(context, errorCodes, (changes, err) => {
if (err.start !== undefined) {
const { lineNumber, change } = getIgnoreCommentLocationForLocation(err.file!, err.start, getNewLineOrDefaultFromHost(context.host, context.formatContext.options));
if (addToSeen(seenLines, lineNumber)) {
changes.push(change);
}
const seenLines = createMap<true>();
return codeFixAll(context, errorCodes, (changes, diag) => {
if (isValidSuppressLocation(diag.file!, diag.start!)) {
makeChange(changes, diag.file!, diag.start!, seenLines);
}
});
},
});
function getIgnoreCommentLocationForLocation(sourceFile: SourceFile, position: number, newLineCharacter: string): { lineNumber: number, change: TextChange } {
function isValidSuppressLocation(sourceFile: SourceFile, position: number) {
return !isInComment(sourceFile, position) && !isInString(sourceFile, position) && !isInTemplateString(sourceFile, position);
}
function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, seenLines?: Map<true>) {
const { line: lineNumber } = getLineAndCharacterOfPosition(sourceFile, position);
// Only need to add `// @ts-ignore` for a line once.
if (seenLines && !addToSeen(seenLines, lineNumber)) {
return;
}
const lineStartPosition = getStartPositionOfLine(lineNumber, sourceFile);
const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition);
// First try to see if we can put the '// @ts-ignore' on the previous line.
// We need to make sure that we are not in the middle of a string literal or a comment.
// We also want to check if the previous line holds a comment for a node on the next line
// if so, we do not want to separate the node from its comment if we can.
if (!isInComment(sourceFile, startPosition) && !isInString(sourceFile, startPosition) && !isInTemplateString(sourceFile, startPosition)) {
const token = getTouchingToken(sourceFile, startPosition, /*includeJsDocComment*/ false);
const tokenLeadingComments = getLeadingCommentRangesOfNode(token, sourceFile);
if (!tokenLeadingComments || !tokenLeadingComments.length || tokenLeadingComments[0].pos >= startPosition) {
return { lineNumber, change: createTextChangeFromStartLength(startPosition, 0, `// @ts-ignore${newLineCharacter}`) };
}
}
// If so, we do not want to separate the node from its comment if we can.
// Otherwise, add an extra new line immediately before the error span.
const insertAtLineStart = isValidSuppressLocation(sourceFile, startPosition);
// If all fails, add an extra new line immediately before the error span.
return { lineNumber, change: createTextChangeFromStartLength(position, 0, `${position === startPosition ? "" : newLineCharacter}// @ts-ignore${newLineCharacter}`) };
const token = getTouchingToken(sourceFile, insertAtLineStart ? startPosition : position, /*includeJsDocComment*/ false);
const clone = setStartsOnNewLine(getSynthesizedDeepClone(token), true);
addSyntheticLeadingComment(clone, SyntaxKind.SingleLineCommentTrivia, " @ts-ignore");
changes.replaceNode(sourceFile, token, clone, { preserveLeadingWhitespace: true, prefix: insertAtLineStart ? undefined : changes.newLineCharacter });
}
}
+10 -16
View File
@@ -21,42 +21,36 @@ namespace ts.codefix {
return actions;
function fix(type: Type, fixId: string): CodeFixAction {
const newText = typeString(type, checker);
return {
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_0_to_1), [original, newText]),
changes: [createFileTextChanges(sourceFile.fileName, [createChange(typeNode, sourceFile, newText)])],
fixId,
};
const newText = checker.typeToString(type);
const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_0_to_1), [original, newText]);
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, typeNode, type, checker));
return { description, changes, fixId };
}
},
fixIds: [fixIdPlain, fixIdNullable],
getAllCodeActions(context) {
const { fixId, program, sourceFile } = context;
const checker = program.getTypeChecker();
return codeFixAllWithTextChanges(context, errorCodes, (changes, err) => {
return codeFixAll(context, errorCodes, (changes, err) => {
const info = getInfo(err.file, err.start!, checker);
if (!info) return;
const { typeNode, type } = info;
const fixedType = typeNode.kind === SyntaxKind.JSDocNullableType && fixId === fixIdNullable ? checker.getNullableType(type, TypeFlags.Undefined) : type;
changes.push(createChange(typeNode, sourceFile, typeString(fixedType, checker)));
doChange(changes, sourceFile, typeNode, fixedType, checker);
});
}
});
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, oldTypeNode: TypeNode, newType: Type, checker: TypeChecker): void {
changes.replaceNode(sourceFile, oldTypeNode, checker.typeToTypeNode(newType, /*enclosingDeclaration*/ oldTypeNode));
}
function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { readonly typeNode: TypeNode, type: Type } {
const decl = findAncestor(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false), isTypeContainer);
const typeNode = decl && decl.type;
return typeNode && { typeNode, type: checker.getTypeFromTypeNode(typeNode) };
}
function createChange(declaration: TypeNode, sourceFile: SourceFile, newText: string): TextChange {
return createTextChange(createTextSpanFromNode(declaration, sourceFile), newText);
}
function typeString(type: Type, checker: TypeChecker): string {
return checker.typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTruncation);
}
// TODO: GH#19856 Node & { type: TypeNode }
type TypeContainer =
| AsExpression | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionDeclaration
+27 -7
View File
@@ -5,12 +5,20 @@ namespace ts.codefix {
const errorCodes = [
Diagnostics._0_is_declared_but_its_value_is_never_read.code,
Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code,
Diagnostics.All_imports_in_import_declaration_are_unused.code,
];
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile } = context;
const token = getToken(sourceFile, context.span.start);
const { errorCode, sourceFile } = context;
const importDecl = tryGetFullImport(sourceFile, context.span.start);
if (importDecl) {
const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_import_from_0), [showModuleSpecifier(importDecl)]);
const changes = textChanges.ChangeTracker.with(context, t => t.deleteNode(sourceFile, importDecl));
return [{ description, changes, fixId: fixIdDelete }];
}
const token = getToken(sourceFile, textSpanEnd(context.span));
const result: CodeFixAction[] = [];
const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token));
@@ -19,7 +27,7 @@ namespace ts.codefix {
result.push({ description, changes: deletion, fixId: fixIdDelete });
}
const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, context.errorCode, sourceFile, token));
const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, errorCode, sourceFile, token));
if (prefix.length) {
const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Prefix_0_with_an_underscore), [token.getText()]);
result.push({ description, changes: prefix, fixId: fixIdPrefix });
@@ -30,7 +38,7 @@ namespace ts.codefix {
fixIds: [fixIdPrefix, fixIdDelete],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const { sourceFile } = context;
const token = getToken(diag.file!, diag.start!);
const token = findPrecedingToken(textSpanEnd(diag), diag.file!);
switch (context.fixId) {
case fixIdPrefix:
if (isIdentifier(token) && canPrefix(token)) {
@@ -38,7 +46,13 @@ namespace ts.codefix {
}
break;
case fixIdDelete:
tryDeleteDeclaration(changes, sourceFile, token);
const importDecl = tryGetFullImport(diag.file!, diag.start!);
if (importDecl) {
changes.deleteNode(sourceFile, importDecl);
}
else {
tryDeleteDeclaration(changes, sourceFile, token);
}
break;
default:
Debug.fail(JSON.stringify(context.fixId));
@@ -46,10 +60,16 @@ namespace ts.codefix {
}),
});
// Sometimes the diagnostic span is an entire ImportDeclaration, so we should remove the whole thing.
function tryGetFullImport(sourceFile: SourceFile, pos: number): ImportDeclaration | undefined {
const startToken = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
return startToken.kind === SyntaxKind.ImportKeyword ? tryCast(startToken.parent, isImportDeclaration) : undefined;
}
function getToken(sourceFile: SourceFile, pos: number): Node {
const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
const token = findPrecedingToken(pos, sourceFile);
// this handles var ["computed"] = 12;
return token.kind === SyntaxKind.OpenBracketToken ? getTokenAtPosition(sourceFile, pos + 1, /*includeJsDocComment*/ false) : token;
return token.kind === SyntaxKind.CloseBracketToken ? findPrecedingToken(pos - 1, sourceFile) : token;
}
function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void {
+69 -106
View File
@@ -24,27 +24,26 @@ namespace ts.codefix {
];
registerCodeFix({
errorCodes,
getCodeActions({ sourceFile, program, span: { start }, errorCode, cancellationToken }) {
getCodeActions(context) {
const { sourceFile, program, span: { start }, errorCode, cancellationToken } = context;
if (isSourceFileJavaScript(sourceFile)) {
return undefined; // TODO: GH#20113
}
const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false);
const fix = getFix(sourceFile, token, errorCode, program, cancellationToken);
if (!fix) return undefined;
const { declaration, textChanges } = fix;
const name = getNameOfDeclaration(declaration);
const description = formatStringFromArgs(getLocaleSpecificMessage(getDiagnostic(errorCode, token)), [name.getText()]);
return [{ description, changes: [{ fileName: sourceFile.fileName, textChanges }], fixId }];
let declaration!: Declaration;
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken); });
if (changes.length === 0) return undefined;
const name = getNameOfDeclaration(declaration).getText();
const description = formatStringFromArgs(getLocaleSpecificMessage(getDiagnostic(errorCode, token)), [name]);
return [{ description, changes, fixId }];
},
fixIds: [fixId],
getAllCodeActions(context) {
const { sourceFile, program, cancellationToken } = context;
const seenFunctions = createMap<true>();
return codeFixAllWithTextChanges(context, errorCodes, (changes, err) => {
const fix = getFix(sourceFile, getTokenAtPosition(err.file!, err.start!, /*includeJsDocComment*/ false), err.code, program, cancellationToken, seenFunctions);
if (fix) changes.push(...fix.textChanges);
return codeFixAll(context, errorCodes, (changes, err) => {
doChange(changes, sourceFile, getTokenAtPosition(err.file!, err.start!, /*includeJsDocComment*/ false), err.code, program, cancellationToken, seenFunctions);
});
},
});
@@ -60,12 +59,7 @@ namespace ts.codefix {
}
}
interface Fix {
readonly declaration: Declaration;
readonly textChanges: TextChange[];
}
function getFix(sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, seenFunctions?: Map<true>): Fix | undefined {
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, seenFunctions?: Map<true>): Declaration | undefined {
if (!isAllowedTokenKind(token.kind)) {
return undefined;
}
@@ -74,11 +68,15 @@ namespace ts.codefix {
// Variable and Property declarations
case Diagnostics.Member_0_implicitly_has_an_1_type.code:
case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code:
return getCodeActionForVariableDeclaration(<PropertyDeclaration | PropertySignature | VariableDeclaration>token.parent, program, cancellationToken);
annotateVariableDeclaration(changes, sourceFile, <PropertyDeclaration | PropertySignature | VariableDeclaration>token.parent, program, cancellationToken);
return token.parent as Declaration;
case Diagnostics.Variable_0_implicitly_has_an_1_type.code: {
const symbol = program.getTypeChecker().getSymbolAtLocation(token);
return symbol && symbol.valueDeclaration && getCodeActionForVariableDeclaration(<VariableDeclaration>symbol.valueDeclaration, program, cancellationToken);
if (symbol && symbol.valueDeclaration) {
annotateVariableDeclaration(changes, sourceFile, <VariableDeclaration>symbol.valueDeclaration, program, cancellationToken);
return symbol.valueDeclaration;
}
}
}
@@ -91,22 +89,34 @@ namespace ts.codefix {
// Parameter declarations
case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
if (isSetAccessor(containingFunction)) {
return getCodeActionForSetAccessor(containingFunction, program, cancellationToken);
annotateSetAccessor(changes, sourceFile, containingFunction, program, cancellationToken);
return containingFunction;
}
// falls through
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
return !seenFunctions || addToSeen(seenFunctions, getNodeId(containingFunction))
? getCodeActionForParameters(cast(token.parent, isParameter), containingFunction, sourceFile, program, cancellationToken)
: undefined;
if (!seenFunctions || addToSeen(seenFunctions, getNodeId(containingFunction))) {
const param = cast(token.parent, isParameter);
annotateParameters(changes, param, containingFunction, sourceFile, program, cancellationToken);
return param;
}
return undefined;
// Get Accessor declarations
case Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code:
case Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type.code:
return isGetAccessor(containingFunction) ? getCodeActionForGetAccessor(containingFunction, sourceFile, program, cancellationToken) : undefined;
if (isGetAccessor(containingFunction) && isIdentifier(containingFunction.name)) {
annotate(changes, sourceFile, containingFunction, inferTypeForVariableFromUsage(containingFunction.name, program, cancellationToken), program);
return containingFunction;
}
return undefined;
// Set Accessor declarations
case Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code:
return isSetAccessor(containingFunction) ? getCodeActionForSetAccessor(containingFunction, program, cancellationToken) : undefined;
if (isSetAccessor(containingFunction)) {
annotateSetAccessor(changes, sourceFile, containingFunction, program, cancellationToken);
return containingFunction;
}
return undefined;
default:
return Debug.fail(String(errorCode));
@@ -127,10 +137,10 @@ namespace ts.codefix {
}
}
function getCodeActionForVariableDeclaration(declaration: VariableDeclaration | PropertyDeclaration | PropertySignature, program: Program, cancellationToken: CancellationToken): Fix | undefined {
if (!isIdentifier(declaration.name)) return undefined;
const type = inferTypeForVariableFromUsage(declaration.name, program, cancellationToken);
return makeFix(declaration, declaration.name.getEnd(), type, program);
function annotateVariableDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: VariableDeclaration | PropertyDeclaration | PropertySignature, program: Program, cancellationToken: CancellationToken): void {
if (isIdentifier(declaration.name)) {
annotate(changes, sourceFile, declaration, inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), program);
}
}
function isApplicableFunctionForInference(declaration: FunctionLike): declaration is MethodDeclaration | FunctionDeclaration | ConstructorDeclaration {
@@ -145,53 +155,51 @@ namespace ts.codefix {
return false;
}
function getCodeActionForParameters(parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): Fix | undefined {
function annotateParameters(changes: textChanges.ChangeTracker, parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): void {
if (!isIdentifier(parameterDeclaration.name) || !isApplicableFunctionForInference(containingFunction)) {
return undefined;
return;
}
const types = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
containingFunction.parameters.map(p => isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : undefined);
if (!types) return undefined;
// We didn't actually find a set of type inference positions matching each parameter position
if (containingFunction.parameters.length !== types.length) {
return undefined;
if (!types || containingFunction.parameters.length !== types.length) {
return;
}
const textChanges = arrayFrom(mapDefinedIterator(zipToIterator(containingFunction.parameters, types), ([parameter, type]) =>
type && !parameter.type && !parameter.initializer ? makeChange(containingFunction, parameter.end, type, program) : undefined));
return textChanges.length ? { declaration: parameterDeclaration, textChanges } : undefined;
zipWith(containingFunction.parameters, types, (parameter, type) => {
if (!parameter.type && !parameter.initializer) {
annotate(changes, sourceFile, parameter, type, program);
}
});
}
function getCodeActionForSetAccessor(setAccessorDeclaration: SetAccessorDeclaration, program: Program, cancellationToken: CancellationToken): Fix | undefined {
const setAccessorParameter = setAccessorDeclaration.parameters[0];
if (!setAccessorParameter || !isIdentifier(setAccessorDeclaration.name) || !isIdentifier(setAccessorParameter.name)) {
return undefined;
function annotateSetAccessor(changes: textChanges.ChangeTracker, sourceFile: SourceFile, setAccessorDeclaration: SetAccessorDeclaration, program: Program, cancellationToken: CancellationToken): void {
const param = firstOrUndefined(setAccessorDeclaration.parameters);
if (param && isIdentifier(setAccessorDeclaration.name) && isIdentifier(param.name)) {
const type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, program, cancellationToken) ||
inferTypeForVariableFromUsage(param.name, program, cancellationToken);
annotate(changes, sourceFile, param, type, program);
}
const type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, program, cancellationToken) ||
inferTypeForVariableFromUsage(setAccessorParameter.name, program, cancellationToken);
return makeFix(setAccessorParameter, setAccessorParameter.name.getEnd(), type, program);
}
function getCodeActionForGetAccessor(getAccessorDeclaration: GetAccessorDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): Fix | undefined {
if (!isIdentifier(getAccessorDeclaration.name)) {
return undefined;
}
const type = inferTypeForVariableFromUsage(getAccessorDeclaration.name, program, cancellationToken);
const closeParenToken = findChildOfKind(getAccessorDeclaration, SyntaxKind.CloseParenToken, sourceFile);
return makeFix(getAccessorDeclaration, closeParenToken.getEnd(), type, program);
function annotate(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: textChanges.TypeAnnotatable, type: Type | undefined, program: Program): void {
const typeNode = type && getTypeNodeIfAccessible(type, declaration, program.getTypeChecker());
if (typeNode) changes.insertTypeAnnotation(sourceFile, declaration, typeNode);
}
function makeFix(declaration: Declaration, start: number, type: Type | undefined, program: Program): Fix | undefined {
return type && { declaration, textChanges: [makeChange(declaration, start, type, program)] };
}
function makeChange(declaration: Declaration, start: number, type: Type | undefined, program: Program): TextChange | undefined {
const typeString = type && typeToString(type, declaration, program.getTypeChecker());
return typeString === undefined ? undefined : createTextChangeFromStartLength(start, 0, `: ${typeString}`);
function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, checker: TypeChecker): TypeNode | undefined {
let typeIsAccessible = true;
const notAccessible = () => { typeIsAccessible = false; };
const res = checker.typeToTypeNode(type, enclosingScope, /*flags*/ undefined, {
trackSymbol: (symbol, declaration, meaning) => {
typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible;
},
reportInaccessibleThisError: notAccessible,
reportPrivateInBaseOfClassExpression: notAccessible,
reportInaccessibleUniqueSymbolError: notAccessible,
});
return typeIsAccessible ? res : undefined;
}
function getReferences(token: PropertyName | Token<SyntaxKind.ConstructorKeyword>, program: Program, cancellationToken: CancellationToken): ReadonlyArray<Identifier> {
@@ -220,51 +228,6 @@ namespace ts.codefix {
}
}
function getTypeAccessiblityWriter(checker: TypeChecker): EmitTextWriter {
let str = "";
let typeIsAccessible = true;
const writeText: (text: string) => void = text => str += text;
return {
getText: () => typeIsAccessible ? str : undefined,
writeKeyword: writeText,
writeOperator: writeText,
writePunctuation: writeText,
writeSpace: writeText,
writeStringLiteral: writeText,
writeParameter: writeText,
writeProperty: writeText,
writeSymbol: writeText,
write: writeText,
writeTextOfNode: writeText,
rawWrite: writeText,
writeLiteral: writeText,
getTextPos: () => 0,
getLine: () => 0,
getColumn: () => 0,
getIndent: () => 0,
isAtStartOfLine: () => false,
writeLine: () => writeText(" "),
increaseIndent: noop,
decreaseIndent: noop,
clear: () => { str = ""; typeIsAccessible = true; },
trackSymbol: (symbol, declaration, meaning) => {
if (checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility !== SymbolAccessibility.Accessible) {
typeIsAccessible = false;
}
},
reportInaccessibleThisError: () => { typeIsAccessible = false; },
reportPrivateInBaseOfClassExpression: () => { typeIsAccessible = false; },
reportInaccessibleUniqueSymbolError: () => { typeIsAccessible = false; }
};
}
function typeToString(type: Type, enclosingDeclaration: Declaration, checker: TypeChecker): string {
const writer = getTypeAccessiblityWriter(checker);
checker.writeType(type, enclosingDeclaration, /*flags*/ undefined, writer);
return writer.getText();
}
namespace InferFromReference {
interface CallContext {
argumentTypes: Type[];
+1
View File
@@ -275,6 +275,7 @@ namespace ts.NavigationBar {
case SpecialPropertyAssignmentKind.ExportsProperty:
case SpecialPropertyAssignmentKind.ModuleExports:
case SpecialPropertyAssignmentKind.PrototypeProperty:
case SpecialPropertyAssignmentKind.Prototype:
addNodeWithRecursiveChild(node, (node as BinaryExpression).right);
break;
case SpecialPropertyAssignmentKind.ThisProperty:
+34 -3
View File
@@ -94,6 +94,10 @@ namespace ts.textChanges {
* Text of inserted node will be formatted with this delta, otherwise delta will be inferred from the new node kind
*/
delta?: number;
/**
* Do not trim leading white spaces in the edit range
*/
preserveLeadingWhitespace?: boolean;
}
enum ChangeKind {
@@ -136,7 +140,7 @@ namespace ts.textChanges {
export function getAdjustedStartPosition(sourceFile: SourceFile, node: Node, options: ConfigurableStart, position: Position) {
if (options.useNonAdjustedStartPosition) {
return node.getStart();
return node.getStart(sourceFile);
}
const fullStart = node.getFullStart();
const start = node.getStart(sourceFile);
@@ -195,6 +199,8 @@ namespace ts.textChanges {
formatContext: formatting.FormatContext;
}
export type TypeAnnotatable = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature;
export class ChangeTracker {
private readonly changes: Change[] = [];
private readonly deletedNodesInLists: true[] = []; // Stores ids of nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`.
@@ -212,7 +218,7 @@ namespace ts.textChanges {
}
/** Public for tests only. Other callers should use `ChangeTracker.with`. */
constructor(private readonly newLineCharacter: string, private readonly formatContext: formatting.FormatContext) {}
constructor(public readonly newLineCharacter: string, private readonly formatContext: formatting.FormatContext) {}
public deleteRange(sourceFile: SourceFile, range: TextRange) {
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range });
@@ -321,6 +327,10 @@ namespace ts.textChanges {
return this;
}
private insertNodesAt(sourceFile: SourceFile, pos: number, newNodes: ReadonlyArray<Node>, options: InsertNodeOptions = {}): void {
this.changes.push({ kind: ChangeKind.ReplaceWithMultipleNodes, sourceFile, options, nodes: newNodes, range: { pos, end: pos } });
}
public insertNodeAtTopOfFile(sourceFile: SourceFile, newNode: Statement, blankLineBetween: boolean): void {
const pos = getInsertionPositionAtSourceFileTop(sourceFile);
this.insertNodeAt(sourceFile, pos, newNode, {
@@ -339,6 +349,21 @@ namespace ts.textChanges {
this.replaceRange(sourceFile, { pos, end: pos }, createToken(modifier), { suffix: " " });
}
/** Prefer this over replacing a node with another that has a type annotation, as it avoids reformatting the other parts of the node. */
public insertTypeAnnotation(sourceFile: SourceFile, node: TypeAnnotatable, type: TypeNode): void {
const end = (isFunctionLike(node)
// If no `)`, is an arrow function `x => x`, so use the end of the first parameter
? findChildOfKind(node, SyntaxKind.CloseParenToken, sourceFile) || first(node.parameters)
: node.kind !== SyntaxKind.VariableDeclaration && node.questionToken ? node.questionToken : node.name).end;
this.insertNodeAt(sourceFile, end, type, { prefix: ": " });
}
public insertTypeParameters(sourceFile: SourceFile, node: SignatureDeclaration, typeParameters: ReadonlyArray<TypeParameterDeclaration>): void {
// If no `(`, is an arrow function `x => x`, so use the pos of the first parameter
const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart(sourceFile);
this.insertNodesAt(sourceFile, start, typeParameters, { prefix: "<", suffix: ">" });
}
private getOptionsForInsertNodeBefore(before: Node, doubleNewlines: boolean): ChangeNodeOptions {
if (isStatement(before) || isClassElement(before)) {
return { suffix: doubleNewlines ? this.newLineCharacter + this.newLineCharacter : this.newLineCharacter };
@@ -346,6 +371,9 @@ namespace ts.textChanges {
else if (isVariableDeclaration(before)) { // insert `x = 1, ` into `const x = 1, y = 2;
return { suffix: ", " };
}
else if (isParameter(before)) {
return {};
}
return Debug.failBadSyntaxKind(before); // We haven't handled this kind of node yet -- add it
}
@@ -430,6 +458,9 @@ namespace ts.textChanges {
else if (isVariableDeclaration(node)) {
return { prefix: ", " };
}
else if (isParameter(node)) {
return {};
}
return Debug.failBadSyntaxKind(node); // We haven't handled this kind of node yet -- add it
}
@@ -628,7 +659,7 @@ namespace ts.textChanges {
? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(newLineCharacter)
: format(change.node);
// strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
const noIndent = (options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, "");
const noIndent = (options.preserveLeadingWhitespace || options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, "");
return (options.prefix || "") + noIndent + (options.suffix || "");
}
+26 -31
View File
@@ -359,6 +359,8 @@ namespace ts {
case SpecialPropertyAssignmentKind.Property:
// static method / property
return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement;
case SpecialPropertyAssignmentKind.Prototype:
return ScriptElementKind.localClassElement;
default: {
assertTypeIsNever(kind);
return ScriptElementKind.unknown;
@@ -1386,37 +1388,30 @@ namespace ts {
*/
/* @internal */
export function suppressLeadingAndTrailingTrivia(node: Node) {
Debug.assert(node !== undefined);
suppressLeading(node);
suppressTrailing(node);
function suppressLeading(node: Node) {
addEmitFlags(node, EmitFlags.NoLeadingComments);
const firstChild = forEachChild(node, child => child);
if (firstChild) {
suppressLeading(firstChild);
}
}
function suppressTrailing(node: Node) {
addEmitFlags(node, EmitFlags.NoTrailingComments);
let lastChild: Node;
forEachChild(
node,
child => (lastChild = child, undefined),
children => {
// As an optimization, jump straight to the end of the list.
if (children.length) {
lastChild = last(children);
}
return undefined;
});
if (lastChild) {
suppressTrailing(lastChild);
}
Debug.assertDefined(node);
suppress(node, EmitFlags.NoLeadingComments, getFirstChild);
suppress(node, EmitFlags.NoTrailingComments, getLastChild);
function suppress(node: Node, flag: EmitFlags, getChild: (n: Node) => Node) {
addEmitFlags(node, flag);
const child = getChild(node);
if (child) suppress(child, flag, getChild);
}
}
function getFirstChild(node: Node): Node | undefined {
return node.forEachChild(child => child);
}
function getLastChild(node: Node): Node | undefined {
let lastChild: Node | undefined;
node.forEachChild(
child => { lastChild = child; },
children => {
// As an optimization, jump straight to the end of the list.
if (children.length) {
lastChild = last(children);
}
});
return lastChild;
}
}
+50 -28
View File
@@ -644,7 +644,8 @@ declare namespace ts {
body?: Block | Expression;
}
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionExpression | ArrowFunction;
type FunctionLike = FunctionLikeDeclaration | FunctionTypeNode | ConstructorTypeNode | IndexSignatureDeclaration | MethodSignature | ConstructSignatureDeclaration | CallSignatureDeclaration | JSDocFunctionType;
/** @deprecated Use SignatureDeclaration */
type FunctionLike = SignatureDeclaration;
interface FunctionDeclaration extends FunctionLikeDeclarationBase, DeclarationStatement {
kind: SyntaxKind.FunctionDeclaration;
name?: Identifier;
@@ -1801,7 +1802,7 @@ declare namespace ts {
*/
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature;
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature | undefined;
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined;
isUndefinedSymbol(symbol: Symbol): boolean;
isArgumentsSymbol(symbol: Symbol): boolean;
isUnknownSymbol(symbol: Symbol): boolean;
@@ -1960,28 +1961,28 @@ declare namespace ts {
JSContainer = 67108864,
Enum = 384,
Variable = 3,
Value = 107455,
Type = 793064,
Value = 67216319,
Type = 67901928,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 107454,
BlockScopedVariableExcludes = 107455,
ParameterExcludes = 107455,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
PropertyExcludes = 0,
EnumMemberExcludes = 900095,
FunctionExcludes = 106927,
ClassExcludes = 899519,
InterfaceExcludes = 792968,
RegularEnumExcludes = 899327,
ConstEnumExcludes = 899967,
ValueModuleExcludes = 106639,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
NamespaceModuleExcludes = 0,
MethodExcludes = 99263,
GetAccessorExcludes = 41919,
SetAccessorExcludes = 74687,
TypeParameterExcludes = 530920,
TypeAliasExcludes = 793064,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
@@ -2749,6 +2750,7 @@ declare namespace ts {
newLine?: NewLineKind;
omitTrailingSemicolon?: boolean;
}
/** @deprecated See comment on SymbolWriter */
interface SymbolTracker {
trackSymbol?(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
reportInaccessibleThisError?(): void;
@@ -2854,11 +2856,6 @@ declare namespace ts {
}
type FileWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind) => void;
type DirectoryWatcherCallback = (fileName: string) => void;
interface WatchedFile {
fileName: string;
callback: FileWatcherCallback;
mtime?: Date;
}
interface System {
args: string[];
newLine: string;
@@ -3215,7 +3212,7 @@ declare namespace ts {
function isEntityName(node: Node): node is EntityName;
function isPropertyName(node: Node): node is PropertyName;
function isBindingName(node: Node): node is BindingName;
function isFunctionLike(node: Node): node is FunctionLike;
function isFunctionLike(node: Node): node is SignatureDeclaration;
function isClassElement(node: Node): node is ClassElement;
function isClassLike(node: Node): node is ClassLikeDeclaration;
function isAccessor(node: Node): node is AccessorDeclaration;
@@ -5066,6 +5063,7 @@ declare namespace ts.server.protocol {
OpenExternalProject = "openExternalProject",
OpenExternalProjects = "openExternalProjects",
CloseExternalProject = "closeExternalProject",
GetOutliningSpans = "getOutliningSpans",
TodoComments = "todoComments",
Indentation = "indentation",
DocCommentTemplate = "docCommentTemplate",
@@ -5224,6 +5222,31 @@ declare namespace ts.server.protocol {
*/
onlyMultiLine: boolean;
}
/**
* Request to obtain outlining spans in file.
*/
interface OutliningSpansRequest extends FileRequest {
command: CommandTypes.GetOutliningSpans;
}
interface OutliningSpan {
/** The span of the document to actually collapse. */
textSpan: TextSpan;
/** The span of the document to display when the user hovers over the collapsed span. */
hintSpan: TextSpan;
/** The text to display in the editor for the collapsed region. */
bannerText: string;
/**
* Whether or not this region should be automatically collapsed when
* the 'Collapse to Definitions' command is invoked.
*/
autoCollapse: boolean;
}
/**
* Response to OutliningSpansRequest request.
*/
interface OutliningSpansResponse extends Response {
body?: OutliningSpan[];
}
/**
* A request to get indentation for a location in file
*/
@@ -7275,7 +7298,7 @@ declare namespace ts.server {
private getFileAndProject(args);
private getFileAndLanguageServiceForSyntacticOperation(args);
private getFileAndProjectWorker(uncheckedFileName, projectFileName);
private getOutliningSpans(args);
private getOutliningSpans(args, simplifiedResult);
private getTodoComments(args);
private getDocCommentTemplate(args);
private getSpanOfEnclosingComment(args);
@@ -7831,7 +7854,6 @@ declare namespace ts.server {
/** Tracks projects that we have already sent telemetry for. */
private readonly seenProjects;
constructor(opts: ProjectServiceOptions);
private createWatcherLog(watchType, project);
toPath(fileName: string): Path;
private loadTypesMap();
updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse): void;
@@ -7853,7 +7875,7 @@ declare namespace ts.server {
private ensureProjectStructuresUptoDate();
private updateProjectIfDirty(project);
getFormatCodeOptions(file?: NormalizedPath): FormatCodeSettings;
private onSourceFileChanged(fileName, eventKind);
private onSourceFileChanged(fileName, eventKind, path);
private handleDeletedFile(info);
private onConfigChangedForConfiguredProject(project, eventKind);
/**
+22 -25
View File
@@ -644,7 +644,8 @@ declare namespace ts {
body?: Block | Expression;
}
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionExpression | ArrowFunction;
type FunctionLike = FunctionLikeDeclaration | FunctionTypeNode | ConstructorTypeNode | IndexSignatureDeclaration | MethodSignature | ConstructSignatureDeclaration | CallSignatureDeclaration | JSDocFunctionType;
/** @deprecated Use SignatureDeclaration */
type FunctionLike = SignatureDeclaration;
interface FunctionDeclaration extends FunctionLikeDeclarationBase, DeclarationStatement {
kind: SyntaxKind.FunctionDeclaration;
name?: Identifier;
@@ -1801,7 +1802,7 @@ declare namespace ts {
*/
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature;
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature | undefined;
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined;
isUndefinedSymbol(symbol: Symbol): boolean;
isArgumentsSymbol(symbol: Symbol): boolean;
isUnknownSymbol(symbol: Symbol): boolean;
@@ -1960,28 +1961,28 @@ declare namespace ts {
JSContainer = 67108864,
Enum = 384,
Variable = 3,
Value = 107455,
Type = 793064,
Value = 67216319,
Type = 67901928,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 107454,
BlockScopedVariableExcludes = 107455,
ParameterExcludes = 107455,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
PropertyExcludes = 0,
EnumMemberExcludes = 900095,
FunctionExcludes = 106927,
ClassExcludes = 899519,
InterfaceExcludes = 792968,
RegularEnumExcludes = 899327,
ConstEnumExcludes = 899967,
ValueModuleExcludes = 106639,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
NamespaceModuleExcludes = 0,
MethodExcludes = 99263,
GetAccessorExcludes = 41919,
SetAccessorExcludes = 74687,
TypeParameterExcludes = 530920,
TypeAliasExcludes = 793064,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
@@ -2749,6 +2750,7 @@ declare namespace ts {
newLine?: NewLineKind;
omitTrailingSemicolon?: boolean;
}
/** @deprecated See comment on SymbolWriter */
interface SymbolTracker {
trackSymbol?(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
reportInaccessibleThisError?(): void;
@@ -2854,11 +2856,6 @@ declare namespace ts {
}
type FileWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind) => void;
type DirectoryWatcherCallback = (fileName: string) => void;
interface WatchedFile {
fileName: string;
callback: FileWatcherCallback;
mtime?: Date;
}
interface System {
args: string[];
newLine: string;
@@ -3270,7 +3267,7 @@ declare namespace ts {
function isEntityName(node: Node): node is EntityName;
function isPropertyName(node: Node): node is PropertyName;
function isBindingName(node: Node): node is BindingName;
function isFunctionLike(node: Node): node is FunctionLike;
function isFunctionLike(node: Node): node is SignatureDeclaration;
function isClassElement(node: Node): node is ClassElement;
function isClassLike(node: Node): node is ClassLikeDeclaration;
function isAccessor(node: Node): node is AccessorDeclaration;
@@ -0,0 +1,74 @@
=== tests/cases/conformance/salsa/mod.js ===
exports.n = {};
>exports.n : Symbol(n, Decl(mod.js, 0, 0))
>exports : Symbol(n, Decl(mod.js, 0, 0))
>n : Symbol(n, Decl(mod.js, 0, 0))
exports.n.K = function () {
>exports.n.K : Symbol(K, Decl(mod.js, 0, 15))
>exports.n : Symbol(K, Decl(mod.js, 0, 15))
>exports : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0))
>n : Symbol(n, Decl(mod.js, 0, 0))
>K : Symbol(K, Decl(mod.js, 0, 15))
this.x = 10;
>this : Symbol(__object, Decl(mod.js, 0, 11), Decl(mod.js, 1, 8))
>x : Symbol((Anonymous function).x, Decl(mod.js, 1, 27))
}
exports.Classic = class {
>exports.Classic : Symbol(Classic, Decl(mod.js, 3, 1))
>exports : Symbol(Classic, Decl(mod.js, 3, 1))
>Classic : Symbol(Classic, Decl(mod.js, 3, 1))
constructor() {
this.p = 1
>this.p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
>this : Symbol((Anonymous class), Decl(mod.js, 4, 17))
>p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
}
}
=== tests/cases/conformance/salsa/use.js ===
import * as s from './mod'
>s : Symbol(s, Decl(use.js, 0, 6))
var k = new s.n.K()
>k : Symbol(k, Decl(use.js, 2, 3))
>s.n.K : Symbol(K, Decl(mod.js, 0, 15))
>s.n : Symbol(s.n, Decl(mod.js, 0, 0))
>s : Symbol(s, Decl(use.js, 0, 6))
>n : Symbol(s.n, Decl(mod.js, 0, 0))
>K : Symbol(K, Decl(mod.js, 0, 15))
k.x
>k.x : Symbol((Anonymous function).x, Decl(mod.js, 1, 27))
>k : Symbol(k, Decl(use.js, 2, 3))
>x : Symbol((Anonymous function).x, Decl(mod.js, 1, 27))
var classic = new s.Classic()
>classic : Symbol(classic, Decl(use.js, 4, 3))
>s.Classic : Symbol(s.Classic, Decl(mod.js, 3, 1))
>s : Symbol(s, Decl(use.js, 0, 6))
>Classic : Symbol(s.Classic, Decl(mod.js, 3, 1))
/** @param {s.n.K} c
@param {s.Classic} classic */
function f(c, classic) {
>f : Symbol(f, Decl(use.js, 4, 29))
>c : Symbol(c, Decl(use.js, 9, 11))
>classic : Symbol(classic, Decl(use.js, 9, 13))
c.x
>c.x : Symbol((Anonymous function).x, Decl(mod.js, 1, 27))
>c : Symbol(c, Decl(use.js, 9, 11))
>x : Symbol((Anonymous function).x, Decl(mod.js, 1, 27))
classic.p
>classic.p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
>classic : Symbol(classic, Decl(use.js, 9, 13))
>p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
}
@@ -0,0 +1,87 @@
=== tests/cases/conformance/salsa/mod.js ===
exports.n = {};
>exports.n = {} : typeof __object
>exports.n : typeof __object
>exports : typeof "tests/cases/conformance/salsa/mod"
>n : typeof __object
>{} : typeof __object
exports.n.K = function () {
>exports.n.K = function () { this.x = 10;} : () => void
>exports.n.K : () => void
>exports.n : typeof __object
>exports : typeof "tests/cases/conformance/salsa/mod"
>n : typeof __object
>K : () => void
>function () { this.x = 10;} : () => void
this.x = 10;
>this.x = 10 : 10
>this.x : any
>this : typeof __object
>x : any
>10 : 10
}
exports.Classic = class {
>exports.Classic = class { constructor() { this.p = 1 }} : typeof (Anonymous class)
>exports.Classic : typeof (Anonymous class)
>exports : typeof "tests/cases/conformance/salsa/mod"
>Classic : typeof (Anonymous class)
>class { constructor() { this.p = 1 }} : typeof (Anonymous class)
constructor() {
this.p = 1
>this.p = 1 : 1
>this.p : number
>this : this
>p : number
>1 : 1
}
}
=== tests/cases/conformance/salsa/use.js ===
import * as s from './mod'
>s : typeof s
var k = new s.n.K()
>k : { x: number; }
>new s.n.K() : { x: number; }
>s.n.K : () => void
>s.n : typeof __object
>s : typeof s
>n : typeof __object
>K : () => void
k.x
>k.x : number
>k : { x: number; }
>x : number
var classic = new s.Classic()
>classic : (Anonymous class)
>new s.Classic() : (Anonymous class)
>s.Classic : typeof (Anonymous class)
>s : typeof s
>Classic : typeof (Anonymous class)
/** @param {s.n.K} c
@param {s.Classic} classic */
function f(c, classic) {
>f : (c: { x: number; }, classic: (Anonymous class)) => void
>c : { x: number; }
>classic : (Anonymous class)
c.x
>c.x : number
>c : { x: number; }
>x : number
classic.p
>classic.p : number
>classic : (Anonymous class)
>p : number
}
@@ -0,0 +1,40 @@
tests/cases/conformance/salsa/first.js(1,1): error TS2539: Cannot assign to '"tests/cases/conformance/salsa/first"' because it is not a variable.
tests/cases/conformance/salsa/first.js(1,11): error TS2304: Cannot find name 'require'.
tests/cases/conformance/salsa/first.js(2,9): error TS2339: Property 'formatters' does not exist on type 'typeof "tests/cases/conformance/salsa/first"'.
tests/cases/conformance/salsa/second.js(1,1): error TS2539: Cannot assign to '"tests/cases/conformance/salsa/second"' because it is not a variable.
tests/cases/conformance/salsa/second.js(1,11): error TS2304: Cannot find name 'require'.
tests/cases/conformance/salsa/second.js(2,9): error TS2339: Property 'formatters' does not exist on type 'typeof "tests/cases/conformance/salsa/second"'.
==== tests/cases/conformance/salsa/mod.js (0 errors) ====
// Based on a pattern from adonis
exports.formatters = {}
==== tests/cases/conformance/salsa/first.js (3 errors) ====
exports = require('./mod')
~~~~~~~
!!! error TS2539: Cannot assign to '"tests/cases/conformance/salsa/first"' because it is not a variable.
~~~~~~~
!!! error TS2304: Cannot find name 'require'.
exports.formatters.j = function (v) {
~~~~~~~~~~
!!! error TS2339: Property 'formatters' does not exist on type 'typeof "tests/cases/conformance/salsa/first"'.
return v
}
==== tests/cases/conformance/salsa/second.js (3 errors) ====
exports = require('./mod')
~~~~~~~
!!! error TS2539: Cannot assign to '"tests/cases/conformance/salsa/second"' because it is not a variable.
~~~~~~~
!!! error TS2304: Cannot find name 'require'.
exports.formatters.o = function (v) {
~~~~~~~~~~
!!! error TS2339: Property 'formatters' does not exist on type 'typeof "tests/cases/conformance/salsa/second"'.
return v
}
==== tests/cases/conformance/salsa/use.js (0 errors) ====
import * as debug from './mod'
debug.formatters.j
var one = debug.formatters.o(1)
@@ -0,0 +1,47 @@
=== tests/cases/conformance/salsa/mod.js ===
// Based on a pattern from adonis
exports.formatters = {}
>exports.formatters : Symbol(formatters, Decl(mod.js, 0, 0))
>exports : Symbol(formatters, Decl(mod.js, 0, 0))
>formatters : Symbol(formatters, Decl(mod.js, 0, 0))
=== tests/cases/conformance/salsa/first.js ===
exports = require('./mod')
>exports : Symbol("tests/cases/conformance/salsa/first", Decl(first.js, 0, 0))
>'./mod' : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0))
exports.formatters.j = function (v) {
>exports : Symbol("tests/cases/conformance/salsa/first", Decl(first.js, 0, 0))
>v : Symbol(v, Decl(first.js, 1, 33))
return v
>v : Symbol(v, Decl(first.js, 1, 33))
}
=== tests/cases/conformance/salsa/second.js ===
exports = require('./mod')
>exports : Symbol("tests/cases/conformance/salsa/second", Decl(second.js, 0, 0))
>'./mod' : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0))
exports.formatters.o = function (v) {
>exports : Symbol("tests/cases/conformance/salsa/second", Decl(second.js, 0, 0))
>v : Symbol(v, Decl(second.js, 1, 33))
return v
>v : Symbol(v, Decl(second.js, 1, 33))
}
=== tests/cases/conformance/salsa/use.js ===
import * as debug from './mod'
>debug : Symbol(debug, Decl(use.js, 0, 6))
debug.formatters.j
>debug.formatters : Symbol(debug.formatters, Decl(mod.js, 0, 0))
>debug : Symbol(debug, Decl(use.js, 0, 6))
>formatters : Symbol(debug.formatters, Decl(mod.js, 0, 0))
var one = debug.formatters.o(1)
>one : Symbol(one, Decl(use.js, 3, 3))
>debug.formatters : Symbol(debug.formatters, Decl(mod.js, 0, 0))
>debug : Symbol(debug, Decl(use.js, 0, 6))
>formatters : Symbol(debug.formatters, Decl(mod.js, 0, 0))
@@ -0,0 +1,73 @@
=== tests/cases/conformance/salsa/mod.js ===
// Based on a pattern from adonis
exports.formatters = {}
>exports.formatters = {} : { [x: string]: any; }
>exports.formatters : { [x: string]: any; }
>exports : typeof "tests/cases/conformance/salsa/mod"
>formatters : { [x: string]: any; }
>{} : { [x: string]: any; }
=== tests/cases/conformance/salsa/first.js ===
exports = require('./mod')
>exports = require('./mod') : typeof "tests/cases/conformance/salsa/mod"
>exports : any
>require('./mod') : typeof "tests/cases/conformance/salsa/mod"
>require : any
>'./mod' : "./mod"
exports.formatters.j = function (v) {
>exports.formatters.j = function (v) { return v} : (v: any) => any
>exports.formatters.j : any
>exports.formatters : any
>exports : typeof "tests/cases/conformance/salsa/first"
>formatters : any
>j : any
>function (v) { return v} : (v: any) => any
>v : any
return v
>v : any
}
=== tests/cases/conformance/salsa/second.js ===
exports = require('./mod')
>exports = require('./mod') : typeof "tests/cases/conformance/salsa/mod"
>exports : any
>require('./mod') : typeof "tests/cases/conformance/salsa/mod"
>require : any
>'./mod' : "./mod"
exports.formatters.o = function (v) {
>exports.formatters.o = function (v) { return v} : (v: any) => any
>exports.formatters.o : any
>exports.formatters : any
>exports : typeof "tests/cases/conformance/salsa/second"
>formatters : any
>o : any
>function (v) { return v} : (v: any) => any
>v : any
return v
>v : any
}
=== tests/cases/conformance/salsa/use.js ===
import * as debug from './mod'
>debug : typeof debug
debug.formatters.j
>debug.formatters.j : any
>debug.formatters : { [x: string]: any; }
>debug : typeof debug
>formatters : { [x: string]: any; }
>j : any
var one = debug.formatters.o(1)
>one : any
>debug.formatters.o(1) : any
>debug.formatters.o : any
>debug.formatters : { [x: string]: any; }
>debug : typeof debug
>formatters : { [x: string]: any; }
>o : any
>1 : 1
@@ -1,10 +1,10 @@
/a.ts(2,8): error TS6133: 'Bar' is declared but its value is never read.
/a.ts(2,1): error TS6133: 'Bar' is declared but its value is never read.
==== /a.ts (1 errors) ====
import Foo from "foo";
import Bar from "bar"; // error: unused
~~~
~~~~~~~~~~~~~~~~~~~~~~
!!! error TS6133: 'Bar' is declared but its value is never read.
export class A extends Foo { }
@@ -1,9 +1,17 @@
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck48.ts(1,9): error TS7025: Generator implicitly has type 'IterableIterator<any>' because it does not yield any values. Consider supplying a return type.
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck48.ts(1,11): error TS7010: 'g', which lacks return-type annotation, implicitly has an 'any' return type.
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck48.ts(5,11): error TS7010: 'h', which lacks return-type annotation, implicitly has an 'any' return type.
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck48.ts (1 errors) ====
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck48.ts (2 errors) ====
function* g() {
~
!!! error TS7025: Generator implicitly has type 'IterableIterator<any>' because it does not yield any values. Consider supplying a return type.
~
!!! error TS7010: 'g', which lacks return-type annotation, implicitly has an 'any' return type.
yield;
}
}
function* h() {
~
!!! error TS7010: 'h', which lacks return-type annotation, implicitly has an 'any' return type.
yield undefined;
}
@@ -1,9 +1,17 @@
//// [generatorTypeCheck48.ts]
function* g() {
yield;
}
}
function* h() {
yield undefined;
}
//// [generatorTypeCheck48.js]
function* g() {
yield;
}
function* h() {
yield undefined;
}
@@ -4,3 +4,11 @@ function* g() {
yield;
}
function* h() {
>h : Symbol(h, Decl(generatorTypeCheck48.ts, 2, 1))
yield undefined;
>undefined : Symbol(undefined)
}
@@ -5,3 +5,12 @@ function* g() {
yield;
>yield : any
}
function* h() {
>h : () => IterableIterator<any>
yield undefined;
>yield undefined : any
>undefined : undefined
}
@@ -0,0 +1,22 @@
error TS5055: Cannot write file 'tests/cases/conformance/salsa/a.js' because it would overwrite input file.
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
tests/cases/conformance/salsa/a.js(1,10): error TS2300: Duplicate identifier 'x'.
tests/cases/conformance/salsa/b.ts(1,5): error TS2300: Duplicate identifier 'x'.
!!! error TS5055: Cannot write file 'tests/cases/conformance/salsa/a.js' because it would overwrite input file.
!!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
==== tests/cases/conformance/salsa/a.js (1 errors) ====
var /*1*/x = function foo() {
~
!!! error TS2300: Duplicate identifier 'x'.
}
x.a = function bar() {
}
==== tests/cases/conformance/salsa/b.ts (1 errors) ====
var x = function () {
~
!!! error TS2300: Duplicate identifier 'x'.
return 1;
}();
@@ -0,0 +1,17 @@
//// [tests/cases/conformance/salsa/jsContainerMergeTsDeclaration.ts] ////
//// [a.js]
var /*1*/x = function foo() {
}
x.a = function bar() {
}
//// [b.ts]
var x = function () {
return 1;
}();
//// [b.js]
var x = function () {
return 1;
}();
@@ -0,0 +1,18 @@
=== tests/cases/conformance/salsa/a.js ===
var /*1*/x = function foo() {
>x : Symbol(x, Decl(a.js, 0, 3), Decl(a.js, 1, 1), Decl(b.ts, 0, 3))
>foo : Symbol(foo, Decl(a.js, 0, 12))
}
x.a = function bar() {
>x.a : Symbol(foo.a, Decl(a.js, 1, 1))
>x : Symbol(x, Decl(a.js, 0, 3), Decl(a.js, 1, 1), Decl(b.ts, 0, 3))
>a : Symbol(foo.a, Decl(a.js, 1, 1))
>bar : Symbol(bar, Decl(a.js, 2, 5))
}
=== tests/cases/conformance/salsa/b.ts ===
var x = function () {
>x : Symbol(x, Decl(a.js, 0, 3), Decl(a.js, 1, 1), Decl(b.ts, 0, 3))
return 1;
}();
@@ -0,0 +1,25 @@
=== tests/cases/conformance/salsa/a.js ===
var /*1*/x = function foo() {
>x : { (): void; a: () => void; }
>function foo() {} : { (): void; a: () => void; }
>foo : { (): void; a: () => void; }
}
x.a = function bar() {
>x.a = function bar() {} : () => void
>x.a : () => void
>x : { (): void; a: () => void; }
>a : () => void
>function bar() {} : () => void
>bar : () => void
}
=== tests/cases/conformance/salsa/b.ts ===
var x = function () {
>x : { (): void; a: () => void; }
>function () { return 1;}() : number
>function () { return 1;} : () => number
return 1;
>1 : 1
}();
@@ -3,7 +3,9 @@ var variable = {};
>variable : Symbol(variable, Decl(a.js, 0, 3))
variable.a = 0;
>variable.a : Symbol(a, Decl(a.js, 0, 18))
>variable : Symbol(variable, Decl(a.js, 0, 3))
>a : Symbol(a, Decl(a.js, 0, 18))
class C {
>C : Symbol(C, Decl(a.js, 1, 15))
@@ -49,7 +51,9 @@ function getObj() {
=== tests/cases/conformance/salsa/b.ts ===
variable.a = 1;
>variable.a : Symbol(a, Decl(a.js, 0, 18))
>variable : Symbol(variable, Decl(a.js, 0, 3))
>a : Symbol(a, Decl(a.js, 0, 18))
(new C()).member.a = 1;
>(new C()).member : Symbol(C.member, Decl(a.js, 5, 19))
@@ -1,13 +1,13 @@
=== tests/cases/conformance/salsa/a.js ===
var variable = {};
>variable : { [x: string]: any; }
>{} : { [x: string]: any; }
>variable : { [x: string]: any; a: number; }
>{} : { [x: string]: any; a: number; }
variable.a = 0;
>variable.a = 0 : 0
>variable.a : any
>variable : { [x: string]: any; }
>a : any
>variable.a : number
>variable : { [x: string]: any; a: number; }
>a : number
>0 : 0
class C {
@@ -71,9 +71,9 @@ function getObj() {
=== tests/cases/conformance/salsa/b.ts ===
variable.a = 1;
>variable.a = 1 : 1
>variable.a : any
>variable : { [x: string]: any; }
>a : any
>variable.a : number
>variable : { [x: string]: any; a: number; }
>a : number
>1 : 1
(new C()).member.a = 1;
@@ -0,0 +1,17 @@
/a.ts(1,20): error TS2307: Cannot find module 'something'.
/b.ts(3,6): error TS2345: Argument of type '""' is not assignable to parameter of type '"x"'.
==== /b.ts (1 errors) ====
import a = require('./a');
declare function f<T>(obj: T, key: keyof T): void;
f(a, "");
~~
!!! error TS2345: Argument of type '""' is not assignable to parameter of type '"x"'.
==== /a.ts (1 errors) ====
import x = require("something");
~~~~~~~~~~~
!!! error TS2307: Cannot find module 'something'.
export { x };
@@ -0,0 +1,22 @@
//// [tests/cases/compiler/literalTypeNameAssertionNotTriggered.ts] ////
//// [a.ts]
import x = require("something");
export { x };
//// [b.ts]
import a = require('./a');
declare function f<T>(obj: T, key: keyof T): void;
f(a, "");
//// [a.js]
"use strict";
exports.__esModule = true;
var x = require("something");
exports.x = x;
//// [b.js]
"use strict";
exports.__esModule = true;
var a = require("./a");
f(a, "");
@@ -0,0 +1,23 @@
=== /b.ts ===
import a = require('./a');
>a : Symbol(a, Decl(b.ts, 0, 0))
declare function f<T>(obj: T, key: keyof T): void;
>f : Symbol(f, Decl(b.ts, 0, 26))
>T : Symbol(T, Decl(b.ts, 1, 19))
>obj : Symbol(obj, Decl(b.ts, 1, 22))
>T : Symbol(T, Decl(b.ts, 1, 19))
>key : Symbol(key, Decl(b.ts, 1, 29))
>T : Symbol(T, Decl(b.ts, 1, 19))
f(a, "");
>f : Symbol(f, Decl(b.ts, 0, 26))
>a : Symbol(a, Decl(b.ts, 0, 0))
=== /a.ts ===
import x = require("something");
>x : Symbol(x, Decl(a.ts, 0, 0))
export { x };
>x : Symbol(x, Decl(a.ts, 1, 8))
@@ -0,0 +1,25 @@
=== /b.ts ===
import a = require('./a');
>a : typeof a
declare function f<T>(obj: T, key: keyof T): void;
>f : <T>(obj: T, key: keyof T) => void
>T : T
>obj : T
>T : T
>key : keyof T
>T : T
f(a, "");
>f(a, "") : any
>f : <T>(obj: T, key: keyof T) => void
>a : typeof a
>"" : ""
=== /a.ts ===
import x = require("something");
>x : any
export { x };
>x : any
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@ for (const element of document.getElementsByTagName("a")) {
>getElementsByTagName : Symbol(Document.getElementsByTagName, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
element.href;
>element.href : Symbol(HTMLAnchorElement.href, Decl(lib.dom.d.ts, --, --))
>element.href : Symbol(HTMLHyperlinkElementUtils.href, Decl(lib.dom.d.ts, --, --))
>element : Symbol(element, Decl(modularizeLibrary_Dom.iterable.ts, 0, 10))
>href : Symbol(HTMLAnchorElement.href, Decl(lib.dom.d.ts, --, --))
>href : Symbol(HTMLHyperlinkElementUtils.href, Decl(lib.dom.d.ts, --, --))
}
@@ -2,9 +2,9 @@
for (const element of document.getElementsByTagName("a")) {
>element : HTMLAnchorElement
>document.getElementsByTagName("a") : NodeListOf<HTMLAnchorElement>
>document.getElementsByTagName : { <K extends "object" | "a" | "abbr" | "acronym" | "address" | "applet" | "area" | "article" | "aside" | "audio" | "b" | "base" | "basefont" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "center" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "dfn" | "dir" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "font" | "footer" | "form" | "frame" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "isindex" | "kbd" | "keygen" | "label" | "legend" | "li" | "link" | "listing" | "map" | "mark" | "marquee" | "menu" | "meta" | "meter" | "nav" | "nextid" | "nobr" | "noframes" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "plaintext" | "pre" | "progress" | "q" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "slot" | "small" | "source" | "span" | "strike" | "strong" | "style" | "sub" | "sup" | "table" | "tbody" | "td" | "template" | "textarea" | "tfoot" | "th" | "thead" | "time" | "title" | "tr" | "track" | "tt" | "u" | "ul" | "var" | "video" | "wbr" | "x-ms-webview" | "xmp">(tagname: K): NodeListOf<HTMLElementTagNameMap[K]>; <K extends "symbol" | "circle" | "clippath" | "defs" | "desc" | "ellipse" | "feblend" | "fecolormatrix" | "fecomponenttransfer" | "fecomposite" | "feconvolvematrix" | "fediffuselighting" | "fedisplacementmap" | "fedistantlight" | "feflood" | "fefunca" | "fefuncb" | "fefuncg" | "fefuncr" | "fegaussianblur" | "feimage" | "femerge" | "femergenode" | "femorphology" | "feoffset" | "fepointlight" | "fespecularlighting" | "fespotlight" | "fetile" | "feturbulence" | "filter" | "foreignobject" | "g" | "image" | "line" | "lineargradient" | "marker" | "mask" | "metadata" | "path" | "pattern" | "polygon" | "polyline" | "radialgradient" | "rect" | "stop" | "svg" | "switch" | "text" | "textpath" | "tspan" | "use" | "view">(tagname: K): NodeListOf<SVGElementTagNameMap[K]>; (tagname: string): NodeListOf<Element>; }
>document.getElementsByTagName : { <K extends "object" | "a" | "abbr" | "acronym" | "address" | "applet" | "area" | "article" | "aside" | "audio" | "b" | "base" | "basefont" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "center" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "dfn" | "dir" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "font" | "footer" | "form" | "frame" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "isindex" | "kbd" | "keygen" | "label" | "legend" | "li" | "link" | "listing" | "map" | "mark" | "marquee" | "menu" | "meta" | "meter" | "nav" | "nextid" | "nobr" | "noframes" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "plaintext" | "pre" | "progress" | "q" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "slot" | "small" | "source" | "span" | "strike" | "strong" | "style" | "sub" | "sup" | "table" | "tbody" | "td" | "template" | "textarea" | "tfoot" | "th" | "thead" | "time" | "title" | "tr" | "track" | "tt" | "u" | "ul" | "var" | "video" | "wbr" | "xmp">(tagname: K): NodeListOf<HTMLElementTagNameMap[K]>; <K extends "symbol" | "circle" | "clippath" | "defs" | "desc" | "ellipse" | "feblend" | "fecolormatrix" | "fecomponenttransfer" | "fecomposite" | "feconvolvematrix" | "fediffuselighting" | "fedisplacementmap" | "fedistantlight" | "feflood" | "fefunca" | "fefuncb" | "fefuncg" | "fefuncr" | "fegaussianblur" | "feimage" | "femerge" | "femergenode" | "femorphology" | "feoffset" | "fepointlight" | "fespecularlighting" | "fespotlight" | "fetile" | "feturbulence" | "filter" | "foreignobject" | "g" | "image" | "line" | "lineargradient" | "marker" | "mask" | "metadata" | "path" | "pattern" | "polygon" | "polyline" | "radialgradient" | "rect" | "stop" | "svg" | "switch" | "text" | "textpath" | "tspan" | "use" | "view">(tagname: K): NodeListOf<SVGElementTagNameMap[K]>; (tagname: string): NodeListOf<Element>; }
>document : Document
>getElementsByTagName : { <K extends "object" | "a" | "abbr" | "acronym" | "address" | "applet" | "area" | "article" | "aside" | "audio" | "b" | "base" | "basefont" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "center" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "dfn" | "dir" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "font" | "footer" | "form" | "frame" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "isindex" | "kbd" | "keygen" | "label" | "legend" | "li" | "link" | "listing" | "map" | "mark" | "marquee" | "menu" | "meta" | "meter" | "nav" | "nextid" | "nobr" | "noframes" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "plaintext" | "pre" | "progress" | "q" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "slot" | "small" | "source" | "span" | "strike" | "strong" | "style" | "sub" | "sup" | "table" | "tbody" | "td" | "template" | "textarea" | "tfoot" | "th" | "thead" | "time" | "title" | "tr" | "track" | "tt" | "u" | "ul" | "var" | "video" | "wbr" | "x-ms-webview" | "xmp">(tagname: K): NodeListOf<HTMLElementTagNameMap[K]>; <K extends "symbol" | "circle" | "clippath" | "defs" | "desc" | "ellipse" | "feblend" | "fecolormatrix" | "fecomponenttransfer" | "fecomposite" | "feconvolvematrix" | "fediffuselighting" | "fedisplacementmap" | "fedistantlight" | "feflood" | "fefunca" | "fefuncb" | "fefuncg" | "fefuncr" | "fegaussianblur" | "feimage" | "femerge" | "femergenode" | "femorphology" | "feoffset" | "fepointlight" | "fespecularlighting" | "fespotlight" | "fetile" | "feturbulence" | "filter" | "foreignobject" | "g" | "image" | "line" | "lineargradient" | "marker" | "mask" | "metadata" | "path" | "pattern" | "polygon" | "polyline" | "radialgradient" | "rect" | "stop" | "svg" | "switch" | "text" | "textpath" | "tspan" | "use" | "view">(tagname: K): NodeListOf<SVGElementTagNameMap[K]>; (tagname: string): NodeListOf<Element>; }
>getElementsByTagName : { <K extends "object" | "a" | "abbr" | "acronym" | "address" | "applet" | "area" | "article" | "aside" | "audio" | "b" | "base" | "basefont" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "center" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "dfn" | "dir" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "font" | "footer" | "form" | "frame" | "frameset" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "isindex" | "kbd" | "keygen" | "label" | "legend" | "li" | "link" | "listing" | "map" | "mark" | "marquee" | "menu" | "meta" | "meter" | "nav" | "nextid" | "nobr" | "noframes" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "plaintext" | "pre" | "progress" | "q" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "slot" | "small" | "source" | "span" | "strike" | "strong" | "style" | "sub" | "sup" | "table" | "tbody" | "td" | "template" | "textarea" | "tfoot" | "th" | "thead" | "time" | "title" | "tr" | "track" | "tt" | "u" | "ul" | "var" | "video" | "wbr" | "xmp">(tagname: K): NodeListOf<HTMLElementTagNameMap[K]>; <K extends "symbol" | "circle" | "clippath" | "defs" | "desc" | "ellipse" | "feblend" | "fecolormatrix" | "fecomponenttransfer" | "fecomposite" | "feconvolvematrix" | "fediffuselighting" | "fedisplacementmap" | "fedistantlight" | "feflood" | "fefunca" | "fefuncb" | "fefuncg" | "fefuncr" | "fegaussianblur" | "feimage" | "femerge" | "femergenode" | "femorphology" | "feoffset" | "fepointlight" | "fespecularlighting" | "fespotlight" | "fetile" | "feturbulence" | "filter" | "foreignobject" | "g" | "image" | "line" | "lineargradient" | "marker" | "mask" | "metadata" | "path" | "pattern" | "polygon" | "polyline" | "radialgradient" | "rect" | "stop" | "svg" | "switch" | "text" | "textpath" | "tspan" | "use" | "view">(tagname: K): NodeListOf<SVGElementTagNameMap[K]>; (tagname: string): NodeListOf<Element>; }
>"a" : "a"
element.href;
@@ -0,0 +1,37 @@
tests/cases/conformance/salsa/mod.js(1,1): error TS2304: Cannot find name 'module'.
tests/cases/conformance/salsa/mod.js(2,1): error TS2304: Cannot find name 'module'.
tests/cases/conformance/salsa/mod.js(5,1): error TS2304: Cannot find name 'module'.
==== tests/cases/conformance/salsa/mod.js (3 errors) ====
module.exports.n = {};
~~~~~~
!!! error TS2304: Cannot find name 'module'.
module.exports.n.K = function C() {
~~~~~~
!!! error TS2304: Cannot find name 'module'.
this.x = 10;
}
module.exports.Classic = class {
~~~~~~
!!! error TS2304: Cannot find name 'module'.
constructor() {
this.p = 1
}
}
==== tests/cases/conformance/salsa/use.js (0 errors) ====
import * as s from './mod'
var k = new s.n.K()
k.x
var classic = new s.Classic()
/** @param {s.n.K} c
@param {s.Classic} classic */
function f(c, classic) {
c.x
classic.p
}
@@ -0,0 +1,67 @@
=== tests/cases/conformance/salsa/mod.js ===
module.exports.n = {};
>module.exports : Symbol(n, Decl(mod.js, 0, 0))
>n : Symbol(n, Decl(mod.js, 0, 0))
module.exports.n.K = function C() {
>module.exports.n : Symbol(K, Decl(mod.js, 0, 22))
>K : Symbol(K, Decl(mod.js, 0, 22))
>C : Symbol(C, Decl(mod.js, 1, 20))
this.x = 10;
>x : Symbol(C.x, Decl(mod.js, 1, 35))
}
module.exports.Classic = class {
>module.exports : Symbol(Classic, Decl(mod.js, 3, 1))
>Classic : Symbol(Classic, Decl(mod.js, 3, 1))
constructor() {
this.p = 1
>this.p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
>this : Symbol((Anonymous class), Decl(mod.js, 4, 24))
>p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
}
}
=== tests/cases/conformance/salsa/use.js ===
import * as s from './mod'
>s : Symbol(s, Decl(use.js, 0, 6))
var k = new s.n.K()
>k : Symbol(k, Decl(use.js, 2, 3))
>s.n.K : Symbol(K, Decl(mod.js, 0, 22))
>s.n : Symbol(s.n, Decl(mod.js, 0, 0))
>s : Symbol(s, Decl(use.js, 0, 6))
>n : Symbol(s.n, Decl(mod.js, 0, 0))
>K : Symbol(K, Decl(mod.js, 0, 22))
k.x
>k.x : Symbol(C.x, Decl(mod.js, 1, 35))
>k : Symbol(k, Decl(use.js, 2, 3))
>x : Symbol(C.x, Decl(mod.js, 1, 35))
var classic = new s.Classic()
>classic : Symbol(classic, Decl(use.js, 4, 3))
>s.Classic : Symbol(s.Classic, Decl(mod.js, 3, 1))
>s : Symbol(s, Decl(use.js, 0, 6))
>Classic : Symbol(s.Classic, Decl(mod.js, 3, 1))
/** @param {s.n.K} c
@param {s.Classic} classic */
function f(c, classic) {
>f : Symbol(f, Decl(use.js, 4, 29))
>c : Symbol(c, Decl(use.js, 9, 11))
>classic : Symbol(classic, Decl(use.js, 9, 13))
c.x
>c.x : Symbol(C.x, Decl(mod.js, 1, 35))
>c : Symbol(c, Decl(use.js, 9, 11))
>x : Symbol(C.x, Decl(mod.js, 1, 35))
classic.p
>classic.p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
>classic : Symbol(classic, Decl(use.js, 9, 13))
>p : Symbol((Anonymous class).p, Decl(mod.js, 5, 19))
}
@@ -0,0 +1,92 @@
=== tests/cases/conformance/salsa/mod.js ===
module.exports.n = {};
>module.exports.n = {} : typeof __object
>module.exports.n : any
>module.exports : any
>module : any
>exports : any
>n : any
>{} : typeof __object
module.exports.n.K = function C() {
>module.exports.n.K = function C() { this.x = 10;} : () => void
>module.exports.n.K : any
>module.exports.n : any
>module.exports : any
>module : any
>exports : any
>n : any
>K : any
>function C() { this.x = 10;} : () => void
>C : () => void
this.x = 10;
>this.x = 10 : 10
>this.x : any
>this : any
>x : any
>10 : 10
}
module.exports.Classic = class {
>module.exports.Classic = class { constructor() { this.p = 1 }} : typeof (Anonymous class)
>module.exports.Classic : any
>module.exports : any
>module : any
>exports : any
>Classic : any
>class { constructor() { this.p = 1 }} : typeof (Anonymous class)
constructor() {
this.p = 1
>this.p = 1 : 1
>this.p : number
>this : this
>p : number
>1 : 1
}
}
=== tests/cases/conformance/salsa/use.js ===
import * as s from './mod'
>s : typeof s
var k = new s.n.K()
>k : { x: number; }
>new s.n.K() : { x: number; }
>s.n.K : () => void
>s.n : typeof __object
>s : typeof s
>n : typeof __object
>K : () => void
k.x
>k.x : number
>k : { x: number; }
>x : number
var classic = new s.Classic()
>classic : (Anonymous class)
>new s.Classic() : (Anonymous class)
>s.Classic : typeof (Anonymous class)
>s : typeof s
>Classic : typeof (Anonymous class)
/** @param {s.n.K} c
@param {s.Classic} classic */
function f(c, classic) {
>f : (c: { x: number; }, classic: (Anonymous class)) => void
>c : { x: number; }
>classic : (Anonymous class)
c.x
>c.x : number
>c : { x: number; }
>x : number
classic.p
>classic.p : number
>classic : (Anonymous class)
>p : number
}
@@ -1,10 +1,10 @@
tests/cases/compiler/noUnusedLocals_selfReference.ts(3,10): error TS6133: 'f' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(5,14): error TS6133: 'g' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(9,7): error TS6133: 'C' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(12,6): error TS6133: 'E' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(13,11): error TS6133: 'I' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(14,6): error TS6133: 'T' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(15,11): error TS6133: 'N' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(3,1): error TS6133: 'f' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(5,5): error TS6133: 'g' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(9,1): error TS6133: 'C' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(12,1): error TS6133: 'E' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(13,1): error TS6133: 'I' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(14,1): error TS6133: 'T' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(15,1): error TS6133: 'N' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference.ts(22,19): error TS6133: 'm' is declared but its value is never read.
@@ -12,31 +12,31 @@ tests/cases/compiler/noUnusedLocals_selfReference.ts(22,19): error TS6133: 'm' i
export {}; // Make this a module scope, so these are local variables.
function f() {
~
~~~~~~~~~~
!!! error TS6133: 'f' is declared but its value is never read.
f;
function g() {
~
~~~~~~~~~~
!!! error TS6133: 'g' is declared but its value is never read.
g;
}
}
class C {
~
~~~~~~~
!!! error TS6133: 'C' is declared but its value is never read.
m() { C; }
}
enum E { A = 0, B = E.A }
~
~~~~~~
!!! error TS6133: 'E' is declared but its value is never read.
interface I { x: I };
~
~~~~~~~~~~~
!!! error TS6133: 'I' is declared but its value is never read.
type T = { x: T };
~
~~~~~~
!!! error TS6133: 'T' is declared but its value is never read.
namespace N { N; }
~
~~~~~~~~~~~
!!! error TS6133: 'N' is declared but its value is never read.
// Avoid a false positive.
@@ -1,12 +1,12 @@
tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(2,14): error TS6133: 'f' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(8,22): error TS6133: 'g' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(12,22): error TS6133: 'h' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(2,5): error TS6133: 'f' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(8,13): error TS6133: 'g' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(12,13): error TS6133: 'h' is declared but its value is never read.
==== tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts (3 errors) ====
namespace n {
function f() {
~
~~~~~~~~~~
!!! error TS6133: 'f' is declared but its value is never read.
f;
}
@@ -14,13 +14,13 @@ tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(12,22):
switch (0) {
case 0:
function g() {
~
~~~~~~~~~~
!!! error TS6133: 'g' is declared but its value is never read.
g;
}
default:
function h() {
~
~~~~~~~~~~
!!! error TS6133: 'h' is declared but its value is never read.
h;
}
@@ -0,0 +1,8 @@
//// [nonstrictTemplateWithNotOctalPrintsAsIs.ts]
// https://github.com/Microsoft/TypeScript/issues/21828
const d2 = `\\0041`;
//// [nonstrictTemplateWithNotOctalPrintsAsIs.js]
// https://github.com/Microsoft/TypeScript/issues/21828
var d2 = "\\0041";
@@ -0,0 +1,5 @@
=== tests/cases/compiler/nonstrictTemplateWithNotOctalPrintsAsIs.ts ===
// https://github.com/Microsoft/TypeScript/issues/21828
const d2 = `\\0041`;
>d2 : Symbol(d2, Decl(nonstrictTemplateWithNotOctalPrintsAsIs.ts, 1, 5))
@@ -0,0 +1,6 @@
=== tests/cases/compiler/nonstrictTemplateWithNotOctalPrintsAsIs.ts ===
// https://github.com/Microsoft/TypeScript/issues/21828
const d2 = `\\0041`;
>d2 : "\\0041"
>`\\0041` : "\\0041"
@@ -0,0 +1,141 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = Outer || {};
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
Outer.app = Outer.app || {};
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
=== tests/cases/conformance/salsa/someview.js ===
Outer.app.SomeView = (function () {
>Outer.app.SomeView : Symbol(Outer.app.SomeView, Decl(someview.js, 0, 0))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>SomeView : Symbol(Outer.app.SomeView, Decl(someview.js, 0, 0))
var SomeView = function() {
>SomeView : Symbol(SomeView, Decl(someview.js, 1, 7))
var me = this;
>me : Symbol(me, Decl(someview.js, 2, 11))
}
return SomeView;
>SomeView : Symbol(SomeView, Decl(someview.js, 1, 7))
})();
Outer.app.Inner = class {
>Outer.app.Inner : Symbol(Outer.app.Inner, Decl(someview.js, 5, 5))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Inner : Symbol(Outer.app.Inner, Decl(someview.js, 5, 5))
constructor() {
/** @type {number} */
this.y = 12;
>this.y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
>this : Symbol((Anonymous class), Decl(someview.js, 6, 17))
>y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
}
}
var example = new Outer.app.Inner();
>example : Symbol(example, Decl(someview.js, 12, 3))
>Outer.app.Inner : Symbol(Outer.app.Inner, Decl(someview.js, 5, 5))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Inner : Symbol(Outer.app.Inner, Decl(someview.js, 5, 5))
example.y;
>example.y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
>example : Symbol(example, Decl(someview.js, 12, 3))
>y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
/** @param {number} k */
Outer.app.statische = function (k) {
>Outer.app.statische : Symbol(Outer.app.statische, Decl(someview.js, 13, 10))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>statische : Symbol(Outer.app.statische, Decl(someview.js, 13, 10))
>k : Symbol(k, Decl(someview.js, 15, 32))
return k ** k;
>k : Symbol(k, Decl(someview.js, 15, 32))
>k : Symbol(k, Decl(someview.js, 15, 32))
}
=== tests/cases/conformance/salsa/application.js ===
Outer.app.Application = (function () {
>Outer.app.Application : Symbol(app.Application, Decl(application.js, 0, 0))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Application : Symbol(app.Application, Decl(application.js, 0, 0))
/**
* Application main class.
* Will be instantiated & initialized by HTML page
*/
var Application = function () {
>Application : Symbol(Application, Decl(application.js, 6, 7))
var me = this;
>me : Symbol(me, Decl(application.js, 7, 11))
me.view = new Outer.app.SomeView();
>me : Symbol(me, Decl(application.js, 7, 11))
>Outer.app.SomeView : Symbol(Outer.app.SomeView, Decl(someview.js, 0, 0))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>SomeView : Symbol(Outer.app.SomeView, Decl(someview.js, 0, 0))
};
return Application;
>Application : Symbol(Application, Decl(application.js, 6, 7))
})();
=== tests/cases/conformance/salsa/main.js ===
var app = new Outer.app.Application();
>app : Symbol(app, Decl(main.js, 0, 3))
>Outer.app.Application : Symbol(app.Application, Decl(application.js, 0, 0))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Application : Symbol(app.Application, Decl(application.js, 0, 0))
var inner = new Outer.app.Inner();
>inner : Symbol(inner, Decl(main.js, 1, 3))
>Outer.app.Inner : Symbol(Outer.app.Inner, Decl(someview.js, 5, 5))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Inner : Symbol(Outer.app.Inner, Decl(someview.js, 5, 5))
inner.y;
>inner.y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
>inner : Symbol(inner, Decl(main.js, 1, 3))
>y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
/** @type {Outer.app.Inner} */
var x;
>x : Symbol(x, Decl(main.js, 4, 3))
x.y;
>x.y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
>x : Symbol(x, Decl(main.js, 4, 3))
>y : Symbol((Anonymous class).y, Decl(someview.js, 7, 19))
Outer.app.statische(101); // Infinity, duh
>Outer.app.statische : Symbol(Outer.app.statische, Decl(someview.js, 13, 10))
>Outer.app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(someview.js, 0, 0), Decl(application.js, 0, 0))
>app : Symbol(app, Decl(module.js, 0, 24), Decl(someview.js, 0, 6), Decl(application.js, 0, 6))
>statische : Symbol(Outer.app.statische, Decl(someview.js, 13, 10))
@@ -0,0 +1,174 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = Outer || {};
>Outer : typeof __object
>Outer || {} : typeof __object
>Outer : typeof __object
>{} : typeof __object
Outer.app = Outer.app || {};
>Outer.app = Outer.app || {} : typeof __object
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>Outer.app || {} : typeof __object
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>{} : typeof __object
=== tests/cases/conformance/salsa/someview.js ===
Outer.app.SomeView = (function () {
>Outer.app.SomeView = (function () { var SomeView = function() { var me = this; } return SomeView;})() : () => void
>Outer.app.SomeView : () => void
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>SomeView : () => void
>(function () { var SomeView = function() { var me = this; } return SomeView;})() : () => void
>(function () { var SomeView = function() { var me = this; } return SomeView;}) : () => () => void
>function () { var SomeView = function() { var me = this; } return SomeView;} : () => () => void
var SomeView = function() {
>SomeView : () => void
>function() { var me = this; } : () => void
var me = this;
>me : any
>this : any
}
return SomeView;
>SomeView : () => void
})();
Outer.app.Inner = class {
>Outer.app.Inner = class { constructor() { /** @type {number} */ this.y = 12; }} : typeof (Anonymous class)
>Outer.app.Inner : typeof (Anonymous class)
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>Inner : typeof (Anonymous class)
>class { constructor() { /** @type {number} */ this.y = 12; }} : typeof (Anonymous class)
constructor() {
/** @type {number} */
this.y = 12;
>this.y = 12 : 12
>this.y : number
>this : this
>y : number
>12 : 12
}
}
var example = new Outer.app.Inner();
>example : (Anonymous class)
>new Outer.app.Inner() : (Anonymous class)
>Outer.app.Inner : typeof (Anonymous class)
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>Inner : typeof (Anonymous class)
example.y;
>example.y : number
>example : (Anonymous class)
>y : number
/** @param {number} k */
Outer.app.statische = function (k) {
>Outer.app.statische = function (k) { return k ** k;} : (k: number) => number
>Outer.app.statische : (k: number) => number
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>statische : (k: number) => number
>function (k) { return k ** k;} : (k: number) => number
>k : number
return k ** k;
>k ** k : number
>k : number
>k : number
}
=== tests/cases/conformance/salsa/application.js ===
Outer.app.Application = (function () {
>Outer.app.Application = (function () { /** * Application main class. * Will be instantiated & initialized by HTML page */ var Application = function () { var me = this; me.view = new Outer.app.SomeView(); }; return Application;})() : () => void
>Outer.app.Application : () => void
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>Application : () => void
>(function () { /** * Application main class. * Will be instantiated & initialized by HTML page */ var Application = function () { var me = this; me.view = new Outer.app.SomeView(); }; return Application;})() : () => void
>(function () { /** * Application main class. * Will be instantiated & initialized by HTML page */ var Application = function () { var me = this; me.view = new Outer.app.SomeView(); }; return Application;}) : () => () => void
>function () { /** * Application main class. * Will be instantiated & initialized by HTML page */ var Application = function () { var me = this; me.view = new Outer.app.SomeView(); }; return Application;} : () => () => void
/**
* Application main class.
* Will be instantiated & initialized by HTML page
*/
var Application = function () {
>Application : () => void
>function () { var me = this; me.view = new Outer.app.SomeView(); } : () => void
var me = this;
>me : any
>this : any
me.view = new Outer.app.SomeView();
>me.view = new Outer.app.SomeView() : any
>me.view : any
>me : any
>view : any
>new Outer.app.SomeView() : any
>Outer.app.SomeView : () => void
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>SomeView : () => void
};
return Application;
>Application : () => void
})();
=== tests/cases/conformance/salsa/main.js ===
var app = new Outer.app.Application();
>app : any
>new Outer.app.Application() : any
>Outer.app.Application : () => void
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>Application : () => void
var inner = new Outer.app.Inner();
>inner : (Anonymous class)
>new Outer.app.Inner() : (Anonymous class)
>Outer.app.Inner : typeof (Anonymous class)
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>Inner : typeof (Anonymous class)
inner.y;
>inner.y : number
>inner : (Anonymous class)
>y : number
/** @type {Outer.app.Inner} */
var x;
>x : (Anonymous class)
x.y;
>x.y : number
>x : (Anonymous class)
>y : number
Outer.app.statische(101); // Infinity, duh
>Outer.app.statische(101) : number
>Outer.app.statische : (k: number) => number
>Outer.app : typeof __object
>Outer : typeof __object
>app : typeof __object
>statische : (k: number) => number
>101 : 101
@@ -0,0 +1,52 @@
=== tests/cases/conformance/salsa/module.js ===
var Inner = function() {}
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
Inner.prototype = {
>Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
m() { },
>m : Symbol(m, Decl(module.js, 1, 19))
i: 1
>i : Symbol(i, Decl(module.js, 2, 12))
}
// incremental assignments still work
Inner.prototype.j = 2
>Inner.prototype : Symbol(Inner.j, Decl(module.js, 4, 1))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>j : Symbol(Inner.j, Decl(module.js, 4, 1))
/** @type {string} */
Inner.prototype.k;
>Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
var inner = new Inner()
>inner : Symbol(inner, Decl(module.js, 9, 3))
>Inner : Symbol(Inner, Decl(module.js, 0, 3), Decl(module.js, 0, 25))
inner.m()
>inner.m : Symbol(m, Decl(module.js, 1, 19))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>m : Symbol(m, Decl(module.js, 1, 19))
inner.i
>inner.i : Symbol(i, Decl(module.js, 2, 12))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>i : Symbol(i, Decl(module.js, 2, 12))
inner.j
>inner.j : Symbol(Inner.j, Decl(module.js, 4, 1))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>j : Symbol(Inner.j, Decl(module.js, 4, 1))
inner.k
>inner.k : Symbol(Inner.k, Decl(module.js, 6, 21))
>inner : Symbol(inner, Decl(module.js, 9, 3))
>k : Symbol(Inner.k, Decl(module.js, 6, 21))
@@ -0,0 +1,63 @@
=== tests/cases/conformance/salsa/module.js ===
var Inner = function() {}
>Inner : () => void
>function() {} : () => void
Inner.prototype = {
>Inner.prototype = { m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
>Inner.prototype : any
>Inner : () => void
>prototype : any
>{ m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
m() { },
>m : () => void
i: 1
>i : number
>1 : 1
}
// incremental assignments still work
Inner.prototype.j = 2
>Inner.prototype.j = 2 : 2
>Inner.prototype.j : any
>Inner.prototype : any
>Inner : () => void
>prototype : any
>j : any
>2 : 2
/** @type {string} */
Inner.prototype.k;
>Inner.prototype.k : any
>Inner.prototype : any
>Inner : () => void
>prototype : any
>k : any
var inner = new Inner()
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>new Inner() : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>Inner : () => void
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>m : () => void
inner.i
>inner.i : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>i : number
inner.j
>inner.j : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>j : number
inner.k
>inner.k : string
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>k : string
@@ -0,0 +1,35 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = function(element, config) {};
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>element : Symbol(element, Decl(module.js, 0, 21))
>config : Symbol(config, Decl(module.js, 0, 29))
=== tests/cases/conformance/salsa/usage.js ===
/** @constructor */
Outer.Pos = function (line, ch) {};
>Outer.Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>line : Symbol(line, Decl(usage.js, 1, 22))
>ch : Symbol(ch, Decl(usage.js, 1, 27))
/** @type {number} */
Outer.Pos.prototype.line;
>Outer.Pos.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Outer.Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
var pos = new Outer.Pos(1, 'x');
>pos : Symbol(pos, Decl(usage.js, 4, 3))
>Outer.Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(usage.js, 0, 0))
>Pos : Symbol(Outer.Pos, Decl(usage.js, 0, 0))
pos.line;
>pos.line : Symbol((Anonymous function).line, Decl(usage.js, 1, 35))
>pos : Symbol(pos, Decl(usage.js, 4, 3))
>line : Symbol((Anonymous function).line, Decl(usage.js, 1, 35))
@@ -0,0 +1,43 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = function(element, config) {};
>Outer : typeof Outer
>function(element, config) {} : typeof Outer
>element : any
>config : any
=== tests/cases/conformance/salsa/usage.js ===
/** @constructor */
Outer.Pos = function (line, ch) {};
>Outer.Pos = function (line, ch) {} : (line: any, ch: any) => void
>Outer.Pos : (line: any, ch: any) => void
>Outer : typeof Outer
>Pos : (line: any, ch: any) => void
>function (line, ch) {} : (line: any, ch: any) => void
>line : any
>ch : any
/** @type {number} */
Outer.Pos.prototype.line;
>Outer.Pos.prototype.line : any
>Outer.Pos.prototype : any
>Outer.Pos : (line: any, ch: any) => void
>Outer : typeof Outer
>Pos : (line: any, ch: any) => void
>prototype : any
>line : any
var pos = new Outer.Pos(1, 'x');
>pos : { line: number; }
>new Outer.Pos(1, 'x') : { line: number; }
>Outer.Pos : (line: any, ch: any) => void
>Outer : typeof Outer
>Pos : (line: any, ch: any) => void
>1 : 1
>'x' : "x"
pos.line;
>pos.line : number
>pos : { line: number; }
>line : number
@@ -0,0 +1,65 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = {}
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
Outer.Inner = function() {}
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
m() { },
>m : Symbol(m, Decl(module.js, 2, 25))
i: 1
>i : Symbol(i, Decl(module.js, 3, 12))
}
// incremental assignments still work
Outer.Inner.prototype.j = 2
>Outer.Inner.prototype : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>j : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
/** @type {string} */
Outer.Inner.prototype.k;
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
var inner = new Outer.Inner()
>inner : Symbol(inner, Decl(module.js, 10, 3))
>Outer.Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
>Outer : Symbol(Outer, Decl(module.js, 0, 3), Decl(module.js, 0, 14), Decl(module.js, 1, 27))
>Inner : Symbol(Inner, Decl(module.js, 0, 14), Decl(module.js, 2, 6))
inner.m()
>inner.m : Symbol(m, Decl(module.js, 2, 25))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>m : Symbol(m, Decl(module.js, 2, 25))
inner.i
>inner.i : Symbol(i, Decl(module.js, 3, 12))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>i : Symbol(i, Decl(module.js, 3, 12))
inner.j
>inner.j : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>j : Symbol((Anonymous function).j, Decl(module.js, 5, 1))
inner.k
>inner.k : Symbol((Anonymous function).k, Decl(module.js, 7, 27))
>inner : Symbol(inner, Decl(module.js, 10, 3))
>k : Symbol((Anonymous function).k, Decl(module.js, 7, 27))
@@ -0,0 +1,78 @@
=== tests/cases/conformance/salsa/module.js ===
var Outer = {}
>Outer : { [x: string]: any; Inner: () => void; }
>{} : { [x: string]: any; Inner: () => void; }
Outer.Inner = function() {}
>Outer.Inner = function() {} : () => void
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>function() {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>{ m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
m() { },
>m : () => void
i: 1
>i : number
>1 : 1
}
// incremental assignments still work
Outer.Inner.prototype.j = 2
>Outer.Inner.prototype.j = 2 : 2
>Outer.Inner.prototype.j : any
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>j : any
>2 : 2
/** @type {string} */
Outer.Inner.prototype.k;
>Outer.Inner.prototype.k : any
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>k : any
var inner = new Outer.Inner()
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>new Outer.Inner() : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>m : () => void
inner.i
>inner.i : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>i : number
inner.j
>inner.j : number
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>j : number
inner.k
>inner.k : string
>inner : { j: number; k: string; } & { [x: string]: any; m(): void; i: number; }
>k : string
@@ -0,0 +1,57 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
=== tests/cases/conformance/salsa/work.js ===
Outer.Inner = function () {}
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
x: 1,
>x : Symbol(x, Decl(work.js, 1, 25))
m() { }
>m : Symbol(m, Decl(work.js, 2, 9))
}
=== tests/cases/conformance/salsa/use.js ===
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(use.js, 1, 3))
inner.x
>inner.x : Symbol(x, Decl(work.js, 1, 25))
>inner : Symbol(inner, Decl(use.js, 1, 3))
>x : Symbol(x, Decl(work.js, 1, 25))
inner.m()
>inner.m : Symbol(m, Decl(work.js, 2, 9))
>inner : Symbol(inner, Decl(use.js, 1, 3))
>m : Symbol(m, Decl(work.js, 2, 9))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(use.js, 4, 3))
>Outer.Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(work.js, 0, 0), Decl(work.js, 0, 28))
>Inner : Symbol(Outer.Inner, Decl(work.js, 0, 0), Decl(work.js, 1, 6))
inno.x
>inno.x : Symbol(x, Decl(work.js, 1, 25))
>inno : Symbol(inno, Decl(use.js, 4, 3))
>x : Symbol(x, Decl(work.js, 1, 25))
inno.m()
>inno.m : Symbol(m, Decl(work.js, 2, 9))
>inno : Symbol(inno, Decl(use.js, 4, 3))
>m : Symbol(m, Decl(work.js, 2, 9))
@@ -0,0 +1,66 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : typeof Outer
>{} : typeof Outer
=== tests/cases/conformance/salsa/work.js ===
Outer.Inner = function () {}
>Outer.Inner = function () {} : () => void
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
>function () {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
>prototype : any
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
>x : number
>1 : 1
m() { }
>m : () => void
}
=== tests/cases/conformance/salsa/use.js ===
/** @type {Outer.Inner} */
var inner
>inner : { [x: string]: any; x: number; m(): void; }
inner.x
>inner.x : number
>inner : { [x: string]: any; x: number; m(): void; }
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { [x: string]: any; x: number; m(): void; }
>m : () => void
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : () => void
>Outer : typeof Outer
>Inner : () => void
inno.x
>inno.x : number
>inno : { [x: string]: any; x: number; m(): void; }
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : { [x: string]: any; x: number; m(): void; }
>m : () => void
@@ -0,0 +1,49 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
Outer.Inner = class {
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
>Inner : Symbol(Inner, Decl(a.js, 0, 15))
constructor() {
this.x = 1
>this.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>this : Symbol((Anonymous class), Decl(a.js, 2, 13))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
}
m() { }
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
}
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(a.js, 10, 3))
inner.x
>inner.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
inner.m()
>inner.m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(a.js, 13, 3))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15))
>Inner : Symbol(Inner, Decl(a.js, 0, 15))
inno.x
>inno.x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
>inno : Symbol(inno, Decl(a.js, 13, 3))
>x : Symbol((Anonymous class).x, Decl(a.js, 3, 19))
inno.m()
>inno.m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
>inno : Symbol(inno, Decl(a.js, 13, 3))
>m : Symbol((Anonymous class).m, Decl(a.js, 5, 5))
@@ -0,0 +1,57 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>{} : { [x: string]: any; Inner: typeof (Anonymous class); }
Outer.Inner = class {
>Outer.Inner = class { constructor() { this.x = 1 } m() { }} : typeof (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>Inner : typeof (Anonymous class)
>class { constructor() { this.x = 1 } m() { }} : typeof (Anonymous class)
constructor() {
this.x = 1
>this.x = 1 : 1
>this.x : number
>this : this
>x : number
>1 : 1
}
m() { }
>m : () => void
}
/** @type {Outer.Inner} */
var inner
>inner : (Anonymous class)
inner.x
>inner.x : number
>inner : (Anonymous class)
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : (Anonymous class)
>m : () => void
var inno = new Outer.Inner()
>inno : (Anonymous class)
>new Outer.Inner() : (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : { [x: string]: any; Inner: typeof (Anonymous class); }
>Inner : typeof (Anonymous class)
inno.x
>inno.x : number
>inno : (Anonymous class)
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : (Anonymous class)
>m : () => void
@@ -0,0 +1,53 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
Outer.Inner = function () {}
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
Outer.Inner.prototype = {
>Outer.Inner.prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>prototype : Symbol(Function.prototype, Decl(lib.d.ts, --, --))
x: 1,
>x : Symbol(x, Decl(a.js, 3, 25))
m() { }
>m : Symbol(m, Decl(a.js, 4, 9))
}
/** @type {Outer.Inner} */
var inner
>inner : Symbol(inner, Decl(a.js, 9, 3))
inner.x
>inner.x : Symbol(x, Decl(a.js, 3, 25))
>inner : Symbol(inner, Decl(a.js, 9, 3))
>x : Symbol(x, Decl(a.js, 3, 25))
inner.m()
>inner.m : Symbol(m, Decl(a.js, 4, 9))
>inner : Symbol(inner, Decl(a.js, 9, 3))
>m : Symbol(m, Decl(a.js, 4, 9))
var inno = new Outer.Inner()
>inno : Symbol(inno, Decl(a.js, 12, 3))
>Outer.Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
>Outer : Symbol(Outer, Decl(a.js, 0, 3), Decl(a.js, 0, 15), Decl(a.js, 2, 28))
>Inner : Symbol(Inner, Decl(a.js, 0, 15), Decl(a.js, 3, 6))
inno.x
>inno.x : Symbol(x, Decl(a.js, 3, 25))
>inno : Symbol(inno, Decl(a.js, 12, 3))
>x : Symbol(x, Decl(a.js, 3, 25))
inno.m()
>inno.m : Symbol(m, Decl(a.js, 4, 9))
>inno : Symbol(inno, Decl(a.js, 12, 3))
>m : Symbol(m, Decl(a.js, 4, 9))
@@ -0,0 +1,62 @@
=== tests/cases/conformance/salsa/a.js ===
var Outer = {};
>Outer : { [x: string]: any; Inner: () => void; }
>{} : { [x: string]: any; Inner: () => void; }
Outer.Inner = function () {}
>Outer.Inner = function () {} : () => void
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>function () {} : () => void
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : any
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
>prototype : any
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
>x : number
>1 : 1
m() { }
>m : () => void
}
/** @type {Outer.Inner} */
var inner
>inner : { [x: string]: any; x: number; m(): void; }
inner.x
>inner.x : number
>inner : { [x: string]: any; x: number; m(): void; }
>x : number
inner.m()
>inner.m() : void
>inner.m : () => void
>inner : { [x: string]: any; x: number; m(): void; }
>m : () => void
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : () => void
>Outer : { [x: string]: any; Inner: () => void; }
>Inner : () => void
inno.x
>inno.x : number
>inno : { [x: string]: any; x: number; m(): void; }
>x : number
inno.m()
>inno.m() : void
>inno.m : () => void
>inno : { [x: string]: any; x: number; m(): void; }
>m : () => void
@@ -4,7 +4,9 @@ var Outer = {};
=== tests/cases/conformance/salsa/a.js ===
Outer.Inner = class {
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
constructor() {
/** @type {number} */
@@ -15,9 +17,29 @@ Outer.Inner = class {
}
}
/** @type {Outer.Inner} */
var local
>local : Symbol(local, Decl(a.js, 8, 3))
local.y
>local.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
>local : Symbol(local, Decl(a.js, 8, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
var inner = new Outer.Inner()
>inner : Symbol(inner, Decl(a.js, 10, 3))
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
inner.y
>inner.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
>inner : Symbol(inner, Decl(a.js, 10, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
=== tests/cases/conformance/salsa/b.js ===
/** @type {Outer.Inner} */
var x;
var x
>x : Symbol(x, Decl(b.js, 1, 3))
x.y
@@ -25,3 +47,14 @@ x.y
>x : Symbol(x, Decl(b.js, 1, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
var z = new Outer.Inner()
>z : Symbol(z, Decl(b.js, 3, 3))
>Outer.Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
>Outer : Symbol(Outer, Decl(def.js, 0, 3), Decl(a.js, 0, 0))
>Inner : Symbol(Outer.Inner, Decl(a.js, 0, 0))
z.y
>z.y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
>z : Symbol(z, Decl(b.js, 3, 3))
>y : Symbol((Anonymous class).y, Decl(a.js, 1, 19))
@@ -1,14 +1,14 @@
=== tests/cases/conformance/salsa/def.js ===
var Outer = {};
>Outer : { [x: string]: any; }
>{} : { [x: string]: any; }
>Outer : typeof Outer
>{} : typeof Outer
=== tests/cases/conformance/salsa/a.js ===
Outer.Inner = class {
>Outer.Inner = class { constructor() { /** @type {number} */ this.y = 12 }} : typeof (Anonymous class)
>Outer.Inner : any
>Outer : { [x: string]: any; }
>Inner : any
>Outer.Inner : typeof (Anonymous class)
>Outer : typeof Outer
>Inner : typeof (Anonymous class)
>class { constructor() { /** @type {number} */ this.y = 12 }} : typeof (Anonymous class)
constructor() {
@@ -22,9 +22,30 @@ Outer.Inner = class {
}
}
/** @type {Outer.Inner} */
var local
>local : (Anonymous class)
local.y
>local.y : number
>local : (Anonymous class)
>y : number
var inner = new Outer.Inner()
>inner : (Anonymous class)
>new Outer.Inner() : (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : typeof Outer
>Inner : typeof (Anonymous class)
inner.y
>inner.y : number
>inner : (Anonymous class)
>y : number
=== tests/cases/conformance/salsa/b.js ===
/** @type {Outer.Inner} */
var x;
var x
>x : (Anonymous class)
x.y
@@ -32,3 +53,15 @@ x.y
>x : (Anonymous class)
>y : number
var z = new Outer.Inner()
>z : (Anonymous class)
>new Outer.Inner() : (Anonymous class)
>Outer.Inner : typeof (Anonymous class)
>Outer : typeof Outer
>Inner : typeof (Anonymous class)
z.y
>z.y : number
>z : (Anonymous class)
>y : number
@@ -0,0 +1,18 @@
=== tests/cases/conformance/salsa/a.js ===
var obj = {};
>obj : Symbol(obj, Decl(a.js, 0, 3), Decl(a.js, 0, 13))
obj.method = function (hunch) {
>obj.method : Symbol(method, Decl(a.js, 0, 13))
>obj : Symbol(obj, Decl(a.js, 0, 3), Decl(a.js, 0, 13))
>method : Symbol(method, Decl(a.js, 0, 13))
>hunch : Symbol(hunch, Decl(a.js, 1, 23))
return true;
}
var b = obj.method();
>b : Symbol(b, Decl(a.js, 4, 3))
>obj.method : Symbol(method, Decl(a.js, 0, 13))
>obj : Symbol(obj, Decl(a.js, 0, 3), Decl(a.js, 0, 13))
>method : Symbol(method, Decl(a.js, 0, 13))
@@ -0,0 +1,23 @@
=== tests/cases/conformance/salsa/a.js ===
var obj = {};
>obj : { [x: string]: any; method: (hunch: any) => boolean; }
>{} : { [x: string]: any; method: (hunch: any) => boolean; }
obj.method = function (hunch) {
>obj.method = function (hunch) { return true;} : (hunch: any) => boolean
>obj.method : (hunch: any) => boolean
>obj : { [x: string]: any; method: (hunch: any) => boolean; }
>method : (hunch: any) => boolean
>function (hunch) { return true;} : (hunch: any) => boolean
>hunch : any
return true;
>true : true
}
var b = obj.method();
>b : boolean
>obj.method() : boolean
>obj.method : (hunch: any) => boolean
>obj : { [x: string]: any; method: (hunch: any) => boolean; }
>method : (hunch: any) => boolean
@@ -0,0 +1,72 @@
=== tests/cases/conformance/salsa/a.js ===
var my = my || {};
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 1, 22))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 1, 22))
my.app = my.app || {};
>my.app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 1, 22))
>app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
>my.app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 1, 22))
>app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
my.app.Application = (function () {
>my.app.Application : Symbol(Application, Decl(a.js, 1, 22))
>my.app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 1, 22))
>app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
>Application : Symbol(Application, Decl(a.js, 1, 22))
var Application = function () {
>Application : Symbol(Application, Decl(a.js, 4, 3))
//...
};
return Application;
>Application : Symbol(Application, Decl(a.js, 4, 3))
})();
my.app.Application()
>my.app.Application : Symbol(Application, Decl(a.js, 1, 22))
>my.app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 1, 22))
>app : Symbol(app, Decl(a.js, 0, 18), Decl(a.js, 3, 3))
>Application : Symbol(Application, Decl(a.js, 1, 22))
=== tests/cases/conformance/salsa/b.js ===
var min = window.min || {};
>min : Symbol(min, Decl(b.js, 0, 3), Decl(b.js, 1, 24))
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
min.app = min.app || {};
>min.app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
>min : Symbol(min, Decl(b.js, 0, 3), Decl(b.js, 1, 24))
>app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
>min.app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
>min : Symbol(min, Decl(b.js, 0, 3), Decl(b.js, 1, 24))
>app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
min.app.Application = (function () {
>min.app.Application : Symbol(Application, Decl(b.js, 1, 24))
>min.app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
>min : Symbol(min, Decl(b.js, 0, 3), Decl(b.js, 1, 24))
>app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
>Application : Symbol(Application, Decl(b.js, 1, 24))
var Application = function () {
>Application : Symbol(Application, Decl(b.js, 4, 3))
//...
};
return Application;
>Application : Symbol(Application, Decl(b.js, 4, 3))
})();
min.app.Application()
>min.app.Application : Symbol(Application, Decl(b.js, 1, 24))
>min.app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
>min : Symbol(min, Decl(b.js, 0, 3), Decl(b.js, 1, 24))
>app : Symbol(app, Decl(b.js, 0, 27), Decl(b.js, 3, 4))
>Application : Symbol(Application, Decl(b.js, 1, 24))
@@ -0,0 +1,96 @@
=== tests/cases/conformance/salsa/a.js ===
var my = my || {};
>my : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>my || {} : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>my : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>{} : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
my.app = my.app || {};
>my.app = my.app || {} : { [x: string]: any; Application: () => void; }
>my.app : { [x: string]: any; Application: () => void; }
>my : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>my.app || {} : { [x: string]: any; Application: () => void; }
>my.app : { [x: string]: any; Application: () => void; }
>my : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>{} : { [x: string]: any; Application: () => void; }
my.app.Application = (function () {
>my.app.Application = (function () {var Application = function () { //...};return Application;})() : () => void
>my.app.Application : () => void
>my.app : { [x: string]: any; Application: () => void; }
>my : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>Application : () => void
>(function () {var Application = function () { //...};return Application;})() : () => void
>(function () {var Application = function () { //...};return Application;}) : () => () => void
>function () {var Application = function () { //...};return Application;} : () => () => void
var Application = function () {
>Application : () => void
>function () { //...} : () => void
//...
};
return Application;
>Application : () => void
})();
my.app.Application()
>my.app.Application() : void
>my.app.Application : () => void
>my.app : { [x: string]: any; Application: () => void; }
>my : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>Application : () => void
=== tests/cases/conformance/salsa/b.js ===
var min = window.min || {};
>min : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>window.min || {} : any
>window.min : any
>window : Window
>min : any
>{} : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
min.app = min.app || {};
>min.app = min.app || {} : { [x: string]: any; Application: () => void; }
>min.app : { [x: string]: any; Application: () => void; }
>min : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>min.app || {} : { [x: string]: any; Application: () => void; }
>min.app : { [x: string]: any; Application: () => void; }
>min : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>{} : { [x: string]: any; Application: () => void; }
min.app.Application = (function () {
>min.app.Application = (function () {var Application = function () { //...};return Application;})() : () => void
>min.app.Application : () => void
>min.app : { [x: string]: any; Application: () => void; }
>min : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>Application : () => void
>(function () {var Application = function () { //...};return Application;})() : () => void
>(function () {var Application = function () { //...};return Application;}) : () => () => void
>function () {var Application = function () { //...};return Application;} : () => () => void
var Application = function () {
>Application : () => void
>function () { //...} : () => void
//...
};
return Application;
>Application : () => void
})();
min.app.Application()
>min.app.Application() : void
>min.app.Application : () => void
>min.app : { [x: string]: any; Application: () => void; }
>min : { [x: string]: any; app: { [x: string]: any; Application: () => void; }; }
>app : { [x: string]: any; Application: () => void; }
>Application : () => void
@@ -0,0 +1,132 @@
=== tests/cases/conformance/salsa/a.js ===
var my = my || {};
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
/** @param {number} n */
my.method = function(n) {
>my.method : Symbol(method, Decl(a.js, 0, 18))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>method : Symbol(method, Decl(a.js, 0, 18))
>n : Symbol(n, Decl(a.js, 2, 21))
return n + 1;
>n : Symbol(n, Decl(a.js, 2, 21))
}
my.number = 1;
>my.number : Symbol(number, Decl(a.js, 4, 1))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>number : Symbol(number, Decl(a.js, 4, 1))
my.object = {};
>my.object : Symbol(object, Decl(a.js, 5, 14))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>object : Symbol(object, Decl(a.js, 5, 14))
my.predicate = my.predicate || {};
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
my.predicate.query = function () {
>my.predicate.query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
var me = this;
>me : Symbol(me, Decl(a.js, 9, 7))
>this : Symbol(__object, Decl(a.js, 7, 30))
me.property = false;
>me : Symbol(me, Decl(a.js, 9, 7))
};
var q = new my.predicate.query();
>q : Symbol(q, Decl(a.js, 12, 3))
>my.predicate.query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
my.predicate.query.another = function () {
>my.predicate.query.another : Symbol((Anonymous function).another, Decl(a.js, 12, 33))
>my.predicate.query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
>another : Symbol((Anonymous function).another, Decl(a.js, 12, 33))
return 1;
}
my.predicate.query.result = 'none'
>my.predicate.query.result : Symbol((Anonymous function).result, Decl(a.js, 15, 1))
>my.predicate.query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>query : Symbol(query, Decl(a.js, 7, 34), Decl(a.js, 13, 13))
>result : Symbol((Anonymous function).result, Decl(a.js, 15, 1))
/** @param {number} first
* @param {number} second
*/
my.predicate.sort = my.predicate.sort || function (first, second) {
>my.predicate.sort : Symbol(sort, Decl(a.js, 16, 34))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>sort : Symbol(sort, Decl(a.js, 16, 34))
>my.predicate.sort : Symbol(sort, Decl(a.js, 16, 34))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>sort : Symbol(sort, Decl(a.js, 16, 34))
>first : Symbol(first, Decl(a.js, 20, 51))
>second : Symbol(second, Decl(a.js, 20, 57))
return first > second ? first : second;
>first : Symbol(first, Decl(a.js, 20, 51))
>second : Symbol(second, Decl(a.js, 20, 57))
>first : Symbol(first, Decl(a.js, 20, 51))
>second : Symbol(second, Decl(a.js, 20, 57))
}
my.predicate.type = class {
>my.predicate.type : Symbol(type, Decl(a.js, 22, 1))
>my.predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>my : Symbol(my, Decl(a.js, 0, 3), Decl(a.js, 0, 18), Decl(a.js, 5, 14), Decl(a.js, 7, 34), Decl(a.js, 12, 33) ... and 1 more)
>predicate : Symbol(predicate, Decl(a.js, 6, 15), Decl(a.js, 8, 3), Decl(a.js, 13, 3), Decl(a.js, 23, 3))
>type : Symbol(type, Decl(a.js, 22, 1))
m() { return 101; }
>m : Symbol((Anonymous class).m, Decl(a.js, 23, 27))
}
// global-ish prefixes
var min = window.min || {};
>min : Symbol(min, Decl(a.js, 29, 3))
min.nest = this.min.nest || function () { };
>min.nest : Symbol(nest, Decl(a.js, 29, 27))
>min : Symbol(min, Decl(a.js, 29, 3))
>nest : Symbol(nest, Decl(a.js, 29, 27))
min.nest.other = self.min.nest.other || class { };
>min.nest.other : Symbol((Anonymous function).other, Decl(a.js, 30, 44))
>min.nest : Symbol(nest, Decl(a.js, 29, 27))
>min : Symbol(min, Decl(a.js, 29, 3))
>nest : Symbol(nest, Decl(a.js, 29, 27))
>other : Symbol((Anonymous function).other, Decl(a.js, 30, 44))
min.property = global.min.property || {};
>min.property : Symbol(property, Decl(a.js, 31, 50))
>min : Symbol(min, Decl(a.js, 29, 3))
>property : Symbol(property, Decl(a.js, 31, 50))
@@ -0,0 +1,196 @@
=== tests/cases/conformance/salsa/a.js ===
var my = my || {};
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>my || {} : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>{} : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
/** @param {number} n */
my.method = function(n) {
>my.method = function(n) { return n + 1;} : (n: number) => number
>my.method : (n: number) => number
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>method : (n: number) => number
>function(n) { return n + 1;} : (n: number) => number
>n : number
return n + 1;
>n + 1 : number
>n : number
>1 : 1
}
my.number = 1;
>my.number = 1 : 1
>my.number : number
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>number : number
>1 : 1
my.object = {};
>my.object = {} : { [x: string]: any; }
>my.object : { [x: string]: any; }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>object : { [x: string]: any; }
>{} : { [x: string]: any; }
my.predicate = my.predicate || {};
>my.predicate = my.predicate || {} : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my.predicate || {} : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>{} : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
my.predicate.query = function () {
>my.predicate.query = function () { var me = this; me.property = false;} : { (): void; another: () => number; result: string; }
>my.predicate.query : { (): void; another: () => number; result: string; }
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>query : { (): void; another: () => number; result: string; }
>function () { var me = this; me.property = false;} : { (): void; another: () => number; result: string; }
var me = this;
>me : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>this : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
me.property = false;
>me.property = false : false
>me.property : any
>me : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>property : any
>false : false
};
var q = new my.predicate.query();
>q : any
>new my.predicate.query() : any
>my.predicate.query : { (): void; another: () => number; result: string; }
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>query : { (): void; another: () => number; result: string; }
my.predicate.query.another = function () {
>my.predicate.query.another = function () { return 1;} : () => number
>my.predicate.query.another : () => number
>my.predicate.query : { (): void; another: () => number; result: string; }
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>query : { (): void; another: () => number; result: string; }
>another : () => number
>function () { return 1;} : () => number
return 1;
>1 : 1
}
my.predicate.query.result = 'none'
>my.predicate.query.result = 'none' : "none"
>my.predicate.query.result : string
>my.predicate.query : { (): void; another: () => number; result: string; }
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>query : { (): void; another: () => number; result: string; }
>result : string
>'none' : "none"
/** @param {number} first
* @param {number} second
*/
my.predicate.sort = my.predicate.sort || function (first, second) {
>my.predicate.sort = my.predicate.sort || function (first, second) { return first > second ? first : second;} : (first: number, second: number) => number
>my.predicate.sort : (first: number, second: number) => number
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>sort : (first: number, second: number) => number
>my.predicate.sort || function (first, second) { return first > second ? first : second;} : (first: number, second: number) => number
>my.predicate.sort : (first: number, second: number) => number
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>sort : (first: number, second: number) => number
>function (first, second) { return first > second ? first : second;} : (first: number, second: number) => number
>first : number
>second : number
return first > second ? first : second;
>first > second ? first : second : number
>first > second : boolean
>first : number
>second : number
>first : number
>second : number
}
my.predicate.type = class {
>my.predicate.type = class { m() { return 101; }} : typeof (Anonymous class)
>my.predicate.type : typeof (Anonymous class)
>my.predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>my : { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }
>predicate : { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }
>type : typeof (Anonymous class)
>class { m() { return 101; }} : typeof (Anonymous class)
m() { return 101; }
>m : () => number
>101 : 101
}
// global-ish prefixes
var min = window.min || {};
>min : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; }
>window.min || {} : any
>window.min : any
>window : any
>min : any
>{} : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; }
min.nest = this.min.nest || function () { };
>min.nest = this.min.nest || function () { } : { (): void; other: typeof (Anonymous class); }
>min.nest : { (): void; other: typeof (Anonymous class); }
>min : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; }
>nest : { (): void; other: typeof (Anonymous class); }
>this.min.nest || function () { } : { (): void; other: typeof (Anonymous class); }
>this.min.nest : any
>this.min : any
>this : any
>min : any
>nest : any
>function () { } : { (): void; other: typeof (Anonymous class); }
min.nest.other = self.min.nest.other || class { };
>min.nest.other = self.min.nest.other || class { } : typeof (Anonymous class)
>min.nest.other : typeof (Anonymous class)
>min.nest : { (): void; other: typeof (Anonymous class); }
>min : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; }
>nest : { (): void; other: typeof (Anonymous class); }
>other : typeof (Anonymous class)
>self.min.nest.other || class { } : typeof (Anonymous class)
>self.min.nest.other : any
>self.min.nest : any
>self.min : any
>self : any
>min : any
>nest : any
>other : any
>class { } : typeof (Anonymous class)
min.property = global.min.property || {};
>min.property = global.min.property || {} : { [x: string]: any; }
>min.property : { [x: string]: any; }
>min : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; }
>property : { [x: string]: any; }
>global.min.property || {} : { [x: string]: any; }
>global.min.property : any
>global.min : any
>global : any
>min : any
>property : any
>{} : { [x: string]: any; }
@@ -1,24 +1,24 @@
=== tests/cases/conformance/salsa/index.js ===
Common.Item = class I {}
>Common.Item : Symbol(Common.Item, Decl(index.js, 0, 0))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Item : Symbol(Common.Item, Decl(index.js, 0, 0))
>I : Symbol(I, Decl(index.js, 0, 13))
Common.Object = class extends Common.Item {}
>Common.Object : Symbol(Common.Object, Decl(index.js, 0, 24))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Object : Symbol(Common.Object, Decl(index.js, 0, 24))
>Common.Item : Symbol(Common.Item, Decl(index.js, 0, 0))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Item : Symbol(Common.Item, Decl(index.js, 0, 0))
Workspace.Object = class extends Common.Object {}
>Workspace.Object : Symbol(Workspace.Object, Decl(index.js, 1, 44))
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3))
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3), Decl(roots.js, 1, 15))
>Object : Symbol(Workspace.Object, Decl(index.js, 1, 44))
>Common.Object : Symbol(Common.Object, Decl(index.js, 0, 24))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
>Object : Symbol(Common.Object, Decl(index.js, 0, 24))
/** @type {Workspace.Object} */
@@ -27,8 +27,8 @@ var am;
=== tests/cases/conformance/salsa/roots.js ===
var Common = {};
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3))
>Common : Symbol(Common, Decl(index.js, 0, 0), Decl(roots.js, 0, 3), Decl(roots.js, 0, 12))
var Workspace = {};
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3))
>Workspace : Symbol(Workspace, Decl(index.js, 1, 44), Decl(roots.js, 1, 3), Decl(roots.js, 1, 15))
@@ -34,9 +34,9 @@ var am;
=== tests/cases/conformance/salsa/roots.js ===
var Common = {};
>Common : typeof Common
>{} : { [x: string]: any; }
>{} : { [x: string]: any; Item: typeof I; Object: typeof (Anonymous class); }
var Workspace = {};
>Workspace : typeof Workspace
>{} : { [x: string]: any; }
>{} : { [x: string]: any; Object: typeof (Anonymous class); }
@@ -2,12 +2,16 @@
// this is a javascript file...
export const Adapter = {};
>Adapter : Symbol(Adapter, Decl(a.js, 2, 12), Decl(a.js, 4, 18))
>Adapter : Symbol(Adapter, Decl(a.js, 2, 12), Decl(a.js, 2, 26), Decl(a.js, 4, 18))
Adapter.prop = {};
>Adapter : Symbol(Adapter, Decl(a.js, 2, 12), Decl(a.js, 4, 18))
>Adapter.prop : Symbol(prop, Decl(a.js, 2, 26))
>Adapter : Symbol(Adapter, Decl(a.js, 2, 12), Decl(a.js, 2, 26), Decl(a.js, 4, 18))
>prop : Symbol(prop, Decl(a.js, 2, 26))
// comment this out, and it works
Adapter.asyncMethod = function() {}
>Adapter : Symbol(Adapter, Decl(a.js, 2, 12), Decl(a.js, 4, 18))
>Adapter.asyncMethod : Symbol(asyncMethod, Decl(a.js, 4, 18))
>Adapter : Symbol(Adapter, Decl(a.js, 2, 12), Decl(a.js, 2, 26), Decl(a.js, 4, 18))
>asyncMethod : Symbol(asyncMethod, Decl(a.js, 4, 18))
@@ -2,21 +2,21 @@
// this is a javascript file...
export const Adapter = {};
>Adapter : { [x: string]: any; }
>{} : { [x: string]: any; }
>Adapter : { [x: string]: any; prop: { [x: string]: any; }; asyncMethod: () => void; }
>{} : { [x: string]: any; prop: { [x: string]: any; }; asyncMethod: () => void; }
Adapter.prop = {};
>Adapter.prop = {} : {}
>Adapter.prop : any
>Adapter : { [x: string]: any; }
>prop : any
>{} : {}
>Adapter.prop = {} : { [x: string]: any; }
>Adapter.prop : { [x: string]: any; }
>Adapter : { [x: string]: any; prop: { [x: string]: any; }; asyncMethod: () => void; }
>prop : { [x: string]: any; }
>{} : { [x: string]: any; }
// comment this out, and it works
Adapter.asyncMethod = function() {}
>Adapter.asyncMethod = function() {} : () => void
>Adapter.asyncMethod : any
>Adapter : { [x: string]: any; }
>asyncMethod : any
>Adapter.asyncMethod : () => void
>Adapter : { [x: string]: any; prop: { [x: string]: any; }; asyncMethod: () => void; }
>asyncMethod : () => void
>function() {} : () => void
@@ -0,0 +1,21 @@
tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts(10,5): error TS2322: Type '{ [SYM]: "str"; }' is not assignable to type 'I'.
Types of property '[SYM]' are incompatible.
Type '"str"' is not assignable to type '"sym"'.
==== tests/cases/compiler/uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts (1 errors) ====
// https://github.com/Microsoft/TypeScript/issues/21962
export const SYM = Symbol('a unique symbol');
export interface I {
[SYM]: 'sym';
[x: string]: 'str';
}
let a: I = {[SYM]: 'sym'}; // Expect ok
let b: I = {[SYM]: 'str'}; // Expect error
~
!!! error TS2322: Type '{ [SYM]: "str"; }' is not assignable to type 'I'.
!!! error TS2322: Types of property '[SYM]' are incompatible.
!!! error TS2322: Type '"str"' is not assignable to type '"sym"'.
@@ -0,0 +1,21 @@
//// [uniqueSymbolAllowsIndexInObjectWithIndexSignature.ts]
// https://github.com/Microsoft/TypeScript/issues/21962
export const SYM = Symbol('a unique symbol');
export interface I {
[SYM]: 'sym';
[x: string]: 'str';
}
let a: I = {[SYM]: 'sym'}; // Expect ok
let b: I = {[SYM]: 'str'}; // Expect error
//// [uniqueSymbolAllowsIndexInObjectWithIndexSignature.js]
"use strict";
exports.__esModule = true;
// https://github.com/Microsoft/TypeScript/issues/21962
exports.SYM = Symbol('a unique symbol');
var a = (_a = {}, _a[exports.SYM] = 'sym', _a); // Expect ok
var b = (_b = {}, _b[exports.SYM] = 'str', _b); // Expect error
var _a, _b;

Some files were not shown because too many files have changed in this diff Show More