@ascribed/astro 0.4.2-next.29 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dev.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AstroIntegration } from "astro";
2
- import { type ProjectInfo } from "./project.js";
2
+ import { type BinaryOption, type ProjectInfo } from "./project.js";
3
3
  type ServerOptions = Parameters<NonNullable<AstroIntegration["hooks"]["astro:server:setup"]>>[0];
4
4
  /**
5
5
  * The assets a build copied from outside the content root, as absolute paths,
@@ -45,5 +45,7 @@ export declare function watchDev(options: {
45
45
  onBuilt?: () => void;
46
46
  /** The sources as the first build read them. */
47
47
  seen?: SeenFiles;
48
+ /** Where to find the binary, to read a project whose `ascribe.toml` has `[from]`. */
49
+ binary?: BinaryOption;
48
50
  }): DevBuilds;
49
51
  export {};
package/dist/dev.js CHANGED
@@ -114,7 +114,7 @@ export function watchDev(options) {
114
114
  if (!failed) {
115
115
  options.onBuilt?.();
116
116
  try {
117
- const reloaded = readProject(project.dir);
117
+ const reloaded = readProject(project.dir, options.binary);
118
118
  if (options.builds.some((build, i) => reloaded.siteRoot(build) !== previousSiteRoots[i])) {
119
119
  throw new Error("ascribe.toml changed output-dir; restart astro dev to reload the collection.");
120
120
  }
package/dist/dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"dev.js","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { AstroIntegration } from \"astro\";\nimport { permalinksText } from \"./permalinks.js\";\nimport { consumerMismatches, readProject, type ProjectInfo } from \"./project.js\";\n\ntype ServerOptions = Parameters<NonNullable<AstroIntegration[\"hooks\"][\"astro:server:setup\"]>>[0];\n\n/**\n * The assets a build copied from outside the content root, as absolute paths,\n * read from the site output's manifest. Watching the content root doesn't\n * cover them. A manifest that's missing or unreadable gives none: the next\n * successful build writes one.\n */\nexport function outsideAssets(project: ProjectInfo, build: string): string[] {\n const manifest = path.join(path.dirname(project.siteRoot(build)), \"site.manifest.json\");\n let files: unknown;\n try {\n files = (JSON.parse(readFileSync(manifest, \"utf8\")) as { files?: unknown }).files;\n } catch {\n return [];\n }\n if (!Array.isArray(files)) return [];\n const assets = new Set<string>();\n for (const entry of files as { kind?: unknown; source?: unknown }[]) {\n if (entry.kind !== \"asset\" || typeof entry.source !== \"string\") continue;\n const absolute = path.resolve(project.contentRoot, entry.source);\n if (!absolute.startsWith(project.contentRoot + path.sep)) assets.add(absolute);\n }\n return [...assets].sort();\n}\n\n/**\n * Each watched file's size and modification time, as last seen. A watcher\n * can report an edit late, after a build already read it: macOS delivers\n * edits made just before the dev server started some seconds after it\n * started. An event that changes neither is no edit, and rebuilding for it\n * would reload the page under the reader.\n */\nexport class SeenFiles {\n private readonly stamps = new Map<string, string>();\n\n /** Records the files under `paths` (files or folders) as they are now. */\n prime(paths: readonly string[]): void {\n for (const at of paths) {\n let entries: string[];\n try {\n entries = statSync(at).isDirectory()\n ? readdirSync(at, { recursive: true, encoding: \"utf8\" }).map((f) => path.join(at, f))\n : [at];\n } catch {\n continue;\n }\n for (const file of entries) {\n const stamp = stampOf(file);\n if (stamp !== undefined && !this.stamps.has(file)) this.stamps.set(file, stamp);\n }\n }\n }\n\n /** Whether `file` differs from when it was last seen (or wasn't seen), and records it. */\n changed(file: string): boolean {\n const stamp = stampOf(file);\n const before = this.stamps.get(file);\n if (stamp === undefined) this.stamps.delete(file);\n else this.stamps.set(file, stamp);\n return stamp === undefined || stamp !== before;\n }\n}\n\nfunction stampOf(file: string): string | undefined {\n try {\n const stat = statSync(file);\n return stat.isFile() ? `${stat.size}:${stat.mtimeMs}` : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** What `watchDev` gives back. */\nexport interface DevBuilds {\n /** Runs `task` in turn with the compiler runs, never during one. */\n inTurn(task: () => Promise<void>): Promise<void>;\n}\n\n/** Watch source files, serialize compiler runs, and refresh Astro after successful output. */\nexport function watchDev(options: {\n server: ServerOptions[\"server\"];\n refreshContent: () => Promise<void>;\n logger: ServerOptions[\"logger\"];\n project: ProjectInfo;\n astro: { base: string; trailingSlash: string; site: string | undefined };\n /** The project's builds the site shows: one, or more when entries share the project. */\n builds: readonly string[];\n rebuild: () => Promise<void>;\n /** Called after each successful rebuild, before Astro reloads the page. */\n onBuilt?: () => void;\n /** The sources as the first build read them. */\n seen?: SeenFiles;\n}): DevBuilds {\n const { server, refreshContent, logger, rebuild } = options;\n let project = options.project;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let pending: Promise<void> = Promise.resolve();\n let dirty = false;\n let running = false;\n let failed = false;\n let assets = new Set<string>();\n const seen = options.seen ?? new SeenFiles();\n const watchAssets = () => {\n assets = new Set(options.builds.flatMap((build) => outsideAssets(project, build)));\n if (assets.size > 0) server.watcher.add([...assets]);\n seen.prime([...assets]);\n };\n\n const drain = async () => {\n running = true;\n const previousProject = project;\n const previousSiteRoots = options.builds.map((build) => previousProject.siteRoot(build));\n const permalinkTexts = () => previousSiteRoots.map((root) => permalinksText(root) ?? \"\");\n const previousPermalinks = permalinkTexts().join(\"\\0\");\n while (dirty) {\n dirty = false;\n try {\n await rebuild();\n failed = false;\n } catch (error) {\n failed = true;\n logger.error(error instanceof Error ? error.message : String(error));\n }\n }\n if (!failed) {\n options.onBuilt?.();\n try {\n const reloaded = readProject(project.dir);\n if (options.builds.some((build, i) => reloaded.siteRoot(build) !== previousSiteRoots[i])) {\n throw new Error(\n \"ascribe.toml changed output-dir; restart astro dev to reload the collection.\",\n );\n }\n const mismatches = consumerMismatches(reloaded, options.astro);\n if (mismatches.length > 0) {\n throw new Error(\n `@ascribed/astro: ascribe.toml and astro.config disagree:\\n- ${mismatches.join(\"\\n- \")}`,\n );\n }\n project = reloaded;\n server.watcher.add(project.contentRoot);\n server.watcher.add(project.configPath);\n watchAssets();\n await refreshContent();\n // Astro keeps each route's `getStaticPaths` until content changes, and adding or removing a\n // permalink may change no page: clear it, as Astro does, so the addresses follow the list.\n if (permalinkTexts().join(\"\\0\") !== previousPermalinks) {\n for (const name of [\"ssr\", \"prerender\"]) {\n server.environments[name]?.hot.send(\"astro:content-changed\", {});\n }\n }\n server.ws.send({ type: \"full-reload\" });\n } catch (error) {\n failed = true;\n logger.error(\n `could not refresh Ascribe content: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n running = false;\n };\n const schedule = () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = undefined;\n pending = pending.then(drain);\n }, 50);\n };\n const onChange = (event: string, file: string) => {\n if (![\"add\", \"change\", \"unlink\"].includes(event)) return;\n const absolute = path.resolve(file);\n const source =\n absolute === project.configPath ||\n assets.has(absolute) ||\n (absolute.startsWith(project.contentRoot + path.sep) &&\n !absolute.startsWith(project.outputRoot + path.sep));\n if (!source) return;\n // A late report of an edit the last build already had.\n if (event !== \"unlink\" && !seen.changed(absolute)) return;\n dirty = true;\n schedule();\n };\n server.watcher.add(project.contentRoot);\n server.watcher.add(project.configPath);\n seen.prime([project.contentRoot, project.configPath]);\n watchAssets();\n server.watcher.on(\"all\", onChange);\n server.httpServer?.once(\"close\", () => {\n if (timer) clearTimeout(timer);\n server.watcher.off(\"all\", onChange);\n });\n server.middlewares.use((_req, res, next) => {\n if (!dirty && !running && !failed) return next();\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n pending = pending.then(drain);\n }\n void pending.then(() => {\n if (failed) {\n res.statusCode = 503;\n res.end(\"Ascribe build failed; fix the source and save to retry.\");\n } else next();\n });\n });\n return {\n inTurn: (task) => {\n const run = pending.then(task);\n pending = run.catch(() => undefined);\n return run;\n },\n };\n}\n"]}
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { AstroIntegration } from \"astro\";\nimport { permalinksText } from \"./permalinks.js\";\nimport { consumerMismatches, readProject, type BinaryOption, type ProjectInfo } from \"./project.js\";\n\ntype ServerOptions = Parameters<NonNullable<AstroIntegration[\"hooks\"][\"astro:server:setup\"]>>[0];\n\n/**\n * The assets a build copied from outside the content root, as absolute paths,\n * read from the site output's manifest. Watching the content root doesn't\n * cover them. A manifest that's missing or unreadable gives none: the next\n * successful build writes one.\n */\nexport function outsideAssets(project: ProjectInfo, build: string): string[] {\n const manifest = path.join(path.dirname(project.siteRoot(build)), \"site.manifest.json\");\n let files: unknown;\n try {\n files = (JSON.parse(readFileSync(manifest, \"utf8\")) as { files?: unknown }).files;\n } catch {\n return [];\n }\n if (!Array.isArray(files)) return [];\n const assets = new Set<string>();\n for (const entry of files as { kind?: unknown; source?: unknown }[]) {\n if (entry.kind !== \"asset\" || typeof entry.source !== \"string\") continue;\n const absolute = path.resolve(project.contentRoot, entry.source);\n if (!absolute.startsWith(project.contentRoot + path.sep)) assets.add(absolute);\n }\n return [...assets].sort();\n}\n\n/**\n * Each watched file's size and modification time, as last seen. A watcher\n * can report an edit late, after a build already read it: macOS delivers\n * edits made just before the dev server started some seconds after it\n * started. An event that changes neither is no edit, and rebuilding for it\n * would reload the page under the reader.\n */\nexport class SeenFiles {\n private readonly stamps = new Map<string, string>();\n\n /** Records the files under `paths` (files or folders) as they are now. */\n prime(paths: readonly string[]): void {\n for (const at of paths) {\n let entries: string[];\n try {\n entries = statSync(at).isDirectory()\n ? readdirSync(at, { recursive: true, encoding: \"utf8\" }).map((f) => path.join(at, f))\n : [at];\n } catch {\n continue;\n }\n for (const file of entries) {\n const stamp = stampOf(file);\n if (stamp !== undefined && !this.stamps.has(file)) this.stamps.set(file, stamp);\n }\n }\n }\n\n /** Whether `file` differs from when it was last seen (or wasn't seen), and records it. */\n changed(file: string): boolean {\n const stamp = stampOf(file);\n const before = this.stamps.get(file);\n if (stamp === undefined) this.stamps.delete(file);\n else this.stamps.set(file, stamp);\n return stamp === undefined || stamp !== before;\n }\n}\n\nfunction stampOf(file: string): string | undefined {\n try {\n const stat = statSync(file);\n return stat.isFile() ? `${stat.size}:${stat.mtimeMs}` : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** What `watchDev` gives back. */\nexport interface DevBuilds {\n /** Runs `task` in turn with the compiler runs, never during one. */\n inTurn(task: () => Promise<void>): Promise<void>;\n}\n\n/** Watch source files, serialize compiler runs, and refresh Astro after successful output. */\nexport function watchDev(options: {\n server: ServerOptions[\"server\"];\n refreshContent: () => Promise<void>;\n logger: ServerOptions[\"logger\"];\n project: ProjectInfo;\n astro: { base: string; trailingSlash: string; site: string | undefined };\n /** The project's builds the site shows: one, or more when entries share the project. */\n builds: readonly string[];\n rebuild: () => Promise<void>;\n /** Called after each successful rebuild, before Astro reloads the page. */\n onBuilt?: () => void;\n /** The sources as the first build read them. */\n seen?: SeenFiles;\n /** Where to find the binary, to read a project whose `ascribe.toml` has `[from]`. */\n binary?: BinaryOption;\n}): DevBuilds {\n const { server, refreshContent, logger, rebuild } = options;\n let project = options.project;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let pending: Promise<void> = Promise.resolve();\n let dirty = false;\n let running = false;\n let failed = false;\n let assets = new Set<string>();\n const seen = options.seen ?? new SeenFiles();\n const watchAssets = () => {\n assets = new Set(options.builds.flatMap((build) => outsideAssets(project, build)));\n if (assets.size > 0) server.watcher.add([...assets]);\n seen.prime([...assets]);\n };\n\n const drain = async () => {\n running = true;\n const previousProject = project;\n const previousSiteRoots = options.builds.map((build) => previousProject.siteRoot(build));\n const permalinkTexts = () => previousSiteRoots.map((root) => permalinksText(root) ?? \"\");\n const previousPermalinks = permalinkTexts().join(\"\\0\");\n while (dirty) {\n dirty = false;\n try {\n await rebuild();\n failed = false;\n } catch (error) {\n failed = true;\n logger.error(error instanceof Error ? error.message : String(error));\n }\n }\n if (!failed) {\n options.onBuilt?.();\n try {\n const reloaded = readProject(project.dir, options.binary);\n if (options.builds.some((build, i) => reloaded.siteRoot(build) !== previousSiteRoots[i])) {\n throw new Error(\n \"ascribe.toml changed output-dir; restart astro dev to reload the collection.\",\n );\n }\n const mismatches = consumerMismatches(reloaded, options.astro);\n if (mismatches.length > 0) {\n throw new Error(\n `@ascribed/astro: ascribe.toml and astro.config disagree:\\n- ${mismatches.join(\"\\n- \")}`,\n );\n }\n project = reloaded;\n server.watcher.add(project.contentRoot);\n server.watcher.add(project.configPath);\n watchAssets();\n await refreshContent();\n // Astro keeps each route's `getStaticPaths` until content changes, and adding or removing a\n // permalink may change no page: clear it, as Astro does, so the addresses follow the list.\n if (permalinkTexts().join(\"\\0\") !== previousPermalinks) {\n for (const name of [\"ssr\", \"prerender\"]) {\n server.environments[name]?.hot.send(\"astro:content-changed\", {});\n }\n }\n server.ws.send({ type: \"full-reload\" });\n } catch (error) {\n failed = true;\n logger.error(\n `could not refresh Ascribe content: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n running = false;\n };\n const schedule = () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = undefined;\n pending = pending.then(drain);\n }, 50);\n };\n const onChange = (event: string, file: string) => {\n if (![\"add\", \"change\", \"unlink\"].includes(event)) return;\n const absolute = path.resolve(file);\n const source =\n absolute === project.configPath ||\n assets.has(absolute) ||\n (absolute.startsWith(project.contentRoot + path.sep) &&\n !absolute.startsWith(project.outputRoot + path.sep));\n if (!source) return;\n // A late report of an edit the last build already had.\n if (event !== \"unlink\" && !seen.changed(absolute)) return;\n dirty = true;\n schedule();\n };\n server.watcher.add(project.contentRoot);\n server.watcher.add(project.configPath);\n seen.prime([project.contentRoot, project.configPath]);\n watchAssets();\n server.watcher.on(\"all\", onChange);\n server.httpServer?.once(\"close\", () => {\n if (timer) clearTimeout(timer);\n server.watcher.off(\"all\", onChange);\n });\n server.middlewares.use((_req, res, next) => {\n if (!dirty && !running && !failed) return next();\n if (timer) {\n clearTimeout(timer);\n timer = undefined;\n pending = pending.then(drain);\n }\n void pending.then(() => {\n if (failed) {\n res.statusCode = 503;\n res.end(\"Ascribe build failed; fix the source and save to retry.\");\n } else next();\n });\n });\n return {\n inTurn: (task) => {\n const run = pending.then(task);\n pending = run.catch(() => undefined);\n return run;\n },\n };\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { APIRoute } from "astro";
2
+ export declare const getStaticPaths: ({ routePattern }: import("astro").GetStaticPathsOptions) => {
3
+ params: {
4
+ id: string;
5
+ };
6
+ props: {
7
+ body: string;
8
+ };
9
+ }[];
10
+ export declare const GET: APIRoute;
@@ -0,0 +1,10 @@
1
+ import { base, permalinks } from "virtual:ascribe/site";
2
+ import { helpPaths } from "./help.js";
3
+ export const getStaticPaths = (({ routePattern }) => helpPaths(permalinks.map((source) => source.siteRoot), base, routePattern));
4
+ export const GET = ({ props }) => new Response(props.body, {
5
+ headers: {
6
+ "Content-Type": "application/json; charset=utf-8",
7
+ "Access-Control-Allow-Origin": "*",
8
+ },
9
+ });
10
+ //# sourceMappingURL=help-route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-route.js","sourceRoot":"","sources":["../src/help-route.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,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,CACzC,IAAI,QAAQ,CAAE,KAA0B,CAAC,IAAI,EAAE;IAC7C,OAAO,EAAE;QACP,cAAc,EAAE,iCAAiC;QACjD,6BAA6B,EAAE,GAAG;KACnC;CACF,CAAC,CAAC","sourcesContent":["// A help entry's own address: one entry of a line's `_ascribe/help.json`, as\n// JSON (`help.ts`). The integration adds this route once for each folder of\n// entries, `<path>[id].json` for the current line and `<line>/go/[id].json`\n// under the base path for each older one; which folder this is comes from\n// the route's pattern. Any origin may read it, as the build's headers say\n// for a host.\nimport type { APIRoute, GetStaticPaths } from \"astro\";\nimport { base, permalinks } from \"virtual:ascribe/site\";\nimport { helpPaths } 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 new Response((props as { body: string }).body, {\n headers: {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Access-Control-Allow-Origin\": \"*\",\n },\n });\n"]}
package/dist/help.d.ts ADDED
@@ -0,0 +1,45 @@
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
+ /**
21
+ * What each entry's address answers, by the address from the host's root:
22
+ * the file it's in with that entry alone, its `version`, `build`, and
23
+ * `line` as the file has them, so a product reads a fetched entry and its
24
+ * bundled copy alike. An address two files give keeps the first's.
25
+ */
26
+ export declare function helpAddresses(siteRoots: readonly string[]): Map<string, HelpFile>;
27
+ /**
28
+ * The route patterns the entries need, one for each folder that has any:
29
+ * the current line's, then each older line's. Throws when a folder isn't
30
+ * under `base`, since an Astro site serves nothing outside it.
31
+ */
32
+ export declare function helpPatterns(siteRoots: readonly string[], base: string): string[];
33
+ /**
34
+ * `getStaticPaths` for the route at `routePattern`, one of `helpPatterns`:
35
+ * one answer for each entry whose address it matches, the entry as JSON.
36
+ */
37
+ export declare function helpPaths(siteRoots: readonly string[], base: string, routePattern: string): {
38
+ params: {
39
+ id: string;
40
+ };
41
+ props: {
42
+ body: string;
43
+ };
44
+ }[];
45
+ export {};
package/dist/help.js ADDED
@@ -0,0 +1,101 @@
1
+ // Each permalink's help at an address of its own, for a product to fetch its
2
+ // line's: one entry of a build's `_ascribe/help.json` (output-layout contract
3
+ // §1.7), as JSON. The current line's entries are beside its permalinks'
4
+ // addresses, at `<path><name>.json`; an older line's are at `go/<name>.json`
5
+ // under the line's own base path, `/docs/3.4/go/connect.json`, since the
6
+ // permalinks' addresses are the current line's. The integration adds a route
7
+ // (`help-route.ts`) for each of those folders, in `astro build` and `astro dev`.
8
+ import { readFileSync } from "node:fs";
9
+ import path from "node:path";
10
+ import { permalinkPattern, readPermalinks } from "./permalinks.js";
11
+ import { normalizeBase } from "./project.js";
12
+ 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
+ /**
32
+ * Each line's file, with the folder its entries are served under: the
33
+ * current line's at the permalinks' path, each older line's at `go/` under
34
+ * its base path. A site output with no file, or no permalinks list, has none.
35
+ */
36
+ function helpFolders(siteRoots) {
37
+ return siteRoots.flatMap((siteRoot) => {
38
+ const list = readPermalinks(siteRoot);
39
+ const help = readHelp(siteRoot);
40
+ const current = list === undefined || help === undefined ? [] : [{ folder: normalizeBase(list.path), help }];
41
+ const older = olderLines(siteRoot).flatMap((line) => {
42
+ const lineHelp = readHelp(line.siteRoot);
43
+ return lineHelp === undefined
44
+ ? []
45
+ : [{ folder: `${normalizeBase(line.base)}go/`, help: lineHelp }];
46
+ });
47
+ return [...current, ...older];
48
+ });
49
+ }
50
+ /**
51
+ * What each entry's address answers, by the address from the host's root:
52
+ * the file it's in with that entry alone, its `version`, `build`, and
53
+ * `line` as the file has them, so a product reads a fetched entry and its
54
+ * bundled copy alike. An address two files give keeps the first's.
55
+ */
56
+ export function helpAddresses(siteRoots) {
57
+ const addresses = new Map();
58
+ for (const { folder, help } of helpFolders(siteRoots)) {
59
+ for (const [name, entry] of Object.entries(help.help)) {
60
+ const address = `${folder}${name}.json`;
61
+ if (addresses.has(address))
62
+ continue;
63
+ addresses.set(address, {
64
+ version: help.version,
65
+ build: help.build,
66
+ ...(help.line === undefined ? {} : { line: help.line }),
67
+ help: { [name]: entry },
68
+ });
69
+ }
70
+ }
71
+ return addresses;
72
+ }
73
+ /** The route pattern for a folder's entries, as Astro takes it: under `base`, which Astro adds. */
74
+ function helpPattern(folder, base) {
75
+ return `${permalinkPattern(folder, base)}.json`;
76
+ }
77
+ /**
78
+ * The route patterns the entries need, one for each folder that has any:
79
+ * the current line's, then each older line's. Throws when a folder isn't
80
+ * under `base`, since an Astro site serves nothing outside it.
81
+ */
82
+ export function helpPatterns(siteRoots, base) {
83
+ const patterns = helpFolders(siteRoots)
84
+ .filter(({ help }) => Object.keys(help.help).length > 0)
85
+ .map(({ folder }) => helpPattern(folder, base));
86
+ return [...new Set(patterns)];
87
+ }
88
+ /**
89
+ * `getStaticPaths` for the route at `routePattern`, one of `helpPatterns`:
90
+ * one answer for each entry whose address it matches, the entry as JSON.
91
+ */
92
+ export function helpPaths(siteRoots, base, routePattern) {
93
+ return [...helpAddresses(siteRoots)].flatMap(([address, help]) => {
94
+ const name = path.posix.basename(address, ".json");
95
+ const folder = address.slice(0, address.length - `${name}.json`.length);
96
+ return helpPattern(folder, base) === routePattern
97
+ ? [{ params: { id: name }, props: { body: `${JSON.stringify(help, null, 2)}\n` } }]
98
+ : [];
99
+ });
100
+ }
101
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"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","sourcesContent":["// Each permalink's help at an address 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. The current line's entries are beside its permalinks'\n// addresses, at `<path><name>.json`; an older line's are at `go/<name>.json`\n// under the line's own base path, `/docs/3.4/go/connect.json`, since the\n// permalinks' addresses are the current line's. The integration adds a route\n// (`help-route.ts`) for each of those folders, in `astro build` and `astro dev`.\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { permalinkPattern, readPermalinks } from \"./permalinks.js\";\nimport { normalizeBase } from \"./project.js\";\nimport { olderLines } from \"./versions.js\";\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\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 route pattern for a folder's entries, as Astro takes it: under `base`, which Astro adds. */\nfunction helpPattern(folder: string, base: string): string {\n return `${permalinkPattern(folder, base)}.json`;\n}\n\n/**\n * The route patterns the entries need, one for each folder that has any:\n * the current line's, then each older line's. Throws when a folder isn't\n * under `base`, since an Astro site serves 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 .map(({ folder }) => helpPattern(folder, base));\n return [...new Set(patterns)];\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.\n */\nexport function helpPaths(\n siteRoots: readonly string[],\n base: string,\n routePattern: string,\n): { params: { id: string }; props: { body: string } }[] {\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 return helpPattern(folder, base) === routePattern\n ? [{ params: { id: name }, props: { body: `${JSON.stringify(help, null, 2)}\\n` } }]\n : [];\n });\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -60,7 +60,7 @@ export interface ProjectsOptions extends SharedOptions {
60
60
  export type AscribeOptions = OneProjectOptions | ProjectsOptions;
61
61
  /**
62
62
  * Runs `ascribe build` for each project, checks the site's routing, adds the markdown plugin, adds a
63
- * page for each permalink's address, and serves published files, and, with `[consumer] agents = true`,
63
+ * page for each permalink's address and an answer for each line's help entries, and serves published files, and, with `[consumer] agents = true`,
64
64
  * `llms.txt` and each page's Markdown, each at its project's base path; and writes the site's one
65
65
  * sitemap and `robots.txt` from every project's page records, and, with `[consumer] headers =
66
66
  * "netlify"`, its `_headers` from their headers lists.
package/dist/index.js CHANGED
@@ -50,6 +50,7 @@ import { SeenFiles, watchDev } from "./dev.js";
50
50
  import { agentsMiddleware, copyAgentFiles, copyPublishedFiles, filesMiddleware, folderUnder, inOrder, } from "./files.js";
51
51
  import { WARN as HEAD_WARN } from "./head-check.js";
52
52
  import { headersFor, headersOutcome, mergeRules, readHeaders } from "./headers.js";
53
+ import { helpPatterns } from "./help.js";
53
54
  import { forwardingRoutes, hasPermalinks, permalinkPattern, readPermalinks } from "./permalinks.js";
54
55
  import { consumerMismatches, homeRoute, normalizeBase, readProject, supplyRouting, } from "./project.js";
55
56
  import { basePathClashes, nameProblems, pagesUnderOtherPaths, permalinkProblems, } from "./projects.js";
@@ -77,7 +78,7 @@ function fail(problems, what) {
77
78
  }
78
79
  /**
79
80
  * Runs `ascribe build` for each project, checks the site's routing, adds the markdown plugin, adds a
80
- * page for each permalink's address, and serves published files, and, with `[consumer] agents = true`,
81
+ * page for each permalink's address and an answer for each line's help entries, and serves published files, and, with `[consumer] agents = true`,
81
82
  * `llms.txt` and each page's Markdown, each at its project's base path; and writes the site's one
82
83
  * sitemap and `robots.txt` from every project's page records, and, with `[consumer] headers =
83
84
  * "netlify"`, its `_headers` from their headers lists.
@@ -151,7 +152,10 @@ export default function ascribe(options) {
151
152
  fail(nameProblems(list), "the `projects` option is wrong");
152
153
  const codegen = command === "preview" ? "" : fileURLToPath(createCodegenDir());
153
154
  entries = list.map((entry) => {
154
- const project = readProject(path.resolve(root, entry.project ?? "."));
155
+ const project = readProject(path.resolve(root, entry.project ?? "."), {
156
+ binary: options.binary,
157
+ root,
158
+ });
155
159
  return {
156
160
  name: entry.name,
157
161
  build: entry.build,
@@ -260,7 +264,7 @@ export default function ascribe(options) {
260
264
  return;
261
265
  const current = entries.map((entry) => ({
262
266
  ...entry,
263
- project: readProject(entry.project.dir),
267
+ project: readProject(entry.project.dir, { binary: options.binary, root }),
264
268
  }));
265
269
  fail(basePathClashes(current), "two projects share a base path");
266
270
  fail(pagesUnderOtherPaths(current), "a page is under another project's base path");
@@ -308,6 +312,16 @@ export default function ascribe(options) {
308
312
  prerender: true,
309
313
  });
310
314
  }
315
+ // Each permalink's help, at `<name>.json` beside its address, and each older line's
316
+ // under the line's base path. One route for each folder: the current line's, then each
317
+ // older line's.
318
+ for (const pattern of helpPatterns(entries.map((entry) => entry.siteRoot), astro.base)) {
319
+ injectRoute({
320
+ pattern,
321
+ entrypoint: new URL("./help-route.js", import.meta.url),
322
+ prerender: true,
323
+ });
324
+ }
311
325
  }
312
326
  const projectHome = (entry) => homeRoute(entry.project.consumer.basePath, astro.trailingSlash);
313
327
  // Dev serving of `_ascribe/files/`, and of the plain output for agents; the build copies them in `astro:build:done`.
@@ -327,6 +341,7 @@ export default function ascribe(options) {
327
341
  ? `export const siteRoot = ${JSON.stringify(entries[0]?.siteRoot ?? "")};\n` +
328
342
  `export const astroRoot = ${JSON.stringify(root)};\n` +
329
343
  `export const home = ${JSON.stringify(homeRoute(astro.base, astro.trailingSlash))};\n` +
344
+ `export const base = ${JSON.stringify(astro.base)};\n` +
330
345
  `export const collections = ${JSON.stringify(named ? Object.fromEntries(entries.map((e) => [e.name, e.siteRoot])) : {})};\n` +
331
346
  `export const permalinks = ${JSON.stringify(entries.map((e) => ({ siteRoot: e.siteRoot, home: projectHome(e) })))};\n` +
332
347
  `export const routes = ${JSON.stringify(entries.map((e) => ({
@@ -378,6 +393,7 @@ export default function ascribe(options) {
378
393
  astro: routing,
379
394
  builds: group.entries.map((entry) => entry.build),
380
395
  rebuild: group.rebuild,
396
+ ...(binary === undefined ? {} : { binary: { binary, root: group.project.dir } }),
381
397
  onBuilt: () => {
382
398
  if (reviewed !== undefined && group.entries.includes(reviewed))
383
399
  review?.rebuilt();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// @ascribed/astro: the Astro integration for Ascribe. Written against Astro\n// 7.3.5.\n//\n// // astro.config.mjs\n// import ascribe from \"@ascribed/astro\";\n// export default defineConfig({\n// // `site`, `base`, and `trailingSlash` come from ascribe.toml's\n// // [consumer] when they're left out here; set here, they must agree.\n// integrations: [ascribe({ build: \"site\" })],\n// });\n//\n// // src/content.config.ts\n// import { defineCollection } from \"astro:content\";\n// import { ascribeCollection } from \"@ascribed/astro/content\";\n// // The generated schema. With the project outside the Astro root, import the\n// // copy inside it instead: \"../.astro/integrations/_ascribed_astro/schema.ts\".\n// import { schema } from \"../.ascribe/build/site/site/_ascribe/schema.ts\";\n// export const collections = { docs: defineCollection(ascribeCollection({ schema })) };\n//\n// // a layout\n// import Elements from \"@ascribed/astro/Elements.astro\"; // <Elements /> in <head>\n// import Availability from \"@ascribed/astro/Availability.astro\"; // the page's availability\n// import Head from \"@ascribed/astro/Head.astro\"; // <Head entry={entry} /> in <head>\n// import Versions from \"@ascribed/astro/Versions.astro\"; // the lines that have the page\n//\n// // the sidebar: the project's navigation, joined to the collection\n// import { sidebar } from \"@ascribed/astro/content\";\n// const groups = sidebar(await getCollection(\"docs\"));\n//\n// // src/pages/404.astro\n// import MissingPermalink from \"@ascribed/astro/MissingPermalink.astro\"; // a permalink that isn't here\n//\n// Several projects in one site, each entry named, and each collection naming its entry:\n//\n// ascribe({\n// projects: [\n// { name: \"docs\", project: \"../docs\", build: \"site\" },\n// { name: \"home\", project: \"home\", build: \"site\" },\n// ],\n// review: \"docs\",\n// })\n// ascribeCollection({ schema, name: \"docs\" })\nimport { existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { AstroIntegration, IntegrationResolvedRoute } from \"astro\";\nimport { findBinary } from \"./binary.js\";\nimport { codeTitles } from \"./code-titles.js\";\nimport { SeenFiles, watchDev, type DevBuilds } from \"./dev.js\";\nimport {\n agentsMiddleware,\n copyAgentFiles,\n copyPublishedFiles,\n filesMiddleware,\n folderUnder,\n inOrder,\n} from \"./files.js\";\nimport { WARN as HEAD_WARN } from \"./head-check.js\";\nimport { headersFor, headersOutcome, mergeRules, readHeaders } from \"./headers.js\";\nimport { forwardingRoutes, hasPermalinks, permalinkPattern, readPermalinks } from \"./permalinks.js\";\nimport {\n consumerMismatches,\n homeRoute,\n normalizeBase,\n readProject,\n supplyRouting,\n type AstroRouting,\n} from \"./project.js\";\nimport {\n basePathClashes,\n nameProblems,\n pagesUnderOtherPaths,\n permalinkProblems,\n type ProjectEntry,\n type ResolvedEntry,\n} from \"./projects.js\";\nimport {\n pageList,\n readRecords,\n routeAs,\n routeKey,\n sitemapRoute,\n type ProjectRobots,\n} from \"./records.js\";\nimport rehypeAscribeAttributes from \"./rehype.js\";\nimport { removeDevFile, siteUrl, writeDevFile } from \"./review/devfile.js\";\nimport { runDiff, runPrompt } from \"./review/diff.js\";\nimport { APP_ID } from \"./review/protocol.js\";\nimport { readRoutes, type RoutedPage } from \"./review/routes.js\";\nimport { channelProblem, ReviewServer, type ToolbarChannel } from \"./review/server.js\";\nimport {\n devRouted,\n devSitePages,\n rootFiles,\n rootFilesMiddleware,\n type RootFileSources,\n} from \"./root-files.js\";\nimport { anchorsFor, hasWarnings, reviewFor, runBuild } from \"./run.js\";\nimport { satteriAscribeAttributes } from \"./satteri.js\";\nimport { copySchema } from \"./schema.js\";\nimport { linesOf, olderLines } from \"./versions.js\";\n\nexport { default as rehypeAscribeAttributes } from \"./rehype.js\";\nexport { satteriAscribeAttributes } from \"./satteri.js\";\nexport type { ProjectEntry } from \"./projects.js\";\n\n/** The virtual module `content.ts` reads the resolved site output roots from. */\nconst SITE_MODULE = \"virtual:ascribe/site\";\n\n/** Options every form of the integration takes. */\ninterface SharedOptions {\n /**\n * The `ascribe` binary, relative to the Astro root. Default: `ASCRIBE_BIN`, then\n * the platform binary installed with `@ascribed/cli`.\n */\n binary?: string;\n /**\n * Mark each block of the site output with the source lines it came from\n * (source anchors), for review: `\"dev\"` in `astro dev` only, `true` always.\n * Default: `false`, though `review` has them in `astro dev`.\n */\n anchors?: boolean | \"dev\";\n /**\n * Review in the site preview: an **Ascribe review** app in `astro dev`'s\n * toolbar, which marks the page's changes and shows the pull request's\n * comments, with source anchors in `astro dev`. Default `true`; `false`\n * removes the app. `astro build` never has it. With several projects, it\n * reviews one: the entry a name names, or the first for `true`.\n */\n review?: boolean | string;\n /**\n * Show a code block's title (`title=\"…\"` in its info string, as `@snippet`\n * writes it), and what a tested example was tested with (`tested=\"…\"`),\n * above it, with a Shiki transformer that puts the block in a\n * `<figure class=\"code-title\">` with a `<figcaption>`. Default `true`.\n */\n codeTitles?: boolean;\n /**\n * The site's one sitemap, at `<base>sitemap.xml`, of every listed page of\n * every project and every page of the site's own. `exclude` lists routes,\n * from the host's root, of the site's own pages to leave out of it, such\n * as one that carries `noindex`.\n */\n sitemap?: { exclude?: string[] };\n}\n\n/** Options of the integration with one project. */\nexport interface OneProjectOptions extends SharedOptions {\n /** The build whose site output is the collection (a name in `ascribe.toml`). */\n build: string;\n /** The directory holding `ascribe.toml`, relative to the Astro root. Default: the root. */\n project?: string;\n projects?: never;\n}\n\n/** Options of the integration with several projects, each entry named. */\nexport interface ProjectsOptions extends SharedOptions {\n /** The projects, each a named build of a project; two entries may share a project. */\n projects: ProjectEntry[];\n build?: never;\n project?: never;\n}\n\n/** Options of the integration. */\nexport type AscribeOptions = OneProjectOptions | ProjectsOptions;\n\n/** The toolbar app's icon: a speech bubble over a page. */\nconst ICON =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 3h8l4 4v6\"/><path d=\"M14 3v4h4\"/><path d=\"M6 3v15\"/><path d=\"M11 14h10v6h-6l-3 2v-2h-1z\"/></svg>';\n\n/** An entry as the hooks use it. */\ninterface Entry extends ResolvedEntry {\n siteRoot: string;\n /** The plain output's root, when the project publishes it for agents. */\n agentsRoot: string | undefined;\n /** Where the generated schema's copy goes, inside the Astro root. */\n schemaDir: string;\n}\n\n/** A project with the entries that build it, which a dev watcher follows together. */\ninterface DevGroup {\n project: ResolvedEntry[\"project\"];\n entries: Entry[];\n rebuild: () => Promise<void>;\n builds?: DevBuilds;\n}\n\nfunction fail(problems: string[], what: string): void {\n if (problems.length > 0) throw new Error(`@ascribed/astro: ${what}:\\n- ${problems.join(\"\\n- \")}`);\n}\n\n/**\n * Runs `ascribe build` for each project, checks the site's routing, adds the markdown plugin, adds a\n * page for each permalink's address, and serves published files, and, with `[consumer] agents = true`,\n * `llms.txt` and each page's Markdown, each at its project's base path; and writes the site's one\n * sitemap and `robots.txt` from every project's page records, and, with `[consumer] headers =\n * \"netlify\"`, its `_headers` from their headers lists.\n */\nexport default function ascribe(options: AscribeOptions): AstroIntegration {\n /** With `projects`; otherwise the one entry has no name a collection gives. */\n const named = options.projects !== undefined;\n let entries: Entry[] = [];\n let groups: DevGroup[] = [];\n let routing: AstroRouting | undefined;\n /** The dev server's sources as its first build read them. */\n const seen = new SeenFiles();\n let binary: string | undefined;\n let reviewed: Entry | undefined;\n let devCommand = false;\n let devHttps = false;\n let review: ReviewServer | undefined;\n /** The site's routes, as Astro resolved them, for what `astro dev` serves of the site's own. */\n let astroRoutes: IntegrationResolvedRoute[] = [];\n /** The site's `public/` folder, where its own `robots.txt` would be. */\n let publicDir = \"\";\n\n /** What the sitemap and `robots.txt` are drawn from, given the site's pages and its routes. */\n const rootSources = (\n sitePages: readonly string[],\n routed: (route: string) => boolean,\n ): RootFileSources => {\n const base = routing?.base ?? \"/\";\n const records = entries.map((entry) => readRecords(entry.siteRoot));\n // Entries of one project share its `ascribe.toml`, and so what it says to crawlers.\n const robots = new Map<string, ProjectRobots>();\n for (const [i, entry] of entries.entries()) {\n if (!robots.has(entry.project.dir))\n robots.set(entry.project.dir, {\n name: entry.name,\n robots: records[i]?.robots ?? { lines: [] },\n });\n }\n const root = normalizeBase(base);\n return {\n projects: [\n ...records.map(pageList),\n // An older line's pages are the site's too: those the current line has point at it.\n ...entries.flatMap((entry) =>\n olderLines(entry.siteRoot).map((line) => pageList(readRecords(line.siteRoot))),\n ),\n ],\n routed,\n sitePages,\n excluded: [\n ...forwardingRoutes(entries.map((entry) => readPermalinks(entry.siteRoot))),\n `${root}404`,\n `${root}500`,\n ...(options.sitemap?.exclude ?? []),\n ],\n robots: [...robots.values()],\n site: routing?.site,\n base,\n ownRobots: existsSync(path.join(publicDir, \"robots.txt\")),\n ownSitemap: existsSync(path.join(publicDir, \"sitemap.xml\")),\n };\n };\n return {\n name: \"@ascribed/astro\",\n hooks: {\n \"astro:config:setup\": async ({\n config,\n command,\n logger,\n updateConfig,\n addDevToolbarApp,\n createCodegenDir,\n injectRoute,\n addMiddleware,\n }) => {\n const root = fileURLToPath(config.root);\n publicDir = fileURLToPath(config.publicDir);\n const list: ProjectEntry[] = options.projects ?? [\n {\n name: \"\",\n build: options.build,\n ...(options.project === undefined ? {} : { project: options.project }),\n },\n ];\n if (named) fail(nameProblems(list), \"the `projects` option is wrong\");\n const codegen = command === \"preview\" ? \"\" : fileURLToPath(createCodegenDir());\n entries = list.map((entry) => {\n const project = readProject(path.resolve(root, entry.project ?? \".\"));\n return {\n name: entry.name,\n build: entry.build,\n project,\n // An unknown build is `ascribe build`'s to report: it knows the implicit `site` build.\n siteRoot: project.siteRoot(entry.build),\n agentsRoot: project.consumer.agents ? project.plainRoot(entry.build) : undefined,\n schemaDir: named ? path.join(codegen, entry.name) : codegen,\n };\n });\n\n // What astro.config leaves unset comes from [consumer]: `site` and `trailingSlash` from the\n // first project that has them, and with one project, `base` from its base path. With\n // `projects`, `base` stays the site's, the root every base path is under.\n const { routing: astro, supplied } = supplyRouting(\n entries.map((entry) => entry.project),\n { base: config.base, trailingSlash: config.trailingSlash, site: config.site },\n !named,\n );\n // `ascribe.toml`'s routing must be Astro's, or every link Ascribe writes is wrong.\n for (const entry of entries) {\n fail(\n consumerMismatches(entry.project, astro),\n named\n ? `\"${entry.name}\"'s ascribe.toml and astro.config disagree`\n : \"ascribe.toml and astro.config disagree\",\n );\n }\n fail(basePathClashes(entries), \"two projects share a base path\");\n\n if (typeof options.review === \"string\" && !entries.some((e) => e.name === options.review)) {\n throw new Error(\n `@ascribed/astro: \\`review\\` names \"${options.review}\", and no entry of \\`projects\\` has that name.`,\n );\n }\n if (reviewFor(options.review, command)) {\n reviewed =\n typeof options.review === \"string\"\n ? entries.find((e) => e.name === options.review)\n : entries[0];\n }\n\n // Where a markdown plugin goes depends on the processor Astro 7.3 runs.\n const processor = config.markdown.processor;\n const pluginLists = processor.options as {\n rehypePlugins?: unknown[];\n hastPlugins?: unknown[];\n };\n if (processor.name === \"satteri\" && pluginLists.hastPlugins !== undefined) {\n pluginLists.hastPlugins.push(satteriAscribeAttributes());\n } else if (processor.name === \"unified\" && pluginLists.rehypePlugins !== undefined) {\n pluginLists.rehypePlugins.push(rehypeAscribeAttributes);\n } else {\n throw new Error(\n `@ascribed/astro: the markdown processor \"${processor.name}\" is not one it can add its plugin to. ` +\n \"Use Astro's default (satteri) or unified(), or add `rehypeAscribeAttributes` to your own.\",\n );\n }\n\n routing = astro;\n\n if (reviewed !== undefined) {\n addDevToolbarApp({\n id: APP_ID,\n name: \"Ascribe review\",\n icon: ICON,\n entrypoint: new URL(\"./toolbar/app.js\", import.meta.url),\n });\n }\n\n if (command !== \"preview\") {\n const found = findBinary({ binary: options.binary, root });\n binary = found;\n const buildEntry = async (entry: Entry) => {\n logger.info(\n `running ${path.basename(found)} build for \"${entry.build}\"${named ? ` (${entry.name})` : \"\"}`,\n );\n const run = {\n binary: found,\n configPath: entry.project.configPath,\n cwd: entry.project.dir,\n anchors: anchorsFor(options.anchors, command, entry === reviewed),\n };\n // `llms.txt` and each page's Markdown, which agents read.\n const plain = entry.agentsRoot === undefined ? [] : ([\"plain\"] as const);\n const result = await runBuild({\n ...run,\n build: entry.build,\n outputs: [\n \"site\",\n ...plain,\n // While review is on, the JSON output says which page is at each route.\n ...(entry === reviewed && review?.active ? ([\"json\"] as const) : []),\n ],\n });\n if (hasWarnings(result.diagnostics)) logger.warn(result.diagnostics);\n else if (result.diagnostics !== \"\") logger.info(result.diagnostics);\n if (result.summary !== \"\") logger.info(result.summary);\n // A versioned build's other lines, which the build's `versions.json` names, once the\n // current line's build has written it. An error in one fails this run as it would the\n // first; `ascribe check` reports every line's warnings, so only what was built is said.\n const older = olderLines(entry.siteRoot).map((line) => line.build);\n if (older.length > 0) {\n const lines = await runBuild({\n ...run,\n build: older,\n outputs: [\n \"site\",\n ...plain,\n ...(entry === reviewed && review?.active ? ([\"json\"] as const) : []),\n ],\n });\n if (lines.summary !== \"\") logger.info(lines.summary);\n }\n // The schema's copy inside the Astro root, for content.config.ts to import.\n mkdirSync(entry.schemaDir, { recursive: true });\n copySchema(entry.siteRoot, entry.schemaDir);\n };\n // What the projects share, which no one project's build can see.\n const checkShared = () => {\n if (entries.length < 2) return;\n const current = entries.map((entry) => ({\n ...entry,\n project: readProject(entry.project.dir),\n }));\n fail(basePathClashes(current), \"two projects share a base path\");\n fail(pagesUnderOtherPaths(current), \"a page is under another project's base path\");\n fail(\n permalinkProblems(\n current,\n current.map((entry) => readPermalinks(entry.siteRoot)),\n ),\n \"the projects' permalinks can't share one route\",\n );\n };\n // One group for each project: a change rebuilds the project it's in.\n const byDir = new Map<string, Entry[]>();\n for (const entry of entries) {\n byDir.set(entry.project.dir, [...(byDir.get(entry.project.dir) ?? []), entry]);\n }\n groups = [...byDir.values()].map((group) => ({\n project: (group[0] as Entry).project,\n entries: group,\n rebuild: async () => {\n for (const entry of group) await buildEntry(entry);\n checkShared();\n },\n }));\n // The sources as the first build reads them: the watcher may report their edits late.\n if (command === \"dev\") {\n for (const group of groups)\n seen.prime([group.project.contentRoot, group.project.configPath]);\n }\n for (const entry of entries) await buildEntry(entry);\n checkShared();\n devCommand = command === \"dev\";\n if (devCommand) {\n // A tag of the head written twice, by Head.astro and the layout, is warned about.\n (globalThis as Record<symbol, unknown>)[HEAD_WARN] = (message: string) =>\n logger.warn(message);\n addMiddleware({\n entrypoint: new URL(\"./head-check.js\", import.meta.url),\n order: \"post\",\n });\n }\n\n // Each permalink's address, a page that forwards to its heading. One route serves every\n // list, at the path of the first that names anything.\n const lists = entries.flatMap((entry) => readPermalinks(entry.siteRoot) ?? []);\n const served = lists.find(hasPermalinks) ?? lists[0];\n if (served !== undefined) {\n injectRoute({\n pattern: permalinkPattern(served.path, astro.base),\n entrypoint: new URL(\"../src/Permalink.astro\", import.meta.url),\n prerender: true,\n });\n }\n }\n\n const projectHome = (entry: Entry) =>\n homeRoute(entry.project.consumer.basePath, astro.trailingSlash);\n // Dev serving of `_ascribe/files/`, and of the plain output for agents; the build copies them in `astro:build:done`.\n updateConfig({\n ...supplied,\n ...(options.codeTitles === false\n ? {}\n : { markdown: { shikiConfig: { transformers: [codeTitles] } } }),\n vite: {\n // `Elements.astro` is Astro source, so Vite must compile it, not load it as a Node module.\n ssr: { noExternal: [\"@ascribed/astro\"] },\n plugins: [\n {\n name: \"@ascribed/astro:site\",\n resolveId: (id) => (id === SITE_MODULE ? `\\0${SITE_MODULE}` : undefined),\n load: (id) =>\n id === `\\0${SITE_MODULE}`\n ? `export const siteRoot = ${JSON.stringify(entries[0]?.siteRoot ?? \"\")};\\n` +\n `export const astroRoot = ${JSON.stringify(root)};\\n` +\n `export const home = ${JSON.stringify(homeRoute(astro.base, astro.trailingSlash))};\\n` +\n `export const collections = ${JSON.stringify(\n named ? Object.fromEntries(entries.map((e) => [e.name, e.siteRoot])) : {},\n )};\\n` +\n `export const permalinks = ${JSON.stringify(\n entries.map((e) => ({ siteRoot: e.siteRoot, home: projectHome(e) })),\n )};\\n` +\n `export const routes = ${JSON.stringify(\n entries.map((e) => ({\n siteRoot: e.siteRoot,\n basePath: e.project.consumer.basePath,\n trailingSlash: e.project.consumer.trailingSlash,\n })),\n )};`\n : undefined,\n },\n {\n name: \"@ascribed/astro:files\",\n configureServer(server) {\n for (const entry of entries) {\n const base = entry.project.consumer.basePath;\n server.middlewares.use(filesMiddleware(entry.siteRoot, base));\n // Each older line's, at its own base path; the lines are read as each request comes.\n server.middlewares.use((req, res, next) =>\n inOrder(\n olderLines(entry.siteRoot).map((line) =>\n filesMiddleware(line.siteRoot, line.base),\n ),\n req,\n res,\n next,\n ),\n );\n if (entry.agentsRoot !== undefined) {\n const siteRoot = entry.siteRoot;\n server.middlewares.use(\n agentsMiddleware(entry.agentsRoot, base, (pathname) =>\n headersFor(siteRoot, pathname),\n ),\n );\n // Each older line's outputs for agents, at its own base path.\n server.middlewares.use((req, res, next) =>\n inOrder(\n olderLines(siteRoot).map((line) =>\n agentsMiddleware(line.plainRoot, line.base, (pathname) =>\n headersFor(line.siteRoot, pathname),\n ),\n ),\n req,\n res,\n next,\n ),\n );\n }\n }\n // The sitemap and robots.txt, as the build would write them now.\n server.middlewares.use(\n rootFilesMiddleware(astro.base, () =>\n rootFiles(\n rootSources(\n devSitePages(astroRoutes, astro),\n devRouted(astroRoutes, astro),\n ),\n ),\n ),\n );\n },\n },\n ],\n },\n });\n },\n \"astro:routes:resolved\": ({ routes }) => {\n astroRoutes = routes;\n },\n \"astro:server:setup\": ({ server, refreshContent, logger, toolbar }) => {\n if (!devCommand || !routing) return;\n if (!refreshContent)\n throw new Error(\"@ascribed/astro: this Astro version does not support refreshContent.\");\n devHttps = Boolean(server.config.server.https);\n for (const group of groups) {\n group.builds = watchDev({\n server,\n seen,\n refreshContent: () => refreshContent({}),\n logger,\n project: group.project,\n astro: routing,\n builds: group.entries.map((entry) => entry.build),\n rebuild: group.rebuild,\n onBuilt: () => {\n if (reviewed !== undefined && group.entries.includes(reviewed)) review?.rebuilt();\n },\n });\n }\n const group = groups.find((g) => reviewed !== undefined && g.entries.includes(reviewed));\n if (reviewed !== undefined && group?.builds !== undefined && binary !== undefined) {\n const entry = reviewed;\n const builds = group.builds;\n const run = { binary, configPath: entry.project.configPath, cwd: entry.project.dir };\n // A versioned build is reviewed in every line, the current one first, each line's\n // routes from its own JSON output.\n const lines = () =>\n linesOf(entry.siteRoot)?.map((line) => ({\n build: line.build,\n siteRoot: line.siteRoot,\n })) ?? [{ build: entry.build, siteRoot: entry.siteRoot }];\n const lineBuilds = () => lines().map((line) => line.build);\n review = new ReviewServer({\n channel: toolbar as ToolbarChannel,\n logger,\n build: entry.build,\n contentRoot: entry.project.contentRoot,\n channelProblem: channelProblem(server.config),\n diff: (base) => runDiff({ ...run, build: lineBuilds(), base }),\n prompt: (page, base) => runPrompt({ ...run, build: lineBuilds(), base, path: page }),\n projectDir: entry.project.dir,\n connect: async () => (await import(\"./review/github.js\")).connect(entry.project.dir),\n writeRoutes: () =>\n builds.inTurn(async () => {\n await runBuild({ ...run, build: lineBuilds(), outputs: [\"json\"] });\n }),\n readRoutes: async () => {\n const all = new Map<string, RoutedPage>();\n const versioned = lines().length > 1;\n for (const line of lines()) {\n const jsonRoot = path.join(path.dirname(line.siteRoot), \"json\");\n for (const [route, page] of await readRoutes(jsonRoot)) {\n if (!all.has(route))\n all.set(route, versioned ? { ...page, build: line.build } : page);\n }\n }\n return all;\n },\n });\n }\n },\n \"astro:server:start\": ({ address, logger }) => {\n review?.listening(address.address);\n if (!devCommand) return;\n // Each project's folder gets its own file, with its own address: its base path.\n for (const group of groups) {\n const entry = group.entries[0] as Entry;\n const dir = group.project.dir;\n try {\n writeDevFile(dir, {\n url: siteUrl(address, { https: devHttps, base: entry.project.consumer.basePath }),\n build: entry.build,\n pid: process.pid,\n });\n // Vite exits on a signal before `astro:server:done` runs.\n process.once(\"exit\", () => removeDevFile(dir, process.pid));\n } catch (error) {\n logger.warn(\n `couldn't write ${groups.length > 1 ? path.join(dir, \".ascribe\", \"dev.json\") : \".ascribe/dev.json\"}, which the editor's Open Site Preview reads: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n },\n \"astro:server:done\": () => {\n review?.dispose();\n review = undefined;\n if (devCommand) for (const group of groups) removeDevFile(group.project.dir, process.pid);\n },\n \"astro:build:done\": async ({ dir, pages, logger }) => {\n const base = routing?.base ?? \"/\";\n const trailingSlash = routing?.trailingSlash ?? \"ignore\";\n // Every page Astro built, by its route from the host's root. Astro lists\n // pages only, not endpoints such as a feed, so a dot in a page's last\n // segment, as in `/v1.2`, is still a page.\n const built = pages.map((page) =>\n routeAs(`${normalizeBase(base)}${page.pathname.replace(/^\\//, \"\")}`, trailingSlash),\n );\n const builtKeys = new Set(built.map(routeKey));\n const files = rootFiles(rootSources(built, (route) => builtKeys.has(routeKey(route))));\n fail(files.problems, \"the site's robots.txt\");\n for (const note of files.notes) logger[note.level](note.text);\n const out = fileURLToPath(dir);\n if (files.sitemap !== undefined) {\n await writeFile(path.join(out, \"sitemap.xml\"), files.sitemap);\n logger.info(`wrote ${sitemapRoute(base)}`);\n }\n if (files.robots !== undefined) {\n await writeFile(path.join(out, \"robots.txt\"), files.robots);\n logger.info(\"wrote /robots.txt\");\n }\n // The host's headers, from the projects that name its format.\n const ownHeaders = path.join(publicDir, \"_headers\");\n const headers = headersOutcome({\n rules: mergeRules(\n entries\n .filter((entry) => entry.project.consumer.headers === \"netlify\")\n .flatMap((entry) =>\n [entry.siteRoot, ...olderLines(entry.siteRoot).map((line) => line.siteRoot)].map(\n (siteRoot) => readHeaders(siteRoot) ?? [],\n ),\n ),\n ),\n base,\n own: existsSync(ownHeaders) ? readFileSync(ownHeaders, \"utf8\") : undefined,\n });\n if (headers.kind === \"fail\") throw new Error(`@ascribed/astro: ${headers.text}`);\n if (headers.kind === \"note\") logger.info(headers.text);\n if (headers.kind === \"write\") {\n await writeFile(path.join(out, \"_headers\"), headers.text);\n logger.info(\"wrote /_headers\");\n }\n // Entries of one project publish at one base path: the first entry's copies go last, so they win.\n for (const entry of [...entries].reverse()) {\n const folder = folderUnder(entry.project.consumer.basePath, base);\n const where = folder === \"\" ? \"\" : ` to ${folder}`;\n if (await copyPublishedFiles(entry.siteRoot, dir, folder))\n logger.info(`copied _ascribe/files/${where}`);\n for (const line of olderLines(entry.siteRoot)) {\n const lineFolder = folderUnder(line.base, base);\n if (await copyPublishedFiles(line.siteRoot, dir, lineFolder))\n logger.info(`copied ${line.build}'s _ascribe/files/ to ${lineFolder}`);\n }\n if (\n entry.agentsRoot !== undefined &&\n (await copyAgentFiles(entry.agentsRoot, dir, folder))\n )\n logger.info(`copied llms.txt and each page's Markdown${where}`);\n if (entry.agentsRoot !== undefined) {\n for (const line of olderLines(entry.siteRoot)) {\n const lineFolder = folderUnder(line.base, base);\n if (await copyAgentFiles(line.plainRoot, dir, lineFolder))\n logger.info(\n `copied ${line.build}'s llms.txt and each page's Markdown to ${lineFolder}`,\n );\n }\n }\n }\n },\n },\n };\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// @ascribed/astro: the Astro integration for Ascribe. Written against Astro\n// 7.3.5.\n//\n// // astro.config.mjs\n// import ascribe from \"@ascribed/astro\";\n// export default defineConfig({\n// // `site`, `base`, and `trailingSlash` come from ascribe.toml's\n// // [consumer] when they're left out here; set here, they must agree.\n// integrations: [ascribe({ build: \"site\" })],\n// });\n//\n// // src/content.config.ts\n// import { defineCollection } from \"astro:content\";\n// import { ascribeCollection } from \"@ascribed/astro/content\";\n// // The generated schema. With the project outside the Astro root, import the\n// // copy inside it instead: \"../.astro/integrations/_ascribed_astro/schema.ts\".\n// import { schema } from \"../.ascribe/build/site/site/_ascribe/schema.ts\";\n// export const collections = { docs: defineCollection(ascribeCollection({ schema })) };\n//\n// // a layout\n// import Elements from \"@ascribed/astro/Elements.astro\"; // <Elements /> in <head>\n// import Availability from \"@ascribed/astro/Availability.astro\"; // the page's availability\n// import Head from \"@ascribed/astro/Head.astro\"; // <Head entry={entry} /> in <head>\n// import Versions from \"@ascribed/astro/Versions.astro\"; // the lines that have the page\n//\n// // the sidebar: the project's navigation, joined to the collection\n// import { sidebar } from \"@ascribed/astro/content\";\n// const groups = sidebar(await getCollection(\"docs\"));\n//\n// // src/pages/404.astro\n// import MissingPermalink from \"@ascribed/astro/MissingPermalink.astro\"; // a permalink that isn't here\n//\n// Several projects in one site, each entry named, and each collection naming its entry:\n//\n// ascribe({\n// projects: [\n// { name: \"docs\", project: \"../docs\", build: \"site\" },\n// { name: \"home\", project: \"home\", build: \"site\" },\n// ],\n// review: \"docs\",\n// })\n// ascribeCollection({ schema, name: \"docs\" })\nimport { existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { AstroIntegration, IntegrationResolvedRoute } from \"astro\";\nimport { findBinary } from \"./binary.js\";\nimport { codeTitles } from \"./code-titles.js\";\nimport { SeenFiles, watchDev, type DevBuilds } from \"./dev.js\";\nimport {\n agentsMiddleware,\n copyAgentFiles,\n copyPublishedFiles,\n filesMiddleware,\n folderUnder,\n inOrder,\n} from \"./files.js\";\nimport { WARN as HEAD_WARN } from \"./head-check.js\";\nimport { headersFor, headersOutcome, mergeRules, readHeaders } from \"./headers.js\";\nimport { helpPatterns } from \"./help.js\";\nimport { forwardingRoutes, hasPermalinks, permalinkPattern, readPermalinks } from \"./permalinks.js\";\nimport {\n consumerMismatches,\n homeRoute,\n normalizeBase,\n readProject,\n supplyRouting,\n type AstroRouting,\n} from \"./project.js\";\nimport {\n basePathClashes,\n nameProblems,\n pagesUnderOtherPaths,\n permalinkProblems,\n type ProjectEntry,\n type ResolvedEntry,\n} from \"./projects.js\";\nimport {\n pageList,\n readRecords,\n routeAs,\n routeKey,\n sitemapRoute,\n type ProjectRobots,\n} from \"./records.js\";\nimport rehypeAscribeAttributes from \"./rehype.js\";\nimport { removeDevFile, siteUrl, writeDevFile } from \"./review/devfile.js\";\nimport { runDiff, runPrompt } from \"./review/diff.js\";\nimport { APP_ID } from \"./review/protocol.js\";\nimport { readRoutes, type RoutedPage } from \"./review/routes.js\";\nimport { channelProblem, ReviewServer, type ToolbarChannel } from \"./review/server.js\";\nimport {\n devRouted,\n devSitePages,\n rootFiles,\n rootFilesMiddleware,\n type RootFileSources,\n} from \"./root-files.js\";\nimport { anchorsFor, hasWarnings, reviewFor, runBuild } from \"./run.js\";\nimport { satteriAscribeAttributes } from \"./satteri.js\";\nimport { copySchema } from \"./schema.js\";\nimport { linesOf, olderLines } from \"./versions.js\";\n\nexport { default as rehypeAscribeAttributes } from \"./rehype.js\";\nexport { satteriAscribeAttributes } from \"./satteri.js\";\nexport type { ProjectEntry } from \"./projects.js\";\n\n/** The virtual module `content.ts` reads the resolved site output roots from. */\nconst SITE_MODULE = \"virtual:ascribe/site\";\n\n/** Options every form of the integration takes. */\ninterface SharedOptions {\n /**\n * The `ascribe` binary, relative to the Astro root. Default: `ASCRIBE_BIN`, then\n * the platform binary installed with `@ascribed/cli`.\n */\n binary?: string;\n /**\n * Mark each block of the site output with the source lines it came from\n * (source anchors), for review: `\"dev\"` in `astro dev` only, `true` always.\n * Default: `false`, though `review` has them in `astro dev`.\n */\n anchors?: boolean | \"dev\";\n /**\n * Review in the site preview: an **Ascribe review** app in `astro dev`'s\n * toolbar, which marks the page's changes and shows the pull request's\n * comments, with source anchors in `astro dev`. Default `true`; `false`\n * removes the app. `astro build` never has it. With several projects, it\n * reviews one: the entry a name names, or the first for `true`.\n */\n review?: boolean | string;\n /**\n * Show a code block's title (`title=\"…\"` in its info string, as `@snippet`\n * writes it), and what a tested example was tested with (`tested=\"…\"`),\n * above it, with a Shiki transformer that puts the block in a\n * `<figure class=\"code-title\">` with a `<figcaption>`. Default `true`.\n */\n codeTitles?: boolean;\n /**\n * The site's one sitemap, at `<base>sitemap.xml`, of every listed page of\n * every project and every page of the site's own. `exclude` lists routes,\n * from the host's root, of the site's own pages to leave out of it, such\n * as one that carries `noindex`.\n */\n sitemap?: { exclude?: string[] };\n}\n\n/** Options of the integration with one project. */\nexport interface OneProjectOptions extends SharedOptions {\n /** The build whose site output is the collection (a name in `ascribe.toml`). */\n build: string;\n /** The directory holding `ascribe.toml`, relative to the Astro root. Default: the root. */\n project?: string;\n projects?: never;\n}\n\n/** Options of the integration with several projects, each entry named. */\nexport interface ProjectsOptions extends SharedOptions {\n /** The projects, each a named build of a project; two entries may share a project. */\n projects: ProjectEntry[];\n build?: never;\n project?: never;\n}\n\n/** Options of the integration. */\nexport type AscribeOptions = OneProjectOptions | ProjectsOptions;\n\n/** The toolbar app's icon: a speech bubble over a page. */\nconst ICON =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M6 3h8l4 4v6\"/><path d=\"M14 3v4h4\"/><path d=\"M6 3v15\"/><path d=\"M11 14h10v6h-6l-3 2v-2h-1z\"/></svg>';\n\n/** An entry as the hooks use it. */\ninterface Entry extends ResolvedEntry {\n siteRoot: string;\n /** The plain output's root, when the project publishes it for agents. */\n agentsRoot: string | undefined;\n /** Where the generated schema's copy goes, inside the Astro root. */\n schemaDir: string;\n}\n\n/** A project with the entries that build it, which a dev watcher follows together. */\ninterface DevGroup {\n project: ResolvedEntry[\"project\"];\n entries: Entry[];\n rebuild: () => Promise<void>;\n builds?: DevBuilds;\n}\n\nfunction fail(problems: string[], what: string): void {\n if (problems.length > 0) throw new Error(`@ascribed/astro: ${what}:\\n- ${problems.join(\"\\n- \")}`);\n}\n\n/**\n * Runs `ascribe build` for each project, checks the site's routing, adds the markdown plugin, adds a\n * page for each permalink's address and an answer for each line's help entries, and serves published files, and, with `[consumer] agents = true`,\n * `llms.txt` and each page's Markdown, each at its project's base path; and writes the site's one\n * sitemap and `robots.txt` from every project's page records, and, with `[consumer] headers =\n * \"netlify\"`, its `_headers` from their headers lists.\n */\nexport default function ascribe(options: AscribeOptions): AstroIntegration {\n /** With `projects`; otherwise the one entry has no name a collection gives. */\n const named = options.projects !== undefined;\n let entries: Entry[] = [];\n let groups: DevGroup[] = [];\n let routing: AstroRouting | undefined;\n /** The dev server's sources as its first build read them. */\n const seen = new SeenFiles();\n let binary: string | undefined;\n let reviewed: Entry | undefined;\n let devCommand = false;\n let devHttps = false;\n let review: ReviewServer | undefined;\n /** The site's routes, as Astro resolved them, for what `astro dev` serves of the site's own. */\n let astroRoutes: IntegrationResolvedRoute[] = [];\n /** The site's `public/` folder, where its own `robots.txt` would be. */\n let publicDir = \"\";\n\n /** What the sitemap and `robots.txt` are drawn from, given the site's pages and its routes. */\n const rootSources = (\n sitePages: readonly string[],\n routed: (route: string) => boolean,\n ): RootFileSources => {\n const base = routing?.base ?? \"/\";\n const records = entries.map((entry) => readRecords(entry.siteRoot));\n // Entries of one project share its `ascribe.toml`, and so what it says to crawlers.\n const robots = new Map<string, ProjectRobots>();\n for (const [i, entry] of entries.entries()) {\n if (!robots.has(entry.project.dir))\n robots.set(entry.project.dir, {\n name: entry.name,\n robots: records[i]?.robots ?? { lines: [] },\n });\n }\n const root = normalizeBase(base);\n return {\n projects: [\n ...records.map(pageList),\n // An older line's pages are the site's too: those the current line has point at it.\n ...entries.flatMap((entry) =>\n olderLines(entry.siteRoot).map((line) => pageList(readRecords(line.siteRoot))),\n ),\n ],\n routed,\n sitePages,\n excluded: [\n ...forwardingRoutes(entries.map((entry) => readPermalinks(entry.siteRoot))),\n `${root}404`,\n `${root}500`,\n ...(options.sitemap?.exclude ?? []),\n ],\n robots: [...robots.values()],\n site: routing?.site,\n base,\n ownRobots: existsSync(path.join(publicDir, \"robots.txt\")),\n ownSitemap: existsSync(path.join(publicDir, \"sitemap.xml\")),\n };\n };\n return {\n name: \"@ascribed/astro\",\n hooks: {\n \"astro:config:setup\": async ({\n config,\n command,\n logger,\n updateConfig,\n addDevToolbarApp,\n createCodegenDir,\n injectRoute,\n addMiddleware,\n }) => {\n const root = fileURLToPath(config.root);\n publicDir = fileURLToPath(config.publicDir);\n const list: ProjectEntry[] = options.projects ?? [\n {\n name: \"\",\n build: options.build,\n ...(options.project === undefined ? {} : { project: options.project }),\n },\n ];\n if (named) fail(nameProblems(list), \"the `projects` option is wrong\");\n const codegen = command === \"preview\" ? \"\" : fileURLToPath(createCodegenDir());\n entries = list.map((entry) => {\n const project = readProject(path.resolve(root, entry.project ?? \".\"), {\n binary: options.binary,\n root,\n });\n return {\n name: entry.name,\n build: entry.build,\n project,\n // An unknown build is `ascribe build`'s to report: it knows the implicit `site` build.\n siteRoot: project.siteRoot(entry.build),\n agentsRoot: project.consumer.agents ? project.plainRoot(entry.build) : undefined,\n schemaDir: named ? path.join(codegen, entry.name) : codegen,\n };\n });\n\n // What astro.config leaves unset comes from [consumer]: `site` and `trailingSlash` from the\n // first project that has them, and with one project, `base` from its base path. With\n // `projects`, `base` stays the site's, the root every base path is under.\n const { routing: astro, supplied } = supplyRouting(\n entries.map((entry) => entry.project),\n { base: config.base, trailingSlash: config.trailingSlash, site: config.site },\n !named,\n );\n // `ascribe.toml`'s routing must be Astro's, or every link Ascribe writes is wrong.\n for (const entry of entries) {\n fail(\n consumerMismatches(entry.project, astro),\n named\n ? `\"${entry.name}\"'s ascribe.toml and astro.config disagree`\n : \"ascribe.toml and astro.config disagree\",\n );\n }\n fail(basePathClashes(entries), \"two projects share a base path\");\n\n if (typeof options.review === \"string\" && !entries.some((e) => e.name === options.review)) {\n throw new Error(\n `@ascribed/astro: \\`review\\` names \"${options.review}\", and no entry of \\`projects\\` has that name.`,\n );\n }\n if (reviewFor(options.review, command)) {\n reviewed =\n typeof options.review === \"string\"\n ? entries.find((e) => e.name === options.review)\n : entries[0];\n }\n\n // Where a markdown plugin goes depends on the processor Astro 7.3 runs.\n const processor = config.markdown.processor;\n const pluginLists = processor.options as {\n rehypePlugins?: unknown[];\n hastPlugins?: unknown[];\n };\n if (processor.name === \"satteri\" && pluginLists.hastPlugins !== undefined) {\n pluginLists.hastPlugins.push(satteriAscribeAttributes());\n } else if (processor.name === \"unified\" && pluginLists.rehypePlugins !== undefined) {\n pluginLists.rehypePlugins.push(rehypeAscribeAttributes);\n } else {\n throw new Error(\n `@ascribed/astro: the markdown processor \"${processor.name}\" is not one it can add its plugin to. ` +\n \"Use Astro's default (satteri) or unified(), or add `rehypeAscribeAttributes` to your own.\",\n );\n }\n\n routing = astro;\n\n if (reviewed !== undefined) {\n addDevToolbarApp({\n id: APP_ID,\n name: \"Ascribe review\",\n icon: ICON,\n entrypoint: new URL(\"./toolbar/app.js\", import.meta.url),\n });\n }\n\n if (command !== \"preview\") {\n const found = findBinary({ binary: options.binary, root });\n binary = found;\n const buildEntry = async (entry: Entry) => {\n logger.info(\n `running ${path.basename(found)} build for \"${entry.build}\"${named ? ` (${entry.name})` : \"\"}`,\n );\n const run = {\n binary: found,\n configPath: entry.project.configPath,\n cwd: entry.project.dir,\n anchors: anchorsFor(options.anchors, command, entry === reviewed),\n };\n // `llms.txt` and each page's Markdown, which agents read.\n const plain = entry.agentsRoot === undefined ? [] : ([\"plain\"] as const);\n const result = await runBuild({\n ...run,\n build: entry.build,\n outputs: [\n \"site\",\n ...plain,\n // While review is on, the JSON output says which page is at each route.\n ...(entry === reviewed && review?.active ? ([\"json\"] as const) : []),\n ],\n });\n if (hasWarnings(result.diagnostics)) logger.warn(result.diagnostics);\n else if (result.diagnostics !== \"\") logger.info(result.diagnostics);\n if (result.summary !== \"\") logger.info(result.summary);\n // A versioned build's other lines, which the build's `versions.json` names, once the\n // current line's build has written it. An error in one fails this run as it would the\n // first; `ascribe check` reports every line's warnings, so only what was built is said.\n const older = olderLines(entry.siteRoot).map((line) => line.build);\n if (older.length > 0) {\n const lines = await runBuild({\n ...run,\n build: older,\n outputs: [\n \"site\",\n ...plain,\n ...(entry === reviewed && review?.active ? ([\"json\"] as const) : []),\n ],\n });\n if (lines.summary !== \"\") logger.info(lines.summary);\n }\n // The schema's copy inside the Astro root, for content.config.ts to import.\n mkdirSync(entry.schemaDir, { recursive: true });\n copySchema(entry.siteRoot, entry.schemaDir);\n };\n // What the projects share, which no one project's build can see.\n const checkShared = () => {\n if (entries.length < 2) return;\n const current = entries.map((entry) => ({\n ...entry,\n project: readProject(entry.project.dir, { binary: options.binary, root }),\n }));\n fail(basePathClashes(current), \"two projects share a base path\");\n fail(pagesUnderOtherPaths(current), \"a page is under another project's base path\");\n fail(\n permalinkProblems(\n current,\n current.map((entry) => readPermalinks(entry.siteRoot)),\n ),\n \"the projects' permalinks can't share one route\",\n );\n };\n // One group for each project: a change rebuilds the project it's in.\n const byDir = new Map<string, Entry[]>();\n for (const entry of entries) {\n byDir.set(entry.project.dir, [...(byDir.get(entry.project.dir) ?? []), entry]);\n }\n groups = [...byDir.values()].map((group) => ({\n project: (group[0] as Entry).project,\n entries: group,\n rebuild: async () => {\n for (const entry of group) await buildEntry(entry);\n checkShared();\n },\n }));\n // The sources as the first build reads them: the watcher may report their edits late.\n if (command === \"dev\") {\n for (const group of groups)\n seen.prime([group.project.contentRoot, group.project.configPath]);\n }\n for (const entry of entries) await buildEntry(entry);\n checkShared();\n devCommand = command === \"dev\";\n if (devCommand) {\n // A tag of the head written twice, by Head.astro and the layout, is warned about.\n (globalThis as Record<symbol, unknown>)[HEAD_WARN] = (message: string) =>\n logger.warn(message);\n addMiddleware({\n entrypoint: new URL(\"./head-check.js\", import.meta.url),\n order: \"post\",\n });\n }\n\n // Each permalink's address, a page that forwards to its heading. One route serves every\n // list, at the path of the first that names anything.\n const lists = entries.flatMap((entry) => readPermalinks(entry.siteRoot) ?? []);\n const served = lists.find(hasPermalinks) ?? lists[0];\n if (served !== undefined) {\n injectRoute({\n pattern: permalinkPattern(served.path, astro.base),\n entrypoint: new URL(\"../src/Permalink.astro\", import.meta.url),\n prerender: true,\n });\n }\n // Each permalink's help, at `<name>.json` beside its address, and each older line's\n // under the line's base path. One route for each folder: the current line's, then each\n // older line's.\n for (const pattern of helpPatterns(\n entries.map((entry) => entry.siteRoot),\n astro.base,\n )) {\n injectRoute({\n pattern,\n entrypoint: new URL(\"./help-route.js\", import.meta.url),\n prerender: true,\n });\n }\n }\n\n const projectHome = (entry: Entry) =>\n homeRoute(entry.project.consumer.basePath, astro.trailingSlash);\n // Dev serving of `_ascribe/files/`, and of the plain output for agents; the build copies them in `astro:build:done`.\n updateConfig({\n ...supplied,\n ...(options.codeTitles === false\n ? {}\n : { markdown: { shikiConfig: { transformers: [codeTitles] } } }),\n vite: {\n // `Elements.astro` is Astro source, so Vite must compile it, not load it as a Node module.\n ssr: { noExternal: [\"@ascribed/astro\"] },\n plugins: [\n {\n name: \"@ascribed/astro:site\",\n resolveId: (id) => (id === SITE_MODULE ? `\\0${SITE_MODULE}` : undefined),\n load: (id) =>\n id === `\\0${SITE_MODULE}`\n ? `export const siteRoot = ${JSON.stringify(entries[0]?.siteRoot ?? \"\")};\\n` +\n `export const astroRoot = ${JSON.stringify(root)};\\n` +\n `export const home = ${JSON.stringify(homeRoute(astro.base, astro.trailingSlash))};\\n` +\n `export const base = ${JSON.stringify(astro.base)};\\n` +\n `export const collections = ${JSON.stringify(\n named ? Object.fromEntries(entries.map((e) => [e.name, e.siteRoot])) : {},\n )};\\n` +\n `export const permalinks = ${JSON.stringify(\n entries.map((e) => ({ siteRoot: e.siteRoot, home: projectHome(e) })),\n )};\\n` +\n `export const routes = ${JSON.stringify(\n entries.map((e) => ({\n siteRoot: e.siteRoot,\n basePath: e.project.consumer.basePath,\n trailingSlash: e.project.consumer.trailingSlash,\n })),\n )};`\n : undefined,\n },\n {\n name: \"@ascribed/astro:files\",\n configureServer(server) {\n for (const entry of entries) {\n const base = entry.project.consumer.basePath;\n server.middlewares.use(filesMiddleware(entry.siteRoot, base));\n // Each older line's, at its own base path; the lines are read as each request comes.\n server.middlewares.use((req, res, next) =>\n inOrder(\n olderLines(entry.siteRoot).map((line) =>\n filesMiddleware(line.siteRoot, line.base),\n ),\n req,\n res,\n next,\n ),\n );\n if (entry.agentsRoot !== undefined) {\n const siteRoot = entry.siteRoot;\n server.middlewares.use(\n agentsMiddleware(entry.agentsRoot, base, (pathname) =>\n headersFor(siteRoot, pathname),\n ),\n );\n // Each older line's outputs for agents, at its own base path.\n server.middlewares.use((req, res, next) =>\n inOrder(\n olderLines(siteRoot).map((line) =>\n agentsMiddleware(line.plainRoot, line.base, (pathname) =>\n headersFor(line.siteRoot, pathname),\n ),\n ),\n req,\n res,\n next,\n ),\n );\n }\n }\n // The sitemap and robots.txt, as the build would write them now.\n server.middlewares.use(\n rootFilesMiddleware(astro.base, () =>\n rootFiles(\n rootSources(\n devSitePages(astroRoutes, astro),\n devRouted(astroRoutes, astro),\n ),\n ),\n ),\n );\n },\n },\n ],\n },\n });\n },\n \"astro:routes:resolved\": ({ routes }) => {\n astroRoutes = routes;\n },\n \"astro:server:setup\": ({ server, refreshContent, logger, toolbar }) => {\n if (!devCommand || !routing) return;\n if (!refreshContent)\n throw new Error(\"@ascribed/astro: this Astro version does not support refreshContent.\");\n devHttps = Boolean(server.config.server.https);\n for (const group of groups) {\n group.builds = watchDev({\n server,\n seen,\n refreshContent: () => refreshContent({}),\n logger,\n project: group.project,\n astro: routing,\n builds: group.entries.map((entry) => entry.build),\n rebuild: group.rebuild,\n ...(binary === undefined ? {} : { binary: { binary, root: group.project.dir } }),\n onBuilt: () => {\n if (reviewed !== undefined && group.entries.includes(reviewed)) review?.rebuilt();\n },\n });\n }\n const group = groups.find((g) => reviewed !== undefined && g.entries.includes(reviewed));\n if (reviewed !== undefined && group?.builds !== undefined && binary !== undefined) {\n const entry = reviewed;\n const builds = group.builds;\n const run = { binary, configPath: entry.project.configPath, cwd: entry.project.dir };\n // A versioned build is reviewed in every line, the current one first, each line's\n // routes from its own JSON output.\n const lines = () =>\n linesOf(entry.siteRoot)?.map((line) => ({\n build: line.build,\n siteRoot: line.siteRoot,\n })) ?? [{ build: entry.build, siteRoot: entry.siteRoot }];\n const lineBuilds = () => lines().map((line) => line.build);\n review = new ReviewServer({\n channel: toolbar as ToolbarChannel,\n logger,\n build: entry.build,\n contentRoot: entry.project.contentRoot,\n channelProblem: channelProblem(server.config),\n diff: (base) => runDiff({ ...run, build: lineBuilds(), base }),\n prompt: (page, base) => runPrompt({ ...run, build: lineBuilds(), base, path: page }),\n projectDir: entry.project.dir,\n connect: async () => (await import(\"./review/github.js\")).connect(entry.project.dir),\n writeRoutes: () =>\n builds.inTurn(async () => {\n await runBuild({ ...run, build: lineBuilds(), outputs: [\"json\"] });\n }),\n readRoutes: async () => {\n const all = new Map<string, RoutedPage>();\n const versioned = lines().length > 1;\n for (const line of lines()) {\n const jsonRoot = path.join(path.dirname(line.siteRoot), \"json\");\n for (const [route, page] of await readRoutes(jsonRoot)) {\n if (!all.has(route))\n all.set(route, versioned ? { ...page, build: line.build } : page);\n }\n }\n return all;\n },\n });\n }\n },\n \"astro:server:start\": ({ address, logger }) => {\n review?.listening(address.address);\n if (!devCommand) return;\n // Each project's folder gets its own file, with its own address: its base path.\n for (const group of groups) {\n const entry = group.entries[0] as Entry;\n const dir = group.project.dir;\n try {\n writeDevFile(dir, {\n url: siteUrl(address, { https: devHttps, base: entry.project.consumer.basePath }),\n build: entry.build,\n pid: process.pid,\n });\n // Vite exits on a signal before `astro:server:done` runs.\n process.once(\"exit\", () => removeDevFile(dir, process.pid));\n } catch (error) {\n logger.warn(\n `couldn't write ${groups.length > 1 ? path.join(dir, \".ascribe\", \"dev.json\") : \".ascribe/dev.json\"}, which the editor's Open Site Preview reads: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n },\n \"astro:server:done\": () => {\n review?.dispose();\n review = undefined;\n if (devCommand) for (const group of groups) removeDevFile(group.project.dir, process.pid);\n },\n \"astro:build:done\": async ({ dir, pages, logger }) => {\n const base = routing?.base ?? \"/\";\n const trailingSlash = routing?.trailingSlash ?? \"ignore\";\n // Every page Astro built, by its route from the host's root. Astro lists\n // pages only, not endpoints such as a feed, so a dot in a page's last\n // segment, as in `/v1.2`, is still a page.\n const built = pages.map((page) =>\n routeAs(`${normalizeBase(base)}${page.pathname.replace(/^\\//, \"\")}`, trailingSlash),\n );\n const builtKeys = new Set(built.map(routeKey));\n const files = rootFiles(rootSources(built, (route) => builtKeys.has(routeKey(route))));\n fail(files.problems, \"the site's robots.txt\");\n for (const note of files.notes) logger[note.level](note.text);\n const out = fileURLToPath(dir);\n if (files.sitemap !== undefined) {\n await writeFile(path.join(out, \"sitemap.xml\"), files.sitemap);\n logger.info(`wrote ${sitemapRoute(base)}`);\n }\n if (files.robots !== undefined) {\n await writeFile(path.join(out, \"robots.txt\"), files.robots);\n logger.info(\"wrote /robots.txt\");\n }\n // The host's headers, from the projects that name its format.\n const ownHeaders = path.join(publicDir, \"_headers\");\n const headers = headersOutcome({\n rules: mergeRules(\n entries\n .filter((entry) => entry.project.consumer.headers === \"netlify\")\n .flatMap((entry) =>\n [entry.siteRoot, ...olderLines(entry.siteRoot).map((line) => line.siteRoot)].map(\n (siteRoot) => readHeaders(siteRoot) ?? [],\n ),\n ),\n ),\n base,\n own: existsSync(ownHeaders) ? readFileSync(ownHeaders, \"utf8\") : undefined,\n });\n if (headers.kind === \"fail\") throw new Error(`@ascribed/astro: ${headers.text}`);\n if (headers.kind === \"note\") logger.info(headers.text);\n if (headers.kind === \"write\") {\n await writeFile(path.join(out, \"_headers\"), headers.text);\n logger.info(\"wrote /_headers\");\n }\n // Entries of one project publish at one base path: the first entry's copies go last, so they win.\n for (const entry of [...entries].reverse()) {\n const folder = folderUnder(entry.project.consumer.basePath, base);\n const where = folder === \"\" ? \"\" : ` to ${folder}`;\n if (await copyPublishedFiles(entry.siteRoot, dir, folder))\n logger.info(`copied _ascribe/files/${where}`);\n for (const line of olderLines(entry.siteRoot)) {\n const lineFolder = folderUnder(line.base, base);\n if (await copyPublishedFiles(line.siteRoot, dir, lineFolder))\n logger.info(`copied ${line.build}'s _ascribe/files/ to ${lineFolder}`);\n }\n if (\n entry.agentsRoot !== undefined &&\n (await copyAgentFiles(entry.agentsRoot, dir, folder))\n )\n logger.info(`copied llms.txt and each page's Markdown${where}`);\n if (entry.agentsRoot !== undefined) {\n for (const line of olderLines(entry.siteRoot)) {\n const lineFolder = folderUnder(line.base, base);\n if (await copyAgentFiles(line.plainRoot, dir, lineFolder))\n logger.info(\n `copied ${line.build}'s llms.txt and each page's Markdown to ${lineFolder}`,\n );\n }\n }\n }\n },\n },\n };\n}\n"]}
package/dist/project.d.ts CHANGED
@@ -25,8 +25,19 @@ export interface ProjectInfo {
25
25
  /** The plain output's root for a build: `<output-dir>/<build>/plain`. */
26
26
  plainRoot(build: string): string;
27
27
  }
28
- /** Reads `ascribe.toml` in `dir`. Throws a readable error if it can't be read. */
29
- export declare function readProject(dir: string): ProjectInfo;
28
+ /** Where to find the binary, as the integration's `binary` option and Astro's root say. */
29
+ export interface BinaryOption {
30
+ binary?: string | undefined;
31
+ root: string;
32
+ }
33
+ /**
34
+ * Reads `ascribe.toml` in `dir`. Throws a readable error if it can't be read.
35
+ * When it has `[from]`, what it takes is the other file's, which the binary
36
+ * reads: `[consumer]` and `[builds]` are then the binary's answer, from
37
+ * `ascribe model --format json`, run with the binary `binary` finds
38
+ * (`findBinary`).
39
+ */
40
+ export declare function readProject(dir: string, binary?: BinaryOption): ProjectInfo;
30
41
  /** A base path with a leading and a trailing `/`, as Ascribe's router has it. */
31
42
  export declare function normalizeBase(base: string): string;
32
43
  /**
package/dist/project.js CHANGED
@@ -1,12 +1,21 @@
1
1
  // What the integration needs from `ascribe.toml`: where a build's site output
2
2
  // goes, and the consumer settings that must agree with `astro.config`.
3
3
  // The compiler validates the whole file; this reads
4
- // only what it compiled.
4
+ // only what it compiled. A file with `[from]` takes keys from another
5
+ // project's, which only the binary follows, so then the binary is asked.
6
+ import { execFileSync } from "node:child_process";
5
7
  import { readFileSync } from "node:fs";
6
8
  import path from "node:path";
7
9
  import { parse } from "smol-toml";
8
- /** Reads `ascribe.toml` in `dir`. Throws a readable error if it can't be read. */
9
- export function readProject(dir) {
10
+ import { findBinary } from "./binary.js";
11
+ /**
12
+ * Reads `ascribe.toml` in `dir`. Throws a readable error if it can't be read.
13
+ * When it has `[from]`, what it takes is the other file's, which the binary
14
+ * reads: `[consumer]` and `[builds]` are then the binary's answer, from
15
+ * `ascribe model --format json`, run with the binary `binary` finds
16
+ * (`findBinary`).
17
+ */
18
+ export function readProject(dir, binary) {
10
19
  const configPath = path.join(dir, "ascribe.toml");
11
20
  let table;
12
21
  try {
@@ -16,7 +25,14 @@ export function readProject(dir) {
16
25
  throw new Error(`@ascribed/astro can't read ${configPath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
17
26
  }
18
27
  const project = section(table, "project");
19
- const consumer = section(table, "consumer");
28
+ let consumer = section(table, "consumer");
29
+ let builds = Object.keys(section(table, "builds"));
30
+ if (Object.keys(section(table, "from")).length > 0) {
31
+ const model = askModel(configPath, findBinary(binary ?? { root: dir }));
32
+ consumer = Object.fromEntries(model.consumer.filter((key) => key.set).map((key) => [key.key, key.value]));
33
+ if (takes(table, "builds"))
34
+ builds = model.builds.map((build) => build.name);
35
+ }
20
36
  const outputDir = typeof project["output-dir"] === "string" ? project["output-dir"] : ".ascribe/build";
21
37
  const contentDir = typeof project["content-root"] === "string" ? project["content-root"] : "docs";
22
38
  const trailingSlash = consumer["trailing-slash"] === "never" ? "never" : "always";
@@ -34,11 +50,43 @@ export function readProject(dir) {
34
50
  agents: typeof consumer["agents"] === "boolean" ? consumer["agents"] : site !== undefined,
35
51
  headers: consumer["headers"] === "netlify" ? "netlify" : undefined,
36
52
  },
37
- builds: Object.keys(section(table, "builds")),
53
+ builds,
38
54
  siteRoot: (build) => path.resolve(dir, outputDir, build, "site"),
39
55
  plainRoot: (build) => path.resolve(dir, outputDir, build, "plain"),
40
56
  };
41
57
  }
58
+ /** The content model as the binary reads it, `[from]` followed. Throws a readable error when it can't. */
59
+ function askModel(configPath, binary) {
60
+ try {
61
+ const out = execFileSync(binary, ["model", "--format", "json", "--config", configPath], {
62
+ encoding: "utf8",
63
+ maxBuffer: 64 * 1024 * 1024,
64
+ stdio: ["ignore", "pipe", "pipe"],
65
+ });
66
+ const report = JSON.parse(out);
67
+ return {
68
+ consumer: report.consumer ?? [],
69
+ builds: (report.builds ?? []).filter((build) => build.line === undefined),
70
+ };
71
+ }
72
+ catch (error) {
73
+ const stderr = error.stderr;
74
+ const detail = typeof stderr === "string" && stderr.trim() !== ""
75
+ ? stderr.trim()
76
+ : error instanceof Error
77
+ ? error.message
78
+ : String(error);
79
+ throw new Error(`@ascribed/astro can't read ${configPath}, whose [from] takes keys from another file, with \`ascribe model\`: ${detail}`, { cause: error });
80
+ }
81
+ }
82
+ /** Whether a `take` list of `[from]` names `name`, or a key in it. */
83
+ function takes(table, name) {
84
+ return Object.values(section(table, "from")).some((from) => {
85
+ const take = typeof from === "object" && from !== null ? from.take : [];
86
+ return (Array.isArray(take) &&
87
+ take.some((key) => typeof key === "string" && (key === name || key.startsWith(`${name}.`))));
88
+ });
89
+ }
42
90
  function section(table, name) {
43
91
  const value = table[name];
44
92
  return typeof value === "object" && value !== null && !Array.isArray(value)
@@ -1 +1 @@
1
- {"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"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","sourcesContent":["// What the integration needs from `ascribe.toml`: where a build's site output\n// goes, and the consumer settings that must agree with `astro.config`.\n// The compiler validates the whole file; this reads\n// only what it compiled.\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { parse } from \"smol-toml\";\n\n/** The parts of an Ascribe project the integration reads. */\nexport interface ProjectInfo {\n /** The directory holding `ascribe.toml`. */\n dir: string;\n /** The path of `ascribe.toml`. */\n configPath: string;\n /** Source files and assets watched during development. */\n contentRoot: string;\n /** Generated output, never treated as a source change. */\n outputRoot: string;\n /** `[consumer]`, with the profile's defaults. */\n consumer: {\n site: string | undefined;\n basePath: string;\n trailingSlash: \"always\" | \"never\";\n /** Whether builds publish what agents read: `llms.txt` and each page's Markdown, in the plain output. */\n agents: boolean;\n /** The host whose format the site's response headers are written in: `\"netlify\"`, or none. */\n headers: \"netlify\" | undefined;\n };\n /** The names of `[builds]`'s tables, in order: empty when there are none, and the one build is `site`. */\n builds: string[];\n /** The site output's root for a build: `<output-dir>/<build>/site`. */\n siteRoot(build: string): string;\n /** The plain output's root for a build: `<output-dir>/<build>/plain`. */\n plainRoot(build: string): string;\n}\n\n/** Reads `ascribe.toml` in `dir`. Throws a readable error if it can't be read. */\nexport function readProject(dir: string): ProjectInfo {\n const configPath = path.join(dir, \"ascribe.toml\");\n let table: Record<string, unknown>;\n try {\n table = parse(readFileSync(configPath, \"utf8\"));\n } catch (error) {\n throw new Error(\n `@ascribed/astro can't read ${configPath}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n const project = section(table, \"project\");\n const consumer = section(table, \"consumer\");\n const outputDir =\n typeof project[\"output-dir\"] === \"string\" ? project[\"output-dir\"] : \".ascribe/build\";\n const contentDir = typeof project[\"content-root\"] === \"string\" ? project[\"content-root\"] : \"docs\";\n const trailingSlash = consumer[\"trailing-slash\"] === \"never\" ? \"never\" : \"always\";\n const site = typeof consumer[\"site\"] === \"string\" ? consumer[\"site\"] : undefined;\n return {\n dir,\n configPath,\n contentRoot: path.resolve(dir, contentDir),\n outputRoot: path.resolve(dir, outputDir),\n consumer: {\n site,\n basePath: normalizeBase(\n typeof consumer[\"base-path\"] === \"string\" ? consumer[\"base-path\"] : \"/\",\n ),\n trailingSlash,\n // `true` with a site unless it says otherwise, as the binary reads it.\n agents: typeof consumer[\"agents\"] === \"boolean\" ? consumer[\"agents\"] : site !== undefined,\n headers: consumer[\"headers\"] === \"netlify\" ? \"netlify\" : undefined,\n },\n builds: Object.keys(section(table, \"builds\")),\n siteRoot: (build) => path.resolve(dir, outputDir, build, \"site\"),\n plainRoot: (build) => path.resolve(dir, outputDir, build, \"plain\"),\n };\n}\n\nfunction section(table: Record<string, unknown>, name: string): Record<string, unknown> {\n const value = table[name];\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\n/** A base path with a leading and a trailing `/`, as Ascribe's router has it. */\nexport function normalizeBase(base: string): string {\n let result = base.trim();\n if (!result.startsWith(\"/\")) result = `/${result}`;\n if (!result.endsWith(\"/\")) result += \"/\";\n return result;\n}\n\n/**\n * The route of a base path, ending the way `trailingSlash` says the site's\n * routes do: the site's root for Astro's `base`, a project's root for its\n * `[consumer] base-path`. (`import.meta.env.BASE_URL` isn't replaced in a\n * package's components.)\n */\nexport function homeRoute(base: string, trailingSlash: \"always\" | \"never\" | \"ignore\"): string {\n const root = normalizeBase(base);\n return trailingSlash === \"never\" && root !== \"/\" ? root.slice(0, -1) : root;\n}\n\n/** Astro's routing settings, as the integration reads and supplies them. */\nexport interface AstroRouting {\n base: string;\n trailingSlash: \"always\" | \"never\" | \"ignore\";\n site: string | undefined;\n}\n\n/**\n * Astro's routing with what astro.config leaves unset taken from `[consumer]`,\n * and the settings taken, for `updateConfig`. Astro gives an integration its\n * configuration with its defaults filled in, so unset is the default: no\n * `site`, `trailingSlash: \"ignore\"`, and `base: \"/\"`. `site` and\n * `trailingSlash` come from the first project that has them, since every\n * project must agree with them anyway. `base` comes from the first project's\n * `base-path` only with `supplyBase`, as with one project; with several, it\n * stays the site's, the root every base path is under. A base Astro has is\n * rewritten to end the way a supplied `trailingSlash` says, as Astro writes\n * it when the setting is its own.\n */\nexport function supplyRouting(\n projects: readonly ProjectInfo[],\n astro: AstroRouting,\n supplyBase: boolean,\n): { routing: AstroRouting; supplied: Partial<AstroRouting> } {\n const supplied: Partial<AstroRouting> = {};\n if (astro.site === undefined) {\n const site = projects.find((project) => project.consumer.site !== undefined)?.consumer.site;\n if (site !== undefined) supplied.site = site;\n }\n const first = projects[0];\n if (first === undefined) return { routing: astro, supplied };\n if (astro.trailingSlash === \"ignore\") supplied.trailingSlash = first.consumer.trailingSlash;\n const trailingSlash = supplied.trailingSlash ?? astro.trailingSlash;\n const base = homeRoute(\n supplyBase && normalizeBase(astro.base) === \"/\" ? first.consumer.basePath : astro.base,\n trailingSlash,\n );\n if (base !== astro.base) supplied.base = base;\n return { routing: { ...astro, ...supplied }, supplied };\n}\n\n/**\n * The ways `ascribe.toml`'s `[consumer]` disagrees with Astro's configuration,\n * as sentences. Ascribe writes every link with its own settings, so a site\n * whose routes differ would have broken links.\n */\nexport function consumerMismatches(\n project: ProjectInfo,\n astro: { base: string; trailingSlash: string; site: string | undefined },\n): string[] {\n const problems: string[] = [];\n const { basePath, trailingSlash, site } = project.consumer;\n // A base path under Astro's `base` leaves the rest of the site to other pages, such as a home page.\n if (!basePath.startsWith(normalizeBase(astro.base))) {\n problems.push(\n `[consumer] base-path is \"${basePath}\", but Astro's \\`base\\` is \"${astro.base}\". Set base-path to that path or a path under it.`,\n );\n }\n // Astro's \"ignore\" serves both forms, so Ascribe's links work either way.\n if (astro.trailingSlash !== \"ignore\" && astro.trailingSlash !== trailingSlash) {\n problems.push(\n `[consumer] trailing-slash is \"${trailingSlash}\", but Astro's \\`trailingSlash\\` is \"${astro.trailingSlash}\".`,\n );\n }\n if (site !== undefined && astro.site !== undefined && origin(site) !== origin(astro.site)) {\n problems.push(`[consumer] site is \"${site}\", but Astro's \\`site\\` is \"${astro.site}\".`);\n }\n return problems;\n}\n\nfunction origin(url: string): string {\n try {\n return new URL(url).origin;\n } catch {\n return url;\n }\n}\n"]}
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"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","sourcesContent":["// What the integration needs from `ascribe.toml`: where a build's site output\n// goes, and the consumer settings that must agree with `astro.config`.\n// The compiler validates the whole file; this reads\n// only what it compiled. A file with `[from]` takes keys from another\n// project's, which only the binary follows, so then the binary is asked.\nimport { execFileSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { parse } from \"smol-toml\";\nimport { findBinary } from \"./binary.js\";\n\n/** The parts of an Ascribe project the integration reads. */\nexport interface ProjectInfo {\n /** The directory holding `ascribe.toml`. */\n dir: string;\n /** The path of `ascribe.toml`. */\n configPath: string;\n /** Source files and assets watched during development. */\n contentRoot: string;\n /** Generated output, never treated as a source change. */\n outputRoot: string;\n /** `[consumer]`, with the profile's defaults. */\n consumer: {\n site: string | undefined;\n basePath: string;\n trailingSlash: \"always\" | \"never\";\n /** Whether builds publish what agents read: `llms.txt` and each page's Markdown, in the plain output. */\n agents: boolean;\n /** The host whose format the site's response headers are written in: `\"netlify\"`, or none. */\n headers: \"netlify\" | undefined;\n };\n /** The names of `[builds]`'s tables, in order: empty when there are none, and the one build is `site`. */\n builds: string[];\n /** The site output's root for a build: `<output-dir>/<build>/site`. */\n siteRoot(build: string): string;\n /** The plain output's root for a build: `<output-dir>/<build>/plain`. */\n plainRoot(build: string): string;\n}\n\n/** Where to find the binary, as the integration's `binary` option and Astro's root say. */\nexport interface BinaryOption {\n binary?: string | undefined;\n root: string;\n}\n\n/**\n * Reads `ascribe.toml` in `dir`. Throws a readable error if it can't be read.\n * When it has `[from]`, what it takes is the other file's, which the binary\n * reads: `[consumer]` and `[builds]` are then the binary's answer, from\n * `ascribe model --format json`, run with the binary `binary` finds\n * (`findBinary`).\n */\nexport function readProject(dir: string, binary?: BinaryOption): ProjectInfo {\n const configPath = path.join(dir, \"ascribe.toml\");\n let table: Record<string, unknown>;\n try {\n table = parse(readFileSync(configPath, \"utf8\"));\n } catch (error) {\n throw new Error(\n `@ascribed/astro can't read ${configPath}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n const project = section(table, \"project\");\n let consumer = section(table, \"consumer\");\n let builds = Object.keys(section(table, \"builds\"));\n if (Object.keys(section(table, \"from\")).length > 0) {\n const model = askModel(configPath, findBinary(binary ?? { root: dir }));\n consumer = Object.fromEntries(\n model.consumer.filter((key) => key.set).map((key) => [key.key, key.value]),\n );\n if (takes(table, \"builds\")) builds = model.builds.map((build) => build.name);\n }\n const outputDir =\n typeof project[\"output-dir\"] === \"string\" ? project[\"output-dir\"] : \".ascribe/build\";\n const contentDir = typeof project[\"content-root\"] === \"string\" ? project[\"content-root\"] : \"docs\";\n const trailingSlash = consumer[\"trailing-slash\"] === \"never\" ? \"never\" : \"always\";\n const site = typeof consumer[\"site\"] === \"string\" ? consumer[\"site\"] : undefined;\n return {\n dir,\n configPath,\n contentRoot: path.resolve(dir, contentDir),\n outputRoot: path.resolve(dir, outputDir),\n consumer: {\n site,\n basePath: normalizeBase(\n typeof consumer[\"base-path\"] === \"string\" ? consumer[\"base-path\"] : \"/\",\n ),\n trailingSlash,\n // `true` with a site unless it says otherwise, as the binary reads it.\n agents: typeof consumer[\"agents\"] === \"boolean\" ? consumer[\"agents\"] : site !== undefined,\n headers: consumer[\"headers\"] === \"netlify\" ? \"netlify\" : undefined,\n },\n builds,\n siteRoot: (build) => path.resolve(dir, outputDir, build, \"site\"),\n plainRoot: (build) => path.resolve(dir, outputDir, build, \"plain\"),\n };\n}\n\n/** What the integration reads of `ascribe model --format json`. */\ninterface ModelReport {\n consumer: { key: string; value?: unknown; set: boolean }[];\n builds: { name: string; line?: string }[];\n}\n\n/** The content model as the binary reads it, `[from]` followed. Throws a readable error when it can't. */\nfunction askModel(configPath: string, binary: string): ModelReport {\n try {\n const out = execFileSync(binary, [\"model\", \"--format\", \"json\", \"--config\", configPath], {\n encoding: \"utf8\",\n maxBuffer: 64 * 1024 * 1024,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n const report = JSON.parse(out) as Partial<ModelReport>;\n return {\n consumer: report.consumer ?? [],\n builds: (report.builds ?? []).filter((build) => build.line === undefined),\n };\n } catch (error) {\n const stderr = (error as { stderr?: unknown }).stderr;\n const detail =\n typeof stderr === \"string\" && stderr.trim() !== \"\"\n ? stderr.trim()\n : error instanceof Error\n ? error.message\n : String(error);\n throw new Error(\n `@ascribed/astro can't read ${configPath}, whose [from] takes keys from another file, with \\`ascribe model\\`: ${detail}`,\n { cause: error },\n );\n }\n}\n\n/** Whether a `take` list of `[from]` names `name`, or a key in it. */\nfunction takes(table: Record<string, unknown>, name: string): boolean {\n return Object.values(section(table, \"from\")).some((from) => {\n const take = typeof from === \"object\" && from !== null ? (from as { take?: unknown }).take : [];\n return (\n Array.isArray(take) &&\n take.some((key) => typeof key === \"string\" && (key === name || key.startsWith(`${name}.`)))\n );\n });\n}\n\nfunction section(table: Record<string, unknown>, name: string): Record<string, unknown> {\n const value = table[name];\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\n\n/** A base path with a leading and a trailing `/`, as Ascribe's router has it. */\nexport function normalizeBase(base: string): string {\n let result = base.trim();\n if (!result.startsWith(\"/\")) result = `/${result}`;\n if (!result.endsWith(\"/\")) result += \"/\";\n return result;\n}\n\n/**\n * The route of a base path, ending the way `trailingSlash` says the site's\n * routes do: the site's root for Astro's `base`, a project's root for its\n * `[consumer] base-path`. (`import.meta.env.BASE_URL` isn't replaced in a\n * package's components.)\n */\nexport function homeRoute(base: string, trailingSlash: \"always\" | \"never\" | \"ignore\"): string {\n const root = normalizeBase(base);\n return trailingSlash === \"never\" && root !== \"/\" ? root.slice(0, -1) : root;\n}\n\n/** Astro's routing settings, as the integration reads and supplies them. */\nexport interface AstroRouting {\n base: string;\n trailingSlash: \"always\" | \"never\" | \"ignore\";\n site: string | undefined;\n}\n\n/**\n * Astro's routing with what astro.config leaves unset taken from `[consumer]`,\n * and the settings taken, for `updateConfig`. Astro gives an integration its\n * configuration with its defaults filled in, so unset is the default: no\n * `site`, `trailingSlash: \"ignore\"`, and `base: \"/\"`. `site` and\n * `trailingSlash` come from the first project that has them, since every\n * project must agree with them anyway. `base` comes from the first project's\n * `base-path` only with `supplyBase`, as with one project; with several, it\n * stays the site's, the root every base path is under. A base Astro has is\n * rewritten to end the way a supplied `trailingSlash` says, as Astro writes\n * it when the setting is its own.\n */\nexport function supplyRouting(\n projects: readonly ProjectInfo[],\n astro: AstroRouting,\n supplyBase: boolean,\n): { routing: AstroRouting; supplied: Partial<AstroRouting> } {\n const supplied: Partial<AstroRouting> = {};\n if (astro.site === undefined) {\n const site = projects.find((project) => project.consumer.site !== undefined)?.consumer.site;\n if (site !== undefined) supplied.site = site;\n }\n const first = projects[0];\n if (first === undefined) return { routing: astro, supplied };\n if (astro.trailingSlash === \"ignore\") supplied.trailingSlash = first.consumer.trailingSlash;\n const trailingSlash = supplied.trailingSlash ?? astro.trailingSlash;\n const base = homeRoute(\n supplyBase && normalizeBase(astro.base) === \"/\" ? first.consumer.basePath : astro.base,\n trailingSlash,\n );\n if (base !== astro.base) supplied.base = base;\n return { routing: { ...astro, ...supplied }, supplied };\n}\n\n/**\n * The ways `ascribe.toml`'s `[consumer]` disagrees with Astro's configuration,\n * as sentences. Ascribe writes every link with its own settings, so a site\n * whose routes differ would have broken links.\n */\nexport function consumerMismatches(\n project: ProjectInfo,\n astro: { base: string; trailingSlash: string; site: string | undefined },\n): string[] {\n const problems: string[] = [];\n const { basePath, trailingSlash, site } = project.consumer;\n // A base path under Astro's `base` leaves the rest of the site to other pages, such as a home page.\n if (!basePath.startsWith(normalizeBase(astro.base))) {\n problems.push(\n `[consumer] base-path is \"${basePath}\", but Astro's \\`base\\` is \"${astro.base}\". Set base-path to that path or a path under it.`,\n );\n }\n // Astro's \"ignore\" serves both forms, so Ascribe's links work either way.\n if (astro.trailingSlash !== \"ignore\" && astro.trailingSlash !== trailingSlash) {\n problems.push(\n `[consumer] trailing-slash is \"${trailingSlash}\", but Astro's \\`trailingSlash\\` is \"${astro.trailingSlash}\".`,\n );\n }\n if (site !== undefined && astro.site !== undefined && origin(site) !== origin(astro.site)) {\n problems.push(`[consumer] site is \"${site}\", but Astro's \\`site\\` is \"${astro.site}\".`);\n }\n return problems;\n}\n\nfunction origin(url: string): string {\n try {\n return new URL(url).origin;\n } catch {\n return url;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ascribed/astro",
3
- "version": "0.4.2-next.29",
3
+ "version": "0.4.3",
4
4
  "description": "A toolchain for documentation written as code. This package is its Astro integration, which publishes a project's pages as a site.",
5
5
  "type": "module",
6
6
  "license": "MPL-2.0",
@@ -67,9 +67,9 @@
67
67
  "node": ">=24"
68
68
  },
69
69
  "dependencies": {
70
- "@ascribed/cli": "0.4.2-next.29",
71
- "@ascribed/elements": "0.4.2-next.29",
72
- "@ascribed/review": "0.4.2-next.29",
70
+ "@ascribed/cli": "0.4.3",
71
+ "@ascribed/elements": "0.4.3",
72
+ "@ascribed/review": "0.4.3",
73
73
  "github-slugger": "^2.0.0",
74
74
  "property-information": "^7.2.0",
75
75
  "smol-toml": "^1.9.1"
@@ -105,7 +105,6 @@
105
105
  "publishConfig": {
106
106
  "access": "public"
107
107
  },
108
- "gitHead": "dbe916f4a1448d9587e1185c32399b422da94607",
109
108
  "scripts": {
110
109
  "build": "tsc -p tsconfig.build.json",
111
110
  "typecheck": "tsc --noEmit",