@mvarble/mesearch-cms 0.1.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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/cms.d.ts +22 -0
  4. package/dist/cms.js +270 -0
  5. package/dist/cms.js.map +1 -0
  6. package/dist/core/bibtex.d.ts +6 -0
  7. package/dist/core/bibtex.js +129 -0
  8. package/dist/core/bibtex.js.map +1 -0
  9. package/dist/core/build.d.ts +29 -0
  10. package/dist/core/build.js +41 -0
  11. package/dist/core/build.js.map +1 -0
  12. package/dist/core/facts.d.ts +4 -0
  13. package/dist/core/facts.js +39 -0
  14. package/dist/core/facts.js.map +1 -0
  15. package/dist/core/frontmatter.d.ts +26 -0
  16. package/dist/core/frontmatter.js +134 -0
  17. package/dist/core/frontmatter.js.map +1 -0
  18. package/dist/core/paths.d.ts +4 -0
  19. package/dist/core/paths.js +17 -0
  20. package/dist/core/paths.js.map +1 -0
  21. package/dist/core/resolver.d.ts +33 -0
  22. package/dist/core/resolver.js +45 -0
  23. package/dist/core/resolver.js.map +1 -0
  24. package/dist/core/scopes.d.ts +9 -0
  25. package/dist/core/scopes.js +29 -0
  26. package/dist/core/scopes.js.map +1 -0
  27. package/dist/core/source.d.ts +15 -0
  28. package/dist/core/source.js +68 -0
  29. package/dist/core/source.js.map +1 -0
  30. package/dist/core/statements.d.ts +18 -0
  31. package/dist/core/statements.js +65 -0
  32. package/dist/core/statements.js.map +1 -0
  33. package/dist/core/store.d.ts +67 -0
  34. package/dist/core/store.js +115 -0
  35. package/dist/core/store.js.map +1 -0
  36. package/dist/core/walk.d.ts +19 -0
  37. package/dist/core/walk.js +122 -0
  38. package/dist/core/walk.js.map +1 -0
  39. package/dist/index.d.ts +13 -0
  40. package/dist/index.js +14 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/model/build.d.ts +13 -0
  43. package/dist/model/build.js +67 -0
  44. package/dist/model/build.js.map +1 -0
  45. package/dist/model/index.d.ts +2 -0
  46. package/dist/model/index.js +3 -0
  47. package/dist/model/index.js.map +1 -0
  48. package/dist/model/outline.d.ts +11 -0
  49. package/dist/model/outline.js +51 -0
  50. package/dist/model/outline.js.map +1 -0
  51. package/dist/presets/blog/index.d.ts +9 -0
  52. package/dist/presets/blog/index.js +346 -0
  53. package/dist/presets/blog/index.js.map +1 -0
  54. package/dist/presets/blog/runtime.d.ts +60 -0
  55. package/dist/presets/blog/runtime.js +55 -0
  56. package/dist/presets/blog/runtime.js.map +1 -0
  57. package/dist/presets/blog/types.d.ts +48 -0
  58. package/dist/presets/blog/types.js +2 -0
  59. package/dist/presets/blog/types.js.map +1 -0
  60. package/dist/presets/mesearch/dates.d.ts +6 -0
  61. package/dist/presets/mesearch/dates.js +100 -0
  62. package/dist/presets/mesearch/dates.js.map +1 -0
  63. package/dist/presets/mesearch/index.d.ts +13 -0
  64. package/dist/presets/mesearch/index.js +407 -0
  65. package/dist/presets/mesearch/index.js.map +1 -0
  66. package/dist/presets/mesearch/runtime.d.ts +56 -0
  67. package/dist/presets/mesearch/runtime.js +57 -0
  68. package/dist/presets/mesearch/runtime.js.map +1 -0
  69. package/dist/presets/mesearch/types.d.ts +46 -0
  70. package/dist/presets/mesearch/types.js +8 -0
  71. package/dist/presets/mesearch/types.js.map +1 -0
  72. package/dist/resolvers/citation.d.ts +38 -0
  73. package/dist/resolvers/citation.js +60 -0
  74. package/dist/resolvers/citation.js.map +1 -0
  75. package/dist/resolvers/equation.d.ts +12 -0
  76. package/dist/resolvers/equation.js +52 -0
  77. package/dist/resolvers/equation.js.map +1 -0
  78. package/dist/resolvers/index.d.ts +4 -0
  79. package/dist/resolvers/index.js +5 -0
  80. package/dist/resolvers/index.js.map +1 -0
  81. package/dist/resolvers/page.d.ts +18 -0
  82. package/dist/resolvers/page.js +61 -0
  83. package/dist/resolvers/page.js.map +1 -0
  84. package/dist/resolvers/statement.d.ts +13 -0
  85. package/dist/resolvers/statement.js +45 -0
  86. package/dist/resolvers/statement.js.map +1 -0
  87. package/dist/runtime.d.ts +1 -0
  88. package/dist/runtime.js +20 -0
  89. package/dist/runtime.js.map +1 -0
  90. package/package.json +80 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matthew Varble
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # @mvarble/mesearch-cms
2
+
3
+ A content database for sites built from markdown and mdsvex documents. It is an in-memory store, rebuilt from the content on every change, holding:
4
+
5
+ - documents and the pages they are shown on;
6
+ - numbered equations and statements, scoped to a post or sequence;
7
+ - references between documents, resolved by pluggable resolvers;
8
+ - each document's outline;
9
+ - KaTeX macros, folded down the tree of documents.
10
+
11
+ A Vite plugin keeps it current during development and serves it to routes as a server-only virtual module of typed queries.
12
+
13
+ ```js
14
+ // vite.config.ts
15
+ import { createCms } from '@mvarble/mesearch-cms';
16
+ import { blogPreset } from '@mvarble/mesearch-cms/presets/blog';
17
+ import { markdownPreprocessors } from '@mvarble/mesearch-markdown';
18
+
19
+ const cms = createCms({ preset: blogPreset(), virtualId: '$cms' });
20
+
21
+ export default defineConfig({
22
+ plugins: [
23
+ ...cms.vite(),
24
+ sveltekit({
25
+ preprocess: markdownPreprocessors({
26
+ remarkPlugins: [cms.remark],
27
+ katex: { macros: cms.macrosFor },
28
+ }),
29
+ }),
30
+ ],
31
+ });
32
+ ```
33
+
34
+ ```ts
35
+ // +page.server.ts
36
+ import { cms } from '$cms';
37
+ export const load = () => ({ posts: cms.posts.list({ limit: 3 }) });
38
+ ```
39
+
40
+ `$cms/loaders` default-exports a dynamic import of every document's component, keyed by filename, and is safe to use in the browser.
41
+
42
+ ## Presets
43
+
44
+ - **`mesearchPreset`** --- `content/{concepts,writeups,sequences}/<slug>/index.{md,svx}`. It reads `depends_on` and sequence membership, takes dates from git, resolves links written as paths on disk, and builds the dependency graph. Equations and the statements a document shows share one count per document. Every `.bib` file under `content/` adds to one bibliography.
45
+ - In both presets a `cite:` link points at the reference list at the end of its own page, and `cms.bibliography(page)` gives what that list holds: everything the page, its statements and its description cite.
46
+ - Both presets share the statement registration (`core/statements.ts`) and the BibTeX reader (`core/bibtex.ts`). The reader decodes LaTeX accents and drops protective braces.
47
+ - **`blogPreset`** --- the blog's `type: post | sequence | statement` documents and `.bib` bibliographies. Statements and equations share one counter per post or sequence, and the preset provides the `cite:`, `eq:` and `statement:` references and the `%title`, `%label`, `%sequence` and `%full` link text.
48
+
49
+ A preset is a list of doctypes and resolvers (see `Doctype` and `Resolver`). A doctype registers what a file contributes in a first pass, then resolves what it refers to in a second, once every document is known, so the result never depends on the order the files are read in.
50
+
51
+ ## How changes propagate
52
+
53
+ Every document has _facts_: everything the markdown plugins and module injection read for it, such as its labels, resolved references, headings and folded macros. When the content changes, the store is rebuilt and the facts compared. Only the documents whose facts changed are recompiled, even when the file that changed was a different one: inserting a statement renumbers every later statement in its scope.
package/dist/cms.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { Plugin } from 'vite';
2
+ import { type KatexMacros } from '@mvarble/mesearch-markdown/katex';
3
+ import { type Preset } from './core/build.ts';
4
+ import type { Store } from './core/store.ts';
5
+ export interface CmsOptions {
6
+ preset: Preset;
7
+ root?: string;
8
+ macros?: KatexMacros;
9
+ virtualId?: string;
10
+ label?: string;
11
+ reload?: 'full' | 'data';
12
+ }
13
+ export interface Cms {
14
+ readonly root: string;
15
+ readonly preset: Preset;
16
+ readonly store: Store;
17
+ build(): Store;
18
+ vite(): Plugin[];
19
+ remark: () => (tree: unknown, vfile: unknown) => void;
20
+ macrosFor(vfile: unknown): KatexMacros;
21
+ }
22
+ export declare function createCms(options: CmsOptions): Cms;
package/dist/cms.js ADDED
@@ -0,0 +1,270 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import { uneval } from 'devalue';
3
+ import { documentMacros } from '@mvarble/mesearch-markdown/katex';
4
+ import { buildStore } from "./core/build.js";
5
+ import { allFacts, diffFacts } from "./core/facts.js";
6
+ import { toAbsolute, toId } from "./core/paths.js";
7
+ import { matchLink } from "./core/resolver.js";
8
+ const RUNTIME_ID = 'virtual:mesearch-cms/runtime';
9
+ const here = fileURLToPath(import.meta.url);
10
+ // What was last printed for each root, so that the several passes of one build
11
+ // --- and the several copies of the config a SvelteKit build evaluates --- do
12
+ // not repeat themselves.
13
+ const lastReported = new Map();
14
+ export function createCms(options) {
15
+ const root = options.root ?? process.cwd();
16
+ const { preset } = options;
17
+ const virtualId = options.virtualId ?? 'virtual:mesearch-cms';
18
+ const resolvedVirtualId = `\0${virtualId}`;
19
+ const loadersId = `${virtualId}/loaders`;
20
+ const resolvedLoadersId = `\0${loadersId}`;
21
+ const label = options.label ?? 'cms';
22
+ // The dev server's queries read the live snapshot through here: the module
23
+ // runner evaluates the virtual module in this same process, but in its own
24
+ // module instance, so a shared global is the one thing both can see.
25
+ const bridge = Symbol.for(`mesearch-cms:${root}:${virtualId}`);
26
+ let store;
27
+ let facts = new Map();
28
+ let snapshot;
29
+ let snapshotCode = '';
30
+ let watching = false;
31
+ function build() {
32
+ store = buildStore({ root, preset, macros: options.macros });
33
+ facts = allFacts(store);
34
+ snapshot = preset.snapshot(store);
35
+ snapshotCode = uneval(snapshot);
36
+ report(store);
37
+ return store;
38
+ }
39
+ const current = () => store ?? build();
40
+ function report(store) {
41
+ const messages = [...new Set(store.diagnostics.map((d) => d.message))];
42
+ const signature = messages.join('\n');
43
+ const previous = lastReported.get(root);
44
+ lastReported.set(root, signature);
45
+ if (signature == previous && !(watching && messages.length))
46
+ return;
47
+ if (messages.length == 0) {
48
+ if (previous)
49
+ console.log(`${label}: content is consistent again`);
50
+ return;
51
+ }
52
+ for (const message of messages)
53
+ console.error(`${label}: ${message}`);
54
+ }
55
+ globalThis[bridge] = () => {
56
+ current();
57
+ return snapshot;
58
+ };
59
+ const isContent = (id) => {
60
+ const rel = toId(root, id);
61
+ return (!rel.startsWith('..') &&
62
+ (rel + '/').startsWith(preset.contentDir.replace(/\/?$/, '/')) &&
63
+ preset.include(rel));
64
+ };
65
+ function vite() {
66
+ let server;
67
+ let command = 'build';
68
+ let pending;
69
+ // Re-transform the documents whose output depends on what just changed.
70
+ // Vite only invalidates the file that was edited, but a label is a
71
+ // function of position, and a page's title is substituted into every
72
+ // link to it: comparing each document's facts before and after says
73
+ // exactly which documents those are.
74
+ function rebuild() {
75
+ const before = facts;
76
+ const beforeSnapshot = snapshotCode;
77
+ const beforeDocs = [...facts.keys()].join('\n');
78
+ build();
79
+ const changed = diffFacts(before, facts);
80
+ const docsChanged = beforeDocs != [...facts.keys()].join('\n');
81
+ if (!server || (changed.length == 0 && beforeSnapshot == snapshotCode))
82
+ return;
83
+ const inPlace = options.reload == 'data' && !docsChanged;
84
+ for (const environment of Object.values(server.environments)) {
85
+ const graph = environment.moduleGraph;
86
+ for (const id of changed) {
87
+ const module = graph.getModuleById(toAbsolute(root, id));
88
+ if (!module)
89
+ continue;
90
+ // Hot-updated where the browser has it, and recompiled on
91
+ // next use everywhere else.
92
+ const reload = environment.reloadModule;
93
+ if (inPlace && environment.name == 'client' && reload) {
94
+ void reload.call(environment, module);
95
+ }
96
+ else {
97
+ graph.invalidateModule(module);
98
+ }
99
+ }
100
+ const virtual = graph.getModuleById(resolvedVirtualId);
101
+ if (virtual)
102
+ graph.invalidateModule(virtual);
103
+ const loaders = graph.getModuleById(resolvedLoadersId);
104
+ if (loaders && docsChanged)
105
+ graph.invalidateModule(loaders);
106
+ }
107
+ if (inPlace)
108
+ server.hot.send({ type: 'custom', event: 'mesearch-cms:update' });
109
+ else
110
+ server.hot.send({ type: 'full-reload' });
111
+ }
112
+ return [
113
+ {
114
+ name: 'mesearch-cms',
115
+ enforce: 'pre',
116
+ configResolved(config) {
117
+ command = config.command;
118
+ watching = command == 'serve';
119
+ },
120
+ configureServer(devServer) {
121
+ server = devServer;
122
+ server.watcher.add(toAbsolute(root, preset.contentDir));
123
+ },
124
+ buildStart() {
125
+ current();
126
+ },
127
+ // `watchChange` rather than `handleHotUpdate`: Vite only
128
+ // dispatches the latter for edits, so a created or deleted
129
+ // document would never reach the content layer. A single save
130
+ // can emit several events --- adding a statement is usually a
131
+ // create plus an edit to the page importing it --- so they are
132
+ // coalesced into one rebuild.
133
+ watchChange(id) {
134
+ if (!isContent(id))
135
+ return;
136
+ if (pending)
137
+ clearTimeout(pending);
138
+ pending = setTimeout(() => {
139
+ pending = undefined;
140
+ rebuild();
141
+ }, 10);
142
+ },
143
+ async resolveId(id) {
144
+ if (id == virtualId)
145
+ return resolvedVirtualId;
146
+ if (id == loadersId)
147
+ return resolvedLoadersId;
148
+ // Resolved from inside this package, so a site need not
149
+ // depend on it directly for the import to be found.
150
+ if (id == RUNTIME_ID)
151
+ return this.resolve(preset.runtime, here, { skipSelf: true });
152
+ return null;
153
+ },
154
+ load(id) {
155
+ if (id == resolvedLoadersId) {
156
+ const entries = [...current().docs.keys()]
157
+ .sort()
158
+ .map((doc) => ` ${JSON.stringify(doc)}: () => import(${JSON.stringify(toAbsolute(root, doc))}),`);
159
+ return `export default {\n${entries.join('\n')}\n};\n`;
160
+ }
161
+ if (id != resolvedVirtualId)
162
+ return null;
163
+ // An SSR build that Vite runs the legacy way is still
164
+ // called the client environment, so `build.ssr` decides.
165
+ const environment = this.environment?.config;
166
+ if (environment?.consumer == 'client' && !environment.build?.ssr) {
167
+ throw new Error(`${label}: \`${virtualId}\` is server-only; import it from a ` +
168
+ '`+page.server` or `+layout.server` module.');
169
+ }
170
+ current();
171
+ if (command == 'serve') {
172
+ return (`import { bindLive } from ${JSON.stringify(RUNTIME_ID)};\n` +
173
+ `export const cms = bindLive(() => globalThis[Symbol.for(${JSON.stringify(bridge.description)})]());\n`);
174
+ }
175
+ return (`import { bind } from ${JSON.stringify(RUNTIME_ID)};\n` +
176
+ `export const cms = bind(${snapshotCode});\n`);
177
+ },
178
+ },
179
+ {
180
+ name: 'mesearch-cms:inject',
181
+ enforce: 'post',
182
+ transform(code, id) {
183
+ if (id.includes('?') || !isContent(id))
184
+ return null;
185
+ const injection = current().injection(toId(root, id));
186
+ if (!injection)
187
+ return null;
188
+ return {
189
+ code: `${code}\nexport const cms = ${JSON.stringify(injection)};\n`,
190
+ map: null,
191
+ };
192
+ },
193
+ },
194
+ ];
195
+ }
196
+ const remark = () => (tree, vfile) => {
197
+ const filename = vfile.filename;
198
+ if (!filename)
199
+ return;
200
+ const store = current();
201
+ const id = toId(root, filename);
202
+ const doc = store.docs.get(id);
203
+ if (!doc)
204
+ return;
205
+ const top = tree.children ?? [];
206
+ // Headings get their ids by position among the same top-level headings
207
+ // the store recorded. The two texts need not agree --- a heading with
208
+ // math in it reaches the renderer as KaTeX markup --- so matching by
209
+ // text would quietly produce anchors nothing links to.
210
+ const headings = top.filter((node) => node.type == 'heading' && (node.depth ?? 0) <= preset.headingDepth);
211
+ if (headings.length != doc.headings.length && doc.headings.length) {
212
+ console.warn(`${label}: ${id}\n found ${headings.length} headings to anchor, expected ` +
213
+ `${doc.headings.length}; some table-of-contents links may miss`);
214
+ }
215
+ headings.forEach((node, i) => {
216
+ const heading = doc.headings[i];
217
+ if (!heading)
218
+ return;
219
+ node.data ??= {};
220
+ node.data.hProperties = { ...node.data.hProperties, id: heading.slug };
221
+ });
222
+ const nodes = top.toReversed();
223
+ while (nodes.length > 0) {
224
+ const node = nodes.pop();
225
+ if (node.children?.length)
226
+ nodes.push(...node.children.toReversed());
227
+ if (node.type == 'math') {
228
+ const math = node;
229
+ for (const resolver of preset.resolvers) {
230
+ if (!resolver.rewriteMath)
231
+ continue;
232
+ for (const written of resolver.matchMath?.(math.value) ?? []) {
233
+ const ref = store.ref(id, resolver.name, written);
234
+ if (ref)
235
+ resolver.rewriteMath(math, written, ref.target);
236
+ }
237
+ }
238
+ }
239
+ if (node.type == 'link') {
240
+ const link = node;
241
+ const match = matchLink(preset.resolvers, link.url, store, doc);
242
+ if (!match?.resolver.rewriteLink)
243
+ continue;
244
+ const ref = store.ref(id, match.resolver.name, match.written);
245
+ if (ref)
246
+ match.resolver.rewriteLink(link, ref.target);
247
+ }
248
+ }
249
+ };
250
+ function macrosFor(vfile) {
251
+ const filename = vfile.filename;
252
+ const store = current();
253
+ const id = filename ? toId(root, filename) : undefined;
254
+ if (id && store.docs.has(id))
255
+ return store.foldedMacros(id);
256
+ return { ...store.siteMacros, ...documentMacros(vfile) };
257
+ }
258
+ return {
259
+ root,
260
+ preset,
261
+ get store() {
262
+ return current();
263
+ },
264
+ build,
265
+ vite,
266
+ remark,
267
+ macrosFor,
268
+ };
269
+ }
270
+ //# sourceMappingURL=cms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cms.js","sourceRoot":"","sources":["../src/cms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type Citation } from '../resolvers/citation.ts';
2
+ import type { SourceFile } from './source.ts';
3
+ import type { Store } from './store.ts';
4
+ export declare function readBibliography(store: Store, file: SourceFile, collection?: string): void;
5
+ export declare function bibliographies(store: Store, collection?: string): Record<string, Citation[]>;
6
+ export declare function detex(text: string): string;
@@ -0,0 +1,129 @@
1
+ import bibtex from 'bibtex';
2
+ import { citationLabel } from "../resolvers/citation.js";
3
+ // Every entry of a `.bib` file, into the bibliography. Keys are site-wide.
4
+ export function readBibliography(store, file, collection = 'citations') {
5
+ const entries = store.collection(collection);
6
+ let parsed;
7
+ try {
8
+ parsed = bibtex.parseBibFile(file.raw);
9
+ }
10
+ catch (error) {
11
+ store.error(file.id, `${file.id}: the bibliography does not parse.\n${error}`);
12
+ return;
13
+ }
14
+ for (const [key, entry] of Object.entries(parsed.entries$)) {
15
+ const field = (name) => {
16
+ const value = entry.getFieldAsString(name);
17
+ return value === undefined ? undefined : detex(String(value));
18
+ };
19
+ const existing = sources.get(store)?.get(key);
20
+ if (existing && existing != file.id) {
21
+ store.error(file.id, `${file.id}: '${key}' is also in ${existing}; this one wins.`);
22
+ }
23
+ if (!sources.has(store))
24
+ sources.set(store, new Map());
25
+ sources.get(store).set(key, file.id);
26
+ entries.set(key, {
27
+ kind: entry.type,
28
+ key,
29
+ title: field('title') ?? '',
30
+ year: field('year') ?? '',
31
+ doi: field('doi'),
32
+ publisher: field('publisher'),
33
+ issn: field('issn'),
34
+ isbn: field('isbn'),
35
+ journal: field('journal'),
36
+ number: field('number'),
37
+ pages: field('pages'),
38
+ volume: field('volume'),
39
+ institution: field('institution'),
40
+ edition: field('edition'),
41
+ url: field('url'),
42
+ series: field('series'),
43
+ authors: (entry.getAuthors()?.authors$ ?? []).map((author) => ({
44
+ lastname: detex(String(author.lastNames$.at(-1))),
45
+ fullname: detex(fullname(author)),
46
+ })),
47
+ });
48
+ }
49
+ }
50
+ // What each page cites --- in its own text, in the statements it shows, and in
51
+ // its description --- by pathname, in the order of the labels.
52
+ export function bibliographies(store, collection = 'citations') {
53
+ const cited = new Map();
54
+ const all = store.collection(collection);
55
+ for (const id of store.docs.keys()) {
56
+ const page = store.pathnameOf(id);
57
+ if (!page)
58
+ continue;
59
+ for (const ref of store.refsOf(id)) {
60
+ if (ref.resolver != 'citation')
61
+ continue;
62
+ const citation = all.get(ref.target.key);
63
+ if (!citation)
64
+ continue;
65
+ if (!cited.has(page))
66
+ cited.set(page, new Map());
67
+ cited.get(page).set(citation.key, citation);
68
+ }
69
+ }
70
+ return Object.fromEntries([...cited].map(([page, citations]) => [
71
+ page,
72
+ [...citations.values()].sort((a, b) => citationLabel(a).localeCompare(citationLabel(b)) || a.key.localeCompare(b.key)),
73
+ ]));
74
+ }
75
+ // Which file each key came from, per build, to report a key defined twice.
76
+ const sources = new WeakMap();
77
+ function fullname(name) {
78
+ const append = (str, add) => `${str.trim()} ${add.trim()}`;
79
+ let out = name.firstNames.join(' ');
80
+ out = append(out, name.vons.join(' '));
81
+ out = append(out, name.lastNames.join(' '));
82
+ out = append(out, name.jrs.join(' '));
83
+ return out;
84
+ }
85
+ const ACCENTS = {
86
+ '"': '\u0308',
87
+ "'": '\u0301',
88
+ '`': '\u0300',
89
+ '^': '\u0302',
90
+ '~': '\u0303',
91
+ '=': '\u0304',
92
+ '.': '\u0307',
93
+ c: '\u0327',
94
+ v: '\u030c',
95
+ u: '\u0306',
96
+ H: '\u030b',
97
+ };
98
+ const LETTERS = {
99
+ ss: 'ß',
100
+ o: 'ø',
101
+ O: 'Ø',
102
+ l: 'ł',
103
+ L: 'Ł',
104
+ ae: 'æ',
105
+ AE: 'Æ',
106
+ oe: 'œ',
107
+ OE: 'Œ',
108
+ aa: 'å',
109
+ AA: 'Å',
110
+ i: 'ı',
111
+ };
112
+ // BibTeX's text as a reader sees it: `{\"u}` is ü, `{\ss}` is ß, and braces
113
+ // that only protect capitals go. Math, between dollar signs, is left alone.
114
+ export function detex(text) {
115
+ return text
116
+ .split(/(\$[^$]*\$)/g)
117
+ .map((part, i) => i % 2
118
+ ? part
119
+ : part
120
+ .replace(/\\(["'`^~=.]|[cvuH](?![a-zA-Z]))\s*\{?([a-zA-Z]|\\i)\}?/g, (_, accent, letter) => ((letter == '\\i' ? 'i' : letter) + ACCENTS[accent]).normalize('NFC'))
121
+ .replace(/\\(ss|ae|AE|oe|OE|aa|AA|o|O|l|L|i)(?![a-zA-Z])\s?/g, (_, name) => LETTERS[name])
122
+ .replace(/[{}]/g, '')
123
+ .replace(/---/g, '—')
124
+ .replace(/--/g, '–'))
125
+ .join('')
126
+ .replace(/\s+/g, ' ')
127
+ .trim();
128
+ }
129
+ //# sourceMappingURL=bibtex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bibtex.js","sourceRoot":"","sources":["../../src/core/bibtex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { KatexMacros } from '@mvarble/mesearch-markdown/katex';
2
+ import { Store, type DocRecord } from './store.ts';
3
+ import { type SourceFile } from './source.ts';
4
+ import { type Resolver } from './resolver.ts';
5
+ export interface Doctype {
6
+ name: string;
7
+ claims(file: SourceFile): boolean;
8
+ initialize?(store: Store, file: SourceFile): void;
9
+ crossReference?(store: Store, file: SourceFile): void;
10
+ finalize?(store: Store): void;
11
+ }
12
+ export interface Preset {
13
+ name: string;
14
+ contentDir: string;
15
+ include(id: string): boolean;
16
+ doctypes: Doctype[];
17
+ resolvers: Resolver[];
18
+ headingDepth: number;
19
+ runtime: string;
20
+ snapshot(store: Store): unknown;
21
+ }
22
+ export interface BuildOptions {
23
+ root: string;
24
+ preset: Preset;
25
+ macros?: KatexMacros;
26
+ }
27
+ export declare function buildStore({ root, preset, macros }: BuildOptions): Store;
28
+ export declare function defaultCrossReference(store: Store, preset: Preset, file: SourceFile): void;
29
+ export declare const docRecord: (id: string, doctype: string, fields?: Partial<Omit<DocRecord, "id" | "doctype">>) => DocRecord;
@@ -0,0 +1,41 @@
1
+ import { Store } from "./store.js";
2
+ import { scan } from "./source.js";
3
+ import { resolveReferences } from "./resolver.js";
4
+ export function buildStore({ root, preset, macros }) {
5
+ const store = new Store(root, macros);
6
+ const files = scan(root, preset.contentDir, preset.include).map((id) => store.file(id));
7
+ const claimed = files.map((file) => ({
8
+ file,
9
+ doctype: preset.doctypes.find((doctype) => doctype.claims(file)),
10
+ }));
11
+ for (const { file, doctype } of claimed)
12
+ doctype?.initialize?.(store, file);
13
+ for (const { file, doctype } of claimed) {
14
+ if (doctype?.crossReference)
15
+ doctype.crossReference(store, file);
16
+ else
17
+ defaultCrossReference(store, preset, file);
18
+ }
19
+ for (const doctype of preset.doctypes)
20
+ doctype.finalize?.(store);
21
+ return store;
22
+ }
23
+ // Anything the first pass registered gets its references resolved --- a page,
24
+ // and anything shown on one.
25
+ export function defaultCrossReference(store, preset, file) {
26
+ const doc = store.docs.get(file.id);
27
+ if (!doc || store.pathnameOf(doc.id) === undefined)
28
+ return;
29
+ resolveReferences(store, doc, file, preset.resolvers);
30
+ }
31
+ // A document with nothing of its own yet, for doctypes to fill in.
32
+ export const docRecord = (id, doctype, fields = {}) => ({
33
+ id,
34
+ doctype,
35
+ scope: fields.scope ?? id,
36
+ host: fields.host,
37
+ macroParent: fields.macroParent,
38
+ macros: fields.macros ?? {},
39
+ headings: fields.headings ?? [],
40
+ });
41
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAkB,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,IAAI,EAAmB,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAiB,MAAM,eAAe,CAAC;AA6CjE,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAgB;IAC7D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjC,IAAI;QACJ,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;KACnE,CAAC,CAAC,CAAC;IAEJ,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,OAAO;QAAE,OAAO,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC5E,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;QACtC,IAAI,OAAO,EAAE,cAAc;YAAE,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;;YAC5D,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;IACjE,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,6BAA6B;AAC7B,MAAM,UAAU,qBAAqB,CAAC,KAAY,EAAE,MAAc,EAAE,IAAgB;IAChF,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,SAAS;QAAE,OAAO;IAC3D,iBAAiB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;AAC1D,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,MAAM,SAAS,GAAG,CACrB,EAAU,EACV,OAAe,EACf,SAAqD,EAAE,EAC9C,EAAE,CAAC,CAAC;IACb,EAAE;IACF,OAAO;IACP,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;IACzB,IAAI,EAAE,MAAM,CAAC,IAAI;IACjB,WAAW,EAAE,MAAM,CAAC,WAAW;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;IAC3B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE;CAClC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Store } from './store.ts';
2
+ export declare function documentFacts(store: Store, id: string): string;
3
+ export declare function allFacts(store: Store): Map<string, string>;
4
+ export declare function diffFacts(before: Map<string, string>, after: Map<string, string>): string[];
@@ -0,0 +1,39 @@
1
+ // A digest of everything the markdown plugins and the module injection read for
2
+ // a single document --- and nothing else. When a rebuild changes a document's
3
+ // facts its compiled module is stale, even if the file itself was not touched:
4
+ // inserting one statement renumbers every later one, in other files too.
5
+ export function documentFacts(store, id) {
6
+ return JSON.stringify({
7
+ pathname: store.pathnameOf(id) ?? null,
8
+ macros: store.foldedMacros(id),
9
+ refs: store
10
+ .refsOf(id)
11
+ .map(({ resolver, written, target }) => [resolver, written, target])
12
+ .sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))),
13
+ headings: (store.docs.get(id)?.headings ?? []).map(({ depth, title, slug }) => [
14
+ depth,
15
+ title,
16
+ slug,
17
+ ]),
18
+ inject: store.injection(id) ?? null,
19
+ });
20
+ }
21
+ export function allFacts(store) {
22
+ const facts = new Map();
23
+ for (const id of [...store.docs.keys()].sort())
24
+ facts.set(id, documentFacts(store, id));
25
+ return facts;
26
+ }
27
+ // Documents whose facts differ between two builds, including documents that
28
+ // appeared or disappeared.
29
+ export function diffFacts(before, after) {
30
+ const changed = [];
31
+ for (const [id, facts] of after)
32
+ if (before.get(id) !== facts)
33
+ changed.push(id);
34
+ for (const id of before.keys())
35
+ if (!after.has(id))
36
+ changed.push(id);
37
+ return changed;
38
+ }
39
+ //# sourceMappingURL=facts.js.map