Skip to content

Commit e3e99b6

Browse files
authored
Merge pull request #216 from pajoma/feat/210-rich-domain-models
refactor(domain): enrich NoteInput with extractScopeAndTags (#210)
2 parents 91fbd08 + 3dfa53a commit e3e99b6

9 files changed

Lines changed: 90 additions & 43 deletions

File tree

src/commands/show-note.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ export class ShowNoteCommand implements vscode.Command, vscode.Disposable {
4848

4949
try {
5050
const userInput: string = await this.ctrl.ui.getUserInput("Enter title for new note");
51-
let parsedInput: J.Model.Input = await this.ctrl.parser.parseInput(userInput);
52-
53-
const doc : vscode.TextDocument = await new J.Features.LoadNotes(parsedInput, this.ctrl).load();
51+
let parsedInput: J.Model.Input = await this.ctrl.parser.parseInput(userInput);
52+
53+
const doc: vscode.TextDocument = await new J.Features.LoadNotes(parsedInput as J.Model.NoteInput, this.ctrl).load();
5454
await this.ctrl.ui.showDocument(doc);
5555

5656

src/features/entries/load-note.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as J from '../..';
88

99
export class LoadNotes {
1010

11-
constructor(public input: J.Model.Input, public ctrl: J.Util.Ctrl) {
11+
constructor(public input: J.Model.NoteInput, public ctrl: J.Util.Ctrl) {
1212

1313
}
1414

src/journal/parser.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919

2020
import * as Path from 'path';
2121
import { IConfiguration, ILogger, Input } from '../model';
22-
import { isNullOrUndefined, isNotNullOrUndefined, normalizeFilename, getCurrentISOWeek, getISOWeekYear } from '../util';
23-
import { SCOPE_DEFAULT } from '../vscode';
22+
import { normalizeFilename, getCurrentISOWeek, getISOWeekYear } from '../util';
2423
import { MatchInput } from './match-input';
2524

2625
/**
@@ -47,20 +46,8 @@ export class Parser {
4746
this.logger.trace("Entering resolveNotePathForInput() in actions/parser.ts");
4847

4948
const date = new Date();
50-
input.scope = SCOPE_DEFAULT;
51-
52-
input.text.match(/#\w+\s/g)?.forEach(tag => {
53-
if (isNullOrUndefined(tag) || tag!.length === 0) { return; }
54-
this.logger.trace("Tags in input string: " + tag);
55-
input.tags.push(tag.trim().substring(0, tag.length - 1));
56-
input.text = input.text.replace(tag, " ");
57-
this.logger.trace("Scopes defined in configuration: " + this.config.getScopes());
58-
const scope: string | undefined = this.config.getScopes().filter((name: string) => name === tag.trim().substring(1, tag.length)).pop();
59-
if (isNotNullOrUndefined(scope) && scope!.length > 0) {
60-
input.scope = scope!;
61-
}
62-
this.logger.trace("Identified scope in input: " + input.scope);
63-
});
49+
input.extractScopeAndTags(this.config.getScopes());
50+
this.logger.trace("Tags in input: " + input.tags + ", scope: " + input.scope);
6451

6552
const inputForFileName = normalizeFilename(input.text);
6653
const granularity = this.config.getEntryGranularity(input.scope);

src/model/config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ export interface InlineTemplate extends ScopedTemplate {
3131
export type EntryGranularity = "daily" | "weekly";
3232
export type NavigationMode = 'existing' | 'calendar';
3333
export interface ScopeDefinitionLite { name?: string; base?: string; }
34-
export type InputDetailsTimeFormat = { sameDay: string; nextDay: string; nextWeek: string; lastDay: string; lastWeek: string; sameElse: string; };
34+
export type InputDetailsTimeFormat = { sameDay: string; nextDay: string; nextWeek: string; lastDay: string; lastWeek: string; sameElse: string; };
35+
36+
export const SCOPE_DEFAULT: string = "default";

src/model/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//
1818

1919

20-
export { EntryGranularity, HeaderTemplate, InlineTemplate, InputDetailsTimeFormat, JournalPageType, NavigationMode, ScopeDefinitionLite, ScopedTemplate } from './config';
20+
export { EntryGranularity, HeaderTemplate, InlineTemplate, InputDetailsTimeFormat, JournalPageType, NavigationMode, ScopeDefinitionLite, ScopedTemplate, SCOPE_DEFAULT } from './config';
2121
export { InlineString } from './inline';
2222
export { Input, NoteInput, SelectedInput } from './input';
2323
export { ScopeDirectory, TemplateInfo } from './templates';

src/model/input.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,20 @@
2020
'use strict';
2121

2222
import { isNullOrUndefined } from "../util/util";
23+
import { SCOPE_DEFAULT } from "./config";
2324

2425
export class Input {
2526

2627

27-
28-
private _offset: number;
29-
private _flags: string = "";
30-
private _text: string = "";
31-
private _scope: string = "";
32-
private _week: number;
28+
29+
private _offset: number;
30+
private _flags: string = "";
31+
protected _text: string = "";
32+
protected _scope: string = SCOPE_DEFAULT;
33+
private _week: number;
3334
private _date: Date | undefined;
34-
35-
private _tags: string[] = [];
35+
36+
protected _tags: string[] = [];
3637

3738

3839

@@ -171,25 +172,31 @@ export class Input {
171172
}
172173
let date = new Date();
173174
date.setDate(date.getDate() + this.offset);
174-
return date;
175-
175+
return date;
176176
}
177177

178-
179-
178+
public extractScopeAndTags(availableScopes: string[]): void {
179+
this._text.match(/#\w+(?:\s|$)/g)?.forEach(match => {
180+
const tag = match.trim();
181+
this._tags.push(tag);
182+
this._text = this._text.replace(match, " ");
183+
const scopeName = tag.substring(1);
184+
const matched = availableScopes.find(name => name === scopeName);
185+
if (matched) { this._scope = matched; }
186+
});
187+
}
180188
}
181189

182190
export class NoteInput extends Input {
183191

184-
private _path: string = "";
192+
private _path: string = "";
185193

186194
constructor() {
187-
super(0);
195+
super(0);
188196
}
189197

190-
public get path() {return this._path;}
191-
public set path( path: string ) {this._path = path;}
192-
198+
public get path() { return this._path; }
199+
public set path(path: string) { this._path = path; }
193200
}
194201

195202
export class SelectedInput extends Input {

src/test/suite/input.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as assert from 'assert';
66
import * as vscode from 'vscode';
77
import * as J from '../..';
88
import { TestLogger } from '../test-logger';
9+
import { SCOPE_DEFAULT } from '../../model/config';
910

1011
suite('Open Journal Entries', () => {
1112
vscode.window.showInformationMessage('Start all tests.');
@@ -219,3 +220,53 @@ suite('Issue #170 — weekday/month/shortcut prefix collisions', () => {
219220
});
220221

221222
});
223+
224+
suite('NoteInput.extractScopeAndTags (#210)', () => {
225+
226+
test("noTags: text without tags stays unchanged, scope defaults", () => {
227+
const input = new J.Model.NoteInput();
228+
input.text = "my note";
229+
input.extractScopeAndTags([]);
230+
assert.strictEqual(input.scope, SCOPE_DEFAULT);
231+
assert.deepStrictEqual(input.tags, []);
232+
assert.strictEqual(input.text, "my note");
233+
});
234+
235+
test("namedScopeMatch: matching tag sets scope, strips from text", () => {
236+
const input = new J.Model.NoteInput();
237+
input.text = "my note #work ";
238+
input.extractScopeAndTags(["work"]);
239+
assert.strictEqual(input.scope, "work");
240+
assert.deepStrictEqual(input.tags, ["#work"]);
241+
assert.ok(!input.text.includes("#work"), "tag should be stripped from text");
242+
});
243+
244+
test("noScopeMatch: unknown tag collected but scope stays default", () => {
245+
const input = new J.Model.NoteInput();
246+
input.text = "my note #unknown ";
247+
input.extractScopeAndTags(["work"]);
248+
assert.strictEqual(input.scope, SCOPE_DEFAULT);
249+
assert.deepStrictEqual(input.tags, ["#unknown"]);
250+
assert.ok(!input.text.includes("#unknown"), "tag should be stripped from text");
251+
});
252+
253+
test("multipleTags: both tags collected, first matching scope wins", () => {
254+
const input = new J.Model.NoteInput();
255+
input.text = "note #work #meeting ";
256+
input.extractScopeAndTags(["work"]);
257+
assert.strictEqual(input.scope, "work");
258+
assert.deepStrictEqual(input.tags, ["#work", "#meeting"]);
259+
assert.ok(!input.text.includes("#work"), "#work should be stripped");
260+
assert.ok(!input.text.includes("#meeting"), "#meeting should be stripped");
261+
});
262+
263+
test("tagAtEndOfString: tag without trailing space is matched (regex fix)", () => {
264+
const input = new J.Model.NoteInput();
265+
input.text = "note #work";
266+
input.extractScopeAndTags(["work"]);
267+
assert.strictEqual(input.scope, "work");
268+
assert.deepStrictEqual(input.tags, ["#work"]);
269+
assert.ok(!input.text.includes("#work"), "tag should be stripped from text");
270+
});
271+
272+
});

src/test/suite/read-templates.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ suite('Read templates from configuration', () => {
8383

8484
// create a new note
8585
const privInput = await ctrl.parser.parseInput("#priv a note created in private scop");
86-
let privNotes = await new J.Features.LoadNotes(privInput, ctrl);
86+
let privNotes = await new J.Features.LoadNotes(privInput as J.Model.NoteInput, ctrl);
8787
let privDoc: vscode.TextDocument = await privNotes.load();
8888
privDoc = await ctrl.ui.saveDocument(privDoc);
8989
const privUri = privDoc.uri;
9090

9191

9292

9393
const workInput = await ctrl.parser.parseInput("#work a note created in work scope");
94-
let workDoc: vscode.TextDocument = await new J.Features.LoadNotes(workInput, ctrl).load();
94+
let workDoc: vscode.TextDocument = await new J.Features.LoadNotes(workInput as J.Model.NoteInput, ctrl).load();
9595
workDoc = await ctrl.ui.saveDocument(workDoc);
9696
const uriWork = workDoc.uri;
9797

src/vscode/conf.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import * as os from 'os';
2222
import * as Path from 'path';
2323
import { Util } from '..';
2424
import { isNotNullOrUndefined, isNullOrUndefined } from '../util';
25-
import { HeaderTemplate, InlineTemplate, ScopedTemplate } from '../model';
25+
import { HeaderTemplate, InlineTemplate, ScopedTemplate, SCOPE_DEFAULT } from '../model';
2626
import { replaceDateFormats, replaceVariableValue } from '../util';
2727

28-
export const SCOPE_DEFAULT: string = "default";
28+
export { SCOPE_DEFAULT };
2929

3030
export type WeeklySyncConfig = {
3131
enabled: boolean;

0 commit comments

Comments
 (0)