Skip to content

Commit 3f86dac

Browse files
committed
feat: add overload for join() to accept FormattableString arrays directly
1 parent 5f62cbc commit 3f86dac

File tree

2 files changed

+51
-3
lines changed

2 files changed

+51
-3
lines changed

src/index.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,39 @@ export const customEmoji = buildFormatterWithArgs<[custom_emoji_id: string]>(
231231
* Separator by default is `, `
232232
* @example
233233
* ```ts
234+
* join([format`hello`, format`world`], "\n")
234235
* format`${join(["test", "other"], (x) => format`${bold(x)}`, "\n")}`
235236
* ```
236237
*/
238+
export function join(
239+
array: (Stringable | false | undefined | null)[],
240+
separator?: string,
241+
): FormattableString;
237242
export function join<T>(
238243
array: T[],
239244
iterator: (item: T, index: number) => Stringable | false | undefined | null,
245+
separator?: string,
246+
): FormattableString;
247+
export function join<T>(
248+
array: T[],
249+
iteratorOrSeparator?:
250+
| ((item: T, index: number) => Stringable | false | undefined | null)
251+
| string,
240252
separator = ", ",
241-
) {
253+
): FormattableString {
242254
let text = "";
243255
const entities: TelegramMessageEntity[] = [];
244256

245-
for (const [index, str] of array.map(iterator).entries()) {
257+
const items =
258+
typeof iteratorOrSeparator === "function"
259+
? array.map(iteratorOrSeparator)
260+
: array;
261+
const sep =
262+
typeof iteratorOrSeparator === "string"
263+
? iteratorOrSeparator
264+
: separator;
265+
266+
for (const [index, str] of (items as (Stringable | false | undefined | null)[]).entries()) {
246267
if (str instanceof FormattableString)
247268
entities.push(
248269
...str.entities.map((e) => ({
@@ -251,7 +272,7 @@ export function join<T>(
251272
})),
252273
);
253274
if (typeof str !== "undefined" && str !== null && str !== false)
254-
text += str.toString() + (index === array.length - 1 ? "" : separator);
275+
text += str.toString() + (index === items.length - 1 ? "" : sep);
255276
}
256277

257278
return new FormattableString(text, entities);

tests/index.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,31 @@ describe("Usage format`` thing", () => {
231231
expect(result.text).toBe("text more");
232232
expect(result.entities).toEqual([]);
233233
});
234+
235+
test("join(array, separator) joins FormattableStrings directly", () => {
236+
const result = join([format`${bold("a")}`, format`${italic("b")}`], "\n");
237+
expect(result.text).toBe("a\nb");
238+
expect(result.entities).toEqual([
239+
{ type: "bold", offset: 0, length: 1 },
240+
{ type: "italic", offset: 2, length: 1 },
241+
]);
242+
});
243+
244+
test("join(array, separator) uses default separator', '", () => {
245+
const result = join([bold("x"), bold("y")]);
246+
expect(result.text).toBe("x, y");
247+
expect(result.entities).toEqual([
248+
{ type: "bold", offset: 0, length: 1 },
249+
{ type: "bold", offset: 3, length: 1 },
250+
]);
251+
});
252+
253+
test("join(array, separator) skips falsy values", () => {
254+
const result = join([bold("a"), null, undefined, false, bold("b")], " | ");
255+
expect(result.text).toBe("a | b");
256+
expect(result.entities).toEqual([
257+
{ type: "bold", offset: 0, length: 1 },
258+
{ type: "bold", offset: 4, length: 1 },
259+
]);
260+
});
234261
});

0 commit comments

Comments
 (0)