Skip to content

Commit 34f3a09

Browse files
authored
Merge pull request #3373 from obsidian-tasks-group/refactor-identicalTo
refactor: Provide consistent identicalTo() methods
2 parents a1be7ea + a8b70f5 commit 34f3a09

File tree

7 files changed

+124
-21
lines changed

7 files changed

+124
-21
lines changed

src/Scripting/TasksFile.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,18 @@ export class TasksFile {
221221
return lowerCaseSearchKey === lowerCaseKey;
222222
});
223223
}
224+
225+
/**
226+
* Compare all the fields in another TasksFile, to detect any differences from this one.
227+
*
228+
* If any field is different in any way, it will return false.
229+
*
230+
* @param other
231+
*/
232+
public identicalTo(other: TasksFile) {
233+
if (this.path !== other.path) {
234+
return false;
235+
}
236+
return this.rawFrontmatterIdenticalTo(other);
237+
}
224238
}

src/Task/ListItem.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,24 +135,17 @@ export class ListItem {
135135
return false;
136136
}
137137

138-
// Note: sectionStart changes every time a line is added or deleted before
138+
// Note: taskLocation changes every time a line is added or deleted before
139139
// any of the tasks in a file. This does mean that redrawing of tasks blocks
140140
// happens more often than is ideal.
141-
const args: Array<keyof ListItem> = [
142-
'originalMarkdown',
143-
'description',
144-
'statusCharacter',
145-
'path',
146-
'lineNumber',
147-
'sectionStart',
148-
'sectionIndex',
149-
'precedingHeader',
150-
];
141+
const args: Array<keyof ListItem> = ['description', 'statusCharacter', 'indentation', 'listMarker'];
151142

152143
for (const el of args) {
153144
if (this[el]?.toString() !== other[el]?.toString()) return false;
154145
}
155146

147+
if (!this.taskLocation.identicalTo(other.taskLocation)) return false;
148+
156149
return ListItem.listsAreIdentical(this.children, other.children);
157150
}
158151

src/Task/Task.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ interface TaskComponents {
4141
export class Task extends ListItem {
4242
// NEW_TASK_FIELD_EDIT_REQUIRED
4343
public readonly status: Status;
44-
public readonly description: string;
45-
public readonly indentation: string;
46-
public readonly listMarker: string;
4744

4845
public readonly tags: string[];
4946

@@ -128,9 +125,6 @@ export class Task extends ListItem {
128125
});
129126
// NEW_TASK_FIELD_EDIT_REQUIRED
130127
this.status = status;
131-
this.description = description;
132-
this.indentation = indentation;
133-
this.listMarker = listMarker;
134128

135129
this.tags = tags;
136130

@@ -784,9 +778,6 @@ export class Task extends ListItem {
784778
// any of the tasks in a file. This does mean that redrawing of tasks blocks
785779
// happens more often than is ideal.
786780
let args: Array<keyof Task> = [
787-
'description',
788-
'indentation',
789-
'listMarker',
790781
'priority',
791782
'blockLink',
792783
'scheduledDateIsInferred',

src/Task/TaskLocation.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,23 @@ export class TaskLocation {
9090
const { _tasksFile, ...rest } = { ...this };
9191
return rest;
9292
}
93+
94+
/**
95+
* Compare all the fields in another TaskLocation, to detect any differences from this one.
96+
*
97+
* If any field is different in any way, it will return false.
98+
*
99+
* @param other
100+
*/
101+
public identicalTo(other: TaskLocation) {
102+
const args: Array<keyof TaskLocation> = ['lineNumber', 'sectionStart', 'sectionIndex', 'precedingHeader'];
103+
104+
for (const el of args) {
105+
if (this[el] !== other[el]) return false;
106+
}
107+
108+
// We do this at the end because TasksFile objects are more expensive
109+
// to compare, due to their storing potentially complext Properties data.
110+
return this._tasksFile.identicalTo(other._tasksFile);
111+
}
93112
}

tests/Scripting/TasksFile.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,26 @@ describe('TasksFile - properties', () => {
323323
expect(tasksFile.property('capital_property')).toEqual('some value');
324324
});
325325
});
326+
327+
describe('TasksFile - identicalTo', () => {
328+
const path = 'a/b/c/d.md';
329+
const cachedMetadata = {};
330+
331+
it('should detect identical objects', () => {
332+
const lhs = new TasksFile(path, cachedMetadata);
333+
const rhs = new TasksFile(path, cachedMetadata);
334+
expect(lhs.identicalTo(rhs)).toEqual(true);
335+
});
336+
337+
it('should check path', () => {
338+
const lhs = new TasksFile(path, cachedMetadata);
339+
const rhs = new TasksFile('somewhere else.md', cachedMetadata);
340+
expect(lhs.identicalTo(rhs)).toEqual(false);
341+
});
342+
343+
it('should check cachedMetadata', () => {
344+
const lhs = getTasksFileFromMockData(example_kanban);
345+
expect(lhs.identicalTo(getTasksFileFromMockData(example_kanban))).toEqual(true);
346+
expect(lhs.identicalTo(getTasksFileFromMockData(jason_properties))).toEqual(false);
347+
});
348+
});

tests/Task/ListItem.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,28 @@ describe('identicalTo', () => {
247247
expect(item2.identicalTo(item1)).toEqual(false);
248248
});
249249

250+
it('should recognise different indentation', () => {
251+
const item1 = ListItem.fromListItemLine('- item', null, taskLocation);
252+
const item2 = ListItem.fromListItemLine(' - item', null, taskLocation);
253+
254+
expect(item2.identicalTo(item1)).toEqual(false);
255+
});
256+
257+
it('should recognise different listMarker', () => {
258+
const item1 = ListItem.fromListItemLine('- item', null, taskLocation);
259+
const item2 = ListItem.fromListItemLine('* item', null, taskLocation);
260+
261+
expect(item2.identicalTo(item1)).toEqual(false);
262+
});
263+
250264
it('should recognise ListItem and Task as different', () => {
251265
const listItem = ListItem.fromListItemLine('- [ ] description', null, taskLocation);
252266
const task = fromLine({ line: '- [ ] description' });
253267

254268
expect(listItem.identicalTo(task)).toEqual(false);
255269
});
256270

257-
it('should recognise different path', () => {
271+
it('should recognise different taskLocation', () => {
258272
const item1 = ListItem.fromListItemLine(
259273
'- same',
260274
null,

tests/Task/TaskLocation.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,52 @@ describe('TaskLocation', () => {
7575
expect(TaskLocation.fromUnknownPosition(new TasksFile('')).hasKnownPath).toBe(false);
7676
});
7777
});
78+
79+
describe('TaskLocation - identicalTo', function () {
80+
const tasksFile: TasksFile = new TasksFile('x.md');
81+
const lineNumber: number = 40;
82+
const sectionStart: number = 30;
83+
const sectionIndex: number = 3;
84+
const precedingHeader: string | null = 'heading';
85+
86+
const lhs = new TaskLocation(tasksFile, lineNumber, sectionStart, sectionIndex, precedingHeader);
87+
88+
it('should detect identical objects', () => {
89+
const rhs = new TaskLocation(tasksFile, lineNumber, sectionStart, sectionIndex, precedingHeader);
90+
expect(lhs.identicalTo(rhs)).toEqual(true);
91+
});
92+
93+
it('should check tasksFile', () => {
94+
const rhs = new TaskLocation(new TasksFile('y.md'), lineNumber, sectionStart, sectionIndex, precedingHeader);
95+
expect(lhs.identicalTo(rhs)).toEqual(false);
96+
});
97+
98+
it('should check lineNumber', () => {
99+
const rhs = new TaskLocation(tasksFile, 0, sectionStart, sectionIndex, precedingHeader);
100+
expect(lhs.identicalTo(rhs)).toEqual(false);
101+
});
102+
103+
it('should check sectionStart', () => {
104+
const rhs = new TaskLocation(tasksFile, lineNumber, 0, sectionIndex, precedingHeader);
105+
expect(lhs.identicalTo(rhs)).toEqual(false);
106+
});
107+
108+
it('should check sectionIndex', () => {
109+
const rhs = new TaskLocation(tasksFile, lineNumber, sectionStart, 0, precedingHeader);
110+
expect(lhs.identicalTo(rhs)).toEqual(false);
111+
});
112+
113+
it('should check precedingHeader', () => {
114+
{
115+
const precedingHeader = null;
116+
const rhs = new TaskLocation(tasksFile, lineNumber, sectionStart, sectionIndex, precedingHeader);
117+
expect(lhs.identicalTo(rhs)).toEqual(false);
118+
}
119+
120+
{
121+
const precedingHeader = 'different header';
122+
const rhs = new TaskLocation(tasksFile, lineNumber, sectionStart, sectionIndex, precedingHeader);
123+
expect(lhs.identicalTo(rhs)).toEqual(false);
124+
}
125+
});
126+
});

0 commit comments

Comments
 (0)