Skip to content

Commit

Permalink
feat: Add WriterFunctions - objectType, unionType, intersectionType
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Feb 18, 2019
1 parent 1d2c85a commit d10877f
Show file tree
Hide file tree
Showing 7 changed files with 10,706 additions and 10,543 deletions.
20,914 changes: 10,463 additions & 10,451 deletions lib/ts-morph.d.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ export { printNode, PrintNodeOptions } from "./utils/compiler/printNode";
export { SourceFileReferencingNodes } from "./utils/references/SourceFileReferenceContainer";
export { CompilerOptionsFromTsConfigOptions, CompilerOptionsFromTsConfigResult, getCompilerOptionsFromTsConfig } from "./utils/tsconfig/getCompilerOptionsFromTsConfig";
export { TypeGuards } from "./utils/TypeGuards";
export { WriterFunctions } from "./utils/WriterFunctions";
export { WriterFunctions, WriterFunctionOrValue } from "./structurePrinters/WriterFunctions";
export * from "./typescript/public";
111 changes: 111 additions & 0 deletions src/structurePrinters/WriterFunctions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* barrel:ignore */
import { CodeBlockWriter } from "../codeBlockWriter";
import * as errors from "../errors";
import { TypeElementMemberedNodeStructure } from "../structures";
import { StructurePrinterFactory } from "../factories/StructurePrinterFactory";
import { WriterFunction } from "../types";

export type WriterFunctionOrValue = string | number | WriterFunction;

const structurePrinterFactory = new StructurePrinterFactory(() => {
throw new errors.NotImplementedError("Not implemented scenario for getting code format settings when using a writer function. Please open an issue.");
});

/**
* Writer functions.
* @remarks These functions are currently very experimental.
*/
export class WriterFunctions {
private constructor() {
}

/**
* Gets a writer function for writing the provided object as an object literal expression.
* @param obj - Object to write.
*/
static object(obj: { [key: string]: WriterFunctionOrValue | undefined; }): WriterFunction {
return (writer: CodeBlockWriter) => {
const keyNames = Object.keys(obj);
writer.write("{");
if (keyNames.length > 0) {
writer.indentBlock(() => {
writeObject();
});
}
writer.write("}");

function writeObject() {
for (let i = 0; i < keyNames.length; i++) {
if (i > 0)
writer.write(",").newLine();

const keyName = keyNames[i];
const value = obj[keyName];
writer.write(keyName);
if (value != null) {
writer.write(": ");
writeValue(writer, value);
}
}

writer.newLine();
}
};
}

/** Gets a writer function for writing an object type. */
static objectType(structure: TypeElementMemberedNodeStructure): WriterFunction {
return (writer: CodeBlockWriter) => {
writer.write("{");
if (anyPropertyHasValue(structure)) {
writer.indentBlock(() => {
structurePrinterFactory.forTypeElementMemberedNode().printText(writer, structure);
});
}
writer.write("}");
};
}

/** Gets a writer function for writing a union type. */
static unionType(firstType: WriterFunctionOrValue, secondType: WriterFunctionOrValue, ...additionalTypes: WriterFunctionOrValue[]) {
return getWriteFunctionForUnionOrIntersectionType("|", [firstType, secondType, ...additionalTypes]);
}

/** Gets a writer function for writing an intersection type. */
static intersectionType(firstType: WriterFunctionOrValue, secondType: WriterFunctionOrValue, ...additionalTypes: WriterFunctionOrValue[]) {
return getWriteFunctionForUnionOrIntersectionType("&", [firstType, secondType, ...additionalTypes]);
}
}

function getWriteFunctionForUnionOrIntersectionType(separator: "|" | "&", args: WriterFunctionOrValue[]) {
return (writer: CodeBlockWriter) => {
writeSeparatedByString(writer, ` ${separator} `, args);
};
}

function anyPropertyHasValue(obj: any) {
for (const key of Object.keys(obj)) {
if (obj[key] == null)
continue;
if (obj[key] instanceof Array && obj[key].length === 0)
continue;

return true;
}

return false;
}

function writeSeparatedByString(writer: CodeBlockWriter, separator: string, values: WriterFunctionOrValue[]) {
for (let i = 0; i < values.length; i++) {
writer.conditionalWrite(i > 0, separator);
writeValue(writer, values[i]);
}
}

function writeValue(writer: CodeBlockWriter, value: WriterFunctionOrValue) {
if (value instanceof Function)
value(writer);
else
writer.write(value.toString());
}
131 changes: 131 additions & 0 deletions src/tests/structurePrinters/writerFunctionsTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { expect } from "chai";
import { CodeBlockWriter } from "../../codeBlockWriter";
import { TypeElementMemberedNodeStructure } from "../../structures";
import { WriterFunction } from "../../types";
import { WriterFunctions } from "../../structurePrinters/WriterFunctions";

describe(nameof<WriterFunctions>(), () => {
function getWriter() {
return new CodeBlockWriter();
}

function doWriterTest(action: (writer: CodeBlockWriter, writerFunctions: typeof WriterFunctions) => void, expected: string) {
const writer = getWriter();
action(writer, WriterFunctions);
expect(writer.toString()).to.equal(expected);
}

describe(nameof(WriterFunctions.object), () => {
function doTest(obj: { [key: string]: string | number | WriterFunction | undefined; }, expected: string) {
doWriterTest((writer, { object }) => object(obj)(writer), expected);
}

it("should write an object with keys", () => {
doTest({
key1: "'testing'",
key2: 5,
key3: undefined,
key4: writer => writer.write("6"),
key5: "undefined"
}, `{
key1: 'testing',
key2: 5,
key3,
key4: 6,
key5: undefined
}`);
});

it("should write an object without keys on the same line", () => {
doTest({}, `{}`);
});
});

describe(nameof(WriterFunctions.objectType), () => {
function doTest(obj: TypeElementMemberedNodeStructure, expected: string) {
doWriterTest((writer, { objectType }) => objectType(obj)(writer), expected);
}

it("should write an object type with only properties", () => {
doTest({
properties: [{ name: "prop" }]
}, `{
prop;
}`);
});

it("should write an object type with only methods", () => {
doTest({
methods: [{ name: "method" }]
}, `{
method();
}`);
});

it("should write an object type with only call signatures", () => {
doTest({
callSignatures: [{}]
}, `{
(): void;
}`);
});

it("should write an object type with only construct signatures", () => {
doTest({
constructSignatures: [{}]
}, `{
new();
}`);
});

it("should write an object type with only index signatures", () => {
doTest({
indexSignatures: [{}]
}, `{
[key: string];
}`);
});

it("should write an object type with everything", () => {
const structure: MakeRequired<TypeElementMemberedNodeStructure> = {
callSignatures: [{}],
constructSignatures: [{}],
indexSignatures: [{}],
properties: [{ name: "prop" }],
methods: [{ name: "method" }]
};

doTest(structure, `{
(): void;
new();
[key: string];
prop;
method();
}`);
});

it("should write an object without keys on the same line", () => {
doTest({}, `{}`);
});
});

describe(nameof(WriterFunctions.unionType), () => {
it("should write when only specifying two types", () => {
doWriterTest((writer, { unionType }) => unionType("C", "A")(writer), "C | A");
});

it("should write when specifying more than two types", () => {
doWriterTest((writer, { unionType }) => unionType("C", "A", w => w.write("5"), 7)(writer), "C | A | 5 | 7");
});
});

describe(nameof(WriterFunctions.intersectionType), () => {
it("should write when only specifying two types", () => {
doWriterTest((writer, { intersectionType }) => intersectionType("C", "A")(writer), "C & A");
});

it("should write when specifying more than two types", () => {
doWriterTest((writer, { intersectionType }) => intersectionType("C", "A", w => w.write("5"), 7)(writer), "C & A & 5 & 7");
});
});
});
42 changes: 0 additions & 42 deletions src/tests/utils/writerFunctionsTests.ts

This file was deleted.

48 changes: 0 additions & 48 deletions src/utils/WriterFunctions.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@ export * from "./StringUtils";
export * from "./tsconfig";
export * from "./TypeGuards";
export * from "./TypeScriptVersionChecker";
export * from "./WriterFunctions";

0 comments on commit d10877f

Please sign in to comment.