Skip to content

Commit

Permalink
chore: crontab & enum parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
Johan committed Oct 16, 2019
1 parent 186989e commit 93a67ba
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/lib/commands/jobs/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const description = "Creates a new cron job";

const hint = "<unique id> <'min hour day month week command'>";

interface CronJob {
uniqueId: string;
}

const run = async (...args: string[]) => {
let [id, commandToAdd] = args;
id = id || (await promptly.prompt("Unique id for the job to add: "));
Expand Down
39 changes: 39 additions & 0 deletions src/lib/cronParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { StringComparison } from "../types";
import { create, empty, ParseResult } from "../types/ParseResult";
import { parse } from "./enumHelper";
import { swap } from "./mapHelper";

export enum CronSchedule {
Custom,
Daily,
Hourly,
Monthly,
Weekly,
Yearly
}

const cronScheduleToTab = new Map<CronSchedule, string>([
[CronSchedule.Daily, "0 0 * * *"],
[CronSchedule.Hourly, "0 * * * *"],
[CronSchedule.Monthly, "0 0 1 * *"],
[CronSchedule.Weekly, "0 0 * * 0"],
[CronSchedule.Yearly, "0 0 1 1 *"]
]);

const cronTabToSchedule = swap(cronScheduleToTab);

export const parseSchedule = (cronTab: string): ParseResult<CronSchedule> =>
create(cronTabToSchedule.get(cronTab));

export const parseCronTab = (
schedule: CronSchedule | string
): ParseResult<string> => {
const key =
typeof schedule === "string"
? parse(CronSchedule, schedule, StringComparison.OrdinalIgnoreCase).value
: schedule;

const value = (key && cronScheduleToTab.get(key)) || undefined;

return create(value);
};
28 changes: 28 additions & 0 deletions src/lib/enumHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ParseResult, StringComparison } from "../types";

export { StringComparison };

export const parse = <T>(
enumType: T,
value: string,
comparision = StringComparison.Ordinal
): ParseResult<T[keyof T]> => {
const result: ParseResult<T[keyof T]> = {
hasValue: false,
value: undefined
};

const matchingKey = Object.keys(enumType).find(x =>
comparision === StringComparison.OrdinalIgnoreCase
? x.toLowerCase() === value.toLowerCase()
: x === value
);

if (matchingKey !== undefined) {
result.value = enumType[matchingKey as keyof typeof enumType];
}

result.hasValue = result.value !== undefined;

return result;
};
5 changes: 5 additions & 0 deletions src/lib/mapHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const swap = <K, V>(map: Map<K, V>): Map<V, K> => {
return new Map<V, K>(
[...map.entries()].map((value: [K, V]) => [value[1], value[0]])
);
};
11 changes: 11 additions & 0 deletions src/types/ParseResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface ParseResult<T> {
hasValue: boolean;
value?: T;
}

export const empty = <T>(): ParseResult<T> => ({ hasValue: false });

export const create = <T>(value?: T): ParseResult<T> => ({
value,
hasValue: value !== undefined
});
4 changes: 4 additions & 0 deletions src/types/StringComparison.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum StringComparison {
Ordinal,
OrdinalIgnoreCase
}
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export { default as CommandParser } from "./CommandParser";
export { CommandRequirement } from "./CommandRequirement";
export { default as ConfigCreationData } from "./ConfigCreationData";
export { default as ExecResult } from "./ExecResult";
export { ParseResult } from "./ParseResult";
export { default as PromptType } from "./PromptType";
export { default as PromptBody } from "./PromptBody";
export { default as SshConfig } from "./SshConfig";
export { StringComparison } from "./StringComparison";
7 changes: 7 additions & 0 deletions test/commands/jobs/add.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
describe("jobs", () => {
describe("add", () => {
it("should work", () => {
test.todo("todo");
});
});
});
20 changes: 20 additions & 0 deletions test/cronParser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
parseCronTab,
parseSchedule,
CronSchedule
} from "../src/lib/cronParser";

const daily = "0 0 * * *";

describe("cronParser", () => {
describe("asCronTab", () => {
it("can parse string", () => {
expect(parseCronTab("Daily").value).toBe(daily);
expect(parseCronTab("daily").value).toBe(daily);
});

it("can parse cron schedule", () => {
expect(parseSchedule(daily).value).toBe(CronSchedule.Daily);
});
});
});
42 changes: 42 additions & 0 deletions test/enumHelper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { parse, StringComparison } from "../src/lib/enumHelper";

enum TestEnum {
First,
Second
}

describe("enumHelper", () => {
describe("parse", () => {
it("should have hasValue set to true when value matches enum value", () => {
expect(parse(TestEnum, "Second").hasValue).toBe(true);
});

it("should have hasValue set to false when value matches enum value with other casing", () => {
expect(parse(TestEnum, "sEcONd").hasValue).toBe(false);
});

it("should have hasValue set to true when value matches enum value and ignoring case", () => {
expect(
parse(TestEnum, "second", StringComparison.OrdinalIgnoreCase).hasValue
).toBe(true);
});

it("should have hasValue set to false when value is invalid", () => {
expect(parse(TestEnum, "invalid").hasValue).toBe(false);
});

it("should have value defined", () => {
expect(parse(TestEnum, "Second").value).toBeDefined();
expect(
parse(TestEnum, "second", StringComparison.OrdinalIgnoreCase).value
).toBeDefined();
});

it("should have value undefined", () => {
expect(parse(TestEnum, "invalid").value).toBeUndefined();
expect(
parse(TestEnum, "second", StringComparison.Ordinal).value
).toBeUndefined();
});
});
});
18 changes: 18 additions & 0 deletions test/mapHelper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { swap } from "../src/lib/mapHelper";

describe("mapHelper", () => {
describe("swap", () => {
it("can swap keys with values", () => {
const map = new Map<string, string>([
["key1", "value1"],
["key2", "value2"]
]);

const result = swap(map);

expect(result.size).toBe(2);
expect(result.get("value1")).toBe("key1");
expect(result.get("value2")).toBe("key2");
});
});
});

0 comments on commit 93a67ba

Please sign in to comment.