TypeScript/src/compiler/factoryPublic.ts
Nathan Shively-Sanders 68f8f22032
Merge pull request #38425 from dsherret/fixJSDocTagFactoryFuncReturnTypes
Fix some JSDoc factory function return types
2020-05-20 13:22:21 -07:00

3877 lines
180 KiB
TypeScript

namespace ts {
function createSynthesizedNode(kind: SyntaxKind): Node {
const node = createNode(kind, -1, -1);
node.flags |= NodeFlags.Synthesized;
return node;
}
/* @internal */
export function updateNode<T extends Node>(updated: T, original: T): T {
if (updated !== original) {
setOriginalNode(updated, original);
setTextRange(updated, original);
aggregateTransformFlags(updated);
}
return updated;
}
/* @internal */ export function createNodeArray<T extends Node>(elements?: T[], hasTrailingComma?: boolean): MutableNodeArray<T>;
export function createNodeArray<T extends Node>(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray<T>;
/**
* Make `elements` into a `NodeArray<T>`. If `elements` is `undefined`, returns an empty `NodeArray<T>`.
*/
export function createNodeArray<T extends Node>(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray<T> {
if (!elements || elements === emptyArray) {
elements = [];
}
else if (isNodeArray(elements)) {
return elements;
}
const array = <NodeArray<T>>elements;
array.pos = -1;
array.end = -1;
array.hasTrailingComma = hasTrailingComma;
return array;
}
/**
* Creates a shallow, memberwise clone of a node with no source map location.
*/
/* @internal */
export function getSynthesizedClone<T extends Node>(node: T): T {
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
// the original node. We also need to exclude specific properties and only include own-
// properties (to skip members already defined on the shared prototype).
if (node === undefined) {
return node;
}
const clone = <T>createSynthesizedNode(node.kind);
clone.flags |= node.flags;
setOriginalNode(clone, node);
for (const key in node) {
if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) {
continue;
}
(<any>clone)[key] = (<any>node)[key];
}
return clone;
}
// Literals
/* @internal */ export function createLiteral(value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote: boolean): StringLiteral; // eslint-disable-line @typescript-eslint/unified-signatures
/* @internal */ export function createLiteral(value: string | number, isSingleQuote: boolean): StringLiteral | NumericLiteral;
/** If a node is passed, creates a string literal whose source text is read from a source node during emit. */
export function createLiteral(value: string | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier): StringLiteral;
export function createLiteral(value: number | PseudoBigInt): NumericLiteral;
export function createLiteral(value: boolean): BooleanLiteral;
export function createLiteral(value: string | number | PseudoBigInt | boolean): PrimaryExpression;
export function createLiteral(value: string | number | PseudoBigInt | boolean | StringLiteral | NoSubstitutionTemplateLiteral | NumericLiteral | Identifier, isSingleQuote?: boolean): PrimaryExpression {
if (typeof value === "number") {
return createNumericLiteral(value + "");
}
// eslint-disable-next-line no-in-operator
if (typeof value === "object" && "base10Value" in value) { // PseudoBigInt
return createBigIntLiteral(pseudoBigIntToString(value) + "n");
}
if (typeof value === "boolean") {
return value ? createTrue() : createFalse();
}
if (isString(value)) {
const res = createStringLiteral(value);
if (isSingleQuote) res.singleQuote = true;
return res;
}
return createLiteralFromNode(value);
}
export function createNumericLiteral(value: string, numericLiteralFlags: TokenFlags = TokenFlags.None): NumericLiteral {
const node = <NumericLiteral>createSynthesizedNode(SyntaxKind.NumericLiteral);
node.text = value;
node.numericLiteralFlags = numericLiteralFlags;
return node;
}
export function createBigIntLiteral(value: string): BigIntLiteral {
const node = <BigIntLiteral>createSynthesizedNode(SyntaxKind.BigIntLiteral);
node.text = value;
return node;
}
export function createStringLiteral(text: string): StringLiteral {
const node = <StringLiteral>createSynthesizedNode(SyntaxKind.StringLiteral);
node.text = text;
return node;
}
export function createRegularExpressionLiteral(text: string): RegularExpressionLiteral {
const node = <RegularExpressionLiteral>createSynthesizedNode(SyntaxKind.RegularExpressionLiteral);
node.text = text;
return node;
}
function createLiteralFromNode(sourceNode: Exclude<PropertyNameLiteral, PrivateIdentifier>): StringLiteral {
const node = createStringLiteral(getTextOfIdentifierOrLiteral(sourceNode));
node.textSourceNode = sourceNode;
return node;
}
// Identifiers
export function createIdentifier(text: string): Identifier;
/* @internal */
export function createIdentifier(text: string, typeArguments: readonly (TypeNode | TypeParameterDeclaration)[] | undefined): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures
export function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[]): Identifier {
const node = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
node.escapedText = escapeLeadingUnderscores(text);
node.originalKeywordKind = text ? stringToToken(text) : SyntaxKind.Unknown;
node.autoGenerateFlags = GeneratedIdentifierFlags.None;
node.autoGenerateId = 0;
if (typeArguments) {
node.typeArguments = createNodeArray(typeArguments as readonly TypeNode[]);
}
return node;
}
export function updateIdentifier(node: Identifier): Identifier;
/* @internal */
export function updateIdentifier(node: Identifier, typeArguments: NodeArray<TypeNode | TypeParameterDeclaration> | undefined): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures
export function updateIdentifier(node: Identifier, typeArguments?: NodeArray<TypeNode | TypeParameterDeclaration> | undefined): Identifier {
return node.typeArguments !== typeArguments
? updateNode(createIdentifier(idText(node), typeArguments), node)
: node;
}
let nextAutoGenerateId = 0;
/** Create a unique temporary variable. */
export function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined): Identifier;
/* @internal */ export function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes: boolean): GeneratedIdentifier;
export function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean): GeneratedIdentifier {
const name = createIdentifier("") as GeneratedIdentifier;
name.autoGenerateFlags = GeneratedIdentifierFlags.Auto;
name.autoGenerateId = nextAutoGenerateId;
nextAutoGenerateId++;
if (recordTempVariable) {
recordTempVariable(name);
}
if (reservedInNestedScopes) {
name.autoGenerateFlags |= GeneratedIdentifierFlags.ReservedInNestedScopes;
}
return name;
}
/** Create a unique temporary variable for use in a loop. */
export function createLoopVariable(): Identifier {
const name = createIdentifier("");
name.autoGenerateFlags = GeneratedIdentifierFlags.Loop;
name.autoGenerateId = nextAutoGenerateId;
nextAutoGenerateId++;
return name;
}
/** Create a unique name based on the supplied text. */
export function createUniqueName(text: string): Identifier {
const name = createIdentifier(text);
name.autoGenerateFlags = GeneratedIdentifierFlags.Unique;
name.autoGenerateId = nextAutoGenerateId;
nextAutoGenerateId++;
return name;
}
/* @internal */ export function createOptimisticUniqueName(text: string): GeneratedIdentifier;
/** Create a unique name based on the supplied text. */
export function createOptimisticUniqueName(text: string): Identifier;
export function createOptimisticUniqueName(text: string): GeneratedIdentifier {
const name = createIdentifier(text) as GeneratedIdentifier;
name.autoGenerateFlags = GeneratedIdentifierFlags.Unique | GeneratedIdentifierFlags.Optimistic;
name.autoGenerateId = nextAutoGenerateId;
nextAutoGenerateId++;
return name;
}
/** Create a unique name based on the supplied text. This does not consider names injected by the transformer. */
export function createFileLevelUniqueName(text: string): Identifier {
const name = createOptimisticUniqueName(text);
name.autoGenerateFlags |= GeneratedIdentifierFlags.FileLevel;
return name;
}
/** Create a unique name generated for a node. */
export function getGeneratedNameForNode(node: Node | undefined): Identifier;
/* @internal */ export function getGeneratedNameForNode(node: Node | undefined, flags: GeneratedIdentifierFlags): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures
export function getGeneratedNameForNode(node: Node | undefined, flags?: GeneratedIdentifierFlags): Identifier {
const name = createIdentifier(node && isIdentifier(node) ? idText(node) : "");
name.autoGenerateFlags = GeneratedIdentifierFlags.Node | flags!;
name.autoGenerateId = nextAutoGenerateId;
name.original = node;
nextAutoGenerateId++;
return name;
}
// Private Identifiers
export function createPrivateIdentifier(text: string): PrivateIdentifier {
if (text[0] !== "#") {
Debug.fail("First character of private identifier must be #: " + text);
}
const node = createSynthesizedNode(SyntaxKind.PrivateIdentifier) as PrivateIdentifier;
node.escapedText = escapeLeadingUnderscores(text);
return node;
}
// Punctuation
export function createToken<TKind extends SyntaxKind>(token: TKind) {
return <Token<TKind>>createSynthesizedNode(token);
}
// Reserved words
export function createSuper() {
return <SuperExpression>createSynthesizedNode(SyntaxKind.SuperKeyword);
}
export function createThis() {
return <ThisExpression & Token<SyntaxKind.ThisKeyword>>createSynthesizedNode(SyntaxKind.ThisKeyword);
}
export function createNull() {
return <NullLiteral & Token<SyntaxKind.NullKeyword>>createSynthesizedNode(SyntaxKind.NullKeyword);
}
export function createTrue() {
return <BooleanLiteral & Token<SyntaxKind.TrueKeyword>>createSynthesizedNode(SyntaxKind.TrueKeyword);
}
export function createFalse() {
return <BooleanLiteral & Token<SyntaxKind.FalseKeyword>>createSynthesizedNode(SyntaxKind.FalseKeyword);
}
// Modifiers
export function createModifier<T extends Modifier["kind"]>(kind: T): Token<T> {
return createToken(kind);
}
export function createModifiersFromModifierFlags(flags: ModifierFlags) {
const result: Modifier[] = [];
if (flags & ModifierFlags.Export) { result.push(createModifier(SyntaxKind.ExportKeyword)); }
if (flags & ModifierFlags.Ambient) { result.push(createModifier(SyntaxKind.DeclareKeyword)); }
if (flags & ModifierFlags.Default) { result.push(createModifier(SyntaxKind.DefaultKeyword)); }
if (flags & ModifierFlags.Const) { result.push(createModifier(SyntaxKind.ConstKeyword)); }
if (flags & ModifierFlags.Public) { result.push(createModifier(SyntaxKind.PublicKeyword)); }
if (flags & ModifierFlags.Private) { result.push(createModifier(SyntaxKind.PrivateKeyword)); }
if (flags & ModifierFlags.Protected) { result.push(createModifier(SyntaxKind.ProtectedKeyword)); }
if (flags & ModifierFlags.Abstract) { result.push(createModifier(SyntaxKind.AbstractKeyword)); }
if (flags & ModifierFlags.Static) { result.push(createModifier(SyntaxKind.StaticKeyword)); }
if (flags & ModifierFlags.Readonly) { result.push(createModifier(SyntaxKind.ReadonlyKeyword)); }
if (flags & ModifierFlags.Async) { result.push(createModifier(SyntaxKind.AsyncKeyword)); }
return result;
}
// Names
export function createQualifiedName(left: EntityName, right: string | Identifier) {
const node = <QualifiedName>createSynthesizedNode(SyntaxKind.QualifiedName);
node.left = left;
node.right = asName(right);
return node;
}
export function updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier) {
return node.left !== left
|| node.right !== right
? updateNode(createQualifiedName(left, right), node)
: node;
}
function parenthesizeForComputedName(expression: Expression): Expression {
return isCommaSequence(expression)
? createParen(expression)
: expression;
}
export function createComputedPropertyName(expression: Expression) {
const node = <ComputedPropertyName>createSynthesizedNode(SyntaxKind.ComputedPropertyName);
node.expression = parenthesizeForComputedName(expression);
return node;
}
export function updateComputedPropertyName(node: ComputedPropertyName, expression: Expression) {
return node.expression !== expression
? updateNode(createComputedPropertyName(expression), node)
: node;
}
// Signature elements
export function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration;
node.name = asName(name);
node.constraint = constraint;
node.default = defaultType;
return node;
}
export function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
return node.name !== name
|| node.constraint !== constraint
|| node.default !== defaultType
? updateNode(createTypeParameterDeclaration(name, constraint, defaultType), node)
: node;
}
export function createParameter(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
dotDotDotToken: DotDotDotToken | undefined,
name: string | BindingName,
questionToken?: QuestionToken,
type?: TypeNode,
initializer?: Expression) {
const node = <ParameterDeclaration>createSynthesizedNode(SyntaxKind.Parameter);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.dotDotDotToken = dotDotDotToken;
node.name = asName(name);
node.questionToken = questionToken;
node.type = type;
node.initializer = initializer ? parenthesizeExpressionForList(initializer) : undefined;
return node;
}
export function updateParameter(
node: ParameterDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
dotDotDotToken: DotDotDotToken | undefined,
name: string | BindingName,
questionToken: QuestionToken | undefined,
type: TypeNode | undefined,
initializer: Expression | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.dotDotDotToken !== dotDotDotToken
|| node.name !== name
|| node.questionToken !== questionToken
|| node.type !== type
|| node.initializer !== initializer
? updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, questionToken, type, initializer), node)
: node;
}
export function createDecorator(expression: Expression) {
const node = <Decorator>createSynthesizedNode(SyntaxKind.Decorator);
node.expression = parenthesizeForAccess(expression);
return node;
}
export function updateDecorator(node: Decorator, expression: Expression) {
return node.expression !== expression
? updateNode(createDecorator(expression), node)
: node;
}
// Type Elements
export function createPropertySignature(
modifiers: readonly Modifier[] | undefined,
name: PropertyName | string,
questionToken: QuestionToken | undefined,
type: TypeNode | undefined,
initializer: Expression | undefined): PropertySignature {
const node = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature;
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.questionToken = questionToken;
node.type = type;
node.initializer = initializer;
return node;
}
export function updatePropertySignature(
node: PropertySignature,
modifiers: readonly Modifier[] | undefined,
name: PropertyName,
questionToken: QuestionToken | undefined,
type: TypeNode | undefined,
initializer: Expression | undefined) {
return node.modifiers !== modifiers
|| node.name !== name
|| node.questionToken !== questionToken
|| node.type !== type
|| node.initializer !== initializer
? updateNode(createPropertySignature(modifiers, name, questionToken, type, initializer), node)
: node;
}
export function createProperty(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | PropertyName,
questionOrExclamationToken: QuestionToken | ExclamationToken | undefined,
type: TypeNode | undefined,
initializer: Expression | undefined) {
const node = <PropertyDeclaration>createSynthesizedNode(SyntaxKind.PropertyDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.questionToken = questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.QuestionToken ? questionOrExclamationToken : undefined;
node.exclamationToken = questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.ExclamationToken ? questionOrExclamationToken : undefined;
node.type = type;
node.initializer = initializer;
return node;
}
export function updateProperty(
node: PropertyDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | PropertyName,
questionOrExclamationToken: QuestionToken | ExclamationToken | undefined,
type: TypeNode | undefined,
initializer: Expression | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.questionToken !== (questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.QuestionToken ? questionOrExclamationToken : undefined)
|| node.exclamationToken !== (questionOrExclamationToken !== undefined && questionOrExclamationToken.kind === SyntaxKind.ExclamationToken ? questionOrExclamationToken : undefined)
|| node.type !== type
|| node.initializer !== initializer
? updateNode(createProperty(decorators, modifiers, name, questionOrExclamationToken, type, initializer), node)
: node;
}
export function createMethodSignature(
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
name: string | PropertyName,
questionToken: QuestionToken | undefined) {
const node = createSignatureDeclaration(SyntaxKind.MethodSignature, typeParameters, parameters, type) as MethodSignature;
node.name = asName(name);
node.questionToken = questionToken;
return node;
}
export function updateMethodSignature(node: MethodSignature, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name: PropertyName, questionToken: QuestionToken | undefined) {
return node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
|| node.name !== name
|| node.questionToken !== questionToken
? updateNode(createMethodSignature(typeParameters, parameters, type, name, questionToken), node)
: node;
}
export function createMethod(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
asteriskToken: AsteriskToken | undefined,
name: string | PropertyName,
questionToken: QuestionToken | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
body: Block | undefined) {
const node = <MethodDeclaration>createSynthesizedNode(SyntaxKind.MethodDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.asteriskToken = asteriskToken;
node.name = asName(name);
node.questionToken = questionToken;
node.typeParameters = asNodeArray(typeParameters);
node.parameters = createNodeArray(parameters);
node.type = type;
node.body = body;
return node;
}
function createMethodCall(object: Expression, methodName: string | Identifier, argumentsList: readonly Expression[]) {
return createCall(
createPropertyAccess(object, asName(methodName)),
/*typeArguments*/ undefined,
argumentsList
);
}
function createGlobalMethodCall(globalObjectName: string, methodName: string, argumentsList: readonly Expression[]) {
return createMethodCall(createIdentifier(globalObjectName), methodName, argumentsList);
}
/* @internal */
export function createObjectDefinePropertyCall(target: Expression, propertyName: string | Expression, attributes: Expression) {
return createGlobalMethodCall("Object", "defineProperty", [target, asExpression(propertyName), attributes]);
}
function tryAddPropertyAssignment(properties: Push<PropertyAssignment>, propertyName: string, expression: Expression | undefined) {
if (expression) {
properties.push(createPropertyAssignment(propertyName, expression));
return true;
}
return false;
}
/* @internal */
export function createPropertyDescriptor(attributes: PropertyDescriptorAttributes, singleLine?: boolean) {
const properties: PropertyAssignment[] = [];
tryAddPropertyAssignment(properties, "enumerable", asExpression(attributes.enumerable));
tryAddPropertyAssignment(properties, "configurable", asExpression(attributes.configurable));
let isData = tryAddPropertyAssignment(properties, "writable", asExpression(attributes.writable));
isData = tryAddPropertyAssignment(properties, "value", attributes.value) || isData;
let isAccessor = tryAddPropertyAssignment(properties, "get", attributes.get);
isAccessor = tryAddPropertyAssignment(properties, "set", attributes.set) || isAccessor;
Debug.assert(!(isData && isAccessor), "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor.");
return createObjectLiteral(properties, !singleLine);
}
export function updateMethod(
node: MethodDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
asteriskToken: AsteriskToken | undefined,
name: PropertyName,
questionToken: QuestionToken | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.asteriskToken !== asteriskToken
|| node.name !== name
|| node.questionToken !== questionToken
|| node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
|| node.body !== body
? updateNode(createMethod(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node)
: node;
}
export function createConstructor(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined) {
const node = <ConstructorDeclaration>createSynthesizedNode(SyntaxKind.Constructor);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.typeParameters = undefined;
node.parameters = createNodeArray(parameters);
node.type = undefined;
node.body = body;
return node;
}
export function updateConstructor(
node: ConstructorDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
parameters: readonly ParameterDeclaration[],
body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.parameters !== parameters
|| node.body !== body
? updateNode(createConstructor(decorators, modifiers, parameters, body), node)
: node;
}
export function createGetAccessor(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | PropertyName,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
body: Block | undefined) {
const node = <GetAccessorDeclaration>createSynthesizedNode(SyntaxKind.GetAccessor);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.typeParameters = undefined;
node.parameters = createNodeArray(parameters);
node.type = type;
node.body = body;
return node;
}
export function updateGetAccessor(
node: GetAccessorDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: PropertyName,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.parameters !== parameters
|| node.type !== type
|| node.body !== body
? updateNode(createGetAccessor(decorators, modifiers, name, parameters, type, body), node)
: node;
}
export function createSetAccessor(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | PropertyName,
parameters: readonly ParameterDeclaration[],
body: Block | undefined) {
const node = <SetAccessorDeclaration>createSynthesizedNode(SyntaxKind.SetAccessor);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.typeParameters = undefined;
node.parameters = createNodeArray(parameters);
node.body = body;
return node;
}
export function updateSetAccessor(
node: SetAccessorDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: PropertyName,
parameters: readonly ParameterDeclaration[],
body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.parameters !== parameters
|| node.body !== body
? updateNode(createSetAccessor(decorators, modifiers, name, parameters, body), node)
: node;
}
export function createCallSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.CallSignature, typeParameters, parameters, type) as CallSignatureDeclaration;
}
export function updateCallSignature(node: CallSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createConstructSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.ConstructSignature, typeParameters, parameters, type) as ConstructSignatureDeclaration;
}
export function updateConstructSignature(node: ConstructSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createIndexSignature(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode): IndexSignatureDeclaration {
const node = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration;
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.parameters = createNodeArray(parameters);
node.type = type;
return node;
}
export function updateIndexSignature(
node: IndexSignatureDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode) {
return node.parameters !== parameters
|| node.type !== type
|| node.decorators !== decorators
|| node.modifiers !== modifiers
? updateNode(createIndexSignature(decorators, modifiers, parameters, type), node)
: node;
}
/* @internal */
export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, typeArguments?: readonly TypeNode[] | undefined) {
const node = createSynthesizedNode(kind) as SignatureDeclaration;
node.typeParameters = asNodeArray(typeParameters);
node.parameters = asNodeArray(parameters);
node.type = type;
node.typeArguments = asNodeArray(typeArguments);
return node;
}
function updateSignatureDeclaration<T extends SignatureDeclaration>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): T {
return node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
? updateNode(<T>createSignatureDeclaration(node.kind, typeParameters, parameters, type), node)
: node;
}
// Types
export function createKeywordTypeNode(kind: KeywordTypeNode["kind"]) {
return <KeywordTypeNode>createSynthesizedNode(kind);
}
export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode) {
return createTypePredicateNodeWithModifier(/*assertsModifier*/ undefined, parameterName, type);
}
export function createTypePredicateNodeWithModifier(assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined) {
const node = createSynthesizedNode(SyntaxKind.TypePredicate) as TypePredicateNode;
node.assertsModifier = assertsModifier;
node.parameterName = asName(parameterName);
node.type = type;
return node;
}
export function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode) {
return updateTypePredicateNodeWithModifier(node, node.assertsModifier, parameterName, type);
}
export function updateTypePredicateNodeWithModifier(node: TypePredicateNode, assertsModifier: AssertsToken | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined) {
return node.assertsModifier !== assertsModifier
|| node.parameterName !== parameterName
|| node.type !== type
? updateNode(createTypePredicateNodeWithModifier(assertsModifier, parameterName, type), node)
: node;
}
export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: readonly TypeNode[] | undefined) {
const node = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode;
node.typeName = asName(typeName);
node.typeArguments = typeArguments && parenthesizeTypeParameters(typeArguments);
return node;
}
export function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray<TypeNode> | undefined) {
return node.typeName !== typeName
|| node.typeArguments !== typeArguments
? updateNode(createTypeReferenceNode(typeName, typeArguments), node)
: node;
}
export function createFunctionTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.FunctionType, typeParameters, parameters, type) as FunctionTypeNode;
}
export function updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createConstructorTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined) {
return createSignatureDeclaration(SyntaxKind.ConstructorType, typeParameters, parameters, type) as ConstructorTypeNode;
}
export function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
return updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createTypeQueryNode(exprName: EntityName) {
const node = createSynthesizedNode(SyntaxKind.TypeQuery) as TypeQueryNode;
node.exprName = exprName;
return node;
}
export function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName) {
return node.exprName !== exprName
? updateNode(createTypeQueryNode(exprName), node)
: node;
}
export function createTypeLiteralNode(members: readonly TypeElement[] | undefined) {
const node = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode;
node.members = createNodeArray(members);
return node;
}
export function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray<TypeElement>) {
return node.members !== members
? updateNode(createTypeLiteralNode(members), node)
: node;
}
export function createArrayTypeNode(elementType: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode;
node.elementType = parenthesizeArrayTypeMember(elementType);
return node;
}
export function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode {
return node.elementType !== elementType
? updateNode(createArrayTypeNode(elementType), node)
: node;
}
export function createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]) {
const node = createSynthesizedNode(SyntaxKind.TupleType) as TupleTypeNode;
node.elements = createNodeArray(elements);
return node;
}
export function updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]) {
return node.elements !== elements
? updateNode(createTupleTypeNode(elements), node)
: node;
}
export function createOptionalTypeNode(type: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.OptionalType) as OptionalTypeNode;
node.type = parenthesizeArrayTypeMember(type);
return node;
}
export function updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode {
return node.type !== type
? updateNode(createOptionalTypeNode(type), node)
: node;
}
export function createRestTypeNode(type: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.RestType) as RestTypeNode;
node.type = type;
return node;
}
export function updateRestTypeNode(node: RestTypeNode, type: TypeNode): RestTypeNode {
return node.type !== type
? updateNode(createRestTypeNode(type), node)
: node;
}
export function createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode {
return <UnionTypeNode>createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types);
}
export function updateUnionTypeNode(node: UnionTypeNode, types: NodeArray<TypeNode>) {
return updateUnionOrIntersectionTypeNode(node, types);
}
export function createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode {
return <IntersectionTypeNode>createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types);
}
export function updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray<TypeNode>) {
return updateUnionOrIntersectionTypeNode(node, types);
}
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: readonly TypeNode[]) {
const node = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode;
node.types = parenthesizeElementTypeMembers(types);
return node;
}
function updateUnionOrIntersectionTypeNode<T extends UnionOrIntersectionTypeNode>(node: T, types: NodeArray<TypeNode>): T {
return node.types !== types
? updateNode(<T>createUnionOrIntersectionTypeNode(node.kind, types), node)
: node;
}
export function createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.ConditionalType) as ConditionalTypeNode;
node.checkType = parenthesizeConditionalTypeMember(checkType);
node.extendsType = parenthesizeConditionalTypeMember(extendsType);
node.trueType = trueType;
node.falseType = falseType;
return node;
}
export function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode) {
return node.checkType !== checkType
|| node.extendsType !== extendsType
|| node.trueType !== trueType
|| node.falseType !== falseType
? updateNode(createConditionalTypeNode(checkType, extendsType, trueType, falseType), node)
: node;
}
export function createInferTypeNode(typeParameter: TypeParameterDeclaration) {
const node = <InferTypeNode>createSynthesizedNode(SyntaxKind.InferType);
node.typeParameter = typeParameter;
return node;
}
export function updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration) {
return node.typeParameter !== typeParameter
? updateNode(createInferTypeNode(typeParameter), node)
: node;
}
export function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean) {
const node = <ImportTypeNode>createSynthesizedNode(SyntaxKind.ImportType);
node.argument = argument;
node.qualifier = qualifier;
node.typeArguments = parenthesizeTypeParameters(typeArguments);
node.isTypeOf = isTypeOf;
return node;
}
export function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean) {
return node.argument !== argument
|| node.qualifier !== qualifier
|| node.typeArguments !== typeArguments
|| node.isTypeOf !== isTypeOf
? updateNode(createImportTypeNode(argument, qualifier, typeArguments, isTypeOf), node)
: node;
}
export function createParenthesizedType(type: TypeNode) {
const node = <ParenthesizedTypeNode>createSynthesizedNode(SyntaxKind.ParenthesizedType);
node.type = type;
return node;
}
export function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode) {
return node.type !== type
? updateNode(createParenthesizedType(type), node)
: node;
}
export function createNamedTupleMember(dotDotDotToken: Token<SyntaxKind.DotDotDotToken> | undefined, name: Identifier, questionToken: Token<SyntaxKind.QuestionToken> | undefined, type: TypeNode) {
const node = <NamedTupleMember>createSynthesizedNode(SyntaxKind.NamedTupleMember);
node.dotDotDotToken = dotDotDotToken;
node.name = name;
node.questionToken = questionToken;
node.type = type;
return node;
}
export function updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: Token<SyntaxKind.DotDotDotToken> | undefined, name: Identifier, questionToken: Token<SyntaxKind.QuestionToken> | undefined, type: TypeNode) {
return node.dotDotDotToken !== dotDotDotToken
|| node.name !== name
|| node.questionToken !== questionToken
|| node.type !== type
? updateNode(createNamedTupleMember(dotDotDotToken, name, questionToken, type), node)
: node;
}
export function createThisTypeNode() {
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
}
export function createTypeOperatorNode(type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | TypeNode, type?: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
node.operator = typeof operatorOrType === "number" ? operatorOrType : SyntaxKind.KeyOfKeyword;
node.type = parenthesizeElementTypeMember(typeof operatorOrType === "number" ? type! : operatorOrType);
return node;
}
export function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode) {
return node.type !== type ? updateNode(createTypeOperatorNode(node.operator, type), node) : node;
}
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.IndexedAccessType) as IndexedAccessTypeNode;
node.objectType = parenthesizeElementTypeMember(objectType);
node.indexType = indexType;
return node;
}
export function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode) {
return node.objectType !== objectType
|| node.indexType !== indexType
? updateNode(createIndexedAccessTypeNode(objectType, indexType), node)
: node;
}
export function createMappedTypeNode(readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
const node = createSynthesizedNode(SyntaxKind.MappedType) as MappedTypeNode;
node.readonlyToken = readonlyToken;
node.typeParameter = typeParameter;
node.questionToken = questionToken;
node.type = type;
return node;
}
export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined): MappedTypeNode {
return node.readonlyToken !== readonlyToken
|| node.typeParameter !== typeParameter
|| node.questionToken !== questionToken
|| node.type !== type
? updateNode(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), node)
: node;
}
export function createLiteralTypeNode(literal: LiteralTypeNode["literal"]) {
const node = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
node.literal = literal;
return node;
}
export function updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]) {
return node.literal !== literal
? updateNode(createLiteralTypeNode(literal), node)
: node;
}
// Binding Patterns
export function createObjectBindingPattern(elements: readonly BindingElement[]) {
const node = <ObjectBindingPattern>createSynthesizedNode(SyntaxKind.ObjectBindingPattern);
node.elements = createNodeArray(elements);
return node;
}
export function updateObjectBindingPattern(node: ObjectBindingPattern, elements: readonly BindingElement[]) {
return node.elements !== elements
? updateNode(createObjectBindingPattern(elements), node)
: node;
}
export function createArrayBindingPattern(elements: readonly ArrayBindingElement[]) {
const node = <ArrayBindingPattern>createSynthesizedNode(SyntaxKind.ArrayBindingPattern);
node.elements = createNodeArray(elements);
return node;
}
export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: readonly ArrayBindingElement[]) {
return node.elements !== elements
? updateNode(createArrayBindingPattern(elements), node)
: node;
}
export function createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression) {
const node = <BindingElement>createSynthesizedNode(SyntaxKind.BindingElement);
node.dotDotDotToken = dotDotDotToken;
node.propertyName = asName(propertyName);
node.name = asName(name);
node.initializer = initializer;
return node;
}
export function updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined) {
return node.propertyName !== propertyName
|| node.dotDotDotToken !== dotDotDotToken
|| node.name !== name
|| node.initializer !== initializer
? updateNode(createBindingElement(dotDotDotToken, propertyName, name, initializer), node)
: node;
}
// Expression
export function createArrayLiteral(elements?: readonly Expression[], multiLine?: boolean) {
const node = <ArrayLiteralExpression>createSynthesizedNode(SyntaxKind.ArrayLiteralExpression);
node.elements = parenthesizeListElements(createNodeArray(elements));
if (multiLine) node.multiLine = true;
return node;
}
export function updateArrayLiteral(node: ArrayLiteralExpression, elements: readonly Expression[]) {
return node.elements !== elements
? updateNode(createArrayLiteral(elements, node.multiLine), node)
: node;
}
export function createObjectLiteral(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean) {
const node = <ObjectLiteralExpression>createSynthesizedNode(SyntaxKind.ObjectLiteralExpression);
node.properties = createNodeArray(properties);
if (multiLine) node.multiLine = true;
return node;
}
export function updateObjectLiteral(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) {
return node.properties !== properties
? updateNode(createObjectLiteral(properties, node.multiLine), node)
: node;
}
export function createPropertyAccess(expression: Expression, name: string | Identifier | PrivateIdentifier) {
const node = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression);
node.expression = parenthesizeForAccess(expression);
node.name = asName(name);
setEmitFlags(node, EmitFlags.NoIndentation);
return node;
}
export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) {
if (isPropertyAccessChain(node)) {
return updatePropertyAccessChain(node, expression, node.questionDotToken, cast(name, isIdentifier));
}
// Because we are updating existed propertyAccess we want to inherit its emitFlags
// instead of using the default from createPropertyAccess
return node.expression !== expression
|| node.name !== name
? updateNode(setEmitFlags(createPropertyAccess(expression, name), getEmitFlags(node)), node)
: node;
}
export function createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier) {
const node = <PropertyAccessChain>createSynthesizedNode(SyntaxKind.PropertyAccessExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
node.questionDotToken = questionDotToken;
node.name = asName(name);
setEmitFlags(node, EmitFlags.NoIndentation);
return node;
}
export function updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessExpression using updatePropertyAccessChain. Use updatePropertyAccess instead.");
// Because we are updating an existing PropertyAccessChain we want to inherit its emitFlags
// instead of using the default from createPropertyAccess
return node.expression !== expression
|| node.questionDotToken !== questionDotToken
|| node.name !== name
? updateNode(setEmitFlags(createPropertyAccessChain(expression, questionDotToken, name), getEmitFlags(node)), node)
: node;
}
export function createElementAccess(expression: Expression, index: number | Expression) {
const node = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
node.expression = parenthesizeForAccess(expression);
node.argumentExpression = asExpression(index);
return node;
}
export function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) {
if (isOptionalChain(node)) {
return updateElementAccessChain(node, expression, node.questionDotToken, argumentExpression);
}
return node.expression !== expression
|| node.argumentExpression !== argumentExpression
? updateNode(createElementAccess(expression, argumentExpression), node)
: node;
}
export function createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression) {
const node = <ElementAccessChain>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
node.questionDotToken = questionDotToken;
node.argumentExpression = asExpression(index);
return node;
}
export function updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update an ElementAccessExpression using updateElementAccessChain. Use updateElementAccess instead.");
return node.expression !== expression
|| node.questionDotToken !== questionDotToken
|| node.argumentExpression !== argumentExpression
? updateNode(createElementAccessChain(expression, questionDotToken, argumentExpression), node)
: node;
}
export function createCall(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
const node = <CallExpression>createSynthesizedNode(SyntaxKind.CallExpression);
node.expression = parenthesizeForAccess(expression);
node.typeArguments = asNodeArray(typeArguments);
node.arguments = parenthesizeListElements(createNodeArray(argumentsArray));
return node;
}
export function updateCall(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) {
if (isOptionalChain(node)) {
return updateCallChain(node, expression, node.questionDotToken, typeArguments, argumentsArray);
}
return node.expression !== expression
|| node.typeArguments !== typeArguments
|| node.arguments !== argumentsArray
? updateNode(createCall(expression, typeArguments, argumentsArray), node)
: node;
}
export function createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
const node = <CallChain>createSynthesizedNode(SyntaxKind.CallExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
node.questionDotToken = questionDotToken;
node.typeArguments = asNodeArray(typeArguments);
node.arguments = parenthesizeListElements(createNodeArray(argumentsArray));
return node;
}
export function updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallExpression using updateCallChain. Use updateCall instead.");
return node.expression !== expression
|| node.questionDotToken !== questionDotToken
|| node.typeArguments !== typeArguments
|| node.arguments !== argumentsArray
? updateNode(createCallChain(expression, questionDotToken, typeArguments, argumentsArray), node)
: node;
}
export function createNew(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
const node = <NewExpression>createSynthesizedNode(SyntaxKind.NewExpression);
node.expression = parenthesizeForNew(expression);
node.typeArguments = asNodeArray(typeArguments);
node.arguments = argumentsArray ? parenthesizeListElements(createNodeArray(argumentsArray)) : undefined;
return node;
}
export function updateNew(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined) {
return node.expression !== expression
|| node.typeArguments !== typeArguments
|| node.arguments !== argumentsArray
? updateNode(createNew(expression, typeArguments, argumentsArray), node)
: node;
}
/** @deprecated */ export function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
export function createTaggedTemplate(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression;
/** @internal */
export function createTaggedTemplate(tag: Expression, typeArgumentsOrTemplate: readonly TypeNode[] | TemplateLiteral | undefined, template?: TemplateLiteral): TaggedTemplateExpression;
export function createTaggedTemplate(tag: Expression, typeArgumentsOrTemplate: readonly TypeNode[] | TemplateLiteral | undefined, template?: TemplateLiteral) {
const node = <TaggedTemplateExpression>createSynthesizedNode(SyntaxKind.TaggedTemplateExpression);
node.tag = parenthesizeForAccess(tag);
if (template) {
node.typeArguments = asNodeArray(typeArgumentsOrTemplate as readonly TypeNode[]);
node.template = template;
}
else {
node.typeArguments = undefined;
node.template = typeArgumentsOrTemplate as TemplateLiteral;
}
return node;
}
/** @deprecated */ export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression;
export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, typeArgumentsOrTemplate: readonly TypeNode[] | TemplateLiteral | undefined, template?: TemplateLiteral) {
return node.tag !== tag
|| (template
? node.typeArguments !== typeArgumentsOrTemplate || node.template !== template
: node.typeArguments !== undefined || node.template !== typeArgumentsOrTemplate)
? updateNode(createTaggedTemplate(tag, typeArgumentsOrTemplate, template), node)
: node;
}
export function createTypeAssertion(type: TypeNode, expression: Expression) {
const node = <TypeAssertion>createSynthesizedNode(SyntaxKind.TypeAssertionExpression);
node.type = type;
node.expression = parenthesizePrefixOperand(expression);
return node;
}
export function updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression) {
return node.type !== type
|| node.expression !== expression
? updateNode(createTypeAssertion(type, expression), node)
: node;
}
export function createParen(expression: Expression) {
const node = <ParenthesizedExpression>createSynthesizedNode(SyntaxKind.ParenthesizedExpression);
node.expression = expression;
return node;
}
export function updateParen(node: ParenthesizedExpression, expression: Expression) {
return node.expression !== expression
? updateNode(createParen(expression), node)
: node;
}
export function createFunctionExpression(
modifiers: readonly Modifier[] | undefined,
asteriskToken: AsteriskToken | undefined,
name: string | Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[] | undefined,
type: TypeNode | undefined,
body: Block) {
const node = <FunctionExpression>createSynthesizedNode(SyntaxKind.FunctionExpression);
node.modifiers = asNodeArray(modifiers);
node.asteriskToken = asteriskToken;
node.name = asName(name);
node.typeParameters = asNodeArray(typeParameters);
node.parameters = createNodeArray(parameters);
node.type = type;
node.body = body;
return node;
}
export function updateFunctionExpression(
node: FunctionExpression,
modifiers: readonly Modifier[] | undefined,
asteriskToken: AsteriskToken | undefined,
name: Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
body: Block) {
return node.name !== name
|| node.modifiers !== modifiers
|| node.asteriskToken !== asteriskToken
|| node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
|| node.body !== body
? updateNode(createFunctionExpression(modifiers, asteriskToken, name, typeParameters, parameters, type, body), node)
: node;
}
export function createArrowFunction(
modifiers: readonly Modifier[] | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
equalsGreaterThanToken: EqualsGreaterThanToken | undefined,
body: ConciseBody) {
const node = <ArrowFunction>createSynthesizedNode(SyntaxKind.ArrowFunction);
node.modifiers = asNodeArray(modifiers);
node.typeParameters = asNodeArray(typeParameters);
node.parameters = createNodeArray(parameters);
node.type = type;
node.equalsGreaterThanToken = equalsGreaterThanToken || createToken(SyntaxKind.EqualsGreaterThanToken);
node.body = parenthesizeConciseBody(body);
return node;
}
export function updateArrowFunction(
node: ArrowFunction,
modifiers: readonly Modifier[] | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>,
body: ConciseBody
): ArrowFunction {
return node.modifiers !== modifiers
|| node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
|| node.equalsGreaterThanToken !== equalsGreaterThanToken
|| node.body !== body
? updateNode(createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), node)
: node;
}
export function createDelete(expression: Expression) {
const node = <DeleteExpression>createSynthesizedNode(SyntaxKind.DeleteExpression);
node.expression = parenthesizePrefixOperand(expression);
return node;
}
export function updateDelete(node: DeleteExpression, expression: Expression) {
return node.expression !== expression
? updateNode(createDelete(expression), node)
: node;
}
export function createTypeOf(expression: Expression) {
const node = <TypeOfExpression>createSynthesizedNode(SyntaxKind.TypeOfExpression);
node.expression = parenthesizePrefixOperand(expression);
return node;
}
export function updateTypeOf(node: TypeOfExpression, expression: Expression) {
return node.expression !== expression
? updateNode(createTypeOf(expression), node)
: node;
}
export function createVoid(expression: Expression) {
const node = <VoidExpression>createSynthesizedNode(SyntaxKind.VoidExpression);
node.expression = parenthesizePrefixOperand(expression);
return node;
}
export function updateVoid(node: VoidExpression, expression: Expression) {
return node.expression !== expression
? updateNode(createVoid(expression), node)
: node;
}
export function createAwait(expression: Expression) {
const node = <AwaitExpression>createSynthesizedNode(SyntaxKind.AwaitExpression);
node.expression = parenthesizePrefixOperand(expression);
return node;
}
export function updateAwait(node: AwaitExpression, expression: Expression) {
return node.expression !== expression
? updateNode(createAwait(expression), node)
: node;
}
export function createPrefix(operator: PrefixUnaryOperator, operand: Expression) {
const node = <PrefixUnaryExpression>createSynthesizedNode(SyntaxKind.PrefixUnaryExpression);
node.operator = operator;
node.operand = parenthesizePrefixOperand(operand);
return node;
}
export function updatePrefix(node: PrefixUnaryExpression, operand: Expression) {
return node.operand !== operand
? updateNode(createPrefix(node.operator, operand), node)
: node;
}
export function createPostfix(operand: Expression, operator: PostfixUnaryOperator) {
const node = <PostfixUnaryExpression>createSynthesizedNode(SyntaxKind.PostfixUnaryExpression);
node.operand = parenthesizePostfixOperand(operand);
node.operator = operator;
return node;
}
export function updatePostfix(node: PostfixUnaryExpression, operand: Expression) {
return node.operand !== operand
? updateNode(createPostfix(operand, node.operator), node)
: node;
}
export function createBinary(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression) {
const node = <BinaryExpression>createSynthesizedNode(SyntaxKind.BinaryExpression);
const operatorToken = asToken(operator);
const operatorKind = operatorToken.kind;
node.left = parenthesizeBinaryOperand(operatorKind, left, /*isLeftSideOfBinary*/ true, /*leftOperand*/ undefined);
node.operatorToken = operatorToken;
node.right = parenthesizeBinaryOperand(operatorKind, right, /*isLeftSideOfBinary*/ false, node.left);
return node;
}
export function updateBinary(node: BinaryExpression, left: Expression, right: Expression, operator: BinaryOperator | BinaryOperatorToken = node.operatorToken) {
return node.left !== left
|| node.right !== right
|| node.operatorToken !== operator
? updateNode(createBinary(left, operator, right), node)
: node;
}
/** @deprecated */ export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
export function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
export function createConditional(condition: Expression, questionTokenOrWhenTrue: QuestionToken | Expression, whenTrueOrWhenFalse: Expression, colonToken?: ColonToken, whenFalse?: Expression) {
const node = <ConditionalExpression>createSynthesizedNode(SyntaxKind.ConditionalExpression);
node.condition = parenthesizeForConditionalHead(condition);
node.questionToken = whenFalse ? <QuestionToken>questionTokenOrWhenTrue : createToken(SyntaxKind.QuestionToken);
node.whenTrue = parenthesizeSubexpressionOfConditionalExpression(whenFalse ? whenTrueOrWhenFalse : <Expression>questionTokenOrWhenTrue);
node.colonToken = whenFalse ? colonToken! : createToken(SyntaxKind.ColonToken);
node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenFalse ? whenFalse : whenTrueOrWhenFalse);
return node;
}
export function updateConditional(
node: ConditionalExpression,
condition: Expression,
questionToken: Token<SyntaxKind.QuestionToken>,
whenTrue: Expression,
colonToken: Token<SyntaxKind.ColonToken>,
whenFalse: Expression
): ConditionalExpression {
return node.condition !== condition
|| node.questionToken !== questionToken
|| node.whenTrue !== whenTrue
|| node.colonToken !== colonToken
|| node.whenFalse !== whenFalse
? updateNode(createConditional(condition, questionToken, whenTrue, colonToken, whenFalse), node)
: node;
}
export function createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]) {
const node = <TemplateExpression>createSynthesizedNode(SyntaxKind.TemplateExpression);
node.head = head;
node.templateSpans = createNodeArray(templateSpans);
return node;
}
export function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]) {
return node.head !== head
|| node.templateSpans !== templateSpans
? updateNode(createTemplateExpression(head, templateSpans), node)
: node;
}
let rawTextScanner: Scanner | undefined;
const invalidValueSentinel: object = {};
function getCookedText(kind: TemplateLiteralToken["kind"], rawText: string) {
if (!rawTextScanner) {
rawTextScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.Standard);
}
switch (kind) {
case SyntaxKind.NoSubstitutionTemplateLiteral:
rawTextScanner.setText("`" + rawText + "`");
break;
case SyntaxKind.TemplateHead:
rawTextScanner.setText("`" + rawText + "${");
break;
case SyntaxKind.TemplateMiddle:
rawTextScanner.setText("}" + rawText + "${");
break;
case SyntaxKind.TemplateTail:
rawTextScanner.setText("}" + rawText + "`");
break;
}
let token = rawTextScanner.scan();
if (token === SyntaxKind.CloseBracketToken) {
token = rawTextScanner.reScanTemplateToken(/* isTaggedTemplate */ false);
}
if (rawTextScanner.isUnterminated()) {
rawTextScanner.setText(undefined);
return invalidValueSentinel;
}
let tokenValue: string | undefined;
switch (token) {
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateHead:
case SyntaxKind.TemplateMiddle:
case SyntaxKind.TemplateTail:
tokenValue = rawTextScanner.getTokenValue();
break;
}
if (rawTextScanner.scan() !== SyntaxKind.EndOfFileToken) {
rawTextScanner.setText(undefined);
return invalidValueSentinel;
}
rawTextScanner.setText(undefined);
return tokenValue;
}
function createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string | undefined) {
const node = <TemplateLiteralLikeNode>createSynthesizedNode(kind);
node.text = text;
if (rawText === undefined || text === rawText) {
node.rawText = rawText;
}
else {
const cooked = getCookedText(kind, rawText);
if (typeof cooked === "object") {
return Debug.fail("Invalid raw text");
}
Debug.assert(text === cooked, "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.");
node.rawText = rawText;
}
return node;
}
export function createTemplateHead(text: string, rawText?: string) {
const node = <TemplateHead>createTemplateLiteralLikeNode(SyntaxKind.TemplateHead, text, rawText);
node.text = text;
return node;
}
export function createTemplateMiddle(text: string, rawText?: string) {
const node = <TemplateMiddle>createTemplateLiteralLikeNode(SyntaxKind.TemplateMiddle, text, rawText);
node.text = text;
return node;
}
export function createTemplateTail(text: string, rawText?: string) {
const node = <TemplateTail>createTemplateLiteralLikeNode(SyntaxKind.TemplateTail, text, rawText);
node.text = text;
return node;
}
export function createNoSubstitutionTemplateLiteral(text: string, rawText?: string) {
const node = <NoSubstitutionTemplateLiteral>createTemplateLiteralLikeNode(SyntaxKind.NoSubstitutionTemplateLiteral, text, rawText);
return node;
}
export function createYield(expression?: Expression): YieldExpression;
export function createYield(asteriskToken: AsteriskToken | undefined, expression: Expression): YieldExpression;
export function createYield(asteriskTokenOrExpression?: AsteriskToken | undefined | Expression, expression?: Expression) {
const asteriskToken = asteriskTokenOrExpression && asteriskTokenOrExpression.kind === SyntaxKind.AsteriskToken ? <AsteriskToken>asteriskTokenOrExpression : undefined;
expression = asteriskTokenOrExpression && asteriskTokenOrExpression.kind !== SyntaxKind.AsteriskToken ? asteriskTokenOrExpression : expression;
const node = <YieldExpression>createSynthesizedNode(SyntaxKind.YieldExpression);
node.asteriskToken = asteriskToken;
node.expression = expression && parenthesizeExpressionForList(expression);
return node;
}
export function updateYield(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression) {
return node.expression !== expression
|| node.asteriskToken !== asteriskToken
? updateNode(createYield(asteriskToken, expression), node)
: node;
}
export function createSpread(expression: Expression) {
const node = <SpreadElement>createSynthesizedNode(SyntaxKind.SpreadElement);
node.expression = parenthesizeExpressionForList(expression);
return node;
}
export function updateSpread(node: SpreadElement, expression: Expression) {
return node.expression !== expression
? updateNode(createSpread(expression), node)
: node;
}
export function createClassExpression(
modifiers: readonly Modifier[] | undefined,
name: string | Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
heritageClauses: readonly HeritageClause[] | undefined,
members: readonly ClassElement[]) {
const node = <ClassExpression>createSynthesizedNode(SyntaxKind.ClassExpression);
node.decorators = undefined;
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.typeParameters = asNodeArray(typeParameters);
node.heritageClauses = asNodeArray(heritageClauses);
node.members = createNodeArray(members);
return node;
}
export function updateClassExpression(
node: ClassExpression,
modifiers: readonly Modifier[] | undefined,
name: Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
heritageClauses: readonly HeritageClause[] | undefined,
members: readonly ClassElement[]) {
return node.modifiers !== modifiers
|| node.name !== name
|| node.typeParameters !== typeParameters
|| node.heritageClauses !== heritageClauses
|| node.members !== members
? updateNode(createClassExpression(modifiers, name, typeParameters, heritageClauses, members), node)
: node;
}
export function createOmittedExpression() {
return <OmittedExpression>createSynthesizedNode(SyntaxKind.OmittedExpression);
}
export function createExpressionWithTypeArguments(typeArguments: readonly TypeNode[] | undefined, expression: Expression) {
const node = <ExpressionWithTypeArguments>createSynthesizedNode(SyntaxKind.ExpressionWithTypeArguments);
node.expression = parenthesizeForAccess(expression);
node.typeArguments = asNodeArray(typeArguments);
return node;
}
export function updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, typeArguments: readonly TypeNode[] | undefined, expression: Expression) {
return node.typeArguments !== typeArguments
|| node.expression !== expression
? updateNode(createExpressionWithTypeArguments(typeArguments, expression), node)
: node;
}
export function createAsExpression(expression: Expression, type: TypeNode) {
const node = <AsExpression>createSynthesizedNode(SyntaxKind.AsExpression);
node.expression = expression;
node.type = type;
return node;
}
export function updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode) {
return node.expression !== expression
|| node.type !== type
? updateNode(createAsExpression(expression, type), node)
: node;
}
export function createNonNullExpression(expression: Expression) {
const node = <NonNullExpression>createSynthesizedNode(SyntaxKind.NonNullExpression);
node.expression = parenthesizeForAccess(expression);
return node;
}
export function updateNonNullExpression(node: NonNullExpression, expression: Expression) {
if (isNonNullChain(node)) {
return updateNonNullChain(node, expression);
}
return node.expression !== expression
? updateNode(createNonNullExpression(expression), node)
: node;
}
export function createNonNullChain(expression: Expression) {
const node = <NonNullChain>createSynthesizedNode(SyntaxKind.NonNullExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
return node;
}
export function updateNonNullChain(node: NonNullChain, expression: Expression) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead.");
return node.expression !== expression
? updateNode(createNonNullChain(expression), node)
: node;
}
export function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier) {
const node = <MetaProperty>createSynthesizedNode(SyntaxKind.MetaProperty);
node.keywordToken = keywordToken;
node.name = name;
return node;
}
export function updateMetaProperty(node: MetaProperty, name: Identifier) {
return node.name !== name
? updateNode(createMetaProperty(node.keywordToken, name), node)
: node;
}
// Misc
export function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail) {
const node = <TemplateSpan>createSynthesizedNode(SyntaxKind.TemplateSpan);
node.expression = expression;
node.literal = literal;
return node;
}
export function updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail) {
return node.expression !== expression
|| node.literal !== literal
? updateNode(createTemplateSpan(expression, literal), node)
: node;
}
export function createSemicolonClassElement() {
return <SemicolonClassElement>createSynthesizedNode(SyntaxKind.SemicolonClassElement);
}
// Element
export function createBlock(statements: readonly Statement[], multiLine?: boolean): Block {
const block = <Block>createSynthesizedNode(SyntaxKind.Block);
block.statements = createNodeArray(statements);
if (multiLine) block.multiLine = multiLine;
return block;
}
export function updateBlock(node: Block, statements: readonly Statement[]) {
return node.statements !== statements
? updateNode(createBlock(statements, node.multiLine), node)
: node;
}
export function createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]) {
const node = <VariableStatement>createSynthesizedNode(SyntaxKind.VariableStatement);
node.decorators = undefined;
node.modifiers = asNodeArray(modifiers);
node.declarationList = isArray(declarationList) ? createVariableDeclarationList(declarationList) : declarationList;
return node;
}
export function updateVariableStatement(node: VariableStatement, modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList) {
return node.modifiers !== modifiers
|| node.declarationList !== declarationList
? updateNode(createVariableStatement(modifiers, declarationList), node)
: node;
}
export function createEmptyStatement() {
return <EmptyStatement>createSynthesizedNode(SyntaxKind.EmptyStatement);
}
export function createExpressionStatement(expression: Expression): ExpressionStatement {
const node = <ExpressionStatement>createSynthesizedNode(SyntaxKind.ExpressionStatement);
node.expression = parenthesizeExpressionForExpressionStatement(expression);
return node;
}
export function updateExpressionStatement(node: ExpressionStatement, expression: Expression) {
return node.expression !== expression
? updateNode(createExpressionStatement(expression), node)
: node;
}
/** @deprecated Use `createExpressionStatement` instead. */
export const createStatement = createExpressionStatement;
/** @deprecated Use `updateExpressionStatement` instead. */
export const updateStatement = updateExpressionStatement;
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement) {
const node = <IfStatement>createSynthesizedNode(SyntaxKind.IfStatement);
node.expression = expression;
node.thenStatement = asEmbeddedStatement(thenStatement);
node.elseStatement = asEmbeddedStatement(elseStatement);
return node;
}
export function updateIf(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined) {
return node.expression !== expression
|| node.thenStatement !== thenStatement
|| node.elseStatement !== elseStatement
? updateNode(createIf(expression, thenStatement, elseStatement), node)
: node;
}
export function createDo(statement: Statement, expression: Expression) {
const node = <DoStatement>createSynthesizedNode(SyntaxKind.DoStatement);
node.statement = asEmbeddedStatement(statement);
node.expression = expression;
return node;
}
export function updateDo(node: DoStatement, statement: Statement, expression: Expression) {
return node.statement !== statement
|| node.expression !== expression
? updateNode(createDo(statement, expression), node)
: node;
}
export function createWhile(expression: Expression, statement: Statement) {
const node = <WhileStatement>createSynthesizedNode(SyntaxKind.WhileStatement);
node.expression = expression;
node.statement = asEmbeddedStatement(statement);
return node;
}
export function updateWhile(node: WhileStatement, expression: Expression, statement: Statement) {
return node.expression !== expression
|| node.statement !== statement
? updateNode(createWhile(expression, statement), node)
: node;
}
export function createFor(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) {
const node = <ForStatement>createSynthesizedNode(SyntaxKind.ForStatement);
node.initializer = initializer;
node.condition = condition;
node.incrementor = incrementor;
node.statement = asEmbeddedStatement(statement);
return node;
}
export function updateFor(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement) {
return node.initializer !== initializer
|| node.condition !== condition
|| node.incrementor !== incrementor
|| node.statement !== statement
? updateNode(createFor(initializer, condition, incrementor, statement), node)
: node;
}
export function createForIn(initializer: ForInitializer, expression: Expression, statement: Statement) {
const node = <ForInStatement>createSynthesizedNode(SyntaxKind.ForInStatement);
node.initializer = initializer;
node.expression = expression;
node.statement = asEmbeddedStatement(statement);
return node;
}
export function updateForIn(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement) {
return node.initializer !== initializer
|| node.expression !== expression
|| node.statement !== statement
? updateNode(createForIn(initializer, expression, statement), node)
: node;
}
export function createForOf(awaitModifier: AwaitKeywordToken | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) {
const node = <ForOfStatement>createSynthesizedNode(SyntaxKind.ForOfStatement);
node.awaitModifier = awaitModifier;
node.initializer = initializer;
node.expression = isCommaSequence(expression) ? createParen(expression) : expression;
node.statement = asEmbeddedStatement(statement);
return node;
}
export function updateForOf(node: ForOfStatement, awaitModifier: AwaitKeywordToken | undefined, initializer: ForInitializer, expression: Expression, statement: Statement) {
return node.awaitModifier !== awaitModifier
|| node.initializer !== initializer
|| node.expression !== expression
|| node.statement !== statement
? updateNode(createForOf(awaitModifier, initializer, expression, statement), node)
: node;
}
export function createContinue(label?: string | Identifier): ContinueStatement {
const node = <ContinueStatement>createSynthesizedNode(SyntaxKind.ContinueStatement);
node.label = asName(label);
return node;
}
export function updateContinue(node: ContinueStatement, label: Identifier | undefined) {
return node.label !== label
? updateNode(createContinue(label), node)
: node;
}
export function createBreak(label?: string | Identifier): BreakStatement {
const node = <BreakStatement>createSynthesizedNode(SyntaxKind.BreakStatement);
node.label = asName(label);
return node;
}
export function updateBreak(node: BreakStatement, label: Identifier | undefined) {
return node.label !== label
? updateNode(createBreak(label), node)
: node;
}
export function createReturn(expression?: Expression): ReturnStatement {
const node = <ReturnStatement>createSynthesizedNode(SyntaxKind.ReturnStatement);
node.expression = expression;
return node;
}
export function updateReturn(node: ReturnStatement, expression: Expression | undefined) {
return node.expression !== expression
? updateNode(createReturn(expression), node)
: node;
}
export function createWith(expression: Expression, statement: Statement) {
const node = <WithStatement>createSynthesizedNode(SyntaxKind.WithStatement);
node.expression = expression;
node.statement = asEmbeddedStatement(statement);
return node;
}
export function updateWith(node: WithStatement, expression: Expression, statement: Statement) {
return node.expression !== expression
|| node.statement !== statement
? updateNode(createWith(expression, statement), node)
: node;
}
export function createSwitch(expression: Expression, caseBlock: CaseBlock): SwitchStatement {
const node = <SwitchStatement>createSynthesizedNode(SyntaxKind.SwitchStatement);
node.expression = parenthesizeExpressionForList(expression);
node.caseBlock = caseBlock;
return node;
}
export function updateSwitch(node: SwitchStatement, expression: Expression, caseBlock: CaseBlock) {
return node.expression !== expression
|| node.caseBlock !== caseBlock
? updateNode(createSwitch(expression, caseBlock), node)
: node;
}
export function createLabel(label: string | Identifier, statement: Statement) {
const node = <LabeledStatement>createSynthesizedNode(SyntaxKind.LabeledStatement);
node.label = asName(label);
node.statement = asEmbeddedStatement(statement);
return node;
}
export function updateLabel(node: LabeledStatement, label: Identifier, statement: Statement) {
return node.label !== label
|| node.statement !== statement
? updateNode(createLabel(label, statement), node)
: node;
}
export function createThrow(expression: Expression) {
const node = <ThrowStatement>createSynthesizedNode(SyntaxKind.ThrowStatement);
node.expression = expression;
return node;
}
export function updateThrow(node: ThrowStatement, expression: Expression) {
return node.expression !== expression
? updateNode(createThrow(expression), node)
: node;
}
export function createTry(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) {
const node = <TryStatement>createSynthesizedNode(SyntaxKind.TryStatement);
node.tryBlock = tryBlock;
node.catchClause = catchClause;
node.finallyBlock = finallyBlock;
return node;
}
export function updateTry(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined) {
return node.tryBlock !== tryBlock
|| node.catchClause !== catchClause
|| node.finallyBlock !== finallyBlock
? updateNode(createTry(tryBlock, catchClause, finallyBlock), node)
: node;
}
export function createDebuggerStatement() {
return <DebuggerStatement>createSynthesizedNode(SyntaxKind.DebuggerStatement);
}
export function createVariableDeclaration(name: string | BindingName, type?: TypeNode, initializer?: Expression) {
/* Internally, one should probably use createTypeScriptVariableDeclaration instead and handle definite assignment assertions */
const node = <VariableDeclaration>createSynthesizedNode(SyntaxKind.VariableDeclaration);
node.name = asName(name);
node.type = type;
node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined;
return node;
}
export function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined) {
/* Internally, one should probably use updateTypeScriptVariableDeclaration instead and handle definite assignment assertions */
return node.name !== name
|| node.type !== type
|| node.initializer !== initializer
? updateNode(createVariableDeclaration(name, type, initializer), node)
: node;
}
/* @internal */
export function createTypeScriptVariableDeclaration(name: string | BindingName, exclaimationToken?: Token<SyntaxKind.ExclamationToken>, type?: TypeNode, initializer?: Expression) {
const node = <VariableDeclaration>createSynthesizedNode(SyntaxKind.VariableDeclaration);
node.name = asName(name);
node.type = type;
node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined;
node.exclamationToken = exclaimationToken;
return node;
}
/* @internal */
export function updateTypeScriptVariableDeclaration(node: VariableDeclaration, name: BindingName, exclaimationToken: Token<SyntaxKind.ExclamationToken> | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
return node.name !== name
|| node.type !== type
|| node.initializer !== initializer
|| node.exclamationToken !== exclaimationToken
? updateNode(createTypeScriptVariableDeclaration(name, exclaimationToken, type, initializer), node)
: node;
}
export function createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags = NodeFlags.None) {
const node = <VariableDeclarationList>createSynthesizedNode(SyntaxKind.VariableDeclarationList);
node.flags |= flags & NodeFlags.BlockScoped;
node.declarations = createNodeArray(declarations);
return node;
}
export function updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]) {
return node.declarations !== declarations
? updateNode(createVariableDeclarationList(declarations, node.flags), node)
: node;
}
export function createFunctionDeclaration(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
asteriskToken: AsteriskToken | undefined,
name: string | Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
body: Block | undefined) {
const node = <FunctionDeclaration>createSynthesizedNode(SyntaxKind.FunctionDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.asteriskToken = asteriskToken;
node.name = asName(name);
node.typeParameters = asNodeArray(typeParameters);
node.parameters = createNodeArray(parameters);
node.type = type;
node.body = body;
return node;
}
export function updateFunctionDeclaration(
node: FunctionDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
asteriskToken: AsteriskToken | undefined,
name: Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
parameters: readonly ParameterDeclaration[],
type: TypeNode | undefined,
body: Block | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.asteriskToken !== asteriskToken
|| node.name !== name
|| node.typeParameters !== typeParameters
|| node.parameters !== parameters
|| node.type !== type
|| node.body !== body
? updateNode(createFunctionDeclaration(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body), node)
: node;
}
/* @internal */
export function updateFunctionLikeBody(declaration: FunctionLikeDeclaration, body: Block): FunctionLikeDeclaration {
switch (declaration.kind) {
case SyntaxKind.FunctionDeclaration:
return createFunctionDeclaration(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body);
case SyntaxKind.MethodDeclaration:
return createMethod(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.questionToken, declaration.typeParameters, declaration.parameters, declaration.type, body);
case SyntaxKind.GetAccessor:
return createGetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, declaration.type, body);
case SyntaxKind.SetAccessor:
return createSetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, body);
case SyntaxKind.Constructor:
return createConstructor(declaration.decorators, declaration.modifiers, declaration.parameters, body);
case SyntaxKind.FunctionExpression:
return createFunctionExpression(declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body);
case SyntaxKind.ArrowFunction:
return createArrowFunction(declaration.modifiers, declaration.typeParameters, declaration.parameters, declaration.type, declaration.equalsGreaterThanToken, body);
}
}
export function createClassDeclaration(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
heritageClauses: readonly HeritageClause[] | undefined,
members: readonly ClassElement[]) {
const node = <ClassDeclaration>createSynthesizedNode(SyntaxKind.ClassDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.typeParameters = asNodeArray(typeParameters);
node.heritageClauses = asNodeArray(heritageClauses);
node.members = createNodeArray(members);
return node;
}
export function updateClassDeclaration(
node: ClassDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: Identifier | undefined,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
heritageClauses: readonly HeritageClause[] | undefined,
members: readonly ClassElement[]) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.typeParameters !== typeParameters
|| node.heritageClauses !== heritageClauses
|| node.members !== members
? updateNode(createClassDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node)
: node;
}
export function createInterfaceDeclaration(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | Identifier,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
heritageClauses: readonly HeritageClause[] | undefined,
members: readonly TypeElement[]) {
const node = <InterfaceDeclaration>createSynthesizedNode(SyntaxKind.InterfaceDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.typeParameters = asNodeArray(typeParameters);
node.heritageClauses = asNodeArray(heritageClauses);
node.members = createNodeArray(members);
return node;
}
export function updateInterfaceDeclaration(
node: InterfaceDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: Identifier,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
heritageClauses: readonly HeritageClause[] | undefined,
members: readonly TypeElement[]) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.typeParameters !== typeParameters
|| node.heritageClauses !== heritageClauses
|| node.members !== members
? updateNode(createInterfaceDeclaration(decorators, modifiers, name, typeParameters, heritageClauses, members), node)
: node;
}
export function createTypeAliasDeclaration(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | Identifier,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
type: TypeNode) {
const node = <TypeAliasDeclaration>createSynthesizedNode(SyntaxKind.TypeAliasDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.typeParameters = asNodeArray(typeParameters);
node.type = type;
return node;
}
export function updateTypeAliasDeclaration(
node: TypeAliasDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: Identifier,
typeParameters: readonly TypeParameterDeclaration[] | undefined,
type: TypeNode) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.typeParameters !== typeParameters
|| node.type !== type
? updateNode(createTypeAliasDeclaration(decorators, modifiers, name, typeParameters, type), node)
: node;
}
export function createEnumDeclaration(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: string | Identifier,
members: readonly EnumMember[]) {
const node = <EnumDeclaration>createSynthesizedNode(SyntaxKind.EnumDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.members = createNodeArray(members);
return node;
}
export function updateEnumDeclaration(
node: EnumDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
name: Identifier,
members: readonly EnumMember[]) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.members !== members
? updateNode(createEnumDeclaration(decorators, modifiers, name, members), node)
: node;
}
export function createModuleDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags = NodeFlags.None) {
const node = <ModuleDeclaration>createSynthesizedNode(SyntaxKind.ModuleDeclaration);
node.flags |= flags & (NodeFlags.Namespace | NodeFlags.NestedNamespace | NodeFlags.GlobalAugmentation);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = name;
node.body = body;
return node;
}
export function updateModuleDeclaration(node: ModuleDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.body !== body
? updateNode(createModuleDeclaration(decorators, modifiers, name, body, node.flags), node)
: node;
}
export function createModuleBlock(statements: readonly Statement[]) {
const node = <ModuleBlock>createSynthesizedNode(SyntaxKind.ModuleBlock);
node.statements = createNodeArray(statements);
return node;
}
export function updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]) {
return node.statements !== statements
? updateNode(createModuleBlock(statements), node)
: node;
}
export function createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock {
const node = <CaseBlock>createSynthesizedNode(SyntaxKind.CaseBlock);
node.clauses = createNodeArray(clauses);
return node;
}
export function updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]) {
return node.clauses !== clauses
? updateNode(createCaseBlock(clauses), node)
: node;
}
export function createNamespaceExportDeclaration(name: string | Identifier) {
const node = <NamespaceExportDeclaration>createSynthesizedNode(SyntaxKind.NamespaceExportDeclaration);
node.name = asName(name);
return node;
}
export function updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier) {
return node.name !== name
? updateNode(createNamespaceExportDeclaration(name), node)
: node;
}
export function createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference) {
const node = <ImportEqualsDeclaration>createSynthesizedNode(SyntaxKind.ImportEqualsDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.name = asName(name);
node.moduleReference = moduleReference;
return node;
}
export function updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.name !== name
|| node.moduleReference !== moduleReference
? updateNode(createImportEqualsDeclaration(decorators, modifiers, name, moduleReference), node)
: node;
}
export function createImportDeclaration(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
importClause: ImportClause | undefined,
moduleSpecifier: Expression): ImportDeclaration {
const node = <ImportDeclaration>createSynthesizedNode(SyntaxKind.ImportDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.importClause = importClause;
node.moduleSpecifier = moduleSpecifier;
return node;
}
export function updateImportDeclaration(
node: ImportDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
importClause: ImportClause | undefined,
moduleSpecifier: Expression) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.importClause !== importClause
|| node.moduleSpecifier !== moduleSpecifier
? updateNode(createImportDeclaration(decorators, modifiers, importClause, moduleSpecifier), node)
: node;
}
export function createImportClause(name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly = false): ImportClause {
const node = <ImportClause>createSynthesizedNode(SyntaxKind.ImportClause);
node.name = name;
node.namedBindings = namedBindings;
node.isTypeOnly = isTypeOnly;
return node;
}
export function updateImportClause(node: ImportClause, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined, isTypeOnly: boolean) {
return node.name !== name
|| node.namedBindings !== namedBindings
|| node.isTypeOnly !== isTypeOnly
? updateNode(createImportClause(name, namedBindings, isTypeOnly), node)
: node;
}
export function createNamespaceImport(name: Identifier): NamespaceImport {
const node = <NamespaceImport>createSynthesizedNode(SyntaxKind.NamespaceImport);
node.name = name;
return node;
}
export function createNamespaceExport(name: Identifier): NamespaceExport {
const node = <NamespaceExport>createSynthesizedNode(SyntaxKind.NamespaceExport);
node.name = name;
return node;
}
export function updateNamespaceImport(node: NamespaceImport, name: Identifier) {
return node.name !== name
? updateNode(createNamespaceImport(name), node)
: node;
}
export function updateNamespaceExport(node: NamespaceExport, name: Identifier) {
return node.name !== name
? updateNode(createNamespaceExport(name), node)
: node;
}
export function createNamedImports(elements: readonly ImportSpecifier[]): NamedImports {
const node = <NamedImports>createSynthesizedNode(SyntaxKind.NamedImports);
node.elements = createNodeArray(elements);
return node;
}
export function updateNamedImports(node: NamedImports, elements: readonly ImportSpecifier[]) {
return node.elements !== elements
? updateNode(createNamedImports(elements), node)
: node;
}
export function createImportSpecifier(propertyName: Identifier | undefined, name: Identifier) {
const node = <ImportSpecifier>createSynthesizedNode(SyntaxKind.ImportSpecifier);
node.propertyName = propertyName;
node.name = name;
return node;
}
export function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
return node.propertyName !== propertyName
|| node.name !== name
? updateNode(createImportSpecifier(propertyName, name), node)
: node;
}
export function createExportAssignment(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression) {
const node = <ExportAssignment>createSynthesizedNode(SyntaxKind.ExportAssignment);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.isExportEquals = isExportEquals;
node.expression = isExportEquals ? parenthesizeBinaryOperand(SyntaxKind.EqualsToken, expression, /*isLeftSideOfBinary*/ false, /*leftOperand*/ undefined) : parenthesizeDefaultExpression(expression);
return node;
}
export function updateExportAssignment(node: ExportAssignment, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, expression: Expression) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.expression !== expression
? updateNode(createExportAssignment(decorators, modifiers, node.isExportEquals, expression), node)
: node;
}
export function createExportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, isTypeOnly = false) {
const node = <ExportDeclaration>createSynthesizedNode(SyntaxKind.ExportDeclaration);
node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers);
node.isTypeOnly = isTypeOnly;
node.exportClause = exportClause;
node.moduleSpecifier = moduleSpecifier;
return node;
}
export function updateExportDeclaration(
node: ExportDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
exportClause: NamedExportBindings | undefined,
moduleSpecifier: Expression | undefined,
isTypeOnly: boolean) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.isTypeOnly !== isTypeOnly
|| node.exportClause !== exportClause
|| node.moduleSpecifier !== moduleSpecifier
? updateNode(createExportDeclaration(decorators, modifiers, exportClause, moduleSpecifier, isTypeOnly), node)
: node;
}
/* @internal */
export function createEmptyExports() {
return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([]), /*moduleSpecifier*/ undefined);
}
export function createNamedExports(elements: readonly ExportSpecifier[]) {
const node = <NamedExports>createSynthesizedNode(SyntaxKind.NamedExports);
node.elements = createNodeArray(elements);
return node;
}
export function updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]) {
return node.elements !== elements
? updateNode(createNamedExports(elements), node)
: node;
}
export function createExportSpecifier(propertyName: string | Identifier | undefined, name: string | Identifier) {
const node = <ExportSpecifier>createSynthesizedNode(SyntaxKind.ExportSpecifier);
node.propertyName = asName(propertyName);
node.name = asName(name);
return node;
}
export function updateExportSpecifier(node: ExportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
return node.propertyName !== propertyName
|| node.name !== name
? updateNode(createExportSpecifier(propertyName, name), node)
: node;
}
// Module references
export function createExternalModuleReference(expression: Expression) {
const node = <ExternalModuleReference>createSynthesizedNode(SyntaxKind.ExternalModuleReference);
node.expression = expression;
return node;
}
export function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression) {
return node.expression !== expression
? updateNode(createExternalModuleReference(expression), node)
: node;
}
// JSDoc
export function createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression {
const node = createSynthesizedNode(SyntaxKind.JSDocTypeExpression) as JSDocTypeExpression;
node.type = type;
return node;
}
export function createJSDocTypeTag(typeExpression: JSDocTypeExpression, comment?: string): JSDocTypeTag {
const tag = createJSDocTag<JSDocTypeTag>(SyntaxKind.JSDocTypeTag, "type", comment);
tag.typeExpression = typeExpression;
return tag;
}
export function createJSDocReturnTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocReturnTag {
const tag = createJSDocTag<JSDocReturnTag>(SyntaxKind.JSDocReturnTag, "returns", comment);
tag.typeExpression = typeExpression;
return tag;
}
export function createJSDocThisTag(typeExpression?: JSDocTypeExpression): JSDocThisTag {
const tag = createJSDocTag<JSDocThisTag>(SyntaxKind.JSDocThisTag, "this");
tag.typeExpression = typeExpression;
return tag;
}
/**
* @deprecated Use `createJSDocParameterTag` to create jsDoc param tag.
*/
export function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
const tag = createJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param", comment);
tag.typeExpression = typeExpression;
tag.name = name;
tag.isBracketed = isBracketed;
return tag;
}
export function createJSDocClassTag(comment?: string): JSDocClassTag {
return createJSDocTag<JSDocClassTag>(SyntaxKind.JSDocClassTag, "class", comment);
}
export function createJSDocComment(comment?: string | undefined, tags?: NodeArray<JSDocTag> | undefined) {
const node = createSynthesizedNode(SyntaxKind.JSDocComment) as JSDoc;
node.comment = comment;
node.tags = tags;
return node;
}
export function createJSDocTag<T extends JSDocTag>(kind: T["kind"], tagName: string, comment?: string): T {
const node = createSynthesizedNode(kind) as T;
node.tagName = createIdentifier(tagName);
node.comment = comment;
return node;
}
export function createJSDocAugmentsTag(classExpression: JSDocAugmentsTag["class"], comment?: string) {
const tag = createJSDocTag<JSDocAugmentsTag>(SyntaxKind.JSDocAugmentsTag, "augments", comment);
tag.class = classExpression;
return tag;
}
export function createJSDocEnumTag(typeExpression?: JSDocTypeExpression, comment?: string) {
const tag = createJSDocTag<JSDocEnumTag>(SyntaxKind.JSDocEnumTag, "enum", comment);
tag.typeExpression = typeExpression;
return tag;
}
export function createJSDocTemplateTag(constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string) {
const tag = createJSDocTag<JSDocTemplateTag>(SyntaxKind.JSDocTemplateTag, "template", comment);
tag.constraint = constraint;
tag.typeParameters = asNodeArray(typeParameters);
return tag;
}
export function createJSDocTypedefTag(fullName?: JSDocNamespaceDeclaration | Identifier, name?: Identifier, comment?: string, typeExpression?: JSDocTypeExpression | JSDocTypeLiteral) {
const tag = createJSDocTag<JSDocTypedefTag>(SyntaxKind.JSDocTypedefTag, "typedef", comment);
tag.fullName = fullName;
tag.name = name;
tag.typeExpression = typeExpression;
return tag;
}
export function createJSDocCallbackTag(fullName: JSDocNamespaceDeclaration | Identifier | undefined, name: Identifier | undefined, comment: string | undefined, typeExpression: JSDocSignature) {
const tag = createJSDocTag<JSDocCallbackTag>(SyntaxKind.JSDocCallbackTag, "callback", comment);
tag.fullName = fullName;
tag.name = name;
tag.typeExpression = typeExpression;
return tag;
}
export function createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag) {
const tag = createSynthesizedNode(SyntaxKind.JSDocSignature) as JSDocSignature;
tag.typeParameters = typeParameters;
tag.parameters = parameters;
tag.type = type;
return tag;
}
function createJSDocPropertyLikeTag<T extends JSDocPropertyLikeTag>(kind: T["kind"], tagName: "arg" | "argument" | "param", typeExpression: JSDocTypeExpression | undefined, name: EntityName, isNameFirst: boolean, isBracketed: boolean, comment?: string) {
const tag = createJSDocTag<T>(kind, tagName, comment);
tag.typeExpression = typeExpression;
tag.name = name;
tag.isNameFirst = isNameFirst;
tag.isBracketed = isBracketed;
return tag;
}
export function createJSDocPropertyTag(typeExpression: JSDocTypeExpression | undefined, name: EntityName, isNameFirst: boolean, isBracketed: boolean, comment?: string) {
return createJSDocPropertyLikeTag<JSDocPropertyTag>(SyntaxKind.JSDocPropertyTag, "param", typeExpression, name, isNameFirst, isBracketed, comment);
}
export function createJSDocParameterTag(typeExpression: JSDocTypeExpression | undefined, name: EntityName, isNameFirst: boolean, isBracketed: boolean, comment?: string) {
return createJSDocPropertyLikeTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param", typeExpression, name, isNameFirst, isBracketed, comment);
}
export function createJSDocTypeLiteral(jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], isArrayType?: boolean) {
const tag = createSynthesizedNode(SyntaxKind.JSDocTypeLiteral) as JSDocTypeLiteral;
tag.jsDocPropertyTags = jsDocPropertyTags;
tag.isArrayType = isArrayType;
return tag;
}
export function createJSDocImplementsTag(classExpression: JSDocImplementsTag["class"], comment?: string) {
const tag = createJSDocTag<JSDocImplementsTag>(SyntaxKind.JSDocImplementsTag, "implements", comment);
tag.class = classExpression;
return tag;
}
export function createJSDocAuthorTag(comment?: string) {
return createJSDocTag<JSDocAuthorTag>(SyntaxKind.JSDocAuthorTag, "author", comment);
}
export function createJSDocPublicTag() {
return createJSDocTag<JSDocPublicTag>(SyntaxKind.JSDocPublicTag, "public");
}
export function createJSDocPrivateTag() {
return createJSDocTag<JSDocPrivateTag>(SyntaxKind.JSDocPrivateTag, "private");
}
export function createJSDocProtectedTag() {
return createJSDocTag<JSDocProtectedTag>(SyntaxKind.JSDocProtectedTag, "protected");
}
export function createJSDocReadonlyTag() {
return createJSDocTag<JSDocReadonlyTag>(SyntaxKind.JSDocReadonlyTag, "readonly");
}
export function appendJSDocToContainer(node: JSDocContainer, jsdoc: JSDoc) {
node.jsDoc = append(node.jsDoc, jsdoc);
return node;
}
/* @internal */
export function createJSDocVariadicType(type: TypeNode): JSDocVariadicType {
const node = createSynthesizedNode(SyntaxKind.JSDocVariadicType) as JSDocVariadicType;
node.type = type;
return node;
}
/* @internal */
export function updateJSDocVariadicType(node: JSDocVariadicType, type: TypeNode): JSDocVariadicType {
return node.type !== type
? updateNode(createJSDocVariadicType(type), node)
: node;
}
// JSX
export function createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) {
const node = <JsxElement>createSynthesizedNode(SyntaxKind.JsxElement);
node.openingElement = openingElement;
node.children = createNodeArray(children);
node.closingElement = closingElement;
return node;
}
export function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) {
return node.openingElement !== openingElement
|| node.children !== children
|| node.closingElement !== closingElement
? updateNode(createJsxElement(openingElement, children, closingElement), node)
: node;
}
export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
const node = <JsxSelfClosingElement>createSynthesizedNode(SyntaxKind.JsxSelfClosingElement);
node.tagName = tagName;
node.typeArguments = asNodeArray(typeArguments);
node.attributes = attributes;
return node;
}
export function updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
return node.tagName !== tagName
|| node.typeArguments !== typeArguments
|| node.attributes !== attributes
? updateNode(createJsxSelfClosingElement(tagName, typeArguments, attributes), node)
: node;
}
export function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
const node = <JsxOpeningElement>createSynthesizedNode(SyntaxKind.JsxOpeningElement);
node.tagName = tagName;
node.typeArguments = asNodeArray(typeArguments);
node.attributes = attributes;
return node;
}
export function updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes) {
return node.tagName !== tagName
|| node.typeArguments !== typeArguments
|| node.attributes !== attributes
? updateNode(createJsxOpeningElement(tagName, typeArguments, attributes), node)
: node;
}
export function createJsxClosingElement(tagName: JsxTagNameExpression) {
const node = <JsxClosingElement>createSynthesizedNode(SyntaxKind.JsxClosingElement);
node.tagName = tagName;
return node;
}
export function updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression) {
return node.tagName !== tagName
? updateNode(createJsxClosingElement(tagName), node)
: node;
}
export function createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) {
const node = <JsxFragment>createSynthesizedNode(SyntaxKind.JsxFragment);
node.openingFragment = openingFragment;
node.children = createNodeArray(children);
node.closingFragment = closingFragment;
return node;
}
export function createJsxText(text: string, containsOnlyTriviaWhiteSpaces?: boolean) {
const node = <JsxText>createSynthesizedNode(SyntaxKind.JsxText);
node.text = text;
node.containsOnlyTriviaWhiteSpaces = !!containsOnlyTriviaWhiteSpaces;
return node;
}
export function updateJsxText(node: JsxText, text: string, containsOnlyTriviaWhiteSpaces?: boolean) {
return node.text !== text
|| node.containsOnlyTriviaWhiteSpaces !== containsOnlyTriviaWhiteSpaces
? updateNode(createJsxText(text, containsOnlyTriviaWhiteSpaces), node)
: node;
}
export function createJsxOpeningFragment() {
return <JsxOpeningFragment>createSynthesizedNode(SyntaxKind.JsxOpeningFragment);
}
export function createJsxJsxClosingFragment() {
return <JsxClosingFragment>createSynthesizedNode(SyntaxKind.JsxClosingFragment);
}
export function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment) {
return node.openingFragment !== openingFragment
|| node.children !== children
|| node.closingFragment !== closingFragment
? updateNode(createJsxFragment(openingFragment, children, closingFragment), node)
: node;
}
export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression) {
const node = <JsxAttribute>createSynthesizedNode(SyntaxKind.JsxAttribute);
node.name = name;
node.initializer = initializer;
return node;
}
export function updateJsxAttribute(node: JsxAttribute, name: Identifier, initializer: StringLiteral | JsxExpression) {
return node.name !== name
|| node.initializer !== initializer
? updateNode(createJsxAttribute(name, initializer), node)
: node;
}
export function createJsxAttributes(properties: readonly JsxAttributeLike[]) {
const node = <JsxAttributes>createSynthesizedNode(SyntaxKind.JsxAttributes);
node.properties = createNodeArray(properties);
return node;
}
export function updateJsxAttributes(node: JsxAttributes, properties: readonly JsxAttributeLike[]) {
return node.properties !== properties
? updateNode(createJsxAttributes(properties), node)
: node;
}
export function createJsxSpreadAttribute(expression: Expression) {
const node = <JsxSpreadAttribute>createSynthesizedNode(SyntaxKind.JsxSpreadAttribute);
node.expression = expression;
return node;
}
export function updateJsxSpreadAttribute(node: JsxSpreadAttribute, expression: Expression) {
return node.expression !== expression
? updateNode(createJsxSpreadAttribute(expression), node)
: node;
}
export function createJsxExpression(dotDotDotToken: DotDotDotToken | undefined, expression: Expression | undefined) {
const node = <JsxExpression>createSynthesizedNode(SyntaxKind.JsxExpression);
node.dotDotDotToken = dotDotDotToken;
node.expression = expression;
return node;
}
export function updateJsxExpression(node: JsxExpression, expression: Expression | undefined) {
return node.expression !== expression
? updateNode(createJsxExpression(node.dotDotDotToken, expression), node)
: node;
}
// Clauses
export function createCaseClause(expression: Expression, statements: readonly Statement[]) {
const node = <CaseClause>createSynthesizedNode(SyntaxKind.CaseClause);
node.expression = parenthesizeExpressionForList(expression);
node.statements = createNodeArray(statements);
return node;
}
export function updateCaseClause(node: CaseClause, expression: Expression, statements: readonly Statement[]) {
return node.expression !== expression
|| node.statements !== statements
? updateNode(createCaseClause(expression, statements), node)
: node;
}
export function createDefaultClause(statements: readonly Statement[]) {
const node = <DefaultClause>createSynthesizedNode(SyntaxKind.DefaultClause);
node.statements = createNodeArray(statements);
return node;
}
export function updateDefaultClause(node: DefaultClause, statements: readonly Statement[]) {
return node.statements !== statements
? updateNode(createDefaultClause(statements), node)
: node;
}
export function createHeritageClause(token: HeritageClause["token"], types: readonly ExpressionWithTypeArguments[]) {
const node = <HeritageClause>createSynthesizedNode(SyntaxKind.HeritageClause);
node.token = token;
node.types = createNodeArray(types);
return node;
}
export function updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]) {
return node.types !== types
? updateNode(createHeritageClause(node.token, types), node)
: node;
}
export function createCatchClause(variableDeclaration: string | VariableDeclaration | undefined, block: Block) {
const node = <CatchClause>createSynthesizedNode(SyntaxKind.CatchClause);
node.variableDeclaration = isString(variableDeclaration) ? createVariableDeclaration(variableDeclaration) : variableDeclaration;
node.block = block;
return node;
}
export function updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block) {
return node.variableDeclaration !== variableDeclaration
|| node.block !== block
? updateNode(createCatchClause(variableDeclaration, block), node)
: node;
}
// Property assignments
export function createPropertyAssignment(name: string | PropertyName, initializer: Expression) {
const node = <PropertyAssignment>createSynthesizedNode(SyntaxKind.PropertyAssignment);
node.name = asName(name);
node.questionToken = undefined;
node.initializer = parenthesizeExpressionForList(initializer);
return node;
}
export function updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression) {
return node.name !== name
|| node.initializer !== initializer
? updateNode(createPropertyAssignment(name, initializer), node)
: node;
}
export function createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression) {
const node = <ShorthandPropertyAssignment>createSynthesizedNode(SyntaxKind.ShorthandPropertyAssignment);
node.name = asName(name);
node.objectAssignmentInitializer = objectAssignmentInitializer !== undefined ? parenthesizeExpressionForList(objectAssignmentInitializer) : undefined;
return node;
}
export function updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined) {
return node.name !== name
|| node.objectAssignmentInitializer !== objectAssignmentInitializer
? updateNode(createShorthandPropertyAssignment(name, objectAssignmentInitializer), node)
: node;
}
export function createSpreadAssignment(expression: Expression) {
const node = <SpreadAssignment>createSynthesizedNode(SyntaxKind.SpreadAssignment);
node.expression = parenthesizeExpressionForList(expression);
return node;
}
export function updateSpreadAssignment(node: SpreadAssignment, expression: Expression) {
return node.expression !== expression
? updateNode(createSpreadAssignment(expression), node)
: node;
}
// Enum
export function createEnumMember(name: string | PropertyName, initializer?: Expression) {
const node = <EnumMember>createSynthesizedNode(SyntaxKind.EnumMember);
node.name = asName(name);
node.initializer = initializer && parenthesizeExpressionForList(initializer);
return node;
}
export function updateEnumMember(node: EnumMember, name: PropertyName, initializer: Expression | undefined) {
return node.name !== name
|| node.initializer !== initializer
? updateNode(createEnumMember(name, initializer), node)
: node;
}
// Top-level nodes
export function updateSourceFileNode(node: SourceFile, statements: readonly Statement[], isDeclarationFile?: boolean, referencedFiles?: SourceFile["referencedFiles"], typeReferences?: SourceFile["typeReferenceDirectives"], hasNoDefaultLib?: boolean, libReferences?: SourceFile["libReferenceDirectives"]) {
if (
node.statements !== statements ||
(isDeclarationFile !== undefined && node.isDeclarationFile !== isDeclarationFile) ||
(referencedFiles !== undefined && node.referencedFiles !== referencedFiles) ||
(typeReferences !== undefined && node.typeReferenceDirectives !== typeReferences) ||
(libReferences !== undefined && node.libReferenceDirectives !== libReferences) ||
(hasNoDefaultLib !== undefined && node.hasNoDefaultLib !== hasNoDefaultLib)
) {
const updated = <SourceFile>createSynthesizedNode(SyntaxKind.SourceFile);
updated.flags |= node.flags;
updated.statements = createNodeArray(statements);
updated.endOfFileToken = node.endOfFileToken;
updated.fileName = node.fileName;
updated.path = node.path;
updated.text = node.text;
updated.isDeclarationFile = isDeclarationFile === undefined ? node.isDeclarationFile : isDeclarationFile;
updated.referencedFiles = referencedFiles === undefined ? node.referencedFiles : referencedFiles;
updated.typeReferenceDirectives = typeReferences === undefined ? node.typeReferenceDirectives : typeReferences;
updated.hasNoDefaultLib = hasNoDefaultLib === undefined ? node.hasNoDefaultLib : hasNoDefaultLib;
updated.libReferenceDirectives = libReferences === undefined ? node.libReferenceDirectives : libReferences;
if (node.amdDependencies !== undefined) updated.amdDependencies = node.amdDependencies;
if (node.moduleName !== undefined) updated.moduleName = node.moduleName;
if (node.languageVariant !== undefined) updated.languageVariant = node.languageVariant;
if (node.renamedDependencies !== undefined) updated.renamedDependencies = node.renamedDependencies;
if (node.languageVersion !== undefined) updated.languageVersion = node.languageVersion;
if (node.scriptKind !== undefined) updated.scriptKind = node.scriptKind;
if (node.externalModuleIndicator !== undefined) updated.externalModuleIndicator = node.externalModuleIndicator;
if (node.commonJsModuleIndicator !== undefined) updated.commonJsModuleIndicator = node.commonJsModuleIndicator;
if (node.identifiers !== undefined) updated.identifiers = node.identifiers;
if (node.nodeCount !== undefined) updated.nodeCount = node.nodeCount;
if (node.identifierCount !== undefined) updated.identifierCount = node.identifierCount;
if (node.symbolCount !== undefined) updated.symbolCount = node.symbolCount;
if (node.parseDiagnostics !== undefined) updated.parseDiagnostics = node.parseDiagnostics;
if (node.bindDiagnostics !== undefined) updated.bindDiagnostics = node.bindDiagnostics;
if (node.bindSuggestionDiagnostics !== undefined) updated.bindSuggestionDiagnostics = node.bindSuggestionDiagnostics;
if (node.lineMap !== undefined) updated.lineMap = node.lineMap;
if (node.classifiableNames !== undefined) updated.classifiableNames = node.classifiableNames;
if (node.resolvedModules !== undefined) updated.resolvedModules = node.resolvedModules;
if (node.resolvedTypeReferenceDirectiveNames !== undefined) updated.resolvedTypeReferenceDirectiveNames = node.resolvedTypeReferenceDirectiveNames;
if (node.imports !== undefined) updated.imports = node.imports;
if (node.moduleAugmentations !== undefined) updated.moduleAugmentations = node.moduleAugmentations;
if (node.pragmas !== undefined) updated.pragmas = node.pragmas;
if (node.localJsxFactory !== undefined) updated.localJsxFactory = node.localJsxFactory;
if (node.localJsxNamespace !== undefined) updated.localJsxNamespace = node.localJsxNamespace;
return updateNode(updated, node);
}
return node;
}
/**
* Creates a shallow, memberwise clone of a node for mutation.
*/
export function getMutableClone<T extends Node>(node: T): T {
const clone = getSynthesizedClone(node);
clone.pos = node.pos;
clone.end = node.end;
clone.parent = node.parent;
return clone;
}
// Transformation nodes
/**
* Creates a synthetic statement to act as a placeholder for a not-emitted statement in
* order to preserve comments.
*
* @param original The original statement.
*/
export function createNotEmittedStatement(original: Node) {
const node = <NotEmittedStatement>createSynthesizedNode(SyntaxKind.NotEmittedStatement);
node.original = original;
setTextRange(node, original);
return node;
}
/**
* Creates a synthetic element to act as a placeholder for the end of an emitted declaration in
* order to properly emit exports.
*/
/* @internal */
export function createEndOfDeclarationMarker(original: Node) {
const node = <EndOfDeclarationMarker>createSynthesizedNode(SyntaxKind.EndOfDeclarationMarker);
node.emitNode = {} as EmitNode;
node.original = original;
return node;
}
/**
* Creates a synthetic element to act as a placeholder for the beginning of a merged declaration in
* order to properly emit exports.
*/
/* @internal */
export function createMergeDeclarationMarker(original: Node) {
const node = <MergeDeclarationMarker>createSynthesizedNode(SyntaxKind.MergeDeclarationMarker);
node.emitNode = {} as EmitNode;
node.original = original;
return node;
}
/**
* Creates a synthetic expression to act as a placeholder for a not-emitted expression in
* order to preserve comments or sourcemap positions.
*
* @param expression The inner expression to emit.
* @param original The original outer expression.
* @param location The location for the expression. Defaults to the positions from "original" if provided.
*/
export function createPartiallyEmittedExpression(expression: Expression, original?: Node) {
const node = <PartiallyEmittedExpression>createSynthesizedNode(SyntaxKind.PartiallyEmittedExpression);
node.expression = expression;
node.original = original;
setTextRange(node, original);
return node;
}
export function updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression) {
if (node.expression !== expression) {
return updateNode(createPartiallyEmittedExpression(expression, node.original), node);
}
return node;
}
function flattenCommaElements(node: Expression): Expression | readonly Expression[] {
if (nodeIsSynthesized(node) && !isParseTreeNode(node) && !node.original && !node.emitNode && !node.id) {
if (node.kind === SyntaxKind.CommaListExpression) {
return (<CommaListExpression>node).elements;
}
if (isBinaryExpression(node) && node.operatorToken.kind === SyntaxKind.CommaToken) {
return [node.left, node.right];
}
}
return node;
}
export function createCommaList(elements: readonly Expression[]) {
const node = <CommaListExpression>createSynthesizedNode(SyntaxKind.CommaListExpression);
node.elements = createNodeArray(sameFlatMap(elements, flattenCommaElements));
return node;
}
export function updateCommaList(node: CommaListExpression, elements: readonly Expression[]) {
return node.elements !== elements
? updateNode(createCommaList(elements), node)
: node;
}
/* @internal */
export function createSyntheticReferenceExpression(expression: Expression, thisArg: Expression) {
const node = <SyntheticReferenceExpression>createSynthesizedNode(SyntaxKind.SyntheticReferenceExpression);
node.expression = expression;
node.thisArg = thisArg;
return node;
}
/* @internal */
export function updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression) {
return node.expression !== expression
|| node.thisArg !== thisArg
? updateNode(createSyntheticReferenceExpression(expression, thisArg), node)
: node;
}
export function createBundle(sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) {
const node = <Bundle>createNode(SyntaxKind.Bundle);
node.prepends = prepends;
node.sourceFiles = sourceFiles;
return node;
}
let allUnscopedEmitHelpers: ReadonlyMap<UnscopedEmitHelper> | undefined;
function getAllUnscopedEmitHelpers() {
return allUnscopedEmitHelpers || (allUnscopedEmitHelpers = arrayToMap([
valuesHelper,
readHelper,
spreadHelper,
spreadArraysHelper,
restHelper,
decorateHelper,
metadataHelper,
paramHelper,
awaiterHelper,
assignHelper,
awaitHelper,
asyncGeneratorHelper,
asyncDelegator,
asyncValues,
extendsHelper,
templateObjectHelper,
generatorHelper,
importStarHelper,
importDefaultHelper,
classPrivateFieldGetHelper,
classPrivateFieldSetHelper,
createBindingHelper,
setModuleDefaultHelper
], helper => helper.name));
}
function createUnparsedSource() {
const node = <UnparsedSource>createNode(SyntaxKind.UnparsedSource);
node.prologues = emptyArray;
node.referencedFiles = emptyArray;
node.libReferenceDirectives = emptyArray;
node.getLineAndCharacterOfPosition = pos => getLineAndCharacterOfPosition(node, pos);
return node;
}
export function createUnparsedSourceFile(text: string): UnparsedSource;
export function createUnparsedSourceFile(inputFile: InputFiles, type: "js" | "dts", stripInternal?: boolean): UnparsedSource;
export function createUnparsedSourceFile(text: string, mapPath: string | undefined, map: string | undefined): UnparsedSource;
export function createUnparsedSourceFile(textOrInputFiles: string | InputFiles, mapPathOrType?: string, mapTextOrStripInternal?: string | boolean): UnparsedSource {
const node = createUnparsedSource();
let stripInternal: boolean | undefined;
let bundleFileInfo: BundleFileInfo | undefined;
if (!isString(textOrInputFiles)) {
Debug.assert(mapPathOrType === "js" || mapPathOrType === "dts");
node.fileName = (mapPathOrType === "js" ? textOrInputFiles.javascriptPath : textOrInputFiles.declarationPath) || "";
node.sourceMapPath = mapPathOrType === "js" ? textOrInputFiles.javascriptMapPath : textOrInputFiles.declarationMapPath;
Object.defineProperties(node, {
text: { get() { return mapPathOrType === "js" ? textOrInputFiles.javascriptText : textOrInputFiles.declarationText; } },
sourceMapText: { get() { return mapPathOrType === "js" ? textOrInputFiles.javascriptMapText : textOrInputFiles.declarationMapText; } },
});
if (textOrInputFiles.buildInfo && textOrInputFiles.buildInfo.bundle) {
node.oldFileOfCurrentEmit = textOrInputFiles.oldFileOfCurrentEmit;
Debug.assert(mapTextOrStripInternal === undefined || typeof mapTextOrStripInternal === "boolean");
stripInternal = mapTextOrStripInternal;
bundleFileInfo = mapPathOrType === "js" ? textOrInputFiles.buildInfo.bundle.js : textOrInputFiles.buildInfo.bundle.dts;
if (node.oldFileOfCurrentEmit) {
parseOldFileOfCurrentEmit(node, Debug.checkDefined(bundleFileInfo));
return node;
}
}
}
else {
node.fileName = "";
node.text = textOrInputFiles;
node.sourceMapPath = mapPathOrType;
node.sourceMapText = mapTextOrStripInternal as string;
}
Debug.assert(!node.oldFileOfCurrentEmit);
parseUnparsedSourceFile(node, bundleFileInfo, stripInternal);
return node;
}
function parseUnparsedSourceFile(node: UnparsedSource, bundleFileInfo: BundleFileInfo | undefined, stripInternal: boolean | undefined) {
let prologues: UnparsedPrologue[] | undefined;
let helpers: UnscopedEmitHelper[] | undefined;
let referencedFiles: FileReference[] | undefined;
let typeReferenceDirectives: string[] | undefined;
let libReferenceDirectives: FileReference[] | undefined;
let texts: UnparsedSourceText[] | undefined;
for (const section of bundleFileInfo ? bundleFileInfo.sections : emptyArray) {
switch (section.kind) {
case BundleFileSectionKind.Prologue:
(prologues || (prologues = [])).push(createUnparsedNode(section, node) as UnparsedPrologue);
break;
case BundleFileSectionKind.EmitHelpers:
(helpers || (helpers = [])).push(getAllUnscopedEmitHelpers().get(section.data)!);
break;
case BundleFileSectionKind.NoDefaultLib:
node.hasNoDefaultLib = true;
break;
case BundleFileSectionKind.Reference:
(referencedFiles || (referencedFiles = [])).push({ pos: -1, end: -1, fileName: section.data });
break;
case BundleFileSectionKind.Type:
(typeReferenceDirectives || (typeReferenceDirectives = [])).push(section.data);
break;
case BundleFileSectionKind.Lib:
(libReferenceDirectives || (libReferenceDirectives = [])).push({ pos: -1, end: -1, fileName: section.data });
break;
case BundleFileSectionKind.Prepend:
const prependNode = createUnparsedNode(section, node) as UnparsedPrepend;
let prependTexts: UnparsedTextLike[] | undefined;
for (const text of section.texts) {
if (!stripInternal || text.kind !== BundleFileSectionKind.Internal) {
(prependTexts || (prependTexts = [])).push(createUnparsedNode(text, node) as UnparsedTextLike);
}
}
prependNode.texts = prependTexts || emptyArray;
(texts || (texts = [])).push(prependNode);
break;
case BundleFileSectionKind.Internal:
if (stripInternal) {
if (!texts) texts = [];
break;
}
// falls through
case BundleFileSectionKind.Text:
(texts || (texts = [])).push(createUnparsedNode(section, node) as UnparsedTextLike);
break;
default:
Debug.assertNever(section);
}
}
node.prologues = prologues || emptyArray;
node.helpers = helpers;
node.referencedFiles = referencedFiles || emptyArray;
node.typeReferenceDirectives = typeReferenceDirectives;
node.libReferenceDirectives = libReferenceDirectives || emptyArray;
node.texts = texts || [<UnparsedTextLike>createUnparsedNode({ kind: BundleFileSectionKind.Text, pos: 0, end: node.text.length }, node)];
}
function parseOldFileOfCurrentEmit(node: UnparsedSource, bundleFileInfo: BundleFileInfo) {
Debug.assert(!!node.oldFileOfCurrentEmit);
let texts: UnparsedTextLike[] | undefined;
let syntheticReferences: UnparsedSyntheticReference[] | undefined;
for (const section of bundleFileInfo.sections) {
switch (section.kind) {
case BundleFileSectionKind.Internal:
case BundleFileSectionKind.Text:
(texts || (texts = [])).push(createUnparsedNode(section, node) as UnparsedTextLike);
break;
case BundleFileSectionKind.NoDefaultLib:
case BundleFileSectionKind.Reference:
case BundleFileSectionKind.Type:
case BundleFileSectionKind.Lib:
(syntheticReferences || (syntheticReferences = [])).push(createUnparsedSyntheticReference(section, node));
break;
// Ignore
case BundleFileSectionKind.Prologue:
case BundleFileSectionKind.EmitHelpers:
case BundleFileSectionKind.Prepend:
break;
default:
Debug.assertNever(section);
}
}
node.texts = texts || emptyArray;
node.helpers = map(bundleFileInfo.sources && bundleFileInfo.sources.helpers, name => getAllUnscopedEmitHelpers().get(name)!);
node.syntheticReferences = syntheticReferences;
return node;
}
function mapBundleFileSectionKindToSyntaxKind(kind: BundleFileSectionKind): SyntaxKind {
switch (kind) {
case BundleFileSectionKind.Prologue: return SyntaxKind.UnparsedPrologue;
case BundleFileSectionKind.Prepend: return SyntaxKind.UnparsedPrepend;
case BundleFileSectionKind.Internal: return SyntaxKind.UnparsedInternalText;
case BundleFileSectionKind.Text: return SyntaxKind.UnparsedText;
case BundleFileSectionKind.EmitHelpers:
case BundleFileSectionKind.NoDefaultLib:
case BundleFileSectionKind.Reference:
case BundleFileSectionKind.Type:
case BundleFileSectionKind.Lib:
return Debug.fail(`BundleFileSectionKind: ${kind} not yet mapped to SyntaxKind`);
default:
return Debug.assertNever(kind);
}
}
function createUnparsedNode(section: BundleFileSection, parent: UnparsedSource): UnparsedNode {
const node = createNode(mapBundleFileSectionKindToSyntaxKind(section.kind), section.pos, section.end) as UnparsedNode;
node.parent = parent;
node.data = section.data;
return node;
}
function createUnparsedSyntheticReference(section: BundleFileHasNoDefaultLib | BundleFileReference, parent: UnparsedSource) {
const node = createNode(SyntaxKind.UnparsedSyntheticReference, section.pos, section.end) as UnparsedSyntheticReference;
node.parent = parent;
node.data = section.data;
node.section = section;
return node;
}
export function createInputFiles(
javascriptText: string,
declarationText: string
): InputFiles;
export function createInputFiles(
readFileText: (path: string) => string | undefined,
javascriptPath: string,
javascriptMapPath: string | undefined,
declarationPath: string,
declarationMapPath: string | undefined,
buildInfoPath: string | undefined
): InputFiles;
export function createInputFiles(
javascriptText: string,
declarationText: string,
javascriptMapPath: string | undefined,
javascriptMapText: string | undefined,
declarationMapPath: string | undefined,
declarationMapText: string | undefined
): InputFiles;
/*@internal*/
export function createInputFiles(
javascriptText: string,
declarationText: string,
javascriptMapPath: string | undefined,
javascriptMapText: string | undefined,
declarationMapPath: string | undefined,
declarationMapText: string | undefined,
javascriptPath: string | undefined,
declarationPath: string | undefined,
buildInfoPath?: string | undefined,
buildInfo?: BuildInfo,
oldFileOfCurrentEmit?: boolean
): InputFiles;
export function createInputFiles(
javascriptTextOrReadFileText: string | ((path: string) => string | undefined),
declarationTextOrJavascriptPath: string,
javascriptMapPath?: string,
javascriptMapTextOrDeclarationPath?: string,
declarationMapPath?: string,
declarationMapTextOrBuildInfoPath?: string,
javascriptPath?: string | undefined,
declarationPath?: string | undefined,
buildInfoPath?: string | undefined,
buildInfo?: BuildInfo,
oldFileOfCurrentEmit?: boolean
): InputFiles {
const node = <InputFiles>createNode(SyntaxKind.InputFiles);
if (!isString(javascriptTextOrReadFileText)) {
const cache = createMap<string | false>();
const textGetter = (path: string | undefined) => {
if (path === undefined) return undefined;
let value = cache.get(path);
if (value === undefined) {
value = javascriptTextOrReadFileText(path);
cache.set(path, value !== undefined ? value : false);
}
return value !== false ? value as string : undefined;
};
const definedTextGetter = (path: string) => {
const result = textGetter(path);
return result !== undefined ? result : `/* Input file ${path} was missing */\r\n`;
};
let buildInfo: BuildInfo | false;
const getAndCacheBuildInfo = (getText: () => string | undefined) => {
if (buildInfo === undefined) {
const result = getText();
buildInfo = result !== undefined ? getBuildInfo(result) : false;
}
return buildInfo || undefined;
};
node.javascriptPath = declarationTextOrJavascriptPath;
node.javascriptMapPath = javascriptMapPath;
node.declarationPath = Debug.checkDefined(javascriptMapTextOrDeclarationPath);
node.declarationMapPath = declarationMapPath;
node.buildInfoPath = declarationMapTextOrBuildInfoPath;
Object.defineProperties(node, {
javascriptText: { get() { return definedTextGetter(declarationTextOrJavascriptPath); } },
javascriptMapText: { get() { return textGetter(javascriptMapPath); } }, // TODO:: if there is inline sourceMap in jsFile, use that
declarationText: { get() { return definedTextGetter(Debug.checkDefined(javascriptMapTextOrDeclarationPath)); } },
declarationMapText: { get() { return textGetter(declarationMapPath); } }, // TODO:: if there is inline sourceMap in dtsFile, use that
buildInfo: { get() { return getAndCacheBuildInfo(() => textGetter(declarationMapTextOrBuildInfoPath)); } }
});
}
else {
node.javascriptText = javascriptTextOrReadFileText;
node.javascriptMapPath = javascriptMapPath;
node.javascriptMapText = javascriptMapTextOrDeclarationPath;
node.declarationText = declarationTextOrJavascriptPath;
node.declarationMapPath = declarationMapPath;
node.declarationMapText = declarationMapTextOrBuildInfoPath;
node.javascriptPath = javascriptPath;
node.declarationPath = declarationPath;
node.buildInfoPath = buildInfoPath;
node.buildInfo = buildInfo;
node.oldFileOfCurrentEmit = oldFileOfCurrentEmit;
}
return node;
}
export function updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends: readonly (UnparsedSource | InputFiles)[] = emptyArray) {
if (node.sourceFiles !== sourceFiles || node.prepends !== prepends) {
return createBundle(sourceFiles, prepends);
}
return node;
}
// Compound nodes
export function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression;
export function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
export function createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) {
return createCall(
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ param ? [param] : [],
/*type*/ undefined,
createBlock(statements, /*multiLine*/ true)
),
/*typeArguments*/ undefined,
/*argumentsArray*/ paramValue ? [paramValue] : []
);
}
export function createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression;
export function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
export function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) {
return createCall(
createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ param ? [param] : [],
/*type*/ undefined,
/*equalsGreaterThanToken*/ undefined,
createBlock(statements, /*multiLine*/ true)
),
/*typeArguments*/ undefined,
/*argumentsArray*/ paramValue ? [paramValue] : []
);
}
export function createComma(left: Expression, right: Expression) {
return <Expression>createBinary(left, SyntaxKind.CommaToken, right);
}
export function createLessThan(left: Expression, right: Expression) {
return <Expression>createBinary(left, SyntaxKind.LessThanToken, right);
}
export function createAssignment(left: ObjectLiteralExpression | ArrayLiteralExpression, right: Expression): DestructuringAssignment;
export function createAssignment(left: Expression, right: Expression): BinaryExpression;
export function createAssignment(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.EqualsToken, right);
}
export function createStrictEquality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.EqualsEqualsEqualsToken, right);
}
export function createStrictInequality(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.ExclamationEqualsEqualsToken, right);
}
export function createAdd(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.PlusToken, right);
}
export function createSubtract(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.MinusToken, right);
}
export function createPostfixIncrement(operand: Expression) {
return createPostfix(operand, SyntaxKind.PlusPlusToken);
}
export function createLogicalAnd(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.AmpersandAmpersandToken, right);
}
export function createLogicalOr(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.BarBarToken, right);
}
export function createNullishCoalesce(left: Expression, right: Expression) {
return createBinary(left, SyntaxKind.QuestionQuestionToken, right);
}
export function createLogicalNot(operand: Expression) {
return createPrefix(SyntaxKind.ExclamationToken, operand);
}
export function createVoidZero() {
return createVoid(createLiteral(0));
}
export function createExportDefault(expression: Expression) {
return createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, /*isExportEquals*/ false, expression);
}
export function createExternalModuleExport(exportName: Identifier) {
return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([createExportSpecifier(/*propertyName*/ undefined, exportName)]));
}
// Utilities
function asName<T extends Identifier | BindingName | PropertyName | EntityName | ThisTypeNode | undefined>(name: string | T): T | Identifier {
return isString(name) ? createIdentifier(name) : name;
}
function asExpression<T extends Expression | undefined>(value: string | number | boolean | T): T | StringLiteral | NumericLiteral | BooleanLiteral {
return typeof value === "string" ? createStringLiteral(value) :
typeof value === "number" ? createNumericLiteral(""+value) :
typeof value === "boolean" ? value ? createTrue() : createFalse() :
value;
}
function asNodeArray<T extends Node>(array: readonly T[]): NodeArray<T>;
function asNodeArray<T extends Node>(array: readonly T[] | undefined): NodeArray<T> | undefined;
function asNodeArray<T extends Node>(array: readonly T[] | undefined): NodeArray<T> | undefined {
return array ? createNodeArray(array) : undefined;
}
function asToken<TKind extends SyntaxKind>(value: TKind | Token<TKind>): Token<TKind> {
return typeof value === "number" ? createToken(value) : value;
}
function asEmbeddedStatement<T extends Node>(statement: T): T | EmptyStatement;
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined;
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined {
return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement;
}
/**
* Clears any EmitNode entries from parse-tree nodes.
* @param sourceFile A source file.
*/
export function disposeEmitNodes(sourceFile: SourceFile) {
// During transformation we may need to annotate a parse tree node with transient
// transformation properties. As parse tree nodes live longer than transformation
// nodes, we need to make sure we reclaim any memory allocated for custom ranges
// from these nodes to ensure we do not hold onto entire subtrees just for position
// information. We also need to reset these nodes to a pre-transformation state
// for incremental parsing scenarios so that we do not impact later emit.
sourceFile = getSourceFileOfNode(getParseTreeNode(sourceFile));
const emitNode = sourceFile && sourceFile.emitNode;
const annotatedNodes = emitNode && emitNode.annotatedNodes;
if (annotatedNodes) {
for (const node of annotatedNodes) {
node.emitNode = undefined;
}
}
}
/**
* Associates a node with the current transformation, initializing
* various transient transformation properties.
*/
/* @internal */
export function getOrCreateEmitNode(node: Node): EmitNode {
if (!node.emitNode) {
if (isParseTreeNode(node)) {
// To avoid holding onto transformation artifacts, we keep track of any
// parse tree node we are annotating. This allows us to clean them up after
// all transformations have completed.
if (node.kind === SyntaxKind.SourceFile) {
return node.emitNode = { annotatedNodes: [node] } as EmitNode;
}
const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node)));
getOrCreateEmitNode(sourceFile).annotatedNodes!.push(node);
}
node.emitNode = {} as EmitNode;
}
return node.emitNode;
}
/**
* Sets `EmitFlags.NoComments` on a node and removes any leading and trailing synthetic comments.
* @internal
*/
export function removeAllComments<T extends Node>(node: T): T {
const emitNode = getOrCreateEmitNode(node);
emitNode.flags |= EmitFlags.NoComments;
emitNode.leadingComments = undefined;
emitNode.trailingComments = undefined;
return node;
}
export function setTextRange<T extends TextRange>(range: T, location: TextRange | undefined): T {
if (location) {
range.pos = location.pos;
range.end = location.end;
}
return range;
}
/**
* Sets flags that control emit behavior of a node.
*/
export function setEmitFlags<T extends Node>(node: T, emitFlags: EmitFlags) {
getOrCreateEmitNode(node).flags = emitFlags;
return node;
}
/**
* Sets flags that control emit behavior of a node.
*/
/* @internal */
export function addEmitFlags<T extends Node>(node: T, emitFlags: EmitFlags) {
const emitNode = getOrCreateEmitNode(node);
emitNode.flags = emitNode.flags | emitFlags;
return node;
}
/**
* Gets a custom text range to use when emitting source maps.
*/
export function getSourceMapRange(node: Node): SourceMapRange {
const emitNode = node.emitNode;
return (emitNode && emitNode.sourceMapRange) || node;
}
/**
* Sets a custom text range to use when emitting source maps.
*/
export function setSourceMapRange<T extends Node>(node: T, range: SourceMapRange | undefined) {
getOrCreateEmitNode(node).sourceMapRange = range;
return node;
}
let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource;
/**
* Create an external source map source file reference
*/
export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource {
return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia);
}
/**
* Gets the TextRange to use for source maps for a token of a node.
*/
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): SourceMapRange | undefined {
const emitNode = node.emitNode;
const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges;
return tokenSourceMapRanges && tokenSourceMapRanges[token];
}
/**
* Sets the TextRange to use for source maps for a token of a node.
*/
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: SourceMapRange | undefined) {
const emitNode = getOrCreateEmitNode(node);
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []);
tokenSourceMapRanges[token] = range;
return node;
}
/**
* Gets a custom text range to use when emitting comments.
*/
/*@internal*/
export function getStartsOnNewLine(node: Node) {
const emitNode = node.emitNode;
return emitNode && emitNode.startsOnNewLine;
}
/**
* Sets a custom text range to use when emitting comments.
*/
/*@internal*/
export function setStartsOnNewLine<T extends Node>(node: T, newLine: boolean) {
getOrCreateEmitNode(node).startsOnNewLine = newLine;
return node;
}
/**
* Gets a custom text range to use when emitting comments.
*/
export function getCommentRange(node: Node) {
const emitNode = node.emitNode;
return (emitNode && emitNode.commentRange) || node;
}
/**
* Sets a custom text range to use when emitting comments.
*/
export function setCommentRange<T extends Node>(node: T, range: TextRange) {
getOrCreateEmitNode(node).commentRange = range;
return node;
}
export function getSyntheticLeadingComments(node: Node): SynthesizedComment[] | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.leadingComments;
}
export function setSyntheticLeadingComments<T extends Node>(node: T, comments: SynthesizedComment[] | undefined) {
getOrCreateEmitNode(node).leadingComments = comments;
return node;
}
export function addSyntheticLeadingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
return setSyntheticLeadingComments(node, append<SynthesizedComment>(getSyntheticLeadingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
}
export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.trailingComments;
}
export function setSyntheticTrailingComments<T extends Node>(node: T, comments: SynthesizedComment[] | undefined) {
getOrCreateEmitNode(node).trailingComments = comments;
return node;
}
export function addSyntheticTrailingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
return setSyntheticTrailingComments(node, append<SynthesizedComment>(getSyntheticTrailingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
}
export function moveSyntheticComments<T extends Node>(node: T, original: Node): T {
setSyntheticLeadingComments(node, getSyntheticLeadingComments(original));
setSyntheticTrailingComments(node, getSyntheticTrailingComments(original));
const emit = getOrCreateEmitNode(original);
emit.leadingComments = undefined;
emit.trailingComments = undefined;
return node;
}
/** @internal */
export function ignoreSourceNewlines<T extends Node>(node: T): T {
getOrCreateEmitNode(node).flags |= EmitFlags.IgnoreSourceNewlines;
return node;
}
/**
* Gets the constant value to emit for an expression.
*/
export function getConstantValue(node: PropertyAccessExpression | ElementAccessExpression): string | number | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.constantValue;
}
/**
* Sets the constant value to emit for an expression.
*/
export function setConstantValue(node: PropertyAccessExpression | ElementAccessExpression, value: string | number): PropertyAccessExpression | ElementAccessExpression {
const emitNode = getOrCreateEmitNode(node);
emitNode.constantValue = value;
return node;
}
/**
* Adds an EmitHelper to a node.
*/
export function addEmitHelper<T extends Node>(node: T, helper: EmitHelper): T {
const emitNode = getOrCreateEmitNode(node);
emitNode.helpers = append(emitNode.helpers, helper);
return node;
}
/**
* Add EmitHelpers to a node.
*/
export function addEmitHelpers<T extends Node>(node: T, helpers: EmitHelper[] | undefined): T {
if (some(helpers)) {
const emitNode = getOrCreateEmitNode(node);
for (const helper of helpers) {
emitNode.helpers = appendIfUnique(emitNode.helpers, helper);
}
}
return node;
}
/**
* Removes an EmitHelper from a node.
*/
export function removeEmitHelper(node: Node, helper: EmitHelper): boolean {
const emitNode = node.emitNode;
if (emitNode) {
const helpers = emitNode.helpers;
if (helpers) {
return orderedRemoveItem(helpers, helper);
}
}
return false;
}
/**
* Gets the EmitHelpers of a node.
*/
export function getEmitHelpers(node: Node): EmitHelper[] | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.helpers;
}
/**
* Moves matching emit helpers from a source node to a target node.
*/
export function moveEmitHelpers(source: Node, target: Node, predicate: (helper: EmitHelper) => boolean) {
const sourceEmitNode = source.emitNode;
const sourceEmitHelpers = sourceEmitNode && sourceEmitNode.helpers;
if (!some(sourceEmitHelpers)) return;
const targetEmitNode = getOrCreateEmitNode(target);
let helpersRemoved = 0;
for (let i = 0; i < sourceEmitHelpers.length; i++) {
const helper = sourceEmitHelpers[i];
if (predicate(helper)) {
helpersRemoved++;
targetEmitNode.helpers = appendIfUnique(targetEmitNode.helpers, helper);
}
else if (helpersRemoved > 0) {
sourceEmitHelpers[i - helpersRemoved] = helper;
}
}
if (helpersRemoved > 0) {
sourceEmitHelpers.length -= helpersRemoved;
}
}
/* @internal */
export function compareEmitHelpers(x: EmitHelper, y: EmitHelper) {
if (x === y) return Comparison.EqualTo;
if (x.priority === y.priority) return Comparison.EqualTo;
if (x.priority === undefined) return Comparison.GreaterThan;
if (y.priority === undefined) return Comparison.LessThan;
return compareValues(x.priority, y.priority);
}
export function setOriginalNode<T extends Node>(node: T, original: Node | undefined): T {
node.original = original;
if (original) {
const emitNode = original.emitNode;
if (emitNode) node.emitNode = mergeEmitNode(emitNode, node.emitNode);
}
return node;
}
function mergeEmitNode(sourceEmitNode: EmitNode, destEmitNode: EmitNode | undefined) {
const {
flags,
leadingComments,
trailingComments,
commentRange,
sourceMapRange,
tokenSourceMapRanges,
constantValue,
helpers,
startsOnNewLine,
} = sourceEmitNode;
if (!destEmitNode) destEmitNode = {} as EmitNode;
// We are using `.slice()` here in case `destEmitNode.leadingComments` is pushed to later.
if (leadingComments) destEmitNode.leadingComments = addRange(leadingComments.slice(), destEmitNode.leadingComments);
if (trailingComments) destEmitNode.trailingComments = addRange(trailingComments.slice(), destEmitNode.trailingComments);
if (flags) destEmitNode.flags = flags;
if (commentRange) destEmitNode.commentRange = commentRange;
if (sourceMapRange) destEmitNode.sourceMapRange = sourceMapRange;
if (tokenSourceMapRanges) destEmitNode.tokenSourceMapRanges = mergeTokenSourceMapRanges(tokenSourceMapRanges, destEmitNode.tokenSourceMapRanges!);
if (constantValue !== undefined) destEmitNode.constantValue = constantValue;
if (helpers) destEmitNode.helpers = addRange(destEmitNode.helpers, helpers);
if (startsOnNewLine !== undefined) destEmitNode.startsOnNewLine = startsOnNewLine;
return destEmitNode;
}
function mergeTokenSourceMapRanges(sourceRanges: (TextRange | undefined)[], destRanges: (TextRange | undefined)[]) {
if (!destRanges) destRanges = [];
for (const key in sourceRanges) {
destRanges[key] = sourceRanges[key];
}
return destRanges;
}
}