Skip to content
This repository was archived by the owner on Jun 21, 2024. It is now read-only.

Commit 7643979

Browse files
feat: implement tag time to format dates within a string
1 parent 535ac92 commit 7643979

File tree

13 files changed

+395
-19
lines changed

13 files changed

+395
-19
lines changed

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ lower`I only had ${num} ${food}!`;
5959
* [hide](#hide) - _Hides interpolated values_
6060
* [lower](#lower) - _Lowercase interpolated values_
6161
* [pluralize](#pluralize) - _Choose between singular or plural forms._
62+
* [time](#time) - _Format dates within a string._
6263
* [trim](#trim) - _Trim interpolated values_
6364
* [upper](#upper) - _Uppercase interpolated values_
6465

@@ -198,6 +199,48 @@ the `pluralize` tag __won't__ perform any replacement on the adjacent text!
198199

199200
_(The `pluralize` tag does not have any options.)_
200201

202+
### time
203+
204+
205+
The `time` tag formats all interpolated dates according to a given format.
206+
207+
```javascript
208+
import {time} from '@customcommander/tagtical';
209+
210+
time`Last login on ${date}@Y-m-d`;
211+
//=> "Last login on 2020-01-09"
212+
```
213+
214+
The format is attached to the date as follow `${date}@Y-m-d`.
215+
216+
The `@` sign links a date with a format and the format is made of formatting characters
217+
as seen in [PHP's date function](https://www.php.net/manual/en/function.date.php).
218+
The format is removed from the string after processing.
219+
220+
Only a subset of these options is supported at the moment:
221+
222+
| Character | Description |
223+
|:----------|:------------------------------------------------|
224+
| Y | Year. Four digits |
225+
| y | Year. Two digits |
226+
| m | Month. Two digits with leading zeros. e.g. "01" |
227+
| n | Month. No leading zeros. e.g. "1" |
228+
| d | Day. Two digits; leading zeros. e.g. "01" |
229+
| j | Day. No leading zeros. e.g. "1" |
230+
231+
Anything that isn't a formatting character is rendered as is.
232+
233+
When an interpolated value isn't a date, the value is rendered as is and the date format is removed.
234+
235+
```javascript
236+
time`Last login on ${0/0}@Y-m-d`;
237+
//=> Last login on NaN
238+
```
239+
240+
241+
242+
_(The `time` tag does not have any options.)_
243+
201244
### trim
202245

203246

src/index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
const tag_function = require('./utils/tag-function');
22
const use_tag = require('./utils/use-tag');
3-
const join = require('./utils/join');
43
const intersperse = require('./utils/intersperse');
5-
const compose = require('./utils/compose');
64
const defaults = require('./defaults');
75
const hide = require('./hide');
86
const lower = require('./lower');
97
const pluralize = require('./pluralize');
8+
const time = require('./time');
109
const trim = require('./trim');
1110
const upper = require('./upper');
1211

12+
const
13+
{ compose
14+
, join
15+
} = require('./utils/fp');
16+
1317
const tag = (...fns) =>
1418
(strs, ...vals) =>
1519
compose(join(''), ...fns.map(use_tag.unwrap))
@@ -19,6 +23,7 @@ tag.defaults = use_tag(defaults);
1923
tag.hide = use_tag(hide);
2024
tag.lower = use_tag(lower);
2125
tag.pluralize = use_tag(pluralize);
26+
tag.time = use_tag(time);
2227
tag.trim = use_tag(trim);
2328
tag.upper = use_tag(upper);
2429
tag.of = compose(use_tag, tag_function);

src/time.js

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2020 Julien Gonzalez
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in all
13+
* copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
* SOFTWARE.
22+
*/
23+
24+
const tag_function = require('./utils/tag-function');
25+
26+
const
27+
{ compose
28+
, constant
29+
, fallback
30+
, join
31+
, map
32+
, match
33+
, split
34+
, tail
35+
, trim
36+
} = require('./utils/fp');
37+
38+
const INVALID_DATE = String(new Date('All those moments will be lost in time, like tears in the rain.'));
39+
const RE = /^\s*@\S+/;
40+
41+
/** @enum {string} */
42+
const formatOptions =
43+
{ DAY_NUM_LEADING_ZEROS: 'd'
44+
, DAY_NUM: 'j'
45+
, MONTH_NUM_LEADING_ZEROS: 'm'
46+
, MONTH_NUM: 'n'
47+
, YEAR_NUM_LONG: 'Y'
48+
, YEAR_NUM: 'y'
49+
};
50+
51+
/**
52+
* @type {Object<string, function(Date): string>}
53+
*/
54+
const formatFunctions =
55+
{ [formatOptions.DAY_NUM_LEADING_ZEROS]:
56+
d => String(d.getDate()).padStart(2, '0')
57+
58+
, [formatOptions.DAY_NUM]:
59+
d => String(d.getDate())
60+
61+
, [formatOptions.MONTH_NUM_LEADING_ZEROS]:
62+
d => String(d.getMonth() + 1).padStart(2, '0')
63+
64+
, [formatOptions.MONTH_NUM]:
65+
d => String(d.getMonth() + 1)
66+
67+
, [formatOptions.YEAR_NUM_LONG]:
68+
d => String(d.getFullYear())
69+
70+
, [formatOptions.YEAR_NUM]:
71+
d => String(d.getFullYear()).slice(-2)
72+
};
73+
74+
const is_date =
75+
x =>
76+
x instanceof Date
77+
&& String(x) !== INVALID_DATE;
78+
79+
/**
80+
* Extract a date format from a string
81+
*
82+
* @example
83+
* get_format('@Y-m-d some extraneous text');
84+
* //=> "Y-m-d"
85+
*
86+
* @function
87+
* @param {string} str
88+
* @return {string}
89+
*/
90+
const get_format =
91+
compose
92+
( tail
93+
, trim
94+
, fallback('')
95+
, match(RE)
96+
);
97+
98+
const clear_format = str => str.replace(RE, '');
99+
100+
const formatter =
101+
d =>
102+
f =>
103+
(formatFunctions[f] || constant(f))
104+
(d);
105+
106+
const format =
107+
(f, d) =>
108+
compose
109+
( join('')
110+
, map(formatter(d))
111+
, split(/([^Yymndj]+)/)
112+
)(f);
113+
114+
/**
115+
* Format dates within a string.
116+
*
117+
* The `time` tag formats all interpolated dates according to a given format.
118+
*
119+
* ```javascript
120+
* import {time} from '@customcommander/tagtical';
121+
*
122+
* time`Last login on ${date}@Y-m-d`;
123+
* //=> "Last login on 2020-01-09"
124+
* ```
125+
*
126+
* The format is attached to the date as follow `${date}@Y-m-d`.
127+
*
128+
* The `@` sign links a date with a format and the format is made of formatting characters
129+
* as seen in [PHP's date function](https://www.php.net/manual/en/function.date.php).
130+
* The format is removed from the string after processing.
131+
*
132+
* Only a subset of these options is supported at the moment:
133+
*
134+
* | Character | Description |
135+
* |:----------|:------------------------------------------------|
136+
* | Y | Year. Four digits |
137+
* | y | Year. Two digits |
138+
* | m | Month. Two digits with leading zeros. e.g. "01" |
139+
* | n | Month. No leading zeros. e.g. "1" |
140+
* | d | Day. Two digits; leading zeros. e.g. "01" |
141+
* | j | Day. No leading zeros. e.g. "1" |
142+
*
143+
* Anything that isn't a formatting character is rendered as is.
144+
*
145+
* When an interpolated value isn't a date, the value is rendered as is and the date format is removed.
146+
*
147+
* ```javascript
148+
* time`Last login on ${0/0}@Y-m-d`;
149+
* //=> Last login on NaN
150+
* ```
151+
*/
152+
module.exports =
153+
tag_function
154+
( (l, x, r) =>
155+
[ l
156+
, !is_date(x) || !get_format(r)
157+
? x
158+
: format(get_format(r), x)
159+
, clear_format(r)
160+
]
161+
);

src/utils/compose.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/utils/cont.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)