Skip to content

Commit

Permalink
feat: #204 - Add IterationStatement, Do, ForIn, ForOf, For, While
Browse files Browse the repository at this point in the history
  • Loading branch information
dicarlo2 committed Jan 9, 2018
1 parent 55c558d commit ce40dee
Show file tree
Hide file tree
Showing 28 changed files with 1,065 additions and 64 deletions.
95 changes: 95 additions & 0 deletions src/compiler/base/AwaitableNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as ts from "typescript";
import {Constructor} from "./../../Constructor";
import * as errors from "./../../errors";
import {AwaitableNodeStructure} from "./../../structures";
import {callBaseFill} from "./../callBaseFill";
import {insertIntoParent, removeChildren, FormattingKind} from "./../../manipulation";
import {Node} from "./../common";
import {NamedNode} from "./../base";

export type AwaitableNodeExtensionType = Node<ts.Node & { awaitModifier?: ts.AwaitKeywordToken; }>;

export interface AwaitableNode {
/**
* If it's an awaited node.
*/
isAwaited(): boolean;
/**
* Gets the await token or undefined if none exists.
*/
getAwaitKeyword(): Node<ts.AwaitKeywordToken> | undefined;
/**
* Gets the await token or throws if none exists.
*/
getAwaitKeywordOrThrow(): Node<ts.AwaitKeywordToken>;
/**
* Sets if the node is awaited.
* @param value - If it should be awaited or not.
*/
setIsAwaited(value: boolean): this;
}

export function AwaitableNode<T extends Constructor<AwaitableNodeExtensionType>>(Base: T): Constructor<AwaitableNode> & T {
return class extends Base implements AwaitableNode {
isAwaited() {
return this.compilerNode.awaitModifier != null;
}

getAwaitKeyword(): Node<ts.AwaitKeywordToken> | undefined {
const awaitModifier = this.compilerNode.awaitModifier;
return awaitModifier == null ? undefined : (this.getNodeFromCompilerNode(awaitModifier) as Node<ts.AwaitKeywordToken>);
}

getAwaitKeywordOrThrow(): Node<ts.AwaitKeywordToken> {
return errors.throwIfNullOrUndefined(this.getAwaitKeyword(), "Expected to find an await token.");
}

setIsAwaited(value: boolean) {
const awaitModifier = this.getAwaitKeyword();
const isSet = awaitModifier != null;

if (isSet === value)
return this;

if (awaitModifier == null) {
const info = getAwaitInsertInfo(this);
insertIntoParent({
insertPos: info.pos,
childIndex: info.childIndex,
insertItemsCount: 1,
parent: this,
newText: " await"
});
}
else {
removeChildren({
children: [awaitModifier],
removePrecedingSpaces: true
});
}

return this;
}

fill(structure: Partial<AwaitableNodeStructure>) {
callBaseFill(Base.prototype, this, structure);

if (structure.isAwaited != null)
this.setIsAwaited(structure.isAwaited);

return this;
}
};
}

function getAwaitInsertInfo(node: Node) {
if (node.getKind() === ts.SyntaxKind.ForOfStatement) {
const forKeyword = node.getFirstChildByKindOrThrow(ts.SyntaxKind.ForKeyword);
return {
pos: forKeyword.getEnd(),
childIndex: forKeyword.getChildIndex() + 1
};
}

throw new errors.NotImplementedError("Expected a for of statement node.");
}
1 change: 1 addition & 0 deletions src/compiler/base/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./AmbientableNode";
export * from "./ArgumentedNode";
export * from "./AsyncableNode";
export * from "./AwaitableNode";
export * from "./BodiedNode";
export * from "./BodyableNode";
export * from "./ChildOrderableNode";
Expand Down
13 changes: 13 additions & 0 deletions src/compiler/statement/DoStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as ts from "typescript";
import {Expression} from "./../common";
import {IterationStatement} from "./IterationStatement";

export const DoStatementBase = IterationStatement;
export class DoStatement extends DoStatementBase<ts.DoStatement> {
/**
* Gets this do statement's expression.
*/
getExpression() {
return this.getNodeFromCompilerNode(this.compilerNode.expression) as Expression;
}
}
22 changes: 22 additions & 0 deletions src/compiler/statement/ForInStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as ts from "typescript";
import {Expression} from "./../common";
import {IterationStatement} from "./IterationStatement";
import {VariableDeclarationList} from "./VariableDeclarationList";

export const ForInStatementBase = IterationStatement;
export class ForInStatement extends ForInStatementBase<ts.ForInStatement> {

/**
* Gets this for in statement's initializer.
*/
getInitializer() {
return this.getNodeFromCompilerNode(this.compilerNode.initializer) as (VariableDeclarationList | Expression);
}

/**
* Gets this for in statement's expression.
*/
getExpression() {
return this.getNodeFromCompilerNode(this.compilerNode.expression) as Expression;
}
}
33 changes: 33 additions & 0 deletions src/compiler/statement/ForOfStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as ts from "typescript";
import {callBaseFill} from "./../callBaseFill";
import {Expression} from "./../common";
import {ForOfStatementStructure} from "./../../structures";
import {IterationStatement} from "./IterationStatement";
import {VariableDeclarationList} from "./VariableDeclarationList";
import {AwaitableNode} from "../base";

export const ForOfStatementBase = AwaitableNode(IterationStatement);
export class ForOfStatement extends ForOfStatementBase<ts.ForOfStatement> {
/**
* Gets this for of statement's initializer.
*/
getInitializer() {
return this.getNodeFromCompilerNode(this.compilerNode.initializer) as (VariableDeclarationList | Expression);
}

/**
* Gets this for of statement's expression.
*/
getExpression() {
return this.getNodeFromCompilerNode(this.compilerNode.expression) as Expression;
}

/**
* Fills the node from a structure.
* @param structure - Structure to fill.
*/
fill(structure: Partial<ForOfStatementStructure>) {
callBaseFill(ForOfStatementBase.prototype, this, structure);
return this;
}
}
57 changes: 57 additions & 0 deletions src/compiler/statement/ForStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as ts from "typescript";
import * as errors from "./../../errors";
import {Expression} from "./../common";
import {IterationStatement} from "./IterationStatement";
import {VariableDeclarationList} from "./VariableDeclarationList";

export const ForStatementBase = IterationStatement;
export class ForStatement extends ForStatementBase<ts.ForStatement> {

/**
* Gets this for statement's initializer or undefined if none exists.
*/
getInitializer() {
return this.compilerNode.initializer == null
? undefined
: this.getNodeFromCompilerNode(this.compilerNode.initializer) as (VariableDeclarationList | Expression);
}

/**
* Gets this for statement's initializer or throws if none exists.
*/
getInitializerOrThrow() {
return errors.throwIfNullOrUndefined(this.getInitializer(), "Expected to find an initializer.");
}

/**
* Gets this for statement's condition or undefined if none exists.
*/
getCondition() {
return this.compilerNode.condition == null
? undefined
: this.getNodeFromCompilerNode(this.compilerNode.condition) as Expression;
}

/**
* Gets this for statement's condition or throws if none exists.
*/
getConditionOrThrow() {
return errors.throwIfNullOrUndefined(this.getCondition(), "Expected to find a condition.");
}

/**
* Gets this for statement's incrementor.
*/
getIncrementor() {
return this.compilerNode.incrementor == null
? undefined
: this.getNodeFromCompilerNode(this.compilerNode.incrementor) as Expression;
}

/**
* Gets this for statement's incrementor or throws if none exists.
*/
getIncrementorOrThrow() {
return errors.throwIfNullOrUndefined(this.getIncrementor(), "Expected to find an incrementor.");
}
}
21 changes: 21 additions & 0 deletions src/compiler/statement/IterationStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as ts from "typescript";
import {removeStatementedNodeChild} from "./../../manipulation";
import {ChildOrderableNode} from "./../base";
import {Statement} from "./Statement";

export const IterationStatementBase = ChildOrderableNode(Statement);
export class IterationStatement<T extends ts.IterationStatement = ts.IterationStatement> extends IterationStatementBase<T> {
/**
* Gets this iteration statement's statement.
*/
getStatement() {
return this.getNodeFromCompilerNode(this.compilerNode.statement) as Statement;
}

/**
* Removes this iteration statement.
*/
remove() {
removeStatementedNodeChild(this);
}
}

0 comments on commit ce40dee

Please sign in to comment.