Skip to content

Commit 82a3058

Browse files
committed
Merge remote-tracking branch 'origin/develop' into feat/198-extract-template-service
2 parents 9c7309f + 5a3c6ee commit 82a3058

8 files changed

Lines changed: 84 additions & 34 deletions

File tree

docs/plans/2026-05-18-199-infer-type-context-object.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Trade-off: keeping the interface in `paths.ts` rather than `src/model/interfaces
1717

1818
`inferType` has no VS Code dependencies — safe to run inside Extension Host suite without special plumbing. Lock down all three classification branches before touching the signature:
1919

20-
- attachment: extension mismatch → `JournalPageType.attachement`
20+
- attachment: extension mismatch → `JournalPageType.attachment`
2121
- entry: `extension` matches AND name matches `/^[\d|\-|_]+$/``JournalPageType.entry`
2222
- note: `extension` matches AND name is alphanumeric → `JournalPageType.note`
2323

@@ -80,7 +80,7 @@ All existing tests plus the new unit tests must pass.
8080
## Test scenarios
8181

8282
- **Compile clean:** `npm run compile` and `npm run compile-tests` both exit 0, no TS errors
83-
- **Regressionattachment:** file with non-matching extension`JournalPageType.attachement`
83+
- **Regressionattachment:** file with non-matching extension`JournalPageType.attachment`
8484
- **Regressionentry:** matching extension + digits/dashes/underscores name`JournalPageType.entry`
8585
- **Regressionnote:** matching extension + alphanumeric name`JournalPageType.note`
8686
- **Regex fix verified:** `2026|05|18.md``JournalPageType.note` after Step 0b (pipe no longer in character class)

src/features/entries/scan-entries.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class ScanEntries {
5454
}
5555

5656
// go into base directory, find all files changed within the last X days (see config)
57-
// for each file, check if it is an entry, a note or an attachement
57+
// for each file, check if it is an entry, a note or an attachment
5858
for (const directory of directories) {
5959
try {
6060
await this.fs.stat(directory.path);
@@ -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
});
@@ -89,7 +89,7 @@ export class ScanEntries {
8989
public async getPreviouslyAccessedFiles(thresholdInMs: number, callback: Function, picker: any, type: J.Model.JournalPageType, directories: Set<J.Model.ScopeDirectory>): Promise<void> {
9090

9191
// go into base directory, find all files changed within the last 40 days
92-
// for each file, check if it is an entry, a note or an attachement
92+
// for each file, check if it is an entry, a note or an attachment
9393

9494

9595
this.logger.trace("Entering getPreviouslyAccessedFiles() in actions/reader.ts and number of directories to scan: ", directories.size);
@@ -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/features/sync/sync-note-links.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export class SyncNoteLinks {
1818
*
1919
* @param doc
2020
*/
21-
public async injectAttachementLinks(doc: vscode.TextDocument, date: Date): Promise<vscode.TextDocument> {
22-
this.ctrl.logger.trace("Entering injectAttachementLinks() in features/sync-note-links for date: ", date);
21+
public async injectAttachmentLinks(doc: vscode.TextDocument, date: Date): Promise<vscode.TextDocument> {
22+
this.ctrl.logger.trace("Entering injectAttachmentLinks() in features/sync-note-links for date: ", date);
2323

2424
try {
2525
await this.ctrl.ui.saveDocument(doc);
@@ -33,12 +33,12 @@ export class SyncNoteLinks {
3333
const promises: Promise<J.Model.InlineString>[] = foundFiles
3434
.filter(file => J.Util.isNullOrUndefined(referencedFiles.find(match => match.fsPath === file.fsPath)))
3535
.map(file => {
36-
this.ctrl.logger.debug("injectAttachementLinks() - File link not present in entry: ", file);
36+
this.ctrl.logger.debug("injectAttachmentLinks() - File link not present in entry: ", file);
3737
return this.buildReference(doc, file);
3838
});
3939

4040
const inlineStrings = await Promise.all(promises);
41-
this.ctrl.logger.trace("injectAttachementLinks() - Number of references to synchronize: ", inlineStrings.length);
41+
this.ctrl.logger.trace("injectAttachmentLinks() - Number of references to synchronize: ", inlineStrings.length);
4242

4343
if (inlineStrings.length > 0) {
4444
this.ctrl.inject.injectInlineString(inlineStrings[0], ...inlineStrings.splice(1))

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.attachment;
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/model/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export enum JournalPageType {
22
note,
33
entry,
4-
attachement
4+
attachment
55
}
66

77
export interface ScopedTemplate {

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 → attachment', () => {
11+
const entry = Path.parse('/base/2026/05/2026-05-18.txt');
12+
assert.strictEqual(inferType(entry, ctx), JournalPageType.attachment);
13+
});
14+
15+
test('no extension → attachment', () => {
16+
const entry = Path.parse('/base/2026/05/2026-05-18');
17+
assert.strictEqual(inferType(entry, ctx), JournalPageType.attachment);
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+
});

src/vscode/dialogues.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ export class Dialogues {
126126
this.pickItem(JournalPageType.note).then(selected => {
127127
resolve(selected);
128128
});
129-
} else if (isNotNullOrUndefined(selected.pickItem) && selected.pickItem === JournalPageType.attachement) {
130-
this.pickItem(JournalPageType.attachement).then(selected => {
129+
} else if (isNotNullOrUndefined(selected.pickItem) && selected.pickItem === JournalPageType.attachment) {
130+
this.pickItem(JournalPageType.attachment).then(selected => {
131131
resolve(selected);
132132
});
133133
} else {
@@ -457,7 +457,7 @@ function addItemToPickList(entries: FileEntry[], input: TimedQuickPick, type: Jo
457457
else { displayName = `$(circle-large-filled) ${displayName}`; break; }
458458
}
459459
case JournalPageType.entry: displayName = `$(clock) ${displayName}`; break;
460-
case JournalPageType.attachement: displayName = `$(package) ${displayName}`; break;
460+
case JournalPageType.attachment: displayName = `$(package) ${displayName}`; break;
461461
}
462462

463463

src/vscode/startup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export class Startup {
9898

9999
try {
100100
ctrl.reader.onNotesInjected = (doc, date) => {
101-
new J.Features.SyncNoteLinks(ctrl).injectAttachementLinks(doc, date)
101+
new J.Features.SyncNoteLinks(ctrl).injectAttachmentLinks(doc, date)
102102
.finally(() => ctrl.logger.trace("Scanning notes completed"));
103103
};
104104

0 commit comments

Comments
 (0)