Extract duplicated ${variable} template resolution into a single TemplateEngine service so that adding or changing a template variable requires editing exactly one place.
feat-210 (rich domain models) is in progress. Once its types land on develop, a TemplateEngine becomes a natural next refactoring step — the timing avoids double-churn on src/model/.
- Extract
replaceDateFormatsandreplaceDateTemplatesWithMomentsFormatsfromsrc/util/dates.tsinto a newTemplateEnginemodule. - Replace the two parallel switch/case blocks with a single central variable map (
TEMPLATE_VARIABLE_MAP) that holds both the moment format string and resolution logic per variable. - Expose two public functions from the engine:
resolveDate(template, date, locale?)— replaces${var}with actual formatted values (replacesreplaceDateFormats)toMomentFormat(template)— replaces${var}with moment format tokens (replacesreplaceDateTemplatesWithMomentsFormats)
- Delete the duplicate implementation in
src/test/direct/path-parse-with-date.ts:124. - Update all callers:
src/journal/paths.ts,src/vscode/conf.ts,src/features/sync/sync-daily-links.ts. - Keep
replaceVariableValueinsrc/util/strings.ts(generic key/value; not template-engine-specific). - Update barrel exports in
src/util/index.ts.
- Changing the set of supported template variables (no new variables in this PR).
- Replacing
replaceVariableValuewith the engine. - Any changes to
src/vscode/conf.tsbeyond updating the import path. - feat-210 rich domain model changes.
replaceDateFormatsandreplaceDateTemplatesWithMomentsFormatsno longer exist insrc/util/dates.ts.- Adding a new template variable requires editing only
TEMPLATE_VARIABLE_MAP(one location). - All existing tests pass without modification to test assertions.
- The duplicate in
src/test/direct/path-parse-with-date.tsis removed; that file imports from the engine instead. npm run compile(or equivalent) succeeds.- No behavior change — output of
resolveDatematches the oldreplaceDateFormatsoutput for all supported variables.
// Central map — the single source of truth
interface TemplateVariableEntry {
momentFormat: string; // used by toMomentFormat
}
const TEMPLATE_VARIABLE_MAP: Record<string, TemplateVariableEntry> = {
year: { momentFormat: 'YYYY' },
month: { momentFormat: 'MM' },
day: { momentFormat: 'DD' },
localTime: { momentFormat: 'LT' },
localDate: { momentFormat: 'LL' },
weekday: { momentFormat: 'dddd' },
week: { momentFormat: 'w' }, // only in resolveDate currently; add to toMomentFormat for symmetry
};export function resolveDate(template: string, date: Date, locale?: string): string
export function toMomentFormat(template: string): string
// regex stays module-private
const TEMPLATE_VAR_REGEX = /\$\{(?:(year|month|day|localTime|localDate|weekday|week)|(d:[\s\S]+?))\}/g;Issue suggests src/core/templates/engine.ts (new core layer). No src/core/ directory exists today. Alternative: src/util/template-engine.ts (fits existing structure; minimal disruption). Preferred: src/util/template-engine.ts unless the author wants to introduce the core layer for future domain-pure modules.
- Moment.js is the only date library in use; stay with it.
- No new runtime dependencies.
- Must not break
src/test/direct/replace-variables-in-string.ts(importsreplaceDateFormatsfrom../../util/dates— update import).
src/core/templates/engine.tsvssrc/util/template-engine.ts? Thecorelayer would be a new architectural boundary. Is that intentional for #211 or a future concern?weekvariable is present inreplaceDateFormatsbut absent fromreplaceDateTemplatesWithMomentsFormats. Intentional gap or bug? ShouldtoMomentFormatalso map${week}→'w'?
- Blocks: none
- Related: #210 (rich domain models — avoid double-churn; implement after feat-210 lands)
- Related: #209 (domain module naming — completed; barrel keys already aligned)