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