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.
Files changed (43) hide show
  1. package/README.md +280 -121
  2. package/dist/client-CzKR81Or.js +551 -0
  3. package/dist/client-CzKR81Or.js.map +1 -0
  4. package/dist/config-check.impl-C5FM7uWi.js +14 -0
  5. package/dist/config-check.impl-C5FM7uWi.js.map +1 -0
  6. package/dist/config-csbquMhF.js +21 -0
  7. package/dist/config-csbquMhF.js.map +1 -0
  8. package/dist/config-file-C07nmm45.js +27 -0
  9. package/dist/config-file-C07nmm45.js.map +1 -0
  10. package/dist/defaults-RGOB9tfi.js +10 -0
  11. package/dist/defaults-RGOB9tfi.js.map +1 -0
  12. package/dist/errors-BCRhKbgG.js +73 -0
  13. package/dist/errors-BCRhKbgG.js.map +1 -0
  14. package/dist/frontmatter-fields-BkXq38CO.js +71 -0
  15. package/dist/frontmatter-fields-BkXq38CO.js.map +1 -0
  16. package/dist/generate.d.ts +1 -0
  17. package/dist/generate.impl-ChFrtwtC.js +34 -0
  18. package/dist/generate.impl-ChFrtwtC.js.map +1 -0
  19. package/dist/generate.js +198 -940
  20. package/dist/generate.js.map +1 -1
  21. package/dist/index.d.ts +213 -18
  22. package/dist/index.js +5 -0
  23. package/package.json +32 -17
  24. package/schema/config.json +178 -0
  25. package/skills/noblog-config/SKILL.md +40 -0
  26. package/skills/noblog-config/assets/nobloger.yaml +30 -0
  27. package/skills/noblog-config/assets/thought-lite.yaml +47 -0
  28. package/skills/noblog-config/references/config-schema.md +110 -0
  29. package/skills/noblog-config/references/notion-property-types.md +42 -0
  30. package/skills/noblog-config/references/theme-examples.md +41 -0
  31. package/dist/cmds/generate.d.ts +0 -3
  32. package/dist/cmds/generate.d.ts.map +0 -1
  33. package/dist/generate.cjs +0 -970
  34. package/dist/generate.cjs.map +0 -1
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/lib/noblog/format.d.ts +0 -24
  37. package/dist/lib/noblog/format.d.ts.map +0 -1
  38. package/dist/lib/noblog/noblog.d.ts +0 -31
  39. package/dist/lib/noblog/noblog.d.ts.map +0 -1
  40. package/dist/lib/noblog/utils.d.ts +0 -36
  41. package/dist/lib/noblog/utils.d.ts.map +0 -1
  42. package/dist/lib/notion/client.d.ts +0 -8
  43. package/dist/lib/notion/client.d.ts.map +0 -1
@@ -0,0 +1,30 @@
1
+ # Matches Nobloger's MarkdownPostLayout and blog listing contract.
2
+ version: 1
3
+ notion:
4
+ properties:
5
+ title: Name
6
+ description: description
7
+ tags: tags
8
+ publishedAt: date
9
+ output:
10
+ savePath: src/pages/posts/
11
+ storePath: .noblog/pages/
12
+ layoutPath: ../../layouts/MarkdownPostLayout.astro
13
+ recursive: true
14
+ frontmatter:
15
+ fields:
16
+ layout:
17
+ from: layoutPath
18
+ title:
19
+ from: title
20
+ required: true
21
+ pubDate:
22
+ from: publishedAt
23
+ as: string
24
+ required: true
25
+ tags:
26
+ from: tags
27
+ default: []
28
+ description:
29
+ from: description
30
+ omitEmpty: true
@@ -0,0 +1,47 @@
1
+ # Matches ThoughtLite's `note` collection; re-check the installed version.
2
+ version: 1
3
+ notion:
4
+ properties:
5
+ title: Name
6
+ publishedAt: date
7
+ description: description
8
+ tags: tags
9
+ series: Series
10
+ sensitive: Sensitive
11
+ top: Top
12
+ archived: archived
13
+ output:
14
+ # The collection reads canonical files directly from this store.
15
+ storePath: src/content/note/
16
+ # Required database-post links stay outside the collection glob.
17
+ savePath: .noblog/note-links/
18
+ recursive: true
19
+ frontmatter:
20
+ fields:
21
+ title:
22
+ from: title
23
+ required: true
24
+ timestamp:
25
+ from: publishedAt
26
+ as: date
27
+ required: true
28
+ series:
29
+ from: series
30
+ omitEmpty: true
31
+ tags:
32
+ from: tags
33
+ omitEmpty: true
34
+ description:
35
+ from: description
36
+ omitEmpty: true
37
+ sensitive:
38
+ from: sensitive
39
+ default: false
40
+ toc:
41
+ value: true
42
+ top:
43
+ from: top
44
+ default: 0
45
+ draft:
46
+ from: archived
47
+ default: false
@@ -0,0 +1,110 @@
1
+ # Noblog YAML configuration reference
2
+
3
+ ## Precedence and credentials
4
+
5
+ Generation resolves settings in this order:
6
+
7
+ ```text
8
+ built-in defaults < YAML configuration < explicit CLI flags and SAVE_PATH
9
+ ```
10
+
11
+ `--config PATH` selects the YAML file. `config check --config PATH` reads and validates only that file; it does not require Notion credentials or access the network.
12
+
13
+ Credentials belong only in `NOTION_API_SECRET` and `NOBLOG_DATABASE_ID`, supplied through the environment or `.env`. Unknown YAML keys are rejected, and there are no credential fields.
14
+
15
+ ## Output
16
+
17
+ ```yaml
18
+ version: 1
19
+ output:
20
+ savePath: src/pages/posts/
21
+ storePath: .noblog/pages/
22
+ layoutPath: ../../layouts/MarkdownPostLayout.astro
23
+ recursive: true
24
+ childPageMarker: "⸎"
25
+ ```
26
+
27
+ | Key | Default | Meaning |
28
+ | --- | --- | --- |
29
+ | `savePath` | `./src/pages/posts/` | Receives relative symlinks for database posts. The positional `SAVE_PATH` and YAML key configure it. |
30
+ | `storePath` | `.noblog/pages/` | Receives every real Markdown file in a flat page-ID layout. Override with `--store`. |
31
+ | `layoutPath` | `../../layouts/MarkdownPostLayout.astro` | Interpreted relative to `savePath`; Noblog writes the equivalent store-relative import. Override with `--layout`. |
32
+ | `recursive` | `true` | Collect and render child pages recursively. |
33
+ | `childPageMarker` | `⸎` (U+2E0E EDITORIAL CORONIS) | Non-empty prefix added to child-page links. Set it to the marker the theme recognizes. |
34
+
35
+ All paths are resolved from the generation working directory. Child pages have no public symlinks. Child-page links are written as `<marker> [title](./<page-id>.md)`. The theme must load and route the canonical store itself when child pages should have routes.
36
+
37
+ ## Notion property mapping
38
+
39
+ ```yaml
40
+ notion:
41
+ properties:
42
+ title: Name
43
+ publishedAt: Published
44
+ series: Series
45
+ ```
46
+
47
+ Keys are logical sources available to frontmatter fields; values are exact, case-sensitive Notion property names. Custom keys such as `series` must be declared here before `from: series` is valid.
48
+
49
+ Without explicit mappings, conventional sources use `description`, `tags`, `date`, and `archived`. The title source uses the last Notion title property. Explicit entries override those conventions individually.
50
+
51
+ Supplying `notion.properties` without `frontmatter.fields` enables the declarative equivalent of the legacy fields: `layout`, `title`, `description`, `tags`, `pubDate`, and `archived`. Explicit `frontmatter.fields` instead emits exactly the declared fields.
52
+
53
+ ## Frontmatter fields
54
+
55
+ ```yaml
56
+ frontmatter:
57
+ fields:
58
+ title:
59
+ from: title
60
+ required: true
61
+ timestamp:
62
+ from: publishedAt
63
+ as: date
64
+ required: true
65
+ series:
66
+ from: series
67
+ omitEmpty: true
68
+ draft:
69
+ from: archived
70
+ default: false
71
+ toc:
72
+ value: true
73
+ provider:
74
+ value:
75
+ name: Notion
76
+ options: [canonical, symlinks]
77
+ ```
78
+
79
+ Each field must have exactly one source:
80
+
81
+ - `from`: a built-in source or a key declared under `notion.properties`.
82
+ - `value`: a static native YAML value.
83
+
84
+ Built-in sources are `title`, `description`, `tags`, `publishedAt`, `archived`, `layoutPath`, `pageId`, and `isDatabasePage`.
85
+
86
+ Modifiers:
87
+
88
+ - `default`: used when the resolved value is empty.
89
+ - `required`: fail generation when the value remains empty after applying the default. Errors include the field and page ID.
90
+ - `omitEmpty`: omit an empty value after default/required processing.
91
+ - `as: string`: convert a string, number, or boolean to a string. Date-like strings are quoted in output so downstream YAML parsers do not coerce them.
92
+ - `as: date`: convert a valid date string or finite number to a YAML timestamp.
93
+
94
+ Empty means `undefined`, `null`, `""`, or `[]`. `false` and `0` are not empty. Resolution order is source/static value, default, required check, omission, then conversion.
95
+
96
+ Static values may be strings, finite numbers, booleans, null, arrays, or nested objects. Notion sources normalize to strings, numbers, booleans, string arrays, or undefined; see the property-type reference.
97
+
98
+ ## Schema and validation
99
+
100
+ The published JSON Schema is `schema/config.json`, also exported as `noblog/config.schema.json`. It is generated from the runtime Zod schema. For a project-local installation, an editor modeline can use:
101
+
102
+ ```yaml
103
+ # yaml-language-server: $schema=./node_modules/noblog/schema/config.json
104
+ ```
105
+
106
+ The JSON Schema describes structure and types. Runtime validation additionally rejects unknown custom `from` sources that are not built in or declared under `notion.properties`; always finish with `noblog config check`.
107
+
108
+ ## Programmatic escape hatch
109
+
110
+ Applications can bypass declarative fields by passing a `FrontmatterAdapter` in `RenderOptions`. It receives `{ page, metadata, layoutPath, isDatabasePage }` and returns a plain object. Root `undefined` values are omitted; arrays, null, dates, and class instances are not valid roots. `createFrontmatterAdapter(fields)` exposes the same declarative behavior to library consumers.
@@ -0,0 +1,42 @@
1
+ # Notion property normalization
2
+
3
+ Noblog reads the actual Notion property type. It does not use a property named `title` or `date` as a substitute for checking its type.
4
+
5
+ | Notion type | Normalized value |
6
+ | --- | --- |
7
+ | `title`, `rich_text` | Concatenated plain-text string |
8
+ | `multi_select` | Array of option names |
9
+ | `select`, `status` | Selected name string, or undefined |
10
+ | `checkbox` | Native boolean |
11
+ | `number` | Native number, or undefined for null |
12
+ | `date` | Start date string, or undefined |
13
+ | `url`, `email`, `phone_number` | String, or undefined for null |
14
+ | `people` | Array of names, falling back to IDs for partial users |
15
+ | `relation` | Array of related page IDs |
16
+ | `files` | Array of uploaded-file or external URLs |
17
+ | `formula` | Normalized formula string, number, boolean, or date start |
18
+ | `created_time`, `last_edited_time` | Notion timestamp string |
19
+ | `created_by`, `last_edited_by` | Name, falling back to ID |
20
+ | `unique_id` | `PREFIX-number`, or the number as a string without a prefix |
21
+ | Unsupported types, missing properties | Undefined |
22
+
23
+ The `date` source remains a string until a field requests `as: date`. This distinction matters: `as: string` preserves a quoted date-like string, while `as: date` emits a native YAML timestamp for themes whose schemas call `z.date()` or `z.coerce.date()`.
24
+
25
+ People, relations, and files are arrays even when Notion contains one item. Apply `omitEmpty` if an empty array should not be emitted. A missing property and an unsupported type both become undefined, allowing `default`, `required`, and `omitEmpty` to handle them consistently.
26
+
27
+ For formula values, Noblog follows the formula's own result type. Verify formulas returning null with the theme's required/optional rules.
28
+
29
+ Custom source names are logical keys, not necessarily Notion names:
30
+
31
+ ```yaml
32
+ notion:
33
+ properties:
34
+ timestampSource: Published At
35
+ frontmatter:
36
+ fields:
37
+ timestamp:
38
+ from: timestampSource
39
+ as: date
40
+ ```
41
+
42
+ Here `timestampSource` is declared locally and `Published At` must exactly match Notion.
@@ -0,0 +1,41 @@
1
+ # Theme examples
2
+
3
+ These examples are snapshots, not substitutes for inspecting the installed theme. The assets contain complete YAML starting points.
4
+
5
+ Child-page links are prefixed by `output.childPageMarker`, which defaults to `⸎` (U+2E0E EDITORIAL CORONIS). Set it to the marker the theme recognizes.
6
+
7
+ ## Nobloger
8
+
9
+ Evidence inspected: `src/layouts/MarkdownPostLayout.astro` and `src/pages/blog/index.astro` in [humbornjo/nobloger](https://github.com/humbornjo/nobloger).
10
+
11
+ Nobloger uses file-based Markdown routes and `Astro.glob("@/pages/posts/*.md")`. Its layout/list contract uses required `title` and string `pubDate`, plus `tags` and optional `description`. Therefore [`assets/nobloger.yaml`](../assets/nobloger.yaml):
12
+
13
+ - keeps database-post symlinks in `src/pages/posts/` for existing routes;
14
+ - stores all real files in `.noblog/pages/`;
15
+ - emits `layout` and a quoted string `pubDate`;
16
+ - omits empty descriptions and does not invent fields from other themes.
17
+
18
+ The existing glob does not list child pages in the hidden store. A theme route must explicitly load that store to expose children. Noblog does not recreate the removed `nob_children` routes.
19
+
20
+ ## ThoughtLite
21
+
22
+ Evidence inspected: `src/content.config.ts` in [tuyuritio/astro-theme-thought-lite](https://github.com/tuyuritio/astro-theme-thought-lite). Its `note` collection loads `./src/content/note/**/*.md` and validates `title`, native date `timestamp`, optional `series`, `tags`, `description`, and native `sensitive`, `toc`, `top`, and `draft` controls.
23
+
24
+ [`assets/thought-lite.yaml`](../assets/thought-lite.yaml):
25
+
26
+ - puts the canonical store directly at `src/content/note/`, where the collection can load root and child pages;
27
+ - keeps required database-post symlinks in `.noblog/note-links/`, separate from collection input;
28
+ - uses `as: date` for `timestamp` and native booleans/numbers elsewhere;
29
+ - maps `archived` to `draft` as an explicit policy choice, not a universal Notion convention;
30
+ - uses static `toc: true` to demonstrate a theme-level constant;
31
+ - emits no Markdown `layout`, because this collection schema does not declare one.
32
+
33
+ Before using it, confirm that the installed version has the same collection glob and fields, and decide whether archived Notion pages should really become drafts. Also confirm `Sensitive`, `Series`, and `Top` exist with those exact names or change the mappings.
34
+
35
+ ## Adapting another theme
36
+
37
+ 1. Copy no asset until its schema and routing evidence match.
38
+ 2. For file-based routes, keep public views in the routed directory and arrange separate store loading for children.
39
+ 3. For a content collection, point `storePath` at the collection input only when all generated pages should belong to that collection. Keep `savePath` distinct; Noblog cannot create a symlink onto its own canonical file.
40
+ 4. Match native schema types. Use `as: date` for date schemas, and avoid stringifying booleans or numbers unless consumers explicitly require strings.
41
+ 5. Validate the final file with `noblog config check --config PATH` and report any remaining route work.
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=generate.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cmds/generate.ts"],"names":[],"mappings":""}