diff --git a/graph.svg b/graph.svg
new file mode 100644
index 0000000..bb23cd2
--- /dev/null
+++ b/graph.svg
@@ -0,0 +1,204 @@
+
+
+
+
+
diff --git a/src/dataLayerLoader.ts b/src/dataLayerLoader.ts
index ef16a58..bf51f0b 100644
--- a/src/dataLayerLoader.ts
+++ b/src/dataLayerLoader.ts
@@ -17,6 +17,7 @@ const defaults: Configuration = {
adapter: 'file',
path: `${process.env.HOME}/.config/projector/entries.json`
}
+
export function dispatcher(options = {}) {
const props: Configuration = {...defaults, ...options}
let adapter: DataStoreAdapter
diff --git a/src/dataStoreAdapter.ts b/src/dataStoreAdapter.ts
index 0a54603..811e32c 100644
--- a/src/dataStoreAdapter.ts
+++ b/src/dataStoreAdapter.ts
@@ -1,8 +1,12 @@
import * as E from './entry'
+import { Value } from '@sinclair/typebox/value'
export abstract class DataStoreAdapter { // need separate read/write abstract classes
persistEntry(entry:E.Entry): boolean {
- this.write(JSON.stringify(entry))
+
+ const str = Value.Encode(E.Entry, entry)
+ console.log(str)
+ this.write(JSON.stringify(str))
return true
}
diff --git a/src/entry.ts b/src/entry.ts
index 9167c40..fad466d 100644
--- a/src/entry.ts
+++ b/src/entry.ts
@@ -61,9 +61,9 @@ export const Default = {
// EntryUpdate (compose)
export const Entry = Type.Object({
- id: Type.Number(), // READ nextID()
- uid: Type.String(), // uid()
- path: Type.String(), // path(parent?)
+ id: Type.Number(), // required
+ uid: Type.String(), // required
+ path: Type.String(), // required
type: Type.String({ default: EntryTypes.Transient }),
status: Type.String({ default: StatusNames.Capture }),
@@ -82,7 +82,6 @@ export const Entry = Type.Object({
depends: Type.Array(Type.String(), { default: [] }), // TODO
parents: Type.Array(Type.String(), { default: [] }), // TODO
- // children: Type.Array(Type.String(), { default: [] }), // TODO
recur: Type.Array(Type.String(), { default: [] }), // TODO
repeat: Type.Array(Type.String(), { default: [] }), // TODO
@@ -99,7 +98,7 @@ export const Entry = Type.Object({
start: Type.Optional(Type.Date()),
reviewed: Type.Optional(Type.Date()),
- created: Type.Date({ default: new Date() }), // FIXME won't work in a long-lived process
+ created: Type.Date(),
modified: Type.Optional(Type.Date()),
})
export type Entry = Static
diff --git a/src/fileStoreAdapter.ts b/src/fileStoreAdapter.ts
index 3c71e3c..d769872 100644
--- a/src/fileStoreAdapter.ts
+++ b/src/fileStoreAdapter.ts
@@ -18,7 +18,7 @@ export class FileStoreAdapter extends DataStoreAdapter {
let fd: number
- using cleanup = new DisposableStack();
+ using cleanup = new DisposableStack()
cleanup.defer(() => {
if(fd !== undefined)
fs.closeSync(fd)
diff --git a/src/parser.ts b/src/parser.ts
index 25b8f99..9d2bb9a 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -127,13 +127,9 @@ function buildState(tokens: string[]): State {
} as State
}
+// remove data only needed for tracking parser state,
+// leaving a command, any subcommands, and filters + modifiers
function extractCommand(state: State): ParsedCommand {
- // return {
- // filters: state.filters,
- // command: state.command,
- // modifiers: state.modifiers,
- // } as ParsedCommand
-
const { tokens, processedIndices, ...parsed } = state
return parsed
}
@@ -147,27 +143,19 @@ function extractCommand(state: State): ParsedCommand {
export function parse(tokens: string[]): ParsedCommand {
let state = buildState(tokens)
-
- // find the command [and any subcommands]
- for (let i = 0; i < tokens.length; i++) {
- const word = tokens[i]
- const command: CommandConfig | null = recogniseCommand(word)
-
- if (command) {
- // if(command.subcommands.length > 0) // FIXME track depth
- state.processedIndices[i] = TokenKind.Command
- state.command.push(command.name)
- break // FIXME subcommands
- }
- }
+ state = parseCommands(state)
- if (state.command.length === 0) {
+ if (state.command.length === 0)
state.command.push(defaultCommandName)
- }
+
+ // how we interpret remaining tokens depends on whether they're
+ // before or after a command
+ const commandIndex = state.processedIndices.indexOf(TokenKind.Command)
- tokens.forEach((word, i) => {
+ state.tokens.forEach((word, i) => {
if(state.processedIndices[i] === undefined) {
- const commandIndex = state.processedIndices.indexOf(TokenKind.Command)
+ // todo match IDs, tags, etc ... otherwise
+ // just treat as a word
if (i < commandIndex) {
state.processedIndices[i] = TokenKind.Filter
state.filters.words.push(word)
@@ -175,16 +163,31 @@ export function parse(tokens: string[]): ParsedCommand {
state.processedIndices[i] = TokenKind.Modifier
state.modifiers.words.push(word)
}
- // todo check if it's an ID, tag, etc ... otherwise
- state.processedIndices[i] = TokenKind.Filter
-
}
})
-
- // now extract ids, tags, etc and assign to filters / modifiers
- // depending on their position relative to the command
- // ...
- return extractCommand(state as State)
+ return extractCommand(state)
+}
+
+function parseCommands(state: State): State {
+ let validCommands = CommandConfigs
+
+ // find the command [and any subcommands]
+ for (let i = 0; i < state.tokens.length; i++) {
+ const word = state.tokens[i]
+ const command: CommandConfig | null = recogniseCommand(word, validCommands)
+
+ if (command) {
+ state.processedIndices[i] = TokenKind.Command
+ state.command.push(command.name)
+ validCommands = command.subcommands
+ // there are no valid subcommands: we're done
+ if (validCommands.length === 0)
+ break
+ } else if(state.processedIndices.some( e => {e === TokenKind.Command}))
+ // we've previously found a command, but matched no valid subcommand
+ break
+ }
+ return state // TODO rather than mutate the state, return an immutable update
}
export function parseArgs(argv: string[]): ParsedCommand {
@@ -206,10 +209,7 @@ function commandAliases(
// matchers
//
-export function recogniseCommand(
- word: string,
- candidates = CommandConfigs,
-): CommandConfig | null {
+export function recogniseCommand(word: string, candidates=CommandConfigs): CommandConfig | null {
// check for exact matches of any aliases
const aliases = commandAliases(candidates)
if (Object.keys(aliases).includes(word)) return aliases[word]
diff --git a/test/test-memoryStoreAdapter.ts b/test/test-memoryStoreAdapter.ts
index c3b0c45..912c580 100644
--- a/test/test-memoryStoreAdapter.ts
+++ b/test/test-memoryStoreAdapter.ts
@@ -16,7 +16,7 @@ describe('memoryStoreAdapter', () => {
})
test('read', (t) => {
- assert.deepEqual(mem!.read(), e)
+ assert.deepEqual(mem!.read(), Value.Decode(E.Entry, e))
})
})