Skip to content

Commit 0430b66

Browse files
committed
feat: implement variations generator with input and options schemas
1 parent 1a0db6c commit 0430b66

File tree

2 files changed

+254
-0
lines changed

2 files changed

+254
-0
lines changed

src/generators/variations.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { type } from "arktype";
2+
import { createLoom } from "../loom";
3+
4+
const variationsInputSchema = type({
5+
codePoints: "string[]",
6+
style: "string",
7+
comment: "string",
8+
});
9+
10+
const variationsOptionsSchema = type({
11+
separator: "string",
12+
commentPrefix: "string",
13+
version: "string",
14+
});
15+
16+
export const variations = createLoom({
17+
inputSchema: variationsInputSchema,
18+
optionsSchema: variationsOptionsSchema,
19+
template: (ctx, item) => {
20+
return `${item.codePoints.join(" ")} ${ctx.options.separator} ${item.style} ${ctx.options.separator} ${ctx.options.commentPrefix} ${item.comment}`;
21+
},
22+
eof: true,
23+
presets: {
24+
commonSymbols: [
25+
{
26+
codePoints: ["2764", "FE0E"],
27+
style: "text",
28+
comment: "heart as text symbol",
29+
},
30+
{
31+
codePoints: ["2764", "FE0F"],
32+
style: "emoji",
33+
comment: "heart as emoji symbol",
34+
},
35+
{
36+
codePoints: ["2B50", "FE0E"],
37+
style: "text",
38+
comment: "star as text symbol",
39+
},
40+
{
41+
codePoints: ["2B50", "FE0F"],
42+
style: "emoji",
43+
comment: "star as emoji symbol",
44+
},
45+
],
46+
punctuation: [
47+
{
48+
codePoints: ["2757", "FE0E"],
49+
style: "text",
50+
comment: "exclamation mark as text",
51+
},
52+
{
53+
codePoints: ["2757", "FE0F"],
54+
style: "emoji",
55+
comment: "exclamation mark as emoji",
56+
},
57+
{
58+
codePoints: ["2753", "FE0E"],
59+
style: "text",
60+
comment: "question mark as text",
61+
},
62+
{
63+
codePoints: ["2753", "FE0F"],
64+
style: "emoji",
65+
comment: "question mark as emoji",
66+
},
67+
],
68+
miscellaneous: [
69+
{
70+
codePoints: ["2600", "FE0E"],
71+
style: "text",
72+
comment: "sun as text symbol",
73+
},
74+
{
75+
codePoints: ["2600", "FE0F"],
76+
style: "emoji",
77+
comment: "sun as emoji symbol",
78+
},
79+
{
80+
codePoints: ["2695", "FE0E"],
81+
style: "text",
82+
comment: "medical symbol as text",
83+
},
84+
{
85+
codePoints: ["2695", "FE0F"],
86+
style: "emoji",
87+
comment: "medical symbol as emoji",
88+
},
89+
],
90+
},
91+
});

test/variations.test.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { describe, expect, it } from "vitest";
2+
import { variations } from "../src/generators/variations";
3+
4+
describe("variations", () => {
5+
const defaultOptions = {
6+
separator: "|",
7+
commentPrefix: "#",
8+
version: "1.0",
9+
};
10+
11+
it("should format a variation with valid input", () => {
12+
const input = {
13+
codePoints: ["2764", "FE0F"],
14+
style: "emoji",
15+
comment: "heart symbol",
16+
};
17+
18+
const result = variations({ ...defaultOptions, input: [input] });
19+
expect(result).toBe(
20+
"2764 FE0F | emoji | # heart symbol\n"
21+
+ "#EOF\n",
22+
);
23+
});
24+
25+
it("should handle multiple variations", () => {
26+
const inputs = [
27+
{
28+
codePoints: ["2764", "FE0E"],
29+
style: "text",
30+
comment: "text heart",
31+
},
32+
{
33+
codePoints: ["2764", "FE0F"],
34+
style: "emoji",
35+
comment: "emoji heart",
36+
},
37+
];
38+
39+
const result = variations({ ...defaultOptions, input: inputs });
40+
expect(result).toBe(
41+
"2764 FE0E | text | # text heart\n"
42+
+ "2764 FE0F | emoji | # emoji heart\n"
43+
+ "#EOF\n",
44+
);
45+
});
46+
47+
it("should use custom separator and comment prefix", () => {
48+
const input = {
49+
codePoints: ["2764", "FE0F"],
50+
style: "emoji",
51+
comment: "heart symbol",
52+
};
53+
54+
const options = {
55+
...defaultOptions,
56+
separator: "->",
57+
commentPrefix: "//",
58+
};
59+
60+
const result = variations({ ...options, input: [input] });
61+
expect(result).toBe(
62+
"2764 FE0F -> emoji -> // heart symbol\n"
63+
+ "#EOF\n",
64+
);
65+
});
66+
67+
it("should validate input schema", () => {
68+
const invalidInput = {
69+
codePoints: ["2764", "FE0F"],
70+
style: "emoji",
71+
comment: "heart symbol",
72+
} as const;
73+
74+
expect(() => variations({
75+
...defaultOptions,
76+
input: [
77+
// @ts-expect-error - testing invalid input
78+
{ ...invalidInput, style: undefined },
79+
],
80+
})).toThrow("style must be a string (was undefined)");
81+
});
82+
83+
it("should validate options schema", () => {
84+
const input = {
85+
codePoints: ["2764", "FE0F"],
86+
style: "emoji",
87+
comment: "heart symbol",
88+
};
89+
90+
const invalidOptions = {
91+
separator: "|",
92+
commentPrefix: "#",
93+
version: "1.0",
94+
} as const;
95+
96+
expect(() => variations({
97+
...invalidOptions,
98+
// @ts-expect-error - testing invalid options
99+
separator: undefined,
100+
input: [input],
101+
})).toThrow("separator must be a string (was undefined)");
102+
});
103+
104+
describe("presets", () => {
105+
describe("commonSymbols", () => {
106+
it("should generate common symbols variations", () => {
107+
const result = variations.commonSymbols(defaultOptions);
108+
109+
expect(result).toEqual(
110+
"2764 FE0E | text | # heart as text symbol\n"
111+
+ "2764 FE0F | emoji | # heart as emoji symbol\n"
112+
+ "2B50 FE0E | text | # star as text symbol\n"
113+
+ "2B50 FE0F | emoji | # star as emoji symbol\n"
114+
+ "#EOF\n",
115+
);
116+
});
117+
});
118+
119+
describe("punctuation", () => {
120+
it("should generate punctuation variations", () => {
121+
const result = variations.punctuation(defaultOptions);
122+
expect(result).toEqual(
123+
"2757 FE0E | text | # exclamation mark as text\n"
124+
+ "2757 FE0F | emoji | # exclamation mark as emoji\n"
125+
+ "2753 FE0E | text | # question mark as text\n"
126+
+ "2753 FE0F | emoji | # question mark as emoji\n"
127+
+ "#EOF\n",
128+
);
129+
});
130+
});
131+
132+
describe("miscellaneous", () => {
133+
it("should generate miscellaneous variations", () => {
134+
const result = variations.miscellaneous(defaultOptions);
135+
136+
expect(result).toEqual(
137+
"2600 FE0E | text | # sun as text symbol\n"
138+
+ "2600 FE0F | emoji | # sun as emoji symbol\n"
139+
+ "2695 FE0E | text | # medical symbol as text\n"
140+
+ "2695 FE0F | emoji | # medical symbol as emoji\n"
141+
+ "#EOF\n",
142+
);
143+
});
144+
});
145+
146+
it("should work with custom options in presets", () => {
147+
const customOptions = {
148+
separator: "->",
149+
commentPrefix: "//",
150+
version: "1.0",
151+
};
152+
153+
const result = variations.commonSymbols(customOptions);
154+
expect(result).toEqual(
155+
"2764 FE0E -> text -> // heart as text symbol\n"
156+
+ "2764 FE0F -> emoji -> // heart as emoji symbol\n"
157+
+ "2B50 FE0E -> text -> // star as text symbol\n"
158+
+ "2B50 FE0F -> emoji -> // star as emoji symbol\n"
159+
+ "#EOF\n",
160+
);
161+
});
162+
});
163+
});

0 commit comments

Comments
 (0)