diff --git a/.gitignore b/.gitignore index ce70b4324..bcb152d87 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,4 @@ package-lock.json .idea/ lcov* coverage/ -.history/*.* +.history/**/*.* diff --git a/helpers/__tests__/dateTime.test.js b/helpers/__tests__/dateTime.test.js new file mode 100644 index 000000000..2f5d729a4 --- /dev/null +++ b/helpers/__tests__/dateTime.test.js @@ -0,0 +1,76 @@ +/* globals describe, expect, it, test */ + +// Last updated: 9.12.2021 by @jgclark + +import colors from 'chalk' +import * as dT from '../dateTime' + +const PLUGIN_NAME = `📙 ${colors.yellow('helpers/dateTime')}` +const section = colors.blue + +describe(`${PLUGIN_NAME}`, () => { + + describe(section('dateTime.js'), () => { + + describe('getDateFromString', () => { + test('fail with empty string', () => { + expect(dT.getDateFromString('')).toEqual(undefined) + }) + test('fail with a time string', () => { + expect(dT.getDateFromString('12:30')).toEqual(undefined) + }) + test('work with a valid YYYY-MM-DD string', () => { + expect(dT.getDateFromString('2021-12-12')).toEqual(new Date(2021,11,12,0,0,0)) + }) + test('work with overflow YYYY-MM-DD string', () => { + expect(dT.getDateFromString('2021-14-44')).toEqual(new Date(2022,2,16,0,0,0)) // surprising but true + }) + test('fail with a different date style', () => { + expect(dT.getDateFromString('3/9/2021')).toEqual(undefined) + }) + }) + + describe('getWeek', () => { + /** + * The ISO 8601 definition for week 01 is the week with the first Thursday of the Gregorian + * year (i.e. of January) in it. The following definitions based on properties of this week + * are mutually equivalent, since the ISO week starts with Monday: + * - It is the first week with a majority (4 or more) of its days in January. + * - Its first day is the Monday nearest to 1 January. + * - It has 4 January in it + * - NB: Here start of week is Sunday not Monday. +*/ + test('2021-12-31 Fri -> week 52', () => { + expect(dT.getWeek(new Date(2021, 11, 31, 0, 0, 0))).toEqual(52) + }) + test('2022-01-01 (Sat) -> week 0', () => { + expect(dT.getWeek(new Date(2022, 0, 1, 0, 0, 0))).toEqual(52) + }) + test('2022-01-02 (Sun) -> week 1 (1st day of week)', () => { + expect(dT.getWeek(new Date(2022, 0, 2, 0, 0, 0))).toEqual(1) + }) + test('2022-01-03 (Mon) -> week 1', () => { + expect(dT.getWeek(new Date(2022, 0, 3, 0, 0, 0))).toEqual(1) + }) + test('2022-01-08 (Sat) -> week 1 (last day of week)', () => { + expect(dT.getWeek(new Date(2022, 0, 8, 0, 0, 0))).toEqual(1) + }) + test('2022-01-09 (Sun) -> week 2', () => { + expect(dT.getWeek(new Date(2022, 0, 9, 0, 0, 0))).toEqual(2) + }) + }) + + // Commenting out, as it requires an NP function, which I missed before writing these + // describe('weekStartEnd', () => { + // test('2021W52 -> (2021-12-26, 2022-01-01)', () => { + // expect(dT.weekStartEnd(52, 2021)).toEqual(new Date(2021, 11, 26, 0, 0, 0), new Date(2022, 0, 1, 0, 0, 0)) + // }) + // test('2022W1 -> (2022-01-02, 2022-01-08)', () => { + // expect(dT.weekStartEnd(1, 2022)).toEqual(new Date(2022, 0, 2, 0, 0, 0), new Date(2022, 0, 8, 0, 0, 0)) + // }) + // test('2022W2 -> (2022-01-09, 2022-01-15)', () => { + // expect(dT.weekStartEnd(2, 2022)).toEqual(new Date(2022, 0, 9, 0, 0, 0), new Date(2022, 0, 15, 0, 0, 0)) + // }) + // }) + }) +}) diff --git a/helpers/dateTime.js b/helpers/dateTime.js index 9979545f6..3f1351c69 100644 --- a/helpers/dateTime.js +++ b/helpers/dateTime.js @@ -298,18 +298,15 @@ export function relativeDateFromNumber(diffIn: number): string { /* Turn a string that includes YYYY-MM-DD into a JS Date * @param {string} - string that contains a date e.g. @due(2021-03-04) * @return {?Date} - JS Date version, if valid date found + * @test - available in jest file */ export function getDateFromString(mention: string): ?Date { const RE_DATE_CAPTURE = `(${RE_DATE})` // capture date of form YYYY-MM-DD - if (mention === '') { - // console.log(`\tgetDateFromString: empty string`) - return // no text, so return nothing - } // console.log(`\tgetDateFromString: ${mention}`) const res = mention.match(RE_DATE_CAPTURE) ?? [] // Use first match, if found - if (res[1].length > 0) { + if (res[1]?.length > 0) { const date = new Date( Number(res[1].slice(0, 4)), Number(res[1].slice(5, 7)) - 1, // only seems to be needed for months?! @@ -318,7 +315,7 @@ export function getDateFromString(mention: string): ?Date { // console.log(toISOShortDateTimeString(date)) return date } else { - // console.log(`\tgetDateFromString: no date found`) + console.log(`\t\tgetDateFromString: no valid date found in '${mention}'`) return } } @@ -439,6 +436,7 @@ export function getWeek(inDate: Date): number { * @param {number} week - week number in year (1-53) * @param {number} year - year (4-digits) * @return {[Date, Date]}} - start and end dates (as JS Dates) + * @test - defined in Jest, but won't work until Calendar.addUnitToDate can be stubbed out */ export function weekStartEnd(week: number, year: number): [Date, Date] { if (week > 53 || week < 1) { diff --git a/jgclark.Review/CHANGELOG.md b/jgclark.Review/CHANGELOG.md index 54c57e35a..32c4ac2bf 100644 --- a/jgclark.Review/CHANGELOG.md +++ b/jgclark.Review/CHANGELOG.md @@ -1,9 +1,9 @@ # What's changed in 🔬 Reviews plugin? See [website README for more details](https://github.com/NotePlan/plugins/tree/main/jgclark.Review), and how to configure. -## [0.4.4] - 2021-12-07 +## [0.4.4..0.4.5] - 2021-12-09 ### Fixed -- in some cases /projectList output was failing to be written, which should fix issue #137 (thanks to @brettnotbritt) +- /projectList could fail on invalid `@due()` dates; made the metadata line reader more resilient ## [0.4.1..0.4.3] - 2021-10-24 ### Fixed diff --git a/jgclark.Review/plugin.json b/jgclark.Review/plugin.json index b44cb3e6e..8c24ccaad 100644 --- a/jgclark.Review/plugin.json +++ b/jgclark.Review/plugin.json @@ -6,7 +6,7 @@ "plugin.icon": "", "plugin.author": "Jonathan Clark", "plugin.url": "https://github.com/NotePlan/plugins/tree/main/jgclark.Review/", - "plugin.version": "0.4.4", + "plugin.version": "0.4.5", "plugin.dependencies": [], "plugin.script": "script.js", "plugin.isRemote": "false", diff --git a/jgclark.Review/src/reviewHelpers.js b/jgclark.Review/src/reviewHelpers.js index 16d0d4852..0680cd4bb 100644 --- a/jgclark.Review/src/reviewHelpers.js +++ b/jgclark.Review/src/reviewHelpers.js @@ -1,8 +1,8 @@ // @flow //----------------------------------------------------------------------------- -// @jgclark // Helper functions for Review plugin -// v0.3.0, 21.8.2021 +// @jgclark +// Last updated for v0.4.5, 9.12.2021 //----------------------------------------------------------------------------- import { @@ -236,16 +236,19 @@ export class Project { const hashtags: $ReadOnlyArray = note.hashtags this.note = note this.title = note.title ?? '(error)' - // console.log(`\tnew Project: ${this.title}`) + console.log(`\tnew Project: ${this.title}`) this.folder = getFolderFromFilename(note.filename) - this.dueDate = getDateFromString(getParamMentionFromList(mentions, "@due")) - if (this.dueDate != null && this.dueDate !== '') { + const tempDueDateStr = getParamMentionFromList(mentions, "@due") + this.dueDate = tempDueDateStr !== '' ? getDateFromString(tempDueDateStr) : undefined + if (this.dueDate != null) { // && this.dueDate !== undefined) { // NB: Written while there was an error in EM's Calendar.unitsBetween() function // $FlowIgnore[incompatible-call] this.dueDays = daysBetween(new Date(), this.dueDate) } - this.reviewedDate = getDateFromString(getParamMentionFromList(mentions, "@reviewed")) - this.reviewInterval = getStringFromMention(getParamMentionFromList(mentions, "@review")) + // this.reviewedDate = getDateFromString(getParamMentionFromList(mentions, "@reviewed")) ?? undefined + const tempReviewedDateStr = getParamMentionFromList(mentions, "@reviewed") + this.reviewedDate = tempReviewedDateStr !== '' ? getDateFromString(tempReviewedDateStr) : undefined + this.reviewInterval = getStringFromMention(getParamMentionFromList(mentions, "@review")) ?? undefined if (this.reviewInterval != null) { if (this.reviewedDate != null) { this.nextReviewDate = calcNextReviewDate(this.reviewedDate, this.reviewInterval) @@ -259,8 +262,10 @@ export class Project { this.nextReviewDays = 0 } } - this.completedDate = getDateFromString(getParamMentionFromList(mentions, "@completed")) - this.completedDays = (this.completedDate !== '') + // this.completedDate = getDateFromString(getParamMentionFromList(mentions, "@completed")) ?? undefined + const tempCompletedDateStr = getParamMentionFromList(mentions, "@completed") + this.completedDate = tempCompletedDateStr !== '' ? getDateFromString(tempCompletedDateStr) : undefined + this.completedDays = (this.completedDate != null) // $FlowIgnore[incompatible-call] ? daysBetween(new Date(), this.completedDate) : undefined diff --git a/jgclark.Review/src/reviews.js b/jgclark.Review/src/reviews.js index 2abbc4dda..fa097d3f5 100644 --- a/jgclark.Review/src/reviews.js +++ b/jgclark.Review/src/reviews.js @@ -3,13 +3,13 @@ //----------------------------------------------------------------------------- // Commands for Reviewing project-style notes, GTD-style. // by @jgclark -// v0.4.4, 7.12.2021 +// Last updated for v0.4.5, 9.12.2021 //----------------------------------------------------------------------------- // Settings const DEFAULT_REVIEW_OPTIONS = ` review: { folderToStore: "Reviews", - foldersToIgnore: ["📋 Templates", "Reviews", "Summaries"], // can be empty list + foldersToIgnore: ["@Archive", "📋 Templates", "Reviews", "Summaries"], // can be empty list noteTypeTags: ["#project", "#area"], // array of hashtags without spaces displayOrder: "alpha", // in '/project lists' the sort options are "due" date, "review" date or "alpha" displayGroupedByFolder: true, // in '/project lists' whether to group the notes by folder @@ -17,7 +17,7 @@ const DEFAULT_REVIEW_OPTIONS = ` review: { }, ` let pref_folderToStore: string = "Reviews" -let pref_foldersToIgnore: Array = ["📋 Templates", "Summaries", "Reviews"] +let pref_foldersToIgnore: Array = ["@Archive", "📋 Templates", "Summaries", "Reviews"] let pref_noteTypeTags: Array = ["#project", "#area"] let pref_displayOrder: string = "alpha" let pref_displayGroupedByFolder: boolean = true @@ -268,7 +268,7 @@ function makeNoteTypeSummary(noteTag: string): Array { if (!np.isArchived || pref_displayArchivedProjects) { projects.push(np) } else { - console.log(`\t Ignoring ${np.title} as archived and don't want to show them}`) + console.log(`\t Ignoring ${np.title} as archived and don't want to show them`) } } if (np.nextReviewDays != null && np.nextReviewDays < 0) {