1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
/**
* Shared card generation logic used by both server (note repository) and client
* (offline-first IndexedDB writes). Pure functions: produces card payloads from
* a note type and field values without touching any storage layer.
*/
const NEW_CARD_STATE = 0;
export interface NoteTypeForGeneration {
frontTemplate: string;
backTemplate: string;
isReversible: boolean;
}
export interface FieldTypeForGeneration {
id: string;
name: string;
}
export interface FieldValueForGeneration {
noteFieldTypeId: string;
value: string;
}
export interface GeneratedCard {
isReversed: boolean;
front: string;
back: string;
state: number;
due: Date;
stability: number;
difficulty: number;
elapsedDays: number;
scheduledDays: number;
reps: number;
lapses: number;
}
export function renderCardTemplate(
template: string,
fields: Map<string, string>,
): string {
let result = template;
for (const [name, value] of fields) {
result = result.replace(new RegExp(`\\{\\{${name}\\}\\}`, "g"), value);
}
return result;
}
export function generateCardsForNote(input: {
noteType: NoteTypeForGeneration;
fieldTypes: FieldTypeForGeneration[];
fieldValues: FieldValueForGeneration[];
now?: Date;
}): GeneratedCard[] {
const { noteType, fieldTypes, fieldValues, now = new Date() } = input;
const fieldMap = new Map<string, string>();
for (const fv of fieldValues) {
const ft = fieldTypes.find((f) => f.id === fv.noteFieldTypeId);
if (ft) {
fieldMap.set(ft.name, fv.value);
}
}
const generated: GeneratedCard[] = [
buildCard(noteType, fieldMap, false, now),
];
if (noteType.isReversible) {
generated.push(buildCard(noteType, fieldMap, true, now));
}
return generated;
}
function buildCard(
noteType: NoteTypeForGeneration,
fields: Map<string, string>,
isReversed: boolean,
now: Date,
): GeneratedCard {
const frontTemplate = isReversed
? noteType.backTemplate
: noteType.frontTemplate;
const backTemplate = isReversed
? noteType.frontTemplate
: noteType.backTemplate;
return {
isReversed,
front: renderCardTemplate(frontTemplate, fields),
back: renderCardTemplate(backTemplate, fields),
state: NEW_CARD_STATE,
due: new Date(now),
stability: 0,
difficulty: 0,
elapsedDays: 0,
scheduledDays: 0,
reps: 0,
lapses: 0,
};
}
|