react-cheminfo 0.35.0 → 0.37.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/bin/check-seo.mjs +333 -0
- package/lib/ecosystem/core/sites.d.ts.map +1 -1
- package/lib/ecosystem/core/sites.js +17 -0
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/core/types.d.ts +1 -1
- package/lib/ecosystem/core/types.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.js +4 -0
- package/lib/ecosystem/ui/glyphs.js.map +1 -1
- package/lib/language/core/index.d.ts +2 -0
- package/lib/language/core/index.d.ts.map +1 -1
- package/lib/language/core/index.js +1 -0
- package/lib/language/core/index.js.map +1 -1
- package/lib/language/core/languagePath.d.ts +52 -0
- package/lib/language/core/languagePath.d.ts.map +1 -0
- package/lib/language/core/languagePath.js +65 -0
- package/lib/language/core/languagePath.js.map +1 -0
- package/lib/seo/core/alternates.d.ts +40 -0
- package/lib/seo/core/alternates.d.ts.map +1 -0
- package/lib/seo/core/alternates.js +42 -0
- package/lib/seo/core/alternates.js.map +1 -0
- package/lib/seo/core/index.d.ts +3 -0
- package/lib/seo/core/index.d.ts.map +1 -1
- package/lib/seo/core/index.js +2 -0
- package/lib/seo/core/index.js.map +1 -1
- package/lib/seo/core/noscript.d.ts +9 -0
- package/lib/seo/core/noscript.d.ts.map +1 -1
- package/lib/seo/core/noscript.js +7 -2
- package/lib/seo/core/noscript.js.map +1 -1
- package/lib/seo/core/pageMeta.d.ts +23 -0
- package/lib/seo/core/pageMeta.d.ts.map +1 -1
- package/lib/seo/core/pageMeta.js +52 -3
- package/lib/seo/core/pageMeta.js.map +1 -1
- package/lib/seo/core/pageProse.d.ts +76 -0
- package/lib/seo/core/pageProse.d.ts.map +1 -0
- package/lib/seo/core/pageProse.js +92 -0
- package/lib/seo/core/pageProse.js.map +1 -0
- package/lib/seo/core/routeProblems.d.ts +33 -0
- package/lib/seo/core/routeProblems.d.ts.map +1 -0
- package/lib/seo/core/routeProblems.js +89 -0
- package/lib/seo/core/routeProblems.js.map +1 -0
- package/lib/seo/core/routes.d.ts +14 -0
- package/lib/seo/core/routes.d.ts.map +1 -1
- package/lib/seo/core/routes.js.map +1 -1
- package/lib/seo/core/siteFiles.d.ts.map +1 -1
- package/lib/seo/core/siteFiles.js +2 -1
- package/lib/seo/core/siteFiles.js.map +1 -1
- package/lib/seo/vite/prerender.d.ts +13 -0
- package/lib/seo/vite/prerender.d.ts.map +1 -1
- package/lib/seo/vite/prerender.js +17 -10
- package/lib/seo/vite/prerender.js.map +1 -1
- package/package.json +2 -1
- package/src/ecosystem/core/sites.ts +17 -0
- package/src/ecosystem/core/types.ts +1 -0
- package/src/ecosystem/ui/glyphs.tsx +16 -0
- package/src/language/core/index.ts +2 -0
- package/src/language/core/languagePath.ts +78 -0
- package/src/seo/core/alternates.ts +65 -0
- package/src/seo/core/index.ts +3 -0
- package/src/seo/core/noscript.ts +18 -2
- package/src/seo/core/pageMeta.ts +74 -3
- package/src/seo/core/pageProse.ts +146 -0
- package/src/seo/core/routeProblems.ts +111 -0
- package/src/seo/core/routes.ts +14 -0
- package/src/seo/core/siteFiles.ts +2 -1
- package/src/seo/vite/prerender.ts +30 -11
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"languagePath.js","sourceRoot":"","sources":["../../../src/language/core/languagePath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAUjE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,SAA8B;IAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IACxD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAElE,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,QAAQ,KAAK,gBAAgB,IAAI,QAAQ,KAAK,KAAK;YAAE,SAAS;QAClE,MAAM,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;IAC5D,CAAC;IACD,OAAO;QACL,QAAQ,EAAE,gBAAgB;QAC1B,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,IAAI,GAAG;KACvC,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAkB,EAAE,IAAY;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IACxD,IAAI,QAAQ,KAAK,gBAAgB;QAAE,OAAO,MAAM,CAAC;IACjD,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,GAAG,MAAM,EAAE,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tags that tell a search engine five addresses are one page written five
|
|
3
|
+
* times.
|
|
4
|
+
*
|
|
5
|
+
* Without them a translated site is read as five sites that happen to look
|
|
6
|
+
* alike: the French tutorial competes with the English one instead of being
|
|
7
|
+
* offered to a French reader, and a search engine picks one of them to keep.
|
|
8
|
+
* With them each address is served to the audience it was written for, and the
|
|
9
|
+
* four it was not stop diluting it.
|
|
10
|
+
*
|
|
11
|
+
* Every page names **every** language including itself — a set that does not
|
|
12
|
+
* list the page it is on is ignored whole — plus `x-default`, which is where a
|
|
13
|
+
* reader whose language we do not speak is sent.
|
|
14
|
+
*/
|
|
15
|
+
import type { Language } from '../../i18n/core/languages.ts';
|
|
16
|
+
/** Which page, in which languages, served from where. */
|
|
17
|
+
export interface AlternateOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Where the site is served, mount path included and no trailing slash, e.g.
|
|
20
|
+
* `https://3d.cheminfo.org`.
|
|
21
|
+
*/
|
|
22
|
+
origin: string;
|
|
23
|
+
/**
|
|
24
|
+
* The page, from the site's own root and with no language prefix on it, e.g.
|
|
25
|
+
* `/tutorial`.
|
|
26
|
+
*/
|
|
27
|
+
path: string;
|
|
28
|
+
/**
|
|
29
|
+
* Every language the site is written in. One language alone means there is
|
|
30
|
+
* nothing to point at, and no tag is written.
|
|
31
|
+
*/
|
|
32
|
+
languages: readonly Language[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The `rel="alternate"` block for one page of a translated site.
|
|
36
|
+
* @param options - The page, its languages and where the site is served.
|
|
37
|
+
* @returns The tags, one per line, or `''` when the site speaks one language.
|
|
38
|
+
*/
|
|
39
|
+
export declare function alternateLinkTags(options: AlternateOptions): string;
|
|
40
|
+
//# sourceMappingURL=alternates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alternates.d.ts","sourceRoot":"","sources":["../../../src/seo/core/alternates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAK7D,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAYnE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tags that tell a search engine five addresses are one page written five
|
|
3
|
+
* times.
|
|
4
|
+
*
|
|
5
|
+
* Without them a translated site is read as five sites that happen to look
|
|
6
|
+
* alike: the French tutorial competes with the English one instead of being
|
|
7
|
+
* offered to a French reader, and a search engine picks one of them to keep.
|
|
8
|
+
* With them each address is served to the audience it was written for, and the
|
|
9
|
+
* four it was not stop diluting it.
|
|
10
|
+
*
|
|
11
|
+
* Every page names **every** language including itself — a set that does not
|
|
12
|
+
* list the page it is on is ignored whole — plus `x-default`, which is where a
|
|
13
|
+
* reader whose language we do not speak is sent.
|
|
14
|
+
*/
|
|
15
|
+
import { DEFAULT_LANGUAGE } from "../../i18n/core/languages.js";
|
|
16
|
+
import { withLanguagePath } from "../../language/core/languagePath.js";
|
|
17
|
+
import { escapeAttribute } from "../../share/core/escape.js";
|
|
18
|
+
/**
|
|
19
|
+
* The `rel="alternate"` block for one page of a translated site.
|
|
20
|
+
* @param options - The page, its languages and where the site is served.
|
|
21
|
+
* @returns The tags, one per line, or `''` when the site speaks one language.
|
|
22
|
+
*/
|
|
23
|
+
export function alternateLinkTags(options) {
|
|
24
|
+
const { origin, path, languages } = options;
|
|
25
|
+
if (languages.length < 2)
|
|
26
|
+
return '';
|
|
27
|
+
const tags = [];
|
|
28
|
+
for (const language of languages) {
|
|
29
|
+
tags.push(linkTag(language, address(origin, language, path)));
|
|
30
|
+
}
|
|
31
|
+
// A reader we have no language for gets the unprefixed address, which is the
|
|
32
|
+
// one every link handed out before the site was translated already points at.
|
|
33
|
+
tags.push(linkTag('x-default', address(origin, DEFAULT_LANGUAGE, path)));
|
|
34
|
+
return tags.join('\n');
|
|
35
|
+
}
|
|
36
|
+
function address(origin, language, path) {
|
|
37
|
+
return `${origin}${withLanguagePath(language, path)}`;
|
|
38
|
+
}
|
|
39
|
+
function linkTag(hreflang, href) {
|
|
40
|
+
return `<link rel="alternate" hreflang="${escapeAttribute(hreflang)}" href="${escapeAttribute(href)}" />`;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=alternates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alternates.js","sourceRoot":"","sources":["../../../src/seo/core/alternates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAqB7D;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAyB;IACzD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAC5C,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,6EAA6E;IAC7E,8EAA8E;IAC9E,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,OAAO,CAAC,MAAc,EAAE,QAAkB,EAAE,IAAY;IAC/D,OAAO,GAAG,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,OAAO,CAAC,QAAgB,EAAE,IAAY;IAC7C,OAAO,mCAAmC,eAAe,CAAC,QAAQ,CAAC,WAAW,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC;AAC5G,CAAC"}
|
package/lib/seo/core/index.d.ts
CHANGED
|
@@ -4,10 +4,13 @@ export type { NoscriptEcosystem, NoscriptHrefs, NoscriptOptions, NoscriptRoute,
|
|
|
4
4
|
export { noscriptIndex } from './noscript.ts';
|
|
5
5
|
export type { PageMetaOptions } from './pageMeta.ts';
|
|
6
6
|
export { injectPageMeta, pageDocumentMeta, pageHeadTags } from './pageMeta.ts';
|
|
7
|
+
export type { PageContent, PageSection, PageTable } from './pageProse.ts';
|
|
8
|
+
export { pageProseHtml } from './pageProse.ts';
|
|
7
9
|
export type { PlainDescriptionOptions } from './plainDescription.ts';
|
|
8
10
|
export { plainDescription, plainProse } from './plainDescription.ts';
|
|
9
11
|
export type { RobotsDisallow } from './robots.ts';
|
|
10
12
|
export { robotsTxt } from './robots.ts';
|
|
13
|
+
export { routeProblems, withheldPhrase } from './routeProblems.ts';
|
|
11
14
|
export type { RouteMeta } from './routes.ts';
|
|
12
15
|
export { assertRoutes, homeRoute, pageMetaFor, routeFor } from './routes.ts';
|
|
13
16
|
export type { SiteFilesOptions } from './siteFiles.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/seo/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/seo/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,YAAY,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/lib/seo/core/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export { writeDocumentMeta } from "./documentMeta.js";
|
|
2
2
|
export { noscriptIndex } from "./noscript.js";
|
|
3
3
|
export { injectPageMeta, pageDocumentMeta, pageHeadTags } from "./pageMeta.js";
|
|
4
|
+
export { pageProseHtml } from "./pageProse.js";
|
|
4
5
|
export { plainDescription, plainProse } from "./plainDescription.js";
|
|
5
6
|
export { robotsTxt } from "./robots.js";
|
|
7
|
+
export { routeProblems, withheldPhrase } from "./routeProblems.js";
|
|
6
8
|
export { assertRoutes, homeRoute, pageMetaFor, routeFor } from "./routes.js";
|
|
7
9
|
export { sitemapXml } from "./siteFiles.js";
|
|
8
10
|
export { startDocumentMeta } from "./startDocumentMeta.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/seo/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAQtD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/seo/core/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAQtD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* the tool needs JavaScript, and links the addresses it answers.
|
|
7
7
|
*/
|
|
8
8
|
import type { SiteId } from '../../ecosystem/core/sites.ts';
|
|
9
|
+
import type { PageContent } from './pageProse.ts';
|
|
9
10
|
import type { RouteMeta } from './routes.ts';
|
|
10
11
|
import type { SiteFilesOptions } from './siteFiles.ts';
|
|
11
12
|
/** How the addresses of the site's own pages are written. */
|
|
@@ -80,6 +81,14 @@ export interface NoscriptText {
|
|
|
80
81
|
export interface NoscriptOptions extends Omit<SiteFilesOptions, 'routes'>, Omit<NoscriptText, 'routes'> {
|
|
81
82
|
/** The addresses it links, each with the label it is linked under. */
|
|
82
83
|
routes: readonly NoscriptRoute[];
|
|
84
|
+
/**
|
|
85
|
+
* What the page being written says, above the crawl path. The block is the
|
|
86
|
+
* only text a crawler is handed before anything runs, so a page with nothing
|
|
87
|
+
* of its own here is indexed on its title and on this site's menu — which
|
|
88
|
+
* every other page of the site carries too.
|
|
89
|
+
* @default undefined — the block is the menu alone
|
|
90
|
+
*/
|
|
91
|
+
content?: PageContent;
|
|
83
92
|
}
|
|
84
93
|
/**
|
|
85
94
|
* The `noscript` block, ready to put in the body.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noscript.d.ts","sourceRoot":"","sources":["../../../src/seo/core/noscript.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAiB,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAK3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,UAAU,CAAC;AAEpD,6DAA6D;AAC7D,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACrC;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACxC;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACnC;AAED,yDAAyD;AACzD,MAAM,WAAW,eACf,SAAQ,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC;IACtE,sEAAsE;IACtE,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"noscript.d.ts","sourceRoot":"","sources":["../../../src/seo/core/noscript.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAiB,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAK3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,UAAU,CAAC;AAEpD,6DAA6D;AAC7D,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACrC;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACxC;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CACnC;AAED,yDAAyD;AACzD,MAAM,WAAW,eACf,SAAQ,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC;IACtE,sEAAsE;IACtE,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IACjC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAoB9D"}
|
package/lib/seo/core/noscript.js
CHANGED
|
@@ -9,6 +9,7 @@ import { siteById, siteDisplayName } from "../../ecosystem/core/lookup.js";
|
|
|
9
9
|
import { ECOSYSTEM_SITES, siteUrl } from "../../ecosystem/core/sites.js";
|
|
10
10
|
import { joinBasePath } from "../../router/core/basePath.js";
|
|
11
11
|
import { escapeAttribute, escapeText } from "../../share/core/escape.js";
|
|
12
|
+
import { pageProseHtml } from "./pageProse.js";
|
|
12
13
|
import { mountPathOf, resolveSite } from "./siteFiles.js";
|
|
13
14
|
/**
|
|
14
15
|
* The `noscript` block, ready to put in the body.
|
|
@@ -26,11 +27,15 @@ export function noscriptIndex(options) {
|
|
|
26
27
|
const site = resolveSite(options.site);
|
|
27
28
|
const hrefs = options.hrefs ?? 'absolute';
|
|
28
29
|
const mount = hrefs === 'absolute' ? mountPathOf(options) : '';
|
|
29
|
-
const
|
|
30
|
+
const content = options.content;
|
|
31
|
+
// The page's own name answers the title it is indexed under, so it wins over
|
|
32
|
+
// a heading the site writes for every one of its pages at once.
|
|
33
|
+
const heading = escapeText(content?.heading ?? options.heading ?? siteDisplayName(site));
|
|
30
34
|
const intro = escapeText(options.intro ??
|
|
31
35
|
`${site.tagline} This tool needs JavaScript; these are the pages it offers:`);
|
|
36
|
+
const prose = content === undefined ? '' : pageProseHtml(content, ' ');
|
|
32
37
|
return `<noscript>
|
|
33
|
-
<h1>${heading}</h1
|
|
38
|
+
<h1>${heading}</h1>${prose}
|
|
34
39
|
<p>${intro}</p>${pageList(options.routes, mount, hrefs, ' ')}${familyList(site.id, options.ecosystem)}
|
|
35
40
|
</noscript>`;
|
|
36
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noscript.js","sourceRoot":"","sources":["../../../src/seo/core/noscript.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAE3E,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"noscript.js","sourceRoot":"","sources":["../../../src/seo/core/noscript.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* carries none of its own, so this only ever writes — see `./template.ts`.
|
|
13
13
|
*/
|
|
14
14
|
import type { SiteId, SiteRecord } from '../../ecosystem/core/sites.ts';
|
|
15
|
+
import type { Language } from '../../i18n/core/languages.ts';
|
|
15
16
|
import type { DocumentMeta } from './documentMeta.ts';
|
|
16
17
|
import type { RouteMeta } from './routes.ts';
|
|
17
18
|
/** Which site is being served, and what it answers. */
|
|
@@ -40,6 +41,17 @@ export interface PageMetaOptions {
|
|
|
40
41
|
* @default '/og.png'
|
|
41
42
|
*/
|
|
42
43
|
image?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Every language the site is written in, the default one included.
|
|
46
|
+
*
|
|
47
|
+
* The language is read off the address — `/fr/tutorial` is the French
|
|
48
|
+
* tutorial — so the canonical, the card and the `hreflang` set are written
|
|
49
|
+
* for the page actually being served, and the routes passed are the table in
|
|
50
|
+
* that language. A site writing one language leaves this out and nothing
|
|
51
|
+
* about its head changes.
|
|
52
|
+
* @default [the default language]
|
|
53
|
+
*/
|
|
54
|
+
languages?: readonly Language[];
|
|
43
55
|
}
|
|
44
56
|
/**
|
|
45
57
|
* Give a page the title, the description and the canonical address of the route
|
|
@@ -73,4 +85,15 @@ export declare function pageHeadTags(options: PageMetaOptions): string;
|
|
|
73
85
|
* not an absolute address.
|
|
74
86
|
*/
|
|
75
87
|
export declare function pageDocumentMeta(options: PageMetaOptions): Required<DocumentMeta>;
|
|
88
|
+
/**
|
|
89
|
+
* The language an address is being served in.
|
|
90
|
+
*
|
|
91
|
+
* Read off the address itself rather than passed beside it, so the catalog a
|
|
92
|
+
* server picks and the canonical it writes cannot disagree.
|
|
93
|
+
* @param options - Which site, which address, and the languages it speaks.
|
|
94
|
+
* @returns The language named by the address, or the default one.
|
|
95
|
+
* @throws {Error} When the deployment names an origin that is not an absolute
|
|
96
|
+
* address.
|
|
97
|
+
*/
|
|
98
|
+
export declare function pageLanguage(options: PageMetaOptions): Language;
|
|
76
99
|
//# sourceMappingURL=pageMeta.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageMeta.d.ts","sourceRoot":"","sources":["../../../src/seo/core/pageMeta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"pageMeta.d.ts","sourceRoot":"","sources":["../../../src/seo/core/pageMeta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAW7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAQ7C,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IAC1B,qEAAqE;IACrE,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IAC7B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAE7E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAmC7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,GACvB,QAAQ,CAAC,YAAY,CAAC,CAQxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ,CAE/D"}
|
package/lib/seo/core/pageMeta.js
CHANGED
|
@@ -12,10 +12,17 @@
|
|
|
12
12
|
* carries none of its own, so this only ever writes — see `./template.ts`.
|
|
13
13
|
*/
|
|
14
14
|
import { siteDisplayName } from "../../ecosystem/core/lookup.js";
|
|
15
|
+
import { DEFAULT_LANGUAGE } from "../../i18n/core/languages.js";
|
|
16
|
+
import { readLanguagePath, withLanguagePath, } from "../../language/core/languagePath.js";
|
|
17
|
+
import { withoutQueryOrFragment } from "../../router/core/address.js";
|
|
18
|
+
import { stripBasePath } from "../../router/core/basePath.js";
|
|
15
19
|
import { escapeAttribute, escapeText } from "../../share/core/escape.js";
|
|
20
|
+
import { alternateLinkTags } from "./alternates.js";
|
|
16
21
|
import { pageMetaFor } from "./routes.js";
|
|
17
22
|
import { mountPathOf, originOf, resolveSite } from "./siteFiles.js";
|
|
18
23
|
import { PAGE_HEAD_MARKER, fill } from "./template.js";
|
|
24
|
+
// A scheme and an authority: what `location.href` hands out.
|
|
25
|
+
const ABSOLUTE_URL = /^[a-z][\d+.a-z-]*:\/\//i;
|
|
19
26
|
/**
|
|
20
27
|
* Give a page the title, the description and the canonical address of the route
|
|
21
28
|
* it answers, plus the card a link to it unfurls into.
|
|
@@ -39,11 +46,24 @@ export function injectPageMeta(html, options) {
|
|
|
39
46
|
*/
|
|
40
47
|
export function pageHeadTags(options) {
|
|
41
48
|
const name = siteDisplayName(resolveSite(options.site));
|
|
42
|
-
const
|
|
49
|
+
const route = routeMetaOf(options);
|
|
50
|
+
const description = route.description;
|
|
43
51
|
const origin = originOf(options);
|
|
44
52
|
const { title, canonical } = pageDocumentMeta(options);
|
|
45
53
|
const image = absolute(options.image ?? '/og.png', origin);
|
|
54
|
+
const alternates = alternateLinkTags({
|
|
55
|
+
origin,
|
|
56
|
+
path: route.path,
|
|
57
|
+
languages: languagesOf(options),
|
|
58
|
+
});
|
|
59
|
+
// A maintenance screen says so on the page itself. `robots.txt` cannot: it
|
|
60
|
+
// stops the crawl, and an address nobody crawled is still listed from
|
|
61
|
+
// whatever links to it, with no description to show for it.
|
|
62
|
+
const robots = route.indexed === false
|
|
63
|
+
? ['<meta name="robots" content="noindex, nofollow" />']
|
|
64
|
+
: [];
|
|
46
65
|
return [
|
|
66
|
+
...robots,
|
|
47
67
|
`<title>${escapeText(title)}</title>`,
|
|
48
68
|
`<meta name="description" content="${escapeAttribute(description)}" />`,
|
|
49
69
|
`<link rel="canonical" href="${escapeAttribute(canonical)}" />`,
|
|
@@ -54,6 +74,7 @@ export function pageHeadTags(options) {
|
|
|
54
74
|
`<meta property="og:url" content="${escapeAttribute(canonical)}" />`,
|
|
55
75
|
`<meta property="og:image" content="${escapeAttribute(image)}" />`,
|
|
56
76
|
'<meta name="twitter:card" content="summary_large_image" />',
|
|
77
|
+
...(alternates === '' ? [] : [alternates]),
|
|
57
78
|
].join('\n');
|
|
58
79
|
}
|
|
59
80
|
/**
|
|
@@ -73,14 +94,42 @@ export function pageDocumentMeta(options) {
|
|
|
73
94
|
return {
|
|
74
95
|
title: `${meta.title} — ${siteDisplayName(site)}`,
|
|
75
96
|
description: meta.description,
|
|
76
|
-
canonical: `${originOf(options)}${meta.path}`,
|
|
97
|
+
canonical: `${originOf(options)}${withLanguagePath(pageLanguage(options), meta.path)}`,
|
|
77
98
|
};
|
|
78
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* The language an address is being served in.
|
|
102
|
+
*
|
|
103
|
+
* Read off the address itself rather than passed beside it, so the catalog a
|
|
104
|
+
* server picks and the canonical it writes cannot disagree.
|
|
105
|
+
* @param options - Which site, which address, and the languages it speaks.
|
|
106
|
+
* @returns The language named by the address, or the default one.
|
|
107
|
+
* @throws {Error} When the deployment names an origin that is not an absolute
|
|
108
|
+
* address.
|
|
109
|
+
*/
|
|
110
|
+
export function pageLanguage(options) {
|
|
111
|
+
return readLanguagePath(ownPath(options), languagesOf(options)).language;
|
|
112
|
+
}
|
|
79
113
|
// A server behind a mount is handed the address the browser asked for, and the
|
|
80
114
|
// route table is written from the site's own root, so the mount the origin
|
|
81
115
|
// carries is taken off it before the table is read.
|
|
82
116
|
function routeMetaOf(options) {
|
|
83
|
-
|
|
117
|
+
const { path } = readLanguagePath(ownPath(options), languagesOf(options));
|
|
118
|
+
return pageMetaFor(options.routes, path);
|
|
119
|
+
}
|
|
120
|
+
// The address from the site's own root, the mount taken off, with the query
|
|
121
|
+
// string and the fragment gone: what the language prefix is read off. An app
|
|
122
|
+
// handing over `location.href` is answered too, so the one reading serves a
|
|
123
|
+
// server, a build and a click alike.
|
|
124
|
+
function ownPath(options) {
|
|
125
|
+
const url = options.url;
|
|
126
|
+
const path = ABSOLUTE_URL.test(url) && URL.canParse(url)
|
|
127
|
+
? new URL(url).pathname
|
|
128
|
+
: withoutQueryOrFragment(url);
|
|
129
|
+
return stripBasePath(mountPathOf(options), path);
|
|
130
|
+
}
|
|
131
|
+
function languagesOf(options) {
|
|
132
|
+
return options.languages ?? [DEFAULT_LANGUAGE];
|
|
84
133
|
}
|
|
85
134
|
function absolute(target, origin) {
|
|
86
135
|
return target.startsWith('/') ? `${origin}${target}` : target;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageMeta.js","sourceRoot":"","sources":["../../../src/seo/core/pageMeta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"pageMeta.js","sourceRoot":"","sources":["../../../src/seo/core/pageMeta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAGjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAEvD,6DAA6D;AAC7D,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAyC/C;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,OAAwB;IACnE,OAAO,IAAI,CAAC,IAAI,EAAE,gBAAgB,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,OAAwB;IACnD,MAAM,IAAI,GAAG,eAAe,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,iBAAiB,CAAC;QACnC,MAAM;QACN,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC;KAChC,CAAC,CAAC;IAEH,2EAA2E;IAC3E,sEAAsE;IACtE,4DAA4D;IAC5D,MAAM,MAAM,GACV,KAAK,CAAC,OAAO,KAAK,KAAK;QACrB,CAAC,CAAC,CAAC,oDAAoD,CAAC;QACxD,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;QACL,GAAG,MAAM;QACT,UAAU,UAAU,CAAC,KAAK,CAAC,UAAU;QACrC,qCAAqC,eAAe,CAAC,WAAW,CAAC,MAAM;QACvE,+BAA+B,eAAe,CAAC,SAAS,CAAC,MAAM;QAC/D,+CAA+C;QAC/C,0CAA0C,eAAe,CAAC,IAAI,CAAC,MAAM;QACrE,sCAAsC,eAAe,CAAC,KAAK,CAAC,MAAM;QAClE,4CAA4C,eAAe,CAAC,WAAW,CAAC,MAAM;QAC9E,oCAAoC,eAAe,CAAC,SAAS,CAAC,MAAM;QACpE,sCAAsC,eAAe,CAAC,KAAK,CAAC,MAAM;QAClE,4DAA4D;QAC5D,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;KAC3C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAwB;IAExB,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO;QACL,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,MAAM,eAAe,CAAC,IAAI,CAAC,EAAE;QACjD,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,gBAAgB,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;KACvF,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,OAAwB;IACnD,OAAO,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC3E,CAAC;AAED,+EAA+E;AAC/E,2EAA2E;AAC3E,oDAAoD;AACpD,SAAS,WAAW,CAAC,OAAwB;IAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1E,OAAO,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED,4EAA4E;AAC5E,6EAA6E;AAC7E,4EAA4E;AAC5E,qCAAqC;AACrC,SAAS,OAAO,CAAC,OAAwB;IACvC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,IAAI,GACR,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;QACzC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ;QACvB,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,aAAa,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,WAAW,CAAC,OAAwB;IAC3C,OAAO,OAAO,CAAC,SAAS,IAAI,CAAC,gBAAgB,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc,EAAE,MAAc;IAC9C,OAAO,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The text a page is indexed on, written into the HTML before anything runs.
|
|
3
|
+
*
|
|
4
|
+
* A prerendered site writes one file per address, and each of them carried the
|
|
5
|
+
* same body: the site's crawl path, and nothing else. A search engine clusters
|
|
6
|
+
* pages by the text it is handed, so a hundred and eighteen element pages
|
|
7
|
+
* differing only in their title are a hundred and seventeen duplicates — and
|
|
8
|
+
* which one it keeps is not ours to choose. A page heavy enough that the
|
|
9
|
+
* renderer never gets to it is indexed on that body alone.
|
|
10
|
+
*
|
|
11
|
+
* So what a site writes here is the text its running app already shows, drawn
|
|
12
|
+
* from the same data: the prose is not written twice, it is written where the
|
|
13
|
+
* build can reach it. Text only, and escaped — the addresses a reader follows
|
|
14
|
+
* are the crawl path's business.
|
|
15
|
+
*/
|
|
16
|
+
/** A table of facts under the prose: the rows a page would show anyway. */
|
|
17
|
+
export interface PageTable {
|
|
18
|
+
/** Header cells, left to right. */
|
|
19
|
+
columns: readonly string[];
|
|
20
|
+
/** Body rows, each as many cells as there are columns. */
|
|
21
|
+
rows: ReadonlyArray<readonly string[]>;
|
|
22
|
+
/**
|
|
23
|
+
* The sentence under the table, saying where the numbers come from.
|
|
24
|
+
* @default undefined — the table stands on its own
|
|
25
|
+
*/
|
|
26
|
+
caption?: string;
|
|
27
|
+
}
|
|
28
|
+
/** One run of the page's text: a heading, prose, and the facts under it. */
|
|
29
|
+
export interface PageSection {
|
|
30
|
+
/**
|
|
31
|
+
* The heading it opens with, as an `h2`.
|
|
32
|
+
* @default undefined — the run carries no heading
|
|
33
|
+
*/
|
|
34
|
+
heading?: string;
|
|
35
|
+
/**
|
|
36
|
+
* The paragraphs under it, each taken as written.
|
|
37
|
+
* @default undefined — no prose
|
|
38
|
+
*/
|
|
39
|
+
paragraphs?: readonly string[];
|
|
40
|
+
/**
|
|
41
|
+
* A list under the prose, one item per line.
|
|
42
|
+
* @default undefined — no list
|
|
43
|
+
*/
|
|
44
|
+
list?: readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* A table under the prose.
|
|
47
|
+
* @default undefined — no table
|
|
48
|
+
*/
|
|
49
|
+
table?: PageTable;
|
|
50
|
+
}
|
|
51
|
+
/** The whole of one page's text, as the page itself would say it. */
|
|
52
|
+
export interface PageContent extends PageSection {
|
|
53
|
+
/**
|
|
54
|
+
* The page's own name, written as its `h1`. It answers the title the page is
|
|
55
|
+
* indexed under, so a reader who searched for it reads the same words again.
|
|
56
|
+
*/
|
|
57
|
+
heading: string;
|
|
58
|
+
/**
|
|
59
|
+
* The runs under the opening prose, in reading order.
|
|
60
|
+
* @default undefined — the page is its opening prose
|
|
61
|
+
*/
|
|
62
|
+
sections?: readonly PageSection[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The page's text as HTML, everything below its heading.
|
|
66
|
+
*
|
|
67
|
+
* The heading itself is left to the caller, which already writes the one `h1`
|
|
68
|
+
* the page carries — `noscriptIndex` does.
|
|
69
|
+
* @param content - What the page says.
|
|
70
|
+
* @param indent - The indentation every line is written at.
|
|
71
|
+
* @default ' '
|
|
72
|
+
* @returns The HTML, opening with a newline, or `''` when the page says nothing
|
|
73
|
+
* below its heading.
|
|
74
|
+
*/
|
|
75
|
+
export declare function pageProseHtml(content: PageContent, indent?: string): string;
|
|
76
|
+
//# sourceMappingURL=pageProse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageProse.d.ts","sourceRoot":"","sources":["../../../src/seo/core/pageProse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,2EAA2E;AAC3E,MAAM,WAAW,SAAS;IACxB,mCAAmC;IACnC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,0DAA0D;IAC1D,IAAI,EAAE,aAAa,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACvC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,qEAAqE;AACrE,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACnC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAO,GAAG,MAAM,CAazE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The text a page is indexed on, written into the HTML before anything runs.
|
|
3
|
+
*
|
|
4
|
+
* A prerendered site writes one file per address, and each of them carried the
|
|
5
|
+
* same body: the site's crawl path, and nothing else. A search engine clusters
|
|
6
|
+
* pages by the text it is handed, so a hundred and eighteen element pages
|
|
7
|
+
* differing only in their title are a hundred and seventeen duplicates — and
|
|
8
|
+
* which one it keeps is not ours to choose. A page heavy enough that the
|
|
9
|
+
* renderer never gets to it is indexed on that body alone.
|
|
10
|
+
*
|
|
11
|
+
* So what a site writes here is the text its running app already shows, drawn
|
|
12
|
+
* from the same data: the prose is not written twice, it is written where the
|
|
13
|
+
* build can reach it. Text only, and escaped — the addresses a reader follows
|
|
14
|
+
* are the crawl path's business.
|
|
15
|
+
*/
|
|
16
|
+
import { escapeText } from "../../share/core/escape.js";
|
|
17
|
+
/**
|
|
18
|
+
* The page's text as HTML, everything below its heading.
|
|
19
|
+
*
|
|
20
|
+
* The heading itself is left to the caller, which already writes the one `h1`
|
|
21
|
+
* the page carries — `noscriptIndex` does.
|
|
22
|
+
* @param content - What the page says.
|
|
23
|
+
* @param indent - The indentation every line is written at.
|
|
24
|
+
* @default ' '
|
|
25
|
+
* @returns The HTML, opening with a newline, or `''` when the page says nothing
|
|
26
|
+
* below its heading.
|
|
27
|
+
*/
|
|
28
|
+
export function pageProseHtml(content, indent = ' ') {
|
|
29
|
+
// The page's own heading is the caller's `h1`; what is left of its opening run
|
|
30
|
+
// is prose like any section's.
|
|
31
|
+
const opening = {
|
|
32
|
+
paragraphs: content.paragraphs,
|
|
33
|
+
list: content.list,
|
|
34
|
+
table: content.table,
|
|
35
|
+
};
|
|
36
|
+
const parts = [
|
|
37
|
+
sectionHtml(opening, indent),
|
|
38
|
+
...(content.sections ?? []).map((section) => sectionHtml(section, indent)),
|
|
39
|
+
];
|
|
40
|
+
return parts.join('');
|
|
41
|
+
}
|
|
42
|
+
function sectionHtml(section, indent) {
|
|
43
|
+
const lines = [];
|
|
44
|
+
if (section.heading !== undefined && section.heading.trim() !== '') {
|
|
45
|
+
lines.push(`${indent}<h2>${escapeText(section.heading)}</h2>`);
|
|
46
|
+
}
|
|
47
|
+
for (const paragraph of section.paragraphs ?? []) {
|
|
48
|
+
if (paragraph.trim() === '')
|
|
49
|
+
continue;
|
|
50
|
+
lines.push(`${indent}<p>${escapeText(paragraph)}</p>`);
|
|
51
|
+
}
|
|
52
|
+
const list = listHtml(section.list, indent);
|
|
53
|
+
if (list !== '')
|
|
54
|
+
lines.push(list);
|
|
55
|
+
const table = tableHtml(section.table, indent);
|
|
56
|
+
if (table !== '')
|
|
57
|
+
lines.push(table);
|
|
58
|
+
return lines.length === 0 ? '' : `\n${lines.join('\n')}`;
|
|
59
|
+
}
|
|
60
|
+
function listHtml(list, indent) {
|
|
61
|
+
// A list with no item is not a list: `<ul>` holds at least one `<li>`.
|
|
62
|
+
if (list === undefined || list.length === 0)
|
|
63
|
+
return '';
|
|
64
|
+
const items = list
|
|
65
|
+
.map((item) => `${indent} <li>${escapeText(item)}</li>`)
|
|
66
|
+
.join('\n');
|
|
67
|
+
return `${indent}<ul>\n${items}\n${indent}</ul>`;
|
|
68
|
+
}
|
|
69
|
+
function tableHtml(table, indent) {
|
|
70
|
+
// A table with no row says nothing, and an empty `<tbody>` is not markup a
|
|
71
|
+
// crawler is owed.
|
|
72
|
+
if (table === undefined || table.rows.length === 0)
|
|
73
|
+
return '';
|
|
74
|
+
const caption = table.caption === undefined || table.caption.trim() === ''
|
|
75
|
+
? ''
|
|
76
|
+
: `\n${indent} <caption>${escapeText(table.caption)}</caption>`;
|
|
77
|
+
const head = table.columns
|
|
78
|
+
.map((column) => `<th>${escapeText(column)}</th>`)
|
|
79
|
+
.join('');
|
|
80
|
+
const body = table.rows
|
|
81
|
+
.map((row) => `${indent} <tr>${row.map((cell) => `<td>${escapeText(cell)}</td>`).join('')}</tr>`)
|
|
82
|
+
.join('\n');
|
|
83
|
+
return `${indent}<table>${caption}
|
|
84
|
+
${indent} <thead>
|
|
85
|
+
${indent} <tr>${head}</tr>
|
|
86
|
+
${indent} </thead>
|
|
87
|
+
${indent} <tbody>
|
|
88
|
+
${body}
|
|
89
|
+
${indent} </tbody>
|
|
90
|
+
${indent}</table>`;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=pageProse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageProse.js","sourceRoot":"","sources":["../../../src/seo/core/pageProse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What is wrong with the prose a site is indexed under.
|
|
3
|
+
*
|
|
4
|
+
* A route table is the only place a search result is written, and it is written
|
|
5
|
+
* once and read for years, so the limits that decide whether a result is
|
|
6
|
+
* readable are checked rather than trusted: a title Google cuts in half, a
|
|
7
|
+
* description too short to say anything or long enough to be clipped, two pages
|
|
8
|
+
* sharing a sentence — which is how a site asks to be deduplicated down to one
|
|
9
|
+
* result — and a snippet promising something the page does not carry.
|
|
10
|
+
*
|
|
11
|
+
* The paths are `assertRoutes`' business; this is about the words.
|
|
12
|
+
*/
|
|
13
|
+
import type { RouteMeta } from './routes.ts';
|
|
14
|
+
/**
|
|
15
|
+
* The phrase in a snippet that names something a site does not publish.
|
|
16
|
+
*
|
|
17
|
+
* Shared with the build-time checker, which reads the same sentences back out
|
|
18
|
+
* of the pages they were written into: one list of words, checked where they
|
|
19
|
+
* are authored and again where they landed.
|
|
20
|
+
* @param text - A title or a description.
|
|
21
|
+
* @returns The phrase, or `undefined` when there is none.
|
|
22
|
+
*/
|
|
23
|
+
export declare function withheldPhrase(text: string): string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Check the table a site is indexed under, before a build reads it.
|
|
26
|
+
*
|
|
27
|
+
* Returns the problems rather than throwing, so a site asserts an empty list in
|
|
28
|
+
* its own test and reads every one of them at once.
|
|
29
|
+
* @param routes - Every address the site answers.
|
|
30
|
+
* @returns One line per problem, empty when the table is fit to ship.
|
|
31
|
+
*/
|
|
32
|
+
export declare function routeProblems(routes: readonly RouteMeta[]): string[];
|
|
33
|
+
//# sourceMappingURL=routeProblems.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeProblems.d.ts","sourceRoot":"","sources":["../../../src/seo/core/routeProblems.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAiB7C;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,EAAE,CA2DpE"}
|