Refactor code
This commit is contained in:
@@ -1,3 +1,2 @@
|
|||||||
import {parse} from "./generated/grammar/task";
|
import { loadTasks } from "./loader";
|
||||||
|
|
||||||
console.log(parse("- [t]"));
|
|
||||||
104
src/loader/index.ts
Normal file
104
src/loader/index.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { createInterface } from "readline";
|
||||||
|
import { parse } from "../generated/grammar/task";
|
||||||
|
import { Task as DefaultTask } from "../model";
|
||||||
|
import { ParseResult } from "../types/grammar/task";
|
||||||
|
import { Task, TaskPriority } from "../types/task";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all tasks from specified directory and filters them with optional query.
|
||||||
|
*/
|
||||||
|
export async function loadTasks(directories: string[], query?: string): Promise<Task[]> {
|
||||||
|
const ctx = {
|
||||||
|
now: dayjs(),
|
||||||
|
LOWEST: TaskPriority.LOWEST,
|
||||||
|
LOW: TaskPriority.LOW,
|
||||||
|
NORMAL: TaskPriority.NORMAL,
|
||||||
|
MEDIUM: TaskPriority.MEDIUM,
|
||||||
|
HIGH: TaskPriority.HIGH,
|
||||||
|
HIGHEST: TaskPriority.HIGHEST
|
||||||
|
};
|
||||||
|
|
||||||
|
const filter = query && createFilter(query, ctx);
|
||||||
|
const tasks = await Promise.all(directories.map(readTasksFromDirectory));
|
||||||
|
|
||||||
|
return tasks.flat().filter(t => filter ? filter(t) : true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a filter function for tasks using a query string and context object.
|
||||||
|
* All context' properties will be passed as variables to the query string.
|
||||||
|
*/
|
||||||
|
function createFilter(query: string, context: Record<string, unknown>): (task: Task) => boolean {
|
||||||
|
const filter = new Function('$', ...Object.keys(context), `return ${query};`);
|
||||||
|
return (task: Task) => filter(task, ...Object.values(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read all files in specific directory and returns all tasks from those files.
|
||||||
|
*/
|
||||||
|
async function readTasksFromDirectory(directory: string): Promise<Task[]> {
|
||||||
|
return walk(directory, readTasksFromFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walks through a specific directory recursively and invokes visitor on each file.
|
||||||
|
* Returns a flat list of items returned by visitors.
|
||||||
|
*/
|
||||||
|
async function walk<T>(directory: string, visitor: (path: string) => Promise<T[]>): Promise<T[]> {
|
||||||
|
const list = [];
|
||||||
|
|
||||||
|
for(const file of fs.readdirSync(directory)) {
|
||||||
|
const path = `${directory}/${file}`;
|
||||||
|
|
||||||
|
if (fs.statSync(path).isDirectory()) {
|
||||||
|
const items = await walk(path, visitor);
|
||||||
|
list.push(...items);
|
||||||
|
} else {
|
||||||
|
const items = await visitor(path);
|
||||||
|
list.push(...items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads all tasks from file path.
|
||||||
|
*/
|
||||||
|
async function readTasksFromFile(path: string): Promise<Task[]> {
|
||||||
|
const fileStream = fs.createReadStream(path);
|
||||||
|
|
||||||
|
const lines = createInterface({
|
||||||
|
input: fileStream,
|
||||||
|
crlfDelay: Infinity
|
||||||
|
});
|
||||||
|
|
||||||
|
const list: Task[] = [];
|
||||||
|
|
||||||
|
for await (const line of lines) {
|
||||||
|
const task = parseTask(line);
|
||||||
|
|
||||||
|
if(task) {
|
||||||
|
list.push(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts line to task model.
|
||||||
|
* If the line does not represent task, returns undefined.
|
||||||
|
*/
|
||||||
|
function parseTask(line: string): Task|undefined {
|
||||||
|
const item = parse(line) as ParseResult;
|
||||||
|
|
||||||
|
if (item.type === 'task') {
|
||||||
|
return new DefaultTask(item.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
1
src/model/index.ts
Normal file
1
src/model/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {LazyTask as Task} from "./task";
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import fs from "fs";
|
|
||||||
import readline from "readline";
|
|
||||||
import { Task } from "../types/task";
|
|
||||||
import { parse } from "../parser";
|
|
||||||
|
|
||||||
export async function readTasksFromDirectory(directory: string): Promise<Task[]> {
|
|
||||||
return walk(directory, readTasksFromFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function walk<T>(directory: string, visitor: (path: string) => Promise<T[]>): Promise<T[]> {
|
|
||||||
const list = [];
|
|
||||||
|
|
||||||
for(const file of fs.readdirSync(directory)) {
|
|
||||||
const path = `${directory}/${file}`;
|
|
||||||
|
|
||||||
if (fs.statSync(path).isDirectory()) {
|
|
||||||
const items = await walk(path, visitor);
|
|
||||||
list.push(...items);
|
|
||||||
} else {
|
|
||||||
const items = await visitor(path);
|
|
||||||
list.push(...items);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function readTasksFromFile(path: string): Promise<Task[]> {
|
|
||||||
const fileStream = fs.createReadStream(path);
|
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
|
||||||
input: fileStream,
|
|
||||||
crlfDelay: Infinity
|
|
||||||
});
|
|
||||||
|
|
||||||
const list: Task[] = [];
|
|
||||||
|
|
||||||
for await (const line of rl) {
|
|
||||||
const task = parse(line);
|
|
||||||
|
|
||||||
if(task) {
|
|
||||||
list.push(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import {parse as rawParse} from "../generated/grammar/task";
|
|
||||||
import { ParseResult } from "../types/grammar/task";
|
|
||||||
import { Task } from "../types/task";
|
|
||||||
import { LazyTask } from "./task";
|
|
||||||
|
|
||||||
export function parse(line: string): Task|undefined {
|
|
||||||
const item = rawParse(line) as ParseResult;
|
|
||||||
|
|
||||||
if (item.type === 'task') {
|
|
||||||
return new LazyTask(item.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user