this repo has no description
1export interface Kink {
2 name: string;
3 description?: string;
4}
5
6export interface KinkCategory {
7 name: string;
8 description?: string;
9 kinks: Kink[];
10 participants: string[];
11}
12
13function sliceOnce(str: string, char: string): [string, string?] {
14 const index = str.indexOf(char);
15
16 if (index !== -1) {
17 const leftHalf = str.slice(0, index).trim();
18 const rightHalf = str.slice(index + char.length).trim();
19 return [leftHalf, rightHalf];
20 }
21
22 return [str.trim(), undefined];
23}
24
25function removeSymbols(str: string, symbolStart: string, symbolEnd: string | null = null): string {
26 if (str.startsWith(symbolStart)) {
27 str = str.slice(1);
28 }
29
30 if (symbolEnd !== null && str.endsWith(symbolEnd)) {
31 str = str.slice(0, -1);
32 }
33
34 return str.trim();
35}
36
37export function unparseKinks(kinkCategories: KinkCategory[]): string {
38 let result: string[] = [];
39 for (const category of kinkCategories) {
40 result.push('# ', category.name);
41 if (category.description) {
42 result.push(' ::: ', category.description);
43 }
44 result.push('\n');
45 if (category.participants.length > 0) {
46 result.push('(', category.participants.join(', '), ')\n');
47 }
48 for (const kink of category.kinks) {
49 result.push('* ', kink.name);
50 if (kink.description) {
51 result.push(' ::: ', kink.description);
52 }
53 result.push('\n');
54 }
55 result.push('\n');
56 }
57
58 return result.join("");
59}
60
61export function parseKinks(kinkStr: string) {
62 const kinkCode = kinkStr
63 .split("\n")
64 .map((e, i) => [e.trim(), i + 1] as const)
65 .filter((e) => e[0]);
66
67 const kinkCategories: KinkCategory[] = [];
68
69 const kinksById: Kink[] = [];
70
71 let curKinkCategory: KinkCategory | undefined;
72 let curKinkId = 0;
73 for (const [line, lineNum] of kinkCode) {
74 if (line.startsWith("#")) {
75 const [categoryName, categoryDesc] = sliceOnce(removeSymbols(line, "#"), ":::");
76
77 curKinkCategory = {
78 name: categoryName,
79 description: categoryDesc,
80 kinks: [],
81 participants: ["Unknown"],
82 };
83 kinkCategories.push(curKinkCategory);
84 } else if (line.startsWith("(") && line.endsWith(")")) {
85 if (curKinkCategory === undefined) {
86 throw new Error(`Encountered a participant definition before a kink type declaration (line ${lineNum})`);
87 }
88 curKinkCategory.participants = removeSymbols(line, "(", ")")
89 .split(",")
90 .map((e) => e.trim());
91 } else if (line.startsWith("*")) {
92 if (curKinkCategory?.kinks === undefined) {
93 throw new Error(`Encountered a kink definition before a kink type declaration (line ${lineNum})`);
94 }
95
96 const [kinkName, kinkDescription] = sliceOnce(removeSymbols(line, "*"), ":::");
97 const kink = { name: kinkName, description: kinkDescription };
98 curKinkCategory.kinks.push(kink);
99 kinksById[curKinkId++] = kink;
100 }
101 }
102
103 return { kinkCategories, kinksById };
104}