@rathnasgala2/template 2.1.0 → 3.0.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 +95 -59
- package/contracts/render-policy.jcs +1 -1
- package/contracts/theme-styling-contract.jcs +1 -1
- package/package.json +2 -2
- package/src/core/index.js +209 -60
- package/src/core/internal/appearance/base-layer.js +711 -137
- package/src/core/internal/appearance/bootstrap-script.js +570 -83
- package/src/core/internal/appearance/contract.js +6 -5
- package/src/core/internal/appearance/controller-markup.js +46 -55
- package/src/core/internal/appearance/minify-script.js +69 -0
- package/src/core/internal/appearance/styling-contract.js +199 -17
- package/src/core/internal/chrome.js +199 -0
- package/src/core/internal/components.js +379 -0
- package/src/core/internal/eleventy-render.js +13 -4
- package/src/core/internal/feeds.js +79 -8
- package/src/core/internal/icons.js +52 -0
- package/src/core/internal/llms.js +252 -0
- package/src/core/internal/media/pipeline.js +32 -17
- package/src/core/internal/messages.js +104 -0
- package/src/core/internal/page-kinds.js +922 -293
- package/src/core/internal/render-policy-content.js +2 -2
- package/src/core/internal/robots.js +78 -0
- package/src/core/internal/route-labels.js +31 -0
- package/src/core/internal/route.js +42 -0
- package/src/core/internal/search-index.js +5 -2
- package/src/core/internal/seo.js +57 -2
- package/src/core/internal/sitemap.js +5 -4
- package/src/core/internal/skeleton.js +73 -132
- package/src/core/internal/structured-data.js +247 -0
- package/src/core/internal/theme-assets.js +21 -2
package/src/core/index.js
CHANGED
|
@@ -100,14 +100,22 @@ import {
|
|
|
100
100
|
} from './internal/page-kinds.js';
|
|
101
101
|
import { assertProvenance } from './internal/provenance.js';
|
|
102
102
|
import {
|
|
103
|
+
deriveAuthorSlugs,
|
|
104
|
+
routeSegmentForLabel,
|
|
105
|
+
} from './internal/route-labels.js';
|
|
106
|
+
import {
|
|
107
|
+
derivePublicBasePath,
|
|
103
108
|
errorDocumentPath,
|
|
109
|
+
joinPublicRoute,
|
|
104
110
|
joinBasePathAndRoute,
|
|
105
111
|
projectFixedAssetPath,
|
|
106
112
|
projectRouteToFilePath,
|
|
107
113
|
renderRedirectDocument,
|
|
108
114
|
} from './internal/route.js';
|
|
109
115
|
import { buildSearchIndex } from './internal/search-index.js';
|
|
110
|
-
import {
|
|
116
|
+
import { resolveSocialImage, twitterCardType } from './internal/seo.js';
|
|
117
|
+
import { buildLlmsDocuments } from './internal/llms.js';
|
|
118
|
+
import { buildRobotsTxt, readAiCrawlerPolicy } from './internal/robots.js';
|
|
111
119
|
import { buildSitemap } from './internal/sitemap.js';
|
|
112
120
|
import {
|
|
113
121
|
defaultThemeStylesheetLinksHtml,
|
|
@@ -115,12 +123,12 @@ import {
|
|
|
115
123
|
} from './internal/theme-assets.js';
|
|
116
124
|
import { resolveTextDirection } from './internal/text-direction.js';
|
|
117
125
|
import {
|
|
118
|
-
|
|
119
|
-
renderFooterNavigation,
|
|
120
|
-
renderHeader,
|
|
126
|
+
escapeHtml,
|
|
121
127
|
renderPageBody,
|
|
122
128
|
renderPrimaryNavigation,
|
|
123
129
|
} from './internal/skeleton.js';
|
|
130
|
+
import { renderFooter, renderHeader } from './internal/chrome.js';
|
|
131
|
+
import { createComponents, createMediaImage } from './internal/components.js';
|
|
124
132
|
import {
|
|
125
133
|
collectIncludedSources,
|
|
126
134
|
compareUtf8Bytes,
|
|
@@ -133,6 +141,13 @@ const SITEMAP_ROUTE = '/sitemap.xml';
|
|
|
133
141
|
/** @type {string} the un-joined route the static search index is published
|
|
134
142
|
* at. */
|
|
135
143
|
const SEARCH_INDEX_ROUTE = '/search-index.json';
|
|
144
|
+
/** @type {string} the output-root path of `robots.txt` (never `basePath`-
|
|
145
|
+
* joined: only a host-root robots file is honoured by crawlers). */
|
|
146
|
+
const ROBOTS_PATH = 'robots.txt';
|
|
147
|
+
/** @type {string} the un-joined route of the llmstxt.org index. */
|
|
148
|
+
const LLMS_ROUTE = '/llms.txt';
|
|
149
|
+
/** @type {string} the un-joined route of the full-text companion. */
|
|
150
|
+
const LLMS_FULL_ROUTE = '/llms-full.txt';
|
|
136
151
|
|
|
137
152
|
/** @type {string} */
|
|
138
153
|
const BUILD_INPUT_SCHEMA_ID = 'urn:gala:schema:build-input:2.0.0';
|
|
@@ -322,63 +337,144 @@ export async function renderPublication(buildInput, options) {
|
|
|
322
337
|
// that navigation/footer text does not flip language from page to page
|
|
323
338
|
// (see `internal/messages.js`).
|
|
324
339
|
const siteMessages = getMessages(validatedInput.publication.defaultLanguage);
|
|
325
|
-
|
|
340
|
+
// Every emitted URL carries the `baseUrl` path (for example `/g9/` on a
|
|
341
|
+
// GitHub project site); output file paths keep using `basePath` alone.
|
|
342
|
+
const publicBasePath = derivePublicBasePath(
|
|
343
|
+
validatedInput.baseUrl,
|
|
344
|
+
validatedInput.basePath,
|
|
345
|
+
);
|
|
346
|
+
const urlPrefix = derivePublicBasePath(validatedInput.baseUrl, '/');
|
|
347
|
+
const homeRoute = joinPublicRoute(publicBasePath, '/');
|
|
326
348
|
|
|
327
349
|
const appearanceControlHtml = renderAppearanceControl({
|
|
328
350
|
messages: siteMessages,
|
|
329
351
|
});
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
352
|
+
|
|
353
|
+
// Run before page assembly, not after: resolving each page's own images
|
|
354
|
+
// (`og:image`, hero, avatar, brand mark) needs the media pipeline's own
|
|
355
|
+
// finished `assets` list (only it knows which derivative file extension a
|
|
356
|
+
// given source image's `sourceDigest` produced — see `internal/seo.js`).
|
|
357
|
+
// This only moves the in-memory computation earlier; `mediaFiles`' actual
|
|
358
|
+
// bytes are still written to `outputDirectory` only after the route
|
|
359
|
+
// listing below, so `outputDirectory/assets/media/` still can never be
|
|
360
|
+
// mistaken for an Eleventy-rendered HTML route.
|
|
361
|
+
const {
|
|
362
|
+
assets: mediaAssets,
|
|
363
|
+
files: mediaFiles,
|
|
364
|
+
dimensions: mediaDimensions,
|
|
365
|
+
} = await processMedia(validatedInput, {
|
|
366
|
+
sourceDirectory: path.resolve(options.sourceDirectory),
|
|
335
367
|
});
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
368
|
+
const mediaImage = createMediaImage({
|
|
369
|
+
mediaAssets,
|
|
370
|
+
publicBasePath,
|
|
371
|
+
mediaDimensions,
|
|
339
372
|
});
|
|
340
|
-
const
|
|
373
|
+
const brandMark = mediaImage(validatedInput.appearance.brandMark);
|
|
374
|
+
const searchIndexHref = joinBasePathAndRoute(
|
|
375
|
+
publicBasePath,
|
|
376
|
+
SEARCH_INDEX_ROUTE,
|
|
377
|
+
);
|
|
378
|
+
const rssHref = joinBasePathAndRoute(publicBasePath, RSS_FEED_ROUTE);
|
|
379
|
+
const publication = validatedInput.publication;
|
|
380
|
+
const footerCard = publication.footerCard;
|
|
341
381
|
// Already verified render-policy-conformant HTML by
|
|
342
382
|
// assertRenderPolicyCompliance's assertPolicyConformantHtml call above —
|
|
343
383
|
// inserted as-is, never re-parsed as Markdown.
|
|
344
384
|
const footerProfileHtml = footerCard?.enabled ? footerCard.body.body : '';
|
|
385
|
+
const authorsById = new Map(
|
|
386
|
+
validatedInput.authors.map((author) => [author.id, author]),
|
|
387
|
+
);
|
|
388
|
+
const footerAuthor =
|
|
389
|
+
authorsById.get(publication.contactAuthorId ?? '') ??
|
|
390
|
+
validatedInput.authors[0];
|
|
391
|
+
const authorSlugs = deriveAuthorSlugs(validatedInput.authors);
|
|
392
|
+
const authorHref = (
|
|
393
|
+
/** @type {import('../../types/index.d.ts').AuthorNormalized} */ author,
|
|
394
|
+
) =>
|
|
395
|
+
joinPublicRoute(
|
|
396
|
+
publicBasePath,
|
|
397
|
+
`/authors/${authorSlugs.get(author.id) ?? author.id}`,
|
|
398
|
+
);
|
|
399
|
+
const footerComponents = createComponents({
|
|
400
|
+
messages: siteMessages,
|
|
401
|
+
site: (route) => joinPublicRoute(publicBasePath, route),
|
|
402
|
+
mediaImage,
|
|
403
|
+
authorHref,
|
|
404
|
+
authorsById,
|
|
405
|
+
recordHref: (record) =>
|
|
406
|
+
joinPublicRoute(publicBasePath, contentRoute(record.frontmatter)),
|
|
407
|
+
tagHref: (tag) =>
|
|
408
|
+
joinPublicRoute(publicBasePath, `/tags/${routeSegmentForLabel(tag)}`),
|
|
409
|
+
});
|
|
410
|
+
const footerAuthorHtml = footerAuthor
|
|
411
|
+
? `<p class="g-label">${footerComponents.text('writtenByLabel')}</p>` +
|
|
412
|
+
`<div class="g-byline">${footerComponents.avatar(footerAuthor)}<div class="g-byline-text">` +
|
|
413
|
+
`<a href="${escapeHtml(authorHref(footerAuthor))}">${escapeHtml(footerAuthor.displayName)}</a>` +
|
|
414
|
+
`</div></div>`
|
|
415
|
+
: '';
|
|
416
|
+
const latestYear = validatedInput.content
|
|
417
|
+
.map((record) => record.frontmatter.publishedAt.slice(0, 4))
|
|
418
|
+
.sort()
|
|
419
|
+
.at(-1);
|
|
345
420
|
const footerHtml = renderFooter({
|
|
346
|
-
|
|
347
|
-
|
|
421
|
+
homeRoute,
|
|
422
|
+
publicationName: publication.title,
|
|
423
|
+
description: publication.description,
|
|
424
|
+
brandMark,
|
|
425
|
+
socialLinks: publication.socialLinks,
|
|
426
|
+
rssHref,
|
|
427
|
+
primaryItems: validatedInput.navigation.items,
|
|
428
|
+
footerItems: validatedInput.navigation.footerItems,
|
|
429
|
+
urlPrefix,
|
|
430
|
+
authorHtml: footerAuthorHtml,
|
|
348
431
|
footerProfileHtml,
|
|
349
|
-
copyrightText:
|
|
432
|
+
copyrightText: `${siteMessages.footerCopyrightPrefix} ${latestYear ? `${latestYear} ` : ''}${publication.title}`,
|
|
350
433
|
messages: siteMessages,
|
|
351
434
|
});
|
|
352
435
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
436
|
+
/**
|
|
437
|
+
* One page's `<header>`, with the primary navigation marking that page's
|
|
438
|
+
* own route current.
|
|
439
|
+
*
|
|
440
|
+
* @param {string | undefined} currentRoute the page's joined route
|
|
441
|
+
* @returns {string}
|
|
442
|
+
*/
|
|
443
|
+
const headerFor = (currentRoute) =>
|
|
444
|
+
renderHeader({
|
|
445
|
+
homeRoute,
|
|
446
|
+
publicationName: publication.title,
|
|
447
|
+
tagline: publication.description,
|
|
448
|
+
brandMark,
|
|
449
|
+
navHtml: renderPrimaryNavigation({
|
|
450
|
+
items: validatedInput.navigation.items,
|
|
451
|
+
currentRoute,
|
|
452
|
+
messages: siteMessages,
|
|
453
|
+
urlPrefix,
|
|
454
|
+
}),
|
|
455
|
+
navItems: validatedInput.navigation.items,
|
|
456
|
+
currentRoute,
|
|
457
|
+
urlPrefix,
|
|
458
|
+
searchIndexHref,
|
|
459
|
+
appearanceControlHtml,
|
|
460
|
+
messages: siteMessages,
|
|
461
|
+
});
|
|
365
462
|
|
|
366
463
|
// The site-wide feeds, resolved once so every page's feed-discovery
|
|
367
464
|
// `<link>` tags and the feed documents themselves agree on the exact same
|
|
368
465
|
// self URLs.
|
|
369
466
|
const feeds = buildFeeds(validatedInput);
|
|
370
467
|
const siteName = validatedInput.publication.title;
|
|
371
|
-
const appearanceScriptHrefValue =
|
|
372
|
-
|
|
373
|
-
);
|
|
468
|
+
const appearanceScriptHrefValue =
|
|
469
|
+
appearanceBootstrapScriptHref(publicBasePath);
|
|
374
470
|
// TPL-H3/TPL-M7: the template-owned gala-base stylesheet's own basePath-
|
|
375
471
|
// joined href, computed the same way as the appearance script href above
|
|
376
472
|
// so it can never drift from the physical file/manifest path written
|
|
377
473
|
// below.
|
|
378
|
-
const baseStylesheetHrefValue =
|
|
379
|
-
|
|
474
|
+
const baseStylesheetHrefValue = joinBasePathAndRoute(
|
|
475
|
+
publicBasePath,
|
|
380
476
|
`/${GALA_BASE_STYLESHEET_PATH}`,
|
|
381
|
-
)
|
|
477
|
+
);
|
|
382
478
|
|
|
383
479
|
// The selected theme package's copied stylesheets/passive assets and the
|
|
384
480
|
// ordered `<link>` markup every generated page's `<head>` inserts.
|
|
@@ -389,58 +485,69 @@ export async function renderPublication(buildInput, options) {
|
|
|
389
485
|
? await loadThemeAssets({
|
|
390
486
|
themeDirectory: path.resolve(options.themeDirectory),
|
|
391
487
|
basePath: validatedInput.basePath,
|
|
488
|
+
publicBasePath,
|
|
392
489
|
})
|
|
393
490
|
: undefined;
|
|
394
491
|
const themeStylesheetLinksHtml = themeAssetsResult
|
|
395
492
|
? themeAssetsResult.linkTagsHtml
|
|
396
|
-
: defaultThemeStylesheetLinksHtml(
|
|
493
|
+
: defaultThemeStylesheetLinksHtml(publicBasePath);
|
|
397
494
|
|
|
398
495
|
/** @type {{virtualPath: string, content: string, permalink: string, layout?: string, data?: Record<string, unknown>}[]} */
|
|
399
496
|
const contentPages = [];
|
|
400
|
-
/** @type {{joinedSource: string, joinedTarget: string, filePath: string}[]} */
|
|
497
|
+
/** @type {{joinedSource: string, joinedTarget: string, publicTarget: string, filePath: string}[]} */
|
|
401
498
|
const redirectProjections = [];
|
|
402
499
|
|
|
403
|
-
const generatedPages = buildGeneratedPages(validatedInput
|
|
500
|
+
const generatedPages = buildGeneratedPages(validatedInput, {
|
|
501
|
+
mediaAssets,
|
|
502
|
+
mediaDimensions,
|
|
503
|
+
});
|
|
404
504
|
generatedPages.forEach((page, index) => {
|
|
405
505
|
const joinedRoute = joinBasePathAndRoute(
|
|
406
506
|
validatedInput.basePath,
|
|
407
507
|
page.route,
|
|
408
508
|
);
|
|
409
|
-
const navHtml = renderPrimaryNavigation({
|
|
410
|
-
items: validatedInput.navigation.items,
|
|
411
|
-
currentRoute: joinedRoute,
|
|
412
|
-
messages: siteMessages,
|
|
413
|
-
});
|
|
414
509
|
const bodyHtml = renderPageBody({
|
|
415
510
|
messages: siteMessages,
|
|
416
|
-
headerHtml,
|
|
417
|
-
navHtml,
|
|
511
|
+
headerHtml: headerFor(joinedRoute),
|
|
418
512
|
footerHtml,
|
|
419
|
-
breadcrumbHtml: page.breadcrumbHtml,
|
|
420
513
|
mainHtml: page.bodyHtml,
|
|
421
514
|
});
|
|
422
|
-
const
|
|
515
|
+
const ogImageInfo = resolveSocialImage({
|
|
423
516
|
mediaAssets,
|
|
517
|
+
mediaDimensions,
|
|
424
518
|
reference: page.socialImageRef,
|
|
425
519
|
baseUrl: validatedInput.baseUrl,
|
|
426
|
-
basePath:
|
|
520
|
+
basePath: publicBasePath,
|
|
427
521
|
});
|
|
522
|
+
const ogImage = ogImageInfo?.url;
|
|
428
523
|
contentPages.push({
|
|
429
524
|
virtualPath: `pages/${page.kind}-${index}.html`,
|
|
430
525
|
content: bodyHtml,
|
|
431
526
|
permalink: projectRouteToFilePath(joinedRoute, routeProfile),
|
|
432
527
|
layout: 'skeleton.njk',
|
|
433
528
|
data: {
|
|
434
|
-
title: page.title,
|
|
529
|
+
title: page.documentTitle ?? page.title,
|
|
530
|
+
ogTitle: page.title,
|
|
435
531
|
lang: page.language,
|
|
436
532
|
dir: page.direction,
|
|
437
533
|
pageKind: page.kind,
|
|
438
534
|
description: page.description,
|
|
439
535
|
robotsContent: page.robotsContent,
|
|
440
|
-
canonicalUrl: new URL(
|
|
536
|
+
canonicalUrl: new URL(
|
|
537
|
+
joinPublicRoute(publicBasePath, page.route),
|
|
538
|
+
validatedInput.baseUrl,
|
|
539
|
+
).toString(),
|
|
441
540
|
siteName,
|
|
442
541
|
ogType: page.ogType ?? 'website',
|
|
443
542
|
ogImage,
|
|
543
|
+
ogImageWidth: ogImageInfo?.width,
|
|
544
|
+
ogImageHeight: ogImageInfo?.height,
|
|
545
|
+
ogImageAlt: ogImage ? page.socialImageAlt : undefined,
|
|
546
|
+
articlePublished: page.articleMeta?.publishedTime,
|
|
547
|
+
articleModified: page.articleMeta?.modifiedTime,
|
|
548
|
+
articleAuthors: page.articleMeta?.authorUrls ?? [],
|
|
549
|
+
articleTags: page.articleMeta?.tags ?? [],
|
|
550
|
+
jsonLd: page.jsonLd,
|
|
444
551
|
twitterCard: twitterCardType(Boolean(ogImage)),
|
|
445
552
|
atomFeedUrl: feeds.atomSelfUrl,
|
|
446
553
|
rssFeedUrl: feeds.rssSelfUrl,
|
|
@@ -464,6 +571,10 @@ export async function renderPublication(buildInput, options) {
|
|
|
464
571
|
redirectProjections.push({
|
|
465
572
|
joinedSource,
|
|
466
573
|
joinedTarget: joined,
|
|
574
|
+
publicTarget: joinPublicRoute(
|
|
575
|
+
publicBasePath,
|
|
576
|
+
contentRoute(record.frontmatter),
|
|
577
|
+
),
|
|
467
578
|
filePath: projectRouteToFilePath(joinedSource, routeProfile),
|
|
468
579
|
});
|
|
469
580
|
}
|
|
@@ -471,7 +582,7 @@ export async function renderPublication(buildInput, options) {
|
|
|
471
582
|
|
|
472
583
|
const redirectPages = redirectProjections.map((projection, index) => ({
|
|
473
584
|
virtualPath: `redirects/${index}.html`,
|
|
474
|
-
content: renderRedirectDocument(projection.
|
|
585
|
+
content: renderRedirectDocument(projection.publicTarget),
|
|
475
586
|
permalink: projection.filePath,
|
|
476
587
|
}));
|
|
477
588
|
|
|
@@ -485,15 +596,9 @@ export async function renderPublication(buildInput, options) {
|
|
|
485
596
|
// page kind's own pure body function. Pushed after the guard above so the
|
|
486
597
|
// guard's own "is there anything authored to render" check is unaffected
|
|
487
598
|
// by this always-present synthetic page.
|
|
488
|
-
const errorNavHtml = renderPrimaryNavigation({
|
|
489
|
-
items: validatedInput.navigation.items,
|
|
490
|
-
currentRoute: undefined,
|
|
491
|
-
messages: siteMessages,
|
|
492
|
-
});
|
|
493
599
|
const errorBodyHtml = renderPageBody({
|
|
494
600
|
messages: siteMessages,
|
|
495
|
-
headerHtml,
|
|
496
|
-
navHtml: errorNavHtml,
|
|
601
|
+
headerHtml: headerFor(undefined),
|
|
497
602
|
footerHtml,
|
|
498
603
|
mainHtml: renderErrorPageBody({ messages: siteMessages, homeRoute }),
|
|
499
604
|
});
|
|
@@ -504,7 +609,8 @@ export async function renderPublication(buildInput, options) {
|
|
|
504
609
|
permalink: errorFilePath,
|
|
505
610
|
layout: 'skeleton.njk',
|
|
506
611
|
data: {
|
|
507
|
-
title: /** @type {string} */ (siteMessages.errorPageHeading)
|
|
612
|
+
title: `${/** @type {string} */ (siteMessages.errorPageHeading)} | ${siteName}`,
|
|
613
|
+
ogTitle: /** @type {string} */ (siteMessages.errorPageHeading),
|
|
508
614
|
lang: validatedInput.publication.defaultLanguage,
|
|
509
615
|
dir: resolveTextDirection(validatedInput.publication.defaultLanguage),
|
|
510
616
|
pageKind: 'error',
|
|
@@ -546,11 +652,42 @@ export async function renderPublication(buildInput, options) {
|
|
|
546
652
|
);
|
|
547
653
|
const sitemapXml = buildSitemap({
|
|
548
654
|
generatedPages,
|
|
549
|
-
basePath:
|
|
655
|
+
basePath: publicBasePath,
|
|
550
656
|
baseUrl: validatedInput.baseUrl,
|
|
551
657
|
});
|
|
552
658
|
const searchIndexJson = buildSearchIndex(validatedInput);
|
|
659
|
+
const absoluteSiteUrl = (/** @type {string} */ route) =>
|
|
660
|
+
new URL(
|
|
661
|
+
joinPublicRoute(publicBasePath, route),
|
|
662
|
+
validatedInput.baseUrl,
|
|
663
|
+
).toString();
|
|
664
|
+
const robotsTxt = buildRobotsTxt({
|
|
665
|
+
aiPolicy: readAiCrawlerPolicy(validatedInput.publication),
|
|
666
|
+
sitemapUrl: absoluteSiteUrl(SITEMAP_ROUTE),
|
|
667
|
+
});
|
|
668
|
+
const llmsFilePath = projectFixedAssetPath(
|
|
669
|
+
validatedInput.basePath,
|
|
670
|
+
LLMS_ROUTE,
|
|
671
|
+
);
|
|
672
|
+
const llmsFullFilePath = projectFixedAssetPath(
|
|
673
|
+
validatedInput.basePath,
|
|
674
|
+
LLMS_FULL_ROUTE,
|
|
675
|
+
);
|
|
676
|
+
const { llmsTxt, llmsFullTxt } = buildLlmsDocuments(validatedInput, {
|
|
677
|
+
rss: feeds.rssSelfUrl,
|
|
678
|
+
atom: feeds.atomSelfUrl,
|
|
679
|
+
sitemap: absoluteSiteUrl(SITEMAP_ROUTE),
|
|
680
|
+
searchIndex: absoluteSiteUrl(SEARCH_INDEX_ROUTE),
|
|
681
|
+
full: absoluteSiteUrl(LLMS_FULL_ROUTE),
|
|
682
|
+
});
|
|
553
683
|
const assetPages = [
|
|
684
|
+
{ virtualPath: 'robots.html', content: robotsTxt, permalink: ROBOTS_PATH },
|
|
685
|
+
{ virtualPath: 'llms.html', content: llmsTxt, permalink: llmsFilePath },
|
|
686
|
+
{
|
|
687
|
+
virtualPath: 'llms-full.html',
|
|
688
|
+
content: llmsFullTxt,
|
|
689
|
+
permalink: llmsFullFilePath,
|
|
690
|
+
},
|
|
554
691
|
{
|
|
555
692
|
virtualPath: 'feeds/atom.html',
|
|
556
693
|
content: feeds.atomXml,
|
|
@@ -604,6 +741,18 @@ export async function renderPublication(buildInput, options) {
|
|
|
604
741
|
searchIndexFilePath,
|
|
605
742
|
{ routeClass: 'asset', mediaType: 'application/json; charset=utf-8' },
|
|
606
743
|
],
|
|
744
|
+
[
|
|
745
|
+
ROBOTS_PATH,
|
|
746
|
+
{ routeClass: 'asset', mediaType: 'text/plain; charset=utf-8' },
|
|
747
|
+
],
|
|
748
|
+
[
|
|
749
|
+
llmsFilePath,
|
|
750
|
+
{ routeClass: 'asset', mediaType: 'text/plain; charset=utf-8' },
|
|
751
|
+
],
|
|
752
|
+
[
|
|
753
|
+
llmsFullFilePath,
|
|
754
|
+
{ routeClass: 'asset', mediaType: 'text/plain; charset=utf-8' },
|
|
755
|
+
],
|
|
607
756
|
]);
|
|
608
757
|
|
|
609
758
|
const outputFilePaths = await listFilesSortedByUtf8Bytes(outputDirectory);
|