Skip to content

Commit ec21f35

Browse files
authored
Merge pull request #41 from KnightNiwrem/master
feat: Add optional `separator` parameter for static `join` method on `FormattedString`
2 parents 52f35ca + 09d9165 commit ec21f35

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

src/format.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,17 +316,27 @@ export class FormattedString
316316
/**
317317
* Joins an array of formatted strings or plain text into a single FormattedString
318318
* @param items Array of text items to join (can be TextWithEntities, CaptionWithEntities, or string)
319+
* @param separator Optional separator to insert between items (defaults to empty string)
319320
* @returns A new FormattedString combining all items
320321
*/
321322
static join(
322323
items: (Stringable | TextWithEntities | CaptionWithEntities | string)[],
324+
separator?: Stringable | TextWithEntities | CaptionWithEntities | string,
323325
) {
324326
if (items.length === 0) {
325327
return new FormattedString("");
326328
}
327329

328-
return items.reduce((acc, item) => {
329-
return fmt`${acc}${item}`;
330+
if (items.length === 1) {
331+
return fmt`${items[0]}`;
332+
}
333+
334+
const sep = separator ?? "";
335+
return items.reduce<FormattedString>((acc, item, index) => {
336+
if (index === 0) {
337+
return fmt`${item}`;
338+
}
339+
return fmt`${acc}${sep}${item}`;
330340
}, new FormattedString(""));
331341
}
332342

test/format.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,76 @@ Deno.test("FormattedString - Static join method", () => {
774774
assertEquals(combinedResult.rawEntities[1]?.length, 7); // "Caption"
775775
});
776776

777+
Deno.test("FormattedString - Static join method with separator", () => {
778+
// Test basic string separator
779+
const result1 = FormattedString.join(["a", "b", "c"], " ");
780+
assertInstanceOf(result1, FormattedString);
781+
assertEquals(result1.rawText, "a b c");
782+
assertEquals(result1.rawEntities.length, 0);
783+
784+
// Test different separator
785+
const result2 = FormattedString.join(["Hello", "World"], " - ");
786+
assertInstanceOf(result2, FormattedString);
787+
assertEquals(result2.rawText, "Hello - World");
788+
assertEquals(result2.rawEntities.length, 0);
789+
790+
// Test with empty separator (should be same as no separator)
791+
const result3 = FormattedString.join(["a", "b", "c"], "");
792+
const result4 = FormattedString.join(["a", "b", "c"]);
793+
assertEquals(result3.rawText, result4.rawText);
794+
795+
// Test with single item and separator
796+
const result5 = FormattedString.join(["single"], " - ");
797+
assertEquals(result5.rawText, "single");
798+
799+
// Test with empty array and separator
800+
const result6 = FormattedString.join([], " - ");
801+
assertEquals(result6.rawText, "");
802+
803+
// Test with formatted strings and separator
804+
const boldText = FormattedString.bold("Bold");
805+
const italicText = FormattedString.italic("Italic");
806+
const result7 = FormattedString.join([boldText, italicText], " | ");
807+
808+
assertInstanceOf(result7, FormattedString);
809+
assertEquals(result7.rawText, "Bold | Italic");
810+
assertEquals(result7.rawEntities.length, 2);
811+
812+
// Test entity positions with separator
813+
assertEquals(result7.rawEntities[0]?.type, "bold");
814+
assertEquals(result7.rawEntities[0]?.offset, 0);
815+
assertEquals(result7.rawEntities[0]?.length, 4); // "Bold"
816+
817+
assertEquals(result7.rawEntities[1]?.type, "italic");
818+
assertEquals(result7.rawEntities[1]?.offset, 7); // After "Bold | "
819+
assertEquals(result7.rawEntities[1]?.length, 6); // "Italic"
820+
821+
// Test with FormattedString as separator
822+
const separatorFormatted = FormattedString.underline(" - ");
823+
const result8 = FormattedString.join(["Hello", "World"], separatorFormatted);
824+
825+
assertInstanceOf(result8, FormattedString);
826+
assertEquals(result8.rawText, "Hello - World");
827+
assertEquals(result8.rawEntities.length, 1);
828+
assertEquals(result8.rawEntities[0]?.type, "underline");
829+
assertEquals(result8.rawEntities[0]?.offset, 5); // After "Hello"
830+
assertEquals(result8.rawEntities[0]?.length, 3); // " - "
831+
832+
// Test with TextWithEntities as separator
833+
const textSeparator = {
834+
text: " -> ",
835+
entities: [{ type: "code", offset: 1, length: 2 }], // "->"
836+
};
837+
const result9 = FormattedString.join(["A", "B"], textSeparator);
838+
839+
assertInstanceOf(result9, FormattedString);
840+
assertEquals(result9.rawText, "A -> B");
841+
assertEquals(result9.rawEntities.length, 1);
842+
assertEquals(result9.rawEntities[0]?.type, "code");
843+
assertEquals(result9.rawEntities[0]?.offset, 2); // After "A "
844+
assertEquals(result9.rawEntities[0]?.length, 2); // "->"
845+
});
846+
777847
Deno.test("FormattedString - Instance slice method", () => {
778848
// Test the example from the problem statement
779849
const originalText = "hello bold and italic world";

0 commit comments

Comments
 (0)