noblog 0.2.3 β 0.3.0-beta.2
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 +280 -121
- package/dist/client-CzKR81Or.js +551 -0
- package/dist/client-CzKR81Or.js.map +1 -0
- package/dist/config-check.impl-C5FM7uWi.js +14 -0
- package/dist/config-check.impl-C5FM7uWi.js.map +1 -0
- package/dist/config-csbquMhF.js +21 -0
- package/dist/config-csbquMhF.js.map +1 -0
- package/dist/config-file-C07nmm45.js +27 -0
- package/dist/config-file-C07nmm45.js.map +1 -0
- package/dist/defaults-RGOB9tfi.js +10 -0
- package/dist/defaults-RGOB9tfi.js.map +1 -0
- package/dist/errors-BCRhKbgG.js +73 -0
- package/dist/errors-BCRhKbgG.js.map +1 -0
- package/dist/frontmatter-fields-BkXq38CO.js +71 -0
- package/dist/frontmatter-fields-BkXq38CO.js.map +1 -0
- package/dist/generate.d.ts +1 -0
- package/dist/generate.impl-ChFrtwtC.js +34 -0
- package/dist/generate.impl-ChFrtwtC.js.map +1 -0
- package/dist/generate.js +198 -940
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +213 -18
- package/dist/index.js +5 -0
- package/package.json +32 -17
- package/schema/config.json +178 -0
- package/skills/noblog-config/SKILL.md +40 -0
- package/skills/noblog-config/assets/nobloger.yaml +30 -0
- package/skills/noblog-config/assets/thought-lite.yaml +47 -0
- package/skills/noblog-config/references/config-schema.md +110 -0
- package/skills/noblog-config/references/notion-property-types.md +42 -0
- package/skills/noblog-config/references/theme-examples.md +41 -0
- package/dist/cmds/generate.d.ts +0 -3
- package/dist/cmds/generate.d.ts.map +0 -1
- package/dist/generate.cjs +0 -970
- package/dist/generate.cjs.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/noblog/format.d.ts +0 -24
- package/dist/lib/noblog/format.d.ts.map +0 -1
- package/dist/lib/noblog/noblog.d.ts +0 -31
- package/dist/lib/noblog/noblog.d.ts.map +0 -1
- package/dist/lib/noblog/utils.d.ts +0 -36
- package/dist/lib/noblog/utils.d.ts.map +0 -1
- package/dist/lib/notion/client.d.ts +0 -8
- package/dist/lib/notion/client.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,208 +1,367 @@
|
|
|
1
1
|
# π Noblog
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Generate Astro-compatible Markdown from your Notion database.
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/noblog)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
Noblog
|
|
8
|
+
Noblog fetches published Notion pages, converts their blocks to Markdown, and writes a complete blog structure with Astro frontmatter. Each page lives once in a canonical store. Database posts also receive public symlinks, while child pages are referenced directly in the store. Custom output, store, and layout paths are supported.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
The renderer includes logic derived from [notion-to-md](https://github.com/souvikinator/notion-to-md), with additional handling for nested formatting and blog generation.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Requirements
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
- Node.js 24 or newer
|
|
15
|
+
- A Notion integration with read access to your database
|
|
16
|
+
- A Notion database with `publish` and `date` properties
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
When dealing with complex formatting like nested styles (e.g., `{BLOCK1}` and `{BLOCK2}` both bold, but only `BLOCK1` also italic), notion-to-md generates malformed markdown:
|
|
18
|
+
## Installation
|
|
18
19
|
|
|
19
|
-
```
|
|
20
|
-
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g noblog
|
|
21
22
|
```
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- **Merged Tag Handling**: Properly merges nested formatting tags
|
|
26
|
-
- **Clean Markdown Output**: Generates valid, renderer-friendly markdown
|
|
27
|
-
- **Astro-Optimized**: Specifically designed for static site generation
|
|
28
|
-
|
|
29
|
-
### ποΈ **Complete Blog Structure**
|
|
24
|
+
For use as a library in another package:
|
|
30
25
|
|
|
31
|
-
|
|
26
|
+
```bash
|
|
27
|
+
npm install noblog
|
|
28
|
+
```
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
## Configuration
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
- β
Parent/child page organization
|
|
37
|
-
- β
Astro-compatible frontmatter
|
|
38
|
-
- β
Customizable save paths
|
|
39
|
-
- β
Layout path customization
|
|
40
|
-
- β
Theme marketplace ready
|
|
32
|
+
Set the following environment variables in your shell or in a `.env` file in the directory where you run `noblog`:
|
|
41
33
|
|
|
42
|
-
|
|
34
|
+
```bash
|
|
35
|
+
NOTION_API_SECRET="your-notion-api-secret"
|
|
36
|
+
NOBLOG_DATABASE_ID="your-notion-database-id"
|
|
37
|
+
```
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
The CLI loads `.env` automatically. Credentials are validated only when generating content, so `--help`, `--version`, and `config check` do not require them. Keep credentials in environment variables or `.env`; YAML configuration has no credential fields.
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
# With Noblog - everything handled automatically
|
|
48
|
-
noblog --layout ../../layouts/BlogLayout.astro
|
|
41
|
+
## Usage
|
|
49
42
|
|
|
50
|
-
|
|
43
|
+
```text
|
|
44
|
+
noblog [generate] [options] [SAVE_PATH] [SUB_PATH]
|
|
51
45
|
```
|
|
52
46
|
|
|
53
|
-
|
|
47
|
+
Running `noblog` without arguments immediately generates content with the default settings. It does not print help.
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
### Commands
|
|
56
50
|
|
|
57
|
-
|
|
51
|
+
| Command | Description |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `noblog` / `noblog generate` | Generate blog content |
|
|
54
|
+
| `noblog config check --config PATH` | Validate YAML without credentials or network access |
|
|
55
|
+
| `noblog help` | Show general help |
|
|
56
|
+
| `noblog version` | Show the installed version |
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
npm install -g noblog
|
|
61
|
-
```
|
|
58
|
+
### Options
|
|
62
59
|
|
|
63
|
-
|
|
60
|
+
| Option | Description |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| `-v, --verbose` | Print diagnostics and error stack traces |
|
|
63
|
+
| `--config PATH` | Load YAML configuration for generation |
|
|
64
|
+
| `--layout PATH` | Set the layout path relative to `SAVE_PATH` |
|
|
65
|
+
| `--store PATH` | Set the canonical Markdown store (default: `.noblog/pages/`) |
|
|
66
|
+
| `-h, --help` | Show general or command-specific help |
|
|
67
|
+
| `--version` | Show the installed version |
|
|
68
|
+
| `--` | Treat all remaining inputs as positional paths |
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
noblog
|
|
67
|
-
```
|
|
70
|
+
### Positional arguments
|
|
68
71
|
|
|
69
|
-
|
|
72
|
+
| Argument | Default | Description |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| `SAVE_PATH` | `./src/pages/posts/` | Public view directory for database posts |
|
|
75
|
+
| `SUB_PATH` | β | Deprecated compatibility argument; ignored with a warning |
|
|
70
76
|
|
|
71
|
-
###
|
|
72
|
-
|
|
73
|
-
Noblog supports various command-line options to customize your blog generation:
|
|
77
|
+
### Examples
|
|
74
78
|
|
|
75
79
|
```bash
|
|
76
|
-
#
|
|
80
|
+
# Generate with all defaults
|
|
77
81
|
noblog
|
|
78
82
|
|
|
79
|
-
#
|
|
83
|
+
# Equivalent explicit command
|
|
84
|
+
noblog generate
|
|
85
|
+
|
|
86
|
+
# Use a custom layout
|
|
80
87
|
noblog --layout ../../layouts/BlogLayout.astro
|
|
81
88
|
|
|
82
|
-
#
|
|
83
|
-
noblog ./content/blog/
|
|
89
|
+
# Write database-post symlinks to ./content/blog/
|
|
90
|
+
noblog ./content/blog/ --layout ../../layouts/CustomLayout.astro
|
|
84
91
|
|
|
85
|
-
#
|
|
86
|
-
noblog -
|
|
87
|
-
# or
|
|
88
|
-
noblog --verbose
|
|
89
|
-
```
|
|
92
|
+
# Store the real Markdown files in a custom canonical store
|
|
93
|
+
noblog --store content/.noblog-pages
|
|
90
94
|
|
|
91
|
-
|
|
95
|
+
# Generate using YAML configuration
|
|
96
|
+
noblog --config ./noblog.yaml
|
|
92
97
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- `-h, --help` - Show help message
|
|
96
|
-
- `--version` - Show version information
|
|
98
|
+
# Validate configuration without credentials or Notion access
|
|
99
|
+
noblog config check --config ./noblog.yaml
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
# Print diagnostics
|
|
102
|
+
noblog generate -v
|
|
99
103
|
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
# Show help for the generate command and its arguments
|
|
105
|
+
noblog generate --help
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## YAML configuration
|
|
102
109
|
|
|
103
|
-
|
|
110
|
+
Pass `--config PATH` to load a versioned YAML file. Configuration is explicit; Noblog does not search for a YAML file automatically. Generation resolves each output setting with this precedence:
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
```text
|
|
113
|
+
built-in defaults < YAML configuration < explicit CLI flags and SAVE_PATH
|
|
114
|
+
```
|
|
106
115
|
|
|
107
|
-
|
|
116
|
+
For example, this config adapts output and frontmatter to a theme with a native date, custom Notion properties, and typed boolean/number fields:
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
version: 1
|
|
120
|
+
notion:
|
|
121
|
+
properties:
|
|
122
|
+
title: Name
|
|
123
|
+
publishedAt: Published
|
|
124
|
+
series: Series
|
|
125
|
+
sensitive: Sensitive
|
|
126
|
+
top: Top
|
|
127
|
+
output:
|
|
128
|
+
savePath: src/pages/posts/
|
|
129
|
+
storePath: .noblog/pages/
|
|
130
|
+
layoutPath: ../../layouts/MarkdownPostLayout.astro
|
|
131
|
+
recursive: true
|
|
132
|
+
childPageMarker: "βΈ"
|
|
133
|
+
frontmatter:
|
|
134
|
+
fields:
|
|
135
|
+
title:
|
|
136
|
+
from: title
|
|
137
|
+
required: true
|
|
138
|
+
timestamp:
|
|
139
|
+
from: publishedAt
|
|
140
|
+
as: date
|
|
141
|
+
required: true
|
|
142
|
+
series:
|
|
143
|
+
from: series
|
|
144
|
+
omitEmpty: true
|
|
145
|
+
sensitive:
|
|
146
|
+
from: sensitive
|
|
147
|
+
default: false
|
|
148
|
+
top:
|
|
149
|
+
from: top
|
|
150
|
+
default: 0
|
|
151
|
+
toc:
|
|
152
|
+
value: true
|
|
153
|
+
```
|
|
108
154
|
|
|
109
|
-
|
|
155
|
+
`output.childPageMarker` sets the prefix on child-page links. It defaults to `βΈ` (U+2E0E EDITORIAL CORONIS) and must be a non-empty string. Set it to a marker your theme recognizes.
|
|
110
156
|
|
|
111
|
-
|
|
157
|
+
The keys under `notion.properties` are logical source names; their values must exactly match Notion property names. Custom sources such as `series` must be declared there before frontmatter can reference them. Built-in sources need no declaration.
|
|
158
|
+
|
|
159
|
+
Validate a file without Notion credentials, a Notion client, or network access:
|
|
112
160
|
|
|
113
161
|
```bash
|
|
114
|
-
|
|
115
|
-
export NOTION_API_SECRET="your-notion-api-secret"
|
|
162
|
+
noblog config check --config ./noblog.yaml
|
|
116
163
|
```
|
|
117
164
|
|
|
118
|
-
|
|
165
|
+
The machine-readable JSON Schema is generated from the runtime Zod schema and shipped as `schema/config.json` (package export: `noblog/config.schema.json`). For a local installation, enable editor validation with:
|
|
119
166
|
|
|
120
|
-
|
|
167
|
+
```yaml
|
|
168
|
+
# yaml-language-server: $schema=./node_modules/noblog/schema/config.json
|
|
169
|
+
```
|
|
121
170
|
|
|
122
|
-
|
|
171
|
+
The schema checks structure and native types. `config check` additionally enforces cross-field rules such as declared custom sources. Invalid YAML, unsupported versions, unknown keys, and invalid field definitions exit with status 2.
|
|
123
172
|
|
|
124
|
-
|
|
173
|
+
A standard Agent Skill is included at [`skills/noblog-config/SKILL.md`](skills/noblog-config/SKILL.md), with detailed references and Nobloger/ThoughtLite examples. Copy that directory into your agent's skills location or point the agent at it. The skill inspects the theme's actual collection schema, frontmatter consumers, and routes before generating YAML; it does not need or request Notion credentials.
|
|
125
174
|
|
|
126
|
-
##
|
|
175
|
+
## Output structure
|
|
127
176
|
|
|
128
|
-
|
|
177
|
+
With the default paths, Noblog names files by Notion page ID. All real Markdown files are flat in `.noblog/pages/`; database posts also have relative symlinks in `SAVE_PATH`:
|
|
129
178
|
|
|
130
|
-
```
|
|
179
|
+
```text
|
|
131
180
|
project-root/
|
|
181
|
+
βββ .noblog/
|
|
182
|
+
β βββ pages/
|
|
183
|
+
β βββ <database-page-id>.md # real file
|
|
184
|
+
β βββ <child-page-id>.md # real file
|
|
132
185
|
βββ src/
|
|
133
186
|
βββ pages/
|
|
134
187
|
βββ posts/
|
|
135
|
-
|
|
136
|
-
βββ blog-post-2.md
|
|
137
|
-
βββ nob_children/
|
|
138
|
-
βββ sub-post-1.md # Referenced/child pages
|
|
139
|
-
βββ sub-post-2.md
|
|
140
|
-
βββ sub-post-3.md
|
|
188
|
+
βββ <database-page-id>.md # relative symlink
|
|
141
189
|
```
|
|
142
190
|
|
|
143
|
-
|
|
191
|
+
Only database posts receive public views. Child pages live exclusively in the canonical store, and child links are written as `<marker> [title](./<child-page-id>.md)`. The marker defaults to `βΈ` (U+2E0E EDITORIAL CORONIS) and is configurable with `output.childPageMarker`; set it to match the marker your theme recognizes. Links resolve as siblings after Vite/Astro resolves symlinks to real paths, so child pages stay out of `src/pages/posts/*.md` listings. Use `--store PATH` to change the canonical store independently of the public path.
|
|
144
192
|
|
|
145
|
-
|
|
193
|
+
**Routing migration:** Noblog no longer creates `/nob_children/` routes. Configure the theme to load and route child pages from `.noblog/pages/` (or the custom store). Existing nested view files are not deleted; remove or redirect them separately after updating the theme. Existing `SUB_PATH` arguments are ignored with a warning.
|
|
146
194
|
|
|
147
|
-
|
|
148
|
-
noblog <SAVE_PATH> <SUB_PATH>
|
|
195
|
+
Generation is repeatable. Existing regular database-post view files with matching page IDs are replaced by links, and all canonical files are updated. Unrelated files are left unchanged; directories and other non-file outputs are not replaced.
|
|
149
196
|
|
|
150
|
-
|
|
151
|
-
noblog ./content/blog/ ./content/blog/subpages/
|
|
152
|
-
```
|
|
197
|
+
The store and views must remain together when building or deploying. If generated content is committed, include both; otherwise regenerate before building. Creating the views requires filesystem symlink support. On Windows, this may require Developer Mode or elevated privileges.
|
|
153
198
|
|
|
154
|
-
##
|
|
199
|
+
## Frontmatter
|
|
155
200
|
|
|
156
|
-
|
|
201
|
+
Without custom Notion or frontmatter mappings, generated files retain the legacy Astro-compatible frontmatter:
|
|
157
202
|
|
|
158
|
-
```
|
|
203
|
+
```yaml
|
|
159
204
|
---
|
|
160
|
-
layout: ../../layouts/MarkdownPostLayout.astro
|
|
205
|
+
layout: ../../src/layouts/MarkdownPostLayout.astro
|
|
161
206
|
title: "Your Blog Post Title"
|
|
162
|
-
tags: ["tag1", "tag2", "tag3"]
|
|
163
|
-
pubDate: 2024-01-24
|
|
164
|
-
archived: false
|
|
165
207
|
description: "Your post description here"
|
|
208
|
+
tags: ["tag1", "tag2", "tag3"]
|
|
209
|
+
pubDate: "2024-01-24"
|
|
210
|
+
archived: "false"
|
|
166
211
|
---
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
When `frontmatter.fields` is present, it defines the complete output field set; legacy fields are not implicitly added. When only `notion.properties` is present, Noblog uses the declarative equivalent of the legacy fields (`layout`, `title`, `description`, `tags`, `pubDate`, and `archived`) with the configured property names.
|
|
215
|
+
|
|
216
|
+
Every custom field has exactly one of:
|
|
217
|
+
|
|
218
|
+
- `from`: read a built-in source or a key declared under `notion.properties`.
|
|
219
|
+
- `value`: emit a static native string, finite number, boolean, null, array, or nested object.
|
|
220
|
+
|
|
221
|
+
Built-in sources are `title`, `description`, `tags`, `publishedAt`, `archived`, `layoutPath`, `pageId`, and `isDatabasePage`. Without explicit property mappings, the conventional Notion names are `description`, `tags`, `date`, and `archived`; title comes from the last Notion title property.
|
|
222
|
+
|
|
223
|
+
Field behavior can be refined with:
|
|
224
|
+
|
|
225
|
+
| Directive | Behavior |
|
|
226
|
+
| --- | --- |
|
|
227
|
+
| `default` | Use this value when the source is empty |
|
|
228
|
+
| `required` | Fail generation if the value remains empty after defaults; errors include the field and page ID |
|
|
229
|
+
| `omitEmpty` | Omit an empty value after default/required processing |
|
|
230
|
+
| `as: string` | Convert a string, number, or boolean to a string; date-like strings remain quoted |
|
|
231
|
+
| `as: date` | Convert a valid date string or finite number to an unquoted YAML timestamp |
|
|
232
|
+
|
|
233
|
+
Empty means `undefined`, `null`, `""`, or `[]`; `false` and `0` are preserved. Processing order is source/static value, default, required check, omission, then conversion.
|
|
234
|
+
|
|
235
|
+
Notion values are normalized according to their actual property types. Text, select/status, dates, URLs, times, users, and unique IDs become strings; checkboxes and numeric properties remain native; multi-selects, people, relations, and files become string arrays. Formula results follow their own value type. Unsupported or missing properties become `undefined`, so defaults and omission rules apply. See the [property-type reference](skills/noblog-config/references/notion-property-types.md) for the complete table.
|
|
236
|
+
|
|
237
|
+
This makes native theme schemas possible without stringly-typed frontmatter: `as: string` can produce `pubDate: "2024-01-24"`, while `as: date` produces `timestamp: 2024-01-24`, and booleans/numbers remain unquoted unless conversion is requested.
|
|
238
|
+
|
|
239
|
+
Vite and Astro resolve Markdown symlinks to their real paths, so layout imports must be relative to the canonical store. The CLI interprets `--layout` relative to `SAVE_PATH`, then writes the equivalent store-relative path for every page.
|
|
240
|
+
|
|
241
|
+
## Programmatic API
|
|
242
|
+
|
|
243
|
+
The package exposes a reusable renderer and filesystem writer. The optional Notion adapter is configured explicitly; importing `noblog` has no environment or network side effects.
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
import {
|
|
247
|
+
createNotionSource,
|
|
248
|
+
renderPages,
|
|
249
|
+
resolveStoreLayoutPath,
|
|
250
|
+
writePages,
|
|
251
|
+
} from "noblog";
|
|
252
|
+
|
|
253
|
+
const notionApiSecret = process.env["NOTION_API_SECRET"];
|
|
254
|
+
const databaseId = process.env["NOBLOG_DATABASE_ID"];
|
|
255
|
+
if (!notionApiSecret || !databaseId) {
|
|
256
|
+
throw new Error("Notion credentials are required");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const notion = createNotionSource({ notionApiSecret, databaseId });
|
|
167
260
|
|
|
168
|
-
|
|
261
|
+
const savePath = "./content/blog/";
|
|
262
|
+
const storePath = ".noblog/pages/";
|
|
263
|
+
const layoutPath = resolveStoreLayoutPath({
|
|
264
|
+
savePath,
|
|
265
|
+
storePath,
|
|
266
|
+
layoutPath: "../../layouts/MarkdownPostLayout.astro",
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const posts = await notion.listPages();
|
|
270
|
+
const pages = await renderPages(posts, notion, { layoutPath });
|
|
271
|
+
|
|
272
|
+
await writePages(pages, { savePath, storePath });
|
|
169
273
|
```
|
|
170
274
|
|
|
171
|
-
|
|
275
|
+
`renderPages` recursively collects child pages by default and returns complete Markdown documents with frontmatter. Set `recursive: false` to render only the supplied database pages. Set `childPageMarker` in `RenderOptions` to override the default `βΈ` (U+2E0E EDITORIAL CORONIS) prefix used for child-page links. `writePages` writes every canonical file but returns only the public database-post view paths. When rendering for a canonical store, use `resolveStoreLayoutPath` as above so layout imports remain valid after symlink resolution.
|
|
276
|
+
|
|
277
|
+
Use `renderPage` for a single page, or supply any implementation of the `NotionReader` interface instead of the built-in adapter. Lower-level helpers such as `renderRichText` and `renderFrontmatter` are exported as well. To customize a block, pass a `transformers` map in `RenderOptions`; return a string to override the default renderer or `undefined` to fall back to it. Each key narrows its handler's block payload to the corresponding Notion block type, so a `paragraph` transformer can access `block.paragraph` directly. The programmatic API does not load `.env`; load environment variables yourself or pass explicit configuration.
|
|
278
|
+
|
|
279
|
+
The same declarative mapping is available programmatically, or you can provide a `FrontmatterAdapter` function for full control:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import { createFrontmatterAdapter, renderPages } from "noblog";
|
|
283
|
+
|
|
284
|
+
const frontmatter = createFrontmatterAdapter({
|
|
285
|
+
title: { from: "title", required: true },
|
|
286
|
+
timestamp: { from: "publishedAt", as: "date" },
|
|
287
|
+
draft: { from: "archived", default: false },
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const pages = await renderPages(posts, notion, {
|
|
291
|
+
layoutPath,
|
|
292
|
+
propertyMap: { publishedAt: "Published" },
|
|
293
|
+
frontmatter,
|
|
294
|
+
});
|
|
295
|
+
```
|
|
172
296
|
|
|
173
|
-
|
|
297
|
+
An adapter receives `{ page, metadata, layoutPath, isDatabasePage }` and returns a plain object. It can use the raw Notion page or normalized metadata, and root `undefined` values are omitted. Values follow the exported `FrontmatterValue` contract: strings, numbers, booleans, `null`, `Date`, and readonly arrays/objects containing those values. Arrays, null, dates, and class instances are rejected as adapter roots.
|
|
174
298
|
|
|
175
|
-
|
|
299
|
+
## Exit codes
|
|
176
300
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
301
|
+
| Code | Meaning |
|
|
302
|
+
| --- | --- |
|
|
303
|
+
| `0` | Help, version, successful validation, or successful generation |
|
|
304
|
+
| `1` | Generation or unexpected runtime failure |
|
|
305
|
+
| `2` | Invalid arguments, YAML, or configuration |
|
|
181
306
|
|
|
182
|
-
|
|
307
|
+
## Development
|
|
183
308
|
|
|
184
|
-
|
|
309
|
+
Noblog uses [Stricli](https://bloomberg.github.io/stricli/) for typed command routing, [tsdown](https://tsdown.dev/) for CLI/library builds, and [Vitest](https://vitest.dev/) for tests.
|
|
185
310
|
|
|
186
311
|
```bash
|
|
187
|
-
|
|
188
|
-
noblog --layout ../../layouts/BlogLayout.astro
|
|
312
|
+
pnpm install
|
|
189
313
|
|
|
190
|
-
#
|
|
191
|
-
|
|
192
|
-
|
|
314
|
+
# Run the TypeScript CLI directly
|
|
315
|
+
pnpm dev --help
|
|
316
|
+
|
|
317
|
+
# Run unit tests and type checking
|
|
318
|
+
pnpm test
|
|
319
|
+
pnpm typecheck
|
|
193
320
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
- If you change the save path to `./content/blog/`, you might need `--layout ../../layouts/CustomLayout.astro` to point to `./content/layouts/CustomLayout.astro`
|
|
321
|
+
# Regenerate the published JSON Schema (also runs during build)
|
|
322
|
+
pnpm schema:generate
|
|
197
323
|
|
|
198
|
-
|
|
324
|
+
# Build and smoke-test the actual dist artifacts
|
|
325
|
+
pnpm test:built
|
|
199
326
|
|
|
200
|
-
|
|
327
|
+
# Run the complete verification suite
|
|
328
|
+
pnpm check
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Project structure
|
|
332
|
+
|
|
333
|
+
```text
|
|
334
|
+
src/
|
|
335
|
+
βββ cli.ts # Process entry
|
|
336
|
+
βββ main.ts # Dotenv loading and dependency composition
|
|
337
|
+
βββ app.ts # Routes, help/version, and exit handling
|
|
338
|
+
βββ config-file.ts # YAML loading and validation
|
|
339
|
+
βββ commands/
|
|
340
|
+
β βββ config*.ts # Offline configuration validation
|
|
341
|
+
β βββ generate.ts # Declarative arguments and documentation
|
|
342
|
+
β βββ generate.impl.ts # Lazy-loaded command action
|
|
343
|
+
βββ workflows/
|
|
344
|
+
β βββ generate.ts # CLI-oriented generation orchestration
|
|
345
|
+
βββ lib/
|
|
346
|
+
βββ noblog/ # Reusable rendering and file-writing package
|
|
347
|
+
β βββ config.ts # Runtime YAML schema and types
|
|
348
|
+
β βββ metadata.ts # Notion property normalization
|
|
349
|
+
β βββ frontmatter-fields.ts # Declarative frontmatter adapter
|
|
350
|
+
β βββ pages.ts # Page collection, caching, and recursion
|
|
351
|
+
β βββ blocks.ts # Notion block-tree loading and rendering
|
|
352
|
+
β βββ rich-text.ts # Rich-text annotations and links
|
|
353
|
+
β βββ markdown.ts # Markdown formatting primitives
|
|
354
|
+
β βββ frontmatter.ts # Legacy/custom frontmatter serialization
|
|
355
|
+
β βββ writer.ts # Canonical store and database-post symlinks
|
|
356
|
+
βββ notion/client.ts # Explicit Notion SDK adapter
|
|
357
|
+
schema/config.json # Generated JSON Schema
|
|
358
|
+
skills/noblog-config/ # Agent Skill, references, and examples
|
|
359
|
+
```
|
|
201
360
|
|
|
202
|
-
|
|
361
|
+
## Acknowledgments
|
|
203
362
|
|
|
204
|
-
- [Notion API](https://developers.notion.com/reference/intro)
|
|
205
|
-
- [
|
|
206
|
-
- [
|
|
207
|
-
- [
|
|
208
|
-
- [
|
|
363
|
+
- [Notion API](https://developers.notion.com/reference/intro) and [Notion SDK](https://github.com/makenotion/notion-sdk-js)
|
|
364
|
+
- [notion-to-md](https://github.com/souvikinator/notion-to-md)
|
|
365
|
+
- [notablog](https://github.com/dragonman225/notablog)
|
|
366
|
+
- [astro-notion-blog](https://github.com/otoyo/astro-notion-blog)
|
|
367
|
+
- [nobloger](https://github.com/humbornjo/nobloger), a starter Astro template
|