mnfst-render 0.5.46 → 0.5.47
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/manifest.render.mjs +73 -16
- package/package.json +1 -1
package/manifest.render.mjs
CHANGED
|
@@ -3114,6 +3114,75 @@ ${urlEntries.join('\n')}
|
|
|
3114
3114
|
writeLlmsFiles(outputDir, pathList, base, ctx);
|
|
3115
3115
|
}
|
|
3116
3116
|
|
|
3117
|
+
/**
|
|
3118
|
+
* Group llms entries into sections by first URL segment ("Blog" for /blog/*),
|
|
3119
|
+
* root page as "Overview", in first-encounter order. Wherever a path holds two
|
|
3120
|
+
* or more sub-areas that each have their own page and children, each sub-area
|
|
3121
|
+
* becomes its own section labelled by its page title, recursively: /docs/ai/*
|
|
3122
|
+
* and /docs/framework/* split into "AI Plugins" and "Framework", and groups
|
|
3123
|
+
* inside them into "Framework / Core Plugins" and so on. A lone sub-area
|
|
3124
|
+
* (/fr/docs under /fr) is walked through when a split lies below it, and the
|
|
3125
|
+
* first segment then leads the label ("Fr / AI Plugins").
|
|
3126
|
+
*/
|
|
3127
|
+
function groupLlmsSections(entries, siteName = '') {
|
|
3128
|
+
const titleCase = (s) => s.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
3129
|
+
const paths = new Set(entries.map((e) => e.pathSeg));
|
|
3130
|
+
const parents = new Set();
|
|
3131
|
+
for (const p of paths) {
|
|
3132
|
+
const segs = p.split('/');
|
|
3133
|
+
for (let i = 1; i < segs.length; i++) parents.add(segs.slice(0, i).join('/'));
|
|
3134
|
+
}
|
|
3135
|
+
const childAreas = new Map();
|
|
3136
|
+
for (const p of paths) {
|
|
3137
|
+
if (!parents.has(p) || !p.includes('/')) continue;
|
|
3138
|
+
const parent = p.slice(0, p.lastIndexOf('/'));
|
|
3139
|
+
if (!childAreas.has(parent)) childAreas.set(parent, new Set());
|
|
3140
|
+
childAreas.get(parent).add(p);
|
|
3141
|
+
}
|
|
3142
|
+
const splits = (prefix) => (childAreas.get(prefix)?.size || 0) >= 2;
|
|
3143
|
+
const below = new Map();
|
|
3144
|
+
const splitsBelow = (prefix) => {
|
|
3145
|
+
if (!below.has(prefix)) {
|
|
3146
|
+
const kids = childAreas.get(prefix);
|
|
3147
|
+
below.set(prefix, splits(prefix) || (kids?.size === 1 && splitsBelow(kids.values().next().value)));
|
|
3148
|
+
}
|
|
3149
|
+
return below.get(prefix);
|
|
3150
|
+
};
|
|
3151
|
+
const suffix = siteName ? new RegExp(`\\s+[—–|-]\\s+${siteName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`) : null;
|
|
3152
|
+
const titles = new Map(entries.map((e) => [e.pathSeg, e.title || '']));
|
|
3153
|
+
const labelCache = new Map();
|
|
3154
|
+
const titleOf = (area) => {
|
|
3155
|
+
if (labelCache.has(area)) return labelCache.get(area);
|
|
3156
|
+
let t = titles.get(area) || '';
|
|
3157
|
+
if (suffix) t = t.replace(suffix, '');
|
|
3158
|
+
t = t.trim();
|
|
3159
|
+
if (!t || t === siteName || t === area) t = titleCase(area.split('/').pop());
|
|
3160
|
+
labelCache.set(area, t);
|
|
3161
|
+
return t;
|
|
3162
|
+
};
|
|
3163
|
+
const sections = new Map();
|
|
3164
|
+
for (const entry of entries) {
|
|
3165
|
+
const segs = entry.pathSeg.split('/');
|
|
3166
|
+
const first = segs[0] || '';
|
|
3167
|
+
let key = first || 'Overview';
|
|
3168
|
+
const parts = first && !splits(first) && splitsBelow(first) ? [titleCase(first)] : [];
|
|
3169
|
+
let prefix = first;
|
|
3170
|
+
for (let i = 1; first && i < segs.length && splitsBelow(prefix); i++) {
|
|
3171
|
+
const child = segs.slice(0, i + 1).join('/');
|
|
3172
|
+
if (!childAreas.get(prefix).has(child)) break;
|
|
3173
|
+
if (splits(prefix)) {
|
|
3174
|
+
key = child;
|
|
3175
|
+
parts.push(titleOf(child));
|
|
3176
|
+
}
|
|
3177
|
+
prefix = child;
|
|
3178
|
+
}
|
|
3179
|
+
const label = parts.length > 1 || (parts.length && splits(first)) ? parts.join(' / ') : (first ? titleCase(first) : 'Overview');
|
|
3180
|
+
if (!sections.has(key)) sections.set(key, { label, entries: [] });
|
|
3181
|
+
sections.get(key).entries.push(entry);
|
|
3182
|
+
}
|
|
3183
|
+
return sections;
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3117
3186
|
/**
|
|
3118
3187
|
* Write llms.txt (curated index) and llms-full.txt (concatenated full content)
|
|
3119
3188
|
* per the llmstxt.org convention. Read each prerendered HTML file in pathList
|
|
@@ -3121,9 +3190,7 @@ ${urlEntries.join('\n')}
|
|
|
3121
3190
|
* injectMetaInDom + smart defaults, so the output reflects the same layered
|
|
3122
3191
|
* precedence (data-head → prerender.meta → smart defaults) without re-deriving.
|
|
3123
3192
|
*
|
|
3124
|
-
*
|
|
3125
|
-
* for /docs/getting-started/*, etc.) so the index is browseable. The root /
|
|
3126
|
-
* page is treated as the site overview.
|
|
3193
|
+
* Sections come from groupLlmsSections.
|
|
3127
3194
|
*/
|
|
3128
3195
|
function writeLlmsFiles(outputDir, pathList, liveBase, ctx = {}) {
|
|
3129
3196
|
const siteName = ctx.siteName || 'Site';
|
|
@@ -3144,18 +3211,7 @@ function writeLlmsFiles(outputDir, pathList, liveBase, ctx = {}) {
|
|
|
3144
3211
|
});
|
|
3145
3212
|
}
|
|
3146
3213
|
|
|
3147
|
-
|
|
3148
|
-
// "Overview". Sections are presented in first-encounter order to preserve
|
|
3149
|
-
// whatever order the project's manifest.json or yaml index dictated.
|
|
3150
|
-
const sections = new Map();
|
|
3151
|
-
const titleCase = (s) => s.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
3152
|
-
for (const entry of entries) {
|
|
3153
|
-
const first = entry.pathSeg.split('/')[0] || '';
|
|
3154
|
-
const sectionKey = first || 'Overview';
|
|
3155
|
-
const sectionLabel = first ? titleCase(first) : 'Overview';
|
|
3156
|
-
if (!sections.has(sectionKey)) sections.set(sectionKey, { label: sectionLabel, entries: [] });
|
|
3157
|
-
sections.get(sectionKey).entries.push(entry);
|
|
3158
|
-
}
|
|
3214
|
+
const sections = groupLlmsSections(entries, siteName);
|
|
3159
3215
|
|
|
3160
3216
|
// --- llms.txt: short curated index ---
|
|
3161
3217
|
let llms = `# ${siteName}\n`;
|
|
@@ -4508,7 +4564,7 @@ async function runPrerender(config) {
|
|
|
4508
4564
|
// observer state at runtime and therefore need the live Alpine scope.
|
|
4509
4565
|
const INTERACTIVE_DIRECTIVES = new Set([
|
|
4510
4566
|
'x-color', 'x-dropdown', 'x-tooltip', 'x-tab', 'x-tabpanel',
|
|
4511
|
-
'x-toast', 'x-carousel', 'x-
|
|
4567
|
+
'x-toast', 'x-carousel', 'x-anchors', 'x-model',
|
|
4512
4568
|
'x-files', 'x-data-files',
|
|
4513
4569
|
]);
|
|
4514
4570
|
// Runtime-only Alpine magics whose values change after the prerender
|
|
@@ -5486,6 +5542,7 @@ if (_isDirectEntry) {
|
|
|
5486
5542
|
export {
|
|
5487
5543
|
main,
|
|
5488
5544
|
discoverRoutes,
|
|
5545
|
+
groupLlmsSections,
|
|
5489
5546
|
acquireOutputLock,
|
|
5490
5547
|
outputLockPath,
|
|
5491
5548
|
markPrerenderedManifestComponents,
|