diff --git a/packages/message-parser/src/grammar.pegjs b/packages/message-parser/src/grammar.pegjs index e69fcd86f4efe..0173a2e089eea 100644 --- a/packages/message-parser/src/grammar.pegjs +++ b/packages/message-parser/src/grammar.pegjs @@ -33,6 +33,7 @@ tasks, unorderedList, timestamp, + timestampFromHours, } = require('./utils'); let skipBold = false; @@ -74,12 +75,28 @@ Blockquote = b:BlockquoteLine+ { return quote(b); } BlockquoteLine = ">" [ \t]* @Paragraph // +// +// +// TimestampType = "t" / "T" / "d" / "D" / "f" / "F" / "R" Unixtime = d:Digit |10| { return d.join(''); } -Timestamp = "" { return timestamp(date, format); } / "" { return timestamp(date); } +TimestampHoursMinutesSeconds = hours:Digit |2| ":" minutes:Digit|2| ":" seconds:Digit |2| "Z"? { return timestampFromHours(hours.join(''), minutes.join(''), seconds.join('')); } + +TimestampHoursMinutes = hours:Digit |2| ":" minutes:Digit|2| "Z"? { return timestampFromHours(hours.join(''), minutes.join('')); } + + +Timestamp = TimestampHoursMinutesSeconds / TimestampHoursMinutes + + +ISO8601Date = year:Digit |4| "-" month:Digit |2| "-" day:Digit |2| "T" hours:Digit |2| ":" minutes:Digit|2| ":" seconds:Digit |2| "." milliseconds:Digit |3| "Z"? { return new Date(year.join('') + '-' + month.join('') + '-' + day.join('') + 'T' + hours.join('') + ':' + minutes.join('') + ':' + seconds.join('') + '.' + milliseconds.join('') + 'Z').getTime().toString(); } + +ISO8601DateWithoutMilliseconds = year:Digit |4| "-" month:Digit |2| "-" day:Digit |2| "T" hours:Digit |2| ":" minutes:Digit|2| ":" seconds:Digit |2| "Z"? { return new Date(year.join('') + '-' + month.join('') + '-' + day.join('') + 'T' + hours.join('') + ':' + minutes.join('') + ':' + seconds.join('') + 'Z').getTime().toString(); } + + +TimestampRules = "" { return timestamp(date, format); } / "" { return timestamp(date); } /** * @@ -230,7 +247,7 @@ InlineEmoji = & { return !skipInlineEmoji; } emo:Emoji { return emo; } InlineEmoticon = & { return !skipInlineEmoji; } emo:Emoticon & (EmoticonNeighbor / InlineItemPattern) { skipInlineEmoji = false; return emo; } InlineItemPattern = Whitespace - / Timestamp + / TimestampRules / MaybeReferences / AutolinkedPhone / AutolinkedEmail @@ -494,7 +511,7 @@ BoldEmoticon = & { return !skipBoldEmoji; } emo:Emoticon & (EmoticonNeighbor / B /* Strike */ Strikethrough = [\x7E] [\x7E] @StrikethroughContent [\x7E] [\x7E] / [\x7E] @StrikethroughContent [\x7E] -StrikethroughContent = text:(Timestamp / Whitespace / InlineCode / MaybeReferences / UserMention / ChannelMention / MaybeItalic / MaybeBold / Emoji / Emoticon / AnyStrike / Line)+ { +StrikethroughContent = text:(TimestampRules / Whitespace / InlineCode / MaybeReferences / UserMention / ChannelMention / MaybeItalic / MaybeBold / Emoji / Emoticon / AnyStrike / Line)+ { return strike(reducePlainTexts(text)); } diff --git a/packages/message-parser/src/utils.ts b/packages/message-parser/src/utils.ts index 5a52fad9b887c..3bf9b8f689c80 100644 --- a/packages/message-parser/src/utils.ts +++ b/packages/message-parser/src/utils.ts @@ -251,6 +251,20 @@ export const timestamp = ( }; }; +export const timestampFromHours = ( + hours: string, + minutes = '00', + seconds = '00', +) => { + const date = new Date(); + + const yearMonthDay = date.toISOString().split('T')[0]; + + return new Date(`${yearMonthDay}T${hours}:${minutes}:${seconds}Z`) + .getTime() + .toString(); +}; + export const extractFirstResult = ( value: Types[keyof Types]['value'], ): Types[keyof Types]['value'] => { diff --git a/packages/message-parser/tests/timestamp.test.ts b/packages/message-parser/tests/timestamp.test.ts index bb9b72655896e..1073125aacc2e 100644 --- a/packages/message-parser/tests/timestamp.test.ts +++ b/packages/message-parser/tests/timestamp.test.ts @@ -1,5 +1,12 @@ import { parse } from '../src'; -import { bold, paragraph, plain, strike, timestamp } from '../src/utils'; +import { + bold, + paragraph, + plain, + strike, + timestamp, + timestampFromHours, +} from '../src/utils'; test.each([ [``, [paragraph([timestamp('1708551317')])]], @@ -25,3 +32,37 @@ test.each([ ])('parses %p', (input, output) => { expect(parse(input)).toMatchObject(output); }); + +test.each([ + [ + '', + [paragraph([timestamp('1753178400000', 'R')])], + ], + [ + '', + [paragraph([timestamp('1753178400000', 'R')])], + ], + [ + '', + [paragraph([timestamp('1753178400000', 'R')])], + ], + ['', [paragraph([timestamp('1753178400000', 'R')])]], + [ + '', + [paragraph([timestamp(timestampFromHours('10', '00', '00'), 'R')])], + ], + [ + '', + [paragraph([timestamp(timestampFromHours('10', '00', '00'), 'R')])], + ], + [ + '', + [paragraph([timestamp(timestampFromHours('10', '00', '00'), 't')])], + ], + [ + '', + [paragraph([timestamp(timestampFromHours('10', '00', '00'), 't')])], + ], +])('parses %p', (input, output) => { + expect(parse(input)).toMatchObject(output); +});