@ascribed/astro 0.4.5-next.33 → 0.4.5-next.34
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 +2 -1
- package/dist/code-languages.d.ts +10 -0
- package/dist/code-languages.js +16 -0
- package/dist/code-languages.js.map +1 -0
- package/dist/code-titles.js +49 -5
- package/dist/code-titles.js.map +1 -1
- package/dist/help-file.d.ts +20 -0
- package/dist/help-file.js +24 -0
- package/dist/help-file.js.map +1 -0
- package/dist/help-route.d.ts +2 -3
- package/dist/help-route.js +12 -6
- package/dist/help-route.js.map +1 -1
- package/dist/help.d.ts +20 -27
- package/dist/help.js +49 -36
- package/dist/help.js.map +1 -1
- package/dist/index.js +9 -6
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js +3 -2
- package/dist/init.js.map +1 -1
- package/dist/names.d.ts +21 -0
- package/dist/names.js +21 -0
- package/dist/names.js.map +1 -1
- package/dist/permalinks.d.ts +13 -7
- package/dist/permalinks.js +11 -3
- package/dist/permalinks.js.map +1 -1
- package/dist/redirects.d.ts +14 -3
- package/dist/redirects.js +31 -10
- package/dist/redirects.js.map +1 -1
- package/dist/run.d.ts +5 -5
- package/dist/run.js +11 -7
- package/dist/run.js.map +1 -1
- package/dist/shapes.d.ts +33 -3
- package/dist/shapes.js.map +1 -1
- package/package.json +5 -5
- package/src/MissingPermalink.astro +3 -3
- package/src/Permalink.astro +14 -2
- package/starter/src/layouts/Docs.astro +48 -33
- package/starter/src/styles/docs.css +329 -0
package/README.md
CHANGED
|
@@ -71,7 +71,7 @@ A versioned build (`versions` in `ascribe.toml`) is one collection with every li
|
|
|
71
71
|
|
|
72
72
|
A page's Markdown version has no head, so its rules are response headers, which each build lists in `_ascribe/headers.json`: `X-Robots-Tag` when the page isn't listed, and a canonical `Link` to the page. `astro dev` sends them. With `[consumer] host = "netlify"`, each build writes them in Netlify's format too, at `_ascribe/host/_headers`, and `astro build` merges every project's into the site's `_headers`; a site with its own `public/_headers` keeps it, and the build fails with the lines it lacks. The same setting has `astro build` write the site's `_redirects`, from the moves each project's `ascribe.addresses` records, ahead of a site's own `public/_redirects`.
|
|
73
73
|
|
|
74
|
-
`npx @ascribed/astro init` writes those files into an Astro project once, as yours from then on: the collection (`src/content.config.ts`), the route (`src/pages/[...slug].astro`),
|
|
74
|
+
`npx @ascribed/astro init` writes those files into an Astro project once, as yours from then on: the collection (`src/content.config.ts`), the route (`src/pages/[...slug].astro`), a layout that loads the elements and draws the sidebar (`src/layouts/Docs.astro`), and the layout's stylesheet (`src/styles/docs.css`), whose colors and spaces are the element library's `--ascribe-*` properties. It never writes over a file. `--project <dir>` names the folder holding `ascribe.toml`, and `--build <name>` the build, when there are several. The layout's sidebar comes from `sidebar(entries, { entry })` in `@ascribed/astro/content`: the project's navigation, in `ascribe.nav`'s order or the default one, from the build's `_ascribe/nav.json`, with no list to keep. `neighbors(entry, entries)` gives a page's previous and next in the same order, for links at its foot. A site's own list, `sidebar(entries, { nav })`, overrides the navigation: its groups, in its order, and the build fails when the list leaves out a page or names one that isn't there; `neighbors` takes it too.
|
|
75
75
|
|
|
76
76
|
The [Astro guide](https://ascribed-dev.com/go/astro-guide/) walks through a site: `ascribe.toml`, the collection, the route, and the layout. Its section's how-tos put [a home page in front of the docs](https://ascribed-dev.com/go/a-home-page-in-front-of-the-docs/), or [several projects in one site](https://ascribed-dev.com/go/several-projects-in-one-site/). The [`@ascribed/astro` reference](https://ascribed-dev.com/go/astro-reference/) has the options, the components, what the integration does in `astro build` and `astro dev`, search engines and crawlers, and [review in the site preview](https://ascribed-dev.com/go/review-in-the-site-preview/). [Review](https://ascribed-dev.com/go/review-guide/) walks through reviewing a pull request on your site.
|
|
77
77
|
|
|
@@ -100,6 +100,7 @@ The [Astro guide](https://ascribed-dev.com/go/astro-guide/) walks through a site
|
|
|
100
100
|
| `src/Availability.astro` | A page's availability as the element library's badge |
|
|
101
101
|
| `src/Versions.astro`, `src/VersionBanner.astro`, `src/versions.ts` | A versioned build's lines, from `<output-dir>/_ascribe/versions.json`, the list of the lines that have a page, and an older line's banner |
|
|
102
102
|
| `src/code-titles.ts` | The Shiki transformer that shows code block titles and tested lines |
|
|
103
|
+
| `src/code-languages.ts` | The Shiki transformer that gives a code block's `<code>` its language as a class |
|
|
103
104
|
| `src/Permalink.astro`, `src/permalinks.ts` | The route at each permalink's address, and its pages, from the site output's `_ascribe/permalinks.json` |
|
|
104
105
|
| `src/MissingPermalink.astro` | The explanation on a site's 404 page for an address under the permalinks' path that matches nothing |
|
|
105
106
|
| `src/schema.ts` | Copies the generated schema inside the Astro root |
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AstroUserConfig } from "astro";
|
|
2
|
+
type ShikiTransformer = NonNullable<NonNullable<NonNullable<AstroUserConfig["markdown"]>["shikiConfig"]>["transformers"]>[number];
|
|
3
|
+
/**
|
|
4
|
+
* The language Shiki highlighted the block as, the `data-language` Astro
|
|
5
|
+
* gives its <pre>. Astro highlights a block with no language, and one in a
|
|
6
|
+
* language Shiki doesn't know, as `plaintext`, which has no class, as a block
|
|
7
|
+
* with no language has none before highlighting.
|
|
8
|
+
*/
|
|
9
|
+
export declare const codeLanguages: ShikiTransformer;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The language Shiki highlighted the block as, the `data-language` Astro
|
|
3
|
+
* gives its <pre>. Astro highlights a block with no language, and one in a
|
|
4
|
+
* language Shiki doesn't know, as `plaintext`, which has no class, as a block
|
|
5
|
+
* with no language has none before highlighting.
|
|
6
|
+
*/
|
|
7
|
+
export const codeLanguages = {
|
|
8
|
+
name: "@ascribed/astro:code-languages",
|
|
9
|
+
code(node) {
|
|
10
|
+
const lang = this.options.lang;
|
|
11
|
+
if (typeof lang !== "string" || lang === "" || lang === "plaintext")
|
|
12
|
+
return;
|
|
13
|
+
this.addClassToHast(node, `language-${lang}`);
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=code-languages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-languages.js","sourceRoot":"","sources":["../src/code-languages.ts"],"names":[],"mappings":"AAYA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAqB;IAC7C,IAAI,EAAE,gCAAgC;IACtC,IAAI,CAAC,IAAI;QACP,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,WAAW;YAAE,OAAO;QAC5E,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,YAAY,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;CACF,CAAC","sourcesContent":["// A code block's language as a class on its <code>, `language-sh`, as\n// CommonMark renders it before Shiki highlights it. Shiki's output keeps the\n// language only in the <pre>'s `data-language`, which HTML-to-text and\n// HTML-to-Markdown converters don't read, so their fences came out with no\n// language (decision #1038, site-render contract §5.2). The integration adds\n// this Shiki transformer, so it's the same in `astro dev` and the build.\nimport type { AstroUserConfig } from \"astro\";\n\ntype ShikiTransformer = NonNullable<\n NonNullable<NonNullable<AstroUserConfig[\"markdown\"]>[\"shikiConfig\"]>[\"transformers\"]\n>[number];\n\n/**\n * The language Shiki highlighted the block as, the `data-language` Astro\n * gives its <pre>. Astro highlights a block with no language, and one in a\n * language Shiki doesn't know, as `plaintext`, which has no class, as a block\n * with no language has none before highlighting.\n */\nexport const codeLanguages: ShikiTransformer = {\n name: \"@ascribed/astro:code-languages\",\n code(node) {\n const lang = this.options.lang;\n if (typeof lang !== \"string\" || lang === \"\" || lang === \"plaintext\") return;\n this.addClassToHast(node, `language-${lang}`);\n },\n};\n"]}
|
package/dist/code-titles.js
CHANGED
|
@@ -1,12 +1,56 @@
|
|
|
1
1
|
import { CLASS_CODE_TESTED } from "./names.js";
|
|
2
2
|
/**
|
|
3
|
-
* The value of `key=
|
|
4
|
-
* its
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* The value of the first `key=value` pair in a code block's meta, the info
|
|
4
|
+
* string past its language, when it isn't empty. The meta has its Markdown
|
|
5
|
+
* escapes taken off, and is read as SPEC §3.3.1 reads an info string, as
|
|
6
|
+
* `ascribe_core::info_string` does: words parted by spaces and tabs, a pair's
|
|
7
|
+
* value a token or a quoted string in which `\"` and `\\` escape, and a pair
|
|
8
|
+
* followed by a space, a tab, or the end. Any other word isn't a pair.
|
|
7
9
|
*/
|
|
8
10
|
function metaValue(meta, key) {
|
|
9
|
-
|
|
11
|
+
let i = 0;
|
|
12
|
+
while (i < meta.length) {
|
|
13
|
+
if (meta[i] === " " || meta[i] === "\t") {
|
|
14
|
+
i += 1;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const pair = /^([a-z][a-z0-9-]*)=/.exec(meta.slice(i));
|
|
18
|
+
let end = wordEnd(meta, i);
|
|
19
|
+
let value;
|
|
20
|
+
if (pair !== null) {
|
|
21
|
+
let j = i + pair[0].length;
|
|
22
|
+
if (meta[j] === '"') {
|
|
23
|
+
let text = "";
|
|
24
|
+
j += 1;
|
|
25
|
+
while (j < meta.length && meta[j] !== '"') {
|
|
26
|
+
if (meta[j] === "\\" && (meta[j + 1] === '"' || meta[j + 1] === "\\"))
|
|
27
|
+
j += 1;
|
|
28
|
+
text += meta[j];
|
|
29
|
+
j += 1;
|
|
30
|
+
}
|
|
31
|
+
if (j < meta.length && (j + 1 === meta.length || isSpace(meta[j + 1]))) {
|
|
32
|
+
value = text;
|
|
33
|
+
end = j + 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else if (j < end && !meta.slice(j, end).includes('"')) {
|
|
37
|
+
value = meta.slice(j, end);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (value !== undefined && pair?.[1] === key)
|
|
41
|
+
return value || undefined;
|
|
42
|
+
i = end;
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
function isSpace(c) {
|
|
47
|
+
return c === " " || c === "\t";
|
|
48
|
+
}
|
|
49
|
+
function wordEnd(text, from) {
|
|
50
|
+
let i = from;
|
|
51
|
+
while (i < text.length && !isSpace(text[i]))
|
|
52
|
+
i += 1;
|
|
53
|
+
return i;
|
|
10
54
|
}
|
|
11
55
|
/** The `title="…"` in a code block's meta, if it has one. */
|
|
12
56
|
export function codeTitle(meta) {
|
package/dist/code-titles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-titles.js","sourceRoot":"","sources":["../src/code-titles.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAM/C
|
|
1
|
+
{"version":3,"file":"code-titles.js","sourceRoot":"","sources":["../src/code-titles.ts"],"names":[],"mappings":"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","sourcesContent":["// A code block's caption, shown above it: its title, and what a tested\n// example was tested with. A `@snippet`'s title is in the code block's info\n// string, as `title=\"…\"`, and its tested line as `tested=\"…\"` (SPEC §4.8), and\n// Astro's own code highlighting ignores both (issue #106), so the integration\n// adds this Shiki transformer, which puts such a block in a\n// <figure class=\"code-title\"> with a <figcaption>: the title, then the tested\n// line in a <div class=\"ascribe-code-tested\"> of its own, whose \"Tested with\"\n// lead-in is the element library's stylesheet's (site-render contract §5.1).\nimport type { AstroUserConfig } from \"astro\";\nimport type { Element, ElementContent } from \"hast\";\nimport { CLASS_CODE_TESTED } from \"./names.js\";\n\ntype ShikiTransformer = NonNullable<\n NonNullable<NonNullable<AstroUserConfig[\"markdown\"]>[\"shikiConfig\"]>[\"transformers\"]\n>[number];\n\n/**\n * The value of the first `key=value` pair in a code block's meta, the info\n * string past its language, when it isn't empty. The meta has its Markdown\n * escapes taken off, and is read as SPEC §3.3.1 reads an info string, as\n * `ascribe_core::info_string` does: words parted by spaces and tabs, a pair's\n * value a token or a quoted string in which `\\\"` and `\\\\` escape, and a pair\n * followed by a space, a tab, or the end. Any other word isn't a pair.\n */\nfunction metaValue(meta: string, key: string): string | undefined {\n let i = 0;\n while (i < meta.length) {\n if (meta[i] === \" \" || meta[i] === \"\\t\") {\n i += 1;\n continue;\n }\n const pair = /^([a-z][a-z0-9-]*)=/.exec(meta.slice(i));\n let end = wordEnd(meta, i);\n let value: string | undefined;\n if (pair !== null) {\n let j = i + pair[0].length;\n if (meta[j] === '\"') {\n let text = \"\";\n j += 1;\n while (j < meta.length && meta[j] !== '\"') {\n if (meta[j] === \"\\\\\" && (meta[j + 1] === '\"' || meta[j + 1] === \"\\\\\")) j += 1;\n text += meta[j];\n j += 1;\n }\n if (j < meta.length && (j + 1 === meta.length || isSpace(meta[j + 1]))) {\n value = text;\n end = j + 1;\n }\n } else if (j < end && !meta.slice(j, end).includes('\"')) {\n value = meta.slice(j, end);\n }\n }\n if (value !== undefined && pair?.[1] === key) return value || undefined;\n i = end;\n }\n return undefined;\n}\n\nfunction isSpace(c: string | undefined): boolean {\n return c === \" \" || c === \"\\t\";\n}\n\nfunction wordEnd(text: string, from: number): number {\n let i = from;\n while (i < text.length && !isSpace(text[i])) i += 1;\n return i;\n}\n\n/** The `title=\"…\"` in a code block's meta, if it has one. */\nexport function codeTitle(meta: string): string | undefined {\n return metaValue(meta, \"title\");\n}\n\n/** The `tested=\"…\"` in a code block's meta, if it has one. */\nexport function codeTested(meta: string): string | undefined {\n return metaValue(meta, \"tested\");\n}\n\n/**\n * The block, in a figure whose caption holds its title and its tested line;\n * `undefined` when it has neither.\n */\nexport function captioned(meta: string, block: ElementContent): Element | undefined {\n const title = codeTitle(meta);\n const tested = codeTested(meta);\n if (title === undefined && tested === undefined) return undefined;\n const caption: ElementContent[] = [];\n if (title !== undefined) caption.push({ type: \"text\", value: title });\n if (tested !== undefined) {\n caption.push({\n type: \"element\",\n tagName: \"div\",\n properties: { className: [CLASS_CODE_TESTED] },\n children: [{ type: \"text\", value: tested }],\n });\n }\n return {\n type: \"element\",\n tagName: \"figure\",\n properties: { className: [\"code-title\"] },\n children: [\n { type: \"element\", tagName: \"figcaption\", properties: {}, children: caption },\n block,\n ],\n };\n}\n\nexport const codeTitles: ShikiTransformer = {\n name: \"@ascribed/astro:code-titles\",\n root(root) {\n const meta = (this.options.meta as { __raw?: string } | undefined)?.__raw ?? \"\";\n const pre = root.children.find((node) => node.type === \"element\");\n // A site's own transformer may have put it in a figure already.\n if (pre === undefined || pre.tagName === \"figure\") return;\n const figure = captioned(meta, pre);\n if (figure !== undefined) root.children = [figure];\n },\n};\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** A permalink's section, as `_ascribe/help.json` has it. */
|
|
2
|
+
interface HelpEntry {
|
|
3
|
+
title: string;
|
|
4
|
+
summary?: string;
|
|
5
|
+
text: string;
|
|
6
|
+
address?: string;
|
|
7
|
+
source: string;
|
|
8
|
+
}
|
|
9
|
+
/** `_ascribe/help.json`. */
|
|
10
|
+
export interface HelpFile {
|
|
11
|
+
version: number;
|
|
12
|
+
/** The build's name, as `ascribe.toml` declares it. */
|
|
13
|
+
build: string;
|
|
14
|
+
/** For a line of a versioned build, the line. */
|
|
15
|
+
line?: string;
|
|
16
|
+
help: Record<string, HelpEntry>;
|
|
17
|
+
}
|
|
18
|
+
/** The file in a build's site output, or `undefined` when there isn't one. */
|
|
19
|
+
export declare function readHelp(siteRoot: string): HelpFile | undefined;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// A build's `_ascribe/help.json` (output-layout contract §1.7): each
|
|
2
|
+
// permalink's section. `help.ts` serves its entries at their own addresses,
|
|
3
|
+
// and `permalinks.ts` links each forwarding page to them.
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
/** The file's format version this reads. */
|
|
7
|
+
const VERSION = 1;
|
|
8
|
+
/** The file in a build's site output, or `undefined` when there isn't one. */
|
|
9
|
+
export function readHelp(siteRoot) {
|
|
10
|
+
const file = path.join(siteRoot, "_ascribe", "help.json");
|
|
11
|
+
let text;
|
|
12
|
+
try {
|
|
13
|
+
text = readFileSync(file, "utf8");
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const help = JSON.parse(text);
|
|
19
|
+
if (help.version !== VERSION) {
|
|
20
|
+
throw new Error(`@ascribed/astro: ${file} is version ${String(help.version)} of the help file, and this version of the integration reads version ${VERSION}. Update @ascribed/astro and @ascribed/cli together.`);
|
|
21
|
+
}
|
|
22
|
+
return help;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=help-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help-file.js","sourceRoot":"","sources":["../src/help-file.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,4EAA4E;AAC5E,0DAA0D;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,4CAA4C;AAC5C,MAAM,OAAO,GAAG,CAAC,CAAC;AAqBlB,8EAA8E;AAC9E,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAC1D,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAa,CAAC;IAC1C,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,oBAAoB,IAAI,eAAe,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,wEAAwE,OAAO,sDAAsD,CACjM,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["// A build's `_ascribe/help.json` (output-layout contract §1.7): each\n// permalink's section. `help.ts` serves its entries at their own addresses,\n// and `permalinks.ts` links each forwarding page to them.\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/** The file's format version this reads. */\nconst VERSION = 1;\n\n/** A permalink's section, as `_ascribe/help.json` has it. */\ninterface HelpEntry {\n title: string;\n summary?: string;\n text: string;\n address?: string;\n source: string;\n}\n\n/** `_ascribe/help.json`. */\nexport interface HelpFile {\n version: number;\n /** The build's name, as `ascribe.toml` declares it. */\n build: string;\n /** For a line of a versioned build, the line. */\n line?: string;\n help: Record<string, HelpEntry>;\n}\n\n/** The file in a build's site output, or `undefined` when there isn't one. */\nexport function readHelp(siteRoot: string): HelpFile | undefined {\n const file = path.join(siteRoot, \"_ascribe\", \"help.json\");\n let text: string;\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n return undefined;\n }\n const help = JSON.parse(text) as HelpFile;\n if (help.version !== VERSION) {\n throw new Error(\n `@ascribed/astro: ${file} is version ${String(help.version)} of the help file, and this version of the integration reads version ${VERSION}. Update @ascribed/astro and @ascribed/cli together.`,\n );\n }\n return help;\n}\n"]}
|
package/dist/help-route.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { APIRoute } from "astro";
|
|
2
|
+
import { type HelpAnswer } from "./help.js";
|
|
2
3
|
export declare const getStaticPaths: ({ routePattern }: import("astro").GetStaticPathsOptions) => {
|
|
3
4
|
params: {
|
|
4
5
|
id: string;
|
|
5
6
|
};
|
|
6
|
-
props:
|
|
7
|
-
body: string;
|
|
8
|
-
};
|
|
7
|
+
props: HelpAnswer;
|
|
9
8
|
}[];
|
|
10
9
|
export declare const GET: APIRoute;
|
package/dist/help-route.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { base, permalinks } from "virtual:ascribe/site";
|
|
2
2
|
import { helpPaths } from "./help.js";
|
|
3
3
|
export const getStaticPaths = (({ routePattern }) => helpPaths(permalinks.map((source) => source.siteRoot), base, routePattern));
|
|
4
|
-
export const GET = ({ props }) =>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
export const GET = ({ props }) => {
|
|
5
|
+
const { body, type, alternate } = props;
|
|
6
|
+
return new Response(body, {
|
|
7
|
+
headers: {
|
|
8
|
+
"Content-Type": `${type}; charset=utf-8`,
|
|
9
|
+
"Access-Control-Allow-Origin": "*",
|
|
10
|
+
...(alternate === undefined
|
|
11
|
+
? {}
|
|
12
|
+
: { Link: `<${alternate}>; rel="alternate"; type="text/markdown"` }),
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
};
|
|
10
16
|
//# sourceMappingURL=help-route.js.map
|
package/dist/help-route.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help-route.js","sourceRoot":"","sources":["../src/help-route.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"help-route.js","sourceRoot":"","sources":["../src/help-route.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AAEvD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAClD,SAAS,CACP,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAC3C,IAAI,EACJ,YAAY,CACb,CAA0B,CAAC;AAE9B,MAAM,CAAC,MAAM,GAAG,GAAa,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACzC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAmB,CAAC;IACtD,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;QACxB,OAAO,EAAE;YACP,cAAc,EAAE,GAAG,IAAI,iBAAiB;YACxC,6BAA6B,EAAE,GAAG;YAClC,GAAG,CAAC,SAAS,KAAK,SAAS;gBACzB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,0CAA0C,EAAE,CAAC;SACvE;KACF,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["// A help entry's own addresses: one entry of a line's `_ascribe/help.json`, as\n// JSON, and its section as Markdown (`help.ts`). The integration adds this\n// route once for each folder of entries and each format, `<path>[id].json`\n// and `<path>[id].md` for the current line and `<line>/go/[id].json` and\n// `<line>/go/[id].md` under the base path for each older one; which folder\n// and format this is comes from the route's pattern. Any origin may read\n// it, and the JSON names the Markdown as its alternate, as the build's\n// headers say for a host.\nimport type { APIRoute, GetStaticPaths } from \"astro\";\nimport { base, permalinks } from \"virtual:ascribe/site\";\nimport { helpPaths, type HelpAnswer } from \"./help.js\";\n\nexport const getStaticPaths = (({ routePattern }) =>\n helpPaths(\n permalinks.map((source) => source.siteRoot),\n base,\n routePattern,\n )) satisfies GetStaticPaths;\n\nexport const GET: APIRoute = ({ props }) => {\n const { body, type, alternate } = props as HelpAnswer;\n return new Response(body, {\n headers: {\n \"Content-Type\": `${type}; charset=utf-8`,\n \"Access-Control-Allow-Origin\": \"*\",\n ...(alternate === undefined\n ? {}\n : { Link: `<${alternate}>; rel=\"alternate\"; type=\"text/markdown\"` }),\n },\n });\n};\n"]}
|
package/dist/help.d.ts
CHANGED
|
@@ -1,22 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
interface HelpEntry {
|
|
3
|
-
title: string;
|
|
4
|
-
summary?: string;
|
|
5
|
-
text: string;
|
|
6
|
-
address?: string;
|
|
7
|
-
source: string;
|
|
8
|
-
}
|
|
9
|
-
/** `_ascribe/help.json`. */
|
|
10
|
-
export interface HelpFile {
|
|
11
|
-
version: number;
|
|
12
|
-
/** The build's name, as `ascribe.toml` declares it. */
|
|
13
|
-
build: string;
|
|
14
|
-
/** For a line of a versioned build, the line. */
|
|
15
|
-
line?: string;
|
|
16
|
-
help: Record<string, HelpEntry>;
|
|
17
|
-
}
|
|
18
|
-
/** The file in a build's site output, or `undefined` when there isn't one. */
|
|
19
|
-
export declare function readHelp(siteRoot: string): HelpFile | undefined;
|
|
1
|
+
import { type HelpFile } from "./help-file.js";
|
|
20
2
|
/**
|
|
21
3
|
* What each entry's address answers, by the address from the host's root:
|
|
22
4
|
* the file it's in with that entry alone, its `version`, `build`, and
|
|
@@ -25,21 +7,32 @@ export declare function readHelp(siteRoot: string): HelpFile | undefined;
|
|
|
25
7
|
*/
|
|
26
8
|
export declare function helpAddresses(siteRoots: readonly string[]): Map<string, HelpFile>;
|
|
27
9
|
/**
|
|
28
|
-
* The route patterns the entries need,
|
|
29
|
-
* the current line's, then each older line's.
|
|
30
|
-
* under `base`, since an Astro site serves
|
|
10
|
+
* The route patterns the entries need, for each folder that has any, its
|
|
11
|
+
* JSON's and its Markdown's: the current line's, then each older line's.
|
|
12
|
+
* Throws when a folder isn't under `base`, since an Astro site serves
|
|
13
|
+
* nothing outside it.
|
|
31
14
|
*/
|
|
32
15
|
export declare function helpPatterns(siteRoots: readonly string[], base: string): string[];
|
|
16
|
+
/**
|
|
17
|
+
* An entry's section as Markdown: its title as a heading, then its `text`,
|
|
18
|
+
* the section as the plain output writes it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function helpMarkdown(help: HelpFile): string;
|
|
21
|
+
/** What an entry's address answers: its body, and the body's media type. A record, so Astro takes it as props. */
|
|
22
|
+
export interface HelpAnswer extends Record<string, unknown> {
|
|
23
|
+
body: string;
|
|
24
|
+
type: string;
|
|
25
|
+
/** For the JSON, where the same entry is as Markdown, its alternate. */
|
|
26
|
+
alternate?: string;
|
|
27
|
+
}
|
|
33
28
|
/**
|
|
34
29
|
* `getStaticPaths` for the route at `routePattern`, one of `helpPatterns`:
|
|
35
|
-
* one answer for each entry whose address it matches, the entry as JSON
|
|
30
|
+
* one answer for each entry whose address it matches, the entry as JSON, or
|
|
31
|
+
* its section as Markdown.
|
|
36
32
|
*/
|
|
37
33
|
export declare function helpPaths(siteRoots: readonly string[], base: string, routePattern: string): {
|
|
38
34
|
params: {
|
|
39
35
|
id: string;
|
|
40
36
|
};
|
|
41
|
-
props:
|
|
42
|
-
body: string;
|
|
43
|
-
};
|
|
37
|
+
props: HelpAnswer;
|
|
44
38
|
}[];
|
|
45
|
-
export {};
|
package/dist/help.js
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
|
-
// Each permalink's help at
|
|
1
|
+
// Each permalink's help at addresses of its own, for a product to fetch its
|
|
2
2
|
// line's: one entry of a build's `_ascribe/help.json` (output-layout contract
|
|
3
|
-
// §1.7), as JSON
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
|
|
3
|
+
// §1.7), as JSON, and its section as Markdown, for an agent to read the
|
|
4
|
+
// section a permalink names in one fetch. The current line's entries are
|
|
5
|
+
// beside its permalinks' addresses, at `<path><name>.json` and
|
|
6
|
+
// `<path><name>.md`; an older line's are at `go/<name>.json` and
|
|
7
|
+
// `go/<name>.md` under the line's own base path, `/docs/3.4/go/connect.json`,
|
|
8
|
+
// since the permalinks' addresses are the current line's. The integration
|
|
9
|
+
// adds a route (`help-route.ts`) for each of those folders and each format,
|
|
10
|
+
// in `astro build` and `astro dev`.
|
|
9
11
|
import path from "node:path";
|
|
12
|
+
import { readHelp } from "./help-file.js";
|
|
10
13
|
import { permalinkPattern, readPermalinks } from "./permalinks.js";
|
|
11
14
|
import { normalizeBase } from "./project.js";
|
|
12
15
|
import { olderLines } from "./versions.js";
|
|
13
|
-
/** The file's format version this reads. */
|
|
14
|
-
const VERSION = 1;
|
|
15
|
-
/** The file in a build's site output, or `undefined` when there isn't one. */
|
|
16
|
-
export function readHelp(siteRoot) {
|
|
17
|
-
const file = path.join(siteRoot, "_ascribe", "help.json");
|
|
18
|
-
let text;
|
|
19
|
-
try {
|
|
20
|
-
text = readFileSync(file, "utf8");
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
const help = JSON.parse(text);
|
|
26
|
-
if (help.version !== VERSION) {
|
|
27
|
-
throw new Error(`@ascribed/astro: ${file} is version ${String(help.version)} of the help file, and this version of the integration reads version ${VERSION}. Update @ascribed/astro and @ascribed/cli together.`);
|
|
28
|
-
}
|
|
29
|
-
return help;
|
|
30
|
-
}
|
|
31
16
|
/**
|
|
32
17
|
* Each line's file, with the folder its entries are served under: the
|
|
33
18
|
* current line's at the permalinks' path, each older line's at `go/` under
|
|
@@ -70,32 +55,60 @@ export function helpAddresses(siteRoots) {
|
|
|
70
55
|
}
|
|
71
56
|
return addresses;
|
|
72
57
|
}
|
|
73
|
-
/** The
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
/** The formats an entry is served in, by the extension its address ends with. */
|
|
59
|
+
const FORMATS = [".json", ".md"];
|
|
60
|
+
/** The route pattern for a folder's entries in a format, as Astro takes it: under `base`, which Astro adds. */
|
|
61
|
+
function helpPattern(folder, base, extension) {
|
|
62
|
+
return `${permalinkPattern(folder, base)}${extension}`;
|
|
76
63
|
}
|
|
77
64
|
/**
|
|
78
|
-
* The route patterns the entries need,
|
|
79
|
-
* the current line's, then each older line's.
|
|
80
|
-
* under `base`, since an Astro site serves
|
|
65
|
+
* The route patterns the entries need, for each folder that has any, its
|
|
66
|
+
* JSON's and its Markdown's: the current line's, then each older line's.
|
|
67
|
+
* Throws when a folder isn't under `base`, since an Astro site serves
|
|
68
|
+
* nothing outside it.
|
|
81
69
|
*/
|
|
82
70
|
export function helpPatterns(siteRoots, base) {
|
|
83
71
|
const patterns = helpFolders(siteRoots)
|
|
84
72
|
.filter(({ help }) => Object.keys(help.help).length > 0)
|
|
85
|
-
.
|
|
73
|
+
.flatMap(({ folder }) => FORMATS.map((extension) => helpPattern(folder, base, extension)));
|
|
86
74
|
return [...new Set(patterns)];
|
|
87
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* An entry's section as Markdown: its title as a heading, then its `text`,
|
|
78
|
+
* the section as the plain output writes it.
|
|
79
|
+
*/
|
|
80
|
+
export function helpMarkdown(help) {
|
|
81
|
+
const [entry] = Object.values(help.help);
|
|
82
|
+
if (entry === undefined)
|
|
83
|
+
return "";
|
|
84
|
+
const text = entry.text.trimEnd();
|
|
85
|
+
return text === "" ? `# ${entry.title}\n` : `# ${entry.title}\n\n${text}\n`;
|
|
86
|
+
}
|
|
88
87
|
/**
|
|
89
88
|
* `getStaticPaths` for the route at `routePattern`, one of `helpPatterns`:
|
|
90
|
-
* one answer for each entry whose address it matches, the entry as JSON
|
|
89
|
+
* one answer for each entry whose address it matches, the entry as JSON, or
|
|
90
|
+
* its section as Markdown.
|
|
91
91
|
*/
|
|
92
92
|
export function helpPaths(siteRoots, base, routePattern) {
|
|
93
93
|
return [...helpAddresses(siteRoots)].flatMap(([address, help]) => {
|
|
94
94
|
const name = path.posix.basename(address, ".json");
|
|
95
95
|
const folder = address.slice(0, address.length - `${name}.json`.length);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
if (helpPattern(folder, base, ".json") === routePattern) {
|
|
97
|
+
return [
|
|
98
|
+
{
|
|
99
|
+
params: { id: name },
|
|
100
|
+
props: {
|
|
101
|
+
body: `${JSON.stringify(help, null, 2)}\n`,
|
|
102
|
+
type: "application/json",
|
|
103
|
+
alternate: `${folder}${name}.md`,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
if (helpPattern(folder, base, ".md") === routePattern) {
|
|
109
|
+
return [{ params: { id: name }, props: { body: helpMarkdown(help), type: "text/markdown" } }];
|
|
110
|
+
}
|
|
111
|
+
return [];
|
|
99
112
|
});
|
|
100
113
|
}
|
|
101
114
|
//# sourceMappingURL=help.js.map
|
package/dist/help.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"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","sourcesContent":["// Each permalink's help at addresses of its own, for a product to fetch its\n// line's: one entry of a build's `_ascribe/help.json` (output-layout contract\n// §1.7), as JSON, and its section as Markdown, for an agent to read the\n// section a permalink names in one fetch. The current line's entries are\n// beside its permalinks' addresses, at `<path><name>.json` and\n// `<path><name>.md`; an older line's are at `go/<name>.json` and\n// `go/<name>.md` under the line's own base path, `/docs/3.4/go/connect.json`,\n// since the permalinks' addresses are the current line's. The integration\n// adds a route (`help-route.ts`) for each of those folders and each format,\n// in `astro build` and `astro dev`.\nimport path from \"node:path\";\nimport { readHelp, type HelpFile } from \"./help-file.js\";\nimport { permalinkPattern, readPermalinks } from \"./permalinks.js\";\nimport { normalizeBase } from \"./project.js\";\nimport { olderLines } from \"./versions.js\";\n\n/** A folder of entries' addresses, from the host's root, and the file they're served from. */\ninterface HelpFolder {\n folder: string;\n help: HelpFile;\n}\n\n/**\n * Each line's file, with the folder its entries are served under: the\n * current line's at the permalinks' path, each older line's at `go/` under\n * its base path. A site output with no file, or no permalinks list, has none.\n */\nfunction helpFolders(siteRoots: readonly string[]): HelpFolder[] {\n return siteRoots.flatMap((siteRoot) => {\n const list = readPermalinks(siteRoot);\n const help = readHelp(siteRoot);\n const current =\n list === undefined || help === undefined ? [] : [{ folder: normalizeBase(list.path), help }];\n const older = olderLines(siteRoot).flatMap((line) => {\n const lineHelp = readHelp(line.siteRoot);\n return lineHelp === undefined\n ? []\n : [{ folder: `${normalizeBase(line.base)}go/`, help: lineHelp }];\n });\n return [...current, ...older];\n });\n}\n\n/**\n * What each entry's address answers, by the address from the host's root:\n * the file it's in with that entry alone, its `version`, `build`, and\n * `line` as the file has them, so a product reads a fetched entry and its\n * bundled copy alike. An address two files give keeps the first's.\n */\nexport function helpAddresses(siteRoots: readonly string[]): Map<string, HelpFile> {\n const addresses = new Map<string, HelpFile>();\n for (const { folder, help } of helpFolders(siteRoots)) {\n for (const [name, entry] of Object.entries(help.help)) {\n const address = `${folder}${name}.json`;\n if (addresses.has(address)) continue;\n addresses.set(address, {\n version: help.version,\n build: help.build,\n ...(help.line === undefined ? {} : { line: help.line }),\n help: { [name]: entry },\n });\n }\n }\n return addresses;\n}\n\n/** The formats an entry is served in, by the extension its address ends with. */\nconst FORMATS = [\".json\", \".md\"] as const;\n\n/** The route pattern for a folder's entries in a format, as Astro takes it: under `base`, which Astro adds. */\nfunction helpPattern(folder: string, base: string, extension: string): string {\n return `${permalinkPattern(folder, base)}${extension}`;\n}\n\n/**\n * The route patterns the entries need, for each folder that has any, its\n * JSON's and its Markdown's: the current line's, then each older line's.\n * Throws when a folder isn't under `base`, since an Astro site serves\n * nothing outside it.\n */\nexport function helpPatterns(siteRoots: readonly string[], base: string): string[] {\n const patterns = helpFolders(siteRoots)\n .filter(({ help }) => Object.keys(help.help).length > 0)\n .flatMap(({ folder }) => FORMATS.map((extension) => helpPattern(folder, base, extension)));\n return [...new Set(patterns)];\n}\n\n/**\n * An entry's section as Markdown: its title as a heading, then its `text`,\n * the section as the plain output writes it.\n */\nexport function helpMarkdown(help: HelpFile): string {\n const [entry] = Object.values(help.help);\n if (entry === undefined) return \"\";\n const text = entry.text.trimEnd();\n return text === \"\" ? `# ${entry.title}\\n` : `# ${entry.title}\\n\\n${text}\\n`;\n}\n\n/** What an entry's address answers: its body, and the body's media type. A record, so Astro takes it as props. */\nexport interface HelpAnswer extends Record<string, unknown> {\n body: string;\n type: string;\n /** For the JSON, where the same entry is as Markdown, its alternate. */\n alternate?: string;\n}\n\n/**\n * `getStaticPaths` for the route at `routePattern`, one of `helpPatterns`:\n * one answer for each entry whose address it matches, the entry as JSON, or\n * its section as Markdown.\n */\nexport function helpPaths(\n siteRoots: readonly string[],\n base: string,\n routePattern: string,\n): { params: { id: string }; props: HelpAnswer }[] {\n return [...helpAddresses(siteRoots)].flatMap(([address, help]) => {\n const name = path.posix.basename(address, \".json\");\n const folder = address.slice(0, address.length - `${name}.json`.length);\n if (helpPattern(folder, base, \".json\") === routePattern) {\n return [\n {\n params: { id: name },\n props: {\n body: `${JSON.stringify(help, null, 2)}\\n`,\n type: \"application/json\",\n alternate: `${folder}${name}.md`,\n },\n },\n ];\n }\n if (helpPattern(folder, base, \".md\") === routePattern) {\n return [{ params: { id: name }, props: { body: helpMarkdown(help), type: \"text/markdown\" } }];\n }\n return [];\n });\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ import { writeFile } from "node:fs/promises";
|
|
|
45
45
|
import path from "node:path";
|
|
46
46
|
import { fileURLToPath } from "node:url";
|
|
47
47
|
import { findBinary } from "./binary.js";
|
|
48
|
+
import { codeLanguages } from "./code-languages.js";
|
|
48
49
|
import { codeTitles } from "./code-titles.js";
|
|
49
50
|
import { SeenFiles, watchDev } from "./dev.js";
|
|
50
51
|
import { agentsMiddleware, copyAgentFiles, copyPublishedFiles, filesMiddleware, folderUnder, inOrder, } from "./files.js";
|
|
@@ -326,9 +327,9 @@ export default function ascribe(options) {
|
|
|
326
327
|
prerender: true,
|
|
327
328
|
});
|
|
328
329
|
}
|
|
329
|
-
// Each permalink's help, at `<name>.json` beside its address, and each
|
|
330
|
-
// under the line's base path. One route for each folder: the
|
|
331
|
-
// older line's.
|
|
330
|
+
// Each permalink's help, at `<name>.json` and `<name>.md` beside its address, and each
|
|
331
|
+
// older line's under the line's base path. One route for each folder and format: the
|
|
332
|
+
// current line's, then each older line's.
|
|
332
333
|
for (const pattern of helpPatterns(entries.map((entry) => entry.siteRoot), astro.base)) {
|
|
333
334
|
injectRoute({
|
|
334
335
|
pattern,
|
|
@@ -342,9 +343,11 @@ export default function ascribe(options) {
|
|
|
342
343
|
updateConfig({
|
|
343
344
|
...supplied,
|
|
344
345
|
...(format.supplied === undefined ? {} : { build: { format: format.supplied } }),
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
346
|
+
markdown: {
|
|
347
|
+
shikiConfig: {
|
|
348
|
+
transformers: options.codeTitles === false ? [codeLanguages] : [codeTitles, codeLanguages],
|
|
349
|
+
},
|
|
350
|
+
},
|
|
348
351
|
vite: {
|
|
349
352
|
// `Elements.astro` is Astro source, so Vite must compile it, not load it as a Node module.
|
|
350
353
|
ssr: { noExternal: ["@ascribed/astro"] },
|