@cosense-toolbox/astro 0.1.0-beta.5 → 0.1.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# @cosense-toolbox/astro
|
|
2
2
|
|
|
3
|
-
Cosense (旧 Scrapbox) の記法で書いた `.csn` / `.csnx` を、Astro
|
|
4
|
-
|
|
3
|
+
Cosense (旧 Scrapbox) の記法で書いた `.csn` / `.csnx` を、Astro のページや content collection で使うための統合です。
|
|
4
|
+
コンパイルには [`@cosense-toolbox/cosense-x`](../cosense-x) を使います。
|
|
5
|
+
|
|
6
|
+
**ドキュメント → <https://cosense-toolbox.qaynam.dev/astro/>**
|
|
5
7
|
|
|
6
8
|
> **beta**:公開 API はまだ変わりうる。
|
|
7
9
|
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/highlight.ts","../src/lint.ts","../src/vite-plugin.ts","../src/index.ts"],"mappings":";;;;;;;;;;;;;KAkBY,0CAA0C;;;;KAkG1C,qBAAqB,KAAK;;;UCxGrB;;;;;;;WAON,kBAAkB;;;;;;WAMlB;;;;UCqBM,4BAA4B,KAC3C;;;;;;;;WAgBS;;;;;;WAMA,gBAAgB;;;;UC9BV;;;;;;;WAON;;WAEA;;;;;;;;WAQA;;UAGM,kCAAkC;;;;;;;;WAQxC;;;;;;;;;;WAUA,SAAS;;;;;;;;;;;WAWT,kBAAkB;;;;;;;;WAQlB,OAAO;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/highlight.ts","../src/lint.ts","../src/vite-plugin.ts","../src/index.ts"],"mappings":";;;;;;;;;;;;;KAkBY,0CAA0C;;;;KAkG1C,qBAAqB,KAAK;;;UCxGrB;;;;;;;WAON,kBAAkB;;;;;;WAMlB;;;;UCqBM,4BAA4B,KAC3C;;;;;;;;WAgBS;;;;;;WAMA,gBAAgB;;;;UC9BV;;;;;;;WAON;;WAEA;;;;;;;;WAQA;;UAGM,kCAAkC;;;;;;;;WAQxC;;;;;;;;;;WAUA,SAAS;;;;;;;;;;;WAWT,kBAAkB;;;;;;;;WAQlB,OAAO;;iBAkFM,QAAQ,UAAS,4BAAiC"}
|
package/dist/index.mjs
CHANGED
|
@@ -450,10 +450,6 @@ const stopOnErrors = ({ errors }) => Array.match(errors, {
|
|
|
450
450
|
onEmpty: () => Effect.void,
|
|
451
451
|
onNonEmpty: (found) => Effect.fail(/* @__PURE__ */ new Error(`リンク切れが ${found.length} 件あるので、ビルドを止めた`))
|
|
452
452
|
});
|
|
453
|
-
/**
|
|
454
|
-
* 開発中は止めずに知らせるだけにする。何も無いときも 1 行出して、調べたことが分かるようにする。
|
|
455
|
-
*/
|
|
456
|
-
const noteWhenClean = (logger) => ({ errors, warnings }) => Array.isEmptyReadonlyArray([...errors, ...warnings]) ? Effect.sync(() => logger.info("リンク切れは見つからなかった")) : Effect.void;
|
|
457
453
|
/** `{base}/_cosense/`。base の末尾の `/` の有無を吸収する。 */
|
|
458
454
|
const assetsPathOf = (config) => `${config.base.replace(/\/$/, "")}/_cosense/`;
|
|
459
455
|
/** 静的なサイトでは出力先そのもの、サーバー出力ではクライアント向けの出力先に置く。 */
|
|
@@ -559,7 +555,7 @@ function cosense(options = {}) {
|
|
|
559
555
|
"astro:server:setup": ({ server, logger }) => {
|
|
560
556
|
if (lint === void 0 || astroConfig === void 0) return;
|
|
561
557
|
const config = astroConfig;
|
|
562
|
-
const check = () => Effect.runFork(
|
|
558
|
+
const check = () => Effect.runFork(reportLint(config, lint, compileOptions, logger));
|
|
563
559
|
const onChange = (file) => {
|
|
564
560
|
if (isCosenseFile(file)) check();
|
|
565
561
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["EXTENSIONS","Arr","CONTENT_TYPES","Arr"],"sources":["../src/assets.ts","../src/highlight.ts","../src/lint.ts","../src/site.ts","../src/vite-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * assets.ts — Cosense 上の画像やファイルを、ビルド時に取ってきてサイトの中に置く。\n *\n * Cosense のファイル (`/files/…`) とアイコン (`/api/pages/…/icon`) は\n * `Cross-Origin-Resource-Policy: same-origin` を返すので、別のサイトの `<img>` からは読めない。\n * リダイレクト先も期限付きの URL (`/files/` は 5 分で切れる) なので、URL を解決して埋め込むだけでは\n * 公開する頃には表示されなくなる。そのため中身を取ってきて、サイトと同じ場所に置く。\n */\nimport { createHash } from \"node:crypto\"\nimport { copyFile, mkdir, readdir, writeFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { fetchAsset, type FetchOptions, isCosenseAssetUrl } from \"@cosense-toolbox/cosense-x/fetch\"\nimport type { Root } from \"hast\"\n\n/** `globalThis` に置き場を置くときのキー (`Symbol.for` に渡す)。 */\nexport const ASSET_STORE_KEY = \"@cosense-toolbox/astro/assets\"\n\nexport interface AssetStoreOptions {\n /**\n * 取ってきたファイルを置くディレクトリ。ビルドをまたいで残し、中身の変わらないファイルは使い回す。\n * ビルドの終わりに、使ったファイルだけをここから出力先に写す\n */\n readonly cacheDir: string\n /** サイトの中で、置いたファイルを配信するパス。`/` で終わる */\n readonly publicPath: string\n /** PAT などの取得のオプション */\n readonly fetchOptions?: FetchOptions\n /**\n * リンク (`<a href>`) した Cosense のファイル (zip や PDF など) の扱い。画像 (`<img>`) は常に取ってくる。\n *\n * - `'keep'`:元の URL のまま。公開プロジェクトならクリックして開ける (CORP は画面の遷移には効かない)\n * - `'download'`:画像と同じく取ってきてサイトに置く。非公開プロジェクトのファイルはこちらでないと開けない\n *\n * @defaultValue `'keep'`\n */\n readonly links?: \"keep\" | \"download\"\n /** 取れなかったときに呼ぶ */\n readonly warn?: (message: string) => void\n}\n\nexport interface AssetStore {\n /** Cosense 上のファイルなら、取ってきて置いたサイトの中の URL を返す。それ以外はそのまま返す */\n readonly resolve: (url: string) => Promise<string>\n /** リンクした Cosense のファイル。`links: 'keep'` なら元の URL のまま返す */\n readonly resolveLink: (url: string) => Promise<string>\n /** HTML の `src` (と `links: 'download'` なら `href`) のうち、Cosense 上のファイルを指すものを差し替える */\n readonly localizeHtml: (html: string) => Promise<string>\n /** このビルドで使ったファイルだけを `dir` に写す */\n readonly copyUsedTo: (dir: string | URL) => Promise<void>\n readonly cacheDir: string\n readonly publicPath: string\n}\n\n/** Content-Type から付ける拡張子。静的なホスティングは拡張子で Content-Type を決めるため。 */\nconst EXTENSIONS: Readonly<Record<string, string>> = {\n \"image/png\": \".png\",\n \"image/jpeg\": \".jpg\",\n \"image/gif\": \".gif\",\n \"image/webp\": \".webp\",\n \"image/avif\": \".avif\",\n \"image/svg+xml\": \".svg\",\n \"image/x-icon\": \".ico\",\n \"application/pdf\": \".pdf\",\n \"video/mp4\": \".mp4\",\n \"audio/mpeg\": \".mp3\",\n}\n\n/** Content-Type で決まらなければ、元の URL の拡張子を使う。 */\nconst extensionOf = (url: string, contentType: string): string => {\n const known = EXTENSIONS[contentType.split(\";\")[0]?.trim().toLowerCase() ?? \"\"]\n if (known !== undefined) return known\n return /\\.[A-Za-z0-9]{1,5}$/.exec(new URL(url).pathname)?.[0]?.toLowerCase() ?? \"\"\n}\n\n/**\n * 元の URL のハッシュ。同じ URL は何度ビルドしても同じ名前になり、ハッシュから元の URL\n * (アップロードしたファイルの ID) は分からない。非公開プロジェクトのファイル ID を出さないため。\n */\nconst hashOf = (url: string): string => createHash(\"sha256\").update(url).digest(\"hex\").slice(0, 16)\n\nconst ICON_RE = /^\\/api\\/pages\\/[^/]+\\/(.+)\\/icon$/\n\nconst decode = (segment: string): string => {\n try {\n return decodeURIComponent(segment)\n } catch {\n return segment\n }\n}\n\n/** ファイル名や URL に使えない文字を `_` にする。日本語はそのまま残す。 */\nconst sanitize = (label: string): string =>\n label\n .replace(/[\\\\/?#%:*\"<>|\\s\\p{Cc}]+/gu, \"_\")\n .replace(/_+/g, \"_\")\n .replace(/^_|_$/g, \"\")\n .slice(0, 60)\n\n/**\n * 人が見て何のファイルか分かるよう、ハッシュのあとに付ける名前。アイコンはユーザー名\n * (ページには `<img alt>` としてもともと出ている)。アップロードしたファイルは ID を出さないので付けない。\n */\nconst labelOf = (url: string): string => {\n const title = ICON_RE.exec(new URL(url).pathname)?.[1]\n return title === undefined ? \"\" : sanitize(title.split(\"/\").map(decode).join(\"_\"))\n}\n\n/** アップロードしたファイル (`/files/…`) は中身が変わらないので、前のビルドで取ったものを使い回せる。 */\nconst isImmutable = (url: string): boolean => new URL(url).pathname.startsWith(\"/files/\")\n\nconst unescapeAttribute = (value: string): string =>\n value\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/&/g, \"&\")\n\nconst ATTRIBUTE_RE = /(\\s(src|href)=\")([^\"]*)(\")/g\n\nexport const createAssetStore = (options: AssetStoreOptions): AssetStore => {\n const fetchOptions = options.fetchOptions ?? {}\n const isAsset = (url: string) => isCosenseAssetUrl(url, fetchOptions)\n // 同じファイルを何度も取りに行かないよう、URL ごとに取得の Promise を覚えておく。\n const downloads = new Map<string, Promise<string>>()\n // このビルドで使ったファイル。出力先にはこれだけを写す。\n const used = new Set<string>()\n\n const publicUrlOf = (file: string): string => {\n used.add(file)\n return `${options.publicPath}${encodeURIComponent(file)}`\n }\n\n /** 前のビルドで置いたファイル。拡張子は取ってくるまで分からないので、ハッシュで探す。 */\n const cachedFileOf = async (base: string): Promise<string | undefined> => {\n const files = await readdir(options.cacheDir).catch(() => [])\n return files.find((file) => file === base || file.startsWith(`${base}.`))\n }\n\n const download = async (url: string): Promise<string> => {\n const label = labelOf(url)\n const base = label === \"\" ? hashOf(url) : `${hashOf(url)}_${label}`\n try {\n const cached = isImmutable(url) ? await cachedFileOf(base) : undefined\n if (cached !== undefined) return publicUrlOf(cached)\n const asset = await fetchAsset(url, fetchOptions)\n const file = `${base}${extensionOf(url, asset.contentType)}`\n await mkdir(options.cacheDir, { recursive: true })\n await writeFile(join(options.cacheDir, file), asset.data)\n return publicUrlOf(file)\n } catch (error) {\n // 1 つの画像のためにビルド全体を止めない。元の URL のまま出し、表示されないことを知らせる。\n options.warn?.(`${url} を取得できないので、元の URL のまま出す: ${String(error)}`)\n return url\n }\n }\n\n const resolve = (url: string): Promise<string> => {\n if (!isAsset(url)) return Promise.resolve(url)\n const cached = downloads.get(url) ?? download(url)\n downloads.set(url, cached)\n return cached\n }\n\n const resolveLink = (url: string): Promise<string> =>\n options.links === \"download\" ? resolve(url) : Promise.resolve(url)\n\n const resolveAttribute = (name: string, url: string): Promise<string> =>\n name === \"href\" ? resolveLink(url) : resolve(url)\n\n const localizeHtml = async (html: string): Promise<string> => {\n const targets = [...html.matchAll(ATTRIBUTE_RE)]\n .map((match) => [match[2] ?? \"\", unescapeAttribute(match[3] ?? \"\")] as const)\n .filter(([, url]) => isAsset(url))\n const resolved = new Map(\n await Promise.all(\n targets.map(\n async ([name, url]) => [`${name} ${url}`, await resolveAttribute(name, url)] as const,\n ),\n ),\n )\n // サイトの中の URL はエンコード済みなので、属性値としてエスケープの要る文字を含まない。\n return html.replace(\n ATTRIBUTE_RE,\n (whole, open: string, name: string, value: string, close: string) => {\n const local = resolved.get(`${name} ${unescapeAttribute(value)}`)\n return local === undefined ? whole : `${open}${local}${close}`\n },\n )\n }\n\n const copyUsedTo = async (dir: string | URL): Promise<void> => {\n const target = dir instanceof URL ? fileURLToPath(dir) : dir\n await mkdir(target, { recursive: true })\n await Promise.all(\n [...used].map((file) => copyFile(join(options.cacheDir, file), join(target, file))),\n )\n }\n\n return {\n resolve,\n resolveLink,\n localizeHtml,\n copyUsedTo,\n cacheDir: options.cacheDir,\n publicPath: options.publicPath,\n }\n}\n\ninterface HastLike {\n readonly type?: string\n readonly tagName?: string\n readonly properties?: Record<string, unknown>\n readonly children?: readonly HastLike[]\n readonly fallback?: HastLike | null\n readonly fallbackEnd?: HastLike | null\n}\n\n/** `img` の `src` と `a` の href。書き換えられるよう、要素とプロパティ名の組で返す。 */\nconst referencesIn = (node: HastLike): (readonly [Record<string, unknown>, \"src\" | \"href\"])[] => {\n const own =\n node.type === \"element\" && node.properties !== undefined\n ? node.tagName === \"img\"\n ? [[node.properties, \"src\"] as const]\n : node.tagName === \"a\"\n ? [[node.properties, \"href\"] as const]\n : []\n : []\n // コンポーネントのノードは、渡されなかったときに出す元の行 (fallback) も持つ。\n const nested = [...(node.children ?? []), node.fallback, node.fallbackEnd].filter(\n (child): child is HastLike => child !== null && child !== undefined,\n )\n return [...own, ...nested.flatMap(referencesIn)]\n}\n\n/** `.csn` / `.csnx` の hast の中で、Cosense 上のファイルを指す URL を差し替える rehype プラグイン。 */\nexport const rehypeCosenseAssets = (store: AssetStore) => () => async (tree: Root) => {\n await Promise.all(\n referencesIn(tree as HastLike).map(async ([properties, key]) => {\n const value = properties[key]\n // hast は要素のプロパティをその場で書き換えるのが決まりなので、ここでも書き換える。\n if (typeof value !== \"string\") return\n properties[key] = key === \"href\" ? await store.resolveLink(value) : await store.resolve(value)\n }),\n )\n}\n","/**\n * highlight.ts — コードブロックを、Astro の Markdown と同じ shiki の設定で色付けする。\n *\n * `.md` / `.mdx` のコードブロックと見た目を揃えるため、`markdown.syntaxHighlight` と\n * `markdown.shikiConfig` をそのまま使う。\n */\nimport type { HastHighlighter, RenderOptions } from \"@cosense-toolbox/cosense-x\"\nimport { codeLanguageOf } from \"@cosense-toolbox/parser/html\"\nimport type { AstroConfig } from \"astro\"\nimport { Effect, Match, Option, pipe } from \"effect\"\nimport { type BundledLanguage, bundledLanguages, createHighlighter } from \"shiki\"\n\ntype MarkdownConfig = AstroConfig[\"markdown\"]\n\n/**\n * `.csn` / `.csnx` のコードブロックの色付け。\n * `'astro'` は `markdown.syntaxHighlight` / `markdown.shikiConfig` に従い、関数なら自分で色付けする。\n */\nexport type SyntaxHighlightOption = \"astro\" | false | HastHighlighter\n\n/**\n * `source` のコードブロックの言語を読み込んでから、色付けする関数を返す。\n * `compile` は色付けを同期で呼ぶので、言語は先に読み込んでおく。\n */\nexport type CodeHighlighter = (source: string) => Promise<HastHighlighter>\n\n/** 行頭 (字下げの後) の `code:ファイル名` からコードブロックを見つける。 */\nconst CODE_BLOCK = /^[ \\t]*code:(.+)$/gm\n\n/** ページに出てくるコードブロックの言語名。`highlight` に渡るのと同じ決め方。 */\nexport const codeLanguagesIn = (source: string): string[] => [\n ...new Set(\n [...source.matchAll(CODE_BLOCK)].map((match) => codeLanguageOf((match[1] ?? \"\").trim())),\n ),\n]\n\n/** shiki を使う設定なら、色付けしない言語 (`excludeLangs`) の一覧。shiki を使わない設定なら None。 */\nconst shikiExclusionsOf = (\n setting: MarkdownConfig[\"syntaxHighlight\"],\n): Option.Option<readonly string[]> =>\n Match.value(setting).pipe(\n Match.when(\"shiki\", () => Option.some([])),\n Match.when({ type: \"shiki\" }, (config) => Option.some(config.excludeLangs ?? [])),\n Match.orElse(() => Option.none()),\n )\n\ntype Shiki = Awaited<ReturnType<typeof createHighlighter>>\n\n/**\n * Astro の Markdown の設定で色付けする。shiki を使わない設定 (`false` や `'prism'`) なら undefined。\n * prism には相当するものが無いので、色付けしない。\n */\nexport const astroShikiHighlighter = (markdown: MarkdownConfig): CodeHighlighter | undefined =>\n pipe(\n shikiExclusionsOf(markdown.syntaxHighlight),\n Option.map((excluded) => shikiHighlighter(markdown.shikiConfig, new Set(excluded))),\n Option.getOrUndefined,\n )\n\nconst shikiHighlighter = (\n { langs, langAlias, theme, themes, defaultColor, transformers }: MarkdownConfig[\"shikiConfig\"],\n excluded: ReadonlySet<string>,\n): CodeHighlighter => {\n const multiple = Object.keys(themes).length > 0\n const themed = multiple\n ? { themes, ...(defaultColor === undefined ? {} : { defaultColor }) }\n : { theme }\n // 最初に色付けするときに 1 度だけ作る。色付けしないサイトで shiki を読み込まないため。\n const shiki = Effect.runSync(\n Effect.cached(\n Effect.promise(() =>\n createHighlighter({ themes: multiple ? Object.values(themes) : [theme], langs }),\n ),\n ),\n )\n const resolve = (language: string): string =>\n Option.getOrElse(Option.fromNullable(langAlias[language]), () => language)\n\n /** ページに出てくる言語のうち、読み込んでいないものを読み込む。shiki が知らない言語は飛ばす。 */\n const loadLanguagesIn = (source: string) => (highlighter: Shiki) => {\n const loaded = new Set(highlighter.getLoadedLanguages())\n const wanted = codeLanguagesIn(source)\n .map(resolve)\n .filter((language) => !excluded.has(language) && !loaded.has(language))\n .filter((language): language is BundledLanguage => language in bundledLanguages)\n return pipe(\n Effect.promise(() => highlighter.loadLanguage(...wanted)),\n Effect.when(() => wanted.length > 0),\n )\n }\n\n /** 読み込めた言語だけを色付けする。知らない言語は null (色付けせず 1 行ずつのまま) にする。 */\n const highlightWith = (highlighter: Shiki): HastHighlighter => {\n const available = new Set(highlighter.getLoadedLanguages())\n return (code, language) =>\n pipe(\n Option.some(resolve(language)),\n Option.filter((lang) => !excluded.has(lang) && available.has(lang)),\n Option.map((lang) => highlighter.codeToHast(code, { lang, ...themed, transformers })),\n Option.getOrNull,\n )\n }\n\n return (source) =>\n pipe(shiki, Effect.tap(loadLanguagesIn(source)), Effect.map(highlightWith), Effect.runPromise)\n}\n\n/** 利用者が渡した色付けをそのまま使う。 */\nexport const customHighlighter =\n (highlight: HastHighlighter): CodeHighlighter =>\n async () =>\n highlight\n\n/**\n * 利用者が統合に渡す描画の設定。色付けは統合が `syntaxHighlight` から作って渡すので含めない。\n */\nexport type AstroRenderOptions = Omit<RenderOptions, \"highlight\">\n\n/**\n * 利用者の `renderOptions` に、統合が作った色付けを足す。色付けしない設定なら何も足さない。\n */\nexport const renderOptionsWith = (\n renderOptions: AstroRenderOptions | undefined,\n highlight: Option.Option<HastHighlighter>,\n): RenderOptions =>\n pipe(\n highlight,\n Option.match({\n onNone: (): RenderOptions => ({ ...renderOptions }),\n onSome: (value): RenderOptions => ({ ...renderOptions, highlight: value }),\n }),\n )\n","/**\n * lint.ts — ビルドの前に、サイトのページのリンク切れを調べる。\n *\n * 判定は `@cosense-toolbox/lsp` の `checkSite` をそのまま使う。エディタの診断と\n * `csn-lsp check` と同じ関数なので、エディタで警告されるものとビルドで止まるものが一致する。\n */\nimport { relative, sep } from \"node:path\"\n\nimport { checkSite, type CheckSiteOptions, type Report } from \"@cosense-toolbox/lsp/check\"\nimport type { ParseOptions } from \"@cosense-toolbox/parser\"\nimport { Array as Arr, Effect } from \"effect\"\n\nexport interface CosenseLintOptions {\n /**\n * サイトに無いページへのリンクの知らせ方。`'error'` ならビルドを止める。\n * `'off'` / `'hint'` / `'information'` / `'warning'` / `'error'`。\n *\n * @defaultValue `'warning'`\n */\n readonly unresolvedLinks?: CheckSiteOptions[\"unresolvedLinks\"]\n /**\n * 1 行目の `---` を frontmatter (YAML) として飛ばすか。\n *\n * @defaultValue `true`\n */\n readonly frontmatter?: boolean\n}\n\n/** 見つかったもの。`errors` があればビルドを止める。 */\nexport interface LintResult {\n readonly errors: ReadonlyArray<string>\n readonly warnings: ReadonlyArray<string>\n}\n\n/** `path:line:column message`。path はプロジェクトのルートから。 */\nconst messageOf =\n (root: string) =>\n ({ path, line, column, message }: Report): string =>\n `${relative(root, path).split(sep).join(\"/\")}:${line}:${column} ${message}`\n\n/**\n * `srcDir` の下の `.csn` / `.csnx` を読み、リンク切れを調べる。\n * パースにはサイトの `parseOptions` を使うので、独自の装飾記法もビルドと同じに読む。\n */\nexport const lintSite = (\n root: string,\n srcDir: string,\n { unresolvedLinks = \"warning\", frontmatter = true }: CosenseLintOptions,\n parseOptions: ParseOptions = {},\n): Effect.Effect<LintResult> =>\n Effect.map(\n checkSite({ roots: [srcDir], unresolvedLinks, parseOptions, frontmatter }),\n (reports) => {\n const [warnings, errors] = Arr.partition(reports, ({ level }) => level === \"error\")\n return {\n errors: Arr.map(errors, messageOf(root)),\n warnings: Arr.map(warnings, messageOf(root)),\n }\n },\n )\n","/**\n * site.ts — プロジェクトの `.csn` / `.csnx` を全部読み、索引とリンクグラフを作る。\n *\n * リンクの解決には全ページのタイトルが要るので、1 ファイルずつのコンパイルの前にまとめて読む。\n * パースは軽いので、全ページを先読みしても問題にならない。\n */\nimport { readdir, readFile } from \"node:fs/promises\"\nimport { join, relative, sep } from \"node:path\"\n\nimport {\n buildGraph,\n createIndex,\n type Graph,\n type PageIndex,\n type ReadOptions,\n readPage,\n} from \"@cosense-toolbox/cosense-x/graph\"\n\nexport const EXTENSIONS = [\".csn\", \".csnx\"] as const\n\nexport const isCosenseFile = (path: string): boolean =>\n EXTENSIONS.some((extension) => path.endsWith(extension))\n\n/** ルートからの相対パス (区切りは `/`)。Astro の content collection の `filePath` と同じ形。 */\nexport const idOf = (root: string, absolute: string): string =>\n relative(root, absolute).split(sep).join(\"/\")\n\nexport interface Site {\n readonly index: PageIndex\n readonly graph: Graph\n}\n\nconst SKIP_DIRECTORIES = new Set([\"node_modules\", \".astro\", \"dist\"])\n\n/** `directory` の下の `.csn` / `.csnx`。読めないディレクトリ (まだ無い src/content など) は空とみなす。 */\nconst listFiles = async (directory: string): Promise<string[]> => {\n const entries = await readdir(directory, { withFileTypes: true }).catch(() => [])\n const nested = await Promise.all(\n entries.map(async (entry) => {\n const path = join(directory, entry.name)\n if (entry.isDirectory()) return SKIP_DIRECTORIES.has(entry.name) ? [] : listFiles(path)\n return entry.isFile() && isCosenseFile(entry.name) ? [path] : []\n }),\n )\n return nested.flat().sort()\n}\n\n/** `directory` の下を読んで、索引とグラフを作る。id は `root` からの相対パス。 */\nexport const scanSite = async (\n root: string,\n directory: string,\n options: Pick<ReadOptions, \"parseOptions\"> = {},\n): Promise<Site> => {\n const files = await listFiles(directory)\n const sources = await Promise.all(\n files.map(async (file) => ({ id: idOf(root, file), source: await readFile(file, \"utf8\") })),\n )\n const pages = sources.map(({ id, source }) => ({\n id,\n metadata: readPage(source, { ...options, filePath: id }).metadata,\n }))\n const index = createIndex(\n pages.map(({ id, metadata }) => ({\n id,\n title: metadata.title,\n slug: metadata.slug,\n draft: metadata.draft,\n })),\n )\n return { index, graph: buildGraph(pages) }\n}\n\n/** 索引とグラフを 1 つだけ持ち、Vite のプラグインと content collection で使い回す。 */\nexport interface SiteCache {\n readonly get: () => Promise<Site>\n /** ファイルが変わったときに捨てる。次の `get` で読み直す */\n readonly reset: () => void\n}\n\nexport const createSiteCache = (\n root: string,\n directory: string,\n options: Pick<ReadOptions, \"parseOptions\"> = {},\n): SiteCache => {\n // dev サーバーでファイルが変わるたびに捨てて読み直すので、ここだけは状態を持つ。\n // モジュールのトップレベルではなく、統合ごとに作るこの関数の中に閉じ込めている。\n let site: Promise<Site> | undefined\n return {\n get: () => {\n site ??= scanSite(root, directory, options)\n return site\n },\n reset: () => {\n site = undefined\n },\n }\n}\n","/**\n * vite-plugin.ts — `.csn` / `.csnx` を Astro のコンポーネントのモジュールにする。\n */\nimport { createReadStream } from \"node:fs\"\nimport { stat } from \"node:fs/promises\"\nimport { basename, extname, join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { compile, type CompileOptions } from \"@cosense-toolbox/cosense-x\"\nimport { Option } from \"effect\"\nimport type { Plugin } from \"vite\"\n\nimport { ASSET_STORE_KEY, type AssetStore } from \"./assets\"\nimport { type AstroRenderOptions, type CodeHighlighter, renderOptionsWith } from \"./highlight\"\nimport { idOf, isCosenseFile, type SiteCache } from \"./site\"\n\nexport const GRAPH_MODULE_ID = \"virtual:cosense-x/graph\"\nconst RESOLVED_GRAPH_MODULE_ID = `\\0${GRAPH_MODULE_ID}`\nexport const ASSETS_MODULE_ID = \"virtual:cosense-x/assets\"\nconst RESOLVED_ASSETS_MODULE_ID = `\\0${ASSETS_MODULE_ID}`\n\n/**\n * `toHtml` などで自分で描画するページから、Cosense 上のファイルを置くための関数。\n * 置き場は統合が作って `globalThis` に置いたものを使う。ページの描画はビルドでも dev でも\n * 統合と同じプロセスで走るので、PAT をモジュールのコードに埋め込まずに済む。\n * 置き場が無いとき (実行時に描画する SSR など) は、元の URL のまま返す。\n */\nconst ASSETS_MODULE = `const store = () => globalThis[Symbol.for(${JSON.stringify(ASSET_STORE_KEY)})];\nexport const cosenseAsset = (url) => store()?.resolve(url) ?? Promise.resolve(url);\nexport const localizeCosenseAssets = (html) => store()?.localizeHtml(html) ?? Promise.resolve(html);\n`\n\n/** dev サーバーで返す Content-Type。ビルドでは静的なホスティングが拡張子から決める。 */\nconst CONTENT_TYPES: Readonly<Record<string, string>> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".pdf\": \"application/pdf\",\n \".mp4\": \"video/mp4\",\n \".mp3\": \"audio/mpeg\",\n}\n\nexport interface AstroCompileOptions extends Omit<\n CompileOptions,\n | \"filePath\"\n | \"format\"\n | \"index\"\n | \"jsxImportSource\"\n | \"elementAttributeNameCase\"\n | \"renderOptions\"\n | \"unresolved\"\n> {\n /**\n * サイトに無いページへのリンクの出し方。`'text'` はテキストにする (非公開のページの名前が\n * URL に漏れない)。`'link'` はタイトルから作った URL へのリンクにする。\n * リンク切れを知らせるのは `lint` の役目。\n *\n * @defaultValue `'text'`\n */\n readonly unresolvedLinks?: \"text\" | \"link\"\n /**\n * 描画の設定。parser の `toHast` のオプションがそのまま渡る\n * (`extensions` / `handlers` / `classNames` / `showPads` / `iconImageUrl` / `title`)。\n * コードブロックの色付けは `syntaxHighlight` で決める。\n */\n readonly renderOptions?: AstroRenderOptions\n}\n\n/** 統合の compile の設定を、`compile` が受け取る形にする。 */\nexport const compileOptionsOf = ({\n unresolvedLinks,\n ...rest\n}: AstroCompileOptions): Omit<AstroCompileOptions, \"unresolvedLinks\"> &\n Pick<CompileOptions, \"unresolved\"> =>\n Option.match(Option.fromNullable(unresolvedLinks), {\n onNone: () => rest,\n onSome: (unresolved) => ({ ...rest, unresolved }),\n })\n\nexport interface VitePluginOptions {\n readonly root: URL\n /** 索引とグラフ。content collection の読み込みと共有する */\n readonly site: SiteCache\n readonly compile: AstroCompileOptions\n /** すべてのページに渡すコンポーネントを default export するモジュールの絶対パス */\n readonly components: string | undefined\n /** Cosense 上のファイルの置き場。無効にしたときは undefined */\n readonly assets: AssetStore | undefined\n /** コードブロックの色付け。色付けしないときは undefined */\n readonly highlighter: CodeHighlighter | undefined\n}\n\n/**\n * `@astrojs/mdx` と同じ形に整える。`Content` を default export にし、\n * Astro がそれを `astro:jsx` のコンポーネントとして描画できるよう印を付ける。\n */\nconst toAstroModule = (\n code: string,\n id: string,\n options: { components: string | undefined; layout: string | undefined; ssr: boolean },\n): string => {\n const { components, layout, ssr } = options\n const content =\n layout === undefined\n ? [\"export const Content = (props = {}) => __cosenseBody(props);\"]\n : // src/pages に置いたページを包むレイアウト。`.mdx` の `layout` と同じく、\n // 本文を default のスロットに入れ、frontmatter などを props で渡す。\n [\n `import __CosenseLayout from ${JSON.stringify(layout)};`,\n \"import { jsx as __cosenseJsx } from 'astro/jsx-runtime';\",\n \"export const Content = (props = {}) => __cosenseJsx(__CosenseLayout, {\",\n \" file, frontmatter, metadata,\",\n \" children: __cosenseBody(props),\",\n \"});\",\n ]\n const tag = ssr\n ? [\n \"import { __astro_tag_component__ } from 'astro/runtime/server/index.js';\",\n \"__astro_tag_component__(Content, 'astro:jsx');\",\n ]\n : []\n return [\n code.replace(\"export default function CosenseContent\", \"function CosenseContent\"),\n components === undefined\n ? \"const __cosenseComponents = {};\"\n : `import __cosenseComponents from ${JSON.stringify(components)};`,\n `export const file = ${JSON.stringify(id)};`,\n \"const __cosenseBody = (props) => CosenseContent({\",\n \" ...props,\",\n \" components: { ...__cosenseComponents, ...props.components },\",\n \"});\",\n ...content,\n \"export default Content;\",\n \"Content[Symbol.for('mdx-component')] = true;\",\n // レイアウトがあれば <head> はレイアウトが出す。無ければ Astro に出させる。\n `Content[Symbol.for('astro.needsHeadRendering')] = ${layout === undefined};`,\n `Content.moduleId = ${JSON.stringify(id)};`,\n ...tag,\n ].join(\"\\n\")\n}\n\nexport const vitePluginCosense = (options: VitePluginOptions): Plugin => {\n const root = fileURLToPath(options.root)\n const loadSite = options.site.get\n\n return {\n name: \"@cosense-toolbox/astro\",\n enforce: \"pre\",\n\n resolveId(id) {\n if (id === GRAPH_MODULE_ID) return RESOLVED_GRAPH_MODULE_ID\n if (id === ASSETS_MODULE_ID) return RESOLVED_ASSETS_MODULE_ID\n return undefined\n },\n\n async load(id) {\n if (id === RESOLVED_ASSETS_MODULE_ID) return ASSETS_MODULE\n if (id !== RESOLVED_GRAPH_MODULE_ID) return undefined\n const { graph } = await loadSite()\n return `export const graph = ${JSON.stringify(graph)};\\nexport default graph;`\n },\n\n transform: {\n filter: { id: /\\.csnx?$/ },\n async handler(code, id) {\n const { index } = await loadSite()\n const highlight = Option.fromNullable(await options.highlighter?.(code))\n const result = await compile(code, {\n ...compileOptionsOf(options.compile),\n renderOptions: renderOptionsWith(options.compile.renderOptions, highlight),\n filePath: idOf(root, id),\n index,\n jsxImportSource: \"astro\",\n })\n for (const warning of result.warnings) this.warn(warning)\n const ssr = this.environment.name === \"ssr\" || this.environment.name === \"prerender\"\n const layout = result.frontmatter.layout\n return {\n code: toAstroModule(result.code, id, {\n components: options.components,\n layout: typeof layout === \"string\" ? layout : undefined,\n ssr,\n }),\n map: null,\n }\n },\n },\n\n // 1 ページの変更で、ほかのページのリンク先やグラフも変わりうる。\n // 索引を作り直し、関わるモジュールをすべて捨てて再読み込みする。\n configureServer(server) {\n // dev では、取ってきたファイルを置き場のディレクトリから返す。ビルドでは出力先に写す。\n const assets = options.assets\n if (assets !== undefined) {\n server.middlewares.use(assets.publicPath, async (request, response, next) => {\n // アイコンの名前は日本語を含みうるので、URL のエンコードを戻す。basename で置き場の外は読ませない。\n const name = (() => {\n try {\n return decodeURIComponent(basename(request.url?.split(\"?\")[0] ?? \"\"))\n } catch {\n return \"\"\n }\n })()\n const file = join(assets.cacheDir, basename(name))\n const found = await stat(file)\n .then((s) => s.isFile())\n .catch(() => false)\n if (!found) {\n next()\n return\n }\n const type = CONTENT_TYPES[extname(file)]\n if (type !== undefined) response.setHeader(\"content-type\", type)\n createReadStream(file).pipe(response)\n })\n }\n\n const onChange = (file: string) => {\n if (!isCosenseFile(file)) return\n options.site.reset()\n for (const environment of Object.values(server.environments)) {\n const graph = environment.moduleGraph\n for (const [id, module] of graph.idToModuleMap) {\n if (id === RESOLVED_GRAPH_MODULE_ID || isCosenseFile(id.split(\"?\")[0] ?? \"\")) {\n graph.invalidateModule(module)\n }\n }\n }\n server.ws.send({ type: \"full-reload\" })\n }\n server.watcher.on(\"add\", onChange)\n server.watcher.on(\"change\", onChange)\n server.watcher.on(\"unlink\", onChange)\n },\n }\n}\n","/**\n * `@cosense-toolbox/astro` — `.csn` / `.csnx` を Astro のページと content collection で使う。\n *\n * ```js\n * // astro.config.mjs\n * import cosense from '@cosense-toolbox/astro'\n * export default defineConfig({\n * integrations: [cosense({ pageUrl: (page) => `/posts/${page.slug}` })],\n * })\n * ```\n */\nimport { fileURLToPath } from \"node:url\"\n\nimport { readPage } from \"@cosense-toolbox/cosense-x/graph\"\nimport type {\n AstroConfig,\n AstroIntegration,\n AstroIntegrationLogger,\n ContentEntryType,\n HookParameters,\n} from \"astro\"\nimport { Array as Arr, Effect, pipe } from \"effect\"\n\nimport { ASSET_STORE_KEY, type AssetStore, createAssetStore, rehypeCosenseAssets } from \"./assets\"\nimport {\n astroShikiHighlighter,\n type CodeHighlighter,\n customHighlighter,\n type SyntaxHighlightOption,\n} from \"./highlight\"\nimport { type CosenseLintOptions, type LintResult, lintSite } from \"./lint\"\nimport { createSiteCache, EXTENSIONS, idOf, isCosenseFile } from \"./site\"\nimport {\n ASSETS_MODULE_ID,\n type AstroCompileOptions,\n GRAPH_MODULE_ID,\n vitePluginCosense,\n} from \"./vite-plugin\"\n\nexport interface CosenseAssetsOptions {\n /**\n * Cosense の Personal Access Token。非公開プロジェクトの画像を取ってくるときに渡す。\n * Cosense への要求にだけ付け、リダイレクト先 (Google Cloud Storage や Gyazo) には送らない。\n *\n * @example `process.env.COSENSE_PAT`\n */\n readonly pat?: string\n /** Cosense の origin。 @defaultValue `https://scrapbox.io` */\n readonly origin?: string\n /**\n * リンクした Cosense のファイル (`[https://scrapbox.io/files/x.zip]` など) の扱い。画像は常に取ってくる。\n * `'keep'` は元の URL のまま (公開プロジェクトならクリックで開ける)、`'download'` は取ってきてサイトに置く。\n * 非公開プロジェクトのファイルは `'download'` でないと、見に来た人が開けない。\n *\n * @defaultValue `'keep'`\n */\n readonly links?: \"keep\" | \"download\"\n}\n\nexport interface CosenseIntegrationOptions extends AstroCompileOptions {\n /**\n * すべてのページに渡すコンポーネントを default export するモジュール (プロジェクトのルートからのパス)。\n * `.csnx` の `<Name />` や、`a` などの要素の差し替えに使う。\n * `<Content components={...} />` で渡したものがあれば、そちらが優先する。\n *\n * @example `'./src/components/cosense.ts'`\n */\n readonly components?: string\n /**\n * Cosense 上の画像やファイル (`/files/…` とアイコン) を、ビルド時に取ってきてサイトの中\n * (`{base}/_cosense/`) に置く。`false` なら元の URL のまま出す。\n *\n * Cosense のファイルは別のサイトからは読めず、リダイレクト先の URL も数分で切れるので、\n * 静的なサイトで表示するにはこうするしかない。非公開プロジェクトの画像も公開されることになる点に注意。\n *\n * @defaultValue `{}` (有効)\n */\n readonly assets?: CosenseAssetsOptions | false\n /**\n * コードブロックの色付け。\n *\n * - `'astro'`: `.md` / `.mdx` と同じく、Astro の `markdown.syntaxHighlight` と `markdown.shikiConfig` に従う。\n * shiki のときだけ色付けし、prism には対応していない\n * - `false`: 色付けしない\n * - 関数: `(code, language) => hast | null` で自分で色付けする\n *\n * @defaultValue `'astro'`\n */\n readonly syntaxHighlight?: SyntaxHighlightOption\n /**\n * ビルドの前に、`srcDir` の下のページのリンク切れを調べる。エディタの診断\n * (`@cosense-toolbox/lsp`) と同じ判定で、`unresolvedLinks: 'error'` ならビルドを止める。\n * 省略すると調べない。\n *\n * @example `{ unresolvedLinks: 'error' }`\n */\n readonly lint?: CosenseLintOptions\n}\n\n/** サイトのリンク切れを調べ、見つかったものをログに出す。 */\nconst reportLint = (\n config: AstroConfig,\n lint: CosenseLintOptions,\n compileOptions: AstroCompileOptions,\n logger: AstroIntegrationLogger,\n): Effect.Effect<LintResult> =>\n pipe(\n lintSite(\n fileURLToPath(config.root),\n fileURLToPath(config.srcDir),\n lint,\n compileOptions.parseOptions,\n ),\n Effect.tap(({ errors, warnings }) =>\n Effect.all([\n Effect.forEach(warnings, (warning) => Effect.sync(() => logger.warn(warning))),\n Effect.forEach(errors, (error) => Effect.sync(() => logger.error(error))),\n ]),\n ),\n )\n\n/** ビルドでは、error があれば失敗してビルドを止める。 */\nconst stopOnErrors = ({ errors }: LintResult): Effect.Effect<void, Error> =>\n Arr.match(errors, {\n onEmpty: () => Effect.void,\n onNonEmpty: (found) =>\n Effect.fail(new Error(`リンク切れが ${found.length} 件あるので、ビルドを止めた`)),\n })\n\n/**\n * 開発中は止めずに知らせるだけにする。何も無いときも 1 行出して、調べたことが分かるようにする。\n */\nconst noteWhenClean =\n (logger: AstroIntegrationLogger) =>\n ({ errors, warnings }: LintResult): Effect.Effect<void> =>\n Arr.isEmptyReadonlyArray([...errors, ...warnings])\n ? Effect.sync(() => logger.info(\"リンク切れは見つからなかった\"))\n : Effect.void\n\n/** `{base}/_cosense/`。base の末尾の `/` の有無を吸収する。 */\nconst assetsPathOf = (config: AstroConfig): string => `${config.base.replace(/\\/$/, \"\")}/_cosense/`\n\n/** 静的なサイトでは出力先そのもの、サーバー出力ではクライアント向けの出力先に置く。 */\nconst assetsDirOf = (config: AstroConfig, dir: URL): URL =>\n new URL(\"_cosense/\", config.output === \"static\" ? dir : config.build.client)\n\n/**\n * `astro:config:setup` の引数のうち、型定義に載っていないもの。\n * `@astrojs/mdx` も使っている、ページの拡張子と content collection の形式を足す口。\n */\ninterface HiddenSetupHooks {\n readonly addPageExtension: (extension: string) => void\n readonly addContentEntryType: (contentEntryType: ContentEntryType) => void\n}\n\nconst CONTENT_MODULE_TYPES = EXTENSIONS.map(\n (extension) => ` '${extension}': Promise<{ Content: import('astro').MDXContent }>;`,\n)\n\nconst CONTENT_TYPES = `declare module 'astro:content' {\n interface Render {\n${CONTENT_MODULE_TYPES.join(\"\\n\")}\n }\n}\n`\n\nconst INJECTED_TYPES = `declare module '${GRAPH_MODULE_ID}' {\n export const graph: import('@cosense-toolbox/cosense-x/graph').Graph;\n export default graph;\n}\ndeclare module '${ASSETS_MODULE_ID}' {\n /** Cosense 上のファイルなら、ビルド時に取ってきて置いたサイトの中の URL を返す。それ以外はそのまま返す */\n export const cosenseAsset: (url: string) => Promise<string>;\n /** HTML の src / href のうち、Cosense 上のファイルを指すものを差し替える (toHtml の出力に使う) */\n export const localizeCosenseAssets: (html: string) => Promise<string>;\n}\n${EXTENSIONS.map(\n (extension) => `\ndeclare module '*${extension}' {\n export const frontmatter: Record<string, unknown>;\n export const metadata: import('@cosense-toolbox/cosense-x').PageMetadata;\n export const file: string;\n export const Content: import('astro').MDXContent;\n export default Content;\n}`,\n).join(\"\\n\")}\n`\n\nexport default function cosense(options: CosenseIntegrationOptions = {}): AstroIntegration {\n const {\n components,\n assets: assetsOptions = {},\n syntaxHighlight = \"astro\",\n lint,\n ...compileOptions\n } = options\n // config:setup で作る。ビルドの始まりと終わりのフックからも使う。\n let assets: AssetStore | undefined\n let astroConfig: AstroConfig | undefined\n return {\n name: \"@cosense-toolbox/astro\",\n hooks: {\n \"astro:config:setup\": (params: HookParameters<\"astro:config:setup\">) => {\n const { addPageExtension, addContentEntryType } = params as unknown as HiddenSetupHooks\n const { config, addRenderer, updateConfig, logger } = params\n const root = fileURLToPath(config.root)\n assets =\n assetsOptions === false\n ? undefined\n : createAssetStore({\n cacheDir: fileURLToPath(new URL(\"cosense-assets/\", config.cacheDir)),\n publicPath: assetsPathOf(config),\n fetchOptions: {\n ...(assetsOptions.pat === undefined ? {} : { pat: assetsOptions.pat }),\n ...(assetsOptions.origin === undefined ? {} : { origin: assetsOptions.origin }),\n },\n ...(assetsOptions.links === undefined ? {} : { links: assetsOptions.links }),\n warn: (message) => logger.warn(message),\n })\n const highlighter: CodeHighlighter | undefined =\n syntaxHighlight === false\n ? undefined\n : syntaxHighlight === \"astro\"\n ? astroShikiHighlighter(config.markdown)\n : customHighlighter(syntaxHighlight)\n // toHtml などで自分で描画するページが、virtual:cosense-x/assets から使う。\n Object.assign(globalThis, { [Symbol.for(ASSET_STORE_KEY)]: assets })\n const site = createSiteCache(\n root,\n fileURLToPath(config.srcDir),\n options.parseOptions === undefined ? {} : { parseOptions: options.parseOptions },\n )\n\n addRenderer({\n name: \"astro:jsx\",\n serverEntrypoint: new URL(\"./server.mjs\", import.meta.url),\n })\n for (const extension of EXTENSIONS) addPageExtension(extension)\n\n addContentEntryType({\n extensions: [...EXTENSIONS],\n async getEntryInfo({ fileUrl, contents }) {\n const { frontmatter, metadata, body } = readPage(contents, {\n filePath: idOf(root, fileURLToPath(fileUrl)),\n ...(options.parseOptions === undefined ? {} : { parseOptions: options.parseOptions }),\n })\n // Cosense では 1 行目がタイトルなので、frontmatter に無くても title などを data に入れる。\n const { links: _links, ...fields } = metadata\n return {\n data: { ...frontmatter, ...fields },\n body,\n slug: metadata.slug,\n rawData: \"\",\n }\n },\n contentModuleTypes: CONTENT_TYPES,\n handlePropagation: true,\n })\n\n updateConfig({\n vite: {\n plugins: [\n vitePluginCosense({\n root: config.root,\n site,\n compile:\n assets === undefined\n ? compileOptions\n : {\n ...compileOptions,\n // 利用者のプラグインが足した画像も差し替えられるよう、最後に当てる。\n rehypePlugins: [\n ...(compileOptions.rehypePlugins ?? []),\n rehypeCosenseAssets(assets),\n ],\n },\n assets,\n highlighter,\n components:\n components === undefined\n ? undefined\n : fileURLToPath(new URL(components, config.root)),\n }),\n ],\n },\n })\n },\n\n \"astro:config:done\": ({ config, injectTypes }) => {\n astroConfig = config\n injectTypes({ filename: \"types.d.ts\", content: INJECTED_TYPES })\n },\n\n \"astro:build:start\": async ({ logger }) => {\n if (lint === undefined || astroConfig === undefined) return\n await Effect.runPromise(\n Effect.flatMap(reportLint(astroConfig, lint, compileOptions, logger), stopOnErrors),\n )\n },\n\n // 開発中は起動したときと、ページを足した・変えた・消したときに調べ直す。\n \"astro:server:setup\": ({ server, logger }) => {\n if (lint === undefined || astroConfig === undefined) return\n const config = astroConfig\n const check = () =>\n Effect.runFork(\n Effect.flatMap(reportLint(config, lint, compileOptions, logger), noteWhenClean(logger)),\n )\n const onChange = (file: string) => {\n if (isCosenseFile(file)) check()\n }\n server.watcher.on(\"add\", onChange)\n server.watcher.on(\"change\", onChange)\n server.watcher.on(\"unlink\", onChange)\n check()\n },\n\n // 置き場のディレクトリはビルドをまたいで残し、中身の変わらないファイルは取り直さない。\n // 出力先には、このビルドで使ったファイルだけを写す。\n \"astro:build:done\": async ({ dir }) => {\n if (assets === undefined || astroConfig === undefined) return\n await assets.copyUsedTo(assetsDirOf(astroConfig, dir))\n },\n },\n }\n}\n\nexport type { Graph, GraphPage, TwoHopGroup } from \"@cosense-toolbox/cosense-x/graph\"\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["EXTENSIONS","Arr","CONTENT_TYPES","Arr"],"sources":["../src/assets.ts","../src/highlight.ts","../src/lint.ts","../src/site.ts","../src/vite-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * assets.ts — Cosense 上の画像やファイルを、ビルド時に取ってきてサイトの中に置く。\n *\n * Cosense のファイル (`/files/…`) とアイコン (`/api/pages/…/icon`) は\n * `Cross-Origin-Resource-Policy: same-origin` を返すので、別のサイトの `<img>` からは読めない。\n * リダイレクト先も期限付きの URL (`/files/` は 5 分で切れる) なので、URL を解決して埋め込むだけでは\n * 公開する頃には表示されなくなる。そのため中身を取ってきて、サイトと同じ場所に置く。\n */\nimport { createHash } from \"node:crypto\"\nimport { copyFile, mkdir, readdir, writeFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { fetchAsset, type FetchOptions, isCosenseAssetUrl } from \"@cosense-toolbox/cosense-x/fetch\"\nimport type { Root } from \"hast\"\n\n/** `globalThis` に置き場を置くときのキー (`Symbol.for` に渡す)。 */\nexport const ASSET_STORE_KEY = \"@cosense-toolbox/astro/assets\"\n\nexport interface AssetStoreOptions {\n /**\n * 取ってきたファイルを置くディレクトリ。ビルドをまたいで残し、中身の変わらないファイルは使い回す。\n * ビルドの終わりに、使ったファイルだけをここから出力先に写す\n */\n readonly cacheDir: string\n /** サイトの中で、置いたファイルを配信するパス。`/` で終わる */\n readonly publicPath: string\n /** PAT などの取得のオプション */\n readonly fetchOptions?: FetchOptions\n /**\n * リンク (`<a href>`) した Cosense のファイル (zip や PDF など) の扱い。画像 (`<img>`) は常に取ってくる。\n *\n * - `'keep'`:元の URL のまま。公開プロジェクトならクリックして開ける (CORP は画面の遷移には効かない)\n * - `'download'`:画像と同じく取ってきてサイトに置く。非公開プロジェクトのファイルはこちらでないと開けない\n *\n * @defaultValue `'keep'`\n */\n readonly links?: \"keep\" | \"download\"\n /** 取れなかったときに呼ぶ */\n readonly warn?: (message: string) => void\n}\n\nexport interface AssetStore {\n /** Cosense 上のファイルなら、取ってきて置いたサイトの中の URL を返す。それ以外はそのまま返す */\n readonly resolve: (url: string) => Promise<string>\n /** リンクした Cosense のファイル。`links: 'keep'` なら元の URL のまま返す */\n readonly resolveLink: (url: string) => Promise<string>\n /** HTML の `src` (と `links: 'download'` なら `href`) のうち、Cosense 上のファイルを指すものを差し替える */\n readonly localizeHtml: (html: string) => Promise<string>\n /** このビルドで使ったファイルだけを `dir` に写す */\n readonly copyUsedTo: (dir: string | URL) => Promise<void>\n readonly cacheDir: string\n readonly publicPath: string\n}\n\n/** Content-Type から付ける拡張子。静的なホスティングは拡張子で Content-Type を決めるため。 */\nconst EXTENSIONS: Readonly<Record<string, string>> = {\n \"image/png\": \".png\",\n \"image/jpeg\": \".jpg\",\n \"image/gif\": \".gif\",\n \"image/webp\": \".webp\",\n \"image/avif\": \".avif\",\n \"image/svg+xml\": \".svg\",\n \"image/x-icon\": \".ico\",\n \"application/pdf\": \".pdf\",\n \"video/mp4\": \".mp4\",\n \"audio/mpeg\": \".mp3\",\n}\n\n/** Content-Type で決まらなければ、元の URL の拡張子を使う。 */\nconst extensionOf = (url: string, contentType: string): string => {\n const known = EXTENSIONS[contentType.split(\";\")[0]?.trim().toLowerCase() ?? \"\"]\n if (known !== undefined) return known\n return /\\.[A-Za-z0-9]{1,5}$/.exec(new URL(url).pathname)?.[0]?.toLowerCase() ?? \"\"\n}\n\n/**\n * 元の URL のハッシュ。同じ URL は何度ビルドしても同じ名前になり、ハッシュから元の URL\n * (アップロードしたファイルの ID) は分からない。非公開プロジェクトのファイル ID を出さないため。\n */\nconst hashOf = (url: string): string => createHash(\"sha256\").update(url).digest(\"hex\").slice(0, 16)\n\nconst ICON_RE = /^\\/api\\/pages\\/[^/]+\\/(.+)\\/icon$/\n\nconst decode = (segment: string): string => {\n try {\n return decodeURIComponent(segment)\n } catch {\n return segment\n }\n}\n\n/** ファイル名や URL に使えない文字を `_` にする。日本語はそのまま残す。 */\nconst sanitize = (label: string): string =>\n label\n .replace(/[\\\\/?#%:*\"<>|\\s\\p{Cc}]+/gu, \"_\")\n .replace(/_+/g, \"_\")\n .replace(/^_|_$/g, \"\")\n .slice(0, 60)\n\n/**\n * 人が見て何のファイルか分かるよう、ハッシュのあとに付ける名前。アイコンはユーザー名\n * (ページには `<img alt>` としてもともと出ている)。アップロードしたファイルは ID を出さないので付けない。\n */\nconst labelOf = (url: string): string => {\n const title = ICON_RE.exec(new URL(url).pathname)?.[1]\n return title === undefined ? \"\" : sanitize(title.split(\"/\").map(decode).join(\"_\"))\n}\n\n/** アップロードしたファイル (`/files/…`) は中身が変わらないので、前のビルドで取ったものを使い回せる。 */\nconst isImmutable = (url: string): boolean => new URL(url).pathname.startsWith(\"/files/\")\n\nconst unescapeAttribute = (value: string): string =>\n value\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/&/g, \"&\")\n\nconst ATTRIBUTE_RE = /(\\s(src|href)=\")([^\"]*)(\")/g\n\nexport const createAssetStore = (options: AssetStoreOptions): AssetStore => {\n const fetchOptions = options.fetchOptions ?? {}\n const isAsset = (url: string) => isCosenseAssetUrl(url, fetchOptions)\n // 同じファイルを何度も取りに行かないよう、URL ごとに取得の Promise を覚えておく。\n const downloads = new Map<string, Promise<string>>()\n // このビルドで使ったファイル。出力先にはこれだけを写す。\n const used = new Set<string>()\n\n const publicUrlOf = (file: string): string => {\n used.add(file)\n return `${options.publicPath}${encodeURIComponent(file)}`\n }\n\n /** 前のビルドで置いたファイル。拡張子は取ってくるまで分からないので、ハッシュで探す。 */\n const cachedFileOf = async (base: string): Promise<string | undefined> => {\n const files = await readdir(options.cacheDir).catch(() => [])\n return files.find((file) => file === base || file.startsWith(`${base}.`))\n }\n\n const download = async (url: string): Promise<string> => {\n const label = labelOf(url)\n const base = label === \"\" ? hashOf(url) : `${hashOf(url)}_${label}`\n try {\n const cached = isImmutable(url) ? await cachedFileOf(base) : undefined\n if (cached !== undefined) return publicUrlOf(cached)\n const asset = await fetchAsset(url, fetchOptions)\n const file = `${base}${extensionOf(url, asset.contentType)}`\n await mkdir(options.cacheDir, { recursive: true })\n await writeFile(join(options.cacheDir, file), asset.data)\n return publicUrlOf(file)\n } catch (error) {\n // 1 つの画像のためにビルド全体を止めない。元の URL のまま出し、表示されないことを知らせる。\n options.warn?.(`${url} を取得できないので、元の URL のまま出す: ${String(error)}`)\n return url\n }\n }\n\n const resolve = (url: string): Promise<string> => {\n if (!isAsset(url)) return Promise.resolve(url)\n const cached = downloads.get(url) ?? download(url)\n downloads.set(url, cached)\n return cached\n }\n\n const resolveLink = (url: string): Promise<string> =>\n options.links === \"download\" ? resolve(url) : Promise.resolve(url)\n\n const resolveAttribute = (name: string, url: string): Promise<string> =>\n name === \"href\" ? resolveLink(url) : resolve(url)\n\n const localizeHtml = async (html: string): Promise<string> => {\n const targets = [...html.matchAll(ATTRIBUTE_RE)]\n .map((match) => [match[2] ?? \"\", unescapeAttribute(match[3] ?? \"\")] as const)\n .filter(([, url]) => isAsset(url))\n const resolved = new Map(\n await Promise.all(\n targets.map(\n async ([name, url]) => [`${name} ${url}`, await resolveAttribute(name, url)] as const,\n ),\n ),\n )\n // サイトの中の URL はエンコード済みなので、属性値としてエスケープの要る文字を含まない。\n return html.replace(\n ATTRIBUTE_RE,\n (whole, open: string, name: string, value: string, close: string) => {\n const local = resolved.get(`${name} ${unescapeAttribute(value)}`)\n return local === undefined ? whole : `${open}${local}${close}`\n },\n )\n }\n\n const copyUsedTo = async (dir: string | URL): Promise<void> => {\n const target = dir instanceof URL ? fileURLToPath(dir) : dir\n await mkdir(target, { recursive: true })\n await Promise.all(\n [...used].map((file) => copyFile(join(options.cacheDir, file), join(target, file))),\n )\n }\n\n return {\n resolve,\n resolveLink,\n localizeHtml,\n copyUsedTo,\n cacheDir: options.cacheDir,\n publicPath: options.publicPath,\n }\n}\n\ninterface HastLike {\n readonly type?: string\n readonly tagName?: string\n readonly properties?: Record<string, unknown>\n readonly children?: readonly HastLike[]\n readonly fallback?: HastLike | null\n readonly fallbackEnd?: HastLike | null\n}\n\n/** `img` の `src` と `a` の href。書き換えられるよう、要素とプロパティ名の組で返す。 */\nconst referencesIn = (node: HastLike): (readonly [Record<string, unknown>, \"src\" | \"href\"])[] => {\n const own =\n node.type === \"element\" && node.properties !== undefined\n ? node.tagName === \"img\"\n ? [[node.properties, \"src\"] as const]\n : node.tagName === \"a\"\n ? [[node.properties, \"href\"] as const]\n : []\n : []\n // コンポーネントのノードは、渡されなかったときに出す元の行 (fallback) も持つ。\n const nested = [...(node.children ?? []), node.fallback, node.fallbackEnd].filter(\n (child): child is HastLike => child !== null && child !== undefined,\n )\n return [...own, ...nested.flatMap(referencesIn)]\n}\n\n/** `.csn` / `.csnx` の hast の中で、Cosense 上のファイルを指す URL を差し替える rehype プラグイン。 */\nexport const rehypeCosenseAssets = (store: AssetStore) => () => async (tree: Root) => {\n await Promise.all(\n referencesIn(tree as HastLike).map(async ([properties, key]) => {\n const value = properties[key]\n // hast は要素のプロパティをその場で書き換えるのが決まりなので、ここでも書き換える。\n if (typeof value !== \"string\") return\n properties[key] = key === \"href\" ? await store.resolveLink(value) : await store.resolve(value)\n }),\n )\n}\n","/**\n * highlight.ts — コードブロックを、Astro の Markdown と同じ shiki の設定で色付けする。\n *\n * `.md` / `.mdx` のコードブロックと見た目を揃えるため、`markdown.syntaxHighlight` と\n * `markdown.shikiConfig` をそのまま使う。\n */\nimport type { HastHighlighter, RenderOptions } from \"@cosense-toolbox/cosense-x\"\nimport { codeLanguageOf } from \"@cosense-toolbox/parser/html\"\nimport type { AstroConfig } from \"astro\"\nimport { Effect, Match, Option, pipe } from \"effect\"\nimport { type BundledLanguage, bundledLanguages, createHighlighter } from \"shiki\"\n\ntype MarkdownConfig = AstroConfig[\"markdown\"]\n\n/**\n * `.csn` / `.csnx` のコードブロックの色付け。\n * `'astro'` は `markdown.syntaxHighlight` / `markdown.shikiConfig` に従い、関数なら自分で色付けする。\n */\nexport type SyntaxHighlightOption = \"astro\" | false | HastHighlighter\n\n/**\n * `source` のコードブロックの言語を読み込んでから、色付けする関数を返す。\n * `compile` は色付けを同期で呼ぶので、言語は先に読み込んでおく。\n */\nexport type CodeHighlighter = (source: string) => Promise<HastHighlighter>\n\n/** 行頭 (字下げの後) の `code:ファイル名` からコードブロックを見つける。 */\nconst CODE_BLOCK = /^[ \\t]*code:(.+)$/gm\n\n/** ページに出てくるコードブロックの言語名。`highlight` に渡るのと同じ決め方。 */\nexport const codeLanguagesIn = (source: string): string[] => [\n ...new Set(\n [...source.matchAll(CODE_BLOCK)].map((match) => codeLanguageOf((match[1] ?? \"\").trim())),\n ),\n]\n\n/** shiki を使う設定なら、色付けしない言語 (`excludeLangs`) の一覧。shiki を使わない設定なら None。 */\nconst shikiExclusionsOf = (\n setting: MarkdownConfig[\"syntaxHighlight\"],\n): Option.Option<readonly string[]> =>\n Match.value(setting).pipe(\n Match.when(\"shiki\", () => Option.some([])),\n Match.when({ type: \"shiki\" }, (config) => Option.some(config.excludeLangs ?? [])),\n Match.orElse(() => Option.none()),\n )\n\ntype Shiki = Awaited<ReturnType<typeof createHighlighter>>\n\n/**\n * Astro の Markdown の設定で色付けする。shiki を使わない設定 (`false` や `'prism'`) なら undefined。\n * prism には相当するものが無いので、色付けしない。\n */\nexport const astroShikiHighlighter = (markdown: MarkdownConfig): CodeHighlighter | undefined =>\n pipe(\n shikiExclusionsOf(markdown.syntaxHighlight),\n Option.map((excluded) => shikiHighlighter(markdown.shikiConfig, new Set(excluded))),\n Option.getOrUndefined,\n )\n\nconst shikiHighlighter = (\n { langs, langAlias, theme, themes, defaultColor, transformers }: MarkdownConfig[\"shikiConfig\"],\n excluded: ReadonlySet<string>,\n): CodeHighlighter => {\n const multiple = Object.keys(themes).length > 0\n const themed = multiple\n ? { themes, ...(defaultColor === undefined ? {} : { defaultColor }) }\n : { theme }\n // 最初に色付けするときに 1 度だけ作る。色付けしないサイトで shiki を読み込まないため。\n const shiki = Effect.runSync(\n Effect.cached(\n Effect.promise(() =>\n createHighlighter({ themes: multiple ? Object.values(themes) : [theme], langs }),\n ),\n ),\n )\n const resolve = (language: string): string =>\n Option.getOrElse(Option.fromNullable(langAlias[language]), () => language)\n\n /** ページに出てくる言語のうち、読み込んでいないものを読み込む。shiki が知らない言語は飛ばす。 */\n const loadLanguagesIn = (source: string) => (highlighter: Shiki) => {\n const loaded = new Set(highlighter.getLoadedLanguages())\n const wanted = codeLanguagesIn(source)\n .map(resolve)\n .filter((language) => !excluded.has(language) && !loaded.has(language))\n .filter((language): language is BundledLanguage => language in bundledLanguages)\n return pipe(\n Effect.promise(() => highlighter.loadLanguage(...wanted)),\n Effect.when(() => wanted.length > 0),\n )\n }\n\n /** 読み込めた言語だけを色付けする。知らない言語は null (色付けせず 1 行ずつのまま) にする。 */\n const highlightWith = (highlighter: Shiki): HastHighlighter => {\n const available = new Set(highlighter.getLoadedLanguages())\n return (code, language) =>\n pipe(\n Option.some(resolve(language)),\n Option.filter((lang) => !excluded.has(lang) && available.has(lang)),\n Option.map((lang) => highlighter.codeToHast(code, { lang, ...themed, transformers })),\n Option.getOrNull,\n )\n }\n\n return (source) =>\n pipe(shiki, Effect.tap(loadLanguagesIn(source)), Effect.map(highlightWith), Effect.runPromise)\n}\n\n/** 利用者が渡した色付けをそのまま使う。 */\nexport const customHighlighter =\n (highlight: HastHighlighter): CodeHighlighter =>\n async () =>\n highlight\n\n/**\n * 利用者が統合に渡す描画の設定。色付けは統合が `syntaxHighlight` から作って渡すので含めない。\n */\nexport type AstroRenderOptions = Omit<RenderOptions, \"highlight\">\n\n/**\n * 利用者の `renderOptions` に、統合が作った色付けを足す。色付けしない設定なら何も足さない。\n */\nexport const renderOptionsWith = (\n renderOptions: AstroRenderOptions | undefined,\n highlight: Option.Option<HastHighlighter>,\n): RenderOptions =>\n pipe(\n highlight,\n Option.match({\n onNone: (): RenderOptions => ({ ...renderOptions }),\n onSome: (value): RenderOptions => ({ ...renderOptions, highlight: value }),\n }),\n )\n","/**\n * lint.ts — ビルドの前に、サイトのページのリンク切れを調べる。\n *\n * 判定は `@cosense-toolbox/lsp` の `checkSite` をそのまま使う。エディタの診断と\n * `csn-lsp check` と同じ関数なので、エディタで警告されるものとビルドで止まるものが一致する。\n */\nimport { relative, sep } from \"node:path\"\n\nimport { checkSite, type CheckSiteOptions, type Report } from \"@cosense-toolbox/lsp/check\"\nimport type { ParseOptions } from \"@cosense-toolbox/parser\"\nimport { Array as Arr, Effect } from \"effect\"\n\nexport interface CosenseLintOptions {\n /**\n * サイトに無いページへのリンクの知らせ方。`'error'` ならビルドを止める。\n * `'off'` / `'hint'` / `'information'` / `'warning'` / `'error'`。\n *\n * @defaultValue `'warning'`\n */\n readonly unresolvedLinks?: CheckSiteOptions[\"unresolvedLinks\"]\n /**\n * 1 行目の `---` を frontmatter (YAML) として飛ばすか。\n *\n * @defaultValue `true`\n */\n readonly frontmatter?: boolean\n}\n\n/** 見つかったもの。`errors` があればビルドを止める。 */\nexport interface LintResult {\n readonly errors: ReadonlyArray<string>\n readonly warnings: ReadonlyArray<string>\n}\n\n/** `path:line:column message`。path はプロジェクトのルートから。 */\nconst messageOf =\n (root: string) =>\n ({ path, line, column, message }: Report): string =>\n `${relative(root, path).split(sep).join(\"/\")}:${line}:${column} ${message}`\n\n/**\n * `srcDir` の下の `.csn` / `.csnx` を読み、リンク切れを調べる。\n * パースにはサイトの `parseOptions` を使うので、独自の装飾記法もビルドと同じに読む。\n */\nexport const lintSite = (\n root: string,\n srcDir: string,\n { unresolvedLinks = \"warning\", frontmatter = true }: CosenseLintOptions,\n parseOptions: ParseOptions = {},\n): Effect.Effect<LintResult> =>\n Effect.map(\n checkSite({ roots: [srcDir], unresolvedLinks, parseOptions, frontmatter }),\n (reports) => {\n const [warnings, errors] = Arr.partition(reports, ({ level }) => level === \"error\")\n return {\n errors: Arr.map(errors, messageOf(root)),\n warnings: Arr.map(warnings, messageOf(root)),\n }\n },\n )\n","/**\n * site.ts — プロジェクトの `.csn` / `.csnx` を全部読み、索引とリンクグラフを作る。\n *\n * リンクの解決には全ページのタイトルが要るので、1 ファイルずつのコンパイルの前にまとめて読む。\n * パースは軽いので、全ページを先読みしても問題にならない。\n */\nimport { readdir, readFile } from \"node:fs/promises\"\nimport { join, relative, sep } from \"node:path\"\n\nimport {\n buildGraph,\n createIndex,\n type Graph,\n type PageIndex,\n type ReadOptions,\n readPage,\n} from \"@cosense-toolbox/cosense-x/graph\"\n\nexport const EXTENSIONS = [\".csn\", \".csnx\"] as const\n\nexport const isCosenseFile = (path: string): boolean =>\n EXTENSIONS.some((extension) => path.endsWith(extension))\n\n/** ルートからの相対パス (区切りは `/`)。Astro の content collection の `filePath` と同じ形。 */\nexport const idOf = (root: string, absolute: string): string =>\n relative(root, absolute).split(sep).join(\"/\")\n\nexport interface Site {\n readonly index: PageIndex\n readonly graph: Graph\n}\n\nconst SKIP_DIRECTORIES = new Set([\"node_modules\", \".astro\", \"dist\"])\n\n/** `directory` の下の `.csn` / `.csnx`。読めないディレクトリ (まだ無い src/content など) は空とみなす。 */\nconst listFiles = async (directory: string): Promise<string[]> => {\n const entries = await readdir(directory, { withFileTypes: true }).catch(() => [])\n const nested = await Promise.all(\n entries.map(async (entry) => {\n const path = join(directory, entry.name)\n if (entry.isDirectory()) return SKIP_DIRECTORIES.has(entry.name) ? [] : listFiles(path)\n return entry.isFile() && isCosenseFile(entry.name) ? [path] : []\n }),\n )\n return nested.flat().sort()\n}\n\n/** `directory` の下を読んで、索引とグラフを作る。id は `root` からの相対パス。 */\nexport const scanSite = async (\n root: string,\n directory: string,\n options: Pick<ReadOptions, \"parseOptions\"> = {},\n): Promise<Site> => {\n const files = await listFiles(directory)\n const sources = await Promise.all(\n files.map(async (file) => ({ id: idOf(root, file), source: await readFile(file, \"utf8\") })),\n )\n const pages = sources.map(({ id, source }) => ({\n id,\n metadata: readPage(source, { ...options, filePath: id }).metadata,\n }))\n const index = createIndex(\n pages.map(({ id, metadata }) => ({\n id,\n title: metadata.title,\n slug: metadata.slug,\n draft: metadata.draft,\n })),\n )\n return { index, graph: buildGraph(pages) }\n}\n\n/** 索引とグラフを 1 つだけ持ち、Vite のプラグインと content collection で使い回す。 */\nexport interface SiteCache {\n readonly get: () => Promise<Site>\n /** ファイルが変わったときに捨てる。次の `get` で読み直す */\n readonly reset: () => void\n}\n\nexport const createSiteCache = (\n root: string,\n directory: string,\n options: Pick<ReadOptions, \"parseOptions\"> = {},\n): SiteCache => {\n // dev サーバーでファイルが変わるたびに捨てて読み直すので、ここだけは状態を持つ。\n // モジュールのトップレベルではなく、統合ごとに作るこの関数の中に閉じ込めている。\n let site: Promise<Site> | undefined\n return {\n get: () => {\n site ??= scanSite(root, directory, options)\n return site\n },\n reset: () => {\n site = undefined\n },\n }\n}\n","/**\n * vite-plugin.ts — `.csn` / `.csnx` を Astro のコンポーネントのモジュールにする。\n */\nimport { createReadStream } from \"node:fs\"\nimport { stat } from \"node:fs/promises\"\nimport { basename, extname, join } from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { compile, type CompileOptions } from \"@cosense-toolbox/cosense-x\"\nimport { Option } from \"effect\"\nimport type { Plugin } from \"vite\"\n\nimport { ASSET_STORE_KEY, type AssetStore } from \"./assets\"\nimport { type AstroRenderOptions, type CodeHighlighter, renderOptionsWith } from \"./highlight\"\nimport { idOf, isCosenseFile, type SiteCache } from \"./site\"\n\nexport const GRAPH_MODULE_ID = \"virtual:cosense-x/graph\"\nconst RESOLVED_GRAPH_MODULE_ID = `\\0${GRAPH_MODULE_ID}`\nexport const ASSETS_MODULE_ID = \"virtual:cosense-x/assets\"\nconst RESOLVED_ASSETS_MODULE_ID = `\\0${ASSETS_MODULE_ID}`\n\n/**\n * `toHtml` などで自分で描画するページから、Cosense 上のファイルを置くための関数。\n * 置き場は統合が作って `globalThis` に置いたものを使う。ページの描画はビルドでも dev でも\n * 統合と同じプロセスで走るので、PAT をモジュールのコードに埋め込まずに済む。\n * 置き場が無いとき (実行時に描画する SSR など) は、元の URL のまま返す。\n */\nconst ASSETS_MODULE = `const store = () => globalThis[Symbol.for(${JSON.stringify(ASSET_STORE_KEY)})];\nexport const cosenseAsset = (url) => store()?.resolve(url) ?? Promise.resolve(url);\nexport const localizeCosenseAssets = (html) => store()?.localizeHtml(html) ?? Promise.resolve(html);\n`\n\n/** dev サーバーで返す Content-Type。ビルドでは静的なホスティングが拡張子から決める。 */\nconst CONTENT_TYPES: Readonly<Record<string, string>> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".pdf\": \"application/pdf\",\n \".mp4\": \"video/mp4\",\n \".mp3\": \"audio/mpeg\",\n}\n\nexport interface AstroCompileOptions extends Omit<\n CompileOptions,\n | \"filePath\"\n | \"format\"\n | \"index\"\n | \"jsxImportSource\"\n | \"elementAttributeNameCase\"\n | \"renderOptions\"\n | \"unresolved\"\n> {\n /**\n * サイトに無いページへのリンクの出し方。`'text'` はテキストにする (非公開のページの名前が\n * URL に漏れない)。`'link'` はタイトルから作った URL へのリンクにする。\n * リンク切れを知らせるのは `lint` の役目。\n *\n * @defaultValue `'text'`\n */\n readonly unresolvedLinks?: \"text\" | \"link\"\n /**\n * 描画の設定。parser の `toHast` のオプションがそのまま渡る\n * (`extensions` / `handlers` / `classNames` / `showPads` / `iconImageUrl` / `title`)。\n * コードブロックの色付けは `syntaxHighlight` で決める。\n */\n readonly renderOptions?: AstroRenderOptions\n}\n\n/** 統合の compile の設定を、`compile` が受け取る形にする。 */\nexport const compileOptionsOf = ({\n unresolvedLinks,\n ...rest\n}: AstroCompileOptions): Omit<AstroCompileOptions, \"unresolvedLinks\"> &\n Pick<CompileOptions, \"unresolved\"> =>\n Option.match(Option.fromNullable(unresolvedLinks), {\n onNone: () => rest,\n onSome: (unresolved) => ({ ...rest, unresolved }),\n })\n\nexport interface VitePluginOptions {\n readonly root: URL\n /** 索引とグラフ。content collection の読み込みと共有する */\n readonly site: SiteCache\n readonly compile: AstroCompileOptions\n /** すべてのページに渡すコンポーネントを default export するモジュールの絶対パス */\n readonly components: string | undefined\n /** Cosense 上のファイルの置き場。無効にしたときは undefined */\n readonly assets: AssetStore | undefined\n /** コードブロックの色付け。色付けしないときは undefined */\n readonly highlighter: CodeHighlighter | undefined\n}\n\n/**\n * `@astrojs/mdx` と同じ形に整える。`Content` を default export にし、\n * Astro がそれを `astro:jsx` のコンポーネントとして描画できるよう印を付ける。\n */\nconst toAstroModule = (\n code: string,\n id: string,\n options: { components: string | undefined; layout: string | undefined; ssr: boolean },\n): string => {\n const { components, layout, ssr } = options\n const content =\n layout === undefined\n ? [\"export const Content = (props = {}) => __cosenseBody(props);\"]\n : // src/pages に置いたページを包むレイアウト。`.mdx` の `layout` と同じく、\n // 本文を default のスロットに入れ、frontmatter などを props で渡す。\n [\n `import __CosenseLayout from ${JSON.stringify(layout)};`,\n \"import { jsx as __cosenseJsx } from 'astro/jsx-runtime';\",\n \"export const Content = (props = {}) => __cosenseJsx(__CosenseLayout, {\",\n \" file, frontmatter, metadata,\",\n \" children: __cosenseBody(props),\",\n \"});\",\n ]\n const tag = ssr\n ? [\n \"import { __astro_tag_component__ } from 'astro/runtime/server/index.js';\",\n \"__astro_tag_component__(Content, 'astro:jsx');\",\n ]\n : []\n return [\n code.replace(\"export default function CosenseContent\", \"function CosenseContent\"),\n components === undefined\n ? \"const __cosenseComponents = {};\"\n : `import __cosenseComponents from ${JSON.stringify(components)};`,\n `export const file = ${JSON.stringify(id)};`,\n \"const __cosenseBody = (props) => CosenseContent({\",\n \" ...props,\",\n \" components: { ...__cosenseComponents, ...props.components },\",\n \"});\",\n ...content,\n \"export default Content;\",\n \"Content[Symbol.for('mdx-component')] = true;\",\n // レイアウトがあれば <head> はレイアウトが出す。無ければ Astro に出させる。\n `Content[Symbol.for('astro.needsHeadRendering')] = ${layout === undefined};`,\n `Content.moduleId = ${JSON.stringify(id)};`,\n ...tag,\n ].join(\"\\n\")\n}\n\nexport const vitePluginCosense = (options: VitePluginOptions): Plugin => {\n const root = fileURLToPath(options.root)\n const loadSite = options.site.get\n\n return {\n name: \"@cosense-toolbox/astro\",\n enforce: \"pre\",\n\n resolveId(id) {\n if (id === GRAPH_MODULE_ID) return RESOLVED_GRAPH_MODULE_ID\n if (id === ASSETS_MODULE_ID) return RESOLVED_ASSETS_MODULE_ID\n return undefined\n },\n\n async load(id) {\n if (id === RESOLVED_ASSETS_MODULE_ID) return ASSETS_MODULE\n if (id !== RESOLVED_GRAPH_MODULE_ID) return undefined\n const { graph } = await loadSite()\n return `export const graph = ${JSON.stringify(graph)};\\nexport default graph;`\n },\n\n transform: {\n filter: { id: /\\.csnx?$/ },\n async handler(code, id) {\n const { index } = await loadSite()\n const highlight = Option.fromNullable(await options.highlighter?.(code))\n const result = await compile(code, {\n ...compileOptionsOf(options.compile),\n renderOptions: renderOptionsWith(options.compile.renderOptions, highlight),\n filePath: idOf(root, id),\n index,\n jsxImportSource: \"astro\",\n })\n for (const warning of result.warnings) this.warn(warning)\n const ssr = this.environment.name === \"ssr\" || this.environment.name === \"prerender\"\n const layout = result.frontmatter.layout\n return {\n code: toAstroModule(result.code, id, {\n components: options.components,\n layout: typeof layout === \"string\" ? layout : undefined,\n ssr,\n }),\n map: null,\n }\n },\n },\n\n // 1 ページの変更で、ほかのページのリンク先やグラフも変わりうる。\n // 索引を作り直し、関わるモジュールをすべて捨てて再読み込みする。\n configureServer(server) {\n // dev では、取ってきたファイルを置き場のディレクトリから返す。ビルドでは出力先に写す。\n const assets = options.assets\n if (assets !== undefined) {\n server.middlewares.use(assets.publicPath, async (request, response, next) => {\n // アイコンの名前は日本語を含みうるので、URL のエンコードを戻す。basename で置き場の外は読ませない。\n const name = (() => {\n try {\n return decodeURIComponent(basename(request.url?.split(\"?\")[0] ?? \"\"))\n } catch {\n return \"\"\n }\n })()\n const file = join(assets.cacheDir, basename(name))\n const found = await stat(file)\n .then((s) => s.isFile())\n .catch(() => false)\n if (!found) {\n next()\n return\n }\n const type = CONTENT_TYPES[extname(file)]\n if (type !== undefined) response.setHeader(\"content-type\", type)\n createReadStream(file).pipe(response)\n })\n }\n\n const onChange = (file: string) => {\n if (!isCosenseFile(file)) return\n options.site.reset()\n for (const environment of Object.values(server.environments)) {\n const graph = environment.moduleGraph\n for (const [id, module] of graph.idToModuleMap) {\n if (id === RESOLVED_GRAPH_MODULE_ID || isCosenseFile(id.split(\"?\")[0] ?? \"\")) {\n graph.invalidateModule(module)\n }\n }\n }\n server.ws.send({ type: \"full-reload\" })\n }\n server.watcher.on(\"add\", onChange)\n server.watcher.on(\"change\", onChange)\n server.watcher.on(\"unlink\", onChange)\n },\n }\n}\n","/**\n * `@cosense-toolbox/astro` — `.csn` / `.csnx` を Astro のページと content collection で使う。\n *\n * ```js\n * // astro.config.mjs\n * import cosense from '@cosense-toolbox/astro'\n * export default defineConfig({\n * integrations: [cosense({ pageUrl: (page) => `/posts/${page.slug}` })],\n * })\n * ```\n */\nimport { fileURLToPath } from \"node:url\"\n\nimport { readPage } from \"@cosense-toolbox/cosense-x/graph\"\nimport type {\n AstroConfig,\n AstroIntegration,\n AstroIntegrationLogger,\n ContentEntryType,\n HookParameters,\n} from \"astro\"\nimport { Array as Arr, Effect, pipe } from \"effect\"\n\nimport { ASSET_STORE_KEY, type AssetStore, createAssetStore, rehypeCosenseAssets } from \"./assets\"\nimport {\n astroShikiHighlighter,\n type CodeHighlighter,\n customHighlighter,\n type SyntaxHighlightOption,\n} from \"./highlight\"\nimport { type CosenseLintOptions, type LintResult, lintSite } from \"./lint\"\nimport { createSiteCache, EXTENSIONS, idOf, isCosenseFile } from \"./site\"\nimport {\n ASSETS_MODULE_ID,\n type AstroCompileOptions,\n GRAPH_MODULE_ID,\n vitePluginCosense,\n} from \"./vite-plugin\"\n\nexport interface CosenseAssetsOptions {\n /**\n * Cosense の Personal Access Token。非公開プロジェクトの画像を取ってくるときに渡す。\n * Cosense への要求にだけ付け、リダイレクト先 (Google Cloud Storage や Gyazo) には送らない。\n *\n * @example `process.env.COSENSE_PAT`\n */\n readonly pat?: string\n /** Cosense の origin。 @defaultValue `https://scrapbox.io` */\n readonly origin?: string\n /**\n * リンクした Cosense のファイル (`[https://scrapbox.io/files/x.zip]` など) の扱い。画像は常に取ってくる。\n * `'keep'` は元の URL のまま (公開プロジェクトならクリックで開ける)、`'download'` は取ってきてサイトに置く。\n * 非公開プロジェクトのファイルは `'download'` でないと、見に来た人が開けない。\n *\n * @defaultValue `'keep'`\n */\n readonly links?: \"keep\" | \"download\"\n}\n\nexport interface CosenseIntegrationOptions extends AstroCompileOptions {\n /**\n * すべてのページに渡すコンポーネントを default export するモジュール (プロジェクトのルートからのパス)。\n * `.csnx` の `<Name />` や、`a` などの要素の差し替えに使う。\n * `<Content components={...} />` で渡したものがあれば、そちらが優先する。\n *\n * @example `'./src/components/cosense.ts'`\n */\n readonly components?: string\n /**\n * Cosense 上の画像やファイル (`/files/…` とアイコン) を、ビルド時に取ってきてサイトの中\n * (`{base}/_cosense/`) に置く。`false` なら元の URL のまま出す。\n *\n * Cosense のファイルは別のサイトからは読めず、リダイレクト先の URL も数分で切れるので、\n * 静的なサイトで表示するにはこうするしかない。非公開プロジェクトの画像も公開されることになる点に注意。\n *\n * @defaultValue `{}` (有効)\n */\n readonly assets?: CosenseAssetsOptions | false\n /**\n * コードブロックの色付け。\n *\n * - `'astro'`: `.md` / `.mdx` と同じく、Astro の `markdown.syntaxHighlight` と `markdown.shikiConfig` に従う。\n * shiki のときだけ色付けし、prism には対応していない\n * - `false`: 色付けしない\n * - 関数: `(code, language) => hast | null` で自分で色付けする\n *\n * @defaultValue `'astro'`\n */\n readonly syntaxHighlight?: SyntaxHighlightOption\n /**\n * ビルドの前に、`srcDir` の下のページのリンク切れを調べる。エディタの診断\n * (`@cosense-toolbox/lsp`) と同じ判定で、`unresolvedLinks: 'error'` ならビルドを止める。\n * 省略すると調べない。\n *\n * @example `{ unresolvedLinks: 'error' }`\n */\n readonly lint?: CosenseLintOptions\n}\n\n/** サイトのリンク切れを調べ、見つかったものをログに出す。 */\nconst reportLint = (\n config: AstroConfig,\n lint: CosenseLintOptions,\n compileOptions: AstroCompileOptions,\n logger: AstroIntegrationLogger,\n): Effect.Effect<LintResult> =>\n pipe(\n lintSite(\n fileURLToPath(config.root),\n fileURLToPath(config.srcDir),\n lint,\n compileOptions.parseOptions,\n ),\n Effect.tap(({ errors, warnings }) =>\n Effect.all([\n Effect.forEach(warnings, (warning) => Effect.sync(() => logger.warn(warning))),\n Effect.forEach(errors, (error) => Effect.sync(() => logger.error(error))),\n ]),\n ),\n )\n\n/** ビルドでは、error があれば失敗してビルドを止める。 */\nconst stopOnErrors = ({ errors }: LintResult): Effect.Effect<void, Error> =>\n Arr.match(errors, {\n onEmpty: () => Effect.void,\n onNonEmpty: (found) =>\n Effect.fail(new Error(`リンク切れが ${found.length} 件あるので、ビルドを止めた`)),\n })\n\n/** `{base}/_cosense/`。base の末尾の `/` の有無を吸収する。 */\nconst assetsPathOf = (config: AstroConfig): string => `${config.base.replace(/\\/$/, \"\")}/_cosense/`\n\n/** 静的なサイトでは出力先そのもの、サーバー出力ではクライアント向けの出力先に置く。 */\nconst assetsDirOf = (config: AstroConfig, dir: URL): URL =>\n new URL(\"_cosense/\", config.output === \"static\" ? dir : config.build.client)\n\n/**\n * `astro:config:setup` の引数のうち、型定義に載っていないもの。\n * `@astrojs/mdx` も使っている、ページの拡張子と content collection の形式を足す口。\n */\ninterface HiddenSetupHooks {\n readonly addPageExtension: (extension: string) => void\n readonly addContentEntryType: (contentEntryType: ContentEntryType) => void\n}\n\nconst CONTENT_MODULE_TYPES = EXTENSIONS.map(\n (extension) => ` '${extension}': Promise<{ Content: import('astro').MDXContent }>;`,\n)\n\nconst CONTENT_TYPES = `declare module 'astro:content' {\n interface Render {\n${CONTENT_MODULE_TYPES.join(\"\\n\")}\n }\n}\n`\n\nconst INJECTED_TYPES = `declare module '${GRAPH_MODULE_ID}' {\n export const graph: import('@cosense-toolbox/cosense-x/graph').Graph;\n export default graph;\n}\ndeclare module '${ASSETS_MODULE_ID}' {\n /** Cosense 上のファイルなら、ビルド時に取ってきて置いたサイトの中の URL を返す。それ以外はそのまま返す */\n export const cosenseAsset: (url: string) => Promise<string>;\n /** HTML の src / href のうち、Cosense 上のファイルを指すものを差し替える (toHtml の出力に使う) */\n export const localizeCosenseAssets: (html: string) => Promise<string>;\n}\n${EXTENSIONS.map(\n (extension) => `\ndeclare module '*${extension}' {\n export const frontmatter: Record<string, unknown>;\n export const metadata: import('@cosense-toolbox/cosense-x').PageMetadata;\n export const file: string;\n export const Content: import('astro').MDXContent;\n export default Content;\n}`,\n).join(\"\\n\")}\n`\n\nexport default function cosense(options: CosenseIntegrationOptions = {}): AstroIntegration {\n const {\n components,\n assets: assetsOptions = {},\n syntaxHighlight = \"astro\",\n lint,\n ...compileOptions\n } = options\n // config:setup で作る。ビルドの始まりと終わりのフックからも使う。\n let assets: AssetStore | undefined\n let astroConfig: AstroConfig | undefined\n return {\n name: \"@cosense-toolbox/astro\",\n hooks: {\n \"astro:config:setup\": (params: HookParameters<\"astro:config:setup\">) => {\n const { addPageExtension, addContentEntryType } = params as unknown as HiddenSetupHooks\n const { config, addRenderer, updateConfig, logger } = params\n const root = fileURLToPath(config.root)\n assets =\n assetsOptions === false\n ? undefined\n : createAssetStore({\n cacheDir: fileURLToPath(new URL(\"cosense-assets/\", config.cacheDir)),\n publicPath: assetsPathOf(config),\n fetchOptions: {\n ...(assetsOptions.pat === undefined ? {} : { pat: assetsOptions.pat }),\n ...(assetsOptions.origin === undefined ? {} : { origin: assetsOptions.origin }),\n },\n ...(assetsOptions.links === undefined ? {} : { links: assetsOptions.links }),\n warn: (message) => logger.warn(message),\n })\n const highlighter: CodeHighlighter | undefined =\n syntaxHighlight === false\n ? undefined\n : syntaxHighlight === \"astro\"\n ? astroShikiHighlighter(config.markdown)\n : customHighlighter(syntaxHighlight)\n // toHtml などで自分で描画するページが、virtual:cosense-x/assets から使う。\n Object.assign(globalThis, { [Symbol.for(ASSET_STORE_KEY)]: assets })\n const site = createSiteCache(\n root,\n fileURLToPath(config.srcDir),\n options.parseOptions === undefined ? {} : { parseOptions: options.parseOptions },\n )\n\n addRenderer({\n name: \"astro:jsx\",\n serverEntrypoint: new URL(\"./server.mjs\", import.meta.url),\n })\n for (const extension of EXTENSIONS) addPageExtension(extension)\n\n addContentEntryType({\n extensions: [...EXTENSIONS],\n async getEntryInfo({ fileUrl, contents }) {\n const { frontmatter, metadata, body } = readPage(contents, {\n filePath: idOf(root, fileURLToPath(fileUrl)),\n ...(options.parseOptions === undefined ? {} : { parseOptions: options.parseOptions }),\n })\n // Cosense では 1 行目がタイトルなので、frontmatter に無くても title などを data に入れる。\n const { links: _links, ...fields } = metadata\n return {\n data: { ...frontmatter, ...fields },\n body,\n slug: metadata.slug,\n rawData: \"\",\n }\n },\n contentModuleTypes: CONTENT_TYPES,\n handlePropagation: true,\n })\n\n updateConfig({\n vite: {\n plugins: [\n vitePluginCosense({\n root: config.root,\n site,\n compile:\n assets === undefined\n ? compileOptions\n : {\n ...compileOptions,\n // 利用者のプラグインが足した画像も差し替えられるよう、最後に当てる。\n rehypePlugins: [\n ...(compileOptions.rehypePlugins ?? []),\n rehypeCosenseAssets(assets),\n ],\n },\n assets,\n highlighter,\n components:\n components === undefined\n ? undefined\n : fileURLToPath(new URL(components, config.root)),\n }),\n ],\n },\n })\n },\n\n \"astro:config:done\": ({ config, injectTypes }) => {\n astroConfig = config\n injectTypes({ filename: \"types.d.ts\", content: INJECTED_TYPES })\n },\n\n \"astro:build:start\": async ({ logger }) => {\n if (lint === undefined || astroConfig === undefined) return\n await Effect.runPromise(\n Effect.flatMap(reportLint(astroConfig, lint, compileOptions, logger), stopOnErrors),\n )\n },\n\n // 開発中は起動したときと、ページを足した・変えた・消したときに調べ直す。\n \"astro:server:setup\": ({ server, logger }) => {\n if (lint === undefined || astroConfig === undefined) return\n const config = astroConfig\n // ビルドと違って止めず、見つけたものを知らせるだけにする。\n const check = () => Effect.runFork(reportLint(config, lint, compileOptions, logger))\n const onChange = (file: string) => {\n if (isCosenseFile(file)) check()\n }\n server.watcher.on(\"add\", onChange)\n server.watcher.on(\"change\", onChange)\n server.watcher.on(\"unlink\", onChange)\n check()\n },\n\n // 置き場のディレクトリはビルドをまたいで残し、中身の変わらないファイルは取り直さない。\n // 出力先には、このビルドで使ったファイルだけを写す。\n \"astro:build:done\": async ({ dir }) => {\n if (assets === undefined || astroConfig === undefined) return\n await assets.copyUsedTo(assetsDirOf(astroConfig, dir))\n },\n },\n }\n}\n\nexport type { Graph, GraphPage, TwoHopGroup } from \"@cosense-toolbox/cosense-x/graph\"\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosense-toolbox/astro",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.7",
|
|
4
4
|
"description": "Astro integration for cosense-x: use .csn / .csnx (Cosense notation) as pages and content collections.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"format:check": "prettier --check . --ignore-path ../../.gitignore --ignore-path ../../.prettierignore"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@cosense-toolbox/cosense-x": "0.1.0-beta.
|
|
39
|
-
"@cosense-toolbox/lsp": "0.1.0-beta.
|
|
40
|
-
"@cosense-toolbox/parser": "0.1.0-beta.
|
|
38
|
+
"@cosense-toolbox/cosense-x": "0.1.0-beta.7",
|
|
39
|
+
"@cosense-toolbox/lsp": "0.1.0-beta.7",
|
|
40
|
+
"@cosense-toolbox/parser": "0.1.0-beta.7",
|
|
41
41
|
"effect": "^3.22.1",
|
|
42
42
|
"shiki": "^4.2.0"
|
|
43
43
|
},
|