@rep2recall/r2r-format
Version:
R2r (offline/online) abstract class for Rep2Recall
115 lines (99 loc) • 2.47 kB
text/typescript
export type ISortedData = Array<{ key: string, value: any }>;
export interface IEntry {
_id?: string;
front: string;
deck: string;
back?: string;
mnemonic?: string;
srsLevel?: number;
nextReview?: Date | string;
tag?: string[];
created?: Date | string;
modified?: Date | string;
stat?: {
streak: { right: number; wrong: number };
};
template?: string;
tFront?: string;
tBack?: string;
css?: string;
js?: string;
data?: ISortedData;
source?: string;
sH?: string;
sCreated?: Date | string;
}
export interface IRender {
front: string;
back?: string;
mnemonic?: string;
tFront?: string;
tBack?: string;
data?: ISortedData | Record<string, any>;
css?: string;
js?: string;
}
export interface ICondOptions<T extends Record<string, any>> {
offset?: number;
limit?: number;
sortBy?: keyof T | "random";
desc?: boolean;
fields?: Array<keyof T> | "*";
}
export interface IPagedOutput<T> {
data: T[];
count: number;
}
export interface IProgress {
text: string;
current?: number;
max?: number;
}
export function ankiMustache(
s: string,
d: Record<string, any> | Array<{key: string, value: any}> = {},
front: string = ""
): string {
if (Array.isArray(d)) {
d = fromSortedData(d).data;
}
s = s.replace(/\{\{FrontSide}}/g, front.replace(/@html\n/g, ""))
for (const [k, v] of Object.entries(d)) {
if (typeof v === "string") {
s = s.replace(
new RegExp(`\\{\\{(\\S+:)?${escapeRegExp(k)}}}`, "g"),
v.replace(/^@[^\n]+\n/gs, "")
);
}
}
s = s.replace(/\{\{#(\S+)}}([^]*)\{\{\1}}/gs, (m, p1, p2) => {
return Object.keys(d).includes(p1) ? p2 : "";
});
s = s.replace(/{{[^}]+}}/g, "");
return s;
}
export function escapeRegExp(s: string) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
export function fromSortedData(sd: ISortedData) {
const data: Record<string, any> = {};
const order: Record<string, number> = {};
let index = 1;
for (const { key, value } of sd) {
data[key] = value;
order[key] = index
index++;
}
return {data, order};
}
export function toSortedData(d: {data: Record<string, any>, order: Record<string, number>}): ISortedData {
const {data, order} = d;
return Object.keys(order).sort((a, b) => {
return order[b] - order[a];
}).map((key) => {
return {
key,
value: data[key]
};
});
}