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

Commit 82c90a1

Browse files
feat: implement tag list to return the textual representation of an array
1 parent 26a3af3 commit 82c90a1

File tree

4 files changed

+171
-0
lines changed

4 files changed

+171
-0
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ lower`I only had ${1} ${'BURRITO'}!`;
5252

5353
* [defaults](#defaults) - _Replace an empty value with a default value_
5454
* [hide](#hide) - _Hides interpolated values_
55+
* [list](#list) - _Textual representation of an array_
5556
* [lower](#lower) - _Lowercase interpolated values_
5657
* [pluralize](#pluralize) - _Choose between singular or plural forms._
5758
* [time](#time) - _Format dates within a string._
@@ -132,6 +133,42 @@ Options:
132133
```
133134

134135

136+
### list
137+
138+
139+
All items in the list are joined with `', '` expected for the last two items
140+
which are joined with `' and '`.
141+
142+
```javascript
143+
import {list} from '@customcommander/tagtical';
144+
145+
const arr = ['Huey', 'Dewey', 'Louie'];
146+
list`Hey ${arr}!`;
147+
//=> "Hey Huey, Dewey and Louie!"
148+
```
149+
150+
Options:
151+
152+
* __delim__ (default `', '`)
153+
154+
The string to use to join all items expect the last.
155+
156+
```javascript
157+
const arr = ['Huey', 'Dewey', 'Louie'];
158+
list({delim: '; '})`Hey ${arr}!`;
159+
//=> "Hey Huey; Dewey and Louie!"
160+
```
161+
* __delimlast__ (default `' and '`)
162+
163+
The string to use to join the last two items.
164+
165+
```javascript
166+
const arr = ['Huey', 'Dewey', 'Louie'];
167+
list({delimlast: ' & '})`Hey ${arr}!`;
168+
//=> "Hey Huey, Dewey & Louie!"
169+
```
170+
171+
135172
### lower
136173

137174

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const use_tag = require('./utils/use-tag');
33
const intersperse = require('./utils/intersperse');
44
const defaults = require('./defaults');
55
const hide = require('./hide');
6+
const list = require('./list');
67
const lower = require('./lower');
78
const pluralize = require('./pluralize');
89
const time = require('./time');
@@ -20,6 +21,7 @@ const tag = (...fns) =>
2021
(intersperse(strs, vals));
2122

2223
tag.defaults = use_tag(defaults);
24+
tag.list = use_tag(list);
2325
tag.hide = use_tag(hide);
2426
tag.lower = use_tag(lower);
2527
tag.pluralize = use_tag(pluralize);

src/list.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
/**
27+
* @typedef {Object} ListOpts
28+
* @property {string} [delim=', ']
29+
* The string to use to join all items expect the last.
30+
*
31+
* ```javascript
32+
* const arr = ['Huey', 'Dewey', 'Louie'];
33+
* list({delim: '; '})`Hey ${arr}!`;
34+
* //=> "Hey Huey; Dewey and Louie!"
35+
* ```
36+
*
37+
* @property {string} [delimlast=' and ']
38+
* The string to use to join the last two items.
39+
*
40+
* ```javascript
41+
* const arr = ['Huey', 'Dewey', 'Louie'];
42+
* list({delimlast: ' & '})`Hey ${arr}!`;
43+
* //=> "Hey Huey, Dewey & Louie!"
44+
* ```
45+
*/
46+
47+
/** @type ListOpts */
48+
const DEFAULT_OPTS =
49+
{ delim: ', '
50+
, delimlast: ' and '
51+
};
52+
53+
/**
54+
* Join `arr` according to given options `opts`.
55+
* @param {ListOpts} opts
56+
* @param {Array} arr
57+
* @return {string}
58+
*/
59+
const join = ({delim, delimlast}, arr) =>
60+
typeof delim !== 'string' ? join({delim: DEFAULT_OPTS.delim, delimlast}, arr)
61+
: typeof delimlast !== 'string' ? join({delim, delimlast: DEFAULT_OPTS.delimlast}, arr)
62+
: arr.length === 0 ? ''
63+
: arr.length === 1 ? arr[0]
64+
: arr.length === 2 ? arr[0] + delimlast + arr[1]
65+
: arr.slice(0, -1).join(delim) + delimlast + arr[arr.length-1];
66+
67+
/**
68+
* Textual representation of an array
69+
*
70+
* All items in the list are joined with `', '` expected for the last two items
71+
* which are joined with `' and '`.
72+
*
73+
* ```javascript
74+
* import {list} from '@customcommander/tagtical';
75+
*
76+
* const arr = ['Huey', 'Dewey', 'Louie'];
77+
* list`Hey ${arr}!`;
78+
* //=> "Hey Huey, Dewey and Louie!"
79+
* ```
80+
*/
81+
module.exports =
82+
tag_function
83+
( (l, x, r, opts) =>
84+
[ l
85+
, Array.isArray(x)
86+
? join(opts, x)
87+
: x
88+
, r
89+
]
90+
, DEFAULT_OPTS
91+
);

test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const tag = require('./dist');
33
const
44
{ defaults
55
, hide
6+
, list
67
, lower
78
, pluralize
89
, time
@@ -197,3 +198,43 @@ test('lower: lowercase all values', t => {
197198
, 'I had bread, beans and covfefe for breakfast'
198199
);
199200
});
201+
202+
test('list: returns a textual representation of a list', t => {
203+
t.plan(6);
204+
205+
t.is
206+
( list`${[]}`
207+
, ''
208+
, 'An empty array returns an empty string'
209+
);
210+
211+
t.is
212+
( list`${['foo']}`
213+
, 'foo'
214+
, 'A single-item array simply returns that item'
215+
);
216+
217+
t.is
218+
( list`${['foo', 'bar']}`
219+
, 'foo and bar'
220+
, 'A pair is joined with the default `delimlast` option'
221+
);
222+
223+
t.is
224+
( list`${['foo', 'bar', 'baz']}`
225+
, 'foo, bar and baz'
226+
, 'Items are joined with the default `delim` and `delimlast` options'
227+
);
228+
229+
t.is
230+
( list({delim: 4, delimlast: 5})`${['foo', 'bar', 'baz']}`
231+
, 'foo, bar and baz'
232+
, '`delim` and `delimlast` must be string'
233+
);
234+
235+
t.is
236+
( list({delim: '; ', delimlast: ' & '})`${['foo', 'bar', 'baz']}`
237+
, 'foo; bar & baz'
238+
, '`delim` and `delimlast` can be changed'
239+
);
240+
});

0 commit comments

Comments
 (0)