refactor: tighten LuaCATS annotations and canonicalize metadata fields (#141)

* refactor: tighten LuaCATS annotations across modules

Problem: type annotations repeated inline unions with no aliases,
used `table<string, any>` where structured types exist, and had
loose `string` where union types should be used.

Solution: add `pending.TaskStatus`, `pending.RecurMode`,
`pending.TaskExtra`, `pending.ForgeType`, `pending.ForgeState`,
`pending.ForgeAuthStatus` aliases and `pending.SyncBackend`
interface. Replace inline unions and loose types with the new
aliases in `store.lua`, `forge.lua`, `config.lua`, `diff.lua`,
`views.lua`, `parse.lua`, `init.lua`, and `oauth.lua`.

* refactor: canonicalize internal metadata field names

Problem: `pending.Metadata` used shorthand field names (`cat`, `rec`,
`rec_mode`) matching user-facing token syntax, coupling internal
representation to config. `RecurSpec.from_completion` used a boolean
where a `pending.RecurMode` alias exists. `category_syntax` was
hardcoded to `'cat'` with no config option.

Solution: rename `Metadata` fields to `category`/`recur`/`recur_mode`,
add `category_syntax` config option (default `'cat'`), rename
`ParsedEntry` fields to match, replace `RecurSpec.from_completion`
with `mode: pending.RecurMode`, and restore `[string]` indexer on
`pending.ForgeConfig` alongside explicit fields.
This commit is contained in:
Barrett Ruth 2026-03-11 12:55:36 -04:00 committed by Barrett Ruth
parent 46b5d52b60
commit 939251f629
Signed by: barrett
GPG key ID: A6C96C9349D2FC81
16 changed files with 144 additions and 80 deletions

View file

@ -2,9 +2,9 @@ local config = require('pending.config')
---@class pending.Metadata
---@field due? string
---@field cat? string
---@field rec? string
---@field rec_mode? 'scheduled'|'completion'
---@field category? string
---@field recur? string
---@field recur_mode? pending.RecurMode
---@field priority? integer
---@class pending.parse
@ -107,6 +107,11 @@ local function is_valid_datetime(s)
return is_valid_date(date_part) and is_valid_time(time_part)
end
---@return string
local function category_key()
return config.get().category_syntax or 'cat'
end
---@return string
local function date_key()
return config.get().date_syntax or 'due'
@ -531,8 +536,10 @@ function M.body(text)
local metadata = {}
local i = #tokens
local ck = category_key()
local dk = date_key()
local rk = recur_key()
local cat_pattern = '^' .. vim.pesc(ck) .. ':(%S+)$'
local date_pattern_strict = '^' .. vim.pesc(dk) .. ':(%d%d%d%d%-%d%d%-%d%d[T%d:]*)$'
local date_pattern_any = '^' .. vim.pesc(dk) .. ':(.+)$'
local rec_pattern = '^' .. vim.pesc(rk) .. ':(%S+)$'
@ -562,12 +569,12 @@ function M.body(text)
metadata.due = resolved
i = i - 1
else
local cat_val = token:match('^cat:(%S+)$')
local cat_val = token:match(cat_pattern)
if cat_val then
if metadata.cat then
if metadata.category then
break
end
metadata.cat = cat_val
metadata.category = cat_val
i = i - 1
else
local pri_bangs = token:match('^%+(!+)$')
@ -581,19 +588,19 @@ function M.body(text)
else
local rec_val = token:match(rec_pattern)
if rec_val then
if metadata.rec then
if metadata.recur then
break
end
local recur = require('pending.recur')
local raw_spec = rec_val
if raw_spec:sub(1, 1) == '!' then
metadata.rec_mode = 'completion'
metadata.recur_mode = 'completion'
raw_spec = raw_spec:sub(2)
end
if not recur.validate(raw_spec) then
break
end
metadata.rec = raw_spec
metadata.recur = raw_spec
i = i - 1
else
break
@ -624,7 +631,7 @@ function M.command_add(text)
local rest = text:sub(#cat_prefix + 2):match('^%s*(.+)$')
if rest then
local desc, meta = M.body(rest)
meta.cat = meta.cat or cat_prefix
meta.category = meta.category or cat_prefix
return desc, meta
end
end