From 52f16d4bc337c25eaad036f961764ac406660f45 Mon Sep 17 00:00:00 2001 From: David Lee Date: Thu, 31 Aug 2023 09:29:21 +1000 Subject: [PATCH] mostly refactoring parser --- graph.svg | 204 ++++++++++++++++++++++++++++++++ src/dataLayerLoader.ts | 1 + src/dataStoreAdapter.ts | 6 +- src/entry.ts | 9 +- src/fileStoreAdapter.ts | 2 +- src/parser.ts | 70 +++++------ test/test-memoryStoreAdapter.ts | 2 +- 7 files changed, 251 insertions(+), 43 deletions(-) create mode 100644 graph.svg diff --git a/graph.svg b/graph.svg new file mode 100644 index 0000000..bb23cd2 --- /dev/null +++ b/graph.svg @@ -0,0 +1,204 @@ + + + + + + +dependency-cruiser output + + +cluster_src + +src + + + +src/commandHandler.ts + + +commandHandler.ts + + + + + +src/entry.ts + + +entry.ts + + + + + +src/commandHandler.ts->src/entry.ts + + + + + +src/uid.ts + + +uid.ts + + + + + +src/commandHandler.ts->src/uid.ts + + + + + +src/configLoader.ts + + +configLoader.ts + + + + + +src/dataLayerLoader.ts + + +dataLayerLoader.ts + + + + + +src/dataLayerLoader.ts->src/commandHandler.ts + + + + + +src/dispatcher.ts + + +dispatcher.ts + + + + + +src/dataLayerLoader.ts->src/dispatcher.ts + + + + + +src/entryRepository.ts + + +entryRepository.ts + + + + + +src/dataLayerLoader.ts->src/entryRepository.ts + + + + + +src/fileStoreAdapter.ts + + +fileStoreAdapter.ts + + + + + +src/dataLayerLoader.ts->src/fileStoreAdapter.ts + + + + + +src/memoryStoreAdapter.ts + + +memoryStoreAdapter.ts + + + + + +src/dataLayerLoader.ts->src/memoryStoreAdapter.ts + + + + + +src/entryRepository.ts->src/entry.ts + + + + + +src/dataStoreAdapter.ts + + +dataStoreAdapter.ts + + + + + +src/fileStoreAdapter.ts->src/dataStoreAdapter.ts + + + + + +src/memoryStoreAdapter.ts->src/dataStoreAdapter.ts + + + + + +src/dataStoreAdapter.ts->src/entry.ts + + + + + +src/index.ts + + +index.ts + + + + + +src/index.ts->src/dataLayerLoader.ts + + + + + +src/parser.ts + + +parser.ts + + + + + +src/index.ts->src/parser.ts + + + + + 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)) }) })