Skip to content

Commit

Permalink
fix: Insert functions with a declaration keyword without a body.
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Feb 15, 2018
1 parent 9859082 commit c64009d
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 20 deletions.
25 changes: 15 additions & 10 deletions src/compiler/statement/StatementedNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as errors from "./../../errors";
import {ClassDeclarationStructure, InterfaceDeclarationStructure, TypeAliasDeclarationStructure, FunctionDeclarationStructure,
EnumDeclarationStructure, NamespaceDeclarationStructure, StatementedNodeStructure, VariableStatementStructure} from "./../../structures";
import * as structureToTexts from "./../../structureToTexts";
import {verifyAndGetIndex, insertIntoBracesOrSourceFile, getRangeFromArray, removeStatementedNodeChildren} from "./../../manipulation";
import {verifyAndGetIndex, insertIntoBracesOrSourceFile, getRangeFromArray, removeStatementedNodeChildren, hasBody} from "./../../manipulation";
import {getNamedNodeByNameOrFindFunction, getNotFoundErrorMessageForNameOrFindFunction, TypeGuards, ArrayUtils} from "./../../utils";
import {callBaseFill} from "./../callBaseFill";
import {Node} from "./../common";
Expand Down Expand Up @@ -602,14 +602,19 @@ export function StatementedNode<T extends Constructor<StatementedNodeExtensionTy
structureToText.writeText(s);
return writer.toString();
});
const newChildren = this._insertMainChildren<FunctionDeclaration>(index, texts, structures, SyntaxKind.FunctionDeclaration, (child, i) => {
// todo: remove filling when writing
const params = structures[i].parameters;
delete structures[i].parameters;
child.fill(structures[i]);
if (params != null)
child.getParameters().forEach((p, j) => p.fill(params[j]));
});
const newChildren = this._insertMainChildren<FunctionDeclaration, FunctionDeclarationStructure>(index, texts, structures, SyntaxKind.FunctionDeclaration,
(child, i) => {
// todo: remove filling when writing
const params = structures[i].parameters;
delete structures[i].parameters;
child.fill(structures[i]);
if (params != null)
child.getParameters().forEach((p, j) => p.fill(params[j]));
}, {
previousBlanklineWhen: (previousMember, firstStructure) => !firstStructure.hasDeclareKeyword || hasBody(previousMember),
separatorNewlineWhen: (previousStructure, nextStructure) => !previousStructure.hasDeclareKeyword || !nextStructure.hasDeclareKeyword,
nextBlanklineWhen: (nextMember, lastStructure) => !lastStructure.hasDeclareKeyword || hasBody(nextMember)
});

return newChildren;
}
Expand Down Expand Up @@ -904,7 +909,7 @@ export function StatementedNode<T extends Constructor<StatementedNodeExtensionTy
expectedSyntaxKind: SyntaxKind,
withEachChild?: ((child: U, index: number) => void),
opts: {
previousBlanklineWhen?: (nextMember: Node, lastStructure: TStructure) => boolean,
previousBlanklineWhen?: (previousMember: Node, firstStructure: TStructure) => boolean,
separatorNewlineWhen?: (previousStructure: TStructure, nextStructure: TStructure) => boolean,
nextBlanklineWhen?: (nextMember: Node, lastStructure: TStructure) => boolean
} = {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {ts} from "./../../typescript";
import {Node} from "./../../compiler";
import {TypeGuards} from "./../../utils";
import {FormattingKind} from "./FormattingKind";
import {hasBody} from "./hasBody";

export function getStatementedNodeChildFormatting(parent: Node, member: Node) {
if (hasBody(member))
Expand All @@ -13,12 +14,3 @@ export function getStatementedNodeChildFormatting(parent: Node, member: Node) {
export function getClausedNodeChildFormatting(parent: Node, member: Node) {
return FormattingKind.Newline;
}

function hasBody(node: Node) {
if (TypeGuards.isBodyableNode(node) && node.getBody() != null)
return true;
if (TypeGuards.isBodiedNode(node))
return true;
return TypeGuards.isInterfaceDeclaration(node) || TypeGuards.isClassDeclaration(node) || TypeGuards.isEnumDeclaration(node) ||
TypeGuards.isEnumDeclaration(node);
}
12 changes: 12 additions & 0 deletions src/manipulation/formatting/hasBody.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {SyntaxKind} from "./../../typescript";
import {Node} from "./../../compiler";
import {TypeGuards} from "./../../utils";

export function hasBody(node: Node) {
if (TypeGuards.isBodyableNode(node) && node.hasBody())
return true;
if (TypeGuards.isBodiedNode(node))
return true;

return TypeGuards.isInterfaceDeclaration(node) || TypeGuards.isClassDeclaration(node) || TypeGuards.isEnumDeclaration(node);
}
1 change: 1 addition & 0 deletions src/manipulation/formatting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from "./getGeneralFormatting";
export * from "./getInterfaceMemberFormatting";
export * from "./getStatementedNodeChildFormatting";
export * from "./getTextFromFormattingEdits";
export * from "./hasBody";
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ export class FunctionDeclarationStructureToText extends StructureToText<Function
private readonly parameterWriter = new ParameterDeclarationStructureToText(this.writer);

writeText(structure: FunctionDeclarationStructure) {
this.writer.conditionalWrite(structure.hasDeclareKeyword, "declare ");
this.writer.write(`function ${structure.name}(`);
if (structure.parameters != null)
this.parameterWriter.writeParameters(structure.parameters);
this.writer.write(`)`).block();
this.writer.write(`)`);
if (structure.hasDeclareKeyword)
this.writer.write(";");
else
this.writer.block();
}
}
6 changes: 6 additions & 0 deletions src/tests/compiler/statement/statementedNode/functionTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ describe(nameof(StatementedNode), () => {
"function Identifier1() {\n}\n\nfunction Identifier2() {\n}\n\nfunction Identifier3() {\n}\n");
});

it("should insert ones with a declaration keyword accordingly", () => {
doTest("function Identifier1() {\n}\ndeclare function Identifier4(): string;", 1,
[{ hasDeclareKeyword: true, name: "Identifier2" }, { hasDeclareKeyword: true, name: "Identifier3" }],
"function Identifier1() {\n}\n\ndeclare function Identifier2();\ndeclare function Identifier3();\ndeclare function Identifier4(): string;");
});

it("should have the expected text adding to non-source file", () => {
const {sourceFile} = getInfoFromText("namespace Namespace {\n}\n");
const namespaceDec = sourceFile.getNamespaces()[0];
Expand Down
30 changes: 30 additions & 0 deletions src/tests/utils/arrayUtilsTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,34 @@ describe(nameof(ArrayUtils), () => {
doTest([1, 2, 3, 5], 6, [1, 2, 3, 5, 6]);
});
});

describe(`#${nameof(ArrayUtils.containsSubArray)}()`, () => {
function doTest(items: number[], subArray: number[], result: boolean) {
expect(ArrayUtils.containsSubArray(items, subArray)).equal(result);
}

it("should be true when it contains the sub array at the start", () => {
doTest([1, 2, 3, 4, 5], [1, 2, 3], true);
});

it("should be true when it contains the sub array at the end", () => {
doTest([1, 2, 3, 4, 5], [3, 4, 5], true);
});

it("should be true when it contains the sub array in the middle", () => {
doTest([1, 2, 3, 4, 5], [2, 3, 4], true);
});

it("should be false when it doesn't contain the sub array", () => {
doTest([1, 2, 3, 4, 5], [1, 2, 2], false);
});

it("should be false when it doesn't contain the sub array in a different order", () => {
doTest([1, 2, 3, 4, 5], [3, 2, 1], false);
});

it("should be false when it doesn't contain all the sub array", () => {
doTest([1, 2, 3, 4, 5], [3, 4, 5, 6], false);
});
});
});
15 changes: 15 additions & 0 deletions src/utils/ArrayUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,19 @@ export class ArrayUtils {

return -1;
}

static containsSubArray<T>(items: T[], subArray: T[]) {
let findIndex = 0;
for (const item of items) {
if (subArray[findIndex] === item) {
findIndex++;
if (findIndex === subArray.length)
return true;
}
else
findIndex = 0;
}

return false;
}
}

0 comments on commit c64009d

Please sign in to comment.