@anja.codes/vitakit 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/check.mjs +14 -12
- package/dist/chunks/authoring.mjs +50 -45
- package/dist/{shared/vitakit.By5VWQ1n.mjs → chunks/bibliography.mjs} +73 -170
- package/dist/chunks/build.mjs +19 -17
- package/dist/chunks/documents.mjs +15 -6
- package/dist/chunks/draft.mjs +3 -3
- package/dist/chunks/eject.mjs +2 -2
- package/dist/chunks/emit.mjs +38 -22
- package/dist/chunks/fields.mjs +2 -2
- package/dist/chunks/inventory.mjs +29 -27
- package/dist/chunks/migrations.mjs +218 -0
- package/dist/chunks/plan.mjs +36 -8
- package/dist/chunks/publication-lists.mjs +202 -0
- package/dist/chunks/schemas.mjs +2 -2
- package/dist/chunks/sections.mjs +3 -3
- package/dist/chunks/validate.mjs +25 -16
- package/dist/chunks/vue.mjs +89 -52
- package/dist/chunks/yaml.mjs +62 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.mjs +12 -10
- package/dist/nuxt.mjs +19 -11
- package/dist/runtime/components/VitaPublications.vue +21 -22
- package/dist/runtime/composables/useVitakit.ts +14 -3
- package/dist/schemas/publications.ts +9 -7
- package/dist/shared/index.d.mts +2 -2
- package/dist/shared/{vitakit.BfpxDtz1.d.mts → vitakit.BfR_mUHm.d.mts} +17 -5
- package/dist/shared/{vitakit.BZZIsWlY.mjs → vitakit.CCTDg7pz.mjs} +21 -1
- package/dist/shared/{vitakit.DbSeENVS.mjs → vitakit.DCK90zq4.mjs} +10 -1
- package/dist/shared/vitakit.DteA9vLy.mjs +135 -0
- package/dist/shared/{vitakit.BerUaxtF.mjs → vitakit.DvABWuUc.mjs} +1 -1
- package/dist/shared/{vitakit.Do5HC_MD.mjs → vitakit.DvvUYUTS.mjs} +61 -3
- package/dist/shared/vitakit.UfoXdL7U.mjs +22 -0
- package/dist/shared/{vitakit.CoWX2Z4R.mjs → vitakit.zwr1ssO5.mjs} +353 -57
- package/dist/tex/templates/publications.eta +4 -2
- package/dist/tex/vitakit-cv.cls +15 -4
- package/dist/tex.d.mts +29 -8
- package/dist/tex.mjs +13 -10
- package/package.json +1 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { f as fail, m as messageOf, a as formatZodIssues } from '../shared/vitakit.DCK90zq4.mjs';
|
|
6
|
+
import 'node:url';
|
|
7
|
+
|
|
8
|
+
const LISTS_FILE = "content/publication-lists.yml";
|
|
9
|
+
const LISTS_HEADER = `# Publication lists: which publications of publications.bib a list shows,
|
|
10
|
+
# in what order and in which groups. A page shows one with
|
|
11
|
+
# <VitaPublications list="recent" title="Recent publications" />
|
|
12
|
+
# and a PDF with
|
|
13
|
+
# \\vitapublications[Recent publications]{recent}
|
|
14
|
+
#
|
|
15
|
+
# Settings, all optional:
|
|
16
|
+
# where: { status: preprint }, { keywords: selected }, { year: 2024 } --
|
|
17
|
+
# fields of the entries in publications.bib; [a, b] means a or b
|
|
18
|
+
# keys: [doe2024, roe2023] -- exactly these, in this order
|
|
19
|
+
# since, until: years
|
|
20
|
+
# sort: date (newest first), year, title, source (as in publications.bib),
|
|
21
|
+
# or a field; order: asc or desc
|
|
22
|
+
# limit: at most this many
|
|
23
|
+
# groupBy: status, year or a field; otherLabel: the heading for the entries
|
|
24
|
+
# without it (Other)
|
|
25
|
+
# \`vitakit explain publications\` shows what each list contains and where.
|
|
26
|
+
`;
|
|
27
|
+
const DERIVED = /* @__PURE__ */ new Set(["key", "status", "year"]);
|
|
28
|
+
const NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
29
|
+
const field = z.string().regex(/^[A-Za-z][\w-]*$/, "expected a BibTeX field name").transform((name) => name.toLowerCase());
|
|
30
|
+
const scalar = z.union([z.string(), z.number(), z.boolean()]);
|
|
31
|
+
const listInput = z.strictObject({
|
|
32
|
+
where: z.record(z.string(), z.union([scalar, z.array(scalar).min(1)])).default({}),
|
|
33
|
+
keys: z.array(z.string().min(1)).min(1).optional(),
|
|
34
|
+
since: z.number().int().optional(),
|
|
35
|
+
until: z.number().int().optional(),
|
|
36
|
+
sort: field.optional(),
|
|
37
|
+
order: z.enum(["asc", "desc"]).optional(),
|
|
38
|
+
limit: z.number().int().positive().optional(),
|
|
39
|
+
groupBy: field.optional(),
|
|
40
|
+
otherLabel: z.string().trim().min(1).optional()
|
|
41
|
+
});
|
|
42
|
+
function resolveList(name, value, schema) {
|
|
43
|
+
const at = (option) => `${name}.${option}`;
|
|
44
|
+
if (!NAME.test(name)) fail(LISTS_FILE, `${name}: a list name is lowercase kebab-case, e.g. recent-papers`);
|
|
45
|
+
const parsed = listInput.safeParse(value ?? {});
|
|
46
|
+
if (!parsed.success) fail(LISTS_FILE, `${name}: invalid
|
|
47
|
+
${formatZodIssues(parsed.error)}`);
|
|
48
|
+
const input = parsed.data;
|
|
49
|
+
const where = {};
|
|
50
|
+
for (const [key, wanted] of Object.entries(input.where)) {
|
|
51
|
+
const parsedField = field.safeParse(key);
|
|
52
|
+
if (!parsedField.success) fail(LISTS_FILE, `${at(`where.${key}`)}: expected a BibTeX field name`);
|
|
53
|
+
where[parsedField.data] = wanted;
|
|
54
|
+
}
|
|
55
|
+
const statuses = schema.statuses.map((status) => status.id);
|
|
56
|
+
for (const status of where.status === void 0 ? [] : [where.status].flat()) {
|
|
57
|
+
if (!statuses.includes(String(status).toLowerCase())) {
|
|
58
|
+
fail(LISTS_FILE, `${at("where.status")}: no status "${status}"; the statuses are ${statuses.join(", ")} (schemas/publications.ts)`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (input.keys && input.sort) fail(LISTS_FILE, `${at("sort")}: a list of keys is shown in the order of its keys; remove sort or keys`);
|
|
62
|
+
if (input.order && (input.keys || input.sort === "source")) fail(LISTS_FILE, `${at("order")}: only applies when sorting by a field`);
|
|
63
|
+
if (input.groupBy === "keywords") fail(LISTS_FILE, `${at("groupBy")}: an entry can have several keywords; group by another field`);
|
|
64
|
+
if (input.otherLabel && (!input.groupBy || input.groupBy === "status")) {
|
|
65
|
+
fail(LISTS_FILE, `${at("otherLabel")}: only applies when grouping by year or by a field`);
|
|
66
|
+
}
|
|
67
|
+
const sort = input.sort ?? "date";
|
|
68
|
+
return {
|
|
69
|
+
where,
|
|
70
|
+
...input.keys ? { keys: input.keys } : {},
|
|
71
|
+
...input.since !== void 0 ? { since: input.since } : {},
|
|
72
|
+
...input.until !== void 0 ? { until: input.until } : {},
|
|
73
|
+
sort,
|
|
74
|
+
order: input.order ?? (sort === "date" || sort === "year" ? "desc" : "asc"),
|
|
75
|
+
...input.limit !== void 0 ? { limit: input.limit } : {},
|
|
76
|
+
...input.groupBy ? { groupBy: input.groupBy } : {},
|
|
77
|
+
otherLabel: input.otherLabel ?? "Other"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function publicationListNames(rootDir) {
|
|
81
|
+
try {
|
|
82
|
+
const data = parse(await readFile(join(rootDir, LISTS_FILE), "utf8"));
|
|
83
|
+
return data && typeof data === "object" && !Array.isArray(data) ? Object.keys(data) : [];
|
|
84
|
+
} catch {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function loadPublicationLists(rootDir, schema) {
|
|
89
|
+
const raw = await readFile(join(rootDir, LISTS_FILE), "utf8").catch((error) => {
|
|
90
|
+
if (error.code === "ENOENT") return void 0;
|
|
91
|
+
throw error;
|
|
92
|
+
});
|
|
93
|
+
if (raw === void 0) return {};
|
|
94
|
+
let data;
|
|
95
|
+
try {
|
|
96
|
+
data = parse(raw);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
fail(LISTS_FILE, messageOf(error));
|
|
99
|
+
}
|
|
100
|
+
if (data === null || data === void 0) return {};
|
|
101
|
+
if (typeof data !== "object" || Array.isArray(data)) fail(LISTS_FILE, "expected one list per name, e.g. `recent: { limit: 3 }`");
|
|
102
|
+
return Object.fromEntries(Object.entries(data).map(([name, value]) => [name, resolveList(name, value, schema)]));
|
|
103
|
+
}
|
|
104
|
+
function publicationStatus(entry, schema) {
|
|
105
|
+
return (entry.custom.status?.trim() || schema.defaultStatus).toLowerCase();
|
|
106
|
+
}
|
|
107
|
+
const plain = (value) => {
|
|
108
|
+
const text = typeof value === "string" ? value.replace(/[{}]/g, "").trim() : void 0;
|
|
109
|
+
return text || void 0;
|
|
110
|
+
};
|
|
111
|
+
function valueOf(entry, name, schema) {
|
|
112
|
+
if (name === "key") return entry.key;
|
|
113
|
+
if (name === "status") return publicationStatus(entry, schema);
|
|
114
|
+
if (name === "year") return entry.year === null ? void 0 : String(entry.year);
|
|
115
|
+
return plain(entry.raw[name]);
|
|
116
|
+
}
|
|
117
|
+
function matches(entry, name, wanted, schema) {
|
|
118
|
+
const value = valueOf(entry, name, schema);
|
|
119
|
+
const actual = name === "keywords" ? value?.split(/[,;]/).map((keyword) => keyword.trim()) ?? [] : value === void 0 ? [] : [value];
|
|
120
|
+
return [wanted].flat().map(String).some((candidate) => actual.includes(name === "status" ? candidate.toLowerCase() : candidate));
|
|
121
|
+
}
|
|
122
|
+
const collator = new Intl.Collator(void 0, { numeric: true, sensitivity: "base" });
|
|
123
|
+
function sortByText(entries, value, order) {
|
|
124
|
+
const keyed = entries.map((entry) => ({ entry, value: value(entry) }));
|
|
125
|
+
const sign = order === "asc" ? 1 : -1;
|
|
126
|
+
return keyed.sort((a, b) => a.value === void 0 ? b.value === void 0 ? 0 : 1 : b.value === void 0 ? -1 : sign * collator.compare(a.value, b.value)).map((item) => item.entry);
|
|
127
|
+
}
|
|
128
|
+
function sortEntries(bib, entries, list, schema) {
|
|
129
|
+
if (list.keys || list.sort === "source") return entries;
|
|
130
|
+
if (list.sort === "date" || list.sort === "year") {
|
|
131
|
+
const dated = entries.filter((entry) => entry.year !== null);
|
|
132
|
+
return [...bib.sort(dated, { by: list.sort, order: list.order }), ...entries.filter((entry) => entry.year === null)];
|
|
133
|
+
}
|
|
134
|
+
return sortByText(entries, (entry) => valueOf(entry, list.sort, schema), list.order);
|
|
135
|
+
}
|
|
136
|
+
function group(entries, list, schema) {
|
|
137
|
+
const by = list.groupBy;
|
|
138
|
+
if (!by) return entries.length ? [{ entries }] : [];
|
|
139
|
+
if (by === "status") {
|
|
140
|
+
return schema.statuses.map((status) => ({ label: status.label, entries: entries.filter((entry) => publicationStatus(entry, schema) === status.id) })).filter((selected) => selected.entries.length);
|
|
141
|
+
}
|
|
142
|
+
const values = [...new Set(entries.map((entry) => valueOf(entry, by, schema)).filter((value) => value !== void 0))];
|
|
143
|
+
values.sort(by === "year" ? (a, b) => Number(b) - Number(a) : collator.compare);
|
|
144
|
+
const groups = values.map((value) => ({ label: value, entries: entries.filter((entry) => valueOf(entry, by, schema) === value) }));
|
|
145
|
+
const other = entries.filter((entry) => valueOf(entry, by, schema) === void 0);
|
|
146
|
+
return other.length ? [...groups, { label: list.otherLabel, entries: other }] : groups;
|
|
147
|
+
}
|
|
148
|
+
function selectionSteps(bib, name, list, schema) {
|
|
149
|
+
const fields = [...Object.keys(list.where), list.sort, list.groupBy].filter((candidate) => !!candidate && !DERIVED.has(candidate) && !["date", "source"].includes(candidate));
|
|
150
|
+
for (const candidate of new Set(fields)) {
|
|
151
|
+
if (bib.entries.length && !bib.entries.some((entry) => plain(entry.raw[candidate]) !== void 0)) {
|
|
152
|
+
fail(LISTS_FILE, `${name}: no publication has a field "${candidate}"`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const steps = [];
|
|
156
|
+
if (list.keys) {
|
|
157
|
+
const byKey = new Map(bib.entries.map((entry) => [entry.key, entry]));
|
|
158
|
+
const missing = list.keys.filter((key) => !byKey.has(key));
|
|
159
|
+
if (missing.length) fail(LISTS_FILE, `${name}.keys: no publication ${missing.join(", ")} in content/publications.bib`);
|
|
160
|
+
steps.push({ rule: `keys: ${list.keys.length}`, apply: () => list.keys.map((key) => byKey.get(key)) });
|
|
161
|
+
}
|
|
162
|
+
for (const [field2, wanted] of Object.entries(list.where)) {
|
|
163
|
+
steps.push({ rule: `where ${field2}: ${[wanted].flat().join(", ")}`, apply: (entries) => entries.filter((entry) => matches(entry, field2, wanted, schema)) });
|
|
164
|
+
}
|
|
165
|
+
if (list.since !== void 0) steps.push({ rule: `since: ${list.since}`, apply: (entries) => entries.filter((entry) => entry.year !== null && entry.year >= list.since) });
|
|
166
|
+
if (list.until !== void 0) steps.push({ rule: `until: ${list.until}`, apply: (entries) => entries.filter((entry) => entry.year !== null && entry.year <= list.until) });
|
|
167
|
+
steps.push({ rule: "sort", apply: (entries) => sortEntries(bib, entries, list, schema) });
|
|
168
|
+
if (list.limit !== void 0) steps.push({ rule: `limit: ${list.limit}`, apply: (entries) => entries.slice(0, list.limit) });
|
|
169
|
+
return steps;
|
|
170
|
+
}
|
|
171
|
+
function selectPublications(bib, name, list, schema) {
|
|
172
|
+
let entries = bib.entries;
|
|
173
|
+
for (const step of selectionSteps(bib, name, list, schema)) entries = step.apply(entries);
|
|
174
|
+
return group(entries, list, schema);
|
|
175
|
+
}
|
|
176
|
+
function explainListSelection(bib, name, list, schema) {
|
|
177
|
+
let entries = bib.entries;
|
|
178
|
+
const steps = [];
|
|
179
|
+
for (const step of selectionSteps(bib, name, list, schema)) {
|
|
180
|
+
const next = step.apply(entries);
|
|
181
|
+
steps.push({ rule: step.rule, removed: entries.length - next.length });
|
|
182
|
+
entries = next;
|
|
183
|
+
}
|
|
184
|
+
return { total: bib.entries.length, steps: steps.filter((step) => step.removed > 0), keys: group(entries, list, schema).flatMap((selected) => selected.entries.map((entry) => entry.key)) };
|
|
185
|
+
}
|
|
186
|
+
function describeList(list) {
|
|
187
|
+
const parts = [];
|
|
188
|
+
if (list.keys) parts.push(`${list.keys.length} chosen by key`);
|
|
189
|
+
for (const [name, wanted] of Object.entries(list.where)) parts.push(`${name} ${[wanted].flat().join(" or ")}`);
|
|
190
|
+
if (list.since !== void 0) parts.push(`since ${list.since}`);
|
|
191
|
+
if (list.until !== void 0) parts.push(`until ${list.until}`);
|
|
192
|
+
if (!list.keys) {
|
|
193
|
+
if (list.sort === "source") parts.push("in .bib order");
|
|
194
|
+
else if (list.sort === "date" || list.sort === "year") parts.push(list.order === "desc" ? "newest first" : "oldest first");
|
|
195
|
+
else parts.push(`by ${list.sort}${list.order === "desc" ? ", descending" : ""}`);
|
|
196
|
+
}
|
|
197
|
+
if (list.limit !== void 0) parts.push(`at most ${list.limit}`);
|
|
198
|
+
if (list.groupBy) parts.push(`grouped by ${list.groupBy}`);
|
|
199
|
+
return parts.join(" \xB7 ");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export { LISTS_FILE, LISTS_HEADER, describeList, explainListSelection, loadPublicationLists, publicationListNames, publicationStatus, resolveList, selectPublications };
|
package/dist/chunks/schemas.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { s as section, t as text, a as richText, u as url, l as linked, d as dateRange, b as absoluteUrl, r as requiredLink } from '../shared/vitakit.
|
|
1
|
+
import { s as section, t as text, a as richText, u as url, l as linked, d as dateRange, b as absoluteUrl, r as requiredLink } from '../shared/vitakit.DvABWuUc.mjs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import '../shared/vitakit.
|
|
3
|
+
import '../shared/vitakit.DCK90zq4.mjs';
|
|
4
4
|
import 'node:url';
|
|
5
5
|
import '../shared/vitakit.D10HyDhF.mjs';
|
|
6
6
|
|
package/dist/chunks/sections.mjs
CHANGED
|
@@ -2,14 +2,14 @@ import { readdir, readFile, stat } from 'node:fs/promises';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { parse } from 'yaml';
|
|
4
4
|
import { schemas } from './schemas.mjs';
|
|
5
|
-
import { f as fail, a as formatZodIssues, i as importProjectModule } from '../shared/vitakit.
|
|
6
|
-
import { c as renderRichFields } from '../shared/vitakit.
|
|
5
|
+
import { f as fail, a as formatZodIssues, i as importProjectModule } from '../shared/vitakit.DCK90zq4.mjs';
|
|
6
|
+
import { c as renderRichFields } from '../shared/vitakit.DvABWuUc.mjs';
|
|
7
7
|
import { r as resolveSitePaths } from '../shared/vitakit.D10HyDhF.mjs';
|
|
8
8
|
import { a as atMost } from '../shared/vitakit.TSMTC5Jl.mjs';
|
|
9
9
|
import 'zod';
|
|
10
10
|
import 'node:url';
|
|
11
11
|
|
|
12
|
-
const RESERVED_SECTION_NAMES = /* @__PURE__ */ new Set(["site", "profile"]);
|
|
12
|
+
const RESERVED_SECTION_NAMES = /* @__PURE__ */ new Set(["site", "profile", "publication-lists"]);
|
|
13
13
|
const SECTION_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
14
14
|
function sectionNameProblem(id) {
|
|
15
15
|
if (RESERVED_SECTION_NAMES.has(id)) return `"${id}" is reserved and cannot be a section`;
|
package/dist/chunks/validate.mjs
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
import { join, sep, isAbsolute, relative } from 'node:path';
|
|
2
2
|
import { parseExpression } from '@babel/parser';
|
|
3
|
-
import { l as loadContent } from '../shared/vitakit.
|
|
3
|
+
import { l as loadContent } from '../shared/vitakit.DteA9vLy.mjs';
|
|
4
4
|
import { inventory } from './inventory.mjs';
|
|
5
|
-
import { m as messageOf, w as whereOf } from '../shared/vitakit.
|
|
6
|
-
import { assertTemplatesAreUsed,
|
|
5
|
+
import { m as messageOf, w as whereOf } from '../shared/vitakit.DCK90zq4.mjs';
|
|
6
|
+
import { assertTemplatesAreUsed, renderSection, renderPublications } from './emit.mjs';
|
|
7
7
|
import 'node:fs/promises';
|
|
8
8
|
import 'gray-matter';
|
|
9
9
|
import 'yaml';
|
|
10
|
+
import './bibliography.mjs';
|
|
11
|
+
import 'node:fs';
|
|
12
|
+
import '../shared/vitakit.DQ6PmGoL.mjs';
|
|
13
|
+
import 'node:url';
|
|
14
|
+
import '@behackl/citation-js-extras';
|
|
10
15
|
import 'unified';
|
|
16
|
+
import 'rehype-parse';
|
|
17
|
+
import 'rehype-sanitize';
|
|
18
|
+
import 'rehype-stringify';
|
|
11
19
|
import 'remark-parse';
|
|
12
20
|
import 'remark-gfm';
|
|
13
21
|
import 'remark-math';
|
|
14
22
|
import 'remark-rehype';
|
|
15
23
|
import 'rehype-katex';
|
|
16
24
|
import 'rehype-raw';
|
|
17
|
-
import 'rehype-stringify';
|
|
18
25
|
import 'unist-util-visit';
|
|
19
|
-
import '../shared/vitakit.D10HyDhF.mjs';
|
|
20
|
-
import 'node:fs';
|
|
21
|
-
import '../shared/vitakit.DQ6PmGoL.mjs';
|
|
22
|
-
import 'node:url';
|
|
23
|
-
import '@behackl/citation-js-extras';
|
|
24
|
-
import 'rehype-parse';
|
|
25
|
-
import 'rehype-sanitize';
|
|
26
26
|
import 'zod';
|
|
27
|
+
import './publication-lists.mjs';
|
|
28
|
+
import '../shared/vitakit.D10HyDhF.mjs';
|
|
27
29
|
import './sections.mjs';
|
|
28
30
|
import './schemas.mjs';
|
|
29
|
-
import '../shared/vitakit.
|
|
31
|
+
import '../shared/vitakit.DvABWuUc.mjs';
|
|
30
32
|
import '../shared/vitakit.TSMTC5Jl.mjs';
|
|
31
33
|
import './fields.mjs';
|
|
32
34
|
import './documents.mjs';
|
|
35
|
+
import '../shared/vitakit.DvvUYUTS.mjs';
|
|
33
36
|
import '../shared/vitakit.D-DdJaDZ.mjs';
|
|
34
|
-
import '../shared/vitakit.Do5HC_MD.mjs';
|
|
35
37
|
import 'eta';
|
|
36
38
|
import '../shared/vitakit.DcQOdM4I.mjs';
|
|
37
39
|
import '../shared/vitakit.CfB3hMHl.mjs';
|
|
@@ -96,9 +98,7 @@ ${problem.message}`;
|
|
|
96
98
|
for (const document of inv.documents) {
|
|
97
99
|
for (const placement of document.placements) {
|
|
98
100
|
try {
|
|
99
|
-
if (placement.section
|
|
100
|
-
await renderPublications(content.publications, document.options, templateDir, content.profile.url);
|
|
101
|
-
} else if (valid.has(placement.section)) {
|
|
101
|
+
if (valid.has(placement.section)) {
|
|
102
102
|
await renderSection(placement.section, content.sections[placement.section] ?? [], document.options, templateDir);
|
|
103
103
|
}
|
|
104
104
|
} catch (error) {
|
|
@@ -109,6 +109,15 @@ ${problem.message}`;
|
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
+
for (const placement of document.publications) {
|
|
113
|
+
const list = content.publications[placement.list];
|
|
114
|
+
if (!list) continue;
|
|
115
|
+
try {
|
|
116
|
+
await renderPublications(list, templateDir, content.profile.url);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
add({ where: local(whereOf(error, "cv-tex/templates/publications.eta")), message: `${messageOf(error)} (in ${document.tex})` });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
112
121
|
}
|
|
113
122
|
}
|
|
114
123
|
const { realpath } = await import('node:fs/promises');
|
package/dist/chunks/vue.mjs
CHANGED
|
@@ -1,38 +1,20 @@
|
|
|
1
1
|
import { parse } from '@vue/compiler-sfc';
|
|
2
|
-
|
|
3
|
-
function lineStart(source, offset) {
|
|
4
|
-
return source.lastIndexOf("\n", offset - 1) + 1;
|
|
5
|
-
}
|
|
6
|
-
function lineEnd(source, offset) {
|
|
7
|
-
const end = source.indexOf("\n", offset);
|
|
8
|
-
return end === -1 ? source.length : end;
|
|
9
|
-
}
|
|
10
|
-
function indentationAt(source, offset) {
|
|
11
|
-
return /^[ \t]*/.exec(source.slice(lineStart(source, offset)))[0];
|
|
12
|
-
}
|
|
13
|
-
function insertLinesAfter(source, offset, lines) {
|
|
14
|
-
const end = lineEnd(source, offset);
|
|
15
|
-
return `${source.slice(0, end)}
|
|
16
|
-
${lines.join("\n")}${source.slice(end)}`;
|
|
17
|
-
}
|
|
18
|
-
function insertLinesBefore(source, offset, lines) {
|
|
19
|
-
const start = lineStart(source, offset);
|
|
20
|
-
return `${source.slice(0, start)}${lines.join("\n")}
|
|
21
|
-
${source.slice(start)}`;
|
|
22
|
-
}
|
|
2
|
+
import { l as lineStart, a as lineEnd, i as indentationAt, b as insertLinesAfter, c as insertLinesBefore } from '../shared/vitakit.UfoXdL7U.mjs';
|
|
23
3
|
|
|
24
4
|
const ELEMENT = 1;
|
|
25
5
|
const ATTRIBUTE = 6;
|
|
26
6
|
const pascal = (name) => name.split("-").map((part) => part[0].toUpperCase() + part.slice(1)).join("");
|
|
27
|
-
function
|
|
7
|
+
function literalAttribute(node, name) {
|
|
28
8
|
for (const prop of node.props ?? []) {
|
|
29
|
-
if (prop.type === ATTRIBUTE && prop.name ===
|
|
30
|
-
if (prop.type !== ATTRIBUTE && prop.name === "bind" && prop.arg?.content ===
|
|
9
|
+
if (prop.type === ATTRIBUTE && prop.name === name) return prop.value?.content;
|
|
10
|
+
if (prop.type !== ATTRIBUTE && prop.name === "bind" && prop.arg?.content === name) {
|
|
31
11
|
return /^\s*(['"`])([^'"`$]*)\1\s*$/.exec(prop.exp?.content ?? "")?.[2];
|
|
32
12
|
}
|
|
33
13
|
}
|
|
34
14
|
return void 0;
|
|
35
15
|
}
|
|
16
|
+
const hasContent = (node) => (node.children ?? []).some((child) => child.type !== 3 && !(child.type === 2 && !child.content.trim()));
|
|
17
|
+
const directive = (node, ...names) => (node?.props ?? []).some((prop) => prop.type !== ATTRIBUTE && names.includes(prop.name));
|
|
36
18
|
function sectionElements(source, components = []) {
|
|
37
19
|
const known = /* @__PURE__ */ new Set(["VitaSection", ...components]);
|
|
38
20
|
let ast;
|
|
@@ -44,21 +26,35 @@ function sectionElements(source, components = []) {
|
|
|
44
26
|
return { ok: false, reason: `cannot be parsed: ${error instanceof Error ? error.message : String(error)}` };
|
|
45
27
|
}
|
|
46
28
|
if (!ast) return { ok: false, reason: "it has no <template>" };
|
|
29
|
+
const roots = (ast.children ?? []).filter((node) => node.type === ELEMENT);
|
|
30
|
+
const root = roots.length === 1 ? roots[0] : void 0;
|
|
47
31
|
const elements = [];
|
|
48
|
-
const
|
|
32
|
+
const lists = [];
|
|
33
|
+
const visit = (node, anchor) => {
|
|
49
34
|
if (node.type === ELEMENT && node.tag) {
|
|
50
35
|
const tag = node.tag.includes("-") ? pascal(node.tag) : node.tag;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
36
|
+
const found = (id2) => ({
|
|
37
|
+
id: id2,
|
|
38
|
+
tag: node.tag,
|
|
39
|
+
start: node.loc.start.offset,
|
|
40
|
+
end: node.loc.end.offset,
|
|
41
|
+
line: node.loc.start.line,
|
|
42
|
+
hasContent: hasContent(node),
|
|
43
|
+
anchor: anchor ?? { start: node.loc.start.offset, end: node.loc.end.offset, line: node.loc.start.line, chained: false }
|
|
44
|
+
});
|
|
45
|
+
const id = known.has(tag) ? literalAttribute(node, "id") : void 0;
|
|
46
|
+
if (id) elements.push(found(id));
|
|
47
|
+
const list = tag === "VitaPublications" ? literalAttribute(node, "list") : void 0;
|
|
48
|
+
if (list) lists.push(found(list));
|
|
49
|
+
}
|
|
50
|
+
const children = (node.children ?? []).filter((child) => child.type === ELEMENT);
|
|
51
|
+
for (const [index, child] of children.entries()) {
|
|
52
|
+
const block = node === root ? { start: child.loc.start.offset, end: child.loc.end.offset, line: child.loc.start.line, chained: directive(children[index + 1], "else", "else-if") } : anchor;
|
|
53
|
+
visit(child, block);
|
|
56
54
|
}
|
|
57
|
-
for (const child of node.children ?? []) visit(child);
|
|
58
55
|
};
|
|
59
56
|
visit(ast);
|
|
60
|
-
|
|
61
|
-
return { ok: true, value: { elements, ...roots.length === 1 ? { root: roots[0] } : {} } };
|
|
57
|
+
return { ok: true, value: { elements, lists, ...root ? { root } : {} } };
|
|
62
58
|
}
|
|
63
59
|
function attribute(value) {
|
|
64
60
|
return value.replace(/&/g, "&").replace(/"/g, """);
|
|
@@ -66,16 +62,20 @@ function attribute(value) {
|
|
|
66
62
|
function sectionElementSource(placement) {
|
|
67
63
|
return `<${placement.component ?? "VitaSection"} id="${placement.id}"${placement.title ? ` title="${attribute(placement.title)}"` : ""} />`;
|
|
68
64
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
function publicationsElementSource(list, title) {
|
|
66
|
+
return `<VitaPublications list="${attribute(list)}"${title ? ` title="${attribute(title)}"` : ""} />`;
|
|
67
|
+
}
|
|
68
|
+
function insertElement(source, markup, anchors, root, after) {
|
|
69
|
+
const sorted = [...anchors].sort((a, b) => a.start - b.start);
|
|
70
|
+
const found = (after && sorted.find((existing) => existing.id === after)) ?? sorted[sorted.length - 1];
|
|
71
|
+
if (found) {
|
|
72
|
+
const { anchor } = found;
|
|
73
|
+
if (anchor.chained) return { ok: false, reason: `a v-else follows line ${anchor.line}; a line after it would split the v-if from its v-else` };
|
|
74
|
+
if (source.slice(lineStart(source, anchor.start), anchor.start).trim() || source.slice(anchor.end, lineEnd(source, anchor.end)).trim()) {
|
|
75
|
+
return { ok: false, reason: `line ${anchor.line} holds other markup too` };
|
|
76
|
+
}
|
|
77
77
|
const indent2 = indentationAt(source, anchor.start);
|
|
78
|
-
return { ok: true, value: { source: insertLinesAfter(source, anchor.end - 1, [`${indent2}${
|
|
78
|
+
return { ok: true, value: { source: insertLinesAfter(source, anchor.end - 1, [`${indent2}${markup}`]), afterSection: found.id } };
|
|
79
79
|
}
|
|
80
80
|
if (!root || !root.tag) return { ok: false, reason: "its template has no single root element to add to" };
|
|
81
81
|
const close = source.lastIndexOf(`</${root.tag}`, root.loc.end.offset);
|
|
@@ -83,7 +83,22 @@ function addSectionToPage(source, placement, components = []) {
|
|
|
83
83
|
return { ok: false, reason: `its <${root.tag}> does not end on a line of its own` };
|
|
84
84
|
}
|
|
85
85
|
const indent = `${indentationAt(source, close)} `;
|
|
86
|
-
return { ok: true, value: { source: insertLinesBefore(source, close, ["", `${indent}${
|
|
86
|
+
return { ok: true, value: { source: insertLinesBefore(source, close, ["", `${indent}${markup}`]) } };
|
|
87
|
+
}
|
|
88
|
+
function addSectionToPage(source, placement, components = []) {
|
|
89
|
+
const found = sectionElements(source, components);
|
|
90
|
+
if (!found.ok) return found;
|
|
91
|
+
const { elements, lists, root } = found.value;
|
|
92
|
+
if (elements.some((element) => element.id === placement.id)) return { ok: false, reason: `it already shows ${placement.id}` };
|
|
93
|
+
const anchors = [...elements, ...lists.filter((list) => list.id === placement.after && !elements.some((element) => element.id === list.id))];
|
|
94
|
+
return insertElement(source, sectionElementSource(placement), anchors, root, placement.after);
|
|
95
|
+
}
|
|
96
|
+
function addPublicationsToPage(source, placement, components = []) {
|
|
97
|
+
const found = sectionElements(source, components);
|
|
98
|
+
if (!found.ok) return found;
|
|
99
|
+
const { elements, lists, root } = found.value;
|
|
100
|
+
if (lists.some((list) => list.id === placement.list)) return { ok: false, reason: `it already shows the list ${placement.list}` };
|
|
101
|
+
return insertElement(source, publicationsElementSource(placement.list, placement.title), [...elements, ...lists], root, placement.after);
|
|
87
102
|
}
|
|
88
103
|
function useComponentForSection(source, id, component, components = []) {
|
|
89
104
|
const found = sectionElements(source, components);
|
|
@@ -104,13 +119,35 @@ function useComponentForSection(source, id, component, components = []) {
|
|
|
104
119
|
}
|
|
105
120
|
return { ok: true, value: { source: result, changed } };
|
|
106
121
|
}
|
|
122
|
+
function publicationsElements(source) {
|
|
123
|
+
let ast;
|
|
124
|
+
try {
|
|
125
|
+
const { descriptor, errors } = parse(source);
|
|
126
|
+
if (errors.length) return { ok: false, reason: `cannot be parsed: ${String(errors[0])}` };
|
|
127
|
+
ast = descriptor.template?.ast;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
return { ok: false, reason: `cannot be parsed: ${error instanceof Error ? error.message : String(error)}` };
|
|
130
|
+
}
|
|
131
|
+
const found = [];
|
|
132
|
+
const visit = (node) => {
|
|
133
|
+
if (node.type === ELEMENT && node.tag && (node.tag.includes("-") ? pascal(node.tag) : node.tag) === "VitaPublications") {
|
|
134
|
+
found.push({
|
|
135
|
+
tag: node.tag,
|
|
136
|
+
start: node.loc.start.offset,
|
|
137
|
+
line: node.loc.start.line,
|
|
138
|
+
hasContent: hasContent(node),
|
|
139
|
+
props: (node.props ?? []).map((prop) => ({
|
|
140
|
+
name: prop.type === ATTRIBUTE ? prop.name : prop.name === "bind" && prop.arg ? prop.arg.content : `v-${prop.name}`,
|
|
141
|
+
start: prop.loc.start.offset,
|
|
142
|
+
end: prop.loc.end.offset,
|
|
143
|
+
...prop.type === ATTRIBUTE ? prop.value ? { value: prop.value.content } : {} : { expression: prop.exp?.content ?? "" }
|
|
144
|
+
}))
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
for (const child of node.children ?? []) visit(child);
|
|
148
|
+
};
|
|
149
|
+
if (ast) visit(ast);
|
|
150
|
+
return { ok: true, value: found };
|
|
151
|
+
}
|
|
107
152
|
|
|
108
|
-
|
|
109
|
-
__proto__: null,
|
|
110
|
-
addSectionToPage: addSectionToPage,
|
|
111
|
-
sectionElementSource: sectionElementSource,
|
|
112
|
-
sectionElements: sectionElements,
|
|
113
|
-
useComponentForSection: useComponentForSection
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
export { indentationAt as a, insertLinesBefore as b, lineEnd as c, addSectionToPage as d, insertLinesAfter as i, lineStart as l, sectionElementSource as s, vue as v };
|
|
153
|
+
export { addPublicationsToPage, addSectionToPage, publicationsElementSource, publicationsElements, sectionElementSource, sectionElements, useComponentForSection };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { parseDocument, isMap, isScalar, isSeq } from 'yaml';
|
|
2
|
+
import { l as lineStart, a as lineEnd } from '../shared/vitakit.UfoXdL7U.mjs';
|
|
3
|
+
|
|
4
|
+
function yamlScalar(value) {
|
|
5
|
+
return /^[A-Za-z0-9/][\w ./()'-]*$/.test(value) && !/(^|\s)#|:\s|\s$/.test(value) ? value : JSON.stringify(value);
|
|
6
|
+
}
|
|
7
|
+
function addNavItem(source, item) {
|
|
8
|
+
const document = parseDocument(source);
|
|
9
|
+
if (document.errors.length) return { ok: false, reason: `cannot be parsed: ${document.errors[0].message}` };
|
|
10
|
+
if (!isMap(document.contents)) return { ok: false, reason: "it is not a map of settings" };
|
|
11
|
+
const entry = `- { label: ${yamlScalar(item.label)}, to: ${yamlScalar(item.to)} }`;
|
|
12
|
+
const nav = document.contents.get("nav", true);
|
|
13
|
+
if (nav === void 0) {
|
|
14
|
+
const ending = source.endsWith("\n") ? "" : "\n";
|
|
15
|
+
return { ok: true, value: `${source}${ending}
|
|
16
|
+
nav:
|
|
17
|
+
${entry}
|
|
18
|
+
` };
|
|
19
|
+
}
|
|
20
|
+
if (!isSeq(nav) || nav.flow) return { ok: false, reason: "its nav is not a list with one entry per line" };
|
|
21
|
+
if (nav.items.some((existing) => isMap(existing) && existing.get("to") === item.to)) {
|
|
22
|
+
return { ok: false, reason: `its menu already links ${item.to}` };
|
|
23
|
+
}
|
|
24
|
+
const last = nav.items[nav.items.length - 1];
|
|
25
|
+
if (!last?.range) return { ok: false, reason: "its nav is empty; add the first entry by hand" };
|
|
26
|
+
const start = lineStart(source, last.range[0]);
|
|
27
|
+
const prefix = /^[ \t]*-[ \t]*/.exec(source.slice(start))?.[0];
|
|
28
|
+
if (!prefix) return { ok: false, reason: "its nav entries are not one per line" };
|
|
29
|
+
const end = lineEnd(source, last.range[1] - 1);
|
|
30
|
+
const indent = prefix.slice(0, prefix.indexOf("-"));
|
|
31
|
+
return { ok: true, value: `${source.slice(0, end)}
|
|
32
|
+
${indent}${entry}${source.slice(end)}` };
|
|
33
|
+
}
|
|
34
|
+
function flow(value) {
|
|
35
|
+
if (Array.isArray(value)) return `[${value.map(flow).join(", ")}]`;
|
|
36
|
+
if (value && typeof value === "object") return `{ ${Object.entries(value).map(([key, item]) => `${yamlScalar(key)}: ${flow(item)}`).join(", ")} }`;
|
|
37
|
+
return typeof value === "string" ? yamlScalar(value) : String(value);
|
|
38
|
+
}
|
|
39
|
+
function publicationListYaml(name, settings) {
|
|
40
|
+
const lines = Object.entries(settings).filter(([, value]) => value !== void 0).map(([key, value]) => ` ${key}: ${flow(value)}`);
|
|
41
|
+
return lines.length ? `${name}:
|
|
42
|
+
${lines.join("\n")}` : `${name}: {}`;
|
|
43
|
+
}
|
|
44
|
+
function publicationListLine(source, name) {
|
|
45
|
+
const document = parseDocument(source);
|
|
46
|
+
const pair = isMap(document.contents) ? document.contents.items.find((item) => isScalar(item.key) && item.key.value === name) : void 0;
|
|
47
|
+
const offset = pair?.key?.range?.[0];
|
|
48
|
+
return offset === void 0 ? void 0 : source.slice(0, offset).split("\n").length;
|
|
49
|
+
}
|
|
50
|
+
function addPublicationList(source, name, settings) {
|
|
51
|
+
const document = parseDocument(source);
|
|
52
|
+
if (document.errors.length) return { ok: false, reason: `cannot be parsed: ${document.errors[0].message}` };
|
|
53
|
+
if (document.contents !== null && !isMap(document.contents)) return { ok: false, reason: "it is not one list per name" };
|
|
54
|
+
if (isMap(document.contents) && document.contents.flow) return { ok: false, reason: "its lists are written on one line" };
|
|
55
|
+
const line = publicationListLine(source, name);
|
|
56
|
+
if (line !== void 0) return { ok: false, reason: `it has a list "${name}" already, on line ${line}` };
|
|
57
|
+
const body = source.replace(/\s*$/, "");
|
|
58
|
+
return { ok: true, value: `${body}${body ? "\n\n" : ""}${publicationListYaml(name, settings)}
|
|
59
|
+
` };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { addNavItem, addPublicationList, publicationListLine, publicationListYaml, yamlScalar };
|
package/dist/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as aligned, c as commands, d as detectPackageManager, m as main } from './shared/vitakit.
|
|
1
|
+
export { a as aligned, c as commands, d as detectPackageManager, m as main } from './shared/vitakit.zwr1ssO5.mjs';
|
|
2
2
|
import 'node:fs';
|
|
3
3
|
import 'node:path';
|
|
4
4
|
import './shared/vitakit.DQ6PmGoL.mjs';
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as zod from 'zod';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export { z } from 'zod';
|
|
4
|
-
import { D as DateRange, V as Visibility, a as VitakitContent } from './shared/vitakit.
|
|
4
|
+
import { D as DateRange, V as Visibility, a as VitakitContent } from './shared/vitakit.BfR_mUHm.mjs';
|
|
5
5
|
import { RichTextMarker } from './shared/index.mjs';
|
|
6
|
-
export { C as ContentIssue, b as DatePoint, E as Entry, c as EntryBase, L as Link, d as Linked, P as Page, e as Profile, f as Publication, g as PublicationBadge, h as PublicationGroup, i as RichText } from './shared/vitakit.
|
|
6
|
+
export { C as ContentIssue, b as DatePoint, E as Entry, c as EntryBase, L as Link, d as Linked, P as Page, e as Profile, f as Publication, g as PublicationBadge, h as PublicationGroup, i as PublicationList, j as RichText } from './shared/vitakit.BfR_mUHm.mjs';
|
|
7
7
|
import { BadgeConfig } from '@behackl/citation-js-extras';
|
|
8
8
|
export { BadgeConfig, badgePresets } from '@behackl/citation-js-extras';
|
|
9
9
|
import * as zod_v4_core from 'zod/v4/core';
|
|
@@ -696,18 +696,18 @@ interface LoadContentOptions {
|
|
|
696
696
|
}
|
|
697
697
|
declare function loadContent(rootDir: string, options?: LoadContentOptions): Promise<VitakitContent>;
|
|
698
698
|
|
|
699
|
-
interface
|
|
699
|
+
interface PublicationStatusConfig {
|
|
700
700
|
/** A value of the `status` field; lowercase, e.g. `preprint` or `talk-slides`. */
|
|
701
701
|
id: string;
|
|
702
|
-
/** Heading on the website and in the PDF. */
|
|
702
|
+
/** Heading of its group, on the website and in the PDF. */
|
|
703
703
|
label: string;
|
|
704
704
|
}
|
|
705
705
|
/** What `schemas/publications.ts` may set; everything is optional. */
|
|
706
706
|
interface PublicationsInput {
|
|
707
|
-
/** The values of `status`, in the order
|
|
708
|
-
|
|
709
|
-
/** The
|
|
710
|
-
|
|
707
|
+
/** The values of `status`, in the order their groups appear. */
|
|
708
|
+
statuses?: PublicationStatusConfig[];
|
|
709
|
+
/** The status of an entry without one. Defaults to the first status. */
|
|
710
|
+
defaultStatus?: string;
|
|
711
711
|
/** BibTeX fields that become links after a reference, on the website. */
|
|
712
712
|
badges?: BadgeConfig[];
|
|
713
713
|
/** Further BibTeX fields to hand to the website, as `entry.fields`. */
|
|
@@ -725,4 +725,4 @@ interface PublicationsInput {
|
|
|
725
725
|
declare function publications(input: PublicationsInput): PublicationsInput;
|
|
726
726
|
|
|
727
727
|
export { DateRange, Visibility, VitakitContent, dateRange, _default$4 as education, _default$3 as employment, entry, extendSection, linked, loadContent, publications, requiredLink, richText, schemas, section, _default as supervision, _default$1 as talks, _default$2 as teaching, text, url, visibility };
|
|
728
|
-
export type { BuiltinSection, LoadContentOptions,
|
|
728
|
+
export type { BuiltinSection, LoadContentOptions, PublicationStatusConfig, PublicationsInput };
|
package/dist/index.mjs
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
export { d as dateRange, e as entry, l as linked, r as requiredLink, a as richText, s as section, t as text, u as url, v as visibility } from './shared/vitakit.
|
|
1
|
+
export { d as dateRange, e as entry, l as linked, r as requiredLink, a as richText, s as section, t as text, u as url, v as visibility } from './shared/vitakit.DvABWuUc.mjs';
|
|
2
2
|
export { education, employment, extendSection, schemas, supervision, talks, teaching } from './chunks/schemas.mjs';
|
|
3
|
-
export { l as loadContent
|
|
3
|
+
export { l as loadContent } from './shared/vitakit.DteA9vLy.mjs';
|
|
4
|
+
export { p as publications } from './chunks/bibliography.mjs';
|
|
4
5
|
export { badgePresets } from '@behackl/citation-js-extras';
|
|
5
6
|
export { z } from 'zod';
|
|
6
|
-
import './shared/vitakit.
|
|
7
|
+
import './shared/vitakit.DCK90zq4.mjs';
|
|
7
8
|
import 'node:url';
|
|
8
9
|
import './shared/vitakit.D10HyDhF.mjs';
|
|
9
10
|
import 'node:fs/promises';
|
|
10
11
|
import 'node:path';
|
|
11
12
|
import 'gray-matter';
|
|
12
13
|
import 'yaml';
|
|
14
|
+
import './chunks/publication-lists.mjs';
|
|
15
|
+
import './chunks/sections.mjs';
|
|
16
|
+
import './shared/vitakit.TSMTC5Jl.mjs';
|
|
17
|
+
import 'node:fs';
|
|
18
|
+
import './shared/vitakit.DQ6PmGoL.mjs';
|
|
13
19
|
import 'unified';
|
|
20
|
+
import 'rehype-parse';
|
|
21
|
+
import 'rehype-sanitize';
|
|
22
|
+
import 'rehype-stringify';
|
|
14
23
|
import 'remark-parse';
|
|
15
24
|
import 'remark-gfm';
|
|
16
25
|
import 'remark-math';
|
|
17
26
|
import 'remark-rehype';
|
|
18
27
|
import 'rehype-katex';
|
|
19
28
|
import 'rehype-raw';
|
|
20
|
-
import 'rehype-stringify';
|
|
21
29
|
import 'unist-util-visit';
|
|
22
|
-
import 'node:fs';
|
|
23
|
-
import './shared/vitakit.DQ6PmGoL.mjs';
|
|
24
|
-
import 'rehype-parse';
|
|
25
|
-
import 'rehype-sanitize';
|
|
26
|
-
import './chunks/sections.mjs';
|
|
27
|
-
import './shared/vitakit.TSMTC5Jl.mjs';
|