Skip to content

Commit 6a49535

Browse files
authored
Merge pull request #220 from pajoma/worktree-feat+199-infer-type-context-object
refactor(paths): decouple inferType from raw positional args (#199)
2 parents 8071990 + 83804d0 commit 6a49535

3 files changed

Lines changed: 71 additions & 21 deletions

File tree

src/features/entries/scan-entries.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class ScanEntries {
6565

6666
await this.walkDir(directory.path, thresholdInMs, (entries: J.Model.FileEntry[]) => {
6767
entries.forEach(entry => {
68-
entry.type = J.Journal.inferType(Path.parse(entry.path), this.config.getFileExtension());
68+
entry.type = J.Journal.inferType(Path.parse(entry.path), { extension: this.config.getFileExtension() });
6969
entry.scope = directory.scope;
7070
this.cache.set(entry.path, entry);
7171
});
@@ -137,7 +137,7 @@ export class ScanEntries {
137137

138138
await this.walkDir(directory.path, thresholdInMs, (entries: J.Model.FileEntry[]) => {
139139
entries.forEach(fe => {
140-
fe.type = J.Journal.inferType(Path.parse(fe.path), this.config.getFileExtension());
140+
fe.type = J.Journal.inferType(Path.parse(fe.path), { extension: this.config.getFileExtension() });
141141
fe.scope = directory.scope;
142142
if (!this.cache.has(fe.path)) {
143143
this.cache.set(fe.path, fe);

src/journal/paths.ts

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -168,25 +168,20 @@ export async function checkIfFileIsAccessible(path: string): Promise<void> {
168168
}
169169

170170

171-
/**
172-
* Tries to infer the file type from the path by matching against the configured patterns
173-
* @param entry - path to entry
174-
* @param ext - configured standard extension
175-
*/
176-
export function inferType(entry: Path.ParsedPath, extension: string): J.Model.JournalPageType {
177-
178-
if (!entry.ext.endsWith(extension)) {
179-
return J.Model.JournalPageType.attachement; // any attachement
180-
} else
181-
182-
// this is getting out of hand if we need to infer it by scanning the patterns from the settings.
183-
// We keep it simple: if the filename contains only digits and special chars, we assume it
184-
// is a journal entry. Everything else is a journal note.
185-
if (entry.name.match(/^[\d|\-|_]+$/gm)) {
186-
return J.Model.JournalPageType.entry; // any entry
187-
} else {
188-
return J.Model.JournalPageType.note; // anything else is a note
189-
}
171+
/** Context passed to inferType. All future fields must be optional (?:) to prevent shotgun surgery. */
172+
export interface InferTypeContext {
173+
extension: string;
174+
}
175+
176+
export function inferType(entry: Path.ParsedPath, ctx: InferTypeContext): J.Model.JournalPageType {
177+
178+
if (!entry.ext.endsWith(ctx.extension)) {
179+
return J.Model.JournalPageType.attachement;
180+
} else if (entry.name.match(/^[\d\-_]+$/)) {
181+
return J.Model.JournalPageType.entry;
182+
} else {
183+
return J.Model.JournalPageType.note;
184+
}
190185

191186

192187
}

src/test/suite/infer-type.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import * as assert from 'assert';
2+
import * as Path from 'path';
3+
import { inferType, InferTypeContext } from '../../journal/paths';
4+
import { JournalPageType } from '../../model/config';
5+
6+
suite('inferType — classification', () => {
7+
const ctx: InferTypeContext = { extension: '.md' };
8+
9+
suite('attachment', () => {
10+
test('extension mismatch → attachement', () => {
11+
const entry = Path.parse('/base/2026/05/2026-05-18.txt');
12+
assert.strictEqual(inferType(entry, ctx), JournalPageType.attachement);
13+
});
14+
15+
test('no extension → attachement', () => {
16+
const entry = Path.parse('/base/2026/05/2026-05-18');
17+
assert.strictEqual(inferType(entry, ctx), JournalPageType.attachement);
18+
});
19+
});
20+
21+
suite('entry', () => {
22+
test('digits-only name → entry', () => {
23+
const entry = Path.parse('/base/2026/05/20260518.md');
24+
assert.strictEqual(inferType(entry, ctx), JournalPageType.entry);
25+
});
26+
27+
test('digits with hyphens → entry', () => {
28+
const entry = Path.parse('/base/2026/05/2026-05-18.md');
29+
assert.strictEqual(inferType(entry, ctx), JournalPageType.entry);
30+
});
31+
32+
test('digits with underscores → entry', () => {
33+
const entry = Path.parse('/base/2026/05/2026_05_18.md');
34+
assert.strictEqual(inferType(entry, ctx), JournalPageType.entry);
35+
});
36+
37+
test('pipe-separated name → note (pipe not a separator)', () => {
38+
// Pipe was previously a literal in the character class; now correctly excluded.
39+
const entry = Path.parse('/base/2026/05/2026|05|18.md');
40+
assert.strictEqual(inferType(entry, ctx), JournalPageType.note);
41+
});
42+
});
43+
44+
suite('note', () => {
45+
test('alphanumeric name → note', () => {
46+
const entry = Path.parse('/base/2026/05/my-note.md');
47+
assert.strictEqual(inferType(entry, ctx), JournalPageType.note);
48+
});
49+
50+
test('name with letters and digits → note', () => {
51+
const entry = Path.parse('/base/2026/05/meeting2026.md');
52+
assert.strictEqual(inferType(entry, ctx), JournalPageType.note);
53+
});
54+
});
55+
});

0 commit comments

Comments
 (0)