diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 6edba58cb11..2993ec3aa0c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1,3 +1,4 @@ +/// /// /* @internal */ @@ -6,8 +7,8 @@ namespace ts { export const enum ModuleInstanceState { NonInstantiated = 0, - Instantiated = 1, - ConstEnumOnly = 2 + Instantiated = 1, + ConstEnumOnly = 2 } const enum Reachability { @@ -188,6 +189,11 @@ namespace ts { } if (node.name.kind === SyntaxKind.ComputedPropertyName) { const nameExpression = (node.name).expression; + // treat computed property names where expression is string/numeric literal as just string/numeric literal + if (isStringOrNumericLiteral(nameExpression.kind)) { + return (nameExpression).text; + } + Debug.assert(isWellKnownSymbolSyntactically(nameExpression)); return getPropertyNameForKnownSymbolName((nameExpression).name.text); } @@ -208,6 +214,9 @@ namespace ts { return "__export"; case SyntaxKind.ExportAssignment: return (node).isExportEquals ? "export=" : "default"; + case SyntaxKind.BinaryExpression: + // Binary expression case is for JS module 'module.exports = expr' + return "export="; case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: return node.flags & NodeFlags.Default ? "default" : undefined; @@ -1069,7 +1078,7 @@ namespace ts { return "__" + indexOf((node.parent).parameters, node); } - function bind(node: Node) { + function bind(node: Node): void { if (!node) { return; } @@ -1145,9 +1154,18 @@ namespace ts { function bindWorker(node: Node) { switch (node.kind) { + /* Strict mode checks */ case SyntaxKind.Identifier: return checkStrictModeIdentifier(node); case SyntaxKind.BinaryExpression: + if (isInJavaScriptFile(node)) { + if (isExportsPropertyAssignment(node)) { + bindExportsPropertyAssignment(node); + } + else if (isModuleExportsAssignment(node)) { + bindModuleExportsAssignment(node); + } + } return checkStrictModeBinaryExpression(node); case SyntaxKind.CatchClause: return checkStrictModeCatchClause(node); @@ -1213,6 +1231,14 @@ namespace ts { checkStrictModeFunctionName(node); const bindingName = (node).name ? (node).name.text : "__function"; return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName); + + case SyntaxKind.CallExpression: + if (isInJavaScriptFile(node)) { + bindCallExpression(node); + } + break; + + // Members of classes, interfaces, and modules case SyntaxKind.ClassExpression: case SyntaxKind.ClassDeclaration: return bindClassLikeDeclaration(node); @@ -1224,6 +1250,8 @@ namespace ts { return bindEnumDeclaration(node); case SyntaxKind.ModuleDeclaration: return bindModuleDeclaration(node); + + // Imports and exports case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.NamespaceImport: case SyntaxKind.ImportSpecifier: @@ -1243,16 +1271,21 @@ namespace ts { function bindSourceFileIfExternalModule() { setExportContextFlag(file); if (isExternalModule(file)) { - bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName)}"`); + bindSourceFileAsExternalModule(); } } - function bindExportAssignment(node: ExportAssignment) { + function bindSourceFileAsExternalModule() { + bindAnonymousDeclaration(file, SymbolFlags.ValueModule, `"${removeFileExtension(file.fileName) }"`); + } + + function bindExportAssignment(node: ExportAssignment | BinaryExpression) { + const boundExpression = node.kind === SyntaxKind.ExportAssignment ? (node).expression : (node).right; if (!container.symbol || !container.symbol.exports) { // Export assignment in some sort of block construct bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)); } - else if (node.expression.kind === SyntaxKind.Identifier) { + else if (boundExpression.kind === SyntaxKind.Identifier) { // An export default clause with an identifier exports all meanings of that identifier declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes); } @@ -1279,6 +1312,34 @@ namespace ts { } } + function setCommonJsModuleIndicator(node: Node) { + if (!file.commonJsModuleIndicator) { + file.commonJsModuleIndicator = node; + bindSourceFileAsExternalModule(); + } + } + + function bindExportsPropertyAssignment(node: BinaryExpression) { + // 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, node.left, SymbolFlags.Property | SymbolFlags.Export, SymbolFlags.None); + } + + function bindModuleExportsAssignment(node: BinaryExpression) { + // 'module.exports = expr' assignment + setCommonJsModuleIndicator(node); + bindExportAssignment(node); + } + + function bindCallExpression(node: CallExpression) { + // We're only inspecting call expressions to detect CommonJS modules, so we can skip + // this check if we've already seen the module indicator + if (!file.commonJsModuleIndicator && isRequireCall(node)) { + setCommonJsModuleIndicator(node); + } + } + function bindClassLikeDeclaration(node: ClassLikeDeclaration) { if (node.kind === SyntaxKind.ClassDeclaration) { bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bfd2eb8d7b8..d9f5474e2ff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -364,7 +364,7 @@ namespace ts { } function isGlobalSourceFile(node: Node) { - return node.kind === SyntaxKind.SourceFile && !isExternalModule(node); + return node.kind === SyntaxKind.SourceFile && !isExternalOrCommonJsModule(node); } function getSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags): Symbol { @@ -480,7 +480,7 @@ namespace ts { } switch (location.kind) { case SyntaxKind.SourceFile: - if (!isExternalModule(location)) break; + if (!isExternalOrCommonJsModule(location)) break; case SyntaxKind.ModuleDeclaration: const moduleExports = getSymbolOfNode(location).exports; if (location.kind === SyntaxKind.SourceFile || @@ -990,11 +990,16 @@ namespace ts { // Module names are escaped in our symbol table. However, string literal values aren't. // Escape the name in the "require(...)" clause to ensure we find the right symbol. - const moduleName = escapeIdentifier(moduleReferenceLiteral.text); + let moduleName = escapeIdentifier(moduleReferenceLiteral.text); if (moduleName === undefined) { return; } + + if (moduleName.indexOf("!") >= 0) { + moduleName = moduleName.substr(0, moduleName.indexOf("!")); + } + const isRelative = isExternalModuleNameRelative(moduleName); if (!isRelative) { const symbol = getSymbol(globals, "\"" + moduleName + "\"", SymbolFlags.ValueModule); @@ -1205,7 +1210,7 @@ namespace ts { } switch (location.kind) { case SyntaxKind.SourceFile: - if (!isExternalModule(location)) { + if (!isExternalOrCommonJsModule(location)) { break; } case SyntaxKind.ModuleDeclaration: @@ -1387,7 +1392,7 @@ namespace ts { function hasExternalModuleSymbol(declaration: Node) { return (declaration.kind === SyntaxKind.ModuleDeclaration && (declaration).name.kind === SyntaxKind.StringLiteral) || - (declaration.kind === SyntaxKind.SourceFile && isExternalModule(declaration)); + (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration)); } function hasVisibleDeclarations(symbol: Symbol): SymbolVisibilityResult { @@ -2061,7 +2066,7 @@ namespace ts { } } else if (node.kind === SyntaxKind.SourceFile) { - return isExternalModule(node) ? node : undefined; + return isExternalOrCommonJsModule(node) ? node : undefined; } } Debug.fail("getContainingModule cant reach here"); @@ -2182,7 +2187,7 @@ namespace ts { case SyntaxKind.SourceFile: return true; - // Export assignements do not create name bindings outside the module + // Export assignments do not create name bindings outside the module case SyntaxKind.ExportAssignment: return false; @@ -2337,6 +2342,26 @@ namespace ts { return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node); } + function getTextOfPropertyName(name: PropertyName): string { + switch (name.kind) { + case SyntaxKind.Identifier: + return (name).text; + case SyntaxKind.StringLiteral: + case SyntaxKind.NumericLiteral: + return (name).text; + case SyntaxKind.ComputedPropertyName: + if (isStringOrNumericLiteral((name).expression.kind)) { + return ((name).expression).text; + } + } + + return undefined; + } + + function isComputedNonLiteralName(name: PropertyName): boolean { + return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((name).expression.kind); + } + // Return the inferred type for a binding element function getTypeForBindingElement(declaration: BindingElement): Type { const pattern = declaration.parent; @@ -2359,10 +2384,17 @@ namespace ts { if (pattern.kind === SyntaxKind.ObjectBindingPattern) { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) const name = declaration.propertyName || declaration.name; + if (isComputedNonLiteralName(name)) { + // computed properties with non-literal names are treated as 'any' + return anyType; + } + // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, // or otherwise the type of the string index signature. - type = getTypeOfPropertyOfType(parentType, name.text) || - isNumericLiteralName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) || + const text = getTextOfPropertyName(name); + + type = getTypeOfPropertyOfType(parentType, text) || + isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); if (!type) { error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name)); @@ -2473,10 +2505,18 @@ namespace ts { // Return the type implied by an object binding pattern function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type { const members: SymbolTable = {}; + let hasComputedProperties = false; forEach(pattern.elements, e => { - const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); const name = e.propertyName || e.name; - const symbol = createSymbol(flags, name.text); + if (isComputedNonLiteralName(name)) { + // do not include computed properties in the implied type + hasComputedProperties = true; + return; + } + + const text = getTextOfPropertyName(name); + const flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0); + const symbol = createSymbol(flags, text); symbol.type = getTypeFromBindingElement(e, includePatternInType); symbol.bindingElement = e; members[symbol.name] = symbol; @@ -2485,6 +2525,9 @@ namespace ts { if (includePatternInType) { result.pattern = pattern; } + if (hasComputedProperties) { + result.flags |= TypeFlags.ObjectLiteralPatternWithComputedProperties; + } return result; } @@ -2567,6 +2610,14 @@ namespace ts { if (declaration.kind === SyntaxKind.ExportAssignment) { return links.type = checkExpression((declaration).expression); } + // Handle module.exports = expr + if (declaration.kind === SyntaxKind.BinaryExpression) { + return links.type = checkExpression((declaration).right); + } + // Handle exports.p = expr + if (declaration.kind === SyntaxKind.PropertyAccessExpression) { + return checkExpressionCached((declaration.parent).right); + } // Handle variable, parameter or property if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) { return unknownType; @@ -2870,23 +2921,25 @@ namespace ts { function resolveBaseTypesOfClass(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; - const baseContructorType = getBaseConstructorTypeOfClass(type); - if (!(baseContructorType.flags & TypeFlags.ObjectType)) { + const baseConstructorType = getBaseConstructorTypeOfClass(type); + if (!(baseConstructorType.flags & TypeFlags.ObjectType)) { return; } const baseTypeNode = getBaseTypeNodeOfClass(type); let baseType: Type; - if (baseContructorType.symbol && baseContructorType.symbol.flags & SymbolFlags.Class) { - // When base constructor type is a class we know that the constructors all have the same type parameters as the + const originalBaseType = baseConstructorType && baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined; + if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class && + areAllOuterTypeParametersApplied(originalBaseType)) { + // When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the // class and all return the instance type of the class. There is no need for further checks and we can apply the // type arguments in the same manner as a type reference to get the same error reporting experience. - baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseContructorType.symbol); + baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol); } else { // The class derives from a "class-like" constructor function, check that we have at least one construct signature // with a matching number of type parameters and use the return type of the first instantiated signature. Elsewhere // we check that all instantiated signatures return the same type. - const constructors = getInstantiatedConstructorsForTypeArguments(baseContructorType, baseTypeNode.typeArguments); + const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments); if (!constructors.length) { error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments); return; @@ -2913,6 +2966,18 @@ namespace ts { } } + function areAllOuterTypeParametersApplied(type: Type): boolean { + // An unapplied type parameter has its symbol still the same as the matching argument symbol. + // Since parameters are applied outer-to-inner, only the last outer parameter needs to be checked. + const outerTypeParameters = (type).outerTypeParameters; + if (outerTypeParameters) { + const last = outerTypeParameters.length - 1; + const typeArguments = (type).typeArguments; + return outerTypeParameters[last].symbol !== typeArguments[last].symbol; + } + return true; + } + function resolveBaseTypesOfInterface(type: InterfaceType): void { type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray; for (const declaration of type.symbol.declarations) { @@ -3841,6 +3906,18 @@ namespace ts { return result; } + function resolveExternalModuleTypeByLiteral(name: StringLiteral) { + const moduleSym = resolveExternalModuleName(name, name); + if (moduleSym) { + const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym); + if (resolvedModuleSymbol) { + return getTypeOfSymbol(resolvedModuleSymbol); + } + } + + return anyType; + } + function getReturnTypeOfSignature(signature: Signature): Type { if (!signature.resolvedReturnType) { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { @@ -4988,7 +5065,7 @@ namespace ts { } function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (someConstituentTypeHasKind(target, TypeFlags.ObjectType)) { + if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && someConstituentTypeHasKind(target, TypeFlags.ObjectType)) { for (const prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { if (reportErrors) { @@ -7442,6 +7519,7 @@ namespace ts { (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); let typeFlags: TypeFlags = 0; + let patternWithComputedProperties = false; for (const memberDecl of node.properties) { let member = memberDecl.symbol; if (memberDecl.kind === SyntaxKind.PropertyAssignment || @@ -7469,8 +7547,11 @@ namespace ts { if (isOptional) { prop.flags |= SymbolFlags.Optional; } + if (hasDynamicName(memberDecl)) { + patternWithComputedProperties = true; + } } - else if (contextualTypeHasPattern) { + else if (contextualTypeHasPattern && !(contextualType.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties)) { // If object literal is contextually typed by the implied type of a binding pattern, and if the // binding pattern specifies a default value for the property, make the property optional. const impliedProp = getPropertyOfType(contextualType, member.name); @@ -7527,7 +7608,7 @@ namespace ts { const numberIndexType = getIndexType(IndexKind.Number); const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType); const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral; - result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags); + result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0); if (inDestructuringPattern) { result.pattern = node; } @@ -9426,6 +9507,12 @@ namespace ts { return anyType; } } + + // In JavaScript files, calls to any identifier 'require' are treated as external module imports + if (isInJavaScriptFile(node) && isRequireCall(node)) { + return resolveExternalModuleTypeByLiteral(node.arguments[0]); + } + return getReturnTypeOfSignature(signature); } @@ -10051,19 +10138,27 @@ namespace ts { const properties = node.properties; for (const p of properties) { if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { - // TODO(andersh): Computed property support - const name = (p).name; + const name = (p).name; + if (name.kind === SyntaxKind.ComputedPropertyName) { + checkComputedPropertyName(name); + } + if (isComputedNonLiteralName(name)) { + continue; + } + + const text = getTextOfPropertyName(name); const type = isTypeAny(sourceType) ? sourceType - : getTypeOfPropertyOfType(sourceType, name.text) || - isNumericLiteralName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) || + : getTypeOfPropertyOfType(sourceType, text) || + isNumericLiteralName(text) && getIndexTypeOfType(sourceType, IndexKind.Number) || getIndexTypeOfType(sourceType, IndexKind.String); if (type) { if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { checkDestructuringAssignment(p, type); } else { - checkDestructuringAssignment((p).initializer || name, type); + // non-shorthand property assignments should always have initializers + checkDestructuringAssignment((p).initializer, type); } } else { @@ -12067,7 +12162,7 @@ namespace ts { // In case of variable declaration, node.parent is variable statement so look at the variable statement's parent const parent = getDeclarationContainer(node); - if (parent.kind === SyntaxKind.SourceFile && isExternalModule(parent)) { + if (parent.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(parent)) { // If the declaration happens to be in external module, report error that require and exports are reserved keywords error(name, Diagnostics.Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_a_module, declarationNameToString(name), declarationNameToString(name)); @@ -12196,6 +12291,14 @@ namespace ts { checkExpressionCached(node.initializer); } } + + if (node.kind === SyntaxKind.BindingElement) { + // check computed properties inside property names of binding elements + if (node.propertyName && node.propertyName.kind === SyntaxKind.ComputedPropertyName) { + checkComputedPropertyName(node.propertyName); + } + } + // For a binding pattern, check contained binding elements if (isBindingPattern(node.name)) { forEach((node.name).elements, checkSourceElement); @@ -13307,11 +13410,14 @@ namespace ts { const enumIsConst = isConst(node); for (const member of node.members) { - if (member.name.kind === SyntaxKind.ComputedPropertyName) { + if (isComputedNonLiteralName(member.name)) { error(member.name, Diagnostics.Computed_property_names_are_not_allowed_in_enums); } - else if (isNumericLiteralName((member.name).text)) { - error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); + else { + const text = getTextOfPropertyName(member.name); + if (isNumericLiteralName(text)) { + error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name); + } } const previousEnumMemberIsNonConstant = autoValue === undefined; @@ -14150,7 +14256,7 @@ namespace ts { forEach(node.statements, checkSourceElement); checkFunctionAndClassExpressionBodies(node); - if (isExternalModule(node)) { + if (isExternalOrCommonJsModule(node)) { checkExternalModuleExports(node); } @@ -14253,7 +14359,7 @@ namespace ts { switch (location.kind) { case SyntaxKind.SourceFile: - if (!isExternalModule(location)) { + if (!isExternalOrCommonJsModule(location)) { break; } case SyntaxKind.ModuleDeclaration: @@ -14999,16 +15105,16 @@ namespace ts { // Initialize global symbol table forEach(host.getSourceFiles(), file => { - if (!isExternalModule(file)) { + if (!isExternalOrCommonJsModule(file)) { mergeSymbolTable(globals, file.locals); } }); - // Initialize special symbols getSymbolLinks(undefinedSymbol).type = undefinedType; getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments"); getSymbolLinks(unknownSymbol).type = unknownType; globals[undefinedSymbol.name] = undefinedSymbol; + // Initialize special types globalArrayType = getGlobalType("Array", /*arity*/ 1); globalObjectType = getGlobalType("Object"); @@ -15769,7 +15875,7 @@ namespace ts { } function checkGrammarForNonSymbolComputedProperty(node: DeclarationName, message: DiagnosticMessage) { - if (node.kind === SyntaxKind.ComputedPropertyName && !isWellKnownSymbolSyntactically((node).expression)) { + if (isDynamicName(node)) { return grammarErrorOnNode(node, message); } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 2ce3bbfaf3b..c866cf41a92 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -739,12 +739,7 @@ namespace ts { * List of supported extensions in order of file resolution precedence. */ export const supportedExtensions = [".ts", ".tsx", ".d.ts"]; - /** - * List of extensions that will be used to look for external modules. - * This list is kept separate from supportedExtensions to for cases when we'll allow to include .js files in compilation, - * but still would like to load only TypeScript files as modules - */ - export const moduleFileExtensions = supportedExtensions; + export const supportedJsExtensions = supportedExtensions.concat(".js", ".jsx"); export function isSupportedSourceFileName(fileName: string) { if (!fileName) { return false; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a43f4ded66c..d0314649b88 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -4244,15 +4244,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return node; } - function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression { - // We create a synthetic copy of the identifier in order to avoid the rewriting that might - // otherwise occur when the identifier is emitted. - const syntheticName = createSynthesizedNode(propName.kind); - syntheticName.text = propName.text; - if (syntheticName.kind !== SyntaxKind.Identifier) { - return createElementAccessExpression(object, syntheticName); + function createPropertyAccessForDestructuringProperty(object: Expression, propName: PropertyName): Expression { + let index: Expression; + const nameIsComputed = propName.kind === SyntaxKind.ComputedPropertyName; + if (nameIsComputed) { + index = ensureIdentifier((propName).expression, /* reuseIdentifierExpression */ false); } - return createPropertyAccessExpression(object, syntheticName); + else { + // We create a synthetic copy of the identifier in order to avoid the rewriting that might + // otherwise occur when the identifier is emitted. + index = createSynthesizedNode(propName.kind); + (index).text = (propName).text; + } + + return !nameIsComputed && index.kind === SyntaxKind.Identifier + ? createPropertyAccessExpression(object, index) + : createElementAccessExpression(object, index); } function createSliceCall(value: Expression, sliceIndex: number): CallExpression { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 39b5a5d322e..96c8e19e7bc 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1,5 +1,5 @@ -/// /// +/// namespace ts { /* @internal */ export let parseTime = 0; @@ -534,7 +534,8 @@ namespace ts { let parseErrorBeforeNextFinishedNode = false; export function parseSourceFile(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean): SourceFile { - initializeState(fileName, _sourceText, languageVersion, _syntaxCursor); + const isJavaScriptFile = hasJavaScriptFileExtension(fileName) || _sourceText.lastIndexOf("// @language=javascript", 0) === 0; + initializeState(fileName, _sourceText, languageVersion, isJavaScriptFile, _syntaxCursor); const result = parseSourceFileWorker(fileName, languageVersion, setParentNodes); @@ -543,7 +544,7 @@ namespace ts { return result; } - function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor) { + function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, isJavaScriptFile: boolean, _syntaxCursor: IncrementalParser.SyntaxCursor) { NodeConstructor = objectAllocator.getNodeConstructor(); SourceFileConstructor = objectAllocator.getSourceFileConstructor(); @@ -556,14 +557,14 @@ namespace ts { identifierCount = 0; nodeCount = 0; - contextFlags = isJavaScript(fileName) ? ParserContextFlags.JavaScriptFile : ParserContextFlags.None; + contextFlags = isJavaScriptFile ? ParserContextFlags.JavaScriptFile : ParserContextFlags.None; parseErrorBeforeNextFinishedNode = false; // Initialize and prime the scanner before parsing the source elements. scanner.setText(sourceText); scanner.setOnError(scanError); scanner.setScriptTarget(languageVersion); - scanner.setLanguageVariant(isTsx(fileName) ? LanguageVariant.JSX : LanguageVariant.Standard); + scanner.setLanguageVariant(allowsJsxExpressions(fileName) ? LanguageVariant.JSX : LanguageVariant.Standard); } function clearState() { @@ -582,6 +583,10 @@ namespace ts { function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean): SourceFile { sourceFile = createSourceFile(fileName, languageVersion); + if (contextFlags & ParserContextFlags.JavaScriptFile) { + sourceFile.parserContextFlags = ParserContextFlags.JavaScriptFile; + } + // Prime the scanner. token = nextToken(); processReferenceComments(sourceFile); @@ -604,7 +609,7 @@ namespace ts { // If this is a javascript file, proactively see if we can get JSDoc comments for // relevant nodes in the file. We'll use these to provide typing informaion if they're // available. - if (isJavaScript(fileName)) { + if (isSourceFileJavaScript(sourceFile)) { addJSDocComments(); } @@ -677,7 +682,7 @@ namespace ts { sourceFile.languageVersion = languageVersion; sourceFile.fileName = normalizePath(fileName); sourceFile.flags = fileExtensionIs(sourceFile.fileName, ".d.ts") ? NodeFlags.DeclarationFile : 0; - sourceFile.languageVariant = isTsx(sourceFile.fileName) ? LanguageVariant.JSX : LanguageVariant.Standard; + sourceFile.languageVariant = allowsJsxExpressions(sourceFile.fileName) ? LanguageVariant.JSX : LanguageVariant.Standard; return sourceFile; } @@ -1202,7 +1207,7 @@ namespace ts { case ParsingContext.ObjectLiteralMembers: return token === SyntaxKind.OpenBracketToken || token === SyntaxKind.AsteriskToken || isLiteralPropertyName(); case ParsingContext.ObjectBindingElements: - return isLiteralPropertyName(); + return token === SyntaxKind.OpenBracketToken || isLiteralPropertyName(); case ParsingContext.HeritageClauseElement: // If we see { } then only consume it as an expression if it is followed by , or { // That way we won't consume the body of a class in its heritage clause. @@ -4582,7 +4587,6 @@ namespace ts { function parseObjectBindingElement(): BindingElement { const node = createNode(SyntaxKind.BindingElement); - // TODO(andersh): Handle computed properties const tokenIsIdentifier = isIdentifier(); const propertyName = parsePropertyName(); if (tokenIsIdentifier && token !== SyntaxKind.ColonToken) { @@ -4590,7 +4594,7 @@ namespace ts { } else { parseExpected(SyntaxKind.ColonToken); - node.propertyName = propertyName; + node.propertyName = propertyName; node.name = parseIdentifierOrPattern(); } node.initializer = parseBindingElementInitializer(/*inParameter*/ false); @@ -5519,7 +5523,7 @@ namespace ts { } export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number) { - initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined); + initializeState("file.js", content, ScriptTarget.Latest, /*isJavaScriptFile*/ true, /*_syntaxCursor:*/ undefined); const jsDocTypeExpression = parseJSDocTypeExpression(start, length); const diagnostics = parseDiagnostics; clearState(); @@ -5840,7 +5844,7 @@ namespace ts { } export function parseIsolatedJSDocComment(content: string, start: number, length: number) { - initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined); + initializeState("file.js", content, ScriptTarget.Latest, /*isJavaScriptFile*/ true, /*_syntaxCursor:*/ undefined); const jsDocComment = parseJSDocComment(/*parent:*/ undefined, start, length); const diagnostics = parseDiagnostics; clearState(); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 8f031a4de43..08321da82e9 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -53,13 +53,13 @@ namespace ts { if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) { const failedLookupLocations: string[] = []; const candidate = normalizePath(combinePaths(containingDirectory, moduleName)); - let resolvedFileName = loadNodeModuleFromFile(candidate, failedLookupLocations, host); + let resolvedFileName = loadNodeModuleFromFile(supportedJsExtensions, candidate, failedLookupLocations, host); if (resolvedFileName) { return { resolvedModule: { resolvedFileName }, failedLookupLocations }; } - resolvedFileName = loadNodeModuleFromDirectory(candidate, failedLookupLocations, host); + resolvedFileName = loadNodeModuleFromDirectory(supportedJsExtensions, candidate, failedLookupLocations, host); return resolvedFileName ? { resolvedModule: { resolvedFileName }, failedLookupLocations } : { resolvedModule: undefined, failedLookupLocations }; @@ -69,8 +69,8 @@ namespace ts { } } - function loadNodeModuleFromFile(candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string { - return forEach(moduleFileExtensions, tryLoad); + function loadNodeModuleFromFile(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string { + return forEach(extensions, tryLoad); function tryLoad(ext: string): string { const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext; @@ -84,7 +84,7 @@ namespace ts { } } - function loadNodeModuleFromDirectory(candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string { + function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string { const packageJsonPath = combinePaths(candidate, "package.json"); if (host.fileExists(packageJsonPath)) { @@ -100,7 +100,7 @@ namespace ts { } if (jsonContent.typings) { - const result = loadNodeModuleFromFile(normalizePath(combinePaths(candidate, jsonContent.typings)), failedLookupLocation, host); + const result = loadNodeModuleFromFile(extensions, normalizePath(combinePaths(candidate, jsonContent.typings)), failedLookupLocation, host); if (result) { return result; } @@ -111,7 +111,7 @@ namespace ts { failedLookupLocation.push(packageJsonPath); } - return loadNodeModuleFromFile(combinePaths(candidate, "index"), failedLookupLocation, host); + return loadNodeModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocation, host); } function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { @@ -122,12 +122,12 @@ namespace ts { if (baseName !== "node_modules") { const nodeModulesFolder = combinePaths(directory, "node_modules"); const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName)); - let result = loadNodeModuleFromFile(candidate, failedLookupLocations, host); + let result = loadNodeModuleFromFile(supportedExtensions, candidate, failedLookupLocations, host); if (result) { return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations }; } - result = loadNodeModuleFromDirectory(candidate, failedLookupLocations, host); + result = loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, host); if (result) { return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations }; } @@ -162,9 +162,10 @@ namespace ts { const failedLookupLocations: string[] = []; let referencedSourceFile: string; + const extensions = compilerOptions.allowNonTsExtensions ? supportedJsExtensions : supportedExtensions; while (true) { searchName = normalizePath(combinePaths(searchPath, moduleName)); - referencedSourceFile = forEach(supportedExtensions, extension => { + referencedSourceFile = forEach(extensions, extension => { if (extension === ".tsx" && !compilerOptions.jsx) { // resolve .tsx files only if jsx support is enabled // 'logical not' handles both undefined and None cases @@ -688,45 +689,60 @@ namespace ts { return; } + const isJavaScriptFile = isSourceFileJavaScript(file); + let imports: LiteralExpression[]; for (const node of file.statements) { - collect(node, /* allowRelativeModuleNames */ true); + collect(node, /* allowRelativeModuleNames */ true, /* collectOnlyRequireCalls */ false); } file.imports = imports || emptyArray; - function collect(node: Node, allowRelativeModuleNames: boolean): void { - switch (node.kind) { - case SyntaxKind.ImportDeclaration: - case SyntaxKind.ImportEqualsDeclaration: - case SyntaxKind.ExportDeclaration: - let moduleNameExpr = getExternalModuleName(node); - if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) { - break; - } - if (!(moduleNameExpr).text) { - break; - } + return; - if (allowRelativeModuleNames || !isExternalModuleNameRelative((moduleNameExpr).text)) { - (imports || (imports = [])).push(moduleNameExpr); - } - break; - case SyntaxKind.ModuleDeclaration: - if ((node).name.kind === SyntaxKind.StringLiteral && (node.flags & NodeFlags.Ambient || isDeclarationFile(file))) { - // TypeScript 1.0 spec (April 2014): 12.1.6 - // An AmbientExternalModuleDeclaration declares an external module. - // This type of declaration is permitted only in the global module. - // The StringLiteral must specify a top - level external module name. - // Relative external module names are not permitted - forEachChild((node).body, node => { + function collect(node: Node, allowRelativeModuleNames: boolean, collectOnlyRequireCalls: boolean): void { + if (!collectOnlyRequireCalls) { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportDeclaration: + let moduleNameExpr = getExternalModuleName(node); + if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) { + break; + } + if (!(moduleNameExpr).text) { + break; + } + + if (allowRelativeModuleNames || !isExternalModuleNameRelative((moduleNameExpr).text)) { + (imports || (imports = [])).push(moduleNameExpr); + } + break; + case SyntaxKind.ModuleDeclaration: + if ((node).name.kind === SyntaxKind.StringLiteral && (node.flags & NodeFlags.Ambient || isDeclarationFile(file))) { // TypeScript 1.0 spec (April 2014): 12.1.6 - // An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules - // only through top - level external module names. Relative external module names are not permitted. - collect(node, /* allowRelativeModuleNames */ false); - }); - } - break; + // An AmbientExternalModuleDeclaration declares an external module. + // This type of declaration is permitted only in the global module. + // The StringLiteral must specify a top - level external module name. + // Relative external module names are not permitted + forEachChild((node).body, node => { + // TypeScript 1.0 spec (April 2014): 12.1.6 + // An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules + // only through top - level external module names. Relative external module names are not permitted. + collect(node, /* allowRelativeModuleNames */ false, collectOnlyRequireCalls); + }); + } + break; + } + } + + if (isJavaScriptFile) { + if (isRequireCall(node)) { + (imports || (imports = [])).push((node).arguments[0]); + } + else { + forEachChild(node, node => collect(node, allowRelativeModuleNames, /* collectOnlyRequireCalls */ true)); + } } } } diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 79158cf4e9d..f560a15dfb9 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -346,9 +346,20 @@ namespace ts { return; } } + if (!cachedConfigFileText) { + const error = createCompilerDiagnostic(Diagnostics.File_0_not_found, configFileName); + reportDiagnostics([error], /* compilerHost */ undefined); + sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); + return; + } const result = parseConfigFileTextToJson(configFileName, cachedConfigFileText); const configObject = result.config; + if (!configObject) { + reportDiagnostics([result.error], /* compilerHost */ undefined); + sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); + return; + } const configParseResult = parseJsonConfigFileContent(configObject, sys, getDirectoryPath(configFileName)); if (configParseResult.errors.length > 0) { reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2489c049b68..eb3322e60b9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -574,7 +574,7 @@ namespace ts { // @kind(SyntaxKind.BindingElement) export interface BindingElement extends Declaration { - propertyName?: Identifier; // Binding property name (in object binding pattern) + propertyName?: PropertyName; // Binding property name (in object binding pattern) dotDotDotToken?: Node; // Present on rest binding element name: Identifier | BindingPattern; // Declared binding element name initializer?: Expression; // Optional initializer @@ -626,7 +626,7 @@ namespace ts { // SyntaxKind.ShorthandPropertyAssignment // SyntaxKind.EnumMember export interface VariableLikeDeclaration extends Declaration { - propertyName?: Identifier; + propertyName?: PropertyName; dotDotDotToken?: Node; name: DeclarationName; questionToken?: Node; @@ -878,7 +878,8 @@ namespace ts { } // @kind(SyntaxKind.BinaryExpression) - export interface BinaryExpression extends Expression { + // Binary expressions can be declarations if they are 'exports.foo = bar' expressions in JS files + export interface BinaryExpression extends Expression, Declaration { left: Expression; operatorToken: Node; right: Expression; @@ -959,7 +960,7 @@ namespace ts { } // @kind(SyntaxKind.PropertyAccessExpression) - export interface PropertyAccessExpression extends MemberExpression { + export interface PropertyAccessExpression extends MemberExpression, Declaration { expression: LeftHandSideExpression; dotToken: Node; name: Identifier; @@ -1531,6 +1532,8 @@ namespace ts { // The first node that causes this file to be an external module /* @internal */ externalModuleIndicator: Node; + // The first node that causes this file to be a CommonJS module + /* @internal */ commonJsModuleIndicator: Node; /* @internal */ identifiers: Map; /* @internal */ nodeCount: number; @@ -2068,6 +2071,7 @@ namespace ts { ContainsAnyFunctionType = 0x00800000, // Type is or contains object literal type ESSymbol = 0x01000000, // Type of symbol primitive introduced in ES6 ThisType = 0x02000000, // This type + ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties /* @internal */ Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 199ca4e636f..1e4ee1bed47 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1,4 +1,3 @@ -/// /// /* @internal */ @@ -362,6 +361,10 @@ namespace ts { return file.externalModuleIndicator !== undefined; } + export function isExternalOrCommonJsModule(file: SourceFile): boolean { + return (file.externalModuleIndicator || file.commonJsModuleIndicator) !== undefined; + } + export function isDeclarationFile(file: SourceFile): boolean { return (file.flags & NodeFlags.DeclarationFile) !== 0; } @@ -1056,6 +1059,57 @@ namespace ts { return node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference; } + export function isSourceFileJavaScript(file: SourceFile): boolean { + return isInJavaScriptFile(file); + } + + export function isInJavaScriptFile(node: Node): boolean { + return node && !!(node.parserContextFlags & ParserContextFlags.JavaScriptFile); + } + + /** + * Returns true if the node is a CallExpression to the identifier 'require' with + * exactly one string literal argument. + * This function does not test if the node is in a JavaScript file or not. + */ + export function isRequireCall(expression: Node): expression is CallExpression { + // of the form 'require("name")' + return expression.kind === SyntaxKind.CallExpression && + (expression).expression.kind === SyntaxKind.Identifier && + ((expression).expression).text === "require" && + (expression).arguments.length === 1 && + (expression).arguments[0].kind === SyntaxKind.StringLiteral; + } + + /** + * Returns true if the node is an assignment to a property on the identifier 'exports'. + * This function does not test if the node is in a JavaScript file or not. + */ + export function isExportsPropertyAssignment(expression: Node): boolean { + // of the form 'exports.name = expr' where 'name' and 'expr' are arbitrary + return isInJavaScriptFile(expression) && + (expression.kind === SyntaxKind.BinaryExpression) && + ((expression).operatorToken.kind === SyntaxKind.EqualsToken) && + ((expression).left.kind === SyntaxKind.PropertyAccessExpression) && + (((expression).left).expression.kind === SyntaxKind.Identifier) && + (((((expression).left).expression)).text === "exports"); + } + + /** + * Returns true if the node is an assignment to the property access expression 'module.exports'. + * This function does not test if the node is in a JavaScript file or not. + */ + export function isModuleExportsAssignment(expression: Node): boolean { + // of the form 'module.exports = expr' where 'expr' is arbitrary + return isInJavaScriptFile(expression) && + (expression.kind === SyntaxKind.BinaryExpression) && + ((expression).operatorToken.kind === SyntaxKind.EqualsToken) && + ((expression).left.kind === SyntaxKind.PropertyAccessExpression) && + (((expression).left).expression.kind === SyntaxKind.Identifier) && + (((((expression).left).expression)).text === "module") && + (((expression).left).name.text === "exports"); + } + export function getExternalModuleName(node: Node): Expression { if (node.kind === SyntaxKind.ImportDeclaration) { return (node).moduleSpecifier; @@ -1435,6 +1489,10 @@ namespace ts { return isFunctionLike(node) && (node.flags & NodeFlags.Async) !== 0 && !isAccessor(node); } + export function isStringOrNumericLiteral(kind: SyntaxKind): boolean { + return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NumericLiteral; + } + /** * A declaration has a dynamic name if both of the following are true: * 1. The declaration has a computed property name @@ -1443,9 +1501,13 @@ namespace ts { * Symbol. */ export function hasDynamicName(declaration: Declaration): boolean { - return declaration.name && - declaration.name.kind === SyntaxKind.ComputedPropertyName && - !isWellKnownSymbolSyntactically((declaration.name).expression); + return declaration.name && isDynamicName(declaration.name); + } + + export function isDynamicName(name: DeclarationName): boolean { + return name.kind === SyntaxKind.ComputedPropertyName && + !isStringOrNumericLiteral((name).expression.kind) && + !isWellKnownSymbolSyntactically((name).expression); } /** @@ -2210,12 +2272,12 @@ namespace ts { return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & NodeFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined; } - export function isJavaScript(fileName: string) { - return fileExtensionIs(fileName, ".js"); + export function hasJavaScriptFileExtension(fileName: string) { + return fileExtensionIs(fileName, ".js") || fileExtensionIs(fileName, ".jsx"); } - export function isTsx(fileName: string) { - return fileExtensionIs(fileName, ".tsx"); + export function allowsJsxExpressions(fileName: string) { + return fileExtensionIs(fileName, ".tsx") || fileExtensionIs(fileName, ".jsx"); } /** diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index bf8b9493829..1c8593a9e12 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -223,10 +223,22 @@ namespace FourSlash { // Add input file which has matched file name with the given reference-file path. // This is necessary when resolveReference flag is specified - private addMatchedInputFile(referenceFilePath: string) { - const inputFile = this.inputFiles[referenceFilePath]; - if (inputFile && !Harness.isLibraryFile(referenceFilePath)) { - this.languageServiceAdapterHost.addScript(referenceFilePath, inputFile); + private addMatchedInputFile(referenceFilePath: string, extensions: string[]) { + const inputFiles = this.inputFiles; + const languageServiceAdapterHost = this.languageServiceAdapterHost; + if (!extensions) { + tryAdd(referenceFilePath); + } + else { + tryAdd(referenceFilePath) || ts.forEach(extensions, ext => tryAdd(referenceFilePath + ext)); + } + + function tryAdd(path: string) { + const inputFile = inputFiles[path]; + if (inputFile && !Harness.isLibraryFile(path)) { + languageServiceAdapterHost.addScript(path, inputFile); + return true; + } } } @@ -280,15 +292,15 @@ namespace FourSlash { ts.forEach(referencedFiles, referenceFile => { // Fourslash insert tests/cases/fourslash into inputFile.unitName so we will properly append the same base directory to refFile path const referenceFilePath = this.basePath + "/" + referenceFile.fileName; - this.addMatchedInputFile(referenceFilePath); + this.addMatchedInputFile(referenceFilePath, /* extensions */ undefined); }); // Add import files into language-service host ts.forEach(importedFiles, importedFile => { // Fourslash insert tests/cases/fourslash into inputFile.unitName and import statement doesn't require ".ts" // so convert them before making appropriate comparison - const importedFilePath = this.basePath + "/" + importedFile.fileName + ".ts"; - this.addMatchedInputFile(importedFilePath); + const importedFilePath = this.basePath + "/" + importedFile.fileName; + this.addMatchedInputFile(importedFilePath, compilationOptions.allowNonTsExtensions ? ts.supportedJsExtensions : ts.supportedExtensions); }); // Check if no-default-lib flag is false and if so add default library @@ -2257,15 +2269,15 @@ namespace FourSlash { const details = this.getCompletionEntryDetails(item.name); if (documentation !== undefined) { - assert.equal(ts.displayPartsToString(details.documentation), documentation, assertionMessage("completion item documentation")); + assert.equal(ts.displayPartsToString(details.documentation), documentation, assertionMessage("completion item documentation for " + name)); } if (text !== undefined) { - assert.equal(ts.displayPartsToString(details.displayParts), text, assertionMessage("completion item detail text")); + assert.equal(ts.displayPartsToString(details.displayParts), text, assertionMessage("completion item detail text for " + name)); } } if (kind !== undefined) { - assert.equal(item.kind, kind, assertionMessage("completion item kind")); + assert.equal(item.kind, kind, assertionMessage("completion item kind for " + name)); } return; diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 50dbef5a410..faf0ad28eb5 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -197,7 +197,7 @@ namespace Harness.LanguageService { getHost() { return this.host; } getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); } getClassifier(): ts.Classifier { return ts.createClassifier(); } - getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents); } + getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavaScriptFileExtension(fileName)); } } /// Shim adapter diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 6543dc67af0..333cea2745d 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -371,6 +371,10 @@ namespace ts.server { openRefCount = 0; constructor(public projectService: ProjectService, public projectOptions?: ProjectOptions) { + if (projectOptions && projectOptions.files) { + // If files are listed explicitly, allow all extensions + projectOptions.compilerOptions.allowNonTsExtensions = true; + } this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions); } @@ -461,6 +465,7 @@ namespace ts.server { setProjectOptions(projectOptions: ProjectOptions) { this.projectOptions = projectOptions; if (projectOptions.compilerOptions) { + projectOptions.compilerOptions.allowNonTsExtensions = true; this.compilerService.setCompilerOptions(projectOptions.compilerOptions); } } @@ -1316,7 +1321,9 @@ namespace ts.server { this.setCompilerOptions(opt); } else { - this.setCompilerOptions(ts.getDefaultCompilerOptions()); + const defaultOpts = ts.getDefaultCompilerOptions(); + defaultOpts.allowNonTsExtensions = true; + this.setCompilerOptions(defaultOpts); } this.languageService = ts.createLanguageService(this.host, this.documentRegistry); this.classifier = ts.createClassifier(); diff --git a/src/services/services.ts b/src/services/services.ts index 529a70b1453..9fb2eef2152 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -801,6 +801,7 @@ namespace ts { public isDefaultLib: boolean; public hasNoDefaultLib: boolean; public externalModuleIndicator: Node; // The first node that causes this file to be an external module + public commonJsModuleIndicator: Node; // The first node that causes this file to be a CommonJS module public nodeCount: number; public identifierCount: number; public symbolCount: number; @@ -2124,7 +2125,7 @@ namespace ts { }; } - export function preProcessFile(sourceText: string, readImportFiles = true): PreProcessedFileInfo { + export function preProcessFile(sourceText: string, readImportFiles = true, detectJavaScriptImports = false): PreProcessedFileInfo { let referencedFiles: FileReference[] = []; let importedFiles: FileReference[] = []; let ambientExternalModules: string[]; @@ -2162,9 +2163,225 @@ namespace ts { }); } - function processImport(): void { + /** + * Returns true if at least one token was consumed from the stream + */ + function tryConsumeDeclare(): boolean { + let token = scanner.getToken(); + if (token === SyntaxKind.DeclareKeyword) { + // declare module "mod" + token = scanner.scan(); + if (token === SyntaxKind.ModuleKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + recordAmbientExternalModule(); + } + } + return true; + } + + return false; + } + + /** + * Returns true if at least one token was consumed from the stream + */ + function tryConsumeImport(): boolean { + let token = scanner.getToken(); + if (token === SyntaxKind.ImportKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import "mod"; + recordModuleName(); + return true; + } + else { + if (token === SyntaxKind.Identifier || isKeyword(token)) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import d from "mod"; + recordModuleName(); + return true; + } + } + else if (token === SyntaxKind.EqualsToken) { + if (tryConsumeRequireCall(/* skipCurrentToken */ true)) { + return true; + } + } + else if (token === SyntaxKind.CommaToken) { + // consume comma and keep going + token = scanner.scan(); + } + else { + // unknown syntax + return true; + } + } + + if (token === SyntaxKind.OpenBraceToken) { + token = scanner.scan(); + // consume "{ a as B, c, d as D}" clauses + // make sure that it stops on EOF + while (token !== SyntaxKind.CloseBraceToken && token !== SyntaxKind.EndOfFileToken) { + token = scanner.scan(); + } + + if (token === SyntaxKind.CloseBraceToken) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import {a as A} from "mod"; + // import d, {a, b as B} from "mod" + recordModuleName(); + } + } + } + } + else if (token === SyntaxKind.AsteriskToken) { + token = scanner.scan(); + if (token === SyntaxKind.AsKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.Identifier || isKeyword(token)) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // import * as NS from "mod" + // import d, * as NS from "mod" + recordModuleName(); + } + } + } + } + } + } + + return true; + } + + return false; + } + + function tryConsumeExport(): boolean { + let token = scanner.getToken(); + if (token === SyntaxKind.ExportKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.OpenBraceToken) { + token = scanner.scan(); + // consume "{ a as B, c, d as D}" clauses + // make sure it stops on EOF + while (token !== SyntaxKind.CloseBraceToken && token !== SyntaxKind.EndOfFileToken) { + token = scanner.scan(); + } + + if (token === SyntaxKind.CloseBraceToken) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // export {a as A} from "mod"; + // export {a, b as B} from "mod" + recordModuleName(); + } + } + } + } + else if (token === SyntaxKind.AsteriskToken) { + token = scanner.scan(); + if (token === SyntaxKind.FromKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // export * from "mod" + recordModuleName(); + } + } + } + else if (token === SyntaxKind.ImportKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.Identifier || isKeyword(token)) { + token = scanner.scan(); + if (token === SyntaxKind.EqualsToken) { + if (tryConsumeRequireCall(/* skipCurrentToken */ true)) { + return true; + } + } + } + } + + return true; + } + + return false; + } + + function tryConsumeRequireCall(skipCurrentToken: boolean): boolean { + let token = skipCurrentToken ? scanner.scan() : scanner.getToken(); + if (token === SyntaxKind.RequireKeyword) { + token = scanner.scan(); + if (token === SyntaxKind.OpenParenToken) { + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // require("mod"); + recordModuleName(); + } + } + return true; + } + return false; + } + + function tryConsumeDefine(): boolean { + let token = scanner.getToken(); + if (token === SyntaxKind.Identifier && scanner.getTokenValue() === "define") { + token = scanner.scan(); + if (token !== SyntaxKind.OpenParenToken) { + return true; + } + + token = scanner.scan(); + if (token === SyntaxKind.StringLiteral) { + // looks like define ("modname", ... - skip string literal and comma + token = scanner.scan(); + if (token === SyntaxKind.CommaToken) { + token = scanner.scan(); + } + else { + // unexpected token + return true; + } + } + + // should be start of dependency list + if (token !== SyntaxKind.OpenBracketToken) { + return true; + } + + // skip open bracket + token = scanner.scan(); + let i = 0; + // scan until ']' or EOF + while (token !== SyntaxKind.CloseBracketToken && token !== SyntaxKind.EndOfFileToken) { + // record string literals as module names + if (token === SyntaxKind.StringLiteral) { + recordModuleName(); + i++; + } + + token = scanner.scan(); + } + return true; + + } + return false; + } + + function processImports(): void { scanner.setText(sourceText); - let token = scanner.scan(); + scanner.scan(); // Look for: // import "mod"; // import d from "mod" @@ -2176,157 +2393,30 @@ namespace ts { // export * from "mod" // export {a as b} from "mod" // export import i = require("mod") + // (for JavaScript files) require("mod") - while (token !== SyntaxKind.EndOfFileToken) { - if (token === SyntaxKind.DeclareKeyword) { - // declare module "mod" - token = scanner.scan(); - if (token === SyntaxKind.ModuleKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - recordAmbientExternalModule(); - continue; - } - } + while (true) { + if (scanner.getToken() === SyntaxKind.EndOfFileToken) { + break; } - else if (token === SyntaxKind.ImportKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // import "mod"; - recordModuleName(); - continue; - } - else { - if (token === SyntaxKind.Identifier || isKeyword(token)) { - token = scanner.scan(); - if (token === SyntaxKind.FromKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // import d from "mod"; - recordModuleName(); - continue - } - } - else if (token === SyntaxKind.EqualsToken) { - token = scanner.scan(); - if (token === SyntaxKind.RequireKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.OpenParenToken) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // import i = require("mod"); - recordModuleName(); - continue; - } - } - } - } - else if (token === SyntaxKind.CommaToken) { - // consume comma and keep going - token = scanner.scan(); - } - else { - // unknown syntax - continue; - } - } - if (token === SyntaxKind.OpenBraceToken) { - token = scanner.scan(); - // consume "{ a as B, c, d as D}" clauses - while (token !== SyntaxKind.CloseBraceToken) { - token = scanner.scan(); - } - - if (token === SyntaxKind.CloseBraceToken) { - token = scanner.scan(); - if (token === SyntaxKind.FromKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // import {a as A} from "mod"; - // import d, {a, b as B} from "mod" - recordModuleName(); - } - } - } - } - else if (token === SyntaxKind.AsteriskToken) { - token = scanner.scan(); - if (token === SyntaxKind.AsKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.Identifier || isKeyword(token)) { - token = scanner.scan(); - if (token === SyntaxKind.FromKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // import * as NS from "mod" - // import d, * as NS from "mod" - recordModuleName(); - } - } - } - } - } - } + // check if at least one of alternative have moved scanner forward + if (tryConsumeDeclare() || + tryConsumeImport() || + tryConsumeExport() || + (detectJavaScriptImports && (tryConsumeRequireCall(/* skipCurrentToken */ false) || tryConsumeDefine()))) { + continue; } - else if (token === SyntaxKind.ExportKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.OpenBraceToken) { - token = scanner.scan(); - // consume "{ a as B, c, d as D}" clauses - while (token !== SyntaxKind.CloseBraceToken) { - token = scanner.scan(); - } - - if (token === SyntaxKind.CloseBraceToken) { - token = scanner.scan(); - if (token === SyntaxKind.FromKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // export {a as A} from "mod"; - // export {a, b as B} from "mod" - recordModuleName(); - } - } - } - } - else if (token === SyntaxKind.AsteriskToken) { - token = scanner.scan(); - if (token === SyntaxKind.FromKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // export * from "mod" - recordModuleName(); - } - } - } - else if (token === SyntaxKind.ImportKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.Identifier || isKeyword(token)) { - token = scanner.scan(); - if (token === SyntaxKind.EqualsToken) { - token = scanner.scan(); - if (token === SyntaxKind.RequireKeyword) { - token = scanner.scan(); - if (token === SyntaxKind.OpenParenToken) { - token = scanner.scan(); - if (token === SyntaxKind.StringLiteral) { - // export import i = require("mod"); - recordModuleName(); - } - } - } - } - } - } + else { + scanner.scan(); } - token = scanner.scan(); } + scanner.setText(undefined); } if (readImportFiles) { - processImport(); + processImports(); } processTripleSlashDirectives(); return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules }; @@ -2815,7 +2905,7 @@ namespace ts { // For JavaScript files, we don't want to report the normal typescript semantic errors. // Instead, we just report errors for using TypeScript-only constructs from within a // JavaScript file. - if (isJavaScript(fileName)) { + if (isSourceFileJavaScript(targetSourceFile)) { return getJavaScriptSemanticDiagnostics(targetSourceFile); } @@ -3054,7 +3144,7 @@ namespace ts { let typeChecker = program.getTypeChecker(); let syntacticStart = new Date().getTime(); let sourceFile = getValidSourceFile(fileName); - let isJavaScriptFile = isJavaScript(fileName); + let isJavaScriptFile = isSourceFileJavaScript(sourceFile); let isJsDocTagName = false; @@ -3826,7 +3916,10 @@ namespace ts { let existingName: string; if (m.kind === SyntaxKind.BindingElement && (m).propertyName) { - existingName = (m).propertyName.text; + // include only identifiers in completion list + if ((m).propertyName.kind === SyntaxKind.Identifier) { + existingName = ((m).propertyName).text + } } else { // TODO(jfreeman): Account for computed property name @@ -3875,22 +3968,25 @@ namespace ts { let { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot, isJsDocTagName } = completionData; - let entries: CompletionEntry[]; if (isJsDocTagName) { // If the current position is a jsDoc tag name, only tag names should be provided for completion return { isMemberCompletion: false, isNewIdentifierLocation: false, entries: getAllJsDocCompletionEntries() }; } - if (isRightOfDot && isJavaScript(fileName)) { - entries = getCompletionEntriesFromSymbols(symbols); - addRange(entries, getJavaScriptCompletionEntries()); + let sourceFile = getValidSourceFile(fileName); + + let entries: CompletionEntry[] = []; + + if (isRightOfDot && isSourceFileJavaScript(sourceFile)) { + const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries); + addRange(entries, getJavaScriptCompletionEntries(sourceFile, uniqueNames)); } else { if (!symbols || symbols.length === 0) { return undefined; } - entries = getCompletionEntriesFromSymbols(symbols); + getCompletionEntriesFromSymbols(symbols, entries); } // Add keywords if this is not a member completion list @@ -3900,26 +3996,23 @@ namespace ts { return { isMemberCompletion, isNewIdentifierLocation, entries }; - function getJavaScriptCompletionEntries(): CompletionEntry[] { + function getJavaScriptCompletionEntries(sourceFile: SourceFile, uniqueNames: Map): CompletionEntry[] { let entries: CompletionEntry[] = []; - let allNames: Map = {}; let target = program.getCompilerOptions().target; - for (let sourceFile of program.getSourceFiles()) { - let nameTable = getNameTable(sourceFile); - for (let name in nameTable) { - if (!allNames[name]) { - allNames[name] = name; - let displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks:*/ true); - if (displayName) { - let entry = { - name: displayName, - kind: ScriptElementKind.warning, - kindModifiers: "", - sortText: "1" - }; - entries.push(entry); - } + let nameTable = getNameTable(sourceFile); + for (let name in nameTable) { + if (!uniqueNames[name]) { + uniqueNames[name] = name; + let displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks:*/ true); + if (displayName) { + let entry = { + name: displayName, + kind: ScriptElementKind.warning, + kindModifiers: "", + sortText: "1" + }; + entries.push(entry); } } } @@ -3963,26 +4056,24 @@ namespace ts { }; } - function getCompletionEntriesFromSymbols(symbols: Symbol[]): CompletionEntry[] { + function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[]): Map { let start = new Date().getTime(); - let entries: CompletionEntry[] = []; - + let uniqueNames: Map = {}; if (symbols) { - let nameToSymbol: Map = {}; for (let symbol of symbols) { let entry = createCompletionEntry(symbol, location); if (entry) { let id = escapeIdentifier(entry.name); - if (!lookUp(nameToSymbol, id)) { + if (!lookUp(uniqueNames, id)) { entries.push(entry); - nameToSymbol[id] = symbol; + uniqueNames[id] = id; } } } } log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start)); - return entries; + return uniqueNames; } } diff --git a/src/services/shims.ts b/src/services/shims.ts index fca72e49d36..6b656ea2738 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -956,7 +956,8 @@ namespace ts { return this.forwardJSONCall( "getPreProcessedFileInfo('" + fileName + "')", () => { - var result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength())); + // for now treat files as JavaScript + var result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()), /* readImportFiles */ true, /* detectJavaScriptImports */ true); var convertResult = { referencedFiles: [], importedFiles: [], diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index df321647e5c..02e36e185a5 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -204,7 +204,7 @@ namespace ts.SignatureHelp { if (!candidates.length) { // We didn't have any sig help items produced by the TS compiler. If this is a JS // file, then see if we can figure out anything better. - if (isJavaScript(sourceFile.fileName)) { + if (isSourceFileJavaScript(sourceFile)) { return createJavaScriptSignatureHelpItems(argumentInfo); } diff --git a/tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt b/tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt new file mode 100644 index 00000000000..dc536e544b2 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring1.errors.txt @@ -0,0 +1,52 @@ +tests/cases/compiler/computedPropertiesInDestructuring1.ts(20,8): error TS2349: Cannot invoke an expression whose type lacks a call signature. +tests/cases/compiler/computedPropertiesInDestructuring1.ts(21,12): error TS2339: Property 'toExponential' does not exist on type 'string'. +tests/cases/compiler/computedPropertiesInDestructuring1.ts(33,4): error TS2349: Cannot invoke an expression whose type lacks a call signature. +tests/cases/compiler/computedPropertiesInDestructuring1.ts(34,5): error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. + + +==== tests/cases/compiler/computedPropertiesInDestructuring1.ts (4 errors) ==== + // destructuring in variable declarations + let foo = "bar"; + let {[foo]: bar} = {bar: "bar"}; + + let {["bar"]: bar2} = {bar: "bar"}; + + let foo2 = () => "bar"; + let {[foo2()]: bar3} = {bar: "bar"}; + + let [{[foo]: bar4}] = [{bar: "bar"}]; + let [{[foo2()]: bar5}] = [{bar: "bar"}]; + + function f1({["bar"]: x}: { bar: number }) {} + function f2({[foo]: x}: { bar: number }) {} + function f3({[foo2()]: x}: { bar: number }) {} + function f4([{[foo]: x}]: [{ bar: number }]) {} + function f5([{[foo2()]: x}]: [{ bar: number }]) {} + + // report errors on type errors in computed properties used in destructuring + let [{[foo()]: bar6}] = [{bar: "bar"}]; + ~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. + let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; + ~~~~~~~~~~~~~ +!!! error TS2339: Property 'toExponential' does not exist on type 'string'. + + // destructuring assignment + ({[foo]: bar} = {bar: "bar"}); + + ({["bar"]: bar2} = {bar: "bar"}); + + ({[foo2()]: bar3} = {bar: "bar"}); + + [{[foo]: bar4}] = [{bar: "bar"}]; + [{[foo2()]: bar5}] = [{bar: "bar"}]; + + [{[foo()]: bar4}] = [{bar: "bar"}]; + ~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. + [{[(1 + {})]: bar4}] = [{bar: "bar"}]; + ~~~~~~ +!!! error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. + + + \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertiesInDestructuring1.js b/tests/baselines/reference/computedPropertiesInDestructuring1.js new file mode 100644 index 00000000000..0bc4286ed7b --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring1.js @@ -0,0 +1,75 @@ +//// [computedPropertiesInDestructuring1.ts] +// destructuring in variable declarations +let foo = "bar"; +let {[foo]: bar} = {bar: "bar"}; + +let {["bar"]: bar2} = {bar: "bar"}; + +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {bar: "bar"}; + +let [{[foo]: bar4}] = [{bar: "bar"}]; +let [{[foo2()]: bar5}] = [{bar: "bar"}]; + +function f1({["bar"]: x}: { bar: number }) {} +function f2({[foo]: x}: { bar: number }) {} +function f3({[foo2()]: x}: { bar: number }) {} +function f4([{[foo]: x}]: [{ bar: number }]) {} +function f5([{[foo2()]: x}]: [{ bar: number }]) {} + +// report errors on type errors in computed properties used in destructuring +let [{[foo()]: bar6}] = [{bar: "bar"}]; +let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; + +// destructuring assignment +({[foo]: bar} = {bar: "bar"}); + +({["bar"]: bar2} = {bar: "bar"}); + +({[foo2()]: bar3} = {bar: "bar"}); + +[{[foo]: bar4}] = [{bar: "bar"}]; +[{[foo2()]: bar5}] = [{bar: "bar"}]; + +[{[foo()]: bar4}] = [{bar: "bar"}]; +[{[(1 + {})]: bar4}] = [{bar: "bar"}]; + + + + +//// [computedPropertiesInDestructuring1.js] +// destructuring in variable declarations +var foo = "bar"; +var _a = foo, bar = { bar: "bar" }[_a]; +var _b = "bar", bar2 = { bar: "bar" }[_b]; +var foo2 = function () { return "bar"; }; +var _c = foo2(), bar3 = { bar: "bar" }[_c]; +var _d = foo, bar4 = [{ bar: "bar" }][0][_d]; +var _e = foo2(), bar5 = [{ bar: "bar" }][0][_e]; +function f1(_a) { + var _b = "bar", x = _a[_b]; +} +function f2(_a) { + var _b = foo, x = _a[_b]; +} +function f3(_a) { + var _b = foo2(), x = _a[_b]; +} +function f4(_a) { + var _b = foo, x = _a[0][_b]; +} +function f5(_a) { + var _b = foo2(), x = _a[0][_b]; +} +// report errors on type errors in computed properties used in destructuring +var _f = foo(), bar6 = [{ bar: "bar" }][0][_f]; +var _g = foo.toExponential(), bar7 = [{ bar: "bar" }][0][_g]; +// destructuring assignment +(_h = { bar: "bar" }, _j = foo, bar = _h[_j], _h); +(_k = { bar: "bar" }, _l = "bar", bar2 = _k[_l], _k); +(_m = { bar: "bar" }, _o = foo2(), bar3 = _m[_o], _m); +_p = foo, bar4 = [{ bar: "bar" }][0][_p]; +_q = foo2(), bar5 = [{ bar: "bar" }][0][_q]; +_r = foo(), bar4 = [{ bar: "bar" }][0][_r]; +_s = (1 + {}), bar4 = [{ bar: "bar" }][0][_s]; +var _h, _j, _k, _l, _m, _o, _p, _q, _r, _s; diff --git a/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.errors.txt b/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.errors.txt new file mode 100644 index 00000000000..96ab892d1b9 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.errors.txt @@ -0,0 +1,51 @@ +tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(21,8): error TS2349: Cannot invoke an expression whose type lacks a call signature. +tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(22,12): error TS2339: Property 'toExponential' does not exist on type 'string'. +tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(34,4): error TS2349: Cannot invoke an expression whose type lacks a call signature. +tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts(35,5): error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. + + +==== tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts (4 errors) ==== + // destructuring in variable declarations + let foo = "bar"; + let {[foo]: bar} = {bar: "bar"}; + + let {["bar"]: bar2} = {bar: "bar"}; + let {[11]: bar2_1} = {11: "bar"}; + + let foo2 = () => "bar"; + let {[foo2()]: bar3} = {bar: "bar"}; + + let [{[foo]: bar4}] = [{bar: "bar"}]; + let [{[foo2()]: bar5}] = [{bar: "bar"}]; + + function f1({["bar"]: x}: { bar: number }) {} + function f2({[foo]: x}: { bar: number }) {} + function f3({[foo2()]: x}: { bar: number }) {} + function f4([{[foo]: x}]: [{ bar: number }]) {} + function f5([{[foo2()]: x}]: [{ bar: number }]) {} + + // report errors on type errors in computed properties used in destructuring + let [{[foo()]: bar6}] = [{bar: "bar"}]; + ~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. + let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; + ~~~~~~~~~~~~~ +!!! error TS2339: Property 'toExponential' does not exist on type 'string'. + + // destructuring assignment + ({[foo]: bar} = {bar: "bar"}); + + ({["bar"]: bar2} = {bar: "bar"}); + + ({[foo2()]: bar3} = {bar: "bar"}); + + [{[foo]: bar4}] = [{bar: "bar"}]; + [{[foo2()]: bar5}] = [{bar: "bar"}]; + + [{[foo()]: bar4}] = [{bar: "bar"}]; + ~~~~~ +!!! error TS2349: Cannot invoke an expression whose type lacks a call signature. + [{[(1 + {})]: bar4}] = [{bar: "bar"}]; + ~~~~~~ +!!! error TS2365: Operator '+' cannot be applied to types 'number' and '{}'. + \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.js b/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.js new file mode 100644 index 00000000000..e6e19f93b80 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring1_ES6.js @@ -0,0 +1,64 @@ +//// [computedPropertiesInDestructuring1_ES6.ts] +// destructuring in variable declarations +let foo = "bar"; +let {[foo]: bar} = {bar: "bar"}; + +let {["bar"]: bar2} = {bar: "bar"}; +let {[11]: bar2_1} = {11: "bar"}; + +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {bar: "bar"}; + +let [{[foo]: bar4}] = [{bar: "bar"}]; +let [{[foo2()]: bar5}] = [{bar: "bar"}]; + +function f1({["bar"]: x}: { bar: number }) {} +function f2({[foo]: x}: { bar: number }) {} +function f3({[foo2()]: x}: { bar: number }) {} +function f4([{[foo]: x}]: [{ bar: number }]) {} +function f5([{[foo2()]: x}]: [{ bar: number }]) {} + +// report errors on type errors in computed properties used in destructuring +let [{[foo()]: bar6}] = [{bar: "bar"}]; +let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; + +// destructuring assignment +({[foo]: bar} = {bar: "bar"}); + +({["bar"]: bar2} = {bar: "bar"}); + +({[foo2()]: bar3} = {bar: "bar"}); + +[{[foo]: bar4}] = [{bar: "bar"}]; +[{[foo2()]: bar5}] = [{bar: "bar"}]; + +[{[foo()]: bar4}] = [{bar: "bar"}]; +[{[(1 + {})]: bar4}] = [{bar: "bar"}]; + + +//// [computedPropertiesInDestructuring1_ES6.js] +// destructuring in variable declarations +let foo = "bar"; +let { [foo]: bar } = { bar: "bar" }; +let { ["bar"]: bar2 } = { bar: "bar" }; +let { [11]: bar2_1 } = { 11: "bar" }; +let foo2 = () => "bar"; +let { [foo2()]: bar3 } = { bar: "bar" }; +let [{ [foo]: bar4 }] = [{ bar: "bar" }]; +let [{ [foo2()]: bar5 }] = [{ bar: "bar" }]; +function f1({ ["bar"]: x }) { } +function f2({ [foo]: x }) { } +function f3({ [foo2()]: x }) { } +function f4([{ [foo]: x }]) { } +function f5([{ [foo2()]: x }]) { } +// report errors on type errors in computed properties used in destructuring +let [{ [foo()]: bar6 }] = [{ bar: "bar" }]; +let [{ [foo.toExponential()]: bar7 }] = [{ bar: "bar" }]; +// destructuring assignment +({ [foo]: bar } = { bar: "bar" }); +({ ["bar"]: bar2 } = { bar: "bar" }); +({ [foo2()]: bar3 } = { bar: "bar" }); +[{ [foo]: bar4 }] = [{ bar: "bar" }]; +[{ [foo2()]: bar5 }] = [{ bar: "bar" }]; +[{ [foo()]: bar4 }] = [{ bar: "bar" }]; +[{ [(1 + {})]: bar4 }] = [{ bar: "bar" }]; diff --git a/tests/baselines/reference/computedPropertiesInDestructuring2.js b/tests/baselines/reference/computedPropertiesInDestructuring2.js new file mode 100644 index 00000000000..8579881b775 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring2.js @@ -0,0 +1,7 @@ +//// [computedPropertiesInDestructuring2.ts] +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {}; + +//// [computedPropertiesInDestructuring2.js] +var foo2 = function () { return "bar"; }; +var _a = foo2(), bar3 = {}[_a]; diff --git a/tests/baselines/reference/computedPropertiesInDestructuring2.symbols b/tests/baselines/reference/computedPropertiesInDestructuring2.symbols new file mode 100644 index 00000000000..4ae6d5323e1 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring2.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/computedPropertiesInDestructuring2.ts === +let foo2 = () => "bar"; +>foo2 : Symbol(foo2, Decl(computedPropertiesInDestructuring2.ts, 0, 3)) + +let {[foo2()]: bar3} = {}; +>foo2 : Symbol(foo2, Decl(computedPropertiesInDestructuring2.ts, 0, 3)) +>bar3 : Symbol(bar3, Decl(computedPropertiesInDestructuring2.ts, 1, 5)) + diff --git a/tests/baselines/reference/computedPropertiesInDestructuring2.types b/tests/baselines/reference/computedPropertiesInDestructuring2.types new file mode 100644 index 00000000000..0fa20662270 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring2.types @@ -0,0 +1,12 @@ +=== tests/cases/compiler/computedPropertiesInDestructuring2.ts === +let foo2 = () => "bar"; +>foo2 : () => string +>() => "bar" : () => string +>"bar" : string + +let {[foo2()]: bar3} = {}; +>foo2() : string +>foo2 : () => string +>bar3 : any +>{} : {} + diff --git a/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.js b/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.js new file mode 100644 index 00000000000..e0bd16287ee --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.js @@ -0,0 +1,8 @@ +//// [computedPropertiesInDestructuring2_ES6.ts] + +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {}; + +//// [computedPropertiesInDestructuring2_ES6.js] +let foo2 = () => "bar"; +let { [foo2()]: bar3 } = {}; diff --git a/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.symbols b/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.symbols new file mode 100644 index 00000000000..cd7cfda9844 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/computedPropertiesInDestructuring2_ES6.ts === + +let foo2 = () => "bar"; +>foo2 : Symbol(foo2, Decl(computedPropertiesInDestructuring2_ES6.ts, 1, 3)) + +let {[foo2()]: bar3} = {}; +>foo2 : Symbol(foo2, Decl(computedPropertiesInDestructuring2_ES6.ts, 1, 3)) +>bar3 : Symbol(bar3, Decl(computedPropertiesInDestructuring2_ES6.ts, 2, 5)) + diff --git a/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.types b/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.types new file mode 100644 index 00000000000..f0d8b1033c8 --- /dev/null +++ b/tests/baselines/reference/computedPropertiesInDestructuring2_ES6.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/computedPropertiesInDestructuring2_ES6.ts === + +let foo2 = () => "bar"; +>foo2 : () => string +>() => "bar" : () => string +>"bar" : string + +let {[foo2()]: bar3} = {}; +>foo2() : string +>foo2 : () => string +>bar3 : any +>{} : {} + diff --git a/tests/baselines/reference/computedPropertyNames10_ES5.types b/tests/baselines/reference/computedPropertyNames10_ES5.types index 87648c1ed80..9dea9cfca93 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES5.types +++ b/tests/baselines/reference/computedPropertyNames10_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : {} ->{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : {} +>v : { [0](): void; [""](): void; } +>{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [0](): void; [""](): void; } [s]() { }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames10_ES6.types b/tests/baselines/reference/computedPropertyNames10_ES6.types index 996dfc99fe9..d2faa138980 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES6.types +++ b/tests/baselines/reference/computedPropertyNames10_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : {} ->{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : {} +>v : { [0](): void; [""](): void; } +>{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [0](): void; [""](): void; } [s]() { }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames11_ES5.js b/tests/baselines/reference/computedPropertyNames11_ES5.js index 64c0b0bd67e..0917f824770 100644 --- a/tests/baselines/reference/computedPropertyNames11_ES5.js +++ b/tests/baselines/reference/computedPropertyNames11_ES5.js @@ -46,16 +46,8 @@ var v = (_a = {}, enumerable: true, configurable: true }), - Object.defineProperty(_a, "", { - set: function (v) { }, - enumerable: true, - configurable: true - }), - Object.defineProperty(_a, 0, { - get: function () { return 0; }, - enumerable: true, - configurable: true - }), + , + , Object.defineProperty(_a, a, { set: function (v) { }, enumerable: true, diff --git a/tests/baselines/reference/computedPropertyNames11_ES5.types b/tests/baselines/reference/computedPropertyNames11_ES5.types index c3c59c2eb9c..e0787fc3ee7 100644 --- a/tests/baselines/reference/computedPropertyNames11_ES5.types +++ b/tests/baselines/reference/computedPropertyNames11_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : {} ->{ get [s]() { return 0; }, set [n](v) { }, get [s + s]() { return 0; }, set [s + n](v) { }, get [+s]() { return 0; }, set [""](v) { }, get [0]() { return 0; }, set [a](v) { }, get [true]() { return 0; }, set [`hello bye`](v) { }, get [`hello ${a} bye`]() { return 0; }} : {} +>v : { [0]: number; [""]: any; } +>{ get [s]() { return 0; }, set [n](v) { }, get [s + s]() { return 0; }, set [s + n](v) { }, get [+s]() { return 0; }, set [""](v) { }, get [0]() { return 0; }, set [a](v) { }, get [true]() { return 0; }, set [`hello bye`](v) { }, get [`hello ${a} bye`]() { return 0; }} : { [0]: number; [""]: any; } get [s]() { return 0; }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames11_ES6.types b/tests/baselines/reference/computedPropertyNames11_ES6.types index ef11511baae..8ad31a7c2a1 100644 --- a/tests/baselines/reference/computedPropertyNames11_ES6.types +++ b/tests/baselines/reference/computedPropertyNames11_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : {} ->{ get [s]() { return 0; }, set [n](v) { }, get [s + s]() { return 0; }, set [s + n](v) { }, get [+s]() { return 0; }, set [""](v) { }, get [0]() { return 0; }, set [a](v) { }, get [true]() { return 0; }, set [`hello bye`](v) { }, get [`hello ${a} bye`]() { return 0; }} : {} +>v : { [0]: number; [""]: any; } +>{ get [s]() { return 0; }, set [n](v) { }, get [s + s]() { return 0; }, set [s + n](v) { }, get [+s]() { return 0; }, set [""](v) { }, get [0]() { return 0; }, set [a](v) { }, get [true]() { return 0; }, set [`hello bye`](v) { }, get [`hello ${a} bye`]() { return 0; }} : { [0]: number; [""]: any; } get [s]() { return 0; }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt b/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt index 9d07f34f3c4..71f81c27245 100644 --- a/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNames12_ES5.errors.txt @@ -3,15 +3,13 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(6, tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(7,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(8,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(9,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. -tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(10,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. -tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(11,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(12,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(13,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(14,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(15,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts (11 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts (9 errors) ==== var s: string; var n: number; var a: any; @@ -32,11 +30,7 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES5.ts(15 ~~~~ !!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. static [""]: number; - ~~~~ -!!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. [0]: number; - ~~~ -!!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. [a]: number; ~~~ !!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. diff --git a/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt b/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt index f0a2267f8b3..8d8cce7e140 100644 --- a/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNames12_ES6.errors.txt @@ -3,15 +3,13 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(6, tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(7,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(8,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(9,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. -tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(10,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. -tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(11,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(12,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(13,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(14,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(15,12): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts (11 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts (9 errors) ==== var s: string; var n: number; var a: any; @@ -32,11 +30,7 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames12_ES6.ts(15 ~~~~ !!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. static [""]: number; - ~~~~ -!!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. [0]: number; - ~~~ -!!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. [a]: number; ~~~ !!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. diff --git a/tests/baselines/reference/computedPropertyNames16_ES5.js b/tests/baselines/reference/computedPropertyNames16_ES5.js index 2c7316e1398..f4d90579d63 100644 --- a/tests/baselines/reference/computedPropertyNames16_ES5.js +++ b/tests/baselines/reference/computedPropertyNames16_ES5.js @@ -48,16 +48,6 @@ var C = (function () { enumerable: true, configurable: true }); - Object.defineProperty(C, "", { - set: function (v) { }, - enumerable: true, - configurable: true - }); - Object.defineProperty(C.prototype, 0, { - get: function () { return 0; }, - enumerable: true, - configurable: true - }); Object.defineProperty(C.prototype, a, { set: function (v) { }, enumerable: true, diff --git a/tests/baselines/reference/computedPropertyNames36_ES5.js b/tests/baselines/reference/computedPropertyNames36_ES5.js index 5519a6d284c..4bb10ea7543 100644 --- a/tests/baselines/reference/computedPropertyNames36_ES5.js +++ b/tests/baselines/reference/computedPropertyNames36_ES5.js @@ -27,10 +27,6 @@ var C = (function () { Object.defineProperty(C.prototype, "get1", { // Computed properties get: function () { return new Foo; }, - enumerable: true, - configurable: true - }); - Object.defineProperty(C.prototype, "set1", { set: function (p) { }, enumerable: true, configurable: true diff --git a/tests/baselines/reference/computedPropertyNames37_ES5.js b/tests/baselines/reference/computedPropertyNames37_ES5.js index 54a7243f3fa..c2a346608fe 100644 --- a/tests/baselines/reference/computedPropertyNames37_ES5.js +++ b/tests/baselines/reference/computedPropertyNames37_ES5.js @@ -27,10 +27,6 @@ var C = (function () { Object.defineProperty(C.prototype, "get1", { // Computed properties get: function () { return new Foo; }, - enumerable: true, - configurable: true - }); - Object.defineProperty(C.prototype, "set1", { set: function (p) { }, enumerable: true, configurable: true diff --git a/tests/baselines/reference/computedPropertyNames40_ES5.errors.txt b/tests/baselines/reference/computedPropertyNames40_ES5.errors.txt index e8ceef0d581..482978064d1 100644 --- a/tests/baselines/reference/computedPropertyNames40_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNames40_ES5.errors.txt @@ -1,7 +1,9 @@ +tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES5.ts(8,5): error TS2393: Duplicate function implementation. tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES5.ts(8,5): error TS2411: Property '[""]' of type '() => Foo' is not assignable to string index type '() => Foo2'. +tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES5.ts(9,5): error TS2393: Duplicate function implementation. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES5.ts (1 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES5.ts (3 errors) ==== class Foo { x } class Foo2 { x; y } @@ -10,7 +12,11 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES5.ts(8, // Computed properties [""]() { return new Foo } + ~~~~ +!!! error TS2393: Duplicate function implementation. ~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2411: Property '[""]' of type '() => Foo' is not assignable to string index type '() => Foo2'. [""]() { return new Foo2 } + ~~~~ +!!! error TS2393: Duplicate function implementation. } \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNames40_ES6.errors.txt b/tests/baselines/reference/computedPropertyNames40_ES6.errors.txt index 1a032a87b2b..669d0d04e66 100644 --- a/tests/baselines/reference/computedPropertyNames40_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNames40_ES6.errors.txt @@ -1,7 +1,9 @@ +tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES6.ts(8,5): error TS2393: Duplicate function implementation. tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES6.ts(8,5): error TS2411: Property '[""]' of type '() => Foo' is not assignable to string index type '() => Foo2'. +tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES6.ts(9,5): error TS2393: Duplicate function implementation. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES6.ts (1 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES6.ts (3 errors) ==== class Foo { x } class Foo2 { x; y } @@ -10,7 +12,11 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames40_ES6.ts(8, // Computed properties [""]() { return new Foo } + ~~~~ +!!! error TS2393: Duplicate function implementation. ~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2411: Property '[""]' of type '() => Foo' is not assignable to string index type '() => Foo2'. [""]() { return new Foo2 } + ~~~~ +!!! error TS2393: Duplicate function implementation. } \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNames42_ES5.errors.txt b/tests/baselines/reference/computedPropertyNames42_ES5.errors.txt index 94153c47aa5..bdb978220a0 100644 --- a/tests/baselines/reference/computedPropertyNames42_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNames42_ES5.errors.txt @@ -1,8 +1,7 @@ -tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES5.ts(8,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES5.ts(8,5): error TS2411: Property '[""]' of type 'Foo' is not assignable to string index type 'Foo2'. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES5.ts (2 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES5.ts (1 errors) ==== class Foo { x } class Foo2 { x; y } @@ -11,8 +10,6 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES5.ts(8, // Computed properties [""]: Foo; - ~~~~ -!!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. ~~~~~~~~~~ !!! error TS2411: Property '[""]' of type 'Foo' is not assignable to string index type 'Foo2'. } \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNames42_ES6.errors.txt b/tests/baselines/reference/computedPropertyNames42_ES6.errors.txt index 1f4e27d6e81..9feb6ba3d32 100644 --- a/tests/baselines/reference/computedPropertyNames42_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNames42_ES6.errors.txt @@ -1,8 +1,7 @@ -tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES6.ts(8,5): error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES6.ts(8,5): error TS2411: Property '[""]' of type 'Foo' is not assignable to string index type 'Foo2'. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES6.ts (2 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES6.ts (1 errors) ==== class Foo { x } class Foo2 { x; y } @@ -11,8 +10,6 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames42_ES6.ts(8, // Computed properties [""]: Foo; - ~~~~ -!!! error TS1166: A computed property name in a class property declaration must directly refer to a built-in symbol. ~~~~~~~~~~ !!! error TS2411: Property '[""]' of type 'Foo' is not assignable to string index type 'Foo2'. } \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNames43_ES5.js b/tests/baselines/reference/computedPropertyNames43_ES5.js index c3b7f6a71d0..57026c3c706 100644 --- a/tests/baselines/reference/computedPropertyNames43_ES5.js +++ b/tests/baselines/reference/computedPropertyNames43_ES5.js @@ -41,10 +41,6 @@ var D = (function (_super) { Object.defineProperty(D.prototype, "get1", { // Computed properties get: function () { return new Foo; }, - enumerable: true, - configurable: true - }); - Object.defineProperty(D.prototype, "set1", { set: function (p) { }, enumerable: true, configurable: true diff --git a/tests/baselines/reference/computedPropertyNames45_ES5.errors.txt b/tests/baselines/reference/computedPropertyNames45_ES5.errors.txt index 83855c5f0b7..8baae68f337 100644 --- a/tests/baselines/reference/computedPropertyNames45_ES5.errors.txt +++ b/tests/baselines/reference/computedPropertyNames45_ES5.errors.txt @@ -1,12 +1,15 @@ +tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES5.ts(5,5): error TS2411: Property '["get1"]' of type 'Foo' is not assignable to string index type 'Foo2'. tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES5.ts(11,5): error TS2411: Property '["set1"]' of type 'Foo' is not assignable to string index type 'Foo2'. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES5.ts (1 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES5.ts (2 errors) ==== class Foo { x } class Foo2 { x; y } class C { get ["get1"]() { return new Foo } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property '["get1"]' of type 'Foo' is not assignable to string index type 'Foo2'. } class D extends C { diff --git a/tests/baselines/reference/computedPropertyNames45_ES6.errors.txt b/tests/baselines/reference/computedPropertyNames45_ES6.errors.txt index 963e01ed86b..e329785f4cf 100644 --- a/tests/baselines/reference/computedPropertyNames45_ES6.errors.txt +++ b/tests/baselines/reference/computedPropertyNames45_ES6.errors.txt @@ -1,12 +1,15 @@ +tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES6.ts(5,5): error TS2411: Property '["get1"]' of type 'Foo' is not assignable to string index type 'Foo2'. tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES6.ts(11,5): error TS2411: Property '["set1"]' of type 'Foo' is not assignable to string index type 'Foo2'. -==== tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES6.ts (1 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyNames45_ES6.ts (2 errors) ==== class Foo { x } class Foo2 { x; y } class C { get ["get1"]() { return new Foo } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2411: Property '["get1"]' of type 'Foo' is not assignable to string index type 'Foo2'. } class D extends C { diff --git a/tests/baselines/reference/computedPropertyNames4_ES5.types b/tests/baselines/reference/computedPropertyNames4_ES5.types index 51baca26586..6984d2e69b8 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES5.types +++ b/tests/baselines/reference/computedPropertyNames4_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : {} ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : {} +>v : { [0]: number; [""]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [0]: number; [""]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyNames4_ES6.types b/tests/baselines/reference/computedPropertyNames4_ES6.types index 05267049517..1fece561f5a 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES6.types +++ b/tests/baselines/reference/computedPropertyNames4_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : {} ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : {} +>v : { [0]: number; [""]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [0]: number; [""]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.types b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.types index 9470aee8eb6..147b2966509 100644 --- a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.types +++ b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNamesSourceMap2_ES5.ts === var v = { ->v : {} ->{ ["hello"]() { debugger; }} : {} +>v : { ["hello"](): void; } +>{ ["hello"]() { debugger; }} : { ["hello"](): void; } ["hello"]() { >"hello" : string diff --git a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES6.types b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES6.types index c4f02155a95..00334680362 100644 --- a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES6.types +++ b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES6.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNamesSourceMap2_ES6.ts === var v = { ->v : {} ->{ ["hello"]() { debugger; }} : {} +>v : { ["hello"](): void; } +>{ ["hello"]() { debugger; }} : { ["hello"](): void; } ["hello"]() { >"hello" : string diff --git a/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.js b/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.js index ece24d691da..e7f88b92775 100644 --- a/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.js +++ b/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.js @@ -10,16 +10,16 @@ class C { static get ["computedname"]() { return ""; } - get ["computedname"]() { + get ["computedname1"]() { return ""; } - get ["computedname"]() { + get ["computedname2"]() { return ""; } - set ["computedname"](x: any) { + set ["computedname3"](x: any) { } - set ["computedname"](y: string) { + set ["computedname4"](y: string) { } set foo(a: string) { } @@ -38,15 +38,15 @@ class C { static get ["computedname"]() { return ""; } - get ["computedname"]() { + get ["computedname1"]() { return ""; } - get ["computedname"]() { + get ["computedname2"]() { return ""; } - set ["computedname"](x) { + set ["computedname3"](x) { } - set ["computedname"](y) { + set ["computedname4"](y) { } set foo(a) { } static set bar(b) { } diff --git a/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.symbols b/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.symbols index 2d249348f9b..b2b1a000dc9 100644 --- a/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.symbols +++ b/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.symbols @@ -21,18 +21,18 @@ class C { static get ["computedname"]() { return ""; } - get ["computedname"]() { + get ["computedname1"]() { return ""; } - get ["computedname"]() { + get ["computedname2"]() { return ""; } - set ["computedname"](x: any) { ->x : Symbol(x, Decl(emitClassDeclarationWithGetterSetterInES6.ts, 18, 25)) + set ["computedname3"](x: any) { +>x : Symbol(x, Decl(emitClassDeclarationWithGetterSetterInES6.ts, 18, 26)) } - set ["computedname"](y: string) { ->y : Symbol(y, Decl(emitClassDeclarationWithGetterSetterInES6.ts, 20, 25)) + set ["computedname4"](y: string) { +>y : Symbol(y, Decl(emitClassDeclarationWithGetterSetterInES6.ts, 20, 26)) } set foo(a: string) { } diff --git a/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.types b/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.types index 292fb961b10..e4f7d6c00b4 100644 --- a/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.types +++ b/tests/baselines/reference/emitClassDeclarationWithGetterSetterInES6.types @@ -25,25 +25,25 @@ class C { return ""; >"" : string } - get ["computedname"]() { ->"computedname" : string + get ["computedname1"]() { +>"computedname1" : string return ""; >"" : string } - get ["computedname"]() { ->"computedname" : string + get ["computedname2"]() { +>"computedname2" : string return ""; >"" : string } - set ["computedname"](x: any) { ->"computedname" : string + set ["computedname3"](x: any) { +>"computedname3" : string >x : any } - set ["computedname"](y: string) { ->"computedname" : string + set ["computedname4"](y: string) { +>"computedname4" : string >y : string } diff --git a/tests/baselines/reference/emitClassDeclarationWithMethodInES6.js b/tests/baselines/reference/emitClassDeclarationWithMethodInES6.js index fc0a510461b..8a79d45b678 100644 --- a/tests/baselines/reference/emitClassDeclarationWithMethodInES6.js +++ b/tests/baselines/reference/emitClassDeclarationWithMethodInES6.js @@ -2,18 +2,18 @@ class D { _bar: string; foo() { } - ["computedName"]() { } - ["computedName"](a: string) { } - ["computedName"](a: string): number { return 1; } + ["computedName1"]() { } + ["computedName2"](a: string) { } + ["computedName3"](a: string): number { return 1; } bar(): string { return this._bar; } baz(a: any, x: string): string { return "HELLO"; } - static ["computedname"]() { } - static ["computedname"](a: string) { } - static ["computedname"](a: string): boolean { return true; } + static ["computedname4"]() { } + static ["computedname5"](a: string) { } + static ["computedname6"](a: string): boolean { return true; } static staticMethod() { var x = 1 + 2; return x @@ -25,18 +25,18 @@ class D { //// [emitClassDeclarationWithMethodInES6.js] class D { foo() { } - ["computedName"]() { } - ["computedName"](a) { } - ["computedName"](a) { return 1; } + ["computedName1"]() { } + ["computedName2"](a) { } + ["computedName3"](a) { return 1; } bar() { return this._bar; } baz(a, x) { return "HELLO"; } - static ["computedname"]() { } - static ["computedname"](a) { } - static ["computedname"](a) { return true; } + static ["computedname4"]() { } + static ["computedname5"](a) { } + static ["computedname6"](a) { return true; } static staticMethod() { var x = 1 + 2; return x; diff --git a/tests/baselines/reference/emitClassDeclarationWithMethodInES6.symbols b/tests/baselines/reference/emitClassDeclarationWithMethodInES6.symbols index b7a4dbbf341..970076f6b78 100644 --- a/tests/baselines/reference/emitClassDeclarationWithMethodInES6.symbols +++ b/tests/baselines/reference/emitClassDeclarationWithMethodInES6.symbols @@ -8,15 +8,15 @@ class D { foo() { } >foo : Symbol(foo, Decl(emitClassDeclarationWithMethodInES6.ts, 1, 17)) - ["computedName"]() { } - ["computedName"](a: string) { } ->a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 4, 21)) + ["computedName1"]() { } + ["computedName2"](a: string) { } +>a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 4, 22)) - ["computedName"](a: string): number { return 1; } ->a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 5, 21)) + ["computedName3"](a: string): number { return 1; } +>a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 5, 22)) bar(): string { ->bar : Symbol(bar, Decl(emitClassDeclarationWithMethodInES6.ts, 5, 53)) +>bar : Symbol(bar, Decl(emitClassDeclarationWithMethodInES6.ts, 5, 54)) return this._bar; >this._bar : Symbol(_bar, Decl(emitClassDeclarationWithMethodInES6.ts, 0, 9)) @@ -30,15 +30,15 @@ class D { return "HELLO"; } - static ["computedname"]() { } - static ["computedname"](a: string) { } ->a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 13, 28)) + static ["computedname4"]() { } + static ["computedname5"](a: string) { } +>a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 13, 29)) - static ["computedname"](a: string): boolean { return true; } ->a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 14, 28)) + static ["computedname6"](a: string): boolean { return true; } +>a : Symbol(a, Decl(emitClassDeclarationWithMethodInES6.ts, 14, 29)) static staticMethod() { ->staticMethod : Symbol(D.staticMethod, Decl(emitClassDeclarationWithMethodInES6.ts, 14, 64)) +>staticMethod : Symbol(D.staticMethod, Decl(emitClassDeclarationWithMethodInES6.ts, 14, 65)) var x = 1 + 2; >x : Symbol(x, Decl(emitClassDeclarationWithMethodInES6.ts, 16, 11)) diff --git a/tests/baselines/reference/emitClassDeclarationWithMethodInES6.types b/tests/baselines/reference/emitClassDeclarationWithMethodInES6.types index 10ae930c244..02a90729486 100644 --- a/tests/baselines/reference/emitClassDeclarationWithMethodInES6.types +++ b/tests/baselines/reference/emitClassDeclarationWithMethodInES6.types @@ -8,15 +8,15 @@ class D { foo() { } >foo : () => void - ["computedName"]() { } ->"computedName" : string + ["computedName1"]() { } +>"computedName1" : string - ["computedName"](a: string) { } ->"computedName" : string + ["computedName2"](a: string) { } +>"computedName2" : string >a : string - ["computedName"](a: string): number { return 1; } ->"computedName" : string + ["computedName3"](a: string): number { return 1; } +>"computedName3" : string >a : string >1 : number @@ -36,15 +36,15 @@ class D { return "HELLO"; >"HELLO" : string } - static ["computedname"]() { } ->"computedname" : string + static ["computedname4"]() { } +>"computedname4" : string - static ["computedname"](a: string) { } ->"computedname" : string + static ["computedname5"](a: string) { } +>"computedname5" : string >a : string - static ["computedname"](a: string): boolean { return true; } ->"computedname" : string + static ["computedname6"](a: string): boolean { return true; } +>"computedname6" : string >a : string >true : boolean diff --git a/tests/baselines/reference/genericClassExpressionInFunction.js b/tests/baselines/reference/genericClassExpressionInFunction.js new file mode 100644 index 00000000000..bb45587eea1 --- /dev/null +++ b/tests/baselines/reference/genericClassExpressionInFunction.js @@ -0,0 +1,104 @@ +//// [genericClassExpressionInFunction.ts] +class A { + genericVar: T +} +function B1() { + // class expression can use T + return class extends A { } +} +class B2 { + anon = class extends A { } +} +function B3() { + return class Inner extends A { } +} +// extends can call B +class K extends B1() { + namae: string; +} +class C extends (new B2().anon) { + name: string; +} +let b3Number = B3(); +class S extends b3Number { + nom: string; +} +var c = new C(); +var k = new K(); +var s = new S(); +c.genericVar = 12; +k.genericVar = 12; +s.genericVar = 12; + + +//// [genericClassExpressionInFunction.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var A = (function () { + function A() { + } + return A; +})(); +function B1() { + // class expression can use T + return (function (_super) { + __extends(class_1, _super); + function class_1() { + _super.apply(this, arguments); + } + return class_1; + })(A); +} +var B2 = (function () { + function B2() { + this.anon = (function (_super) { + __extends(class_2, _super); + function class_2() { + _super.apply(this, arguments); + } + return class_2; + })(A); + } + return B2; +})(); +function B3() { + return (function (_super) { + __extends(Inner, _super); + function Inner() { + _super.apply(this, arguments); + } + return Inner; + })(A); +} +// extends can call B +var K = (function (_super) { + __extends(K, _super); + function K() { + _super.apply(this, arguments); + } + return K; +})(B1()); +var C = (function (_super) { + __extends(C, _super); + function C() { + _super.apply(this, arguments); + } + return C; +})((new B2().anon)); +var b3Number = B3(); +var S = (function (_super) { + __extends(S, _super); + function S() { + _super.apply(this, arguments); + } + return S; +})(b3Number); +var c = new C(); +var k = new K(); +var s = new S(); +c.genericVar = 12; +k.genericVar = 12; +s.genericVar = 12; diff --git a/tests/baselines/reference/genericClassExpressionInFunction.symbols b/tests/baselines/reference/genericClassExpressionInFunction.symbols new file mode 100644 index 00000000000..b5a6b8c6c70 --- /dev/null +++ b/tests/baselines/reference/genericClassExpressionInFunction.symbols @@ -0,0 +1,92 @@ +=== tests/cases/conformance/classes/classExpressions/genericClassExpressionInFunction.ts === +class A { +>A : Symbol(A, Decl(genericClassExpressionInFunction.ts, 0, 0)) +>T : Symbol(T, Decl(genericClassExpressionInFunction.ts, 0, 8)) + + genericVar: T +>genericVar : Symbol(genericVar, Decl(genericClassExpressionInFunction.ts, 0, 12)) +>T : Symbol(T, Decl(genericClassExpressionInFunction.ts, 0, 8)) +} +function B1() { +>B1 : Symbol(B1, Decl(genericClassExpressionInFunction.ts, 2, 1)) +>U : Symbol(U, Decl(genericClassExpressionInFunction.ts, 3, 12)) + + // class expression can use T + return class extends A { } +>A : Symbol(A, Decl(genericClassExpressionInFunction.ts, 0, 0)) +>U : Symbol(U, Decl(genericClassExpressionInFunction.ts, 3, 12)) +} +class B2 { +>B2 : Symbol(B2, Decl(genericClassExpressionInFunction.ts, 6, 1)) +>V : Symbol(V, Decl(genericClassExpressionInFunction.ts, 7, 9)) + + anon = class extends A { } +>anon : Symbol(anon, Decl(genericClassExpressionInFunction.ts, 7, 13)) +>A : Symbol(A, Decl(genericClassExpressionInFunction.ts, 0, 0)) +>V : Symbol(V, Decl(genericClassExpressionInFunction.ts, 7, 9)) +} +function B3() { +>B3 : Symbol(B3, Decl(genericClassExpressionInFunction.ts, 9, 1)) +>W : Symbol(W, Decl(genericClassExpressionInFunction.ts, 10, 12)) + + return class Inner extends A { } +>Inner : Symbol(Inner, Decl(genericClassExpressionInFunction.ts, 11, 10)) +>TInner : Symbol(TInner, Decl(genericClassExpressionInFunction.ts, 11, 23)) +>A : Symbol(A, Decl(genericClassExpressionInFunction.ts, 0, 0)) +>W : Symbol(W, Decl(genericClassExpressionInFunction.ts, 10, 12)) +} +// extends can call B +class K extends B1() { +>K : Symbol(K, Decl(genericClassExpressionInFunction.ts, 12, 1)) +>B1 : Symbol(B1, Decl(genericClassExpressionInFunction.ts, 2, 1)) + + namae: string; +>namae : Symbol(namae, Decl(genericClassExpressionInFunction.ts, 14, 30)) +} +class C extends (new B2().anon) { +>C : Symbol(C, Decl(genericClassExpressionInFunction.ts, 16, 1)) +>new B2().anon : Symbol(B2.anon, Decl(genericClassExpressionInFunction.ts, 7, 13)) +>B2 : Symbol(B2, Decl(genericClassExpressionInFunction.ts, 6, 1)) +>anon : Symbol(B2.anon, Decl(genericClassExpressionInFunction.ts, 7, 13)) + + name: string; +>name : Symbol(name, Decl(genericClassExpressionInFunction.ts, 17, 41)) +} +let b3Number = B3(); +>b3Number : Symbol(b3Number, Decl(genericClassExpressionInFunction.ts, 20, 3)) +>B3 : Symbol(B3, Decl(genericClassExpressionInFunction.ts, 9, 1)) + +class S extends b3Number { +>S : Symbol(S, Decl(genericClassExpressionInFunction.ts, 20, 28)) +>b3Number : Symbol(b3Number, Decl(genericClassExpressionInFunction.ts, 20, 3)) + + nom: string; +>nom : Symbol(nom, Decl(genericClassExpressionInFunction.ts, 21, 34)) +} +var c = new C(); +>c : Symbol(c, Decl(genericClassExpressionInFunction.ts, 24, 3)) +>C : Symbol(C, Decl(genericClassExpressionInFunction.ts, 16, 1)) + +var k = new K(); +>k : Symbol(k, Decl(genericClassExpressionInFunction.ts, 25, 3)) +>K : Symbol(K, Decl(genericClassExpressionInFunction.ts, 12, 1)) + +var s = new S(); +>s : Symbol(s, Decl(genericClassExpressionInFunction.ts, 26, 3)) +>S : Symbol(S, Decl(genericClassExpressionInFunction.ts, 20, 28)) + +c.genericVar = 12; +>c.genericVar : Symbol(A.genericVar, Decl(genericClassExpressionInFunction.ts, 0, 12)) +>c : Symbol(c, Decl(genericClassExpressionInFunction.ts, 24, 3)) +>genericVar : Symbol(A.genericVar, Decl(genericClassExpressionInFunction.ts, 0, 12)) + +k.genericVar = 12; +>k.genericVar : Symbol(A.genericVar, Decl(genericClassExpressionInFunction.ts, 0, 12)) +>k : Symbol(k, Decl(genericClassExpressionInFunction.ts, 25, 3)) +>genericVar : Symbol(A.genericVar, Decl(genericClassExpressionInFunction.ts, 0, 12)) + +s.genericVar = 12; +>s.genericVar : Symbol(A.genericVar, Decl(genericClassExpressionInFunction.ts, 0, 12)) +>s : Symbol(s, Decl(genericClassExpressionInFunction.ts, 26, 3)) +>genericVar : Symbol(A.genericVar, Decl(genericClassExpressionInFunction.ts, 0, 12)) + diff --git a/tests/baselines/reference/genericClassExpressionInFunction.types b/tests/baselines/reference/genericClassExpressionInFunction.types new file mode 100644 index 00000000000..943391fdd59 --- /dev/null +++ b/tests/baselines/reference/genericClassExpressionInFunction.types @@ -0,0 +1,108 @@ +=== tests/cases/conformance/classes/classExpressions/genericClassExpressionInFunction.ts === +class A { +>A : A +>T : T + + genericVar: T +>genericVar : T +>T : T +} +function B1() { +>B1 : () => typeof (Anonymous class) +>U : U + + // class expression can use T + return class extends A { } +>class extends A { } : typeof (Anonymous class) +>A : A +>U : U +} +class B2 { +>B2 : B2 +>V : V + + anon = class extends A { } +>anon : typeof (Anonymous class) +>class extends A { } : typeof (Anonymous class) +>A : A +>V : V +} +function B3() { +>B3 : () => typeof Inner +>W : W + + return class Inner extends A { } +>class Inner extends A { } : typeof Inner +>Inner : typeof Inner +>TInner : TInner +>A : A +>W : W +} +// extends can call B +class K extends B1() { +>K : K +>B1() : B1.(Anonymous class) +>B1 : () => typeof (Anonymous class) + + namae: string; +>namae : string +} +class C extends (new B2().anon) { +>C : C +>(new B2().anon) : B2.(Anonymous class) +>new B2().anon : typeof (Anonymous class) +>new B2() : B2 +>B2 : typeof B2 +>anon : typeof (Anonymous class) + + name: string; +>name : string +} +let b3Number = B3(); +>b3Number : typeof Inner +>B3() : typeof Inner +>B3 : () => typeof Inner + +class S extends b3Number { +>S : S +>b3Number : B3.Inner + + nom: string; +>nom : string +} +var c = new C(); +>c : C +>new C() : C +>C : typeof C + +var k = new K(); +>k : K +>new K() : K +>K : typeof K + +var s = new S(); +>s : S +>new S() : S +>S : typeof S + +c.genericVar = 12; +>c.genericVar = 12 : number +>c.genericVar : number +>c : C +>genericVar : number +>12 : number + +k.genericVar = 12; +>k.genericVar = 12 : number +>k.genericVar : number +>k : K +>genericVar : number +>12 : number + +s.genericVar = 12; +>s.genericVar = 12 : number +>s.genericVar : number +>s : S +>genericVar : number +>12 : number + diff --git a/tests/baselines/reference/literalsInComputedProperties1.errors.txt b/tests/baselines/reference/literalsInComputedProperties1.errors.txt new file mode 100644 index 00000000000..e9972229f79 --- /dev/null +++ b/tests/baselines/reference/literalsInComputedProperties1.errors.txt @@ -0,0 +1,66 @@ +tests/cases/compiler/literalsInComputedProperties1.ts(40,5): error TS2452: An enum member cannot have a numeric name. +tests/cases/compiler/literalsInComputedProperties1.ts(41,5): error TS2452: An enum member cannot have a numeric name. +tests/cases/compiler/literalsInComputedProperties1.ts(42,5): error TS2452: An enum member cannot have a numeric name. +tests/cases/compiler/literalsInComputedProperties1.ts(43,5): error TS2452: An enum member cannot have a numeric name. + + +==== tests/cases/compiler/literalsInComputedProperties1.ts (4 errors) ==== + + let x = { + 1:1, + [2]:1, + "3":1, + ["4"]:1 + } + x[1].toExponential(); + x[2].toExponential(); + x[3].toExponential(); + x[4].toExponential(); + + interface A { + 1:number; + [2]:number; + "3":number; + ["4"]:number; + } + + let y:A; + y[1].toExponential(); + y[2].toExponential(); + y[3].toExponential(); + y[4].toExponential(); + + class C { + 1:number; + [2]:number; + "3":number; + ["4"]:number; + } + + let z:C; + z[1].toExponential(); + z[2].toExponential(); + z[3].toExponential(); + z[4].toExponential(); + + enum X { + 1 = 1, + ~ +!!! error TS2452: An enum member cannot have a numeric name. + [2] = 2, + ~~~ +!!! error TS2452: An enum member cannot have a numeric name. + "3" = 3, + ~~~ +!!! error TS2452: An enum member cannot have a numeric name. + ["4"] = 4, + ~~~~~ +!!! error TS2452: An enum member cannot have a numeric name. + "foo" = 5, + ["bar"] = 6 + } + + let a = X["foo"]; + let a0 = X["bar"]; + + // TODO: make sure that enum still disallow template literals as member names \ No newline at end of file diff --git a/tests/baselines/reference/literalsInComputedProperties1.js b/tests/baselines/reference/literalsInComputedProperties1.js new file mode 100644 index 00000000000..ef11dbff6ea --- /dev/null +++ b/tests/baselines/reference/literalsInComputedProperties1.js @@ -0,0 +1,94 @@ +//// [literalsInComputedProperties1.ts] + +let x = { + 1:1, + [2]:1, + "3":1, + ["4"]:1 +} +x[1].toExponential(); +x[2].toExponential(); +x[3].toExponential(); +x[4].toExponential(); + +interface A { + 1:number; + [2]:number; + "3":number; + ["4"]:number; +} + +let y:A; +y[1].toExponential(); +y[2].toExponential(); +y[3].toExponential(); +y[4].toExponential(); + +class C { + 1:number; + [2]:number; + "3":number; + ["4"]:number; +} + +let z:C; +z[1].toExponential(); +z[2].toExponential(); +z[3].toExponential(); +z[4].toExponential(); + +enum X { + 1 = 1, + [2] = 2, + "3" = 3, + ["4"] = 4, + "foo" = 5, + ["bar"] = 6 +} + +let a = X["foo"]; +let a0 = X["bar"]; + +// TODO: make sure that enum still disallow template literals as member names + +//// [literalsInComputedProperties1.js] +var x = (_a = { + 1: 1 + }, + _a[2] = 1, + _a["3"] = 1, + _a["4"] = 1, + _a +); +x[1].toExponential(); +x[2].toExponential(); +x[3].toExponential(); +x[4].toExponential(); +var y; +y[1].toExponential(); +y[2].toExponential(); +y[3].toExponential(); +y[4].toExponential(); +var C = (function () { + function C() { + } + return C; +})(); +var z; +z[1].toExponential(); +z[2].toExponential(); +z[3].toExponential(); +z[4].toExponential(); +var X; +(function (X) { + X[X["1"] = 1] = "1"; + X[X[2] = 2] = 2; + X[X["3"] = 3] = "3"; + X[X["4"] = 4] = "4"; + X[X["foo"] = 5] = "foo"; + X[X["bar"] = 6] = "bar"; +})(X || (X = {})); +var a = X["foo"]; +var a0 = X["bar"]; +var _a; +// TODO: make sure that enum still disallow template literals as member names diff --git a/tests/cases/compiler/computedPropertiesInDestructuring1.ts b/tests/cases/compiler/computedPropertiesInDestructuring1.ts new file mode 100644 index 00000000000..d3ccaa57ad1 --- /dev/null +++ b/tests/cases/compiler/computedPropertiesInDestructuring1.ts @@ -0,0 +1,36 @@ +// destructuring in variable declarations +let foo = "bar"; +let {[foo]: bar} = {bar: "bar"}; + +let {["bar"]: bar2} = {bar: "bar"}; + +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {bar: "bar"}; + +let [{[foo]: bar4}] = [{bar: "bar"}]; +let [{[foo2()]: bar5}] = [{bar: "bar"}]; + +function f1({["bar"]: x}: { bar: number }) {} +function f2({[foo]: x}: { bar: number }) {} +function f3({[foo2()]: x}: { bar: number }) {} +function f4([{[foo]: x}]: [{ bar: number }]) {} +function f5([{[foo2()]: x}]: [{ bar: number }]) {} + +// report errors on type errors in computed properties used in destructuring +let [{[foo()]: bar6}] = [{bar: "bar"}]; +let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; + +// destructuring assignment +({[foo]: bar} = {bar: "bar"}); + +({["bar"]: bar2} = {bar: "bar"}); + +({[foo2()]: bar3} = {bar: "bar"}); + +[{[foo]: bar4}] = [{bar: "bar"}]; +[{[foo2()]: bar5}] = [{bar: "bar"}]; + +[{[foo()]: bar4}] = [{bar: "bar"}]; +[{[(1 + {})]: bar4}] = [{bar: "bar"}]; + + diff --git a/tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts b/tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts new file mode 100644 index 00000000000..4951e474fdb --- /dev/null +++ b/tests/cases/compiler/computedPropertiesInDestructuring1_ES6.ts @@ -0,0 +1,36 @@ +// @target: ES6 +// destructuring in variable declarations +let foo = "bar"; +let {[foo]: bar} = {bar: "bar"}; + +let {["bar"]: bar2} = {bar: "bar"}; +let {[11]: bar2_1} = {11: "bar"}; + +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {bar: "bar"}; + +let [{[foo]: bar4}] = [{bar: "bar"}]; +let [{[foo2()]: bar5}] = [{bar: "bar"}]; + +function f1({["bar"]: x}: { bar: number }) {} +function f2({[foo]: x}: { bar: number }) {} +function f3({[foo2()]: x}: { bar: number }) {} +function f4([{[foo]: x}]: [{ bar: number }]) {} +function f5([{[foo2()]: x}]: [{ bar: number }]) {} + +// report errors on type errors in computed properties used in destructuring +let [{[foo()]: bar6}] = [{bar: "bar"}]; +let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}]; + +// destructuring assignment +({[foo]: bar} = {bar: "bar"}); + +({["bar"]: bar2} = {bar: "bar"}); + +({[foo2()]: bar3} = {bar: "bar"}); + +[{[foo]: bar4}] = [{bar: "bar"}]; +[{[foo2()]: bar5}] = [{bar: "bar"}]; + +[{[foo()]: bar4}] = [{bar: "bar"}]; +[{[(1 + {})]: bar4}] = [{bar: "bar"}]; diff --git a/tests/cases/compiler/computedPropertiesInDestructuring2.ts b/tests/cases/compiler/computedPropertiesInDestructuring2.ts new file mode 100644 index 00000000000..806c528c17c --- /dev/null +++ b/tests/cases/compiler/computedPropertiesInDestructuring2.ts @@ -0,0 +1,2 @@ +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {}; \ No newline at end of file diff --git a/tests/cases/compiler/computedPropertiesInDestructuring2_ES6.ts b/tests/cases/compiler/computedPropertiesInDestructuring2_ES6.ts new file mode 100644 index 00000000000..c21f86bed1c --- /dev/null +++ b/tests/cases/compiler/computedPropertiesInDestructuring2_ES6.ts @@ -0,0 +1,4 @@ +// @target: ES6 + +let foo2 = () => "bar"; +let {[foo2()]: bar3} = {}; \ No newline at end of file diff --git a/tests/cases/compiler/literalsInComputedProperties1.ts b/tests/cases/compiler/literalsInComputedProperties1.ts new file mode 100644 index 00000000000..e3fed5b80aa --- /dev/null +++ b/tests/cases/compiler/literalsInComputedProperties1.ts @@ -0,0 +1,52 @@ +// @noImplicitAny: true + +let x = { + 1:1, + [2]:1, + "3":1, + ["4"]:1 +} +x[1].toExponential(); +x[2].toExponential(); +x[3].toExponential(); +x[4].toExponential(); + +interface A { + 1:number; + [2]:number; + "3":number; + ["4"]:number; +} + +let y:A; +y[1].toExponential(); +y[2].toExponential(); +y[3].toExponential(); +y[4].toExponential(); + +class C { + 1:number; + [2]:number; + "3":number; + ["4"]:number; +} + +let z:C; +z[1].toExponential(); +z[2].toExponential(); +z[3].toExponential(); +z[4].toExponential(); + +enum X { + 1 = 1, + [2] = 2, + "3" = 3, + ["4"] = 4, + "foo" = 5, + ["bar"] = 6 +} + +let a = X["foo"]; +let a0 = X["bar"]; + +// TODO: make sure that enum still disallow template literals as member names \ No newline at end of file diff --git a/tests/cases/conformance/classes/classExpressions/genericClassExpressionInFunction.ts b/tests/cases/conformance/classes/classExpressions/genericClassExpressionInFunction.ts new file mode 100644 index 00000000000..14885ca9905 --- /dev/null +++ b/tests/cases/conformance/classes/classExpressions/genericClassExpressionInFunction.ts @@ -0,0 +1,30 @@ +class A { + genericVar: T +} +function B1() { + // class expression can use T + return class extends A { } +} +class B2 { + anon = class extends A { } +} +function B3() { + return class Inner extends A { } +} +// extends can call B +class K extends B1() { + namae: string; +} +class C extends (new B2().anon) { + name: string; +} +let b3Number = B3(); +class S extends b3Number { + nom: string; +} +var c = new C(); +var k = new K(); +var s = new S(); +c.genericVar = 12; +k.genericVar = 12; +s.genericVar = 12; diff --git a/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithGetterSetterInES6.ts b/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithGetterSetterInES6.ts index 70c0b35763e..54c95c95a37 100644 --- a/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithGetterSetterInES6.ts +++ b/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithGetterSetterInES6.ts @@ -10,16 +10,16 @@ class C { static get ["computedname"]() { return ""; } - get ["computedname"]() { + get ["computedname1"]() { return ""; } - get ["computedname"]() { + get ["computedname2"]() { return ""; } - set ["computedname"](x: any) { + set ["computedname3"](x: any) { } - set ["computedname"](y: string) { + set ["computedname4"](y: string) { } set foo(a: string) { } diff --git a/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithMethodInES6.ts b/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithMethodInES6.ts index c5d95bc6cb1..b7399a3511c 100644 --- a/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithMethodInES6.ts +++ b/tests/cases/conformance/es6/classDeclaration/emitClassDeclarationWithMethodInES6.ts @@ -2,18 +2,18 @@ class D { _bar: string; foo() { } - ["computedName"]() { } - ["computedName"](a: string) { } - ["computedName"](a: string): number { return 1; } + ["computedName1"]() { } + ["computedName2"](a: string) { } + ["computedName3"](a: string): number { return 1; } bar(): string { return this._bar; } baz(a: any, x: string): string { return "HELLO"; } - static ["computedname"]() { } - static ["computedname"](a: string) { } - static ["computedname"](a: string): boolean { return true; } + static ["computedname4"]() { } + static ["computedname5"](a: string) { } + static ["computedname6"](a: string): boolean { return true; } static staticMethod() { var x = 1 + 2; return x diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics1.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics1.ts deleted file mode 100644 index e409029276b..00000000000 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics1.ts +++ /dev/null @@ -1,19 +0,0 @@ -/// - -// @allowNonTsExtensions: true -// @Filename: a.js -//// /** -//// * @type {number} -//// * @type {string} -//// */ -//// var v; - -verify.getSyntacticDiagnostics(`[ - { - "message": "\'type\' tag already specified.", - "start": 26, - "length": 4, - "category": "error", - "code": 1223 - } -]`); \ No newline at end of file diff --git a/tests/cases/fourslash/javaScriptModules12.ts b/tests/cases/fourslash/javaScriptModules12.ts new file mode 100644 index 00000000000..c391f150963 --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules12.ts @@ -0,0 +1,57 @@ +/// + +// Invocations of 'require' stop top-level variables from becoming global + +// @allowNonTsExtensions: true + +// @Filename: mod1.js +//// var x = require('fs'); +//// /*1*/ + +// @Filename: mod2.js +//// var y; +//// if(true) { +//// y = require('fs'); +//// } +//// /*2*/ + +// @Filename: glob1.js +//// var a = require; +//// /*3*/ + +// @Filename: glob2.js +//// var b = ''; +//// /*4*/ + +// @Filename: consumer.js +//// /*5*/ + +goTo.marker('1'); +verify.completionListContains('x'); +verify.not.completionListContains('y'); +verify.completionListContains('a'); +verify.completionListContains('b'); + +goTo.marker('2'); +verify.not.completionListContains('x'); +verify.completionListContains('y'); +verify.completionListContains('a'); +verify.completionListContains('b'); + +goTo.marker('3'); +verify.not.completionListContains('x'); +verify.not.completionListContains('y'); +verify.completionListContains('a'); +verify.completionListContains('b'); + +goTo.marker('4'); +verify.not.completionListContains('x'); +verify.not.completionListContains('y'); +verify.completionListContains('a'); +verify.completionListContains('b'); + +goTo.marker('5'); +verify.not.completionListContains('x'); +verify.not.completionListContains('y'); +verify.completionListContains('a'); +verify.completionListContains('b'); diff --git a/tests/cases/fourslash/javaScriptModules13.ts b/tests/cases/fourslash/javaScriptModules13.ts new file mode 100644 index 00000000000..8b22971009c --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules13.ts @@ -0,0 +1,26 @@ +/// + +// Assignments to 'module.exports' create an external module + +// @allowNonTsExtensions: true +// @Filename: myMod.js +//// if (true) { +//// module.exports = { a: 10 }; +//// } +//// var invisible = true; + +// @Filename: isGlobal.js +//// var y = 10; + +// @Filename: consumer.js +//// var x = require('myMod'); +//// /**/; + +goTo.file('consumer.js'); +goTo.marker(); + +verify.completionListContains('y'); +verify.not.completionListContains('invisible'); + +edit.insert('x.'); +verify.completionListContains('a'); diff --git a/tests/cases/fourslash/javaScriptModules14.ts b/tests/cases/fourslash/javaScriptModules14.ts new file mode 100644 index 00000000000..5434f94cf8d --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules14.ts @@ -0,0 +1,28 @@ +/// + +// Assignments to 'exports.p' stop global variables from being visible in other files + +// @allowNonTsExtensions: true +// @Filename: myMod.js +//// if (true) { +//// exports.b = true; +//// } else { +//// exports.n = 3; +//// } +//// function fn() { +//// exports.s = 'foo'; +//// } +//// var invisible = true; + +// @Filename: isGlobal.js +//// var y = 10; + +// @Filename: consumer.js +//// var x = require('myMod'); +//// /**/; + +goTo.file('consumer.js'); +goTo.marker(); + +verify.completionListContains('y'); +verify.not.completionListContains('invisible'); diff --git a/tests/cases/fourslash/javaScriptModules15.ts b/tests/cases/fourslash/javaScriptModules15.ts new file mode 100644 index 00000000000..ff888d99336 --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules15.ts @@ -0,0 +1,27 @@ +/// + +// Assignments to 'exports.p' define a property 'p' even if they're not at top-level + +// @allowNonTsExtensions: true +// @Filename: myMod.js +//// if (true) { +//// exports.b = true; +//// } else { +//// exports.n = 3; +//// } +//// function fn() { +//// exports.s = 'foo'; +//// } + +// @Filename: consumer.js +//// var x = require('myMod'); +//// x/**/; + +goTo.file('consumer.js'); +goTo.marker(); +edit.insert('.'); +verify.completionListContains("n", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +verify.completionListContains("s", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +verify.completionListContains("b", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +edit.insert('n.'); +verify.completionListContains("toFixed", /*displayText:*/ undefined, /*documentation*/ undefined, "method"); diff --git a/tests/cases/fourslash/javaScriptModules16.ts b/tests/cases/fourslash/javaScriptModules16.ts new file mode 100644 index 00000000000..c556f288145 --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules16.ts @@ -0,0 +1,22 @@ +/// + +// Assignments to 'exports.p' define a property 'p' + +// @allowNonTsExtensions: true +// @Filename: myMod.js +//// exports.n = 3; +//// exports.s = 'foo'; +//// exports.b = true; + +// @Filename: consumer.js +//// var x = require('myMod'); +//// x/**/; + +goTo.file('consumer.js'); +goTo.marker(); +edit.insert('.'); +verify.completionListContains("n", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +verify.completionListContains("s", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +verify.completionListContains("b", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +edit.insert('n.'); +verify.completionListContains("toFixed", /*displayText:*/ undefined, /*documentation*/ undefined, "method"); diff --git a/tests/cases/fourslash/javaScriptModules17.ts b/tests/cases/fourslash/javaScriptModules17.ts new file mode 100644 index 00000000000..8514ed0ee18 --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules17.ts @@ -0,0 +1,18 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: myMod.js +//// module.exports = { n: 3, s: 'foo', b: true }; + +// @Filename: consumer.js +//// var x = require('./myMod'); +//// x/**/; + +goTo.file('consumer.js'); +goTo.marker(); +edit.insert('.'); +verify.completionListContains("n", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +verify.completionListContains("s", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +verify.completionListContains("b", /*displayText:*/ undefined, /*documentation*/ undefined, "property"); +edit.insert('n.'); +verify.completionListContains("toFixed", /*displayText:*/ undefined, /*documentation*/ undefined, "method"); diff --git a/tests/cases/fourslash/javaScriptModules18.ts b/tests/cases/fourslash/javaScriptModules18.ts new file mode 100644 index 00000000000..d3117f86b3f --- /dev/null +++ b/tests/cases/fourslash/javaScriptModules18.ts @@ -0,0 +1,14 @@ +/// + +// CommonJS modules should not pollute the global namespace + +// @allowNonTsExtensions: true +// @Filename: myMod.js +//// var x = require('fs'); + +// @Filename: other.js +//// /**/; + +goTo.file('other.js'); + +verify.not.completionListContains('x'); diff --git a/tests/cases/unittests/moduleResolution.ts b/tests/cases/unittests/moduleResolution.ts index a76428a62a1..c53cad5725a 100644 --- a/tests/cases/unittests/moduleResolution.ts +++ b/tests/cases/unittests/moduleResolution.ts @@ -95,8 +95,8 @@ module ts { let resolution = nodeModuleNameResolver(moduleName, containingFile.name, createModuleResolutionHost(containingFile, packageJson, moduleFile)); assert.equal(resolution.resolvedModule.resolvedFileName, moduleFile.name); assert.equal(!!resolution.resolvedModule.isExternalLibraryImport, false); - // expect three failed lookup location - attempt to load module as file with all supported extensions - assert.equal(resolution.failedLookupLocations.length, 3); + // expect five failed lookup location - attempt to load module as file with all supported extensions + assert.equal(resolution.failedLookupLocations.length, 5); } it("module name as directory - load from typings", () => { @@ -117,6 +117,8 @@ module ts { "/a/b/foo.ts", "/a/b/foo.tsx", "/a/b/foo.d.ts", + "/a/b/foo.js", + "/a/b/foo.jsx", "/a/b/foo/index.ts", "/a/b/foo/index.tsx", ]); @@ -143,7 +145,7 @@ module ts { "/a/b/c/node_modules/foo/package.json", "/a/b/c/node_modules/foo/index.ts", "/a/b/c/node_modules/foo/index.tsx", - "/a/b/c/node_modules/foo/index.d.ts" + "/a/b/c/node_modules/foo/index.d.ts", ]) }); diff --git a/tests/cases/unittests/services/preProcessFile.ts b/tests/cases/unittests/services/preProcessFile.ts index a3f8db5528f..d9ddaf0f256 100644 --- a/tests/cases/unittests/services/preProcessFile.ts +++ b/tests/cases/unittests/services/preProcessFile.ts @@ -2,8 +2,8 @@ /// describe('PreProcessFile:', function () { - function test(sourceText: string, readImportFile: boolean, expectedPreProcess: ts.PreProcessedFileInfo): void { - var resultPreProcess = ts.preProcessFile(sourceText, readImportFile); + function test(sourceText: string, readImportFile: boolean, detectJavaScriptImports: boolean, expectedPreProcess: ts.PreProcessedFileInfo): void { + var resultPreProcess = ts.preProcessFile(sourceText, readImportFile, detectJavaScriptImports); var resultIsLibFile = resultPreProcess.isLibFile; var resultImportedFiles = resultPreProcess.importedFiles; @@ -45,7 +45,9 @@ describe('PreProcessFile:', function () { } describe("Test preProcessFiles,", function () { it("Correctly return referenced files from triple slash", function () { - test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", true, + test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [{ fileName: "refFile1.ts", pos: 0, end: 37 }, { fileName: "refFile2.ts", pos: 38, end: 73 }, { fileName: "refFile3.ts", pos: 74, end: 109 }, { fileName: "..\\refFile4d.ts", pos: 110, end: 150 }], @@ -56,7 +58,9 @@ describe('PreProcessFile:', function () { }), it("Do not return reference path because of invalid triple-slash syntax", function () { - test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", true, + test("///" + "\n" + "///" + "\n" + "///" + "\n" + "///", + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [], importedFiles: [], @@ -66,7 +70,9 @@ describe('PreProcessFile:', function () { }), it("Correctly return imported files", function () { - test("import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\"); import i3= require(\"r3.ts\"); import i4=require(\"r4.ts\"); import i5 = require (\"r5.ts\");", true, + test("import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\"); import i3= require(\"r3.ts\"); import i4=require(\"r4.ts\"); import i5 = require (\"r5.ts\");", + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [], importedFiles: [{ fileName: "r1.ts", pos: 20, end: 25 }, { fileName: "r2.ts", pos: 49, end: 54 }, { fileName: "r3.ts", pos: 78, end: 83 }, @@ -77,7 +83,9 @@ describe('PreProcessFile:', function () { }), it("Do not return imported files if readImportFiles argument is false", function () { - test("import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\"); import i3= require(\"r3.ts\"); import i4=require(\"r4.ts\"); import i5 = require (\"r5.ts\");", false, + test("import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\"); import i3= require(\"r3.ts\"); import i4=require(\"r4.ts\"); import i5 = require (\"r5.ts\");", + /* readImports */ false, + /* detectJavaScriptImports */ false, { referencedFiles: [], importedFiles: [], @@ -87,7 +95,9 @@ describe('PreProcessFile:', function () { }), it("Do not return import path because of invalid import syntax", function () { - test("import i1 require(\"r1.ts\"); import = require(\"r2.ts\") import i3= require(\"r3.ts\"); import i5", true, + test("import i1 require(\"r1.ts\"); import = require(\"r2.ts\") import i3= require(\"r3.ts\"); import i5", + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [], importedFiles: [{ fileName: "r3.ts", pos: 73, end: 78 }], @@ -97,7 +107,9 @@ describe('PreProcessFile:', function () { }), it("Correctly return referenced files and import files", function () { - test("///" + "\n" + "///" + "\n" + "import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\");", true, + test("///" + "\n" + "///" + "\n" + "import i1 = require(\"r1.ts\"); import i2 =require(\"r2.ts\");", + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [{ fileName: "refFile1.ts", pos: 0, end: 35 }, { fileName: "refFile2.ts", pos: 36, end: 71 }], importedFiles: [{ fileName: "r1.ts", pos: 92, end: 97 }, { fileName: "r2.ts", pos: 121, end: 126 }], @@ -107,7 +119,9 @@ describe('PreProcessFile:', function () { }), it("Correctly return referenced files and import files even with some invalid syntax", function () { - test("///" + "\n" + "///" + "\n" + "import i1 = require(\"r1.ts\"); import = require(\"r2.ts\"); import i2 = require(\"r3.ts\");", true, + test("///" + "\n" + "///" + "\n" + "import i1 = require(\"r1.ts\"); import = require(\"r2.ts\"); import i2 = require(\"r3.ts\");", + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [{ fileName: "refFile1.ts", pos: 0, end: 35 }], importedFiles: [{ fileName: "r1.ts", pos: 91, end: 96 }, { fileName: "r3.ts", pos: 148, end: 153 }], @@ -124,7 +138,8 @@ describe('PreProcessFile:', function () { "import {a as A} from \"m5\";" + "\n" + "import {a as A, b, c as C} from \"m6\";" + "\n" + "import def , {a, b, c as C} from \"m7\";" + "\n", - true, + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [], importedFiles: [ @@ -146,7 +161,8 @@ describe('PreProcessFile:', function () { "export {a} from \"m2\";" + "\n" + "export {a as A} from \"m3\";" + "\n" + "export {a as A, b, c as C} from \"m4\";" + "\n", - true, + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [], importedFiles: [ @@ -166,7 +182,11 @@ describe('PreProcessFile:', function () { declare module "B" {} function foo() { } - `, false, { + `, + /* readImports */ false, + /* detectJavaScriptImports */ false, + + { referencedFiles: [], importedFiles: [], ambientExternalModules: ["B"], @@ -176,7 +196,8 @@ describe('PreProcessFile:', function () { it("Correctly handles export import declarations", function () { test("export import a = require(\"m1\");", - true, + /* readImports */true, + /* detectJavaScriptImports */ false, { referencedFiles: [], importedFiles: [ @@ -186,7 +207,61 @@ describe('PreProcessFile:', function () { isLibFile: false }) }); - + it("Correctly handles export require calls in JavaScript files", function () { + test(` + export import a = require("m1"); + var x = require('m2'); + foo(require('m3')); + var z = { f: require('m4') } + `, + /* readImports */true, + /* detectJavaScriptImports */ true, + { + referencedFiles: [], + importedFiles: [ + { fileName: "m1", pos: 39, end: 41 }, + { fileName: "m2", pos: 74, end: 76 }, + { fileName: "m3", pos: 105, end: 107 }, + { fileName: "m4", pos: 146, end: 148 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }) + }); + it("Correctly handles dependency lists in define([deplist]) calls in JavaScript files", function () { + test(` + define(["mod1", "mod2"], (m1, m2) => { + }); + `, + /* readImports */true, + /* detectJavaScriptImports */ true, + { + referencedFiles: [], + importedFiles: [ + { fileName: "mod1", pos: 21, end: 25 }, + { fileName: "mod2", pos: 29, end: 33 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }) + }); + it("Correctly handles dependency lists in define(modName, [deplist]) calls in JavaScript files", function () { + test(` + define("mod", ["mod1", "mod2"], (m1, m2) => { + }); + `, + /* readImports */true, + /* detectJavaScriptImports */ true, + { + referencedFiles: [], + importedFiles: [ + { fileName: "mod1", pos: 28, end: 32 }, + { fileName: "mod2", pos: 36, end: 40 }, + ], + ambientExternalModules: undefined, + isLibFile: false + }) + }); }); }); diff --git a/tests/webTestServer.ts b/tests/webTestServer.ts index 6ddc18f1344..6bd15359e3f 100644 --- a/tests/webTestServer.ts +++ b/tests/webTestServer.ts @@ -5,7 +5,7 @@ import fs = require("fs"); import path = require("path"); import url = require("url"); import child_process = require("child_process"); -import os = require('os'); +import os = require("os"); /// Command line processing /// @@ -276,7 +276,6 @@ if ((browser && browser === 'chrome')) { console.log(`default Chrome location is unknown for platform '${os.platform()}'`); break; } - if (fs.existsSync(defaultChromePath)) { browserPath = defaultChromePath; } else {