Merge branch 'master' into common_source_directory

This commit is contained in:
Andy Hanson
2016-11-11 13:10:29 -08:00
299 changed files with 12814 additions and 2608 deletions
+156 -23
View File
@@ -560,6 +560,7 @@ namespace ts {
skipTransformFlagAggregation = true;
bindChildrenWorker(node);
skipTransformFlagAggregation = false;
subtreeTransformFlags |= node.transformFlags & ~getTransformFlagsSubtreeExclusions(node.kind);
}
else {
const savedSubtreeTransformFlags = subtreeTransformFlags;
@@ -895,8 +896,8 @@ namespace ts {
const enclosingLabeledStatement = node.parent.kind === SyntaxKind.LabeledStatement
? lastOrUndefined(activeLabels)
: undefined;
// if do statement is wrapped in labeled statement then target labels for break/continue with or without
// label should be the same
// if do statement is wrapped in labeled statement then target labels for break/continue with or without
// label should be the same
const preConditionLabel = enclosingLabeledStatement ? enclosingLabeledStatement.continueTarget : createBranchLabel();
const postDoLabel = enclosingLabeledStatement ? enclosingLabeledStatement.breakTarget : createBranchLabel();
addAntecedent(preDoLabel, currentFlow);
@@ -1138,8 +1139,8 @@ namespace ts {
}
else if (node.kind === SyntaxKind.ArrayLiteralExpression) {
for (const e of (<ArrayLiteralExpression>node).elements) {
if (e.kind === SyntaxKind.SpreadElementExpression) {
bindAssignmentTargetFlow((<SpreadElementExpression>e).expression);
if (e.kind === SyntaxKind.SpreadElement) {
bindAssignmentTargetFlow((<SpreadElement>e).expression);
}
else {
bindDestructuringTargetFlow(e);
@@ -1154,6 +1155,9 @@ namespace ts {
else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
bindAssignmentTargetFlow((<ShorthandPropertyAssignment>p).name);
}
else if (p.kind === SyntaxKind.SpreadAssignment) {
bindAssignmentTargetFlow((<SpreadAssignment>p).expression);
}
}
}
}
@@ -1234,9 +1238,11 @@ namespace ts {
const postExpressionLabel = createBranchLabel();
bindCondition(node.condition, trueLabel, falseLabel);
currentFlow = finishFlowLabel(trueLabel);
bind(node.questionToken);
bind(node.whenTrue);
addAntecedent(postExpressionLabel, currentFlow);
currentFlow = finishFlowLabel(falseLabel);
bind(node.colonToken);
bind(node.whenFalse);
addAntecedent(postExpressionLabel, currentFlow);
currentFlow = finishFlowLabel(postExpressionLabel);
@@ -1547,7 +1553,7 @@ namespace ts {
const seen = createMap<ElementKind>();
for (const prop of node.properties) {
if (prop.name.kind !== SyntaxKind.Identifier) {
if (prop.kind === SyntaxKind.SpreadAssignment || prop.name.kind !== SyntaxKind.Identifier) {
continue;
}
@@ -1913,6 +1919,9 @@ namespace ts {
return bindParameter(<ParameterDeclaration>node);
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
if ((node as BindingElement).dotDotDotToken && node.parent.kind === SyntaxKind.ObjectBindingPattern) {
emitFlags |= NodeFlags.HasRestAttribute;
}
return bindVariableDeclarationOrBindingElement(<VariableDeclaration | BindingElement>node);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
@@ -1926,8 +1935,21 @@ namespace ts {
case SyntaxKind.EnumMember:
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
case SyntaxKind.SpreadAssignment:
case SyntaxKind.JsxSpreadAttribute:
emitFlags |= NodeFlags.HasJsxSpreadAttributes;
let root = container;
let hasRest = false;
while (root.parent) {
if (root.kind === SyntaxKind.ObjectLiteralExpression &&
root.parent.kind === SyntaxKind.BinaryExpression &&
(root.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
(root.parent as BinaryExpression).left === root) {
hasRest = true;
break;
}
root = root.parent;
}
emitFlags |= hasRest ? NodeFlags.HasRestAttribute : NodeFlags.HasSpreadAttribute;
return;
case SyntaxKind.CallSignature:
@@ -2492,9 +2514,9 @@ namespace ts {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression
if (subtreeFlags & TransformFlags.ContainsSpreadExpression
|| isSuperOrSuperProperty(expression, expressionKind)) {
// If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6
// If the this node contains a SpreadExpression, or is a super call, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
}
@@ -2523,7 +2545,7 @@ namespace ts {
if (node.typeArguments) {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) {
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
// If the this node contains a SpreadElementExpression then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
@@ -2538,10 +2560,13 @@ namespace ts {
const operatorTokenKind = node.operatorToken.kind;
const leftKind = node.left.kind;
if (operatorTokenKind === SyntaxKind.EqualsToken
&& (leftKind === SyntaxKind.ObjectLiteralExpression
|| leftKind === SyntaxKind.ArrayLiteralExpression)) {
// Destructuring assignments are ES6 syntax.
if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) {
// Destructuring object assignments with are ES2015 syntax
// and possibly ESNext if they contain rest
transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment;
}
else if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ArrayLiteralExpression) {
// Destructuring assignments are ES2015 syntax.
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment;
}
else if (operatorTokenKind === SyntaxKind.AsteriskAsteriskToken
@@ -2575,6 +2600,11 @@ namespace ts {
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
}
// parameters with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If a parameter has an initializer, a binding pattern or a dotDotDot token, then
// it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel.
if (subtreeFlags & TransformFlags.ContainsBindingPattern || initializer || dotDotDotToken) {
@@ -2808,6 +2838,11 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2017;
}
// function declarations with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If a FunctionDeclaration's subtree has marked the container as needing to capture the
// lexical this, or the function contains parameters with initializers, then this node is
// ES6 syntax.
@@ -2845,6 +2880,12 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2017;
}
// function expressions with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If a FunctionExpression's subtree has marked the container as needing to capture the
// lexical this, or the function contains parameters with initializers, then this node is
// ES6 syntax.
@@ -2882,6 +2923,11 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2017;
}
// arrow functions with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext;
}
// If an ArrowFunction contains a lexical this, its container must capture the lexical this.
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
@@ -2910,8 +2956,13 @@ namespace ts {
let transformFlags = subtreeFlags;
const nameKind = node.name.kind;
// A VariableDeclaration with a binding pattern is ES6 syntax.
if (nameKind === SyntaxKind.ObjectBindingPattern || nameKind === SyntaxKind.ArrayBindingPattern) {
// A VariableDeclaration with an object binding pattern is ES2015 syntax
// and possibly ESNext syntax if it contains an object binding pattern
if (nameKind === SyntaxKind.ObjectBindingPattern) {
transformFlags |= TransformFlags.AssertESNext | TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
}
// A VariableDeclaration with an object binding pattern is ES2015 syntax.
else if (nameKind === SyntaxKind.ArrayBindingPattern) {
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
}
@@ -3052,6 +3103,10 @@ namespace ts {
transformFlags |= TransformFlags.AssertJsx;
break;
case SyntaxKind.ForOfStatement:
// for-of might be ESNext if it has a rest destructuring
transformFlags |= TransformFlags.AssertESNext;
// FALLTHROUGH
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateHead:
case SyntaxKind.TemplateMiddle:
@@ -3059,7 +3114,6 @@ namespace ts {
case SyntaxKind.TemplateExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.ForOfStatement:
case SyntaxKind.StaticKeyword:
// These nodes are ES6 syntax.
transformFlags |= TransformFlags.AssertES2015;
@@ -3123,11 +3177,18 @@ namespace ts {
}
break;
case SyntaxKind.SpreadElementExpression:
// This node is ES6 syntax, but is handled by a containing node.
transformFlags |= TransformFlags.ContainsSpreadElementExpression;
case SyntaxKind.SpreadElement:
case SyntaxKind.SpreadAssignment:
// This node is ES6 or ES next syntax, but is handled by a containing node.
transformFlags |= TransformFlags.ContainsSpreadExpression;
break;
case SyntaxKind.BindingElement:
if ((node as BindingElement).dotDotDotToken) {
// this node is ES2015 or ES next syntax, but is handled by a containing node.
transformFlags |= TransformFlags.ContainsSpreadExpression;
}
case SyntaxKind.SuperKeyword:
// This node is ES6 syntax.
transformFlags |= TransformFlags.AssertES2015;
@@ -3140,8 +3201,13 @@ namespace ts {
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
// These nodes are ES6 syntax.
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
// These nodes are ES2015 or ES Next syntax.
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsBindingPattern;
}
else {
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
}
break;
case SyntaxKind.Decorator:
@@ -3163,13 +3229,19 @@ namespace ts {
transformFlags |= TransformFlags.ContainsLexicalThis;
}
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
// If an ObjectLiteralExpression contains a spread element, then it
// is an ES next node.
transformFlags |= TransformFlags.AssertESNext;
}
break;
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.NewExpression:
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) {
// If the this node contains a SpreadElementExpression, then it is an ES6
if (subtreeFlags & TransformFlags.ContainsSpreadExpression) {
// If the this node contains a SpreadExpression, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
}
@@ -3204,4 +3276,65 @@ namespace ts {
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
return transformFlags & ~excludeFlags;
}
/**
* Gets the transform flags to exclude when unioning the transform flags of a subtree.
*
* NOTE: This needs to be kept up-to-date with the exclusions used in `computeTransformFlagsForNode`.
* For performance reasons, `computeTransformFlagsForNode` uses local constant values rather
* than calling this function.
*/
/* @internal */
export function getTransformFlagsSubtreeExclusions(kind: SyntaxKind) {
if (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) {
return TransformFlags.TypeExcludes;
}
switch (kind) {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.ArrayLiteralExpression:
return TransformFlags.ArrayLiteralOrCallOrNewExcludes;
case SyntaxKind.ModuleDeclaration:
return TransformFlags.ModuleExcludes;
case SyntaxKind.Parameter:
return TransformFlags.ParameterExcludes;
case SyntaxKind.ArrowFunction:
return TransformFlags.ArrowFunctionExcludes;
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
return TransformFlags.FunctionExcludes;
case SyntaxKind.VariableDeclarationList:
return TransformFlags.VariableDeclarationListExcludes;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return TransformFlags.ClassExcludes;
case SyntaxKind.Constructor:
return TransformFlags.ConstructorExcludes;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return TransformFlags.MethodOrAccessorExcludes;
case SyntaxKind.AnyKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.TypeParameter:
case SyntaxKind.PropertySignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
return TransformFlags.TypeExcludes;
case SyntaxKind.ObjectLiteralExpression:
return TransformFlags.ObjectLiteralExcludes;
default:
return TransformFlags.NodeExcludes;
}
}
}
+330 -117
View File
@@ -335,6 +335,9 @@ namespace ts {
});
let jsxElementType: Type;
let _jsxNamespace: string;
let _jsxFactoryEntity: EntityName;
/** Things we lazy load from the JSX namespace */
const jsxTypes = createMap<Type>();
const JsxNames = {
@@ -372,6 +375,22 @@ namespace ts {
return checker;
function getJsxNamespace(): string {
if (_jsxNamespace === undefined) {
_jsxNamespace = "React";
if (compilerOptions.jsxFactory) {
_jsxFactoryEntity = parseIsolatedEntityName(compilerOptions.jsxFactory, languageVersion);
if (_jsxFactoryEntity) {
_jsxNamespace = getFirstIdentifier(_jsxFactoryEntity).text;
}
}
else if (compilerOptions.reactNamespace) {
_jsxNamespace = compilerOptions.reactNamespace;
}
}
return _jsxNamespace;
}
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
// Ensure we have all the type information in place for this file so that all the
// emitter questions of this resolver will return the right information.
@@ -2229,14 +2248,8 @@ namespace ts {
// The specified symbol flags need to be reinterpreted as type flags
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
}
else if (!(flags & TypeFormatFlags.InTypeAlias) && ((getObjectFlags(type) & ObjectFlags.Anonymous && !(<AnonymousType>type).target) || type.flags & TypeFlags.UnionOrIntersection) && type.aliasSymbol &&
else if (!(flags & TypeFormatFlags.InTypeAlias) && (getObjectFlags(type) & ObjectFlags.Anonymous || type.flags & TypeFlags.UnionOrIntersection) && type.aliasSymbol &&
isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
// We emit inferred type as type-alias at the current localtion if all the following is true
// the input type is has alias symbol that is accessible
// the input type is a union, intersection or anonymous type that is fully instantiated (if not we want to keep dive into)
// e.g.: export type Bar<X, Y> = () => [X, Y];
// export type Foo<Y> = Bar<any, Y>;
// export const y = (x: Foo<string>) => 1 // we want to emit as ...x: () => [any, string])
const typeArguments = type.aliasTypeArguments;
writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags);
}
@@ -2500,6 +2513,13 @@ namespace ts {
writePunctuation(writer, SyntaxKind.OpenBraceToken);
writer.writeLine();
writer.increaseIndent();
writeObjectLiteralType(resolved);
writer.decreaseIndent();
writePunctuation(writer, SyntaxKind.CloseBraceToken);
inObjectTypeLiteral = saveInObjectTypeLiteral;
}
function writeObjectLiteralType(resolved: ResolvedType) {
for (const signature of resolved.callSignatures) {
buildSignatureDisplay(signature, writer, enclosingDeclaration, globalFlagsToPass, /*kind*/ undefined, symbolStack);
writePunctuation(writer, SyntaxKind.SemicolonToken);
@@ -2532,11 +2552,8 @@ namespace ts {
writer.writeLine();
}
}
writer.decreaseIndent();
writePunctuation(writer, SyntaxKind.CloseBraceToken);
inObjectTypeLiteral = saveInObjectTypeLiteral;
}
}
}
function buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) {
const targetSymbol = getTargetSymbol(symbol);
@@ -2978,26 +2995,31 @@ namespace ts {
return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false);
}
function getTextOfPropertyName(name: PropertyName): string {
switch (name.kind) {
case SyntaxKind.Identifier:
return (<Identifier>name).text;
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return (<LiteralExpression>name).text;
case SyntaxKind.ComputedPropertyName:
if (isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind)) {
return (<LiteralExpression>(<ComputedPropertyName>name).expression).text;
}
}
return undefined;
}
function isComputedNonLiteralName(name: PropertyName): boolean {
return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind);
}
function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type {
Debug.assert(!!(source.flags & TypeFlags.Object), "Rest types only support object types right now.");
const members = createMap<Symbol>();
const names = createMap<true>();
for (const name of properties) {
names[getTextOfPropertyName(name)] = true;
}
for (const prop of getPropertiesOfType(source)) {
const inNamesToRemove = prop.name in names;
const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected);
const isMethod = prop.flags & SymbolFlags.Method;
const isSetOnlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
if (!inNamesToRemove && !isPrivate && !isMethod && !isSetOnlyAccessor) {
members[prop.name] = prop;
}
}
const stringIndexInfo = getIndexInfoOfType(source, IndexKind.String);
const numberIndexInfo = getIndexInfoOfType(source, IndexKind.Number);
return createAnonymousType(symbol, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
}
/** Return the inferred type for a binding element */
function getTypeForBindingElement(declaration: BindingElement): Type {
const pattern = <BindingPattern>declaration.parent;
@@ -3018,26 +3040,41 @@ namespace ts {
let type: Type;
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
const name = declaration.propertyName || <Identifier>declaration.name;
if (isComputedNonLiteralName(name)) {
// computed properties with non-literal names are treated as 'any'
return anyType;
}
if (declaration.initializer) {
getContextualType(declaration.initializer);
if (declaration.dotDotDotToken) {
if (!(parentType.flags & TypeFlags.Object)) {
error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types);
return unknownType;
}
const literalMembers: PropertyName[] = [];
for (const element of pattern.elements) {
if (element.kind !== SyntaxKind.OmittedExpression && !(element as BindingElement).dotDotDotToken) {
literalMembers.push(element.propertyName || element.name as Identifier);
}
}
type = getRestType(parentType, literalMembers, declaration.symbol);
}
else {
// Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
const name = declaration.propertyName || <Identifier>declaration.name;
if (isComputedNonLiteralName(name)) {
// computed properties with non-literal names are treated as 'any'
return anyType;
}
if (declaration.initializer) {
getContextualType(declaration.initializer);
}
// 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.
const text = getTextOfPropertyName(name);
// 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.
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));
return unknownType;
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));
return unknownType;
}
}
}
else {
@@ -3045,7 +3082,11 @@ namespace ts {
// present (aka the tuple element property). This call also checks that the parentType is in
// fact an iterable or array (depending on target language).
const elementType = checkIteratedTypeOrElementType(parentType, pattern, /*allowStringInput*/ false);
if (!declaration.dotDotDotToken) {
if (declaration.dotDotDotToken) {
// Rest element has an array type with the same element type as the parent type
type = createArrayType(elementType);
}
else {
// Use specific property type when parent is a tuple or numeric index type when parent is an array
const propName = "" + indexOf(pattern.elements, declaration);
type = isTupleLikeType(parentType)
@@ -3061,10 +3102,6 @@ namespace ts {
return unknownType;
}
}
else {
// Rest element has an array type with the same element type as the parent type
type = createArrayType(elementType);
}
}
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
// undefined from the final type.
@@ -3245,8 +3282,8 @@ namespace ts {
let hasComputedProperties = false;
forEach(pattern.elements, e => {
const name = e.propertyName || <Identifier>e.name;
if (isComputedNonLiteralName(name)) {
// do not include computed properties in the implied type
if (isComputedNonLiteralName(name) || e.dotDotDotToken) {
// do not include computed properties or rests in the implied type
hasComputedProperties = true;
return;
}
@@ -4164,8 +4201,8 @@ namespace ts {
else {
mapper = createTypeMapper(typeParameters, typeArguments);
members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1);
callSignatures = instantiateList(source.declaredCallSignatures, mapper, instantiateSignature);
constructSignatures = instantiateList(source.declaredConstructSignatures, mapper, instantiateSignature);
callSignatures = instantiateSignatures(source.declaredCallSignatures, mapper);
constructSignatures = instantiateSignatures(source.declaredConstructSignatures, mapper);
stringIndexInfo = instantiateIndexInfo(source.declaredStringIndexInfo, mapper);
numberIndexInfo = instantiateIndexInfo(source.declaredNumberIndexInfo, mapper);
}
@@ -4232,7 +4269,7 @@ namespace ts {
for (const baseSig of baseSignatures) {
const typeParamCount = baseSig.typeParameters ? baseSig.typeParameters.length : 0;
if (typeParamCount === typeArgCount) {
const sig = typeParamCount ? getSignatureInstantiation(baseSig, typeArguments) : cloneSignature(baseSig);
const sig = typeParamCount ? createSignatureInstantiation(baseSig, typeArguments) : cloneSignature(baseSig);
sig.typeParameters = classType.localTypeParameters;
sig.resolvedReturnType = classType;
result.push(sig);
@@ -4343,6 +4380,11 @@ namespace ts {
getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly);
}
function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo {
return info1 && info2 && createIndexInfo(
getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly);
}
function resolveIntersectionTypeMembers(type: IntersectionType) {
// The members and properties collections are empty for intersection types. To get all properties of an
// intersection type use getPropertiesOfType (only the language service uses this).
@@ -4363,8 +4405,8 @@ namespace ts {
const symbol = type.symbol;
if (type.target) {
const members = createInstantiatedSymbolTable(getPropertiesOfObjectType(type.target), type.mapper, /*mappingThisOnly*/ false);
const callSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper, instantiateSignature);
const constructSignatures = instantiateList(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper, instantiateSignature);
const callSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Call), type.mapper);
const constructSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper);
const stringIndexInfo = instantiateIndexInfo(getIndexInfoOfType(type.target, IndexKind.String), type.mapper);
const numberIndexInfo = instantiateIndexInfo(getIndexInfoOfType(type.target, IndexKind.Number), type.mapper);
setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
@@ -4479,7 +4521,9 @@ namespace ts {
function getPropertiesOfType(type: Type): Symbol[] {
type = getApparentType(type);
return type.flags & TypeFlags.UnionOrIntersection ? getPropertiesOfUnionOrIntersectionType(<UnionType>type) : getPropertiesOfObjectType(type);
return type.flags & TypeFlags.UnionOrIntersection ?
getPropertiesOfUnionOrIntersectionType(<UnionType>type) :
getPropertiesOfObjectType(type);
}
/**
@@ -4534,6 +4578,7 @@ namespace ts {
if (isReadonlySymbol(prop)) {
isReadonly = true;
}
}
else if (containingType.flags & TypeFlags.Union) {
isPartial = true;
@@ -4982,6 +5027,12 @@ namespace ts {
}
function getSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature {
const instantiations = signature.instantiations || (signature.instantiations = createMap<Signature>());
const id = getTypeListId(typeArguments);
return instantiations[id] || (instantiations[id] = createSignatureInstantiation(signature, typeArguments));
}
function createSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature {
return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), /*eraseTypeParameters*/ true);
}
@@ -5860,6 +5911,68 @@ namespace ts {
return links.resolvedType;
}
/**
* Since the source of spread types are object literals, which are not binary,
* this function should be called in a left folding style, with left = previous result of getSpreadType
* and right = the new element to be spread.
*/
function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): ResolvedType | IntrinsicType {
Debug.assert(!!(left.flags & (TypeFlags.Object | TypeFlags.Any)) && !!(right.flags & (TypeFlags.Object | TypeFlags.Any)), "Only object types may be spread.");
if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
return anyType;
}
const members = createMap<Symbol>();
const skippedPrivateMembers = createMap<boolean>();
let stringIndexInfo: IndexInfo;
let numberIndexInfo: IndexInfo;
if (left === emptyObjectType) {
// for the first spread element, left === emptyObjectType, so take the right's string indexer
stringIndexInfo = getIndexInfoOfType(right, IndexKind.String);
numberIndexInfo = getIndexInfoOfType(right, IndexKind.Number);
}
else {
stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String));
numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number));
}
for (const rightProp of getPropertiesOfType(right)) {
// we approximate own properties as non-methods plus methods that are inside the object literal
const isOwnProperty = !(rightProp.flags & SymbolFlags.Method) || isFromObjectLiteral;
const isSetterWithoutGetter = rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor);
if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) {
skippedPrivateMembers[rightProp.name] = true;
}
else if (isOwnProperty && !isSetterWithoutGetter) {
members[rightProp.name] = rightProp;
}
}
for (const leftProp of getPropertiesOfType(left)) {
if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor)
|| leftProp.name in skippedPrivateMembers) {
continue;
}
if (leftProp.name in members) {
const rightProp = members[leftProp.name];
const rightType = getTypeOfSymbol(rightProp);
if (maybeTypeOfKind(rightType, TypeFlags.Undefined) || rightProp.flags & SymbolFlags.Optional) {
const declarations: Declaration[] = concatenate(leftProp.declarations, rightProp.declarations);
const flags = SymbolFlags.Property | SymbolFlags.Transient | (leftProp.flags & SymbolFlags.Optional);
const result = <TransientSymbol>createSymbol(flags, leftProp.name);
result.type = getUnionType([getTypeOfSymbol(leftProp), getTypeWithFacts(rightType, TypeFacts.NEUndefined)]);
result.leftSpread = leftProp;
result.rightSpread = rightProp;
result.declarations = declarations;
result.isReadonly = isReadonlySymbol(leftProp) || isReadonlySymbol(rightProp);
members[leftProp.name] = result;
}
}
else {
members[leftProp.name] = leftProp;
}
}
return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
}
function createLiteralType(flags: TypeFlags, text: string) {
const type = <LiteralType>createType(flags);
type.text = text;
@@ -6037,6 +6150,14 @@ namespace ts {
return items;
}
function instantiateTypes(types: Type[], mapper: TypeMapper) {
return instantiateList(types, mapper, instantiateType);
}
function instantiateSignatures(signatures: Signature[], mapper: TypeMapper) {
return instantiateList(signatures, mapper, instantiateSignature);
}
function createUnaryTypeMapper(source: Type, target: Type): TypeMapper {
return t => t === source ? target : t;
}
@@ -6063,7 +6184,6 @@ namespace ts {
count == 2 ? createBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
createArrayTypeMapper(sources, targets);
mapper.mappedTypes = sources;
mapper.targetTypes = targets;
return mapper;
}
@@ -6190,7 +6310,7 @@ namespace ts {
result.target = type;
result.mapper = mapper;
result.aliasSymbol = type.aliasSymbol;
result.aliasTypeArguments = mapper.targetTypes;
result.aliasTypeArguments = instantiateTypes(type.aliasTypeArguments, mapper);
mapper.instantiations[type.id] = result;
return result;
}
@@ -6266,14 +6386,14 @@ namespace ts {
instantiateAnonymousType(<AnonymousType>type, mapper) : type;
}
if ((<ObjectType>type).objectFlags & ObjectFlags.Reference) {
return createTypeReference((<TypeReference>type).target, instantiateList((<TypeReference>type).typeArguments, mapper, instantiateType));
return createTypeReference((<TypeReference>type).target, instantiateTypes((<TypeReference>type).typeArguments, mapper));
}
}
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
return getUnionType(instantiateList((<UnionType>type).types, mapper, instantiateType), /*subtypeReduction*/ false, type.aliasSymbol, mapper.targetTypes);
return getUnionType(instantiateTypes((<UnionType>type).types, mapper), /*subtypeReduction*/ false, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
}
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(instantiateList((<IntersectionType>type).types, mapper, instantiateType), type.aliasSymbol, mapper.targetTypes);
return getIntersectionType(instantiateTypes((<IntersectionType>type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
}
if (type.flags & TypeFlags.Index) {
return getIndexType(instantiateType((<IndexType>type).type, mapper));
@@ -6723,9 +6843,15 @@ namespace ts {
}
if (!message) {
message = relation === comparableRelation ?
Diagnostics.Type_0_is_not_comparable_to_type_1 :
Diagnostics.Type_0_is_not_assignable_to_type_1;
if (relation === comparableRelation) {
message = Diagnostics.Type_0_is_not_comparable_to_type_1;
}
else if (sourceType === targetType) {
message = Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated;
}
else {
message = Diagnostics.Type_0_is_not_assignable_to_type_1;
}
}
reportError(message, sourceType, targetType);
@@ -6825,6 +6951,27 @@ namespace ts {
}
}
if (target.flags & TypeFlags.TypeParameter) {
// Given a type parameter K with a constraint keyof T, a type S is
// assignable to K if S is assignable to keyof T.
const constraint = getConstraintOfTypeParameter(<TypeParameter>target);
if (constraint && constraint.flags & TypeFlags.Index) {
if (result = isRelatedTo(source, constraint, reportErrors)) {
return result;
}
}
}
else if (target.flags & TypeFlags.Index) {
// Given a type parameter T with a constraint C, a type S is assignable to
// keyof T if S is assignable to keyof C.
const constraint = getConstraintOfTypeParameter((<IndexType>target).type);
if (constraint) {
if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) {
return result;
}
}
}
if (source.flags & TypeFlags.TypeParameter) {
let constraint = getConstraintOfTypeParameter(<TypeParameter>source);
@@ -8543,7 +8690,7 @@ namespace ts {
unknownType;
}
function getTypeOfDestructuredSpreadElement(type: Type) {
function getTypeOfDestructuredSpreadExpression(type: Type) {
return createArrayType(checkIteratedTypeOrElementType(type, /*errorNode*/ undefined, /*allowStringInput*/ false) || unknownType);
}
@@ -8557,8 +8704,8 @@ namespace ts {
return getTypeOfDestructuredArrayElement(getAssignedType(node), indexOf(node.elements, element));
}
function getAssignedTypeOfSpreadElement(node: SpreadElementExpression): Type {
return getTypeOfDestructuredSpreadElement(getAssignedType(<ArrayLiteralExpression>node.parent));
function getAssignedTypeOfSpreadExpression(node: SpreadElement): Type {
return getTypeOfDestructuredSpreadExpression(getAssignedType(<ArrayLiteralExpression>node.parent));
}
function getAssignedTypeOfPropertyAssignment(node: PropertyAssignment | ShorthandPropertyAssignment): Type {
@@ -8582,8 +8729,8 @@ namespace ts {
return undefinedType;
case SyntaxKind.ArrayLiteralExpression:
return getAssignedTypeOfArrayLiteralElement(<ArrayLiteralExpression>parent, node);
case SyntaxKind.SpreadElementExpression:
return getAssignedTypeOfSpreadElement(<SpreadElementExpression>parent);
case SyntaxKind.SpreadElement:
return getAssignedTypeOfSpreadExpression(<SpreadElement>parent);
case SyntaxKind.PropertyAssignment:
return getAssignedTypeOfPropertyAssignment(<PropertyAssignment>parent);
case SyntaxKind.ShorthandPropertyAssignment:
@@ -8599,7 +8746,7 @@ namespace ts {
getTypeOfDestructuredProperty(parentType, node.propertyName || <Identifier>node.name) :
!node.dotDotDotToken ?
getTypeOfDestructuredArrayElement(parentType, indexOf(pattern.elements, node)) :
getTypeOfDestructuredSpreadElement(parentType);
getTypeOfDestructuredSpreadExpression(parentType);
return getTypeWithDefault(type, node.initializer);
}
@@ -10614,7 +10761,7 @@ namespace ts {
return mapper && mapper.context;
}
function checkSpreadElementExpression(node: SpreadElementExpression, contextualMapper?: TypeMapper): Type {
function checkSpreadExpression(node: SpreadElement, contextualMapper?: TypeMapper): Type {
// It is usually not safe to call checkExpressionCached if we can be contextually typing.
// You can tell that we are contextually typing because of the contextualMapper parameter.
// While it is true that a spread element can have a contextual type, it does not do anything
@@ -10636,7 +10783,7 @@ namespace ts {
const elementTypes: Type[] = [];
const inDestructuringPattern = isAssignmentTarget(node);
for (const e of elements) {
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) {
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElement) {
// Given the following situation:
// var c: {};
// [...c] = ["", 0];
@@ -10649,7 +10796,7 @@ namespace ts {
// get the contextual element type from it. So we do something similar to
// getContextualTypeForElementExpression, which will crucially not error
// if there is no index type / iterated type.
const restArrayType = checkExpression((<SpreadElementExpression>e).expression, contextualMapper);
const restArrayType = checkExpression((<SpreadElement>e).expression, contextualMapper);
const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
(languageVersion >= ScriptTarget.ES2015 ? getElementTypeOfIterable(restArrayType, /*errorNode*/ undefined) : undefined);
if (restElementType) {
@@ -10660,7 +10807,7 @@ namespace ts {
const type = checkExpressionForMutableLocation(e, contextualMapper);
elementTypes.push(type);
}
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression;
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement;
}
if (!hasSpreadElement) {
// If array literal is actually a destructuring pattern, mark it as an implied type. We do this such
@@ -10777,8 +10924,11 @@ namespace ts {
// Grammar checking
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
const propertiesTable = createMap<Symbol>();
const propertiesArray: Symbol[] = [];
let propertiesTable = createMap<Symbol>();
let propertiesArray: Symbol[] = [];
let spread: Type = emptyObjectType;
let propagatedFlags: TypeFlags = 0;
const contextualType = getApparentTypeOfContextualType(node);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
@@ -10803,6 +10953,7 @@ namespace ts {
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
type = checkExpressionForMutableLocation((<ShorthandPropertyAssignment>memberDecl).name, contextualMapper);
}
typeFlags |= type.flags;
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
if (inDestructuringPattern) {
@@ -10840,6 +10991,23 @@ namespace ts {
prop.target = member;
member = prop;
}
else if (memberDecl.kind === SyntaxKind.SpreadAssignment) {
if (propertiesArray.length > 0) {
spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true);
propertiesArray = [];
propertiesTable = createMap<Symbol>();
hasComputedStringProperty = false;
hasComputedNumberProperty = false;
typeFlags = 0;
}
const type = checkExpression((memberDecl as SpreadAssignment).expression);
if (!(type.flags & (TypeFlags.Object | TypeFlags.Any))) {
error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
return unknownType;
}
spread = getSpreadType(spread, type, /*isFromObjectLiteral*/ false);
continue;
}
else {
// TypeScript 1.0 spec (April 2014)
// A get accessor declaration is processed in the same manner as
@@ -10879,20 +11047,36 @@ namespace ts {
}
}
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
result.objectFlags |= ObjectFlags.ObjectLiteral;
if (patternWithComputedProperties) {
result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
if (spread !== emptyObjectType) {
if (propertiesArray.length > 0) {
spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true);
}
spread.flags |= propagatedFlags;
spread.symbol = node.symbol;
return spread;
}
if (inDestructuringPattern) {
result.pattern = node;
return createObjectLiteralType();
function createObjectLiteralType() {
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
result.objectFlags |= ObjectFlags.ObjectLiteral;
if (patternWithComputedProperties) {
result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
}
if (inDestructuringPattern) {
result.pattern = node;
}
if (!(result.flags & TypeFlags.Nullable)) {
propagatedFlags |= (result.flags & TypeFlags.PropagatingFlags);
}
return result;
}
return result;
}
}
function checkJsxSelfClosingElement(node: JsxSelfClosingElement) {
checkJsxOpeningLikeElement(node);
@@ -11309,10 +11493,10 @@ namespace ts {
function checkJsxOpeningLikeElement(node: JsxOpeningLikeElement) {
checkGrammarJsxElement(node);
checkJsxPreconditions(node);
// The reactNamespace symbol should be marked as 'used' so we don't incorrectly elide its import. And if there
// is no reactNamespace symbol in scope when targeting React emit, we should issue an error.
// The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import.
// And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error.
const reactRefErr = compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
const reactNamespace = compilerOptions.reactNamespace ? compilerOptions.reactNamespace : "React";
const reactNamespace = getJsxNamespace();
const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace);
if (reactSym) {
// Mark local symbol as referenced here because it might not have been marked
@@ -11513,6 +11697,21 @@ namespace ts {
diagnostics.add(createDiagnosticForNodeFromMessageChain(propNode, errorInfo));
}
function markPropertyAsReferenced(prop: Symbol) {
if (prop &&
noUnusedIdentifiers &&
(prop.flags & SymbolFlags.ClassMember) &&
prop.valueDeclaration && (getModifierFlags(prop.valueDeclaration) & ModifierFlags.Private)) {
if (prop.flags & SymbolFlags.Instantiated) {
getSymbolLinks(prop).target.isReferenced = true;
}
else {
prop.isReferenced = true;
}
}
}
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) {
const type = checkNonNullExpression(left);
if (isTypeAny(type) || type === silentNeverType) {
@@ -11532,17 +11731,7 @@ namespace ts {
return unknownType;
}
if (noUnusedIdentifiers &&
(prop.flags & SymbolFlags.ClassMember) &&
prop.valueDeclaration && (getModifierFlags(prop.valueDeclaration) & ModifierFlags.Private)) {
if (prop.flags & SymbolFlags.Instantiated) {
getSymbolLinks(prop).target.isReferenced = true;
}
else {
prop.isReferenced = true;
}
}
markPropertyAsReferenced(prop);
getNodeLinks(node).resolvedSymbol = prop;
@@ -11786,7 +11975,7 @@ namespace ts {
function getSpreadArgumentIndex(args: Expression[]): number {
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg && arg.kind === SyntaxKind.SpreadElementExpression) {
if (arg && arg.kind === SyntaxKind.SpreadElement) {
return i;
}
}
@@ -13752,6 +13941,11 @@ namespace ts {
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), declarationNameToString(name));
}
}
else if (property.kind === SyntaxKind.SpreadAssignment) {
if (property.expression.kind !== SyntaxKind.Identifier) {
error(property.expression, Diagnostics.An_object_rest_element_must_be_an_identifier);
}
}
else {
error(property, Diagnostics.Property_assignment_expected);
}
@@ -13774,7 +13968,7 @@ namespace ts {
const elements = node.elements;
const element = elements[elementIndex];
if (element.kind !== SyntaxKind.OmittedExpression) {
if (element.kind !== SyntaxKind.SpreadElementExpression) {
if (element.kind !== SyntaxKind.SpreadElement) {
const propName = "" + elementIndex;
const type = isTypeAny(sourceType)
? sourceType
@@ -13798,10 +13992,10 @@ namespace ts {
}
else {
if (elementIndex < elements.length - 1) {
error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern);
}
else {
const restExpression = (<SpreadElementExpression>element).expression;
const restExpression = (<SpreadElement>element).expression;
if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
@@ -14434,8 +14628,8 @@ namespace ts {
return checkBinaryExpression(<BinaryExpression>node, contextualMapper);
case SyntaxKind.ConditionalExpression:
return checkConditionalExpression(<ConditionalExpression>node, contextualMapper);
case SyntaxKind.SpreadElementExpression:
return checkSpreadElementExpression(<SpreadElementExpression>node, contextualMapper);
case SyntaxKind.SpreadElement:
return checkSpreadExpression(<SpreadElement>node, contextualMapper);
case SyntaxKind.OmittedExpression:
return undefinedWideningType;
case SyntaxKind.YieldExpression:
@@ -16332,6 +16526,7 @@ namespace ts {
const parentType = getTypeForBindingElementParent(parent);
const name = node.propertyName || <Identifier>node.name;
const property = getPropertyOfType(parentType, getTextOfPropertyName(name));
markPropertyAsReferenced(property);
if (parent.initializer && property && getParentOfSymbol(property)) {
checkClassPropertyAccess(parent, parent.initializer, parentType, property);
}
@@ -16946,6 +17141,7 @@ namespace ts {
let hasDuplicateDefaultClause = false;
const expressionType = checkExpression(node.expression);
const expressionIsLiteral = isLiteralType(expressionType);
forEach(node.caseBlock.clauses, clause => {
// Grammar check for duplicate default clauses, skip if we already report duplicate default clause
if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) {
@@ -16966,10 +17162,16 @@ namespace ts {
// TypeScript 1.0 spec (April 2014): 5.9
// In a 'switch' statement, each 'case' expression must be of a type that is comparable
// to or from the type of the 'switch' expression.
const caseType = checkExpression(caseClause.expression);
if (!isTypeEqualityComparableTo(expressionType, caseType)) {
let caseType = checkExpression(caseClause.expression);
const caseIsLiteral = isLiteralType(caseType);
let comparedExpressionType = expressionType;
if (!caseIsLiteral || !expressionIsLiteral) {
caseType = caseIsLiteral ? getBaseTypeOfLiteralType(caseType) : caseType;
comparedExpressionType = getBaseTypeOfLiteralType(expressionType);
}
if (!isTypeEqualityComparableTo(comparedExpressionType, caseType)) {
// expressionType is not comparable to caseType, try the reversed check and report errors if it fails
checkTypeComparableTo(caseType, expressionType, caseClause.expression, /*headMessage*/ undefined);
checkTypeComparableTo(caseType, comparedExpressionType, caseClause.expression, /*headMessage*/ undefined);
}
}
forEach(clause.statements, checkSourceElement);
@@ -19074,6 +19276,10 @@ namespace ts {
return symbols;
}
else if (symbol.flags & SymbolFlags.Transient) {
if ((symbol as SymbolLinks).leftSpread) {
const links = symbol as SymbolLinks;
return [links.leftSpread, links.rightSpread];
}
let target: Symbol;
let next = symbol;
while (next = getSymbolLinks(next).target) {
@@ -19562,7 +19768,8 @@ namespace ts {
getTypeReferenceDirectivesForEntityName,
getTypeReferenceDirectivesForSymbol,
isLiteralConstDeclaration,
writeLiteralConstValue
writeLiteralConstValue,
getJsxFactoryEntity: () => _jsxFactoryEntity
};
// defined here to avoid outer scope pollution
@@ -19774,9 +19981,13 @@ namespace ts {
if (requestedExternalEmitHelpers & NodeFlags.HasClassExtends && languageVersion < ScriptTarget.ES2015) {
verifyHelperSymbol(exports, "__extends", SymbolFlags.Value);
}
if (requestedExternalEmitHelpers & NodeFlags.HasJsxSpreadAttributes && compilerOptions.jsx !== JsxEmit.Preserve) {
if (requestedExternalEmitHelpers & NodeFlags.HasSpreadAttribute &&
(languageVersion < ScriptTarget.ESNext || compilerOptions.jsx === JsxEmit.React)) {
verifyHelperSymbol(exports, "__assign", SymbolFlags.Value);
}
if (languageVersion < ScriptTarget.ESNext && requestedExternalEmitHelpers & NodeFlags.HasRestAttribute) {
verifyHelperSymbol(exports, "__rest", SymbolFlags.Value);
}
if (requestedExternalEmitHelpers & NodeFlags.HasDecorators) {
verifyHelperSymbol(exports, "__decorate", SymbolFlags.Value);
if (compilerOptions.emitDecoratorMetadata) {
@@ -20337,7 +20548,6 @@ namespace ts {
checkGrammarHeritageClause(heritageClause);
}
}
return false;
}
@@ -20385,6 +20595,9 @@ namespace ts {
const GetOrSetAccessor = GetAccessor | SetAccessor;
for (const prop of node.properties) {
if (prop.kind === SyntaxKind.SpreadAssignment) {
continue;
}
const name = prop.name;
if (name.kind === SyntaxKind.ComputedPropertyName) {
// If the name is not a ComputedPropertyName, the grammar checking will skip it
@@ -20688,7 +20901,7 @@ namespace ts {
if (node.dotDotDotToken) {
const elements = (<BindingPattern>node.parent).elements;
if (node !== lastOrUndefined(elements)) {
return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern);
}
if (node.name.kind === SyntaxKind.ArrayBindingPattern || node.name.kind === SyntaxKind.ObjectBindingPattern) {
@@ -20696,7 +20909,7 @@ namespace ts {
}
if (node.initializer) {
// Error on equals token which immediate precedes the initializer
// Error on equals token which immediately precedes the initializer
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
}
+8 -1
View File
@@ -77,6 +77,11 @@ namespace ts {
type: "string",
description: Diagnostics.Specify_the_object_invoked_for_createElement_and_spread_when_targeting_react_JSX_emit
},
{
name: "jsxFactory",
type: "string",
description: Diagnostics.Specify_the_JSX_factory_function_to_use_when_targeting_react_JSX_emit_e_g_React_createElement_or_h
},
{
name: "listFiles",
type: "boolean",
@@ -265,6 +270,7 @@ namespace ts {
"es2015": ScriptTarget.ES2015,
"es2016": ScriptTarget.ES2016,
"es2017": ScriptTarget.ES2017,
"esnext": ScriptTarget.ESNext,
}),
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015,
paramType: Diagnostics.VERSION,
@@ -428,7 +434,8 @@ namespace ts {
"es2015.symbol.wellknown": "lib.es2015.symbol.wellknown.d.ts",
"es2016.array.include": "lib.es2016.array.include.d.ts",
"es2017.object": "lib.es2017.object.d.ts",
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts"
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts",
"es2017.string": "lib.es2017.string.d.ts",
}),
},
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon
+12
View File
@@ -1127,6 +1127,18 @@ namespace ts {
};
}
export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessageChain): Diagnostic {
return {
file: undefined,
start: undefined,
length: undefined,
code: chain.code,
category: chain.category,
messageText: chain.next ? chain : chain.messageText
};
}
export function chainDiagnosticMessages(details: DiagnosticMessageChain, message: DiagnosticMessage, ...args: any[]): DiagnosticMessageChain;
export function chainDiagnosticMessages(details: DiagnosticMessageChain, message: DiagnosticMessage): DiagnosticMessageChain {
let text = getLocaleSpecificMessage(message);
+29 -1
View File
@@ -1455,7 +1455,7 @@
"category": "Error",
"code": 2461
},
"A rest element must be last in an array destructuring pattern": {
"A rest element must be last in a destructuring pattern": {
"category": "Error",
"code": 2462
},
@@ -1983,6 +1983,18 @@
"category": "Error",
"code": 2697
},
"Spread types may only be created from object types.": {
"category": "Error",
"code": 2698
},
"Rest types may only be created from object types.": {
"category": "Error",
"code": 2700
},
"An object rest element must be an identifier.": {
"category": "Error",
"code": 2701
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@@ -2381,6 +2393,10 @@
"category": "Error",
"code": 5066
},
"Invalid value for 'jsxFactory'. '{0}' is not a valid identifier or qualified-name.": {
"category": "Error",
"code": 5067
},
"Concatenate and emit output to single file.": {
"category": "Message",
"code": 6001
@@ -2897,6 +2913,10 @@
"category": "Message",
"code": 6145
},
"Specify the JSX factory function to use when targeting 'react' JSX emit, e.g. 'React.createElement' or 'h'.": {
"category": "Message",
"code": 6146
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
@@ -3158,5 +3178,13 @@
"Implement inherited abstract class": {
"category": "Message",
"code": 90007
},
"Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig": {
"category": "Error",
"code": 90009
},
"Type '{0}' is not assignable to type '{1}'. Two different types with this name exist, but they are unrelated.": {
"category": "Error",
"code": 90010
}
}
+30 -4
View File
@@ -42,6 +42,14 @@ var __assign = (this && this.__assign) || Object.assign || function(t) {
return t;
};`;
const restHelper = `
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && !e.indexOf(p))
t[p] = s[p];
return t;
};`;
// emit output for the __decorate helper function
const decorateHelper = `
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
@@ -226,6 +234,7 @@ const _super = (function (geti, seti) {
let currentFileIdentifiers: Map<string>;
let extendsEmitted: boolean;
let assignEmitted: boolean;
let restEmitted: boolean;
let decorateEmitted: boolean;
let paramEmitted: boolean;
let awaiterEmitted: boolean;
@@ -732,6 +741,8 @@ const _super = (function (geti, seti) {
return emitPropertyAssignment(<PropertyAssignment>node);
case SyntaxKind.ShorthandPropertyAssignment:
return emitShorthandPropertyAssignment(<ShorthandPropertyAssignment>node);
case SyntaxKind.SpreadAssignment:
return emitSpreadAssignment(node as SpreadAssignment);
// Enum
case SyntaxKind.EnumMember:
@@ -822,8 +833,8 @@ const _super = (function (geti, seti) {
return emitTemplateExpression(<TemplateExpression>node);
case SyntaxKind.YieldExpression:
return emitYieldExpression(<YieldExpression>node);
case SyntaxKind.SpreadElementExpression:
return emitSpreadElementExpression(<SpreadElementExpression>node);
case SyntaxKind.SpreadElement:
return emitSpreadExpression(<SpreadElement>node);
case SyntaxKind.ClassExpression:
return emitClassExpression(<ClassExpression>node);
case SyntaxKind.OmittedExpression:
@@ -1374,7 +1385,7 @@ const _super = (function (geti, seti) {
emitExpressionWithPrefix(" ", node.expression);
}
function emitSpreadElementExpression(node: SpreadElementExpression) {
function emitSpreadExpression(node: SpreadElement) {
write("...");
emitExpression(node.expression);
}
@@ -2102,6 +2113,13 @@ const _super = (function (geti, seti) {
}
}
function emitSpreadAssignment(node: SpreadAssignment) {
if (node.expression) {
write("...");
emitExpression(node.expression);
}
}
//
// Enum
//
@@ -2205,11 +2223,19 @@ const _super = (function (geti, seti) {
helpersEmitted = true;
}
if (compilerOptions.jsx !== JsxEmit.Preserve && !assignEmitted && (node.flags & NodeFlags.HasJsxSpreadAttributes)) {
if ((languageVersion < ScriptTarget.ESNext || currentSourceFile.scriptKind === ScriptKind.JSX || currentSourceFile.scriptKind === ScriptKind.TSX) &&
compilerOptions.jsx !== JsxEmit.Preserve &&
!assignEmitted &&
node.flags & NodeFlags.HasSpreadAttribute) {
writeLines(assignHelper);
assignEmitted = true;
}
if (languageVersion < ScriptTarget.ESNext && !restEmitted && node.flags & NodeFlags.HasRestAttribute) {
writeLines(restHelper);
restEmitted = true;
}
if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) {
writeLines(decorateHelper);
if (compilerOptions.emitDecoratorMetadata) {
+580 -9
View File
@@ -692,12 +692,12 @@ namespace ts {
}
export function createSpread(expression: Expression, location?: TextRange) {
const node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression, location);
const node = <SpreadElement>createNode(SyntaxKind.SpreadElement, location);
node.expression = parenthesizeExpressionForList(expression);
return node;
}
export function updateSpread(node: SpreadElementExpression, expression: Expression) {
export function updateSpread(node: SpreadElement, expression: Expression) {
if (node.expression !== expression) {
return updateNode(createSpread(expression, node), node);
}
@@ -1399,14 +1399,27 @@ namespace ts {
return node;
}
export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) {
export function createSpreadAssignment(expression: Expression, location?: TextRange) {
const node = <SpreadAssignment>createNode(SyntaxKind.SpreadAssignment, location);
node.expression = expression !== undefined ? parenthesizeExpressionForList(expression) : undefined;
return node;
}
export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression) {
if (node.name !== name || node.objectAssignmentInitializer !== objectAssignmentInitializer) {
return updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer, node), node);
}
return node;
}
// Top-level nodes
export function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) {
if (node.expression !== expression) {
return updateNode(createSpreadAssignment(expression, node), node);
}
return node;
}
// Top-level nodes
export function updateSourceFileNode(node: SourceFile, statements: Statement[]) {
if (node.statements !== statements) {
@@ -1628,7 +1641,34 @@ namespace ts {
return react;
}
export function createReactCreateElement(reactNamespace: string, tagName: Expression, props: Expression, children: Expression[], parentElement: JsxOpeningLikeElement, location: TextRange): LeftHandSideExpression {
function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement): Expression {
if (isQualifiedName(jsxFactory)) {
return createPropertyAccess(
createJsxFactoryExpressionFromEntityName(
jsxFactory.left,
parent
),
setEmitFlags(
getMutableClone(jsxFactory.right),
EmitFlags.NoSourceMap
)
);
}
else {
return createReactNamespace(jsxFactory.text, parent);
}
}
function createJsxFactoryExpression(jsxFactoryEntity: EntityName, reactNamespace: string, parent: JsxOpeningLikeElement): Expression {
return jsxFactoryEntity ?
createJsxFactoryExpressionFromEntityName(jsxFactoryEntity, parent) :
createPropertyAccess(
createReactNamespace(reactNamespace, parent),
"createElement"
);
}
export function createExpressionForJsxElement(jsxFactoryEntity: EntityName, reactNamespace: string, tagName: Expression, props: Expression, children: Expression[], parentElement: JsxOpeningLikeElement, location: TextRange): LeftHandSideExpression {
const argumentsList = [tagName];
if (props) {
argumentsList.push(props);
@@ -1651,10 +1691,7 @@ namespace ts {
}
return createCall(
createPropertyAccess(
createReactNamespace(reactNamespace, parentElement),
"createElement"
),
createJsxFactoryExpression(jsxFactoryEntity, reactNamespace, parentElement),
/*typeArguments*/ undefined,
argumentsList,
location
@@ -3055,4 +3092,538 @@ namespace ts {
function tryGetModuleNameFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration, host: EmitHost, resolver: EmitResolver, compilerOptions: CompilerOptions) {
return tryGetModuleNameFromFile(resolver.getExternalModuleFileFromDeclaration(declaration), host, compilerOptions);
}
/**
* Transforms the body of a function-like node.
*
* @param node A function-like node.
*/
export function transformFunctionBody(node: FunctionLikeDeclaration,
visitor: (node: Node) => VisitResult<Node>,
currentSourceFile: SourceFile,
context: TransformationContext,
enableSubstitutionsForCapturedThis: () => void,
convertObjectRest?: boolean) {
let multiLine = false; // indicates whether the block *must* be emitted as multiple lines
let singleLine = false; // indicates whether the block *may* be emitted as a single line
let statementsLocation: TextRange;
let closeBraceLocation: TextRange;
const statements: Statement[] = [];
const body = node.body;
let statementOffset: number;
context.startLexicalEnvironment();
if (isBlock(body)) {
// ensureUseStrict is false because no new prologue-directive should be added.
// addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array
statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
}
addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis);
addDefaultValueAssignmentsIfNeeded(statements, node, visitor, convertObjectRest);
addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false);
// If we added any generated statements, this must be a multi-line block.
if (!multiLine && statements.length > 0) {
multiLine = true;
}
if (isBlock(body)) {
statementsLocation = body.statements;
addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset));
// If the original body was a multi-line block, this must be a multi-line block.
if (!multiLine && body.multiLine) {
multiLine = true;
}
}
else {
Debug.assert(node.kind === SyntaxKind.ArrowFunction);
// To align with the old emitter, we use a synthetic end position on the location
// for the statement list we synthesize when we down-level an arrow function with
// an expression function body. This prevents both comments and source maps from
// being emitted for the end position only.
statementsLocation = moveRangeEnd(body, -1);
const equalsGreaterThanToken = (<ArrowFunction>node).equalsGreaterThanToken;
if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
singleLine = true;
}
else {
multiLine = true;
}
}
const expression = visitNode(body, visitor, isExpression);
const returnStatement = createReturn(expression, /*location*/ body);
setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments);
statements.push(returnStatement);
// To align with the source map emit for the old emitter, we set a custom
// source map location for the close brace.
closeBraceLocation = body;
}
const lexicalEnvironment = context.endLexicalEnvironment();
addRange(statements, lexicalEnvironment);
// If we added any final generated statements, this must be a multi-line block
if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) {
multiLine = true;
}
const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine);
if (!multiLine && singleLine) {
setEmitFlags(block, EmitFlags.SingleLine);
}
if (closeBraceLocation) {
setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation);
}
setOriginalNode(block, node.body);
return block;
}
/**
* Adds a statement to capture the `this` of a function declaration if it is needed.
*
* @param statements The statements for the new function body.
* @param node A node.
*/
export function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node, enableSubstitutionsForCapturedThis: () => void): void {
if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) {
captureThisForNode(statements, node, createThis(), enableSubstitutionsForCapturedThis);
}
}
export function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, enableSubstitutionsForCapturedThis?: () => void, originalStatement?: Statement): void {
enableSubstitutionsForCapturedThis();
const captureThisStatement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
"_this",
/*type*/ undefined,
initializer
)
]),
originalStatement
);
setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue);
setSourceMapRange(captureThisStatement, node);
statements.push(captureThisStatement);
}
/**
* Gets a value indicating whether we need to add default value assignments for a
* function-like node.
*
* @param node A function-like node.
*/
function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean {
return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0;
}
/**
* Adds statements to the body of a function-like node if it contains parameters with
* binding patterns or initializers.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
*/
export function addDefaultValueAssignmentsIfNeeded(statements: Statement[],
node: FunctionLikeDeclaration,
visitor: (node: Node) => VisitResult<Node>,
convertObjectRest: boolean): void {
if (!shouldAddDefaultValueAssignments(node)) {
return;
}
for (const parameter of node.parameters) {
const { name, initializer, dotDotDotToken } = parameter;
// A rest parameter cannot have a binding pattern or an initializer,
// so let's just ignore it.
if (dotDotDotToken) {
continue;
}
if (isBindingPattern(name)) {
addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer, visitor, convertObjectRest);
}
else if (initializer) {
addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer, visitor);
}
}
}
/**
* Adds statements to the body of a function-like node for parameters with binding patterns
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForBindingPattern(statements: Statement[],
parameter: ParameterDeclaration,
name: BindingPattern, initializer: Expression,
visitor: (node: Node) => VisitResult<Node>,
convertObjectRest: boolean): void {
const temp = getGeneratedNameForNode(parameter);
// In cases where a binding pattern is simply '[]' or '{}',
// we usually don't want to emit a var declaration; however, in the presence
// of an initializer, we must emit that expression to preserve side effects.
if (name.elements.length > 0) {
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
flattenParameterDestructuring(parameter, temp, visitor, convertObjectRest)
)
),
EmitFlags.CustomPrologue
)
);
}
else if (initializer) {
statements.push(
setEmitFlags(
createStatement(
createAssignment(
temp,
visitNode(initializer, visitor, isExpression)
)
),
EmitFlags.CustomPrologue
)
);
}
}
/**
* Adds statements to the body of a function-like node for parameters with initializers.
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForInitializer(statements: Statement[],
parameter: ParameterDeclaration,
name: Identifier,
initializer: Expression,
visitor: (node: Node) => VisitResult<Node>): void {
initializer = visitNode(initializer, visitor, isExpression);
const statement = createIf(
createStrictEquality(
getSynthesizedClone(name),
createVoidZero()
),
setEmitFlags(
createBlock([
createStatement(
createAssignment(
setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap),
setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)),
/*location*/ parameter
)
)
], /*location*/ parameter),
EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps
),
/*elseStatement*/ undefined,
/*location*/ parameter
);
statement.startsOnNewLine = true;
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue);
statements.push(statement);
}
/**
* Gets a value indicating whether we need to add statements to handle a rest parameter.
*
* @param node A ParameterDeclaration node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) {
return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper;
}
/**
* Adds statements to the body of a function-like node if it contains a rest parameter.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
export function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void {
const parameter = lastOrUndefined(node.parameters);
if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) {
return;
}
// `declarationName` is the name of the local declaration for the parameter.
const declarationName = getMutableClone(<Identifier>parameter.name);
setEmitFlags(declarationName, EmitFlags.NoSourceMap);
// `expressionName` is the name of the parameter used in expressions.
const expressionName = getSynthesizedClone(<Identifier>parameter.name);
const restIndex = node.parameters.length - 1;
const temp = createLoopVariable();
// var param = [];
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
declarationName,
/*type*/ undefined,
createArrayLiteral([])
)
]),
/*location*/ parameter
),
EmitFlags.CustomPrologue
)
);
// for (var _i = restIndex; _i < arguments.length; _i++) {
// param[_i - restIndex] = arguments[_i];
// }
const forStatement = createFor(
createVariableDeclarationList([
createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex))
], /*location*/ parameter),
createLessThan(
temp,
createPropertyAccess(createIdentifier("arguments"), "length"),
/*location*/ parameter
),
createPostfixIncrement(temp, /*location*/ parameter),
createBlock([
startOnNewLine(
createStatement(
createAssignment(
createElementAccess(
expressionName,
createSubtract(temp, createLiteral(restIndex))
),
createElementAccess(createIdentifier("arguments"), temp)
),
/*location*/ parameter
)
)
])
);
setEmitFlags(forStatement, EmitFlags.CustomPrologue);
startOnNewLine(forStatement);
statements.push(forStatement);
}
export function convertForOf(node: ForOfStatement, convertedLoopBodyStatements: Statement[],
visitor: (node: Node) => VisitResult<Node>,
enableSubstitutionsForBlockScopedBindings: () => void,
context: TransformationContext,
convertObjectRest?: boolean): ForStatement | ForOfStatement {
// The following ES6 code:
//
// for (let v of expr) { }
//
// should be emitted as
//
// for (var _i = 0, _a = expr; _i < _a.length; _i++) {
// var v = _a[_i];
// }
//
// where _a and _i are temps emitted to capture the RHS and the counter,
// respectively.
// When the left hand side is an expression instead of a let declaration,
// the "let v" is not emitted.
// When the left hand side is a let/const, the v is renamed if there is
// another v in scope.
// Note that all assignments to the LHS are emitted in the body, including
// all destructuring.
// Note also that because an extra statement is needed to assign to the LHS,
// for-of bodies are always emitted as blocks.
const expression = visitNode(node.expression, visitor, isExpression);
const initializer = node.initializer;
const statements: Statement[] = [];
// In the case where the user wrote an identifier as the RHS, like this:
//
// for (let v of arr) { }
//
// we don't want to emit a temporary variable for the RHS, just use it directly.
const counter = convertObjectRest ? undefined : createLoopVariable();
const rhsReference = expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>expression).text)
: createTempVariable(/*recordTempVariable*/ undefined);
const elementAccess = convertObjectRest ? rhsReference : createElementAccess(rhsReference, counter);
// Initialize LHS
// var v = _a[_i];
if (isVariableDeclarationList(initializer)) {
if (initializer.flags & NodeFlags.BlockScoped) {
enableSubstitutionsForBlockScopedBindings();
}
const firstOriginalDeclaration = firstOrUndefined(initializer.declarations);
if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) {
// This works whether the declaration is a var, let, or const.
// It will use rhsIterationValue _a[_i] as the initializer.
const declarations = flattenVariableDestructuring(
firstOriginalDeclaration,
elementAccess,
visitor,
/*recordTempVariable*/ undefined,
convertObjectRest
);
const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer);
setOriginalNode(declarationList, initializer);
// Adjust the source map range for the first declaration to align with the old
// emitter.
const firstDeclaration = declarations[0];
const lastDeclaration = lastOrUndefined(declarations);
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
declarationList
)
);
}
else {
// The following call does not include the initializer, so we have
// to emit it separately.
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
setOriginalNode(
createVariableDeclarationList([
createVariableDeclaration(
firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
/*type*/ undefined,
createElementAccess(rhsReference, counter)
)
], /*location*/ moveRangePos(initializer, -1)),
initializer
),
/*location*/ moveRangeEnd(initializer, -1)
)
);
}
}
else {
// Initializer is an expression. Emit the expression in the body, so that it's
// evaluated on every iteration.
const assignment = createAssignment(initializer, elementAccess);
if (isDestructuringAssignment(assignment)) {
// This is a destructuring pattern, so we flatten the destructuring instead.
statements.push(
createStatement(
flattenDestructuringAssignment(
context,
assignment,
/*needsValue*/ false,
context.hoistVariableDeclaration,
visitor,
convertObjectRest
)
)
);
}
else {
// Currently there is not way to check that assignment is binary expression of destructing assignment
// so we have to cast never type to binaryExpression
(<BinaryExpression>assignment).end = initializer.end;
statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1)));
}
}
let bodyLocation: TextRange;
let statementsLocation: TextRange;
if (convertedLoopBodyStatements) {
addRange(statements, convertedLoopBodyStatements);
}
else {
const statement = visitNode(node.statement, visitor, isStatement);
if (isBlock(statement)) {
addRange(statements, statement.statements);
bodyLocation = statement;
statementsLocation = statement.statements;
}
else {
statements.push(statement);
}
}
// The old emitter does not emit source maps for the expression
setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression));
// The old emitter does not emit source maps for the block.
// We add the location to preserve comments.
const body = createBlock(
createNodeArray(statements, /*location*/ statementsLocation),
/*location*/ bodyLocation
);
setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps);
let forStatement: ForStatement | ForOfStatement;
if (convertObjectRest) {
forStatement = createForOf(
createVariableDeclarationList([
createVariableDeclaration(rhsReference, /*type*/ undefined, /*initializer*/ undefined, /*location*/ node.expression)
], /*location*/ node.expression),
node.expression,
body,
/*location*/ node
);
}
else {
forStatement = createFor(
setEmitFlags(
createVariableDeclarationList([
createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)),
createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression)
], /*location*/ node.expression),
EmitFlags.NoHoisting
),
createLessThan(
counter,
createPropertyAccess(rhsReference, "length"),
/*location*/ node.expression
),
createPostfixIncrement(counter, /*location*/ node.expression),
body,
/*location*/ node
);
}
// Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps);
return forStatement;
}
}
+36 -5
View File
@@ -74,6 +74,8 @@ namespace ts {
visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
case SyntaxKind.SpreadAssignment:
return visitNode(cbNode, (<SpreadAssignment>node).expression);
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
@@ -197,8 +199,8 @@ namespace ts {
visitNode(cbNode, (<ConditionalExpression>node).whenTrue) ||
visitNode(cbNode, (<ConditionalExpression>node).colonToken) ||
visitNode(cbNode, (<ConditionalExpression>node).whenFalse);
case SyntaxKind.SpreadElementExpression:
return visitNode(cbNode, (<SpreadElementExpression>node).expression);
case SyntaxKind.SpreadElement:
return visitNode(cbNode, (<SpreadElement>node).expression);
case SyntaxKind.Block:
case SyntaxKind.ModuleBlock:
return visitNodes(cbNodes, (<Block>node).statements);
@@ -438,6 +440,10 @@ namespace ts {
return result;
}
export function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName {
return Parser.parseIsolatedEntityName(text, languageVersion);
}
export function isExternalModule(file: SourceFile): boolean {
return file.externalModuleIndicator !== undefined;
}
@@ -589,6 +595,16 @@ namespace ts {
return result;
}
export function parseIsolatedEntityName(content: string, languageVersion: ScriptTarget): EntityName {
initializeState(content, languageVersion, /*syntaxCursor*/ undefined, ScriptKind.JS);
// Prime the scanner.
nextToken();
const entityName = parseEntityName(/*allowReservedWords*/ true);
const isInvalid = token() === SyntaxKind.EndOfFileToken && !parseDiagnostics.length;
clearState();
return isInvalid ? entityName : undefined;
}
function getLanguageVariant(scriptKind: ScriptKind) {
// .tsx and .jsx files are treated as jsx language variant.
return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS ? LanguageVariant.JSX : LanguageVariant.Standard;
@@ -1269,9 +1285,11 @@ namespace ts {
// which would be a candidate for improved error reporting.
return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
case ParsingContext.ObjectLiteralMembers:
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || isLiteralPropertyName();
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
case ParsingContext.RestProperties:
return isLiteralPropertyName();
case ParsingContext.ObjectBindingElements:
return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || 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.
@@ -1398,6 +1416,7 @@ namespace ts {
case ParsingContext.ArrayBindingElements:
return token() === SyntaxKind.CloseBracketToken;
case ParsingContext.Parameters:
case ParsingContext.RestProperties:
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/;
case ParsingContext.TypeArguments:
@@ -1583,6 +1602,9 @@ namespace ts {
case ParsingContext.Parameters:
return isReusableParameter(node);
case ParsingContext.RestProperties:
return false;
// Any other lists we do not care about reusing nodes in. But feel free to add if
// you can do so safely. Danger areas involve nodes that may involve speculative
// parsing. If speculative parsing is involved with the node, then the range the
@@ -1780,6 +1802,7 @@ namespace ts {
case ParsingContext.BlockStatements: return Diagnostics.Declaration_or_statement_expected;
case ParsingContext.SwitchClauses: return Diagnostics.case_or_default_expected;
case ParsingContext.SwitchClauseStatements: return Diagnostics.Statement_expected;
case ParsingContext.RestProperties: // fallthrough
case ParsingContext.TypeMembers: return Diagnostics.Property_or_signature_expected;
case ParsingContext.ClassMembers: return Diagnostics.Unexpected_token_A_constructor_method_accessor_or_property_was_expected;
case ParsingContext.EnumMembers: return Diagnostics.Enum_member_expected;
@@ -4122,7 +4145,7 @@ namespace ts {
}
function parseSpreadElement(): Expression {
const node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression);
const node = <SpreadElement>createNode(SyntaxKind.SpreadElement);
parseExpected(SyntaxKind.DotDotDotToken);
node.expression = parseAssignmentExpressionOrHigher();
return finishNode(node);
@@ -4162,6 +4185,12 @@ namespace ts {
function parseObjectLiteralElement(): ObjectLiteralElementLike {
const fullStart = scanner.getStartPos();
const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
if (dotDotDotToken) {
const spreadElement = <SpreadAssignment>createNode(SyntaxKind.SpreadAssignment, fullStart);
spreadElement.expression = parseAssignmentExpressionOrHigher();
return addJSDocComment(finishNode(spreadElement));
}
const decorators = parseDecorators();
const modifiers = parseModifiers();
@@ -4865,6 +4894,7 @@ namespace ts {
function parseObjectBindingElement(): BindingElement {
const node = <BindingElement>createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
const tokenIsIdentifier = isIdentifier();
const propertyName = parsePropertyName();
if (tokenIsIdentifier && token() !== SyntaxKind.ColonToken) {
@@ -5809,6 +5839,7 @@ namespace ts {
JsxChildren, // Things between opening and closing JSX tags
ArrayLiteralMembers, // Members in array literal
Parameters, // Parameters in parameter list
RestProperties, // Property names in a rest type list
TypeParameters, // Type parameters in type parameter list
TypeArguments, // Type arguments in type argument list
TupleElementTypes, // Element types in tuple element type list
+184 -159
View File
@@ -5,7 +5,7 @@
namespace ts {
/** The version of the TypeScript compiler release */
export const version = "2.1.0";
export const version = "2.2.0";
const emptyArray: any[] = [];
@@ -239,11 +239,11 @@ namespace ts {
const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
const fileName = diagnostic.file.fileName;
const relativeFileName = convertToRelativePath(fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName));
output += `${ relativeFileName }(${ line + 1 },${ character + 1 }): `;
output += `${relativeFileName}(${line + 1},${character + 1}): `;
}
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()) }${ host.getNewLine() }`;
output += `${category} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`;
}
return output;
}
@@ -420,6 +420,7 @@ namespace ts {
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
getFileProcessingDiagnostics: () => fileProcessingDiagnostics,
getResolvedTypeReferenceDirectives: () => resolvedTypeReferenceDirectives,
isSourceFileFromExternalLibrary,
dropDiagnosticsProducingTypeChecker
};
@@ -449,10 +450,6 @@ namespace ts {
return commonSourceDirectory;
}
function isSourceFileFromExternalLibrary(file: SourceFile): boolean {
return !!sourceFilesFoundSearchingNodeModules[file.path];
}
function getClassifiableNames() {
if (!classifiableNames) {
// Initialize a checker so that all our files are bound.
@@ -480,7 +477,7 @@ namespace ts {
return resolveModuleNamesWorker(moduleNames, containingFile);
}
// at this point we know that either
// at this point we know that either
// - file has local declarations for ambient modules
// OR
// - old program state is available
@@ -674,7 +671,7 @@ namespace ts {
}
const modifiedFilePaths = modifiedSourceFiles.map(f => f.newFile.path);
// try to verify results of module resolution
// try to verify results of module resolution
for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) {
const newSourceFilePath = getNormalizedAbsolutePath(newSourceFile.fileName, currentDirectory);
if (resolveModuleNamesWorker) {
@@ -734,6 +731,10 @@ namespace ts {
};
}
function isSourceFileFromExternalLibrary(file: SourceFile): boolean {
return sourceFilesFoundSearchingNodeModules[file.path];
}
function getDiagnosticsProducingTypeChecker() {
return diagnosticsProducingTypeChecker || (diagnosticsProducingTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ true));
}
@@ -908,48 +909,24 @@ namespace ts {
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
return runWithCancellationToken(() => {
const diagnostics: Diagnostic[] = [];
let parent: Node = sourceFile;
walk(sourceFile);
return diagnostics;
function walk(node: Node): boolean {
if (!node) {
return false;
}
function walk(node: Node) {
// Return directly from the case if the given node doesnt want to visit each child
// Otherwise break to visit each child
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ExportAssignment:
if ((<ExportAssignment>node).isExportEquals) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file));
return true;
switch (parent.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
if ((<ParameterDeclaration | PropertyDeclaration>parent).questionToken === node) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics._0_can_only_be_used_in_a_ts_file, "?"));
return;
}
break;
case SyntaxKind.ClassDeclaration:
let classDeclaration = <ClassDeclaration>node;
if (checkModifiers(classDeclaration.modifiers) ||
checkTypeParameters(classDeclaration.typeParameters)) {
return true;
}
break;
case SyntaxKind.HeritageClause:
let heritageClause = <HeritageClause>node;
if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.InterfaceDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ModuleDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.TypeAliasDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file));
return true;
// Pass through
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
@@ -959,124 +936,151 @@ namespace ts {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
const functionDeclaration = <FunctionLikeDeclaration>node;
if (checkModifiers(functionDeclaration.modifiers) ||
checkTypeParameters(functionDeclaration.typeParameters) ||
checkTypeAnnotation(functionDeclaration.type)) {
return true;
}
break;
case SyntaxKind.VariableStatement:
const variableStatement = <VariableStatement>node;
if (checkModifiers(variableStatement.modifiers)) {
return true;
}
break;
case SyntaxKind.VariableDeclaration:
const variableDeclaration = <VariableDeclaration>node;
if (checkTypeAnnotation(variableDeclaration.type)) {
return true;
// type annotation
if ((<FunctionLikeDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration>parent).type === node) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.types_can_only_be_used_in_a_ts_file));
return;
}
}
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file));
return;
case SyntaxKind.ExportAssignment:
if ((<ExportAssignment>node).isExportEquals) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file));
return;
}
break;
case SyntaxKind.HeritageClause:
let heritageClause = <HeritageClause>node;
if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file));
return;
}
break;
case SyntaxKind.InterfaceDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file));
return;
case SyntaxKind.ModuleDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file));
return;
case SyntaxKind.TypeAliasDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file));
return;
case SyntaxKind.EnumDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
return;
case SyntaxKind.TypeAssertionExpression:
let typeAssertionExpression = <TypeAssertion>node;
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
return;
}
const prevParent = parent;
parent = node;
forEachChild(node, walk, walkArray);
parent = prevParent;
}
function walkArray(nodes: NodeArray<Node>) {
if (parent.decorators === nodes && !options.experimentalDecorators) {
diagnostics.push(createDiagnosticForNode(parent, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning));
}
switch (parent.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
// Check type parameters
if (nodes === (<ClassDeclaration | FunctionLikeDeclaration>parent).typeParameters) {
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
return;
}
// pass through
case SyntaxKind.VariableStatement:
// Check modifiers
if (nodes === (<ClassDeclaration | FunctionLikeDeclaration | VariableStatement>parent).modifiers) {
return checkModifiers(<NodeArray<Modifier>>nodes, parent.kind === SyntaxKind.VariableStatement);
}
break;
case SyntaxKind.PropertyDeclaration:
// Check modifiers of property declaration
if (nodes === (<PropertyDeclaration>parent).modifiers) {
for (const modifier of <NodeArray<Modifier>>nodes) {
if (modifier.kind !== SyntaxKind.StaticKeyword) {
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
}
}
return;
}
break;
case SyntaxKind.Parameter:
// Check modifiers of parameter declaration
if (nodes === (<ParameterDeclaration>parent).modifiers) {
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file));
return;
}
break;
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
const expression = <CallExpression>node;
if (expression.typeArguments && expression.typeArguments.length > 0) {
const start = expression.typeArguments.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start,
Diagnostics.type_arguments_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ExpressionWithTypeArguments:
// Check type arguments
if (nodes === (<CallExpression | NewExpression | ExpressionWithTypeArguments>parent).typeArguments) {
diagnostics.push(createDiagnosticForNodeArray(nodes, Diagnostics.type_arguments_can_only_be_used_in_a_ts_file));
return;
}
break;
case SyntaxKind.Parameter:
const parameter = <ParameterDeclaration>node;
if (parameter.modifiers) {
const start = parameter.modifiers.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start,
Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file));
return true;
}
if (parameter.questionToken) {
diagnostics.push(createDiagnosticForNode(parameter.questionToken, Diagnostics._0_can_only_be_used_in_a_ts_file, "?"));
return true;
}
if (parameter.type) {
diagnostics.push(createDiagnosticForNode(parameter.type, Diagnostics.types_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.PropertyDeclaration:
const propertyDeclaration = <PropertyDeclaration>node;
if (propertyDeclaration.modifiers) {
for (const modifier of propertyDeclaration.modifiers) {
if (modifier.kind !== SyntaxKind.StaticKeyword) {
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
return true;
}
}
for (const node of nodes) {
walk(node);
}
}
function checkModifiers(modifiers: NodeArray<Modifier>, isConstValid: boolean) {
for (const modifier of modifiers) {
switch (modifier.kind) {
case SyntaxKind.ConstKeyword:
if (isConstValid) {
continue;
}
}
if (checkTypeAnnotation((<PropertyDeclaration>node).type)) {
return true;
}
break;
case SyntaxKind.EnumDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.TypeAssertionExpression:
let typeAssertionExpression = <TypeAssertion>node;
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.Decorator:
if (!options.experimentalDecorators) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning));
}
return true;
}
// Fallthrough to report error
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.DeclareKeyword:
case SyntaxKind.AbstractKeyword:
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
break;
return forEachChild(node, walk);
}
function checkTypeParameters(typeParameters: NodeArray<TypeParameterDeclaration>): boolean {
if (typeParameters) {
const start = typeParameters.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, typeParameters.end - start, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
return true;
}
return false;
}
function checkTypeAnnotation(type: TypeNode): boolean {
if (type) {
diagnostics.push(createDiagnosticForNode(type, Diagnostics.types_can_only_be_used_in_a_ts_file));
return true;
}
return false;
}
function checkModifiers(modifiers: NodeArray<Modifier>): boolean {
if (modifiers) {
for (const modifier of modifiers) {
switch (modifier.kind) {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.DeclareKeyword:
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
return true;
// These are all legal modifiers.
case SyntaxKind.StaticKeyword:
case SyntaxKind.ExportKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.DefaultKeyword:
case SyntaxKind.AbstractKeyword:
}
// These are all legal modifiers.
case SyntaxKind.StaticKeyword:
case SyntaxKind.ExportKeyword:
case SyntaxKind.DefaultKeyword:
}
}
}
return false;
function createDiagnosticForNodeArray(nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
const start = nodes.pos;
return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2);
}
// Since these are syntactic diagnostics, parent might not have been set
// this means the sourceFile cannot be infered from the node
function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
}
});
}
@@ -1140,9 +1144,14 @@ namespace ts {
if (options.importHelpers
&& (options.isolatedModules || isExternalModuleFile)
&& !file.isDeclarationFile) {
const externalHelpersModuleReference = <StringLiteral>createNode(SyntaxKind.StringLiteral);
// synthesize 'import "tslib"' declaration
const externalHelpersModuleReference = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
externalHelpersModuleReference.text = externalHelpersModuleNameText;
externalHelpersModuleReference.parent = file;
const importDecl = createSynthesizedNode(SyntaxKind.ImportDeclaration);
importDecl.parent = file;
externalHelpersModuleReference.parent = importDecl;
imports = [externalHelpersModuleReference];
}
@@ -1439,7 +1448,9 @@ namespace ts {
collectExternalModuleReferences(file);
if (file.imports.length || file.moduleAugmentations.length) {
file.resolvedModules = createMap<ResolvedModuleFull>();
const moduleNames = map(concatenate(file.imports, file.moduleAugmentations), getTextOfLiteral);
// Because global augmentation doesn't have string literal name, we can check for global augmentation as such.
const nonGlobalAugmentation = filter(file.moduleAugmentations, (moduleAugmentation) => moduleAugmentation.kind === SyntaxKind.StringLiteral);
const moduleNames = map(concatenate(file.imports, nonGlobalAugmentation), getTextOfLiteral);
const resolutions = resolveModuleNamesReusingOldState(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory), file);
Debug.assert(resolutions.length === moduleNames.length);
for (let i = 0; i < moduleNames.length; i++) {
@@ -1670,7 +1681,15 @@ namespace ts {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators"));
}
if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) {
if (options.jsxFactory) {
if (options.reactNamespace) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory"));
}
if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory));
}
}
else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace));
}
@@ -1690,13 +1709,19 @@ namespace ts {
const emitFilePath = toPath(emitFileName, currentDirectory, getCanonicalFileName);
// Report error if the output overwrites input file
if (filesByName.contains(emitFilePath)) {
createEmitBlockingDiagnostics(emitFileName, Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file);
let chain: DiagnosticMessageChain;
if (!options.configFilePath) {
// The program is from either an inferred project or an external project
chain = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript_files_Learn_more_at_https_Colon_Slash_Slashaka_ms_Slashtsconfig);
}
chain = chainDiagnosticMessages(chain, Diagnostics.Cannot_write_file_0_because_it_would_overwrite_input_file, emitFileName);
blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain));
}
// Report error if multiple files write into same file
if (emitFilesSeen.contains(emitFilePath)) {
// Already seen the same emit file - report error
createEmitBlockingDiagnostics(emitFileName, Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files);
blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName));
}
else {
emitFilesSeen.set(emitFilePath, true);
@@ -1705,9 +1730,9 @@ namespace ts {
}
}
function createEmitBlockingDiagnostics(emitFileName: string, message: DiagnosticMessage) {
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
hasEmitBlockingDiagnostics.set(toPath(emitFileName, currentDirectory, getCanonicalFileName), true);
programDiagnostics.add(createCompilerDiagnostic(message, emitFileName));
programDiagnostics.add(diag);
}
}
+9 -4
View File
@@ -17,7 +17,11 @@ namespace ts {
readFile(path: string, encoding?: string): string;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
/**
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
* use native OS file watching
*/
watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
resolvePath(path: string): string;
fileExists(path: string): boolean;
@@ -439,6 +443,7 @@ namespace ts {
return filter<string>(_fs.readdirSync(path), dir => fileSystemEntryExists(combinePaths(path, dir), FileSystemEntryKind.Directory));
}
const noOpFileWatcher: FileWatcher = { close: noop };
const nodeSystem: System = {
args: process.argv.slice(2),
newLine: _os.EOL,
@@ -448,7 +453,7 @@ namespace ts {
},
readFile,
writeFile,
watchFile: (fileName, callback) => {
watchFile: (fileName, callback, pollingInterval) => {
if (useNonPollingWatchers) {
const watchedFile = watchedFileSet.addFile(fileName, callback);
return {
@@ -456,7 +461,7 @@ namespace ts {
};
}
else {
_fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged);
_fs.watchFile(fileName, { persistent: true, interval: pollingInterval || 250 }, fileChanged);
return {
close: () => _fs.unwatchFile(fileName, fileChanged)
};
@@ -475,7 +480,7 @@ namespace ts {
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
let options: any;
if (!directoryExists(directoryName)) {
return;
return noOpFileWatcher;
}
if (isNode4OrLater() && (process.platform === "win32" || process.platform === "darwin")) {
+5
View File
@@ -1,6 +1,7 @@
/// <reference path="visitor.ts" />
/// <reference path="transformers/ts.ts" />
/// <reference path="transformers/jsx.ts" />
/// <reference path="transformers/esnext.ts" />
/// <reference path="transformers/es2017.ts" />
/// <reference path="transformers/es2016.ts" />
/// <reference path="transformers/es2015.ts" />
@@ -116,6 +117,10 @@ namespace ts {
transformers.push(transformJsx);
}
if (languageVersion < ScriptTarget.ESNext) {
transformers.push(transformESNext);
}
if (languageVersion < ScriptTarget.ES2017) {
transformers.push(transformES2017);
}
+235 -44
View File
@@ -17,7 +17,8 @@ namespace ts {
node: BinaryExpression,
needsValue: boolean,
recordTempVariable: (node: Identifier) => void,
visitor?: (node: Node) => VisitResult<Node>): Expression {
visitor?: (node: Node) => VisitResult<Node>,
transformRest?: boolean): Expression {
if (isEmptyObjectLiteralOrArrayLiteral(node.left)) {
const right = node.right;
@@ -51,7 +52,7 @@ namespace ts {
location = value;
}
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
if (needsValue) {
expressions.push(value);
@@ -61,7 +62,7 @@ namespace ts {
aggregateTransformFlags(expression);
return expression;
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange) {
const expression = createAssignment(name, value, location);
// NOTE: this completely disables source maps, but aligns with the behavior of
@@ -77,6 +78,10 @@ namespace ts {
emitAssignment(name, value, location);
return name;
}
function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange) {
emitAssignment(createObjectLiteral(elements), value, location);
}
}
/**
@@ -89,14 +94,15 @@ namespace ts {
export function flattenParameterDestructuring(
node: ParameterDeclaration,
value: Expression,
visitor?: (node: Node) => VisitResult<Node>) {
visitor?: (node: Node) => VisitResult<Node>,
transformRest?: boolean) {
const declarations: VariableDeclaration[] = [];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, transformRest, visitor);
return declarations;
function emitAssignment(name: Identifier, value: Expression, location: TextRange) {
function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange) {
const declaration = createVariableDeclaration(name, /*type*/ undefined, value, location);
// NOTE: this completely disables source maps, but aligns with the behavior of
@@ -112,6 +118,10 @@ namespace ts {
emitAssignment(name, value, location);
return name;
}
function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange) {
emitAssignment(createObjectBindingPattern(elements), value, location);
}
}
/**
@@ -125,15 +135,16 @@ namespace ts {
node: VariableDeclaration,
value?: Expression,
visitor?: (node: Node) => VisitResult<Node>,
recordTempVariable?: (node: Identifier) => void) {
recordTempVariable?: (node: Identifier) => void,
transformRest?: boolean) {
const declarations: VariableDeclaration[] = [];
let pendingAssignments: Expression[];
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, recordTempVariable, emitRestAssignment, transformRest, visitor);
return declarations;
function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) {
function emitAssignment(name: Identifier | BindingPattern, value: Expression, location: TextRange, original: Node) {
if (pendingAssignments) {
pendingAssignments.push(value);
value = inlineExpressions(pendingAssignments);
@@ -167,6 +178,10 @@ namespace ts {
}
return name;
}
function emitRestAssignment(elements: BindingElement[], value: Expression, location: TextRange, original: Node) {
emitAssignment(createObjectBindingPattern(elements), value, location, original);
}
}
/**
@@ -186,15 +201,17 @@ namespace ts {
const pendingAssignments: Expression[] = [];
flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, visitor);
flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment, noop, emitRestAssignment, /*transformRest*/ false, visitor);
const expression = inlineExpressions(pendingAssignments);
aggregateTransformFlags(expression);
return expression;
function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) {
function emitAssignment(name: Identifier | ObjectLiteralExpression, value: Expression, location: TextRange, original: Node) {
const expression = createAssignmentCallback
? createAssignmentCallback(name, value, location)
? createAssignmentCallback(name.kind === SyntaxKind.Identifier ? name : emitTempVariableAssignment(name, location),
value,
location)
: createAssignment(name, value, location);
emitPendingAssignment(expression, original);
@@ -206,6 +223,10 @@ namespace ts {
return name;
}
function emitRestAssignment(elements: ObjectLiteralElementLike[], value: Expression, location: TextRange, original: Node) {
emitAssignment(createObjectLiteral(elements), value, location, original);
}
function emitPendingAssignment(expression: Expression, original: Node) {
expression.original = original;
@@ -223,6 +244,9 @@ namespace ts {
location: TextRange,
emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void,
emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier,
recordTempVariable: (node: Identifier) => void,
emitRestAssignment: (elements: (ObjectLiteralElementLike[] | BindingElement[]), value: Expression, location: TextRange, original: Node) => void,
transformRest: boolean,
visitor?: (node: Node) => VisitResult<Node>) {
if (value && visitor) {
value = visitNode(value, visitor, isExpression);
@@ -284,23 +308,92 @@ namespace ts {
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
}
for (const p of properties) {
let bindingElements: ObjectLiteralElementLike[] = [];
for (let i = 0; i < properties.length; i++) {
const p = properties[i];
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
const target = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>p).initializer || propName;
// Assignment for target = value.propName should highligh whole property, hence use p as source map node
emitDestructuringAssignment(target, createDestructuringPropertyAccess(value, propName), p);
if (!transformRest ||
p.transformFlags & TransformFlags.ContainsSpreadExpression ||
(p.kind === SyntaxKind.PropertyAssignment && p.initializer.transformFlags & TransformFlags.ContainsSpreadExpression)) {
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, location, target);
bindingElements = [];
}
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
const bindingTarget = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>p).initializer || propName;
// Assignment for bindingTarget = value.propName should highlight whole property, hence use p as source map node
emitDestructuringAssignment(bindingTarget, createDestructuringPropertyAccess(value, propName), p);
}
else {
bindingElements.push(p);
}
}
else if (i === properties.length - 1 &&
p.kind === SyntaxKind.SpreadAssignment &&
p.expression.kind === SyntaxKind.Identifier) {
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, location, target);
bindingElements = [];
}
const propName = (p as SpreadAssignment).expression as Identifier;
const restCall = createRestCall(value, target.properties, p => p.name, target);
emitDestructuringAssignment(propName, restCall, p);
}
}
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, location, target);
bindingElements = [];
}
}
function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
if (transformRest) {
emitESNextArrayLiteralAssignment(target, value, location);
}
else {
emitES2015ArrayLiteralAssignment(target, value, location);
}
}
function emitESNextArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
const elements = target.elements;
const numElements = elements.length;
if (numElements !== 1) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
// When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
// When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
}
const expressions: Expression[] = [];
const spreadContainingExpressions: [Expression, Identifier][] = [];
for (let i = 0; i < numElements; i++) {
const e = elements[i];
if (e.kind === SyntaxKind.OmittedExpression) {
continue;
}
if (e.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) {
const tmp = createTempVariable(recordTempVariable);
spreadContainingExpressions.push([e, tmp]);
expressions.push(tmp);
}
else {
expressions.push(e);
}
}
emitAssignment(updateArrayLiteral(target, expressions) as any as Identifier, value, undefined, undefined);
for (const [e, tmp] of spreadContainingExpressions) {
emitDestructuringAssignment(e, tmp, e);
}
}
function emitES2015ArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) {
const elements = target.elements;
const numElements = elements.length;
if (numElements !== 1) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
// When doing so we want to highlight the passed-in source map node since thats the one needing this temp assignment
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment);
}
@@ -308,20 +401,41 @@ namespace ts {
const e = elements[i];
if (e.kind !== SyntaxKind.OmittedExpression) {
// Assignment for target = value.propName should highligh whole property, hence use e as source map node
if (e.kind !== SyntaxKind.SpreadElementExpression) {
if (e.kind !== SyntaxKind.SpreadElement) {
emitDestructuringAssignment(e, createElementAccess(value, createLiteral(i)), e);
}
else if (i === numElements - 1) {
emitDestructuringAssignment((<SpreadElementExpression>e).expression, createArraySlice(value, i), e);
emitDestructuringAssignment((<SpreadElement>e).expression, createArraySlice(value, i), e);
}
}
}
}
/** Given value: o, propName: p, pattern: { a, b, ...p } from the original statement
* `{ a, b, ...p } = o`, create `p = __rest(o, ["a", "b"]);`*/
function createRestCall<T extends Node>(value: Expression, elements: T[], getPropertyName: (element: T) => PropertyName, location: TextRange): Expression {
const propertyNames: LiteralExpression[] = [];
for (let i = 0; i < elements.length - 1; i++) {
if (isOmittedExpression(elements[i])) {
continue;
}
const str = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
str.pos = location.pos;
str.end = location.end;
str.text = getTextOfPropertyName(getPropertyName(elements[i]));
propertyNames.push(str);
}
const args = createSynthesizedNodeArray([value, createArrayLiteral(propertyNames, location)]);
return createCall(createIdentifier("__rest"), undefined, args);
}
function emitBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) {
// Any temporary assignments needed to emit target = value should point to target
const initializer = visitor ? visitNode(target.initializer, visitor, isExpression) : target.initializer;
if (initializer) {
if (transformRest) {
value = value || initializer;
}
else if (initializer) {
// Combine value and initializer
value = value ? createDefaultValueCheck(value, initializer, target) : initializer;
}
@@ -331,9 +445,11 @@ namespace ts {
}
const name = target.name;
if (isBindingPattern(name)) {
const elements = name.elements;
const numElements = elements.length;
if (!isBindingPattern(name)) {
emitAssignment(name, value, target, target);
}
else {
const numElements = name.elements.length;
if (numElements !== 1) {
// For anything other than a single-element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
@@ -341,29 +457,104 @@ namespace ts {
// so in that case, we'll intentionally create that temporary.
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment);
}
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
else if (name.kind === SyntaxKind.ObjectBindingPattern) {
// Rewrite element to a declaration with an initializer that fetches property
const propName = element.propertyName || <Identifier>element.name;
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
}
else {
if (!element.dotDotDotToken) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, i));
}
else if (i === numElements - 1) {
emitBindingElement(element, createArraySlice(value, i));
}
}
if (name.kind === SyntaxKind.ArrayBindingPattern) {
emitArrayBindingElement(name as ArrayBindingPattern, value);
}
else {
emitObjectBindingElement(target, value);
}
}
}
function emitArrayBindingElement(name: ArrayBindingPattern, value: Expression) {
if (transformRest) {
emitESNextArrayBindingElement(name, value);
}
else {
emitAssignment(name, value, target, target);
emitES2015ArrayBindingElement(name, value);
}
}
function emitES2015ArrayBindingElement(name: ArrayBindingPattern, value: Expression) {
const elements = name.elements;
const numElements = elements.length;
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
if (!element.dotDotDotToken) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, i));
}
else if (i === numElements - 1) {
emitBindingElement(element, createArraySlice(value, i));
}
}
}
function emitESNextArrayBindingElement(name: ArrayBindingPattern, value: Expression) {
const elements = name.elements;
const numElements = elements.length;
const bindingElements: BindingElement[] = [];
const spreadContainingElements: BindingElement[] = [];
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
if (element.transformFlags & TransformFlags.ContainsSpreadExpression && i < numElements - 1) {
spreadContainingElements.push(element);
bindingElements.push(createBindingElement(undefined, undefined, getGeneratedNameForNode(element), undefined, value));
}
else {
bindingElements.push(element);
}
}
emitAssignment(updateArrayBindingPattern(name, bindingElements) as any as Identifier, value, undefined, undefined);
for (const element of spreadContainingElements) {
emitBindingElement(element, getGeneratedNameForNode(element));
}
}
function emitObjectBindingElement(target: VariableDeclaration | ParameterDeclaration | BindingElement, value: Expression) {
const name = target.name as BindingPattern;
const elements = name.elements;
const numElements = elements.length;
let bindingElements: BindingElement[] = [];
for (let i = 0; i < numElements; i++) {
const element = elements[i];
if (isOmittedExpression(element)) {
continue;
}
if (i === numElements - 1 && element.dotDotDotToken) {
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, target, target);
bindingElements = [];
}
const restCall = createRestCall(value,
name.elements,
element => (element as BindingElement).propertyName || <Identifier>(element as BindingElement).name,
name);
emitBindingElement(element, restCall);
}
else if (transformRest && !(element.transformFlags & TransformFlags.ContainsSpreadExpression)) {
// do not emit until we have a complete bundle of ES2015 syntax
bindingElements.push(element);
}
else {
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, target, target);
bindingElements = [];
}
// Rewrite element to a declaration with an initializer that fetches property
const propName = element.propertyName || <Identifier>element.name;
emitBindingElement(element, createDestructuringPropertyAccess(value, propName));
}
}
if (bindingElements.length) {
emitRestAssignment(bindingElements, value, target, target);
bindingElements = [];
}
}
+24 -514
View File
@@ -861,7 +861,7 @@ namespace ts {
}
if (constructor) {
addDefaultValueAssignmentsIfNeeded(statements, constructor);
addDefaultValueAssignmentsIfNeeded(statements, constructor, visitor, /*convertObjectRest*/ false);
addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper);
Debug.assert(statementOffset >= 0, "statementOffset not initialized correctly!");
@@ -954,7 +954,7 @@ namespace ts {
// If this isn't a derived class, just capture 'this' for arrow functions if necessary.
if (!hasExtendsClause) {
if (ctor) {
addCaptureThisForNodeIfNeeded(statements, ctor);
addCaptureThisForNodeIfNeeded(statements, ctor, enableSubstitutionsForCapturedThis);
}
return SuperCaptureResult.NoReplacement;
}
@@ -1016,7 +1016,7 @@ namespace ts {
}
// Perform the capture.
captureThisForNode(statements, ctor, superCallExpression, firstStatement);
captureThisForNode(statements, ctor, superCallExpression, enableSubstitutionsForCapturedThis, firstStatement);
// If we're actually replacing the original statement, we need to signal this to the caller.
if (superCallExpression) {
@@ -1085,242 +1085,6 @@ namespace ts {
}
}
/**
* Gets a value indicating whether we need to add default value assignments for a
* function-like node.
*
* @param node A function-like node.
*/
function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean {
return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0;
}
/**
* Adds statements to the body of a function-like node if it contains parameters with
* binding patterns or initializers.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
*/
function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): void {
if (!shouldAddDefaultValueAssignments(node)) {
return;
}
for (const parameter of node.parameters) {
const { name, initializer, dotDotDotToken } = parameter;
// A rest parameter cannot have a binding pattern or an initializer,
// so let's just ignore it.
if (dotDotDotToken) {
continue;
}
if (isBindingPattern(name)) {
addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer);
}
else if (initializer) {
addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer);
}
}
}
/**
* Adds statements to the body of a function-like node for parameters with binding patterns
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression): void {
const temp = getGeneratedNameForNode(parameter);
// In cases where a binding pattern is simply '[]' or '{}',
// we usually don't want to emit a var declaration; however, in the presence
// of an initializer, we must emit that expression to preserve side effects.
if (name.elements.length > 0) {
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
flattenParameterDestructuring(parameter, temp, visitor)
)
),
EmitFlags.CustomPrologue
)
);
}
else if (initializer) {
statements.push(
setEmitFlags(
createStatement(
createAssignment(
temp,
visitNode(initializer, visitor, isExpression)
)
),
EmitFlags.CustomPrologue
)
);
}
}
/**
* Adds statements to the body of a function-like node for parameters with initializers.
*
* @param statements The statements for the new function body.
* @param parameter The parameter for the function.
* @param name The name of the parameter.
* @param initializer The initializer for the parameter.
*/
function addDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void {
initializer = visitNode(initializer, visitor, isExpression);
const statement = createIf(
createStrictEquality(
getSynthesizedClone(name),
createVoidZero()
),
setEmitFlags(
createBlock([
createStatement(
createAssignment(
setEmitFlags(getMutableClone(name), EmitFlags.NoSourceMap),
setEmitFlags(initializer, EmitFlags.NoSourceMap | getEmitFlags(initializer)),
/*location*/ parameter
)
)
], /*location*/ parameter),
EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps
),
/*elseStatement*/ undefined,
/*location*/ parameter
);
statement.startsOnNewLine = true;
setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue);
statements.push(statement);
}
/**
* Gets a value indicating whether we need to add statements to handle a rest parameter.
*
* @param node A ParameterDeclaration node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) {
return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper;
}
/**
* Adds statements to the body of a function-like node if it contains a rest parameter.
*
* @param statements The statements for the new function body.
* @param node A function-like node.
* @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is
* part of a constructor declaration with a
* synthesized call to `super`
*/
function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void {
const parameter = lastOrUndefined(node.parameters);
if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) {
return;
}
// `declarationName` is the name of the local declaration for the parameter.
const declarationName = getMutableClone(<Identifier>parameter.name);
setEmitFlags(declarationName, EmitFlags.NoSourceMap);
// `expressionName` is the name of the parameter used in expressions.
const expressionName = getSynthesizedClone(<Identifier>parameter.name);
const restIndex = node.parameters.length - 1;
const temp = createLoopVariable();
// var param = [];
statements.push(
setEmitFlags(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
declarationName,
/*type*/ undefined,
createArrayLiteral([])
)
]),
/*location*/ parameter
),
EmitFlags.CustomPrologue
)
);
// for (var _i = restIndex; _i < arguments.length; _i++) {
// param[_i - restIndex] = arguments[_i];
// }
const forStatement = createFor(
createVariableDeclarationList([
createVariableDeclaration(temp, /*type*/ undefined, createLiteral(restIndex))
], /*location*/ parameter),
createLessThan(
temp,
createPropertyAccess(createIdentifier("arguments"), "length"),
/*location*/ parameter
),
createPostfixIncrement(temp, /*location*/ parameter),
createBlock([
startOnNewLine(
createStatement(
createAssignment(
createElementAccess(
expressionName,
createSubtract(temp, createLiteral(restIndex))
),
createElementAccess(createIdentifier("arguments"), temp)
),
/*location*/ parameter
)
)
])
);
setEmitFlags(forStatement, EmitFlags.CustomPrologue);
startOnNewLine(forStatement);
statements.push(forStatement);
}
/**
* Adds a statement to capture the `this` of a function declaration if it is needed.
*
* @param statements The statements for the new function body.
* @param node A node.
*/
function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node): void {
if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) {
captureThisForNode(statements, node, createThis());
}
}
function captureThisForNode(statements: Statement[], node: Node, initializer: Expression | undefined, originalStatement?: Statement): void {
enableSubstitutionsForCapturedThis();
const captureThisStatement = createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
"_this",
/*type*/ undefined,
initializer
)
]),
originalStatement
);
setEmitFlags(captureThisStatement, EmitFlags.NoComments | EmitFlags.CustomPrologue);
setSourceMapRange(captureThisStatement, node);
statements.push(captureThisStatement);
}
/**
* Adds statements to the class body function for a class to define the members of the
* class.
@@ -1518,7 +1282,7 @@ namespace ts {
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
transformFunctionBody(node),
transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis),
/*location*/ node
),
/*original*/ node);
@@ -1545,7 +1309,7 @@ namespace ts {
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
saveStateAndInvoke(node, transformFunctionBody),
saveStateAndInvoke(node, node => transformFunctionBody(node, visitor, currentSourceFile, context, enableSubstitutionsForCapturedThis)),
location
),
/*original*/ node
@@ -1555,96 +1319,6 @@ namespace ts {
return expression;
}
/**
* Transforms the body of a function-like node.
*
* @param node A function-like node.
*/
function transformFunctionBody(node: FunctionLikeDeclaration) {
let multiLine = false; // indicates whether the block *must* be emitted as multiple lines
let singleLine = false; // indicates whether the block *may* be emitted as a single line
let statementsLocation: TextRange;
let closeBraceLocation: TextRange;
const statements: Statement[] = [];
const body = node.body;
let statementOffset: number;
startLexicalEnvironment();
if (isBlock(body)) {
// ensureUseStrict is false because no new prologue-directive should be added.
// addPrologueDirectives will simply put already-existing directives at the beginning of the target statement-array
statementOffset = addPrologueDirectives(statements, body.statements, /*ensureUseStrict*/ false, visitor);
}
addCaptureThisForNodeIfNeeded(statements, node);
addDefaultValueAssignmentsIfNeeded(statements, node);
addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false);
// If we added any generated statements, this must be a multi-line block.
if (!multiLine && statements.length > 0) {
multiLine = true;
}
if (isBlock(body)) {
statementsLocation = body.statements;
addRange(statements, visitNodes(body.statements, visitor, isStatement, statementOffset));
// If the original body was a multi-line block, this must be a multi-line block.
if (!multiLine && body.multiLine) {
multiLine = true;
}
}
else {
Debug.assert(node.kind === SyntaxKind.ArrowFunction);
// To align with the old emitter, we use a synthetic end position on the location
// for the statement list we synthesize when we down-level an arrow function with
// an expression function body. This prevents both comments and source maps from
// being emitted for the end position only.
statementsLocation = moveRangeEnd(body, -1);
const equalsGreaterThanToken = (<ArrowFunction>node).equalsGreaterThanToken;
if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
singleLine = true;
}
else {
multiLine = true;
}
}
const expression = visitNode(body, visitor, isExpression);
const returnStatement = createReturn(expression, /*location*/ body);
setEmitFlags(returnStatement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTrailingComments);
statements.push(returnStatement);
// To align with the source map emit for the old emitter, we set a custom
// source map location for the close brace.
closeBraceLocation = body;
}
const lexicalEnvironment = endLexicalEnvironment();
addRange(statements, lexicalEnvironment);
// If we added any final generated statements, this must be a multi-line block
if (!multiLine && lexicalEnvironment && lexicalEnvironment.length) {
multiLine = true;
}
const block = createBlock(createNodeArray(statements, statementsLocation), node.body, multiLine);
if (!multiLine && singleLine) {
setEmitFlags(block, EmitFlags.SingleLine);
}
if (closeBraceLocation) {
setTokenSourceMapRange(block, SyntaxKind.CloseBraceToken, closeBraceLocation);
}
setOriginalNode(block, node.body);
return block;
}
/**
* Visits an ExpressionStatement that contains a destructuring assignment.
*
@@ -1926,171 +1600,7 @@ namespace ts {
}
function convertForOfToFor(node: ForOfStatement, convertedLoopBodyStatements: Statement[]): ForStatement {
// The following ES6 code:
//
// for (let v of expr) { }
//
// should be emitted as
//
// for (var _i = 0, _a = expr; _i < _a.length; _i++) {
// var v = _a[_i];
// }
//
// where _a and _i are temps emitted to capture the RHS and the counter,
// respectively.
// When the left hand side is an expression instead of a let declaration,
// the "let v" is not emitted.
// When the left hand side is a let/const, the v is renamed if there is
// another v in scope.
// Note that all assignments to the LHS are emitted in the body, including
// all destructuring.
// Note also that because an extra statement is needed to assign to the LHS,
// for-of bodies are always emitted as blocks.
const expression = visitNode(node.expression, visitor, isExpression);
const initializer = node.initializer;
const statements: Statement[] = [];
// In the case where the user wrote an identifier as the RHS, like this:
//
// for (let v of arr) { }
//
// we don't want to emit a temporary variable for the RHS, just use it directly.
const counter = createLoopVariable();
const rhsReference = expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>expression).text)
: createTempVariable(/*recordTempVariable*/ undefined);
// Initialize LHS
// var v = _a[_i];
if (isVariableDeclarationList(initializer)) {
if (initializer.flags & NodeFlags.BlockScoped) {
enableSubstitutionsForBlockScopedBindings();
}
const firstOriginalDeclaration = firstOrUndefined(initializer.declarations);
if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) {
// This works whether the declaration is a var, let, or const.
// It will use rhsIterationValue _a[_i] as the initializer.
const declarations = flattenVariableDestructuring(
firstOriginalDeclaration,
createElementAccess(rhsReference, counter),
visitor
);
const declarationList = createVariableDeclarationList(declarations, /*location*/ initializer);
setOriginalNode(declarationList, initializer);
// Adjust the source map range for the first declaration to align with the old
// emitter.
const firstDeclaration = declarations[0];
const lastDeclaration = lastOrUndefined(declarations);
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
declarationList
)
);
}
else {
// The following call does not include the initializer, so we have
// to emit it separately.
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
setOriginalNode(
createVariableDeclarationList([
createVariableDeclaration(
firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
/*type*/ undefined,
createElementAccess(rhsReference, counter)
)
], /*location*/ moveRangePos(initializer, -1)),
initializer
),
/*location*/ moveRangeEnd(initializer, -1)
)
);
}
}
else {
// Initializer is an expression. Emit the expression in the body, so that it's
// evaluated on every iteration.
const assignment = createAssignment(initializer, createElementAccess(rhsReference, counter));
if (isDestructuringAssignment(assignment)) {
// This is a destructuring pattern, so we flatten the destructuring instead.
statements.push(
createStatement(
flattenDestructuringAssignment(
context,
assignment,
/*needsValue*/ false,
hoistVariableDeclaration,
visitor
)
)
);
}
else {
// Currently there is not way to check that assignment is binary expression of destructing assignment
// so we have to cast never type to binaryExpression
(<BinaryExpression>assignment).end = initializer.end;
statements.push(createStatement(assignment, /*location*/ moveRangeEnd(initializer, -1)));
}
}
let bodyLocation: TextRange;
let statementsLocation: TextRange;
if (convertedLoopBodyStatements) {
addRange(statements, convertedLoopBodyStatements);
}
else {
const statement = visitNode(node.statement, visitor, isStatement);
if (isBlock(statement)) {
addRange(statements, statement.statements);
bodyLocation = statement;
statementsLocation = statement.statements;
}
else {
statements.push(statement);
}
}
// The old emitter does not emit source maps for the expression
setEmitFlags(expression, EmitFlags.NoSourceMap | getEmitFlags(expression));
// The old emitter does not emit source maps for the block.
// We add the location to preserve comments.
const body = createBlock(
createNodeArray(statements, /*location*/ statementsLocation),
/*location*/ bodyLocation
);
setEmitFlags(body, EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps);
const forStatement = createFor(
setEmitFlags(
createVariableDeclarationList([
createVariableDeclaration(counter, /*type*/ undefined, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)),
createVariableDeclaration(rhsReference, /*type*/ undefined, expression, /*location*/ node.expression)
], /*location*/ node.expression),
EmitFlags.NoHoisting
),
createLessThan(
counter,
createPropertyAccess(rhsReference, "length"),
/*location*/ node.expression
),
createPostfixIncrement(counter, /*location*/ node.expression),
body,
/*location*/ node
);
// Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter.
setEmitFlags(forStatement, EmitFlags.NoTokenTrailingSourceMaps);
return forStatement;
return <ForStatement>convertForOf(node, convertedLoopBodyStatements, visitor, enableSubstitutionsForBlockScopedBindings, context, /*transformRest*/ false);
}
/**
@@ -2751,7 +2261,7 @@ namespace ts {
setEmitFlags(thisArg, EmitFlags.NoSubstitution);
}
let resultingCall: CallExpression | BinaryExpression;
if (node.transformFlags & TransformFlags.ContainsSpreadElementExpression) {
if (node.transformFlags & TransformFlags.ContainsSpreadExpression) {
// [source]
// f(...a, b)
// x.m(...a, b)
@@ -2813,7 +2323,7 @@ namespace ts {
*/
function visitNewExpression(node: NewExpression): LeftHandSideExpression {
// We are here because we contain a SpreadElementExpression.
Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadElementExpression) !== 0);
Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadExpression) !== 0);
// [source]
// new C(...a)
@@ -2834,7 +2344,7 @@ namespace ts {
}
/**
* Transforms an array of Expression nodes that contains a SpreadElementExpression.
* Transforms an array of Expression nodes that contains a SpreadExpression.
*
* @param elements The array of Expression nodes.
* @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array.
@@ -2851,14 +2361,14 @@ namespace ts {
// expressions into an array literal.
const numElements = elements.length;
const segments = flatten(
spanMap(elements, partitionSpreadElement, (partition, visitPartition, _start, end) =>
spanMap(elements, partitionSpread, (partition, visitPartition, _start, end) =>
visitPartition(partition, multiLine, hasTrailingComma && end === numElements)
)
);
if (segments.length === 1) {
const firstElement = elements[0];
return needsUniqueCopy && isSpreadElementExpression(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression
return needsUniqueCopy && isSpreadExpression(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression
? createArraySlice(segments[0])
: segments[0];
}
@@ -2867,17 +2377,17 @@ namespace ts {
return createArrayConcat(segments.shift(), segments);
}
function partitionSpreadElement(node: Expression) {
return isSpreadElementExpression(node)
? visitSpanOfSpreadElements
: visitSpanOfNonSpreadElements;
function partitionSpread(node: Expression) {
return isSpreadExpression(node)
? visitSpanOfSpreads
: visitSpanOfNonSpreads;
}
function visitSpanOfSpreadElements(chunk: Expression[]): VisitResult<Expression> {
return map(chunk, visitExpressionOfSpreadElement);
function visitSpanOfSpreads(chunk: Expression[]): VisitResult<Expression> {
return map(chunk, visitExpressionOfSpread);
}
function visitSpanOfNonSpreadElements(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult<Expression> {
function visitSpanOfNonSpreads(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult<Expression> {
return createArrayLiteral(
visitNodes(createNodeArray(chunk, /*location*/ undefined, hasTrailingComma), visitor, isExpression),
/*location*/ undefined,
@@ -2886,11 +2396,11 @@ namespace ts {
}
/**
* Transforms the expression of a SpreadElementExpression node.
* Transforms the expression of a SpreadExpression node.
*
* @param node A SpreadElementExpression node.
* @param node A SpreadExpression node.
*/
function visitExpressionOfSpreadElement(node: SpreadElementExpression) {
function visitExpressionOfSpread(node: SpreadElement) {
return visitNode(node.expression, visitor, isExpression);
}
@@ -3076,7 +2586,7 @@ namespace ts {
const statements: Statement[] = [];
startLexicalEnvironment();
addRange(statements, prologue);
addCaptureThisForNodeIfNeeded(statements, node);
addCaptureThisForNodeIfNeeded(statements, node, enableSubstitutionsForCapturedThis);
addRange(statements, visitNodes(createNodeArray(remaining), visitor, isStatement));
addRange(statements, endLexicalEnvironment());
const clone = getMutableClone(node);
@@ -3266,11 +2776,11 @@ namespace ts {
}
const callArgument = singleOrUndefined((<CallExpression>statementExpression).arguments);
if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElementExpression) {
if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElement) {
return false;
}
const expression = (<SpreadElementExpression>callArgument).expression;
const expression = (<SpreadElement>callArgument).expression;
return isIdentifier(expression) && expression === parameter.name;
}
}
-1
View File
@@ -32,7 +32,6 @@ namespace ts {
switch (node.kind) {
case SyntaxKind.BinaryExpression:
return visitBinaryExpression(<BinaryExpression>node);
default:
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);
+272
View File
@@ -0,0 +1,272 @@
/// <reference path="../factory.ts" />
/// <reference path="../visitor.ts" />
/*@internal*/
namespace ts {
export function transformESNext(context: TransformationContext) {
const {
hoistVariableDeclaration,
} = context;
let currentSourceFile: SourceFile;
return transformSourceFile;
function transformSourceFile(node: SourceFile) {
currentSourceFile = node;
return visitEachChild(node, visitor, context);
}
function visitor(node: Node): VisitResult<Node> {
if (node.transformFlags & TransformFlags.ESNext) {
return visitorWorker(node);
}
else if (node.transformFlags & TransformFlags.ContainsESNext) {
return visitEachChild(node, visitor, context);
}
else {
return node;
}
}
function visitorWorker(node: Node): VisitResult<Node> {
switch (node.kind) {
case SyntaxKind.ObjectLiteralExpression:
return visitObjectLiteralExpression(node as ObjectLiteralExpression);
case SyntaxKind.BinaryExpression:
return visitBinaryExpression(node as BinaryExpression);
case SyntaxKind.VariableDeclaration:
return visitVariableDeclaration(node as VariableDeclaration);
case SyntaxKind.ForOfStatement:
return visitForOfStatement(node as ForOfStatement);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
return node;
case SyntaxKind.FunctionDeclaration:
return visitFunctionDeclaration(node as FunctionDeclaration);
case SyntaxKind.FunctionExpression:
return visitFunctionExpression(node as FunctionExpression);
case SyntaxKind.ArrowFunction:
return visitArrowFunction(node as ArrowFunction);
case SyntaxKind.Parameter:
return visitParameter(node as ParameterDeclaration);
default:
Debug.failBadSyntaxKind(node);
return visitEachChild(node, visitor, context);
}
}
function chunkObjectLiteralElements(elements: ObjectLiteralElement[]): Expression[] {
let chunkObject: (ShorthandPropertyAssignment | PropertyAssignment)[];
const objects: Expression[] = [];
for (const e of elements) {
if (e.kind === SyntaxKind.SpreadAssignment) {
if (chunkObject) {
objects.push(createObjectLiteral(chunkObject));
chunkObject = undefined;
}
const target = (e as SpreadAssignment).expression;
objects.push(visitNode(target, visitor, isExpression));
}
else {
if (!chunkObject) {
chunkObject = [];
}
if (e.kind === SyntaxKind.PropertyAssignment) {
const p = e as PropertyAssignment;
chunkObject.push(createPropertyAssignment(p.name, visitNode(p.initializer, visitor, isExpression)));
}
else {
chunkObject.push(e as ShorthandPropertyAssignment);
}
}
}
if (chunkObject) {
objects.push(createObjectLiteral(chunkObject));
}
return objects;
}
function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression {
// spread elements emit like so:
// non-spread elements are chunked together into object literals, and then all are passed to __assign:
// { a, ...o, b } => __assign({a}, o, {b});
// If the first element is a spread element, then the first argument to __assign is {}:
// { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2)
const objects = chunkObjectLiteralElements(node.properties);
if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) {
objects.unshift(createObjectLiteral());
}
return createCall(createIdentifier("__assign"), undefined, objects);
}
/**
* Visits a BinaryExpression that contains a destructuring assignment.
*
* @param node A BinaryExpression node.
*/
function visitBinaryExpression(node: BinaryExpression): Expression {
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.AssertESNext) {
return flattenDestructuringAssignment(context, node, /*needsDestructuringValue*/ true, hoistVariableDeclaration, visitor, /*transformRest*/ true);
}
return visitEachChild(node, visitor, context);
}
/**
* Visits a VariableDeclaration node with a binding pattern.
*
* @param node A VariableDeclaration node.
*/
function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
// If we are here it is because the name contains a binding pattern with a rest somewhere in it.
if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.AssertESNext) {
const result = flattenVariableDestructuring(node, /*value*/ undefined, visitor, /*recordTempVariable*/ undefined, /*transformRest*/ true);
return result;
}
return visitEachChild(node, visitor, context);
}
/**
* Visits a ForOfStatement and converts it into a ES2015-compatible ForOfStatement.
*
* @param node A ForOfStatement.
*/
function visitForOfStatement(node: ForOfStatement): VisitResult<Statement> {
// The following ESNext code:
//
// for (let { x, y, ...rest } of expr) { }
//
// should be emitted as
//
// for (var _a of expr) {
// let { x, y } = _a, rest = __rest(_a, ["x", "y"]);
// }
//
// where _a is a temp emitted to capture the RHS.
// When the left hand side is an expression instead of a let declaration,
// the `let` before the `{ x, y }` is not emitted.
// When the left hand side is a let/const, the v is renamed if there is
// another v in scope.
// Note that all assignments to the LHS are emitted in the body, including
// all destructuring.
// Note also that because an extra statement is needed to assign to the LHS,
// for-of bodies are always emitted as blocks.
// for (<init> of <expression>) <statement>
// where <init> is [let] variabledeclarationlist | expression
const initializer = node.initializer;
if (!isRestBindingPattern(initializer) && !isRestAssignment(initializer)) {
return visitEachChild(node, visitor, context);
}
return convertForOf(node, undefined, visitor, noop, context, /*transformRest*/ true);
}
function isRestBindingPattern(initializer: ForInitializer) {
if (isVariableDeclarationList(initializer)) {
const declaration = firstOrUndefined(initializer.declarations);
return declaration && declaration.name &&
declaration.name.kind === SyntaxKind.ObjectBindingPattern &&
!!(declaration.name.transformFlags & TransformFlags.ContainsSpreadExpression);
}
return false;
}
function isRestAssignment(initializer: ForInitializer) {
return initializer.kind === SyntaxKind.ObjectLiteralExpression &&
initializer.transformFlags & TransformFlags.ContainsSpreadExpression;
}
function visitParameter(node: ParameterDeclaration): ParameterDeclaration {
if (isObjectRestParameter(node)) {
// Binding patterns are converted into a generated name and are
// evaluated inside the function body.
return setOriginalNode(
createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
getGeneratedNameForNode(node),
/*questionToken*/ undefined,
/*type*/ undefined,
node.initializer,
/*location*/ node
),
/*original*/ node
);
}
else {
return node;
}
}
function isObjectRestParameter(node: ParameterDeclaration) {
return node.name &&
node.name.kind === SyntaxKind.ObjectBindingPattern &&
!!(node.name.transformFlags & TransformFlags.ContainsSpreadExpression);
}
function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration {
const hasRest = forEach(node.parameters, isObjectRestParameter);
const body = hasRest ?
transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block :
visitEachChild(node.body, visitor, context);
return setOriginalNode(
createFunctionDeclaration(
/*decorators*/ undefined,
node.modifiers,
node.asteriskToken,
node.name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
body,
/*location*/ node
),
/*original*/ node);
}
function visitArrowFunction(node: ArrowFunction) {
const hasRest = forEach(node.parameters, isObjectRestParameter);
const body = hasRest ?
transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block :
visitEachChild(node.body, visitor, context);
const func = setOriginalNode(
createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
node.equalsGreaterThanToken,
body,
/*location*/ node
),
/*original*/ node
);
setEmitFlags(func, EmitFlags.CapturesThis);
return func;
}
function visitFunctionExpression(node: FunctionExpression): Expression {
const hasRest = forEach(node.parameters, isObjectRestParameter);
const body = hasRest ?
transformFunctionBody(node, visitor, currentSourceFile, context, noop, /*convertObjectRest*/ true) as Block :
visitEachChild(node.body, visitor, context);
return setOriginalNode(
createFunctionExpression(
/*modifiers*/ undefined,
node.asteriskToken,
name,
/*typeParameters*/ undefined,
visitNodes(node.parameters, visitor, isParameter),
/*type*/ undefined,
body,
/*location*/ node
),
/*original*/ node
);
}
}
}
+2 -1
View File
@@ -113,7 +113,8 @@ namespace ts {
|| createAssignHelper(currentSourceFile.externalHelpersModuleName, segments);
}
const element = createReactCreateElement(
const element = createExpressionForJsxElement(
context.getEmitResolver().getJsxFactoryEntity(),
compilerOptions.reactNamespace,
tagName,
objectProperties,
+1 -1
View File
@@ -1474,7 +1474,7 @@ namespace ts {
if (isAssignmentExpression(node)) {
return hasExportedReferenceInDestructuringTarget(node.left);
}
else if (isSpreadElementExpression(node)) {
else if (isSpreadExpression(node)) {
return hasExportedReferenceInDestructuringTarget(node.expression);
}
else if (isObjectLiteralExpression(node)) {
+5 -1
View File
@@ -471,7 +471,11 @@ namespace ts {
currentSourceFile = node;
// ensure "use strict" is emitted in all scenarios in alwaysStrict mode
if (compilerOptions.alwaysStrict) {
// There is no need to emit "use strict" in the following cases:
// 1. The file is an external module and target is es2015 or higher
// or 2. The file is an external module and module-kind is es6 or es2015 as such value is not allowed when targeting es5 or lower
if (compilerOptions.alwaysStrict &&
!(isExternalModule(node) && (compilerOptions.target >= ScriptTarget.ES2015 || compilerOptions.module === ModuleKind.ES2015))) {
node = ensureUseStrict(node);
}
+1
View File
@@ -27,6 +27,7 @@
"visitor.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
"transformers/es2017.ts",
"transformers/es2016.ts",
"transformers/es2015.ts",
+68 -45
View File
@@ -246,7 +246,7 @@ namespace ts {
ConditionalExpression,
TemplateExpression,
YieldExpression,
SpreadElementExpression,
SpreadElement,
ClassExpression,
OmittedExpression,
ExpressionWithTypeArguments,
@@ -320,6 +320,7 @@ namespace ts {
// Property assignments
PropertyAssignment,
ShorthandPropertyAssignment,
SpreadAssignment,
// Enum
EnumMember,
@@ -418,20 +419,21 @@ namespace ts {
HasDecorators = 1 << 11, // If the file has decorators (initialized by binding)
HasParamDecorators = 1 << 12, // If the file has parameter decorators (initialized by binding)
HasAsyncFunctions = 1 << 13, // If the file has async functions (initialized by binding)
HasJsxSpreadAttributes = 1 << 14, // If the file as JSX spread attributes (initialized by binding)
DisallowInContext = 1 << 15, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 16, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 17, // If node was parsed as part of a decorator
AwaitContext = 1 << 18, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 19, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 20, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 21, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 22, // If we've computed data from children and cached it in this node
HasSpreadAttribute = 1 << 14, // If the file as JSX spread attributes (initialized by binding)
HasRestAttribute = 1 << 15, // If the file has object destructure elements
DisallowInContext = 1 << 16, // If node was parsed in a context where 'in-expressions' are not allowed
YieldContext = 1 << 17, // If node was parsed in the 'yield' context created when parsing a generator
DecoratorContext = 1 << 18, // If node was parsed as part of a decorator
AwaitContext = 1 << 19, // If node was parsed in the 'await' context created when parsing an async function
ThisNodeHasError = 1 << 20, // If the parser encountered an error when parsing the code that created this node
JavaScriptFile = 1 << 21, // If node was parsed in a JavaScript
ThisNodeOrAnySubNodesHasError = 1 << 22, // If this node or any of its children had an error
HasAggregatedChildData = 1 << 23, // If we've computed data from children and cached it in this node
BlockScoped = Let | Const,
ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn,
EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions | HasJsxSpreadAttributes,
EmitHelperFlags = HasClassExtends | HasDecorators | HasParamDecorators | HasAsyncFunctions | HasSpreadAttribute | HasRestAttribute,
ReachabilityAndEmitFlags = ReachabilityCheckFlags | EmitHelperFlags,
// Parsing context flags
@@ -454,7 +456,6 @@ namespace ts {
Async = 1 << 8, // Property/Method/Function
Default = 1 << 9, // Function/Class (export default declaration)
Const = 1 << 11, // Variable declaration
HasComputedFlags = 1 << 29, // Modifier flags have been computed
AccessibilityModifier = Public | Private | Protected,
@@ -649,7 +650,7 @@ namespace ts {
export interface BindingElement extends Declaration {
kind: SyntaxKind.BindingElement;
propertyName?: PropertyName; // Binding property name (in object binding pattern)
dotDotDotToken?: DotDotDotToken; // Present on rest binding element
dotDotDotToken?: DotDotDotToken; // Present on rest element (in object binding pattern)
name: BindingName; // Declared binding element name
initializer?: Expression; // Optional initializer
}
@@ -675,7 +676,7 @@ namespace ts {
name?: PropertyName;
}
export type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | MethodDeclaration | AccessorDeclaration;
export type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | MethodDeclaration | AccessorDeclaration | SpreadAssignment;
export interface PropertyAssignment extends ObjectLiteralElement {
kind: SyntaxKind.PropertyAssignment;
@@ -694,6 +695,11 @@ namespace ts {
objectAssignmentInitializer?: Expression;
}
export interface SpreadAssignment extends ObjectLiteralElement {
kind: SyntaxKind.SpreadAssignment;
expression: Expression;
}
// SyntaxKind.VariableDeclaration
// SyntaxKind.Parameter
// SyntaxKind.BindingElement
@@ -1279,8 +1285,8 @@ namespace ts {
multiLine?: boolean;
}
export interface SpreadElementExpression extends Expression {
kind: SyntaxKind.SpreadElementExpression;
export interface SpreadElement extends Expression {
kind: SyntaxKind.SpreadElement;
expression: Expression;
}
@@ -2192,6 +2198,7 @@ namespace ts {
/* @internal */ getFileProcessingDiagnostics(): DiagnosticCollection;
/* @internal */ getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>;
/* @internal */ isSourceFileFromExternalLibrary(file: SourceFile): boolean;
// For testing purposes only.
/* @internal */ structureIsReused?: boolean;
}
@@ -2380,6 +2387,12 @@ namespace ts {
CannotBeNamed
}
/* @internal */
export const enum SyntheticSymbolKind {
UnionOrIntersection,
Spread
}
export const enum TypePredicateKind {
This,
Identifier
@@ -2472,6 +2485,7 @@ namespace ts {
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean;
writeLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, writer: SymbolWriter): void;
getJsxFactoryEntity(): EntityName;
}
export const enum SymbolFlags {
@@ -2591,7 +2605,9 @@ namespace ts {
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
leftSpread?: Symbol; // Left source for synthetic spread property
rightSpread?: Symbol; // Right source for synthetic spread property
hasNonUniformType?: boolean; // True if constituents have non-uniform types
isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
@@ -2709,7 +2725,7 @@ namespace ts {
EnumLike = Enum | EnumLiteral,
UnionOrIntersection = Union | Intersection,
StructuredType = Object | Union | Intersection,
StructuredOrTypeParameter = StructuredType | TypeParameter,
StructuredOrTypeParameter = StructuredType | TypeParameter | Index,
// 'Narrowable' types are types where narrowing actually narrows.
// This *should* be every type other than null, undefined, void, and never
@@ -2923,6 +2939,8 @@ namespace ts {
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
/* @internal */
typePredicate?: TypePredicate;
/* @internal */
instantiations?: Map<Signature>; // Generic signature instantiation cache
}
export const enum IndexKind {
@@ -2940,7 +2958,6 @@ namespace ts {
export interface TypeMapper {
(t: TypeParameter): Type;
mappedTypes?: Type[]; // Types mapped by this mapper
targetTypes?: Type[]; // Types substituted for mapped types
instantiations?: Type[]; // Cache of instantiations created using this type mapper.
context?: InferenceContext; // The inference context this mapper was created from.
// Only inference mappers have this set (in createInferenceMapper).
@@ -3058,6 +3075,7 @@ namespace ts {
moduleResolution?: ModuleResolutionKind;
newLine?: NewLineKind;
noEmit?: boolean;
/*@internal*/noEmitForJsFiles?: boolean;
noEmitHelpers?: boolean;
noEmitOnError?: boolean;
noErrorTruncation?: boolean;
@@ -3078,6 +3096,7 @@ namespace ts {
project?: string;
/* @internal */ pretty?: DiagnosticStyle;
reactNamespace?: string;
jsxFactory?: string;
removeComments?: boolean;
rootDir?: string;
rootDirs?: string[];
@@ -3160,7 +3179,8 @@ namespace ts {
ES2015 = 2,
ES2016 = 3,
ES2017 = 4,
Latest = ES2017,
ESNext = 5,
Latest = ESNext,
}
export const enum LanguageVariant {
@@ -3475,32 +3495,34 @@ namespace ts {
ContainsTypeScript = 1 << 1,
Jsx = 1 << 2,
ContainsJsx = 1 << 3,
ES2017 = 1 << 4,
ContainsES2017 = 1 << 5,
ES2016 = 1 << 6,
ContainsES2016 = 1 << 7,
ES2015 = 1 << 8,
ContainsES2015 = 1 << 9,
Generator = 1 << 10,
ContainsGenerator = 1 << 11,
DestructuringAssignment = 1 << 12,
ContainsDestructuringAssignment = 1 << 13,
ESNext = 1 << 4,
ContainsESNext = 1 << 5,
ES2017 = 1 << 6,
ContainsES2017 = 1 << 7,
ES2016 = 1 << 8,
ContainsES2016 = 1 << 9,
ES2015 = 1 << 10,
ContainsES2015 = 1 << 11,
Generator = 1 << 12,
ContainsGenerator = 1 << 13,
DestructuringAssignment = 1 << 14,
ContainsDestructuringAssignment = 1 << 15,
// Markers
// - Flags used to indicate that a subtree contains a specific transformation.
ContainsDecorators = 1 << 14,
ContainsPropertyInitializer = 1 << 15,
ContainsLexicalThis = 1 << 16,
ContainsCapturedLexicalThis = 1 << 17,
ContainsLexicalThisInComputedPropertyName = 1 << 18,
ContainsDefaultValueAssignments = 1 << 19,
ContainsParameterPropertyAssignments = 1 << 20,
ContainsSpreadElementExpression = 1 << 21,
ContainsComputedPropertyName = 1 << 22,
ContainsBlockScopedBinding = 1 << 23,
ContainsBindingPattern = 1 << 24,
ContainsYield = 1 << 25,
ContainsHoistedDeclarationOrCompletion = 1 << 26,
ContainsDecorators = 1 << 16,
ContainsPropertyInitializer = 1 << 17,
ContainsLexicalThis = 1 << 18,
ContainsCapturedLexicalThis = 1 << 19,
ContainsLexicalThisInComputedPropertyName = 1 << 20,
ContainsDefaultValueAssignments = 1 << 21,
ContainsParameterPropertyAssignments = 1 << 22,
ContainsSpreadExpression = 1 << 23,
ContainsComputedPropertyName = 1 << 24,
ContainsBlockScopedBinding = 1 << 25,
ContainsBindingPattern = 1 << 26,
ContainsYield = 1 << 27,
ContainsHoistedDeclarationOrCompletion = 1 << 28,
HasComputedFlags = 1 << 29, // Transform flags have been computed.
@@ -3508,6 +3530,7 @@ namespace ts {
// - Bitmasks that are used to assert facts about the syntax of a node and its subtree.
AssertTypeScript = TypeScript | ContainsTypeScript,
AssertJsx = Jsx | ContainsJsx,
AssertESNext = ESNext | ContainsESNext,
AssertES2017 = ES2017 | ContainsES2017,
AssertES2016 = ES2016 | ContainsES2016,
AssertES2015 = ES2015 | ContainsES2015,
@@ -3517,7 +3540,7 @@ namespace ts {
// Scope Exclusions
// - Bitmasks that exclude flags from propagating out of a specific context
// into the subtree flags of their container.
NodeExcludes = TypeScript | Jsx | ES2017 | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags,
NodeExcludes = TypeScript | Jsx | ESNext | ES2017 | ES2016 | ES2015 | DestructuringAssignment | Generator | HasComputedFlags,
ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion,
FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion,
ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion,
@@ -3526,7 +3549,7 @@ namespace ts {
ModuleExcludes = NodeExcludes | ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion,
TypeExcludes = ~ContainsTypeScript,
ObjectLiteralExcludes = NodeExcludes | ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpreadElementExpression,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpreadExpression,
VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern,
ParameterExcludes = NodeExcludes | ContainsBindingPattern,
+59 -33
View File
@@ -192,7 +192,7 @@ namespace ts {
export function nodePosToString(node: Node): string {
const file = getSourceFileOfNode(node);
const loc = getLineAndCharacterOfPosition(file, node.pos);
return `${ file.fileName }(${ loc.line + 1 },${ loc.character + 1 })`;
return `${file.fileName}(${loc.line + 1},${loc.character + 1})`;
}
export function getStartPosOfNode(node: Node): number {
@@ -439,7 +439,7 @@ namespace ts {
}
export function isBlockScope(node: Node, parentNode: Node) {
switch (node.kind) {
switch (node.kind) {
case SyntaxKind.SourceFile:
case SyntaxKind.CaseBlock:
case SyntaxKind.CatchClause:
@@ -485,6 +485,22 @@ namespace ts {
return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
}
export function getTextOfPropertyName(name: PropertyName): string {
switch (name.kind) {
case SyntaxKind.Identifier:
return (<Identifier>name).text;
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return (<LiteralExpression>name).text;
case SyntaxKind.ComputedPropertyName:
if (isStringOrNumericLiteral((<ComputedPropertyName>name).expression.kind)) {
return (<LiteralExpression>(<ComputedPropertyName>name).expression).text;
}
}
return undefined;
}
export function entityNameToString(name: EntityNameOrEntityNameExpression): string {
switch (name.kind) {
case SyntaxKind.Identifier:
@@ -498,6 +514,10 @@ namespace ts {
export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
const sourceFile = getSourceFileOfNode(node);
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2);
}
export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): Diagnostic {
const span = getErrorSpanForNode(sourceFile, node);
return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2);
}
@@ -624,9 +644,9 @@ namespace ts {
export function getJsDocCommentsFromText(node: Node, text: string) {
const commentRanges = (node.kind === SyntaxKind.Parameter ||
node.kind === SyntaxKind.TypeParameter ||
node.kind === SyntaxKind.FunctionExpression ||
node.kind === SyntaxKind.ArrowFunction) ?
node.kind === SyntaxKind.TypeParameter ||
node.kind === SyntaxKind.FunctionExpression ||
node.kind === SyntaxKind.ArrowFunction) ?
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
getLeadingCommentRangesOfNodeFromText(node, text);
return filter(commentRanges, isJsDocComment);
@@ -891,7 +911,7 @@ namespace ts {
export function isObjectLiteralOrClassExpressionMethod(node: Node): node is MethodDeclaration {
return node.kind === SyntaxKind.MethodDeclaration &&
(node.parent.kind === SyntaxKind.ObjectLiteralExpression ||
node.parent.kind === SyntaxKind.ClassExpression);
node.parent.kind === SyntaxKind.ClassExpression);
}
export function isIdentifierTypePredicate(predicate: TypePredicate): predicate is IdentifierTypePredicate {
@@ -1113,8 +1133,8 @@ namespace ts {
// if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target;
return (<FunctionLikeDeclaration>node.parent).body !== undefined
&& (node.parent.kind === SyntaxKind.Constructor
|| node.parent.kind === SyntaxKind.MethodDeclaration
|| node.parent.kind === SyntaxKind.SetAccessor)
|| node.parent.kind === SyntaxKind.MethodDeclaration
|| node.parent.kind === SyntaxKind.SetAccessor)
&& node.parent.parent.kind === SyntaxKind.ClassDeclaration;
}
@@ -1179,7 +1199,7 @@ namespace ts {
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
case SyntaxKind.TemplateExpression:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.OmittedExpression:
@@ -1461,7 +1481,7 @@ namespace ts {
}, tags => tags);
}
function getJSDocs<T>(node: Node, checkParentVariableStatement: boolean, getDocs: (docs: JSDoc[]) => T[], getTags: (tags: JSDocTag[]) => T[]): T[] {
function getJSDocs<T>(node: Node, checkParentVariableStatement: boolean, getDocs: (docs: JSDoc[]) => T[], getTags: (tags: JSDocTag[]) => T[]): T[] {
// TODO: Get rid of getJsDocComments and friends (note the lowercase 's' in Js)
// TODO: A lot of this work should be cached, maybe. I guess it's only used in services right now...
let result: T[] = undefined;
@@ -1482,8 +1502,8 @@ namespace ts {
const variableStatementNode =
isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent :
isVariableOfVariableDeclarationStatement ? node.parent.parent :
undefined;
isVariableOfVariableDeclarationStatement ? node.parent.parent :
undefined;
if (variableStatementNode) {
result = append(result, getJSDocs(variableStatementNode, checkParentVariableStatement, getDocs, getTags));
}
@@ -1641,14 +1661,14 @@ namespace ts {
return (<ForInStatement | ForOfStatement>parent).initializer === node ? AssignmentKind.Definite : AssignmentKind.None;
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
node = parent;
break;
case SyntaxKind.ShorthandPropertyAssignment:
if ((<ShorthandPropertyAssignment>parent).name !== node) {
return AssignmentKind.None;
}
// Fall through
// Fall through
case SyntaxKind.PropertyAssignment:
node = parent.parent;
break;
@@ -2226,7 +2246,7 @@ namespace ts {
case SyntaxKind.YieldExpression:
return 2;
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
return 1;
default:
@@ -2550,14 +2570,18 @@ namespace ts {
if (options.outFile || options.out) {
const moduleKind = getEmitModuleKind(options);
const moduleEmitEnabled = moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System;
const sourceFiles = host.getSourceFiles();
const sourceFiles = getAllEmittableSourceFiles();
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
return filter(sourceFiles, moduleEmitEnabled ? isNonDeclarationFile : isBundleEmitNonExternalModule);
}
else {
const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
const sourceFiles = targetSourceFile === undefined ? getAllEmittableSourceFiles() : [targetSourceFile];
return filterSourceFilesInDirectory(sourceFiles, file => host.isSourceFileFromExternalLibrary(file));
}
function getAllEmittableSourceFiles() {
return options.noEmitForJsFiles ? filter(host.getSourceFiles(), sourceFile => !isSourceFileJavaScript(sourceFile)) : host.getSourceFiles();
}
}
/** Don't call this for `--outFile`, just for `--outDir` or plain emit. */
@@ -2602,7 +2626,7 @@ namespace ts {
}
else {
for (const sourceFile of sourceFiles) {
// Don't emit if source file is a declaration file, or was located under node_modules
// Don't emit if source file is a declaration file, or was located under node_modules
if (!isDeclarationFile(sourceFile) && !host.isSourceFileFromExternalLibrary(sourceFile)) {
onSingleFileEmit(host, sourceFile);
}
@@ -2664,7 +2688,7 @@ namespace ts {
onBundledEmit(host);
}
else {
const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
const sourceFiles = targetSourceFile === undefined ? getSourceFilesToEmit(host) : [targetSourceFile];
for (const sourceFile of sourceFiles) {
if (shouldEmitInDirectory(sourceFile, file => host.isSourceFileFromExternalLibrary(file))) {
onSingleFileEmit(host, sourceFile);
@@ -2701,11 +2725,11 @@ namespace ts {
function onBundledEmit(host: EmitHost) {
// Can emit only sources that are not declaration file and are either non module code or module with
// --module or --target es6 specified. Files included by searching under node_modules are also not emitted.
const bundledSources = filter(host.getSourceFiles(),
const bundledSources = filter(getSourceFilesToEmit(host),
sourceFile => !isDeclarationFile(sourceFile) &&
!host.isSourceFileFromExternalLibrary(sourceFile) &&
(!isExternalModule(sourceFile) ||
!!getEmitModuleKind(options)));
!host.isSourceFileFromExternalLibrary(sourceFile) &&
(!isExternalModule(sourceFile) ||
!!getEmitModuleKind(options)));
if (bundledSources.length) {
const jsFilePath = options.outFile || options.out;
const emitFileNames: EmitFileNames = {
@@ -2891,7 +2915,7 @@ namespace ts {
writeComment: (text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => void,
node: TextRange, newLine: string, removeComments: boolean) {
let leadingComments: CommentRange[];
let currentDetachedCommentInfo: {nodePos: number, detachedCommentEndPos: number};
let currentDetachedCommentInfo: { nodePos: number, detachedCommentEndPos: number };
if (removeComments) {
// removeComments is true, only reserve pinned comment at the top of file
// For example:
@@ -3238,10 +3262,10 @@ namespace ts {
function stringifyValue(value: any): string {
return typeof value === "string" ? `"${escapeString(value)}"`
: typeof value === "number" ? isFinite(value) ? String(value) : "null"
: typeof value === "boolean" ? value ? "true" : "false"
: typeof value === "object" && value ? isArray(value) ? cycleCheck(stringifyArray, value) : cycleCheck(stringifyObject, value)
: /*fallback*/ "null";
: typeof value === "number" ? isFinite(value) ? String(value) : "null"
: typeof value === "boolean" ? value ? "true" : "false"
: typeof value === "object" && value ? isArray(value) ? cycleCheck(stringifyArray, value) : cycleCheck(stringifyObject, value)
: /*fallback*/ "null";
}
function cycleCheck(cb: (value: any) => string, value: any) {
@@ -3266,7 +3290,7 @@ namespace ts {
function stringifyProperty(memo: string, value: any, key: string) {
return value === undefined || typeof value === "function" || key === "__cycle" ? memo
: (memo ? memo + "," : memo) + `"${escapeString(key)}":${stringifyValue(value)}`;
: (memo ? memo + "," : memo) + `"${escapeString(key)}":${stringifyValue(value)}`;
}
const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
@@ -3511,7 +3535,7 @@ namespace ts {
* @param token The token.
*/
export function createTokenRange(pos: number, token: SyntaxKind): TextRange {
return createRange(pos, pos + tokenToString(token).length);
return createRange(pos, pos + tokenToString(token).length);
}
export function rangeIsOnSingleLine(range: TextRange, sourceFile: SourceFile) {
@@ -3874,6 +3898,7 @@ namespace ts {
const kind = node.kind;
return kind === SyntaxKind.PropertyAssignment
|| kind === SyntaxKind.ShorthandPropertyAssignment
|| kind === SyntaxKind.SpreadAssignment
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor
@@ -3961,8 +3986,8 @@ namespace ts {
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral;
}
export function isSpreadElementExpression(node: Node): node is SpreadElementExpression {
return node.kind === SyntaxKind.SpreadElementExpression;
export function isSpreadExpression(node: Node): node is SpreadElement {
return node.kind === SyntaxKind.SpreadElement;
}
export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments {
@@ -4020,7 +4045,7 @@ namespace ts {
|| kind === SyntaxKind.YieldExpression
|| kind === SyntaxKind.ArrowFunction
|| kind === SyntaxKind.BinaryExpression
|| kind === SyntaxKind.SpreadElementExpression
|| kind === SyntaxKind.SpreadElement
|| kind === SyntaxKind.AsExpression
|| kind === SyntaxKind.OmittedExpression
|| isUnaryExpressionKind(kind);
@@ -4322,6 +4347,7 @@ namespace ts {
namespace ts {
export function getDefaultLibFileName(options: CompilerOptions): string {
switch (options.target) {
case ScriptTarget.ESNext:
case ScriptTarget.ES2017:
return "lib.es2017.d.ts";
case ScriptTarget.ES2016:
+16 -66
View File
@@ -267,9 +267,9 @@ namespace ts {
case SyntaxKind.VoidExpression:
case SyntaxKind.AwaitExpression:
case SyntaxKind.YieldExpression:
case SyntaxKind.SpreadElementExpression:
case SyntaxKind.SpreadElement:
case SyntaxKind.NonNullExpression:
result = reduceNode((<ParenthesizedExpression | DeleteExpression | TypeOfExpression | VoidExpression | AwaitExpression | YieldExpression | SpreadElementExpression | NonNullExpression>node).expression, f, result);
result = reduceNode((<ParenthesizedExpression | DeleteExpression | TypeOfExpression | VoidExpression | AwaitExpression | YieldExpression | SpreadElement | NonNullExpression>node).expression, f, result);
break;
case SyntaxKind.PrefixUnaryExpression:
@@ -510,6 +510,10 @@ namespace ts {
result = reduceNode((<ShorthandPropertyAssignment>node).objectAssignmentInitializer, f, result);
break;
case SyntaxKind.SpreadAssignment:
result = reduceNode((node as SpreadAssignment).expression, f, result);
break;
// Top-level nodes
case SyntaxKind.SourceFile:
result = reduceLeft((<SourceFile>node).statements, f, result);
@@ -553,6 +557,7 @@ namespace ts {
return undefined;
}
aggregateTransformFlags(node);
const visited = visitor(node);
if (visited === node) {
return node;
@@ -621,6 +626,7 @@ namespace ts {
// Visit each original node.
for (let i = 0; i < count; i++) {
const node = nodes[i + start];
aggregateTransformFlags(node);
const visited = node !== undefined ? visitor(node) : undefined;
if (updated !== undefined || visited === undefined || visited !== node) {
if (updated === undefined) {
@@ -870,9 +876,9 @@ namespace ts {
return updateYield(<YieldExpression>node,
visitNode((<YieldExpression>node).expression, visitor, isExpression));
case SyntaxKind.SpreadElementExpression:
return updateSpread(<SpreadElementExpression>node,
visitNode((<SpreadElementExpression>node).expression, visitor, isExpression));
case SyntaxKind.SpreadElement:
return updateSpread(<SpreadElement>node,
visitNode((<SpreadElement>node).expression, visitor, isExpression));
case SyntaxKind.ClassExpression:
return updateClassExpression(<ClassExpression>node,
@@ -1125,7 +1131,11 @@ namespace ts {
visitNode((<ShorthandPropertyAssignment>node).name, visitor, isIdentifier),
visitNode((<ShorthandPropertyAssignment>node).objectAssignmentInitializer, visitor, isExpression));
// Top-level nodes
case SyntaxKind.SpreadAssignment:
return updateSpreadAssignment(node as SpreadAssignment,
visitNode((node as SpreadAssignment).expression, visitor, isExpression));
// Top-level nodes
case SyntaxKind.SourceFile:
context.startLexicalEnvironment();
return updateSourceFileNode(<SourceFile>node,
@@ -1268,66 +1278,6 @@ namespace ts {
return transformFlags | aggregateTransformFlagsForNode(child);
}
/**
* Gets the transform flags to exclude when unioning the transform flags of a subtree.
*
* NOTE: This needs to be kept up-to-date with the exclusions used in `computeTransformFlagsForNode`.
* For performance reasons, `computeTransformFlagsForNode` uses local constant values rather
* than calling this function.
*/
function getTransformFlagsSubtreeExclusions(kind: SyntaxKind) {
if (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode) {
return TransformFlags.TypeExcludes;
}
switch (kind) {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.ArrayLiteralExpression:
return TransformFlags.ArrayLiteralOrCallOrNewExcludes;
case SyntaxKind.ModuleDeclaration:
return TransformFlags.ModuleExcludes;
case SyntaxKind.Parameter:
return TransformFlags.ParameterExcludes;
case SyntaxKind.ArrowFunction:
return TransformFlags.ArrowFunctionExcludes;
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
return TransformFlags.FunctionExcludes;
case SyntaxKind.VariableDeclarationList:
return TransformFlags.VariableDeclarationListExcludes;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return TransformFlags.ClassExcludes;
case SyntaxKind.Constructor:
return TransformFlags.ConstructorExcludes;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return TransformFlags.MethodOrAccessorExcludes;
case SyntaxKind.AnyKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.TypeParameter:
case SyntaxKind.PropertySignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
return TransformFlags.TypeExcludes;
case SyntaxKind.ObjectLiteralExpression:
return TransformFlags.ObjectLiteralExcludes;
default:
return TransformFlags.NodeExcludes;
}
}
export namespace Debug {
export const failNotOptional = shouldAssert(AssertionLevel.Normal)
? (message?: string) => assert(false, message || "Node not optional.")