Add support for '--test' CLI option
This commit is contained in:
@@ -3,20 +3,21 @@ import { BackendSettings } from "../types/config";
|
|||||||
import { Notification } from "../types/notification";
|
import { Notification } from "../types/notification";
|
||||||
import { Backend } from "./base";
|
import { Backend } from "./base";
|
||||||
import { TaskPriority } from "../types/task";
|
import { TaskPriority } from "../types/task";
|
||||||
|
import { enhancedStringConfig } from "../util/config";
|
||||||
|
|
||||||
type Config = {
|
type Config = {
|
||||||
url: string;
|
url: string;
|
||||||
tokenFile: string;
|
token: string;
|
||||||
topic?: string;
|
topic?: string;
|
||||||
} & BackendSettings;
|
} & BackendSettings;
|
||||||
|
|
||||||
export class NtfySH extends Backend<Config> {
|
export class NtfySH extends Backend<Config> {
|
||||||
public name = "ntfy";
|
public name = "ntfy";
|
||||||
|
|
||||||
protected requiredFields = ['url', 'tokenFile'] as const;
|
protected requiredFields = ['url', 'token'] as const;
|
||||||
|
|
||||||
protected notify(config: Config, notification: Notification): void {
|
protected notify(config: Config, notification: Notification): void {
|
||||||
const token = fs.readFileSync(config.tokenFile, 'utf-8');
|
const token = enhancedStringConfig(config.token);
|
||||||
|
|
||||||
fetch(`https://${config.url}/${config.topic || 'obsidian'}`, {
|
fetch(`https://${config.url}/${config.topic || 'obsidian'}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ import { program } from "commander";
|
|||||||
import { CLIOptions } from "../types/cli";
|
import { CLIOptions } from "../types/cli";
|
||||||
|
|
||||||
import { loadConfig } from "../config";
|
import { loadConfig } from "../config";
|
||||||
import { notify, scan } from "../runner";
|
import { notify, scan, test } from "../runner";
|
||||||
|
|
||||||
const getOptions = () => program
|
const getOptions = () => program
|
||||||
.name("obsidian-tasks-reminder")
|
.name("obsidian-tasks-reminder")
|
||||||
.version("0.0.1")
|
.version("0.0.1")
|
||||||
.requiredOption("-c, --config <file>", "sets the path to the YAML file with configuration")
|
.requiredOption("-c, --config <file>", "sets the path to the YAML file with configuration")
|
||||||
.option("-x, --set <arg>", "overrides the config option for this specific run (arg: <key>=<name>, i.e. backend.ntfy.enable=false", (v: string, prev: string[]) => prev.concat([v]), [])
|
.option("-x, --set <arg>", "overrides the config option for this specific run (arg: <key>=<name>, i.e. backend.ntfy.enable=false", (v: string, prev: string[]) => prev.concat([v]), [])
|
||||||
|
.option("-t, --test", "evaluates the query, applies the mapper and prints to stdout the notifications about to be trigger, without actual triggering them")
|
||||||
.option("-s, --scan", "scans new tasks for future notifications and generates the database")
|
.option("-s, --scan", "scans new tasks for future notifications and generates the database")
|
||||||
.option("-n, --notify", "reads the generated database and triggers notifications if any")
|
.option("-n, --notify", "reads the generated database and triggers notifications if any")
|
||||||
.parse()
|
.parse()
|
||||||
@@ -36,12 +37,19 @@ const getOptions = () => program
|
|||||||
current = current[segment];
|
current = current[segment];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.test) {
|
||||||
|
await test(config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.scan) {
|
if (options.scan) {
|
||||||
scan(config);
|
await scan(config);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.notify) {
|
if (options.notify) {
|
||||||
notify(config);
|
await notify(config);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { Task } from "../types/task";
|
import { Task } from "../types/task";
|
||||||
import { Notification, NotificationDatabase } from "../types/notification";
|
import { Notification, NotificationDatabase } from "../types/notification";
|
||||||
import { jsMapper } from "../util";
|
import { jsMapper } from "../util/code";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,19 +16,24 @@ export function dumpDatabase(file: string, tasks: Task[], mapper?: string) {
|
|||||||
* Applies the mapper for each task from list, groups them by time and serializes into JSON format.
|
* Applies the mapper for each task from list, groups them by time and serializes into JSON format.
|
||||||
*/
|
*/
|
||||||
export function serializeDatabase(tasks: Task[], mapper?: string): string {
|
export function serializeDatabase(tasks: Task[], mapper?: string): string {
|
||||||
const transformer = mapper
|
return JSON.stringify(createDatabase(tasks, mapper));
|
||||||
? jsMapper<Task, Notification>(mapper, {})
|
}
|
||||||
: defaultMapper;
|
|
||||||
|
|
||||||
const output = tasks.map(wrapWithTimeFiller(transformer)).reduce((acc, n) => {
|
/**
|
||||||
|
* Applies the mapper for each task from list and groups them by time.
|
||||||
|
*/
|
||||||
|
export function createDatabase(tasks: Task[], mapper?: string): NotificationDatabase {
|
||||||
|
const transformer = mapper
|
||||||
|
? jsMapper<Task, Notification>(mapper, {})
|
||||||
|
: defaultMapper;
|
||||||
|
|
||||||
|
return tasks.map(wrapWithTimeFiller(transformer)).reduce((acc, n) => {
|
||||||
if (n.time) {
|
if (n.time) {
|
||||||
(acc[n.time] = (acc[n.time] || [])).push(n);
|
(acc[n.time] = (acc[n.time] || [])).push(n);
|
||||||
};
|
};
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as NotificationDatabase);
|
}, {} as NotificationDatabase);
|
||||||
|
|
||||||
return JSON.stringify(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapWithTimeFiller(mapper: (task: Task) => Notification): (task: Task) => Notification {
|
function wrapWithTimeFiller(mapper: (task: Task) => Notification): (task: Task) => Notification {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { parse } from "../generated/grammar/task";
|
|||||||
import { Task as DefaultTask } from "../model";
|
import { Task as DefaultTask } from "../model";
|
||||||
import { ParseResult } from "../types/grammar";
|
import { ParseResult } from "../types/grammar";
|
||||||
import { Task, TaskPriority } from "../types/task";
|
import { Task, TaskPriority } from "../types/task";
|
||||||
import { jsMapper } from "../util";
|
import { jsMapper } from "../util/code";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all tasks from specified directory and filters them with optional query.
|
* Returns all tasks from specified directory and filters them with optional query.
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
import { loadTasks } from "../loader";
|
import { loadTasks } from "../loader";
|
||||||
import { dumpDatabase } from "../database/serializer";
|
import { createDatabase, dumpDatabase } from "../database/serializer";
|
||||||
import { loadDatabase } from "../database/deserializer";
|
import { loadDatabase } from "../database/deserializer";
|
||||||
import { remind } from "../backend";
|
import { remind } from "../backend";
|
||||||
import { Config } from "../types/config";
|
import { Config } from "../types/config";
|
||||||
|
|
||||||
|
export async function test(config: Config) {
|
||||||
|
const tasks = await loadTasks(config.sources, config.query);
|
||||||
|
const db = createDatabase(tasks, config.mapper);
|
||||||
|
|
||||||
|
for (const time of Object.keys(db)) {
|
||||||
|
console.log(time);
|
||||||
|
|
||||||
|
for (const notification of db[time]) {
|
||||||
|
console.log(` - title: ${notification.title}\n text: ${notification.text}\n priority: ${notification.priority}\n tags: ${notification.tags?.join(",")}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function scan(config: Config) {
|
export async function scan(config: Config) {
|
||||||
const tasks = await loadTasks(config.sources, config.query);
|
const tasks = await loadTasks(config.sources, config.query);
|
||||||
dumpDatabase(config.databaseFile, tasks, config.mapper);
|
dumpDatabase(config.databaseFile, tasks, config.mapper);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export type CLIOptions = {
|
export type CLIOptions = {
|
||||||
config: string;
|
config: string;
|
||||||
|
test: boolean;
|
||||||
scan: boolean;
|
scan: boolean;
|
||||||
notify: boolean;
|
notify: boolean;
|
||||||
set: string[];
|
set: string[];
|
||||||
|
|||||||
17
src/util/config.ts
Normal file
17
src/util/config.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { readFileSync } from "fs";
|
||||||
|
|
||||||
|
const specialOptions: Record<string, (text: string) => string> = {
|
||||||
|
$__file: (arg: string) => readFileSync(arg, 'utf8').trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enhancedStringConfig = (value: string) => {
|
||||||
|
const trimmed = value.trim();
|
||||||
|
|
||||||
|
for(const opt of Object.keys(specialOptions)) {
|
||||||
|
if(trimmed.startsWith(`${opt}:`) && opt in specialOptions) {
|
||||||
|
return specialOptions[opt](trimmed.slice(opt.length + 1).trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trimmed;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user