diff --git a/src/TaskSerializer/DefaultTaskSerializer.ts b/src/TaskSerializer/DefaultTaskSerializer.ts index 2ee9d1312c..ccb5a4eb7e 100644 --- a/src/TaskSerializer/DefaultTaskSerializer.ts +++ b/src/TaskSerializer/DefaultTaskSerializer.ts @@ -60,10 +60,13 @@ function dateFieldRegex(symbols: string) { } function fieldRegex(symbols: string, valueRegexString: string) { - let source = symbols; + // \uFE0F? allows an optional Variant Selector 16 on emojis. + let source = symbols + '\uFE0F?'; if (valueRegexString !== '') { source += ' *' + valueRegexString; } + // The regexes end with `$` because they will be matched and + // removed from the end until none are left. source += '$'; return new RegExp(source, 'u'); } @@ -93,10 +96,7 @@ export const DEFAULT_SYMBOLS: DefaultTaskSerializerSymbols = { dependsOnSymbol: 'β›”', idSymbol: 'πŸ†”', TaskFormatRegularExpressions: { - // The following regex's end with `$` because they will be matched and - // removed from the end until none are left. - // \uFE0F? allows an optional Variant Selector 16 on emojis. - priorityRegex: fieldRegex('([πŸ”Ίβ«πŸ”ΌπŸ”½β¬])\uFE0F?', ''), + priorityRegex: fieldRegex('([πŸ”Ίβ«πŸ”ΌπŸ”½β¬])', ''), startDateRegex: dateFieldRegex('πŸ›«'), createdDateRegex: dateFieldRegex('βž•'), scheduledDateRegex: dateFieldRegex('[β³βŒ›]'), @@ -105,7 +105,7 @@ export const DEFAULT_SYMBOLS: DefaultTaskSerializerSymbols = { cancelledDateRegex: dateFieldRegex('❌'), recurrenceRegex: fieldRegex('πŸ”', '([a-zA-Z0-9, !]+)'), onCompletionRegex: fieldRegex('🏁', '([a-zA-Z]+)'), - dependsOnRegex: fieldRegex('β›”\uFE0F?', '(' + taskIdSequenceRegex.source + ')'), + dependsOnRegex: fieldRegex('β›”', '(' + taskIdSequenceRegex.source + ')'), idRegex: fieldRegex('πŸ†”', '(' + taskIdRegex.source + ')'), }, } as const; diff --git a/tests/TaskSerializer/DefaultTaskSerializer.test.ts b/tests/TaskSerializer/DefaultTaskSerializer.test.ts index dd4321235b..6f50109603 100644 --- a/tests/TaskSerializer/DefaultTaskSerializer.test.ts +++ b/tests/TaskSerializer/DefaultTaskSerializer.test.ts @@ -66,16 +66,16 @@ describe('validate emoji regular expressions', () => { expect(generateRegexApprovalTest()).toMatchInlineSnapshot(` " priorityRegex: /([πŸ”Ίβ«πŸ”ΌπŸ”½β¬])\\ufe0f?$/u - startDateRegex: /πŸ›« *(\\d{4}-\\d{2}-\\d{2})$/u - createdDateRegex: /βž• *(\\d{4}-\\d{2}-\\d{2})$/u - scheduledDateRegex: /[β³βŒ›] *(\\d{4}-\\d{2}-\\d{2})$/u - dueDateRegex: /[πŸ“…πŸ“†πŸ—“] *(\\d{4}-\\d{2}-\\d{2})$/u - doneDateRegex: /βœ… *(\\d{4}-\\d{2}-\\d{2})$/u - cancelledDateRegex: /❌ *(\\d{4}-\\d{2}-\\d{2})$/u - recurrenceRegex: /πŸ” *([a-zA-Z0-9, !]+)$/u - onCompletionRegex: /🏁 *([a-zA-Z]+)$/u + startDateRegex: /πŸ›«\\ufe0f? *(\\d{4}-\\d{2}-\\d{2})$/u + createdDateRegex: /βž•\\ufe0f? *(\\d{4}-\\d{2}-\\d{2})$/u + scheduledDateRegex: /[β³βŒ›]\\ufe0f? *(\\d{4}-\\d{2}-\\d{2})$/u + dueDateRegex: /[πŸ“…πŸ“†πŸ—“]\\ufe0f? *(\\d{4}-\\d{2}-\\d{2})$/u + doneDateRegex: /βœ…\\ufe0f? *(\\d{4}-\\d{2}-\\d{2})$/u + cancelledDateRegex: /❌\\ufe0f? *(\\d{4}-\\d{2}-\\d{2})$/u + recurrenceRegex: /πŸ”\\ufe0f? *([a-zA-Z0-9, !]+)$/u + onCompletionRegex: /🏁\\ufe0f? *([a-zA-Z]+)$/u dependsOnRegex: /β›”\\ufe0f? *([a-zA-Z0-9-_]+( *, *[a-zA-Z0-9-_]+ *)*)$/u - idRegex: /πŸ†” *([a-zA-Z0-9-_]+)$/u + idRegex: /πŸ†”\\ufe0f? *([a-zA-Z0-9-_]+)$/u " `); }); @@ -122,6 +122,15 @@ describe.each(symbolMap)("DefaultTaskSerializer with '$taskFormat' symbols", ({ expect(taskDetails).toMatchTaskDetails({ ['scheduledDate']: moment('2021-06-20', 'YYYY-MM-DD') }); }); + it('should parse a scheduledDate - with Variation Selector', () => { + // This test showed the existence of https://github.com/obsidian-tasks-group/obsidian-tasks/issues/3179 + const input = '⏳️ 2024-11-18'; + expect(hasVariantSelector16(input)).toBe(true); + + const taskDetails = deserialize(input); + expect(taskDetails).toMatchTaskDetails({ ['scheduledDate']: moment('2024-11-18', 'YYYY-MM-DD') }); + }); + it('should parse a dueDate - with non-standard emoji 1', () => { const taskDetails = deserialize('πŸ“† 2021-06-20'); expect(taskDetails).toMatchTaskDetails({ ['dueDate']: moment('2021-06-20', 'YYYY-MM-DD') });