@riebeckite/core 0.0.11 → 0.0.13
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 +94 -94
- package/README_ja.md +75 -75
- package/dist/client.d.ts +2 -0
- package/dist/client.js +43 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +212 -13
- package/dist/src/content/content_manager.d.ts +5 -0
- package/dist/src/pipeline.d.ts +3 -1
- package/dist/src/plugin/plugin_runtime.d.ts +3 -0
- package/dist/src/types/plugin.d.ts +3 -0
- package/dist/src/types/plugin_page.d.ts +36 -0
- package/dist/src/types/plugin_pipeline.d.ts +6 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
# @riebeckite/core
|
|
2
|
-
|
|
3
|
-
The portable framework contract for Riebeckite: configuration, content sources,
|
|
4
|
-
the content manager, the Markdown/HTML pipeline, plugin and theme contracts,
|
|
5
|
-
diagnostics, and observability.
|
|
6
|
-
|
|
7
|
-
[日本語](./README_ja.md)
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
`@riebeckite/core` owns content loading and interpretation and the contracts
|
|
12
|
-
that extensions build against. It is intentionally free of HonoX, Vite, and any
|
|
13
|
-
specific plugin, theme, or application: those depend on Core, never the reverse.
|
|
14
|
-
|
|
15
|
-
A site configures Core through `defineConfig`, and a framework integration such
|
|
16
|
-
as [`@riebeckite/honox`](../integrations/honox/README.md) drives the build.
|
|
17
|
-
Plugins and themes are plain objects created by `definePlugin` and `defineTheme`.
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
20
|
-
|
|
21
|
-
```sh
|
|
22
|
-
pnpm add @riebeckite/core
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Core is also installed transitively by `@riebeckite/honox` and by the
|
|
26
|
-
`@riebeckite/plugin-*` and `@riebeckite/theme-*` packages.
|
|
27
|
-
|
|
28
|
-
## Usage
|
|
29
|
-
|
|
30
|
-
```ts
|
|
31
|
-
import { defineConfig } from "@riebeckite/core";
|
|
32
|
-
|
|
33
|
-
export default defineConfig({
|
|
34
|
-
site: { title: "My notes", baseUrl: "https://example.com" },
|
|
35
|
-
content: { directory: "../../content" },
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
The content directory is resolved relative to the application root. See
|
|
40
|
-
[Configuration](../../docs/en/configuration.md) for the full field list and the
|
|
41
|
-
`projectRoot` / `appRoot` / `configRoot` / `contentRoot` resolution rules.
|
|
42
|
-
|
|
43
|
-
## Public API
|
|
44
|
-
|
|
45
|
-
### Configuration
|
|
46
|
-
|
|
47
|
-
- `defineConfig`, `resolveConfig`, `resolveConfigModule`, `isPublished`,
|
|
48
|
-
`isExcluded`
|
|
49
|
-
- `ConfigValidationError`
|
|
50
|
-
|
|
51
|
-
### Content
|
|
52
|
-
|
|
53
|
-
- `ContentManager` — interpretation, manifest, graph, plugin orchestration, and
|
|
54
|
-
public-location resolution
|
|
55
|
-
- `ContentSource`, `FileSystemContentSource`, `readContentSourceEntry`,
|
|
56
|
-
`getContentSourceEntry`
|
|
57
|
-
- `queryContentEntries` with the `ContentQuery*` filter and sort types
|
|
58
|
-
- `createContentGraph`, `readOnlyContentGraph`, `buildGraphEdges`,
|
|
59
|
-
`layoutRadialGraph`
|
|
60
|
-
- `resolveDefaultContentLocation`, `attachmentUrl`, and the content path and
|
|
61
|
-
extension helpers
|
|
62
|
-
- `readContentBuildStateStatus`, `resolveContentBuildStatePath`
|
|
63
|
-
|
|
64
|
-
### Pipeline
|
|
65
|
-
|
|
66
|
-
- `Pipeline`, `PipelineOptions`
|
|
67
|
-
|
|
68
|
-
### Plugins
|
|
69
|
-
|
|
70
|
-
- `definePlugin`, `resolvePlugins`, `getResolvedPluginMetadata`,
|
|
71
|
-
`PluginDependencyError`
|
|
72
|
-
- `defineEndpoint`, `createClientEntry`, `createStyleAsset`
|
|
73
|
-
- Plugin context, asset, endpoint, diagnostic, SEO, and pipeline types under
|
|
74
|
-
`Plugin*`
|
|
75
|
-
|
|
76
|
-
### Themes and contracts
|
|
77
|
-
|
|
78
|
-
- `defineTheme` and the `Theme*` types
|
|
79
|
-
- `RiebeckiteConfig`, `ResolvedRiebeckiteConfig`, `SiteConfig`,
|
|
80
|
-
`PostContent`, `PostFrontmatter`, `PublishStrategy`
|
|
81
|
-
|
|
82
|
-
### Utilities and observability
|
|
83
|
-
|
|
84
|
-
- `uniqueStrings`, `escapeHtml`, `escapeHtmlAttribute`, `normalizeTag`,
|
|
85
|
-
`calculateReadingTime`, `stripHtml`
|
|
86
|
-
- `ConsoleLogger`, `NoopLogger`, `NoopTracer`, `SinkTracer`,
|
|
87
|
-
`CompositeTraceSink`
|
|
88
|
-
|
|
89
|
-
## See also
|
|
90
|
-
|
|
91
|
-
- [Framework Reference](../../docs/en/
|
|
92
|
-
- [Content System](../../docs/en/content-system.md)
|
|
93
|
-
- [Plugin System](../../docs/en/plugin-
|
|
94
|
-
- [Architecture](../../docs/en/architecture.md)
|
|
1
|
+
# @riebeckite/core
|
|
2
|
+
|
|
3
|
+
The portable framework contract for Riebeckite: configuration, content sources,
|
|
4
|
+
the content manager, the Markdown/HTML pipeline, plugin and theme contracts,
|
|
5
|
+
diagnostics, and observability.
|
|
6
|
+
|
|
7
|
+
[日本語](./README_ja.md)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
`@riebeckite/core` owns content loading and interpretation and the contracts
|
|
12
|
+
that extensions build against. It is intentionally free of HonoX, Vite, and any
|
|
13
|
+
specific plugin, theme, or application: those depend on Core, never the reverse.
|
|
14
|
+
|
|
15
|
+
A site configures Core through `defineConfig`, and a framework integration such
|
|
16
|
+
as [`@riebeckite/honox`](../integrations/honox/README.md) drives the build.
|
|
17
|
+
Plugins and themes are plain objects created by `definePlugin` and `defineTheme`.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
pnpm add @riebeckite/core
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Core is also installed transitively by `@riebeckite/honox` and by the
|
|
26
|
+
`@riebeckite/plugin-*` and `@riebeckite/theme-*` packages.
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { defineConfig } from "@riebeckite/core";
|
|
32
|
+
|
|
33
|
+
export default defineConfig({
|
|
34
|
+
site: { title: "My notes", baseUrl: "https://example.com" },
|
|
35
|
+
content: { directory: "../../content" },
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The content directory is resolved relative to the application root. See
|
|
40
|
+
[Configuration](../../docs/en/reference/configuration.md) for the full field list and the
|
|
41
|
+
`projectRoot` / `appRoot` / `configRoot` / `contentRoot` resolution rules.
|
|
42
|
+
|
|
43
|
+
## Public API
|
|
44
|
+
|
|
45
|
+
### Configuration
|
|
46
|
+
|
|
47
|
+
- `defineConfig`, `resolveConfig`, `resolveConfigModule`, `isPublished`,
|
|
48
|
+
`isExcluded`
|
|
49
|
+
- `ConfigValidationError`
|
|
50
|
+
|
|
51
|
+
### Content
|
|
52
|
+
|
|
53
|
+
- `ContentManager` — interpretation, manifest, graph, plugin orchestration, and
|
|
54
|
+
public-location resolution
|
|
55
|
+
- `ContentSource`, `FileSystemContentSource`, `readContentSourceEntry`,
|
|
56
|
+
`getContentSourceEntry`
|
|
57
|
+
- `queryContentEntries` with the `ContentQuery*` filter and sort types
|
|
58
|
+
- `createContentGraph`, `readOnlyContentGraph`, `buildGraphEdges`,
|
|
59
|
+
`layoutRadialGraph`
|
|
60
|
+
- `resolveDefaultContentLocation`, `attachmentUrl`, and the content path and
|
|
61
|
+
extension helpers
|
|
62
|
+
- `readContentBuildStateStatus`, `resolveContentBuildStatePath`
|
|
63
|
+
|
|
64
|
+
### Pipeline
|
|
65
|
+
|
|
66
|
+
- `Pipeline`, `PipelineOptions`
|
|
67
|
+
|
|
68
|
+
### Plugins
|
|
69
|
+
|
|
70
|
+
- `definePlugin`, `resolvePlugins`, `getResolvedPluginMetadata`,
|
|
71
|
+
`PluginDependencyError`
|
|
72
|
+
- `defineEndpoint`, `createClientEntry`, `createStyleAsset`
|
|
73
|
+
- Plugin context, asset, endpoint, diagnostic, SEO, and pipeline types under
|
|
74
|
+
`Plugin*`
|
|
75
|
+
|
|
76
|
+
### Themes and contracts
|
|
77
|
+
|
|
78
|
+
- `defineTheme` and the `Theme*` types
|
|
79
|
+
- `RiebeckiteConfig`, `ResolvedRiebeckiteConfig`, `SiteConfig`,
|
|
80
|
+
`PostContent`, `PostFrontmatter`, `PublishStrategy`
|
|
81
|
+
|
|
82
|
+
### Utilities and observability
|
|
83
|
+
|
|
84
|
+
- `uniqueStrings`, `escapeHtml`, `escapeHtmlAttribute`, `normalizeTag`,
|
|
85
|
+
`calculateReadingTime`, `stripHtml`
|
|
86
|
+
- `ConsoleLogger`, `NoopLogger`, `NoopTracer`, `SinkTracer`,
|
|
87
|
+
`CompositeTraceSink`
|
|
88
|
+
|
|
89
|
+
## See also
|
|
90
|
+
|
|
91
|
+
- [Framework Reference](../../docs/en/reference/README.md)
|
|
92
|
+
- [Content System](../../docs/en/framework/content-system.md)
|
|
93
|
+
- [Plugin System](../../docs/en/reference/plugin-api.md) / [Theme System](../../docs/en/reference/theme-api.md)
|
|
94
|
+
- [Architecture](../../docs/en/framework/architecture.md)
|
package/README_ja.md
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
# @riebeckite/core
|
|
2
|
-
|
|
3
|
-
Riebeckite の移植可能なフレームワーク契約です。設定、コンテンツソース、ContentManager、Markdown/HTML パイプライン、Plugin と Theme の契約、診断、可観測性を担います。
|
|
4
|
-
|
|
5
|
-
[English](./README.md)
|
|
6
|
-
|
|
7
|
-
## 概要
|
|
8
|
-
|
|
9
|
-
`@riebeckite/core` はコンテンツの読み込みと解釈、および拡張が依存する契約を所有します。HonoX や Vite、特定の Plugin・Theme・アプリケーションには依存しません。依存の向きは常に Core へ向かい、その逆には向かいません。
|
|
10
|
-
|
|
11
|
-
サイトは `defineConfig` で Core を設定し、[`@riebeckite/honox`](../integrations/honox/README_ja.md) のような integration がビルドを実行します。Plugin と Theme は `definePlugin`、`defineTheme` が返すただのオブジェクトです。
|
|
12
|
-
|
|
13
|
-
## インストール
|
|
14
|
-
|
|
15
|
-
```sh
|
|
16
|
-
pnpm add @riebeckite/core
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
`@riebeckite/honox`、`@riebeckite/plugin-*`、`@riebeckite/theme-*` をインストールすると、依存として一緒に入ります。
|
|
20
|
-
|
|
21
|
-
## 使い方
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
import { defineConfig } from "@riebeckite/core";
|
|
25
|
-
|
|
26
|
-
export default defineConfig({
|
|
27
|
-
site: { title: "My notes", baseUrl: "https://example.com" },
|
|
28
|
-
content: { directory: "../../content" },
|
|
29
|
-
});
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
コンテンツディレクトリはアプリケーションルート基準で解決します。設定項目の全体と `projectRoot` / `appRoot` / `configRoot` / `contentRoot` の解決規則は [Configuration](../../docs/ja/configuration.md) を参照してください。
|
|
33
|
-
|
|
34
|
-
## 公開 API
|
|
35
|
-
|
|
36
|
-
### 設定
|
|
37
|
-
|
|
38
|
-
- `defineConfig`、`resolveConfig`、`resolveConfigModule`、`isPublished`、`isExcluded`
|
|
39
|
-
- `ConfigValidationError`
|
|
40
|
-
|
|
41
|
-
### コンテンツ
|
|
42
|
-
|
|
43
|
-
- `ContentManager` — 解釈、マニフェスト、グラフ、Plugin の実行、公開 URL の解決
|
|
44
|
-
- `ContentSource`、`FileSystemContentSource`、`readContentSourceEntry`、`getContentSourceEntry`
|
|
45
|
-
- `queryContentEntries` と `ContentQuery*` のフィルタ・ソート型
|
|
46
|
-
- `createContentGraph`、`readOnlyContentGraph`、`buildGraphEdges`、`layoutRadialGraph`
|
|
47
|
-
- `resolveDefaultContentLocation`、`attachmentUrl`、コンテンツパスと拡張子のヘルパー
|
|
48
|
-
- `readContentBuildStateStatus`、`resolveContentBuildStatePath`
|
|
49
|
-
|
|
50
|
-
### パイプライン
|
|
51
|
-
|
|
52
|
-
- `Pipeline`、`PipelineOptions`
|
|
53
|
-
|
|
54
|
-
### Plugin
|
|
55
|
-
|
|
56
|
-
- `definePlugin`、`resolvePlugins`、`getResolvedPluginMetadata`、`PluginDependencyError`
|
|
57
|
-
- `defineEndpoint`、`createClientEntry`、`createStyleAsset`
|
|
58
|
-
- `Plugin*` のコンテキスト、アセット、エンドポイント、診断、SEO、パイプラインの型
|
|
59
|
-
|
|
60
|
-
### Theme と契約
|
|
61
|
-
|
|
62
|
-
- `defineTheme` と `Theme*` の型
|
|
63
|
-
- `RiebeckiteConfig`、`ResolvedRiebeckiteConfig`、`SiteConfig`、`PostContent`、`PostFrontmatter`、`PublishStrategy`
|
|
64
|
-
|
|
65
|
-
### ユーティリティと可観測性
|
|
66
|
-
|
|
67
|
-
- `uniqueStrings`、`escapeHtml`、`escapeHtmlAttribute`、`normalizeTag`、`calculateReadingTime`、`stripHtml`
|
|
68
|
-
- `ConsoleLogger`、`NoopLogger`、`NoopTracer`、`SinkTracer`、`CompositeTraceSink`
|
|
69
|
-
|
|
70
|
-
## 関連資料
|
|
71
|
-
|
|
72
|
-
- [Framework Reference](../../docs/ja/
|
|
73
|
-
- [Content System](../../docs/ja/content-system.md)
|
|
74
|
-
- [Plugin System](../../docs/ja/plugin-
|
|
75
|
-
- [Architecture](../../docs/ja/architecture.md)
|
|
1
|
+
# @riebeckite/core
|
|
2
|
+
|
|
3
|
+
Riebeckite の移植可能なフレームワーク契約です。設定、コンテンツソース、ContentManager、Markdown/HTML パイプライン、Plugin と Theme の契約、診断、可観測性を担います。
|
|
4
|
+
|
|
5
|
+
[English](./README.md)
|
|
6
|
+
|
|
7
|
+
## 概要
|
|
8
|
+
|
|
9
|
+
`@riebeckite/core` はコンテンツの読み込みと解釈、および拡張が依存する契約を所有します。HonoX や Vite、特定の Plugin・Theme・アプリケーションには依存しません。依存の向きは常に Core へ向かい、その逆には向かいません。
|
|
10
|
+
|
|
11
|
+
サイトは `defineConfig` で Core を設定し、[`@riebeckite/honox`](../integrations/honox/README_ja.md) のような integration がビルドを実行します。Plugin と Theme は `definePlugin`、`defineTheme` が返すただのオブジェクトです。
|
|
12
|
+
|
|
13
|
+
## インストール
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm add @riebeckite/core
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`@riebeckite/honox`、`@riebeckite/plugin-*`、`@riebeckite/theme-*` をインストールすると、依存として一緒に入ります。
|
|
20
|
+
|
|
21
|
+
## 使い方
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { defineConfig } from "@riebeckite/core";
|
|
25
|
+
|
|
26
|
+
export default defineConfig({
|
|
27
|
+
site: { title: "My notes", baseUrl: "https://example.com" },
|
|
28
|
+
content: { directory: "../../content" },
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
コンテンツディレクトリはアプリケーションルート基準で解決します。設定項目の全体と `projectRoot` / `appRoot` / `configRoot` / `contentRoot` の解決規則は [Configuration](../../docs/ja/reference/configuration.md) を参照してください。
|
|
33
|
+
|
|
34
|
+
## 公開 API
|
|
35
|
+
|
|
36
|
+
### 設定
|
|
37
|
+
|
|
38
|
+
- `defineConfig`、`resolveConfig`、`resolveConfigModule`、`isPublished`、`isExcluded`
|
|
39
|
+
- `ConfigValidationError`
|
|
40
|
+
|
|
41
|
+
### コンテンツ
|
|
42
|
+
|
|
43
|
+
- `ContentManager` — 解釈、マニフェスト、グラフ、Plugin の実行、公開 URL の解決
|
|
44
|
+
- `ContentSource`、`FileSystemContentSource`、`readContentSourceEntry`、`getContentSourceEntry`
|
|
45
|
+
- `queryContentEntries` と `ContentQuery*` のフィルタ・ソート型
|
|
46
|
+
- `createContentGraph`、`readOnlyContentGraph`、`buildGraphEdges`、`layoutRadialGraph`
|
|
47
|
+
- `resolveDefaultContentLocation`、`attachmentUrl`、コンテンツパスと拡張子のヘルパー
|
|
48
|
+
- `readContentBuildStateStatus`、`resolveContentBuildStatePath`
|
|
49
|
+
|
|
50
|
+
### パイプライン
|
|
51
|
+
|
|
52
|
+
- `Pipeline`、`PipelineOptions`
|
|
53
|
+
|
|
54
|
+
### Plugin
|
|
55
|
+
|
|
56
|
+
- `definePlugin`、`resolvePlugins`、`getResolvedPluginMetadata`、`PluginDependencyError`
|
|
57
|
+
- `defineEndpoint`、`createClientEntry`、`createStyleAsset`
|
|
58
|
+
- `Plugin*` のコンテキスト、アセット、エンドポイント、診断、SEO、パイプラインの型
|
|
59
|
+
|
|
60
|
+
### Theme と契約
|
|
61
|
+
|
|
62
|
+
- `defineTheme` と `Theme*` の型
|
|
63
|
+
- `RiebeckiteConfig`、`ResolvedRiebeckiteConfig`、`SiteConfig`、`PostContent`、`PostFrontmatter`、`PublishStrategy`
|
|
64
|
+
|
|
65
|
+
### ユーティリティと可観測性
|
|
66
|
+
|
|
67
|
+
- `uniqueStrings`、`escapeHtml`、`escapeHtmlAttribute`、`normalizeTag`、`calculateReadingTime`、`stripHtml`
|
|
68
|
+
- `ConsoleLogger`、`NoopLogger`、`NoopTracer`、`SinkTracer`、`CompositeTraceSink`
|
|
69
|
+
|
|
70
|
+
## 関連資料
|
|
71
|
+
|
|
72
|
+
- [Framework Reference](../../docs/ja/reference/README.md)
|
|
73
|
+
- [Content System](../../docs/ja/framework/content-system.md)
|
|
74
|
+
- [Plugin System](../../docs/ja/reference/plugin-api.md) / [Theme System](../../docs/ja/reference/theme-api.md)
|
|
75
|
+
- [Architecture](../../docs/ja/framework/architecture.md)
|
package/dist/client.d.ts
ADDED
package/dist/client.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/content/graph_layout.ts
|
|
2
|
+
function buildGraphEdges(nodes, visibleSlugs = new Set(nodes.map((node) => node.slug))) {
|
|
3
|
+
const edges = /* @__PURE__ */ new Map();
|
|
4
|
+
for (const node of nodes) {
|
|
5
|
+
for (const target of node.outgoing) {
|
|
6
|
+
if (!visibleSlugs.has(node.slug) || !visibleSlugs.has(target)) continue;
|
|
7
|
+
const key = `${node.slug}\0${target}`;
|
|
8
|
+
edges.set(key, { source: node.slug, target });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return Array.from(edges.values());
|
|
12
|
+
}
|
|
13
|
+
function layoutRadialGraph(nodes, options) {
|
|
14
|
+
const layout = /* @__PURE__ */ new Map();
|
|
15
|
+
const centerX = options.width / 2;
|
|
16
|
+
const centerY = options.height / 2;
|
|
17
|
+
const radius = Math.min(options.width, options.height) * (options.radiusRatio ?? 0.36);
|
|
18
|
+
const minNodeRadius = options.minNodeRadius ?? 8;
|
|
19
|
+
const maxNodeRadius = options.maxNodeRadius ?? 14;
|
|
20
|
+
const selectedIndex = Math.max(
|
|
21
|
+
nodes.findIndex((node) => node.slug === options.centerSlug),
|
|
22
|
+
0
|
|
23
|
+
);
|
|
24
|
+
nodes.forEach((node, index) => {
|
|
25
|
+
const shiftedIndex = (index - selectedIndex + nodes.length) % nodes.length;
|
|
26
|
+
const angle = shiftedIndex / Math.max(nodes.length, 1) * Math.PI * 2;
|
|
27
|
+
const linkCount = node.outgoing.length + node.backlinks.length;
|
|
28
|
+
const isCenter = node.slug === options.centerSlug;
|
|
29
|
+
layout.set(node.slug, {
|
|
30
|
+
x: isCenter ? centerX : centerX + Math.cos(angle) * radius,
|
|
31
|
+
y: isCenter ? centerY : centerY + Math.sin(angle) * radius,
|
|
32
|
+
radius: clamp(7 + linkCount, minNodeRadius, maxNodeRadius)
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
return layout;
|
|
36
|
+
}
|
|
37
|
+
function clamp(value, min, max) {
|
|
38
|
+
return Math.min(Math.max(value, min), max);
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
buildGraphEdges,
|
|
42
|
+
layoutRadialGraph
|
|
43
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,8 @@ export type { PluginDiagnostic, PluginDiagnosticLevel, } from "./src/types/plugi
|
|
|
47
47
|
export type { PluginEndpoint, PluginEndpointContext, PluginEndpointMethod, PluginEndpointOptions, PluginEndpointRequest, PluginEndpointResponse, } from "./src/types/plugin_endpoint.js";
|
|
48
48
|
export { defineEndpoint } from "./src/types/plugin_endpoint.js";
|
|
49
49
|
export type { PluginHeadTag } from "./src/types/plugin_head.js";
|
|
50
|
-
export type {
|
|
50
|
+
export type { PluginPage, PluginPageContext, PluginPageType, ResolvedPluginPage, } from "./src/types/plugin_page.js";
|
|
51
|
+
export type { HtmlPipeline, MarkdownEmbedFragment, MarkdownExecutionContext, MarkdownPipeline, MarkdownPipelineContext, PipelinePlugin, } from "./src/types/plugin_pipeline.js";
|
|
51
52
|
export type { PluginSeoExtension, RenderableFeedEntry, SeoMetadata, WebsiteSeoInput, } from "./src/types/plugin_seo.js";
|
|
52
53
|
export type { PostContent, PostFrontmatter } from "./src/types/post_content.js";
|
|
53
54
|
export type { PublishFrontmatter, PublishStrategy, } from "./src/types/publish_strategy.js";
|
package/dist/index.js
CHANGED
|
@@ -1546,7 +1546,15 @@ var Pipeline = class {
|
|
|
1546
1546
|
options;
|
|
1547
1547
|
isBuildTime;
|
|
1548
1548
|
pluginCaches = /* @__PURE__ */ new Map();
|
|
1549
|
-
async execute(markDownContent,
|
|
1549
|
+
async execute(markDownContent, context = {}) {
|
|
1550
|
+
return await this.executeWithEmbedState(
|
|
1551
|
+
markDownContent,
|
|
1552
|
+
context,
|
|
1553
|
+
0,
|
|
1554
|
+
new Set(context.sourceSlug ? [context.sourceSlug] : [])
|
|
1555
|
+
);
|
|
1556
|
+
}
|
|
1557
|
+
async executeWithEmbedState(markDownContent, context, embedDepth, embedTrail) {
|
|
1550
1558
|
const processor = unified();
|
|
1551
1559
|
const plugins = resolvePlugins(this.options.plugins);
|
|
1552
1560
|
this.use(processor, remarkParse);
|
|
@@ -1560,7 +1568,7 @@ var Pipeline = class {
|
|
|
1560
1568
|
this.use(processor, remarkMath);
|
|
1561
1569
|
this.use(processor, remarkGfm);
|
|
1562
1570
|
const markdownPipelineContext = {
|
|
1563
|
-
sourceSlug,
|
|
1571
|
+
sourceSlug: context.sourceSlug,
|
|
1564
1572
|
contentIndex: this.contentIndex,
|
|
1565
1573
|
resolvePermalink: (slug) => this.getPermalink(slug),
|
|
1566
1574
|
renderNoteEmbed: this.createNoteEmbedRenderer(embedDepth, embedTrail),
|
|
@@ -1580,6 +1588,7 @@ var Pipeline = class {
|
|
|
1580
1588
|
markdownPipelineContext
|
|
1581
1589
|
);
|
|
1582
1590
|
}
|
|
1591
|
+
this.use(processor, normalizeMarkdownLinks, markdownPipelineContext);
|
|
1583
1592
|
this.use(processor, remarkRehype, { allowDangerousHtml: true });
|
|
1584
1593
|
this.use(processor, rehypeRaw);
|
|
1585
1594
|
for (const plugin of plugins) {
|
|
@@ -1626,11 +1635,11 @@ var Pipeline = class {
|
|
|
1626
1635
|
if (!markdown) return null;
|
|
1627
1636
|
const nextEmbedTrail = new Set(embedTrail);
|
|
1628
1637
|
nextEmbedTrail.add(slug);
|
|
1629
|
-
const content = await this.
|
|
1638
|
+
const content = await this.executeWithEmbedState(
|
|
1630
1639
|
markdown,
|
|
1640
|
+
{ sourceSlug: slug },
|
|
1631
1641
|
embedDepth + 1,
|
|
1632
|
-
nextEmbedTrail
|
|
1633
|
-
slug
|
|
1642
|
+
nextEmbedTrail
|
|
1634
1643
|
);
|
|
1635
1644
|
return content.html;
|
|
1636
1645
|
};
|
|
@@ -1693,6 +1702,81 @@ function selectBlockFragment(markdown, blockId) {
|
|
|
1693
1702
|
const line = lines.find((currentLine) => blockIdRe.test(currentLine));
|
|
1694
1703
|
return line?.replace(blockIdRe, "").trimEnd() || null;
|
|
1695
1704
|
}
|
|
1705
|
+
function normalizeMarkdownLinks(context) {
|
|
1706
|
+
return (tree) => {
|
|
1707
|
+
visitMarkdownLinkNodes(tree, (node) => {
|
|
1708
|
+
const normalizedUrl = normalizeMarkdownLinkUrl(node.url, context);
|
|
1709
|
+
if (normalizedUrl) node.url = normalizedUrl;
|
|
1710
|
+
});
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
function visitMarkdownLinkNodes(node, visitor) {
|
|
1714
|
+
const linkNode = node;
|
|
1715
|
+
if ((node.type === "link" || node.type === "definition") && typeof linkNode.url === "string") {
|
|
1716
|
+
visitor(linkNode);
|
|
1717
|
+
}
|
|
1718
|
+
for (const child of linkNode.children ?? []) {
|
|
1719
|
+
visitMarkdownLinkNodes(child, visitor);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
function normalizeMarkdownLinkUrl(url, context) {
|
|
1723
|
+
if (!context.sourceSlug) return null;
|
|
1724
|
+
if (!isMarkdownContentLink(url)) return null;
|
|
1725
|
+
const [pathAndQuery, hash3 = ""] = splitOnce(url, "#");
|
|
1726
|
+
const [rawPath, query = ""] = splitOnce(pathAndQuery, "?");
|
|
1727
|
+
const decodedPath = decodeUriPath(rawPath);
|
|
1728
|
+
if (!decodedPath?.toLowerCase().endsWith(".md")) return null;
|
|
1729
|
+
const resolvedSlug = resolveRelativeMarkdownSlug(
|
|
1730
|
+
context.sourceSlug,
|
|
1731
|
+
decodedPath
|
|
1732
|
+
);
|
|
1733
|
+
if (!resolvedSlug) return null;
|
|
1734
|
+
const indexedSlug = getExactContentSlug(context, resolvedSlug);
|
|
1735
|
+
if (!indexedSlug) return null;
|
|
1736
|
+
const suffix = `${query ? `?${query}` : ""}${hash3 ? `#${hash3}` : ""}`;
|
|
1737
|
+
return `${context.resolvePermalink(indexedSlug)}${suffix}`;
|
|
1738
|
+
}
|
|
1739
|
+
function getExactContentSlug(context, slug) {
|
|
1740
|
+
try {
|
|
1741
|
+
context.resolvePermalink(slug);
|
|
1742
|
+
return slug;
|
|
1743
|
+
} catch {
|
|
1744
|
+
return context.contentIndex.get(slug.toLowerCase()) ?? null;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
function isMarkdownContentLink(url) {
|
|
1748
|
+
if (url.startsWith("#") || url.startsWith("//")) return false;
|
|
1749
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(url)) return false;
|
|
1750
|
+
return true;
|
|
1751
|
+
}
|
|
1752
|
+
function resolveRelativeMarkdownSlug(sourceSlug, targetPath) {
|
|
1753
|
+
const sourceDirectory = sourceSlug.includes("/") ? sourceSlug.slice(0, sourceSlug.lastIndexOf("/")) : "";
|
|
1754
|
+
const baseParts = targetPath.startsWith("/") ? [] : sourceDirectory.split("/");
|
|
1755
|
+
const parts = [...baseParts, ...targetPath.replace(/^\/+/, "").split("/")];
|
|
1756
|
+
const normalizedParts = [];
|
|
1757
|
+
for (const part of parts) {
|
|
1758
|
+
if (!part || part === ".") continue;
|
|
1759
|
+
if (part === "..") {
|
|
1760
|
+
if (normalizedParts.length === 0) return null;
|
|
1761
|
+
normalizedParts.pop();
|
|
1762
|
+
continue;
|
|
1763
|
+
}
|
|
1764
|
+
normalizedParts.push(part);
|
|
1765
|
+
}
|
|
1766
|
+
return normalizedParts.join("/").replace(/\.md$/i, "");
|
|
1767
|
+
}
|
|
1768
|
+
function decodeUriPath(path4) {
|
|
1769
|
+
try {
|
|
1770
|
+
return decodeURI(path4);
|
|
1771
|
+
} catch {
|
|
1772
|
+
return null;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
function splitOnce(value, separator) {
|
|
1776
|
+
const index = value.indexOf(separator);
|
|
1777
|
+
if (index < 0) return [value];
|
|
1778
|
+
return [value.slice(0, index), value.slice(index + separator.length)];
|
|
1779
|
+
}
|
|
1696
1780
|
function selectHeadingFragment(markdown, heading) {
|
|
1697
1781
|
const lines = markdown.split(/\r?\n/);
|
|
1698
1782
|
const targetHeading = heading.trim().toLowerCase();
|
|
@@ -1982,6 +2066,53 @@ var PluginRuntime = class {
|
|
|
1982
2066
|
collectGeneratedOutputs() {
|
|
1983
2067
|
return this.generatedOutputs.all();
|
|
1984
2068
|
}
|
|
2069
|
+
async resolvePage(pathname, manifest, contentIndex) {
|
|
2070
|
+
const matches = [];
|
|
2071
|
+
const normalizedPathname = normalizePagePath(pathname);
|
|
2072
|
+
const context = {
|
|
2073
|
+
...this.createContext(contentIndex),
|
|
2074
|
+
manifest,
|
|
2075
|
+
pathname: normalizedPathname
|
|
2076
|
+
};
|
|
2077
|
+
for (const plugin of this.plugins()) {
|
|
2078
|
+
for (const pageType of plugin.pageTypes ?? []) {
|
|
2079
|
+
const page = await pageType.resolve(
|
|
2080
|
+
this.createPluginContext(plugin, context)
|
|
2081
|
+
);
|
|
2082
|
+
if (page) {
|
|
2083
|
+
matches.push({
|
|
2084
|
+
page: { ...page, type: pageType.id, pluginName: plugin.name },
|
|
2085
|
+
priority: pageType.priority ?? 0
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
if (matches.length === 0) return null;
|
|
2091
|
+
const highestPriority = Math.max(...matches.map((match) => match.priority));
|
|
2092
|
+
const highest = matches.filter(
|
|
2093
|
+
(match) => match.priority === highestPriority
|
|
2094
|
+
);
|
|
2095
|
+
if (highest.length !== 1) {
|
|
2096
|
+
throw new Error(
|
|
2097
|
+
`Multiple plugin page types match ${normalizedPathname} at priority ${highestPriority}: ${highest.map((match) => match.page.type).join(", ")}`
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
return highest[0].page;
|
|
2101
|
+
}
|
|
2102
|
+
async getPagePaths(manifest, contentIndex) {
|
|
2103
|
+
const paths = [];
|
|
2104
|
+
const context = { ...this.createContext(contentIndex), manifest };
|
|
2105
|
+
for (const plugin of this.plugins()) {
|
|
2106
|
+
for (const pageType of plugin.pageTypes ?? []) {
|
|
2107
|
+
const declared = pageType.paths;
|
|
2108
|
+
if (!declared) continue;
|
|
2109
|
+
paths.push(
|
|
2110
|
+
...typeof declared === "function" ? await declared(this.createPluginContext(plugin, context)) : declared
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
return [...new Set(paths.map(normalizePagePath))];
|
|
2115
|
+
}
|
|
1985
2116
|
async collectDiagnostics(contentIndex) {
|
|
1986
2117
|
const tracer = this.observability().tracer;
|
|
1987
2118
|
return await tracer.span("diagnostics.run", {}, async () => {
|
|
@@ -2087,9 +2218,57 @@ var PluginRuntime = class {
|
|
|
2087
2218
|
return this.pipelineOptions.observability ?? noopObservability;
|
|
2088
2219
|
}
|
|
2089
2220
|
plugins() {
|
|
2090
|
-
|
|
2221
|
+
const plugins = resolvePlugins(this.pipelineOptions.plugins);
|
|
2222
|
+
const pageTypes = /* @__PURE__ */ new Map();
|
|
2223
|
+
for (const plugin of plugins) {
|
|
2224
|
+
const declaredPageTypes = plugin.pageTypes;
|
|
2225
|
+
if (declaredPageTypes !== void 0 && !Array.isArray(declaredPageTypes)) {
|
|
2226
|
+
throw new TypeError(`Plugin ${plugin.name} pageTypes must be an array`);
|
|
2227
|
+
}
|
|
2228
|
+
for (const pageType of declaredPageTypes ?? []) {
|
|
2229
|
+
validatePageType(plugin.name, pageType);
|
|
2230
|
+
const previous = pageTypes.get(pageType.id);
|
|
2231
|
+
if (previous) {
|
|
2232
|
+
throw new Error(
|
|
2233
|
+
`Plugin page type "${pageType.id}" is provided by both ${previous} and ${plugin.name}`
|
|
2234
|
+
);
|
|
2235
|
+
}
|
|
2236
|
+
pageTypes.set(pageType.id, plugin.name);
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
return plugins;
|
|
2091
2240
|
}
|
|
2092
2241
|
};
|
|
2242
|
+
function validatePageType(pluginName, pageType) {
|
|
2243
|
+
if (typeof pageType !== "object" || pageType === null) {
|
|
2244
|
+
throw new TypeError(`Plugin ${pluginName} pageTypes must contain objects`);
|
|
2245
|
+
}
|
|
2246
|
+
const candidate = pageType;
|
|
2247
|
+
if (typeof candidate.id !== "string" || candidate.id.trim() === "") {
|
|
2248
|
+
throw new TypeError(
|
|
2249
|
+
`Plugin ${pluginName} page type id must be a non-empty string`
|
|
2250
|
+
);
|
|
2251
|
+
}
|
|
2252
|
+
if (typeof candidate.resolve !== "function") {
|
|
2253
|
+
throw new TypeError(
|
|
2254
|
+
`Plugin ${pluginName} page type "${candidate.id}" must provide a resolve function`
|
|
2255
|
+
);
|
|
2256
|
+
}
|
|
2257
|
+
if (candidate.paths !== void 0 && !Array.isArray(candidate.paths) && typeof candidate.paths !== "function") {
|
|
2258
|
+
throw new TypeError(
|
|
2259
|
+
`Plugin ${pluginName} page type "${candidate.id}" paths must be an array or function`
|
|
2260
|
+
);
|
|
2261
|
+
}
|
|
2262
|
+
if (candidate.priority !== void 0 && (typeof candidate.priority !== "number" || !Number.isFinite(candidate.priority))) {
|
|
2263
|
+
throw new TypeError(
|
|
2264
|
+
`Plugin ${pluginName} page type "${candidate.id}" priority must be a finite number`
|
|
2265
|
+
);
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
function normalizePagePath(pathname) {
|
|
2269
|
+
const path4 = `/${pathname.split("/").filter(Boolean).join("/")}`;
|
|
2270
|
+
return path4 === "/" ? path4 : path4.replace(/\/$/, "");
|
|
2271
|
+
}
|
|
2093
2272
|
function countSeverity(diagnostics, severity) {
|
|
2094
2273
|
return diagnostics.filter((diagnostic) => diagnostic.severity === severity).length;
|
|
2095
2274
|
}
|
|
@@ -2672,7 +2851,10 @@ function createContentIdIndex(entries) {
|
|
|
2672
2851
|
return byContentId;
|
|
2673
2852
|
}
|
|
2674
2853
|
function getManifestTitle(slug, title) {
|
|
2675
|
-
|
|
2854
|
+
if (typeof title === "string" && title.trim()) {
|
|
2855
|
+
return title.trim();
|
|
2856
|
+
}
|
|
2857
|
+
return slug.split("/").at(-1) ?? slug;
|
|
2676
2858
|
}
|
|
2677
2859
|
function uniqueAssets(assets) {
|
|
2678
2860
|
return Array.from(
|
|
@@ -2785,12 +2967,9 @@ var ContentManager = class {
|
|
|
2785
2967
|
this.pipelineOptions,
|
|
2786
2968
|
this.isBuildTime
|
|
2787
2969
|
);
|
|
2788
|
-
const content = await this.pipeline.execute(
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
/* @__PURE__ */ new Set([slug]),
|
|
2792
|
-
slug
|
|
2793
|
-
);
|
|
2970
|
+
const content = await this.pipeline.execute(rawPost, {
|
|
2971
|
+
sourceSlug: slug
|
|
2972
|
+
});
|
|
2794
2973
|
await this.pluginRuntime.runPostHook(
|
|
2795
2974
|
"onPostParsed",
|
|
2796
2975
|
slug,
|
|
@@ -2885,6 +3064,26 @@ var ContentManager = class {
|
|
|
2885
3064
|
const manifest = await this.getManifest();
|
|
2886
3065
|
return manifest.diagnostics;
|
|
2887
3066
|
}
|
|
3067
|
+
/** Resolves a page contributed by an enabled plugin. */
|
|
3068
|
+
async resolvePage(pathname) {
|
|
3069
|
+
const [manifest, contentIndex] = await Promise.all([
|
|
3070
|
+
this.getManifest(),
|
|
3071
|
+
this.getContentIndex()
|
|
3072
|
+
]);
|
|
3073
|
+
return await this.pluginRuntime.resolvePage(
|
|
3074
|
+
pathname,
|
|
3075
|
+
manifest,
|
|
3076
|
+
contentIndex
|
|
3077
|
+
);
|
|
3078
|
+
}
|
|
3079
|
+
/** Returns plugin page paths for SSG enumeration. */
|
|
3080
|
+
async getPagePaths() {
|
|
3081
|
+
const [manifest, contentIndex] = await Promise.all([
|
|
3082
|
+
this.getManifest(),
|
|
3083
|
+
this.getContentIndex()
|
|
3084
|
+
]);
|
|
3085
|
+
return await this.pluginRuntime.getPagePaths(manifest, contentIndex);
|
|
3086
|
+
}
|
|
2888
3087
|
async inspect() {
|
|
2889
3088
|
const [entries, contentIndex] = await Promise.all([
|
|
2890
3089
|
this.entryReader.getEntries(),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PipelineOptions } from "../pipeline.js";
|
|
2
2
|
import type { ContentManifest, ContentPublicLocation } from "../types/content_manifest.js";
|
|
3
3
|
import type { Diagnostic } from "../types/diagnostic.js";
|
|
4
|
+
import type { ResolvedPluginPage } from "../types/plugin_page.js";
|
|
4
5
|
import type { PostContent } from "../types/post_content.js";
|
|
5
6
|
import type { ResolvedRiebeckiteConfig } from "../types/resolved_riebeckite_config.js";
|
|
6
7
|
import { type ContentBuildPreparation } from "./content_build_coordinator.js";
|
|
@@ -45,6 +46,10 @@ export declare class ContentManager {
|
|
|
45
46
|
getBacklinks(targetSlug: string): Promise<Backlink[]>;
|
|
46
47
|
getContentGraph(): Promise<ContentGraph>;
|
|
47
48
|
getDiagnostics(): Promise<Diagnostic[]>;
|
|
49
|
+
/** Resolves a page contributed by an enabled plugin. */
|
|
50
|
+
resolvePage(pathname: string): Promise<ResolvedPluginPage | null>;
|
|
51
|
+
/** Returns plugin page paths for SSG enumeration. */
|
|
52
|
+
getPagePaths(): Promise<readonly string[]>;
|
|
48
53
|
inspect(): Promise<ContentInspection>;
|
|
49
54
|
dispose(): Promise<void>;
|
|
50
55
|
getContentLocations(): Promise<ReadonlyMap<string, ContentPublicLocation>>;
|
package/dist/src/pipeline.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ContentSource } from "./content/content_source.js";
|
|
2
2
|
import type { Observability } from "./observability.js";
|
|
3
3
|
import type { RiebeckitePlugin } from "./types/plugin.js";
|
|
4
|
+
import type { MarkdownExecutionContext } from "./types/plugin_pipeline.js";
|
|
4
5
|
import type { PostContent } from "./types/post_content.js";
|
|
5
6
|
export interface PipelineOptions {
|
|
6
7
|
plugins?: RiebeckitePlugin[];
|
|
@@ -16,7 +17,8 @@ export declare class Pipeline {
|
|
|
16
17
|
private isBuildTime;
|
|
17
18
|
private pluginCaches;
|
|
18
19
|
constructor(contentIndex: Map<string, string>, permalinks: ReadonlyMap<string, string>, getMarkdownBySlug?: (slug: string) => Promise<string>, options?: PipelineOptions, isBuildTime?: boolean);
|
|
19
|
-
execute(markDownContent: string,
|
|
20
|
+
execute(markDownContent: string, context?: MarkdownExecutionContext): Promise<PostContent>;
|
|
21
|
+
private executeWithEmbedState;
|
|
20
22
|
private getPermalink;
|
|
21
23
|
private use;
|
|
22
24
|
private createNoteEmbedRenderer;
|
|
@@ -3,6 +3,7 @@ import type { ContentLocationInput, ContentManifest, ContentManifestEntry, Conte
|
|
|
3
3
|
import type { Diagnostic } from "../types/diagnostic.js";
|
|
4
4
|
import type { GeneratedOutput } from "../types/generated_output.js";
|
|
5
5
|
import { type PluginClientEntry } from "../types/plugin_asset.js";
|
|
6
|
+
import type { ResolvedPluginPage } from "../types/plugin_page.js";
|
|
6
7
|
import type { PostContent } from "../types/post_content.js";
|
|
7
8
|
/**
|
|
8
9
|
* Explicit build lifecycle stages. `idle` means no build lifecycle has been
|
|
@@ -53,6 +54,8 @@ export declare class PluginRuntime {
|
|
|
53
54
|
collectClientEntries(): PluginClientEntry[];
|
|
54
55
|
/** Returns registered outputs sorted by path for a deterministic build. */
|
|
55
56
|
collectGeneratedOutputs(): GeneratedOutput[];
|
|
57
|
+
resolvePage(pathname: string, manifest: ContentManifest, contentIndex: Map<string, string>): Promise<ResolvedPluginPage | null>;
|
|
58
|
+
getPagePaths(manifest: ContentManifest, contentIndex: Map<string, string>): Promise<readonly string[]>;
|
|
56
59
|
collectDiagnostics(contentIndex: Map<string, string>): Promise<Diagnostic[]>;
|
|
57
60
|
private runBuildLifecycle;
|
|
58
61
|
private createContext;
|
|
@@ -3,6 +3,7 @@ import type { Diagnostic } from "./diagnostic.js";
|
|
|
3
3
|
import type { PluginAsset, PluginClientEntry } from "./plugin_asset.js";
|
|
4
4
|
import type { PluginContentContext, PluginContentLocationAugmentContext, PluginContentLocationResolver, PluginContentRenderer, PluginContext, PluginGeneratedHtmlInspector, PluginGraphContext, PluginLifecycleContext, PluginManifestContext, PluginPostContext } from "./plugin_context.js";
|
|
5
5
|
import type { PluginEndpoint } from "./plugin_endpoint.js";
|
|
6
|
+
import type { PluginPageType } from "./plugin_page.js";
|
|
6
7
|
import type { HtmlPipeline, MarkdownPipeline, MarkdownPipelineContext, PipelinePlugin } from "./plugin_pipeline.js";
|
|
7
8
|
import type { PluginSeoExtension } from "./plugin_seo.js";
|
|
8
9
|
export type RiebeckitePlugin<TOptions = unknown> = {
|
|
@@ -57,6 +58,8 @@ export type RiebeckitePlugin<TOptions = unknown> = {
|
|
|
57
58
|
seo?: PluginSeoExtension;
|
|
58
59
|
extendContentGraph?(context: PluginGraphContext): void | Promise<void>;
|
|
59
60
|
renderers?: PluginContentRenderer[];
|
|
61
|
+
/** Framework-independent page types contributed by this plugin. */
|
|
62
|
+
pageTypes?: PluginPageType[];
|
|
60
63
|
};
|
|
61
64
|
export type PluginInput = RiebeckitePlugin | false | null | undefined;
|
|
62
65
|
export type ResolvedPluginMetadata = {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ContentManifest } from "./content_manifest.js";
|
|
2
|
+
import type { PluginContext } from "./plugin_context.js";
|
|
3
|
+
import type { PluginHeadTag } from "./plugin_head.js";
|
|
4
|
+
/** A framework-independent page supplied by a Riebeckite plugin. */
|
|
5
|
+
export type PluginPage = {
|
|
6
|
+
/** Stable identifier of the page type that produced this page. */
|
|
7
|
+
type: string;
|
|
8
|
+
/** Canonical, absolute URL path. */
|
|
9
|
+
pathname: string;
|
|
10
|
+
/** HTML for the page body. The site owns the surrounding document frame. */
|
|
11
|
+
body: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
/** Optional document metadata rendered by the site's document frame. */
|
|
15
|
+
headTags?: readonly PluginHeadTag[];
|
|
16
|
+
};
|
|
17
|
+
export type PluginPageContext = PluginContext & {
|
|
18
|
+
/** The public manifest. Unpublished content is not exposed through pages. */
|
|
19
|
+
manifest: ContentManifest;
|
|
20
|
+
/** Request pathname, normalized to an absolute path. */
|
|
21
|
+
pathname: string;
|
|
22
|
+
};
|
|
23
|
+
export type PluginPageType = {
|
|
24
|
+
/** Globally unique, stable page type identifier. */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Paths emitted by SSG for this type. */
|
|
27
|
+
paths?: readonly string[] | ((context: PluginContext & {
|
|
28
|
+
manifest: ContentManifest;
|
|
29
|
+
}) => readonly string[] | Promise<readonly string[]>);
|
|
30
|
+
/** Higher values win when more than one type matches a request. */
|
|
31
|
+
priority?: number;
|
|
32
|
+
resolve(context: PluginPageContext): PluginPage | null | Promise<PluginPage | null>;
|
|
33
|
+
};
|
|
34
|
+
export type ResolvedPluginPage = PluginPage & {
|
|
35
|
+
pluginName: string;
|
|
36
|
+
};
|
|
@@ -6,9 +6,14 @@ export type MarkdownPipeline = {
|
|
|
6
6
|
use(plugin: PipelinePlugin, options?: unknown): void;
|
|
7
7
|
};
|
|
8
8
|
export type HtmlPipeline = MarkdownPipeline;
|
|
9
|
-
|
|
9
|
+
/** Identifies the source being processed by a Markdown pipeline execution. */
|
|
10
|
+
export type MarkdownExecutionContext = {
|
|
10
11
|
/** Slug of the content currently being rendered, when available. */
|
|
11
12
|
sourceSlug?: string;
|
|
13
|
+
};
|
|
14
|
+
export type MarkdownPipelineContext = {
|
|
15
|
+
/** Source identity supplied for this execution, when available. */
|
|
16
|
+
sourceSlug?: MarkdownExecutionContext["sourceSlug"];
|
|
12
17
|
contentIndex: Map<string, string>;
|
|
13
18
|
resolvePermalink: (slug: string) => string;
|
|
14
19
|
renderNoteEmbed?: (slug: string, fragment: MarkdownEmbedFragment | null) => Promise<string | null>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
"source": "./index.ts",
|
|
13
13
|
"default": "./dist/index.js"
|
|
14
14
|
},
|
|
15
|
+
"./client": {
|
|
16
|
+
"types": "./dist/client.d.ts",
|
|
17
|
+
"import": "./dist/client.js",
|
|
18
|
+
"source": "./client.ts",
|
|
19
|
+
"default": "./dist/client.js"
|
|
20
|
+
},
|
|
15
21
|
"./package.json": "./package.json"
|
|
16
22
|
},
|
|
17
23
|
"files": [
|
|
@@ -43,7 +49,7 @@
|
|
|
43
49
|
},
|
|
44
50
|
"devDependencies": {
|
|
45
51
|
"tsx": "^4.22.4",
|
|
46
|
-
"@riebeckite/test": "0.0.
|
|
52
|
+
"@riebeckite/test": "0.0.13"
|
|
47
53
|
},
|
|
48
54
|
"repository": {
|
|
49
55
|
"type": "git",
|