@silicajs/core 0.5.1 → 0.6.1
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/dist/{chunk-2TXWBKM4.js → chunk-2EKH4A4V.js} +124 -3
- package/dist/chunk-2EKH4A4V.js.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +113 -24
- package/dist/index.js.map +1 -1
- package/dist/precompute-worker.js +5 -1
- package/dist/precompute-worker.js.map +1 -1
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +11 -1
- package/dist/{theme-BK5ZRXFG.d.ts → theme-DuygYyeF.d.ts} +18 -2
- package/dist/theme.d.ts +1 -1
- package/package.json +4 -4
- package/dist/chunk-2TXWBKM4.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
asFullSlug,
|
|
11
11
|
asRelativeURL,
|
|
12
12
|
asSimpleSlug,
|
|
13
|
+
createAssetResolutionIndex,
|
|
13
14
|
createWikiLinkResolutionIndex,
|
|
14
15
|
generateDescriptionFromContent,
|
|
15
16
|
getDescription,
|
|
@@ -18,21 +19,25 @@ import {
|
|
|
18
19
|
hasNumericPrefixInPath,
|
|
19
20
|
hrefToSlug,
|
|
20
21
|
joinSegments,
|
|
22
|
+
normalizeAssetReference,
|
|
21
23
|
normalizePath,
|
|
22
24
|
normalizeSlug,
|
|
23
25
|
numericPrefixSortKey,
|
|
24
26
|
pathToRoot,
|
|
25
27
|
renderMarkdown,
|
|
26
28
|
renderMarkdownHtml,
|
|
29
|
+
resolveAssetPath,
|
|
27
30
|
resolveRelative,
|
|
31
|
+
resolveRelativeAsset,
|
|
28
32
|
resolveWikiLink,
|
|
29
33
|
simplifySlug,
|
|
30
34
|
slugToHref,
|
|
35
|
+
slugifyAssetPath,
|
|
31
36
|
slugifyFilePath,
|
|
32
37
|
slugifySegment,
|
|
33
38
|
stripNumericPrefix,
|
|
34
39
|
tagToHref
|
|
35
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-2EKH4A4V.js";
|
|
36
41
|
|
|
37
42
|
// src/config.ts
|
|
38
43
|
import path from "path";
|
|
@@ -149,6 +154,7 @@ async function scanContent(projectRoot, config) {
|
|
|
149
154
|
const markdown = [];
|
|
150
155
|
const assets = [];
|
|
151
156
|
for (const relativePath of entries.sort()) {
|
|
157
|
+
const sourcePath = relativePath.replace(/\\/g, "/");
|
|
152
158
|
const absolutePath = path2.join(contentRoot, relativePath);
|
|
153
159
|
const stats = await fs.lstat(absolutePath);
|
|
154
160
|
if (!stats.isFile()) continue;
|
|
@@ -158,7 +164,7 @@ async function scanContent(projectRoot, config) {
|
|
|
158
164
|
const parsed = matter(raw);
|
|
159
165
|
markdown.push({
|
|
160
166
|
absolutePath,
|
|
161
|
-
|
|
167
|
+
sourcePath,
|
|
162
168
|
slug: slugifyFilePath(
|
|
163
169
|
asFilePath(relativePath),
|
|
164
170
|
config.contentDir,
|
|
@@ -175,12 +181,26 @@ async function scanContent(projectRoot, config) {
|
|
|
175
181
|
} else {
|
|
176
182
|
assets.push({
|
|
177
183
|
absolutePath,
|
|
178
|
-
|
|
184
|
+
sourcePath,
|
|
185
|
+
assetPath: slugifyAssetPath(sourcePath, config.ordering)
|
|
179
186
|
});
|
|
180
187
|
}
|
|
181
188
|
}
|
|
189
|
+
assertUniqueAssetPaths(assets);
|
|
182
190
|
return { markdown, assets };
|
|
183
191
|
}
|
|
192
|
+
function assertUniqueAssetPaths(assets) {
|
|
193
|
+
const sourcePathByAssetPath = /* @__PURE__ */ new Map();
|
|
194
|
+
for (const asset of assets) {
|
|
195
|
+
const existing = sourcePathByAssetPath.get(asset.assetPath);
|
|
196
|
+
if (existing && existing !== asset.sourcePath) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Asset path collision: ${existing} and ${asset.sourcePath} both map to ${asset.assetPath}`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
sourcePathByAssetPath.set(asset.assetPath, asset.sourcePath);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
184
204
|
async function isWithinRoot(absolutePath, realRoot) {
|
|
185
205
|
const realPath = await fs.realpath(absolutePath);
|
|
186
206
|
const relative = path2.relative(realRoot, realPath);
|
|
@@ -208,7 +228,7 @@ import {
|
|
|
208
228
|
makeExcerpt
|
|
209
229
|
} from "@silicajs/search";
|
|
210
230
|
var VAULT_DATABASE_FILENAME = "vault.db";
|
|
211
|
-
var VAULT_DATABASE_VERSION = "
|
|
231
|
+
var VAULT_DATABASE_VERSION = "2";
|
|
212
232
|
async function writeVaultDatabase(projectRoot, input) {
|
|
213
233
|
const silicaRoot = path3.join(projectRoot, ".silica");
|
|
214
234
|
await fs2.ensureDir(silicaRoot);
|
|
@@ -241,7 +261,7 @@ function createVaultDatabaseSchema(db) {
|
|
|
241
261
|
CREATE TABLE notes (
|
|
242
262
|
slug TEXT PRIMARY KEY,
|
|
243
263
|
file TEXT NOT NULL,
|
|
244
|
-
|
|
264
|
+
source_path TEXT NOT NULL,
|
|
245
265
|
title TEXT NOT NULL,
|
|
246
266
|
menu_label TEXT NOT NULL,
|
|
247
267
|
description TEXT,
|
|
@@ -285,6 +305,14 @@ function createVaultDatabaseSchema(db) {
|
|
|
285
305
|
PRIMARY KEY (strategy_key, alias, slug)
|
|
286
306
|
);
|
|
287
307
|
|
|
308
|
+
CREATE TABLE asset_aliases (
|
|
309
|
+
strategy_key TEXT NOT NULL,
|
|
310
|
+
alias TEXT NOT NULL,
|
|
311
|
+
asset_path TEXT NOT NULL,
|
|
312
|
+
sort_key TEXT,
|
|
313
|
+
PRIMARY KEY (strategy_key, alias, asset_path)
|
|
314
|
+
);
|
|
315
|
+
|
|
288
316
|
CREATE INDEX notes_prerender_idx ON notes(prerender, slug);
|
|
289
317
|
CREATE INDEX notes_listed_sort_idx ON notes(listed, sort_key, slug);
|
|
290
318
|
CREATE INDEX links_target_idx ON links(target_slug, kind, source_slug);
|
|
@@ -292,6 +320,8 @@ function createVaultDatabaseSchema(db) {
|
|
|
292
320
|
CREATE INDEX note_tags_tag_idx ON note_tags(tag, slug);
|
|
293
321
|
CREATE INDEX slug_aliases_lookup_idx
|
|
294
322
|
ON slug_aliases(strategy_key, alias, sort_key, slug);
|
|
323
|
+
CREATE INDEX asset_aliases_lookup_idx
|
|
324
|
+
ON asset_aliases(strategy_key, alias, sort_key, asset_path);
|
|
295
325
|
`);
|
|
296
326
|
}
|
|
297
327
|
function populateVaultDatabase(db, input) {
|
|
@@ -306,7 +336,7 @@ function populateVaultDatabase(db, input) {
|
|
|
306
336
|
INSERT INTO notes (
|
|
307
337
|
slug,
|
|
308
338
|
file,
|
|
309
|
-
|
|
339
|
+
source_path,
|
|
310
340
|
title,
|
|
311
341
|
menu_label,
|
|
312
342
|
description,
|
|
@@ -325,7 +355,7 @@ function populateVaultDatabase(db, input) {
|
|
|
325
355
|
VALUES (
|
|
326
356
|
@slug,
|
|
327
357
|
@file,
|
|
328
|
-
@
|
|
358
|
+
@sourcePath,
|
|
329
359
|
@title,
|
|
330
360
|
@menuLabel,
|
|
331
361
|
@description,
|
|
@@ -356,6 +386,15 @@ function populateVaultDatabase(db, input) {
|
|
|
356
386
|
INSERT OR IGNORE INTO slug_aliases (strategy_key, alias, slug, sort_key)
|
|
357
387
|
VALUES (?, ?, ?, ?)
|
|
358
388
|
`);
|
|
389
|
+
const insertAssetAlias = db.prepare(`
|
|
390
|
+
INSERT OR IGNORE INTO asset_aliases (
|
|
391
|
+
strategy_key,
|
|
392
|
+
alias,
|
|
393
|
+
asset_path,
|
|
394
|
+
sort_key
|
|
395
|
+
)
|
|
396
|
+
VALUES (?, ?, ?, ?)
|
|
397
|
+
`);
|
|
359
398
|
const insertAll = db.transaction(() => {
|
|
360
399
|
insertMetadata.run("version", VAULT_DATABASE_VERSION);
|
|
361
400
|
insertMetadata.run("generatedAt", input.manifest.generatedAt);
|
|
@@ -375,7 +414,7 @@ function populateVaultDatabase(db, input) {
|
|
|
375
414
|
insertNote.run({
|
|
376
415
|
slug: entry.slug,
|
|
377
416
|
file: entry.file,
|
|
378
|
-
|
|
417
|
+
sourcePath: entry.sourcePath,
|
|
379
418
|
title: entry.title,
|
|
380
419
|
menuLabel: entry.menuLabel,
|
|
381
420
|
description: entry.description,
|
|
@@ -423,6 +462,14 @@ function populateVaultDatabase(db, input) {
|
|
|
423
462
|
);
|
|
424
463
|
}
|
|
425
464
|
}
|
|
465
|
+
for (const asset of input.assets) {
|
|
466
|
+
for (const [strategy, alias] of makeAssetAliases(
|
|
467
|
+
asset.sourcePath,
|
|
468
|
+
input.config.ordering
|
|
469
|
+
)) {
|
|
470
|
+
insertAssetAlias.run(strategy, alias, asset.assetPath, asset.assetPath);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
426
473
|
});
|
|
427
474
|
insertAll();
|
|
428
475
|
buildSearchTables(db, input.searchRecords);
|
|
@@ -447,6 +494,20 @@ function makeSlugAliases(slug) {
|
|
|
447
494
|
alias
|
|
448
495
|
]);
|
|
449
496
|
}
|
|
497
|
+
function makeAssetAliases(sourcePath, ordering) {
|
|
498
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
499
|
+
const normalized = normalizeAssetReference(sourcePath, ordering);
|
|
500
|
+
const basename = normalizeAssetReference(
|
|
501
|
+
path3.posix.basename(sourcePath),
|
|
502
|
+
ordering
|
|
503
|
+
);
|
|
504
|
+
if (normalized) aliases.set(`absolute:${normalized}`, normalized);
|
|
505
|
+
if (basename) aliases.set(`shortest:${basename}`, basename);
|
|
506
|
+
return [...aliases.entries()].map(([key, alias]) => [
|
|
507
|
+
key.split(":")[0] ?? "shortest",
|
|
508
|
+
alias
|
|
509
|
+
]);
|
|
510
|
+
}
|
|
450
511
|
async function removeDatabaseFiles(databasePath) {
|
|
451
512
|
await fs2.remove(databasePath);
|
|
452
513
|
await removeDatabaseSidecars(databasePath);
|
|
@@ -470,18 +531,23 @@ async function precompute(options = {}) {
|
|
|
470
531
|
const config = options.config ?? await loadConfig(projectRoot);
|
|
471
532
|
const scan = await scanContent(projectRoot, config);
|
|
472
533
|
const markdownFiles = filterPublished(scan.markdown, config);
|
|
534
|
+
const assetEntries = scan.assets.map(({ sourcePath, assetPath }) => ({
|
|
535
|
+
sourcePath,
|
|
536
|
+
assetPath
|
|
537
|
+
}));
|
|
473
538
|
const allSlugs = markdownFiles.map((file) => file.slug);
|
|
474
539
|
const wikilinkIndex = createWikiLinkResolutionIndex(
|
|
475
540
|
allSlugs,
|
|
476
541
|
config.ordering
|
|
477
542
|
);
|
|
543
|
+
const assetIndex = createAssetResolutionIndex(assetEntries, config.ordering);
|
|
478
544
|
const entries = [];
|
|
479
545
|
const graphLinks = {};
|
|
480
546
|
const brokenLinks = [];
|
|
481
547
|
const searchRecords = [];
|
|
482
548
|
const runtimeContentRoot = path4.join(projectRoot, ".silica/content");
|
|
483
549
|
const relativeGitPaths = markdownFiles.map(
|
|
484
|
-
(file) => normalizeGitPath(path4.join(config.contentDir, file.
|
|
550
|
+
(file) => normalizeGitPath(path4.join(config.contentDir, file.sourcePath))
|
|
485
551
|
);
|
|
486
552
|
const gitDatesByPath = await getGitDatesForFiles(
|
|
487
553
|
projectRoot,
|
|
@@ -492,16 +558,18 @@ async function precompute(options = {}) {
|
|
|
492
558
|
await writeRuntimeMarkdown(runtimeContentRoot, markdownFiles);
|
|
493
559
|
const analyses = await analyzeMarkdownFiles(markdownFiles, config, allSlugs, {
|
|
494
560
|
concurrency: options.analysisConcurrency,
|
|
495
|
-
wikilinkIndex
|
|
561
|
+
wikilinkIndex,
|
|
562
|
+
assetIndex,
|
|
563
|
+
assetEntries
|
|
496
564
|
});
|
|
497
565
|
for (const [index, file] of markdownFiles.entries()) {
|
|
498
566
|
const gitDates = gitDatesByPath.get(
|
|
499
|
-
normalizeGitPath(path4.join(config.contentDir, file.
|
|
567
|
+
normalizeGitPath(path4.join(config.contentDir, file.sourcePath))
|
|
500
568
|
) ?? {};
|
|
501
569
|
const analysis = analyses[index];
|
|
502
|
-
const title = analysis.title ?? titleFromFilePath(file.
|
|
570
|
+
const title = analysis.title ?? titleFromFilePath(file.sourcePath, config.ordering);
|
|
503
571
|
const menuLabel = getMenuLabel(file.frontmatter, title);
|
|
504
|
-
const sortKey = config.ordering.numericPrefixes && hasNumericPrefixInPath(file.
|
|
572
|
+
const sortKey = config.ordering.numericPrefixes && hasNumericPrefixInPath(file.sourcePath) ? numericPrefixSortKey(file.sourcePath) : void 0;
|
|
505
573
|
const entry = {
|
|
506
574
|
slug: file.slug,
|
|
507
575
|
title,
|
|
@@ -509,8 +577,8 @@ async function precompute(options = {}) {
|
|
|
509
577
|
description: analysis.description,
|
|
510
578
|
generatedDescription: analysis.generatedDescription,
|
|
511
579
|
tags: analysis.tags,
|
|
512
|
-
file: normalizeGitPath(path4.join(".silica/content", file.
|
|
513
|
-
|
|
580
|
+
file: normalizeGitPath(path4.join(".silica/content", file.sourcePath)),
|
|
581
|
+
sourcePath: file.sourcePath,
|
|
514
582
|
sortKey,
|
|
515
583
|
created: stringifyDate(
|
|
516
584
|
getDate(file.frontmatter.created) ?? getDate(file.frontmatter.date) ?? gitDates.created ?? file.stats.birthtime
|
|
@@ -549,7 +617,8 @@ async function precompute(options = {}) {
|
|
|
549
617
|
renderHashes,
|
|
550
618
|
cacheState,
|
|
551
619
|
prerender,
|
|
552
|
-
searchRecords
|
|
620
|
+
searchRecords,
|
|
621
|
+
assets: assetEntries
|
|
553
622
|
});
|
|
554
623
|
await writeSitemapAndRobots(projectRoot, config, manifest);
|
|
555
624
|
if (config.wikilinks.strict && brokenLinks.length > 0) {
|
|
@@ -569,17 +638,30 @@ ${message}`);
|
|
|
569
638
|
async function analyzeMarkdownFiles(files, config, allSlugs, options) {
|
|
570
639
|
const workerCount = getAnalysisWorkerCount(files.length, options.concurrency);
|
|
571
640
|
if (workerCount <= 1) {
|
|
572
|
-
return analyzeMarkdownFilesSerial(
|
|
641
|
+
return analyzeMarkdownFilesSerial(
|
|
642
|
+
files,
|
|
643
|
+
config,
|
|
644
|
+
options.wikilinkIndex,
|
|
645
|
+
options.assetIndex
|
|
646
|
+
);
|
|
573
647
|
}
|
|
574
|
-
return analyzeMarkdownFilesParallel(
|
|
648
|
+
return analyzeMarkdownFilesParallel(
|
|
649
|
+
files,
|
|
650
|
+
config,
|
|
651
|
+
allSlugs,
|
|
652
|
+
options.assetEntries,
|
|
653
|
+
workerCount
|
|
654
|
+
);
|
|
575
655
|
}
|
|
576
|
-
async function analyzeMarkdownFilesSerial(files, config, wikilinkIndex) {
|
|
656
|
+
async function analyzeMarkdownFilesSerial(files, config, wikilinkIndex, assetIndex) {
|
|
577
657
|
const analyses = [];
|
|
578
658
|
for (const file of files) {
|
|
579
659
|
analyses.push(
|
|
580
660
|
await analyzeMarkdown(file.raw, {
|
|
581
661
|
slug: asFullSlug(file.slug),
|
|
662
|
+
sourcePath: file.sourcePath,
|
|
582
663
|
wikilinkIndex,
|
|
664
|
+
assetIndex,
|
|
583
665
|
assetBaseUrl: "/silica",
|
|
584
666
|
wikilinkStrategy: config.wikilinks.strategy,
|
|
585
667
|
tags: config.tags,
|
|
@@ -589,7 +671,7 @@ async function analyzeMarkdownFilesSerial(files, config, wikilinkIndex) {
|
|
|
589
671
|
}
|
|
590
672
|
return analyses;
|
|
591
673
|
}
|
|
592
|
-
function analyzeMarkdownFilesParallel(files, config, allSlugs, workerCount) {
|
|
674
|
+
function analyzeMarkdownFilesParallel(files, config, allSlugs, assetEntries, workerCount) {
|
|
593
675
|
return new Promise((resolve, reject) => {
|
|
594
676
|
const workerUrl = new URL("./precompute-worker.js", import.meta.url);
|
|
595
677
|
const workers = [];
|
|
@@ -619,6 +701,7 @@ function analyzeMarkdownFilesParallel(files, config, allSlugs, workerCount) {
|
|
|
619
701
|
const batch = files.slice(start, start + ANALYSIS_BATCH_SIZE).map((file, offset) => ({
|
|
620
702
|
index: start + offset,
|
|
621
703
|
slug: file.slug,
|
|
704
|
+
sourcePath: file.sourcePath,
|
|
622
705
|
raw: file.raw
|
|
623
706
|
}));
|
|
624
707
|
nextIndex += batch.length;
|
|
@@ -631,6 +714,7 @@ function analyzeMarkdownFilesParallel(files, config, allSlugs, workerCount) {
|
|
|
631
714
|
const worker = new Worker(workerUrl, {
|
|
632
715
|
workerData: {
|
|
633
716
|
allSlugs,
|
|
717
|
+
assetEntries,
|
|
634
718
|
wikilinkStrategy: config.wikilinks.strategy,
|
|
635
719
|
tags: config.tags,
|
|
636
720
|
ordering: config.ordering
|
|
@@ -687,7 +771,7 @@ function getRequestedAnalysisConcurrency(requestedConcurrency, available) {
|
|
|
687
771
|
async function writeRuntimeMarkdown(runtimeContentRoot, files) {
|
|
688
772
|
await fs3.emptyDir(runtimeContentRoot);
|
|
689
773
|
for (const file of files) {
|
|
690
|
-
const destination = path4.join(runtimeContentRoot, file.
|
|
774
|
+
const destination = path4.join(runtimeContentRoot, file.sourcePath);
|
|
691
775
|
await fs3.ensureDir(path4.dirname(destination));
|
|
692
776
|
await fs3.writeFile(destination, file.raw);
|
|
693
777
|
}
|
|
@@ -764,7 +848,7 @@ function makeRenderHashes(manifest, graph) {
|
|
|
764
848
|
description: entry.description,
|
|
765
849
|
generatedDescription: entry.generatedDescription,
|
|
766
850
|
tags: entry.tags,
|
|
767
|
-
|
|
851
|
+
sourcePath: entry.sourcePath,
|
|
768
852
|
sortKey: entry.sortKey,
|
|
769
853
|
created: entry.created,
|
|
770
854
|
modified: entry.modified,
|
|
@@ -974,11 +1058,11 @@ async function copyAssets(projectRoot, config, assets) {
|
|
|
974
1058
|
await fs3.emptyDir(destinationRoot);
|
|
975
1059
|
for (const asset of assets) {
|
|
976
1060
|
await fs3.ensureDir(
|
|
977
|
-
path4.dirname(path4.join(destinationRoot, asset.
|
|
1061
|
+
path4.dirname(path4.join(destinationRoot, asset.assetPath))
|
|
978
1062
|
);
|
|
979
1063
|
await fs3.copyFile(
|
|
980
1064
|
asset.absolutePath,
|
|
981
|
-
path4.join(destinationRoot, asset.
|
|
1065
|
+
path4.join(destinationRoot, asset.assetPath)
|
|
982
1066
|
);
|
|
983
1067
|
}
|
|
984
1068
|
await fs3.ensureDir(path4.join(projectRoot, ".silica/next/public"));
|
|
@@ -1039,6 +1123,7 @@ export {
|
|
|
1039
1123
|
asFullSlug,
|
|
1040
1124
|
asRelativeURL,
|
|
1041
1125
|
asSimpleSlug,
|
|
1126
|
+
createAssetResolutionIndex,
|
|
1042
1127
|
createWikiLinkResolutionIndex,
|
|
1043
1128
|
defineConfig,
|
|
1044
1129
|
formatPropertyLabel,
|
|
@@ -1054,19 +1139,23 @@ export {
|
|
|
1054
1139
|
isMarkdownFile,
|
|
1055
1140
|
joinSegments,
|
|
1056
1141
|
loadConfig,
|
|
1142
|
+
normalizeAssetReference,
|
|
1057
1143
|
normalizePath,
|
|
1058
1144
|
normalizeSlug,
|
|
1059
1145
|
pathToRoot,
|
|
1060
1146
|
precompute,
|
|
1061
1147
|
renderMarkdown,
|
|
1062
1148
|
renderMarkdownHtml,
|
|
1149
|
+
resolveAssetPath,
|
|
1063
1150
|
resolveConfig,
|
|
1064
1151
|
resolvePublicAssetPath,
|
|
1065
1152
|
resolveRelative,
|
|
1153
|
+
resolveRelativeAsset,
|
|
1066
1154
|
resolveWikiLink,
|
|
1067
1155
|
scanContent,
|
|
1068
1156
|
simplifySlug,
|
|
1069
1157
|
slugToHref,
|
|
1158
|
+
slugifyAssetPath,
|
|
1070
1159
|
slugifyFilePath,
|
|
1071
1160
|
slugifySegment,
|
|
1072
1161
|
tagToHref
|