@silicajs/core 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.
- package/README.md +10 -0
- package/dist/chunk-L565TMI5.js +1045 -0
- package/dist/chunk-L565TMI5.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +469 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime.d.ts +25 -0
- package/dist/runtime.js +33 -0
- package/dist/runtime.js.map +1 -0
- package/dist/theme-Cd1tqolh.d.ts +235 -0
- package/dist/theme.d.ts +4 -0
- package/dist/theme.js +1 -0
- package/dist/theme.js.map +1 -0
- package/package.json +68 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzeMarkdown,
|
|
3
|
+
asFilePath,
|
|
4
|
+
asFullSlug,
|
|
5
|
+
asRelativeURL,
|
|
6
|
+
asSimpleSlug,
|
|
7
|
+
formatPropertyLabel,
|
|
8
|
+
formatPropertyValue,
|
|
9
|
+
getDescription,
|
|
10
|
+
getMenuLabel,
|
|
11
|
+
getPageProperties,
|
|
12
|
+
getTitle,
|
|
13
|
+
hasNumericPrefixInPath,
|
|
14
|
+
hrefToSlug,
|
|
15
|
+
joinSegments,
|
|
16
|
+
normalizePath,
|
|
17
|
+
normalizeSlug,
|
|
18
|
+
numericPrefixSortKey,
|
|
19
|
+
pathToRoot,
|
|
20
|
+
renderMarkdown,
|
|
21
|
+
renderMarkdownHtml,
|
|
22
|
+
resolveRelative,
|
|
23
|
+
resolveWikiLink,
|
|
24
|
+
simplifySlug,
|
|
25
|
+
slugToHref,
|
|
26
|
+
slugifyFilePath,
|
|
27
|
+
slugifySegment,
|
|
28
|
+
tagToHref
|
|
29
|
+
} from "./chunk-L565TMI5.js";
|
|
30
|
+
|
|
31
|
+
// src/config.ts
|
|
32
|
+
import path from "path";
|
|
33
|
+
import { existsSync } from "fs";
|
|
34
|
+
import { createJiti } from "jiti";
|
|
35
|
+
function defineConfig(config) {
|
|
36
|
+
return config;
|
|
37
|
+
}
|
|
38
|
+
async function loadConfig(projectRoot = process.cwd()) {
|
|
39
|
+
const configPath = path.join(projectRoot, "silica.config.ts");
|
|
40
|
+
const jsConfigPath = path.join(projectRoot, "silica.config.js");
|
|
41
|
+
const configFile = existsSync(configPath) ? configPath : existsSync(jsConfigPath) ? jsConfigPath : void 0;
|
|
42
|
+
let userConfig = {};
|
|
43
|
+
if (configFile) {
|
|
44
|
+
const jiti = createJiti(projectRoot, { interopDefault: true });
|
|
45
|
+
const loaded = await jiti.import(
|
|
46
|
+
configFile
|
|
47
|
+
);
|
|
48
|
+
userConfig = "default" in loaded ? loaded.default : loaded;
|
|
49
|
+
}
|
|
50
|
+
return resolveConfig(userConfig, projectRoot);
|
|
51
|
+
}
|
|
52
|
+
function resolveConfig(config = {}, projectRoot = process.cwd()) {
|
|
53
|
+
const auth = config.auth === false ? void 0 : config.auth;
|
|
54
|
+
const authEnabled = Boolean(
|
|
55
|
+
auth?.enabled ?? auth?.provider ?? auth?.allowedDomains?.length ?? auth?.allowedEmails?.length
|
|
56
|
+
);
|
|
57
|
+
const allowedDomains = auth?.allowedDomains ?? [];
|
|
58
|
+
const allowedEmails = auth?.allowedEmails ?? [];
|
|
59
|
+
if (authEnabled && allowedDomains.length === 0 && allowedEmails.length === 0) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
"Silica auth requires at least one allowedDomains or allowedEmails entry."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
projectRoot,
|
|
66
|
+
title: config.title ?? "Silica",
|
|
67
|
+
description: config.description ?? "A Silica knowledge site",
|
|
68
|
+
baseUrl: config.baseUrl,
|
|
69
|
+
contentDir: config.contentDir ?? "content",
|
|
70
|
+
theme: config.theme ?? "default",
|
|
71
|
+
auth: authEnabled ? {
|
|
72
|
+
provider: auth?.provider ?? "google",
|
|
73
|
+
enabled: true,
|
|
74
|
+
allowedDomains,
|
|
75
|
+
allowedEmails
|
|
76
|
+
} : void 0,
|
|
77
|
+
wikilinks: {
|
|
78
|
+
strategy: config.wikilinks?.strategy ?? "shortest",
|
|
79
|
+
strict: config.wikilinks?.strict ?? false
|
|
80
|
+
},
|
|
81
|
+
tags: {
|
|
82
|
+
inline: config.tags?.inline ?? true
|
|
83
|
+
},
|
|
84
|
+
ordering: {
|
|
85
|
+
numericPrefixes: config.ordering?.numericPrefixes ?? true
|
|
86
|
+
},
|
|
87
|
+
filters: {
|
|
88
|
+
removeDrafts: config.filters?.removeDrafts ?? true,
|
|
89
|
+
explicitPublish: config.filters?.explicitPublish ?? false
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/files.ts
|
|
95
|
+
import path2 from "path";
|
|
96
|
+
import fg from "fast-glob";
|
|
97
|
+
import fs from "fs-extra";
|
|
98
|
+
import matter from "gray-matter";
|
|
99
|
+
async function scanContent(projectRoot, config) {
|
|
100
|
+
const contentRoot = path2.join(projectRoot, config.contentDir);
|
|
101
|
+
const realContentRoot = await fs.realpath(contentRoot);
|
|
102
|
+
const entries = await fg("**/*", {
|
|
103
|
+
cwd: contentRoot,
|
|
104
|
+
dot: false,
|
|
105
|
+
followSymbolicLinks: false,
|
|
106
|
+
onlyFiles: true,
|
|
107
|
+
unique: true
|
|
108
|
+
});
|
|
109
|
+
const markdown = [];
|
|
110
|
+
const assets = [];
|
|
111
|
+
for (const relativePath of entries.sort()) {
|
|
112
|
+
const absolutePath = path2.join(contentRoot, relativePath);
|
|
113
|
+
const stats = await fs.lstat(absolutePath);
|
|
114
|
+
if (!stats.isFile()) continue;
|
|
115
|
+
if (!await isWithinRoot(absolutePath, realContentRoot)) continue;
|
|
116
|
+
if (isMarkdownFile(relativePath)) {
|
|
117
|
+
const raw = await fs.readFile(absolutePath, "utf8");
|
|
118
|
+
const parsed = matter(raw);
|
|
119
|
+
markdown.push({
|
|
120
|
+
absolutePath,
|
|
121
|
+
relativePath: relativePath.replace(/\\/g, "/"),
|
|
122
|
+
slug: slugifyFilePath(
|
|
123
|
+
asFilePath(relativePath),
|
|
124
|
+
config.contentDir,
|
|
125
|
+
config.ordering
|
|
126
|
+
),
|
|
127
|
+
raw,
|
|
128
|
+
body: parsed.content,
|
|
129
|
+
frontmatter: parsed.data,
|
|
130
|
+
stats: {
|
|
131
|
+
birthtime: stats.birthtime,
|
|
132
|
+
mtime: stats.mtime
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
} else {
|
|
136
|
+
assets.push({
|
|
137
|
+
absolutePath,
|
|
138
|
+
relativePath: relativePath.replace(/\\/g, "/")
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { markdown, assets };
|
|
143
|
+
}
|
|
144
|
+
async function isWithinRoot(absolutePath, realRoot) {
|
|
145
|
+
const realPath = await fs.realpath(absolutePath);
|
|
146
|
+
const relative = path2.relative(realRoot, realPath);
|
|
147
|
+
return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
|
|
148
|
+
}
|
|
149
|
+
function isMarkdownFile(filePath) {
|
|
150
|
+
return /\.(md|markdown|mdx)$/i.test(filePath);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/precompute.ts
|
|
154
|
+
import crypto from "crypto";
|
|
155
|
+
import { execFile } from "child_process";
|
|
156
|
+
import path3 from "path";
|
|
157
|
+
import { promisify } from "util";
|
|
158
|
+
import fs2 from "fs-extra";
|
|
159
|
+
import { buildSearchIndex } from "@silicajs/search";
|
|
160
|
+
var execFileAsync = promisify(execFile);
|
|
161
|
+
async function precompute(options = {}) {
|
|
162
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
163
|
+
const config = options.config ?? await loadConfig(projectRoot);
|
|
164
|
+
const scan = await scanContent(projectRoot, config);
|
|
165
|
+
const markdownFiles = filterPublished(scan.markdown, config);
|
|
166
|
+
const allSlugs = markdownFiles.map((file) => file.slug);
|
|
167
|
+
const entries = [];
|
|
168
|
+
const graphLinks = {};
|
|
169
|
+
const brokenLinks = [];
|
|
170
|
+
const searchRecords = [];
|
|
171
|
+
const runtimeContentRoot = path3.join(projectRoot, ".silica/content");
|
|
172
|
+
const relativeGitPaths = markdownFiles.map(
|
|
173
|
+
(file) => normalizeGitPath(path3.join(config.contentDir, file.relativePath))
|
|
174
|
+
);
|
|
175
|
+
const gitDatesByPath = await getGitDatesForFiles(
|
|
176
|
+
projectRoot,
|
|
177
|
+
relativeGitPaths
|
|
178
|
+
);
|
|
179
|
+
await fs2.ensureDir(path3.join(projectRoot, ".silica"));
|
|
180
|
+
await fs2.ensureDir(path3.join(projectRoot, ".silica/next/public/silica"));
|
|
181
|
+
await writeRuntimeMarkdown(runtimeContentRoot, markdownFiles);
|
|
182
|
+
for (const file of markdownFiles) {
|
|
183
|
+
const gitDates = gitDatesByPath.get(
|
|
184
|
+
normalizeGitPath(path3.join(config.contentDir, file.relativePath))
|
|
185
|
+
) ?? {};
|
|
186
|
+
const analysis = await analyzeMarkdown(file.raw, {
|
|
187
|
+
slug: asFullSlug(file.slug),
|
|
188
|
+
allSlugs,
|
|
189
|
+
assetBaseUrl: "/silica",
|
|
190
|
+
wikilinkStrategy: config.wikilinks.strategy,
|
|
191
|
+
tags: config.tags,
|
|
192
|
+
ordering: config.ordering
|
|
193
|
+
});
|
|
194
|
+
const title = analysis.title ?? titleFromSlug(file.slug);
|
|
195
|
+
const menuLabel = getMenuLabel(file.frontmatter, title);
|
|
196
|
+
const sortKey = config.ordering.numericPrefixes && hasNumericPrefixInPath(file.relativePath) ? numericPrefixSortKey(file.relativePath) : void 0;
|
|
197
|
+
const entry = {
|
|
198
|
+
slug: file.slug,
|
|
199
|
+
title,
|
|
200
|
+
menuLabel,
|
|
201
|
+
description: analysis.description,
|
|
202
|
+
tags: analysis.tags,
|
|
203
|
+
file: normalizeGitPath(path3.join(".silica/content", file.relativePath)),
|
|
204
|
+
relativeFile: file.relativePath,
|
|
205
|
+
sortKey,
|
|
206
|
+
created: stringifyDate(
|
|
207
|
+
getDate(file.frontmatter.created) ?? getDate(file.frontmatter.date) ?? gitDates.created ?? file.stats.birthtime
|
|
208
|
+
),
|
|
209
|
+
modified: stringifyDate(
|
|
210
|
+
getDate(file.frontmatter.modified) ?? gitDates.modified ?? file.stats.mtime
|
|
211
|
+
),
|
|
212
|
+
frontmatter: file.frontmatter
|
|
213
|
+
};
|
|
214
|
+
entries.push(entry);
|
|
215
|
+
graphLinks[file.slug] = analysis.links;
|
|
216
|
+
brokenLinks.push(...analysis.brokenLinks);
|
|
217
|
+
if (isListedEntry(entry)) {
|
|
218
|
+
searchRecords.push({
|
|
219
|
+
id: file.slug,
|
|
220
|
+
slug: file.slug,
|
|
221
|
+
title,
|
|
222
|
+
content: analysis.plainText,
|
|
223
|
+
description: analysis.description,
|
|
224
|
+
tags: analysis.tags
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
await copyAssets(projectRoot, config, scan.assets);
|
|
229
|
+
const manifest = makeManifest(config, entries);
|
|
230
|
+
const graph = makeGraph(graphLinks, brokenLinks);
|
|
231
|
+
const buildId = crypto.randomUUID();
|
|
232
|
+
const searchIndex = await buildSearchIndex(searchRecords);
|
|
233
|
+
await writeJson(
|
|
234
|
+
path3.join(projectRoot, ".silica/manifest.json"),
|
|
235
|
+
serializeManifest(manifest)
|
|
236
|
+
);
|
|
237
|
+
await writeJson(path3.join(projectRoot, ".silica/graph.json"), graph);
|
|
238
|
+
await writeJson(path3.join(projectRoot, ".silica/config.json"), config);
|
|
239
|
+
await writeJson(
|
|
240
|
+
path3.join(projectRoot, ".silica/search-index.json"),
|
|
241
|
+
searchIndex
|
|
242
|
+
);
|
|
243
|
+
await fs2.writeFile(
|
|
244
|
+
path3.join(projectRoot, ".silica/build-id.txt"),
|
|
245
|
+
`${buildId}
|
|
246
|
+
`
|
|
247
|
+
);
|
|
248
|
+
await writeSitemapAndRobots(projectRoot, config, manifest);
|
|
249
|
+
if (config.wikilinks.strict && brokenLinks.length > 0) {
|
|
250
|
+
const message = brokenLinks.map((link) => `${link.source} -> ${link.target}`).join("\n");
|
|
251
|
+
throw new Error(`Broken wikilinks detected:
|
|
252
|
+
${message}`);
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
manifest,
|
|
256
|
+
graph,
|
|
257
|
+
searchRecords,
|
|
258
|
+
buildId,
|
|
259
|
+
brokenLinks
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async function writeRuntimeMarkdown(runtimeContentRoot, files) {
|
|
263
|
+
await fs2.emptyDir(runtimeContentRoot);
|
|
264
|
+
for (const file of files) {
|
|
265
|
+
const destination = path3.join(runtimeContentRoot, file.relativePath);
|
|
266
|
+
await fs2.ensureDir(path3.dirname(destination));
|
|
267
|
+
await fs2.writeFile(destination, file.raw);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function serializeManifest(manifest) {
|
|
271
|
+
return {
|
|
272
|
+
version: manifest.version,
|
|
273
|
+
generatedAt: manifest.generatedAt,
|
|
274
|
+
contentDir: manifest.contentDir,
|
|
275
|
+
entries: manifest.entries
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
async function getGitDates(projectRoot, relativePath) {
|
|
279
|
+
return (await getGitDatesForFiles(projectRoot, [normalizeGitPath(relativePath)])).get(normalizeGitPath(relativePath)) ?? {};
|
|
280
|
+
}
|
|
281
|
+
async function getGitDatesForFiles(projectRoot, relativePaths) {
|
|
282
|
+
const wanted = new Set(relativePaths.map(normalizeGitPath));
|
|
283
|
+
const datesByPath = /* @__PURE__ */ new Map();
|
|
284
|
+
if (wanted.size === 0) return datesByPath;
|
|
285
|
+
try {
|
|
286
|
+
const { stdout } = await execFileAsync(
|
|
287
|
+
"git",
|
|
288
|
+
["log", "--format=__SILICA_COMMIT__%aI", "--name-only", "--", ...wanted],
|
|
289
|
+
{
|
|
290
|
+
cwd: projectRoot,
|
|
291
|
+
timeout: 2e3
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
let commitDate;
|
|
295
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
296
|
+
const trimmed = line.trim();
|
|
297
|
+
if (!trimmed) continue;
|
|
298
|
+
if (trimmed.startsWith("__SILICA_COMMIT__")) {
|
|
299
|
+
const parsed = new Date(trimmed.slice("__SILICA_COMMIT__".length));
|
|
300
|
+
commitDate = Number.isNaN(parsed.valueOf()) ? void 0 : parsed;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const relativePath = normalizeGitPath(trimmed);
|
|
304
|
+
if (!commitDate || !wanted.has(relativePath)) continue;
|
|
305
|
+
const dates = datesByPath.get(relativePath) ?? {};
|
|
306
|
+
dates.modified ??= commitDate;
|
|
307
|
+
dates.created = commitDate;
|
|
308
|
+
datesByPath.set(relativePath, dates);
|
|
309
|
+
}
|
|
310
|
+
} catch {
|
|
311
|
+
return datesByPath;
|
|
312
|
+
}
|
|
313
|
+
return datesByPath;
|
|
314
|
+
}
|
|
315
|
+
function normalizeGitPath(relativePath) {
|
|
316
|
+
return relativePath.replace(/\\/g, "/");
|
|
317
|
+
}
|
|
318
|
+
function filterPublished(files, config) {
|
|
319
|
+
return files.filter((file) => {
|
|
320
|
+
if (config.filters.removeDrafts && file.frontmatter.draft === true)
|
|
321
|
+
return false;
|
|
322
|
+
if (config.filters.explicitPublish && file.frontmatter.publish !== true)
|
|
323
|
+
return false;
|
|
324
|
+
return true;
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
function makeManifest(config, entries) {
|
|
328
|
+
const sorted = [...entries].sort(compareManifestEntries);
|
|
329
|
+
return {
|
|
330
|
+
version: 1,
|
|
331
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
332
|
+
contentDir: config.contentDir,
|
|
333
|
+
allSlugs: sorted.map((entry) => entry.slug),
|
|
334
|
+
entries: sorted,
|
|
335
|
+
bySlug: Object.fromEntries(sorted.map((entry) => [entry.slug, entry]))
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
function compareManifestEntries(a, b) {
|
|
339
|
+
if (a.sortKey || b.sortKey) {
|
|
340
|
+
return (a.sortKey ?? fallbackSortKey(a.slug)).localeCompare(
|
|
341
|
+
b.sortKey ?? fallbackSortKey(b.slug)
|
|
342
|
+
) || a.slug.localeCompare(b.slug);
|
|
343
|
+
}
|
|
344
|
+
return a.slug.localeCompare(b.slug);
|
|
345
|
+
}
|
|
346
|
+
function fallbackSortKey(slug) {
|
|
347
|
+
return slug.split("/").map((segment) => `~~~~~~~~~~:${segment}`).join("/");
|
|
348
|
+
}
|
|
349
|
+
function makeGraph(links, brokenLinks) {
|
|
350
|
+
const backlinks = {};
|
|
351
|
+
for (const [source, targets] of Object.entries(links)) {
|
|
352
|
+
links[source] = [...new Set(targets)].sort();
|
|
353
|
+
for (const target of targets) {
|
|
354
|
+
backlinks[target] ??= [];
|
|
355
|
+
backlinks[target].push(source);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
for (const [target, sources] of Object.entries(backlinks)) {
|
|
359
|
+
backlinks[target] = [...new Set(sources)].sort();
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
version: 1,
|
|
363
|
+
links,
|
|
364
|
+
backlinks,
|
|
365
|
+
brokenLinks
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
async function copyAssets(projectRoot, config, assets) {
|
|
369
|
+
const destinationRoot = path3.join(projectRoot, ".silica/next/public/silica");
|
|
370
|
+
await fs2.emptyDir(destinationRoot);
|
|
371
|
+
for (const asset of assets) {
|
|
372
|
+
await fs2.ensureDir(
|
|
373
|
+
path3.dirname(path3.join(destinationRoot, asset.relativePath))
|
|
374
|
+
);
|
|
375
|
+
await fs2.copyFile(
|
|
376
|
+
asset.absolutePath,
|
|
377
|
+
path3.join(destinationRoot, asset.relativePath)
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
await fs2.ensureDir(path3.join(projectRoot, ".silica/next/public"));
|
|
381
|
+
await fs2.writeFile(path3.join(destinationRoot, ".gitkeep"), "");
|
|
382
|
+
}
|
|
383
|
+
async function writeSitemapAndRobots(projectRoot, config, manifest) {
|
|
384
|
+
const publicRoot = path3.join(projectRoot, ".silica/next/public");
|
|
385
|
+
await fs2.ensureDir(publicRoot);
|
|
386
|
+
const baseUrl = (config.baseUrl ?? "http://localhost:3000").replace(
|
|
387
|
+
/\/$/,
|
|
388
|
+
""
|
|
389
|
+
);
|
|
390
|
+
const urls = manifest.entries.filter(isListedEntry).map(
|
|
391
|
+
(entry) => ` <url><loc>${baseUrl}${slugToHref(entry.slug)}</loc></url>`
|
|
392
|
+
).join("\n");
|
|
393
|
+
if (!await fs2.pathExists(path3.join(projectRoot, "public/sitemap.xml"))) {
|
|
394
|
+
await fs2.writeFile(
|
|
395
|
+
path3.join(publicRoot, "sitemap.xml"),
|
|
396
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
397
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
398
|
+
${urls}
|
|
399
|
+
</urlset>
|
|
400
|
+
`
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
if (!await fs2.pathExists(path3.join(projectRoot, "public/robots.txt"))) {
|
|
404
|
+
await fs2.writeFile(
|
|
405
|
+
path3.join(publicRoot, "robots.txt"),
|
|
406
|
+
`User-agent: *
|
|
407
|
+
Allow: /
|
|
408
|
+
Sitemap: ${baseUrl}/sitemap.xml
|
|
409
|
+
`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
async function writeJson(filePath, value) {
|
|
414
|
+
await fs2.ensureDir(path3.dirname(filePath));
|
|
415
|
+
await fs2.writeJson(filePath, value, { spaces: 2 });
|
|
416
|
+
}
|
|
417
|
+
function getDate(value) {
|
|
418
|
+
if (value instanceof Date) return value;
|
|
419
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
420
|
+
const parsed = new Date(value);
|
|
421
|
+
if (!Number.isNaN(parsed.valueOf())) return parsed;
|
|
422
|
+
}
|
|
423
|
+
return void 0;
|
|
424
|
+
}
|
|
425
|
+
function isListedEntry(entry) {
|
|
426
|
+
return entry.frontmatter.listed !== false;
|
|
427
|
+
}
|
|
428
|
+
function stringifyDate(value) {
|
|
429
|
+
return value?.toISOString();
|
|
430
|
+
}
|
|
431
|
+
function titleFromSlug(slug) {
|
|
432
|
+
const leaf = slug.split("/").at(-1) ?? slug;
|
|
433
|
+
return leaf.replace(/-/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase()).replace(/^Index$/, "Home");
|
|
434
|
+
}
|
|
435
|
+
export {
|
|
436
|
+
analyzeMarkdown,
|
|
437
|
+
asFilePath,
|
|
438
|
+
asFullSlug,
|
|
439
|
+
asRelativeURL,
|
|
440
|
+
asSimpleSlug,
|
|
441
|
+
defineConfig,
|
|
442
|
+
formatPropertyLabel,
|
|
443
|
+
formatPropertyValue,
|
|
444
|
+
getDescription,
|
|
445
|
+
getGitDates,
|
|
446
|
+
getMenuLabel,
|
|
447
|
+
getPageProperties,
|
|
448
|
+
getTitle,
|
|
449
|
+
hrefToSlug,
|
|
450
|
+
isMarkdownFile,
|
|
451
|
+
joinSegments,
|
|
452
|
+
loadConfig,
|
|
453
|
+
normalizePath,
|
|
454
|
+
normalizeSlug,
|
|
455
|
+
pathToRoot,
|
|
456
|
+
precompute,
|
|
457
|
+
renderMarkdown,
|
|
458
|
+
renderMarkdownHtml,
|
|
459
|
+
resolveConfig,
|
|
460
|
+
resolveRelative,
|
|
461
|
+
resolveWikiLink,
|
|
462
|
+
scanContent,
|
|
463
|
+
simplifySlug,
|
|
464
|
+
slugToHref,
|
|
465
|
+
slugifyFilePath,
|
|
466
|
+
slugifySegment,
|
|
467
|
+
tagToHref
|
|
468
|
+
};
|
|
469
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/files.ts","../src/precompute.ts"],"sourcesContent":["import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { createJiti } from \"jiti\";\nimport type { ResolvedSilicaConfig, SilicaConfig } from \"./types.js\";\n\nexport function defineConfig(config: SilicaConfig): SilicaConfig {\n return config;\n}\n\nexport async function loadConfig(\n projectRoot = process.cwd(),\n): Promise<ResolvedSilicaConfig> {\n const configPath = path.join(projectRoot, \"silica.config.ts\");\n const jsConfigPath = path.join(projectRoot, \"silica.config.js\");\n const configFile = existsSync(configPath)\n ? configPath\n : existsSync(jsConfigPath)\n ? jsConfigPath\n : undefined;\n\n let userConfig: SilicaConfig = {};\n if (configFile) {\n const jiti = createJiti(projectRoot, { interopDefault: true });\n const loaded = await jiti.import<SilicaConfig | { default: SilicaConfig }>(\n configFile,\n );\n userConfig = \"default\" in loaded ? loaded.default : loaded;\n }\n\n return resolveConfig(userConfig, projectRoot);\n}\n\nexport function resolveConfig(\n config: SilicaConfig = {},\n projectRoot = process.cwd(),\n): ResolvedSilicaConfig {\n const auth = config.auth === false ? undefined : config.auth;\n const authEnabled = Boolean(\n auth?.enabled ??\n auth?.provider ??\n auth?.allowedDomains?.length ??\n auth?.allowedEmails?.length,\n );\n const allowedDomains = auth?.allowedDomains ?? [];\n const allowedEmails = auth?.allowedEmails ?? [];\n\n if (\n authEnabled &&\n allowedDomains.length === 0 &&\n allowedEmails.length === 0\n ) {\n throw new Error(\n \"Silica auth requires at least one allowedDomains or allowedEmails entry.\",\n );\n }\n\n return {\n projectRoot,\n title: config.title ?? \"Silica\",\n description: config.description ?? \"A Silica knowledge site\",\n baseUrl: config.baseUrl,\n contentDir: config.contentDir ?? \"content\",\n theme: config.theme ?? \"default\",\n auth: authEnabled\n ? {\n provider: auth?.provider ?? \"google\",\n enabled: true,\n allowedDomains,\n allowedEmails,\n }\n : undefined,\n wikilinks: {\n strategy: config.wikilinks?.strategy ?? \"shortest\",\n strict: config.wikilinks?.strict ?? false,\n },\n tags: {\n inline: config.tags?.inline ?? true,\n },\n ordering: {\n numericPrefixes: config.ordering?.numericPrefixes ?? true,\n },\n filters: {\n removeDrafts: config.filters?.removeDrafts ?? true,\n explicitPublish: config.filters?.explicitPublish ?? false,\n },\n };\n}\n","import path from \"node:path\";\nimport fg from \"fast-glob\";\nimport fs from \"fs-extra\";\nimport matter from \"gray-matter\";\nimport type { ResolvedSilicaConfig } from \"./types.js\";\nimport { asFilePath, slugifyFilePath } from \"./path.js\";\n\nexport type ContentMarkdownFile = {\n absolutePath: string;\n relativePath: string;\n slug: string;\n raw: string;\n body: string;\n frontmatter: Record<string, unknown>;\n stats: {\n birthtime?: Date;\n mtime?: Date;\n };\n};\n\nexport type ContentAssetFile = {\n absolutePath: string;\n relativePath: string;\n};\n\nexport type ContentScan = {\n markdown: ContentMarkdownFile[];\n assets: ContentAssetFile[];\n};\n\nexport async function scanContent(\n projectRoot: string,\n config: ResolvedSilicaConfig,\n): Promise<ContentScan> {\n const contentRoot = path.join(projectRoot, config.contentDir);\n const realContentRoot = await fs.realpath(contentRoot);\n const entries = await fg(\"**/*\", {\n cwd: contentRoot,\n dot: false,\n followSymbolicLinks: false,\n onlyFiles: true,\n unique: true,\n });\n\n const markdown: ContentMarkdownFile[] = [];\n const assets: ContentAssetFile[] = [];\n\n for (const relativePath of entries.sort()) {\n const absolutePath = path.join(contentRoot, relativePath);\n const stats = await fs.lstat(absolutePath);\n if (!stats.isFile()) continue;\n if (!(await isWithinRoot(absolutePath, realContentRoot))) continue;\n\n if (isMarkdownFile(relativePath)) {\n const raw = await fs.readFile(absolutePath, \"utf8\");\n const parsed = matter(raw);\n markdown.push({\n absolutePath,\n relativePath: relativePath.replace(/\\\\/g, \"/\"),\n slug: slugifyFilePath(\n asFilePath(relativePath),\n config.contentDir,\n config.ordering,\n ),\n raw,\n body: parsed.content,\n frontmatter: parsed.data,\n stats: {\n birthtime: stats.birthtime,\n mtime: stats.mtime,\n },\n });\n } else {\n assets.push({\n absolutePath,\n relativePath: relativePath.replace(/\\\\/g, \"/\"),\n });\n }\n }\n\n return { markdown, assets };\n}\n\nasync function isWithinRoot(\n absolutePath: string,\n realRoot: string,\n): Promise<boolean> {\n const realPath = await fs.realpath(absolutePath);\n const relative = path.relative(realRoot, realPath);\n return (\n relative === \"\" ||\n (!relative.startsWith(\"..\") && !path.isAbsolute(relative))\n );\n}\n\nexport function isMarkdownFile(filePath: string): boolean {\n return /\\.(md|markdown|mdx)$/i.test(filePath);\n}\n","import crypto from \"node:crypto\";\nimport { execFile } from \"node:child_process\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport fs from \"fs-extra\";\nimport { buildSearchIndex, type SearchRecord } from \"@silicajs/search\";\nimport { loadConfig } from \"./config.js\";\nimport { scanContent, type ContentMarkdownFile } from \"./files.js\";\nimport {\n asFullSlug,\n hasNumericPrefixInPath,\n numericPrefixSortKey,\n slugToHref,\n} from \"./path.js\";\nimport { getMenuLabel } from \"./pipeline/frontmatter.js\";\nimport { analyzeMarkdown } from \"./pipeline/index.js\";\nimport type {\n BrokenLink,\n Graph,\n Manifest,\n ManifestEntry,\n PrecomputeResult,\n ResolvedSilicaConfig,\n} from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nexport type PrecomputeOptions = {\n projectRoot?: string;\n config?: ResolvedSilicaConfig;\n};\n\nexport async function precompute(\n options: PrecomputeOptions = {},\n): Promise<PrecomputeResult> {\n const projectRoot = options.projectRoot ?? process.cwd();\n const config = options.config ?? (await loadConfig(projectRoot));\n const scan = await scanContent(projectRoot, config);\n const markdownFiles = filterPublished(scan.markdown, config);\n const allSlugs = markdownFiles.map((file) => file.slug);\n const entries: ManifestEntry[] = [];\n const graphLinks: Record<string, string[]> = {};\n const brokenLinks: BrokenLink[] = [];\n const searchRecords: SearchRecord[] = [];\n const runtimeContentRoot = path.join(projectRoot, \".silica/content\");\n const relativeGitPaths = markdownFiles.map((file) =>\n normalizeGitPath(path.join(config.contentDir, file.relativePath)),\n );\n const gitDatesByPath = await getGitDatesForFiles(\n projectRoot,\n relativeGitPaths,\n );\n\n await fs.ensureDir(path.join(projectRoot, \".silica\"));\n await fs.ensureDir(path.join(projectRoot, \".silica/next/public/silica\"));\n await writeRuntimeMarkdown(runtimeContentRoot, markdownFiles);\n\n for (const file of markdownFiles) {\n const gitDates =\n gitDatesByPath.get(\n normalizeGitPath(path.join(config.contentDir, file.relativePath)),\n ) ?? {};\n const analysis = await analyzeMarkdown(file.raw, {\n slug: asFullSlug(file.slug),\n allSlugs,\n assetBaseUrl: \"/silica\",\n wikilinkStrategy: config.wikilinks.strategy,\n tags: config.tags,\n ordering: config.ordering,\n });\n\n const title = analysis.title ?? titleFromSlug(file.slug);\n const menuLabel = getMenuLabel(file.frontmatter, title);\n const sortKey =\n config.ordering.numericPrefixes &&\n hasNumericPrefixInPath(file.relativePath)\n ? numericPrefixSortKey(file.relativePath)\n : undefined;\n const entry: ManifestEntry = {\n slug: file.slug,\n title,\n menuLabel,\n description: analysis.description,\n tags: analysis.tags,\n file: normalizeGitPath(path.join(\".silica/content\", file.relativePath)),\n relativeFile: file.relativePath,\n sortKey,\n created: stringifyDate(\n getDate(file.frontmatter.created) ??\n getDate(file.frontmatter.date) ??\n gitDates.created ??\n file.stats.birthtime,\n ),\n modified: stringifyDate(\n getDate(file.frontmatter.modified) ??\n gitDates.modified ??\n file.stats.mtime,\n ),\n frontmatter: file.frontmatter,\n };\n entries.push(entry);\n graphLinks[file.slug] = analysis.links;\n brokenLinks.push(...analysis.brokenLinks);\n if (isListedEntry(entry)) {\n searchRecords.push({\n id: file.slug,\n slug: file.slug,\n title,\n content: analysis.plainText,\n description: analysis.description,\n tags: analysis.tags,\n });\n }\n }\n\n await copyAssets(projectRoot, config, scan.assets);\n\n const manifest = makeManifest(config, entries);\n const graph = makeGraph(graphLinks, brokenLinks);\n const buildId = crypto.randomUUID();\n const searchIndex = await buildSearchIndex(searchRecords);\n\n await writeJson(\n path.join(projectRoot, \".silica/manifest.json\"),\n serializeManifest(manifest),\n );\n await writeJson(path.join(projectRoot, \".silica/graph.json\"), graph);\n await writeJson(path.join(projectRoot, \".silica/config.json\"), config);\n await writeJson(\n path.join(projectRoot, \".silica/search-index.json\"),\n searchIndex,\n );\n await fs.writeFile(\n path.join(projectRoot, \".silica/build-id.txt\"),\n `${buildId}\\n`,\n );\n await writeSitemapAndRobots(projectRoot, config, manifest);\n\n if (config.wikilinks.strict && brokenLinks.length > 0) {\n const message = brokenLinks\n .map((link) => `${link.source} -> ${link.target}`)\n .join(\"\\n\");\n throw new Error(`Broken wikilinks detected:\\n${message}`);\n }\n\n return {\n manifest,\n graph,\n searchRecords,\n buildId,\n brokenLinks,\n };\n}\n\nasync function writeRuntimeMarkdown(\n runtimeContentRoot: string,\n files: ContentMarkdownFile[],\n): Promise<void> {\n await fs.emptyDir(runtimeContentRoot);\n for (const file of files) {\n const destination = path.join(runtimeContentRoot, file.relativePath);\n await fs.ensureDir(path.dirname(destination));\n await fs.writeFile(destination, file.raw);\n }\n}\n\nfunction serializeManifest(\n manifest: Manifest,\n): Omit<Manifest, \"allSlugs\" | \"bySlug\"> {\n return {\n version: manifest.version,\n generatedAt: manifest.generatedAt,\n contentDir: manifest.contentDir,\n entries: manifest.entries,\n };\n}\n\nexport async function getGitDates(\n projectRoot: string,\n relativePath: string,\n): Promise<{ created?: Date; modified?: Date }> {\n return (\n (\n await getGitDatesForFiles(projectRoot, [normalizeGitPath(relativePath)])\n ).get(normalizeGitPath(relativePath)) ?? {}\n );\n}\n\nasync function getGitDatesForFiles(\n projectRoot: string,\n relativePaths: string[],\n): Promise<Map<string, { created?: Date; modified?: Date }>> {\n const wanted = new Set(relativePaths.map(normalizeGitPath));\n const datesByPath = new Map<string, { created?: Date; modified?: Date }>();\n if (wanted.size === 0) return datesByPath;\n\n try {\n const { stdout } = await execFileAsync(\n \"git\",\n [\"log\", \"--format=__SILICA_COMMIT__%aI\", \"--name-only\", \"--\", ...wanted],\n {\n cwd: projectRoot,\n timeout: 2_000,\n },\n );\n let commitDate: Date | undefined;\n for (const line of stdout.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (trimmed.startsWith(\"__SILICA_COMMIT__\")) {\n const parsed = new Date(trimmed.slice(\"__SILICA_COMMIT__\".length));\n commitDate = Number.isNaN(parsed.valueOf()) ? undefined : parsed;\n continue;\n }\n const relativePath = normalizeGitPath(trimmed);\n if (!commitDate || !wanted.has(relativePath)) continue;\n const dates = datesByPath.get(relativePath) ?? {};\n dates.modified ??= commitDate;\n dates.created = commitDate;\n datesByPath.set(relativePath, dates);\n }\n } catch {\n return datesByPath;\n }\n return datesByPath;\n}\n\nfunction normalizeGitPath(relativePath: string): string {\n return relativePath.replace(/\\\\/g, \"/\");\n}\n\nfunction filterPublished(\n files: ContentMarkdownFile[],\n config: ResolvedSilicaConfig,\n): ContentMarkdownFile[] {\n return files.filter((file) => {\n if (config.filters.removeDrafts && file.frontmatter.draft === true)\n return false;\n if (config.filters.explicitPublish && file.frontmatter.publish !== true)\n return false;\n return true;\n });\n}\n\nfunction makeManifest(\n config: ResolvedSilicaConfig,\n entries: ManifestEntry[],\n): Manifest {\n const sorted = [...entries].sort(compareManifestEntries);\n return {\n version: 1,\n generatedAt: new Date().toISOString(),\n contentDir: config.contentDir,\n allSlugs: sorted.map((entry) => entry.slug),\n entries: sorted,\n bySlug: Object.fromEntries(sorted.map((entry) => [entry.slug, entry])),\n };\n}\n\nfunction compareManifestEntries(a: ManifestEntry, b: ManifestEntry): number {\n if (a.sortKey || b.sortKey) {\n return (\n (a.sortKey ?? fallbackSortKey(a.slug)).localeCompare(\n b.sortKey ?? fallbackSortKey(b.slug),\n ) || a.slug.localeCompare(b.slug)\n );\n }\n\n return a.slug.localeCompare(b.slug);\n}\n\nfunction fallbackSortKey(slug: string): string {\n return slug\n .split(\"/\")\n .map((segment) => `~~~~~~~~~~:${segment}`)\n .join(\"/\");\n}\n\nfunction makeGraph(\n links: Record<string, string[]>,\n brokenLinks: BrokenLink[],\n): Graph {\n const backlinks: Record<string, string[]> = {};\n for (const [source, targets] of Object.entries(links)) {\n links[source] = [...new Set(targets)].sort();\n for (const target of targets) {\n backlinks[target] ??= [];\n backlinks[target]!.push(source);\n }\n }\n\n for (const [target, sources] of Object.entries(backlinks)) {\n backlinks[target] = [...new Set(sources)].sort();\n }\n\n return {\n version: 1,\n links,\n backlinks,\n brokenLinks,\n };\n}\n\nasync function copyAssets(\n projectRoot: string,\n config: ResolvedSilicaConfig,\n assets: Array<{ absolutePath: string; relativePath: string }>,\n): Promise<void> {\n const destinationRoot = path.join(projectRoot, \".silica/next/public/silica\");\n await fs.emptyDir(destinationRoot);\n for (const asset of assets) {\n await fs.ensureDir(\n path.dirname(path.join(destinationRoot, asset.relativePath)),\n );\n await fs.copyFile(\n asset.absolutePath,\n path.join(destinationRoot, asset.relativePath),\n );\n }\n\n await fs.ensureDir(path.join(projectRoot, \".silica/next/public\"));\n await fs.writeFile(path.join(destinationRoot, \".gitkeep\"), \"\");\n}\n\nasync function writeSitemapAndRobots(\n projectRoot: string,\n config: ResolvedSilicaConfig,\n manifest: Manifest,\n): Promise<void> {\n const publicRoot = path.join(projectRoot, \".silica/next/public\");\n await fs.ensureDir(publicRoot);\n const baseUrl = (config.baseUrl ?? \"http://localhost:3000\").replace(\n /\\/$/,\n \"\",\n );\n const urls = manifest.entries\n .filter(isListedEntry)\n .map(\n (entry) => ` <url><loc>${baseUrl}${slugToHref(entry.slug)}</loc></url>`,\n )\n .join(\"\\n\");\n if (!(await fs.pathExists(path.join(projectRoot, \"public/sitemap.xml\")))) {\n await fs.writeFile(\n path.join(publicRoot, \"sitemap.xml\"),\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n${urls}\\n</urlset>\\n`,\n );\n }\n if (!(await fs.pathExists(path.join(projectRoot, \"public/robots.txt\")))) {\n await fs.writeFile(\n path.join(publicRoot, \"robots.txt\"),\n `User-agent: *\\nAllow: /\\nSitemap: ${baseUrl}/sitemap.xml\\n`,\n );\n }\n}\n\nasync function writeJson(filePath: string, value: unknown): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeJson(filePath, value, { spaces: 2 });\n}\n\nfunction getDate(value: unknown): Date | undefined {\n if (value instanceof Date) return value;\n if (typeof value === \"string\" || typeof value === \"number\") {\n const parsed = new Date(value);\n if (!Number.isNaN(parsed.valueOf())) return parsed;\n }\n return undefined;\n}\n\nexport function isListedEntry(entry: ManifestEntry): boolean {\n return entry.frontmatter.listed !== false;\n}\n\nfunction stringifyDate(value?: Date): string | undefined {\n return value?.toISOString();\n}\n\nfunction titleFromSlug(slug: string): string {\n const leaf = slug.split(\"/\").at(-1) ?? slug;\n return leaf\n .replace(/-/g, \" \")\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase())\n .replace(/^Index$/, \"Home\");\n}\n"],"mappings":"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","names":["path","path","path","fs","path","fs"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { d as RenderContext, A as AnalyzeResult, e as RenderResult } from './theme-Cd1tqolh.js';
|
|
2
|
+
export { B as BrokenLink, G as Graph, M as Manifest, b as ManifestEntry, c as MarkdownComponents, f as ResolvedSilicaConfig, g as SilicaCalloutProps, h as SilicaCodeBlockProps, j as SilicaEmbedProps, k as SilicaMermaidProps, l as SilicaTheme, n as ThemeLayoutConfig, o as ThemeLayoutProps, p as ThemeNavigationEntry, q as ThemePage, r as ThemePageProps, s as ThemeProviderComponent, t as TocItem, y as hrefToSlug, I as resolveWikiLink, J as simplifySlug, K as slugToHref } from './theme-Cd1tqolh.js';
|
|
3
|
+
import 'react';
|
|
4
|
+
import '@silicajs/search';
|
|
5
|
+
import '@silicajs/remark-obsidian';
|
|
6
|
+
|
|
7
|
+
type PageProperty = {
|
|
8
|
+
key: string;
|
|
9
|
+
label: string;
|
|
10
|
+
value: string;
|
|
11
|
+
};
|
|
12
|
+
declare function getMenuLabel(frontmatter: Record<string, unknown>, title: string): string;
|
|
13
|
+
declare function getPageProperties(frontmatter: Record<string, unknown>): PageProperty[];
|
|
14
|
+
declare function formatPropertyLabel(key: string): string;
|
|
15
|
+
declare function formatPropertyValue(value: unknown): string | undefined;
|
|
16
|
+
|
|
17
|
+
declare function renderMarkdown(raw: string, context: RenderContext): Promise<RenderResult>;
|
|
18
|
+
declare function renderMarkdownHtml(raw: string, context: RenderContext): Promise<string>;
|
|
19
|
+
declare function analyzeMarkdown(raw: string, context: RenderContext): Promise<AnalyzeResult>;
|
|
20
|
+
declare function getTitle(frontmatter: Record<string, unknown>, plainText: string): string | undefined;
|
|
21
|
+
declare function getDescription(frontmatter: Record<string, unknown>, plainText: string): string | undefined;
|
|
22
|
+
|
|
23
|
+
declare function tagToHref(tag: string): string;
|
|
24
|
+
|
|
25
|
+
export { AnalyzeResult, type PageProperty, RenderContext, RenderResult, analyzeMarkdown, formatPropertyLabel, formatPropertyValue, getDescription, getMenuLabel, getPageProperties, getTitle, renderMarkdown, renderMarkdownHtml, tagToHref };
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
analyzeMarkdown,
|
|
3
|
+
formatPropertyLabel,
|
|
4
|
+
formatPropertyValue,
|
|
5
|
+
getDescription,
|
|
6
|
+
getMenuLabel,
|
|
7
|
+
getPageProperties,
|
|
8
|
+
getTitle,
|
|
9
|
+
hrefToSlug,
|
|
10
|
+
renderMarkdown,
|
|
11
|
+
renderMarkdownHtml,
|
|
12
|
+
resolveWikiLink,
|
|
13
|
+
simplifySlug,
|
|
14
|
+
slugToHref,
|
|
15
|
+
tagToHref
|
|
16
|
+
} from "./chunk-L565TMI5.js";
|
|
17
|
+
export {
|
|
18
|
+
analyzeMarkdown,
|
|
19
|
+
formatPropertyLabel,
|
|
20
|
+
formatPropertyValue,
|
|
21
|
+
getDescription,
|
|
22
|
+
getMenuLabel,
|
|
23
|
+
getPageProperties,
|
|
24
|
+
getTitle,
|
|
25
|
+
hrefToSlug,
|
|
26
|
+
renderMarkdown,
|
|
27
|
+
renderMarkdownHtml,
|
|
28
|
+
resolveWikiLink,
|
|
29
|
+
simplifySlug,
|
|
30
|
+
slugToHref,
|
|
31
|
+
tagToHref
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|