noblog 0.3.0-beta.2 → 0.3.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -2
- package/dist/{client-CzKR81Or.js → client-BIBJQzBg.js} +13 -8
- package/dist/client-BIBJQzBg.js.map +1 -0
- package/dist/{config-check.impl-C5FM7uWi.js → config-check.impl-NO--hbh0.js} +2 -2
- package/dist/{config-check.impl-C5FM7uWi.js.map → config-check.impl-NO--hbh0.js.map} +1 -1
- package/dist/{config-file-C07nmm45.js → config-file-CZX2WJnz.js} +2 -2
- package/dist/{config-file-C07nmm45.js.map → config-file-CZX2WJnz.js.map} +1 -1
- package/dist/{errors-BCRhKbgG.js → errors-Bm4iVQVp.js} +7 -2
- package/dist/errors-Bm4iVQVp.js.map +1 -0
- package/dist/{generate.impl-ChFrtwtC.js → generate.impl-zbCKiANA.js} +4 -2
- package/dist/generate.impl-zbCKiANA.js.map +1 -0
- package/dist/generate.js +5 -4
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +22 -4
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/schema/config.json +23 -0
- package/skills/noblog-config/SKILL.md +1 -1
- package/skills/noblog-config/references/config-schema.md +11 -1
- package/skills/noblog-config/references/theme-examples.md +1 -1
- package/dist/client-CzKR81Or.js.map +0 -1
- package/dist/errors-BCRhKbgG.js.map +0 -1
- package/dist/generate.impl-ChFrtwtC.js.map +0 -1
package/README.md
CHANGED
|
@@ -154,6 +154,17 @@ frontmatter:
|
|
|
154
154
|
|
|
155
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.
|
|
156
156
|
|
|
157
|
+
`output.childPageWrapper` optionally wraps the child-page link instead:
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
output:
|
|
161
|
+
childPageWrapper:
|
|
162
|
+
head: "<noblog-subpage>"
|
|
163
|
+
tail: "</noblog-subpage>"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
When configured, the wrapper overrides `output.childPageMarker`. Both strings must be non-empty and single-line. The wrapper is emitted as raw content, so use it with an HTML-capable Markdown renderer.
|
|
167
|
+
|
|
157
168
|
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
169
|
|
|
159
170
|
Validate a file without Notion credentials, a Notion client, or network access:
|
|
@@ -188,7 +199,7 @@ project-root/
|
|
|
188
199
|
└── <database-page-id>.md # relative symlink
|
|
189
200
|
```
|
|
190
201
|
|
|
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.
|
|
202
|
+
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. Set `output.childPageWrapper` to wrap the link in custom `head`/`tail` strings instead; the wrapper overrides the marker. 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.
|
|
192
203
|
|
|
193
204
|
**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.
|
|
194
205
|
|
|
@@ -196,6 +207,10 @@ Generation is repeatable. Existing regular database-post view files with matchin
|
|
|
196
207
|
|
|
197
208
|
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.
|
|
198
209
|
|
|
210
|
+
## Heading support
|
|
211
|
+
|
|
212
|
+
Noblog renders Notion heading levels 1 through 4 as Markdown `#` through `####`. The installed `@notionhq/client` types do not declare `heading_4`, so the package exports `Heading4BlockObjectResponse` and `NoblogBlock`; custom readers and block transformers can use those types without assertions.
|
|
213
|
+
|
|
199
214
|
## Frontmatter
|
|
200
215
|
|
|
201
216
|
Without custom Notion or frontmatter mappings, generated files retain the legacy Astro-compatible frontmatter:
|
|
@@ -272,7 +287,7 @@ const pages = await renderPages(posts, notion, { layoutPath });
|
|
|
272
287
|
await writePages(pages, { savePath, storePath });
|
|
273
288
|
```
|
|
274
289
|
|
|
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.
|
|
290
|
+
`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. Set `childPageWrapper` to `{ head, tail }` to wrap the link instead; it overrides `childPageMarker`. `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
291
|
|
|
277
292
|
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
293
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as getErrorCode } from "./errors-
|
|
1
|
+
import { t as getErrorCode } from "./errors-Bm4iVQVp.js";
|
|
2
2
|
import { n as DEFAULT_LAYOUT_PATH } from "./defaults-RGOB9tfi.js";
|
|
3
3
|
import { stringify } from "yaml";
|
|
4
4
|
import { markdownTable } from "markdown-table";
|
|
@@ -140,6 +140,7 @@ const equation = (text) => `$$\n${text}\n$$`;
|
|
|
140
140
|
const heading1 = (text) => `# ${text}`;
|
|
141
141
|
const heading2 = (text) => `## ${text}`;
|
|
142
142
|
const heading3 = (text) => `### ${text}`;
|
|
143
|
+
const heading4 = (text) => `#### ${text}`;
|
|
143
144
|
const quote = (text) => `> ${text.replace(/\n/g, " \n> ")}`;
|
|
144
145
|
function callout(text, icon) {
|
|
145
146
|
return `> ${icon?.type === "emoji" ? `${icon.emoji} ` : ""}${text.replace(/\n/g, " \n> ")}`;
|
|
@@ -296,7 +297,7 @@ function transformBlock(type, block, context) {
|
|
|
296
297
|
}
|
|
297
298
|
async function renderBlockNode(node, children, listNumber, context) {
|
|
298
299
|
const { block } = node;
|
|
299
|
-
const content = await transformBlock(block.type, block, context) ?? await renderDefaultBlock(node, context.childPageMarker ?? "⸎");
|
|
300
|
+
const content = await transformBlock(block.type, block, context) ?? await renderDefaultBlock(node, context.childPageMarker ?? "⸎", context.childPageWrapper);
|
|
300
301
|
switch (block.type) {
|
|
301
302
|
case "toggle": return toggle(content, children);
|
|
302
303
|
case "callout": return callout(children ? `${content}\n${children}`.trim() : content, block.callout.icon);
|
|
@@ -311,7 +312,7 @@ function withIndentedChildren(content, children, markerWidth) {
|
|
|
311
312
|
const indentation = " ".repeat(markerWidth);
|
|
312
313
|
return `${content}\n${nested.split("\n").map((line) => line ? `${indentation}${line}` : "").join("\n")}`;
|
|
313
314
|
}
|
|
314
|
-
async function renderDefaultBlock(node, childPageMarker) {
|
|
315
|
+
async function renderDefaultBlock(node, childPageMarker, childPageWrapper) {
|
|
315
316
|
const { block } = node;
|
|
316
317
|
switch (block.type) {
|
|
317
318
|
case "image": {
|
|
@@ -333,13 +334,14 @@ async function renderDefaultBlock(node, childPageMarker) {
|
|
|
333
334
|
const id = target.type === "page_id" ? target.page_id : target.database_id;
|
|
334
335
|
return link(block.type, `https://www.notion.so/${id}`);
|
|
335
336
|
}
|
|
336
|
-
case "child_page": return renderChildPageLink(block, childPageMarker);
|
|
337
|
+
case "child_page": return renderChildPageLink(block, childPageMarker, childPageWrapper);
|
|
337
338
|
case "child_database": return heading2(block.child_database.title || "child_database");
|
|
338
339
|
case "table": return renderTable(node.children, block.table.has_column_header);
|
|
339
340
|
case "code": return codeBlock(renderRichText(block.code.rich_text), block.code.language);
|
|
340
341
|
case "heading_1": return heading1(renderRichText(block.heading_1.rich_text));
|
|
341
342
|
case "heading_2": return heading2(renderRichText(block.heading_2.rich_text));
|
|
342
343
|
case "heading_3": return heading3(renderRichText(block.heading_3.rich_text));
|
|
344
|
+
case "heading_4": return heading4(renderRichText(block.heading_4.rich_text));
|
|
343
345
|
case "quote": return quote(renderRichText(block.quote.rich_text));
|
|
344
346
|
case "to_do": return todo(renderRichText(block.to_do.rich_text), block.to_do.checked);
|
|
345
347
|
case "paragraph": return renderRichText(block.paragraph.rich_text);
|
|
@@ -363,8 +365,9 @@ function renderFileLink(content, fallbackTitle) {
|
|
|
363
365
|
const title = renderPlainText(content.caption).trim() || getFileName(url) || fallbackTitle;
|
|
364
366
|
return link(title, url);
|
|
365
367
|
}
|
|
366
|
-
function renderChildPageLink(block, marker) {
|
|
367
|
-
|
|
368
|
+
function renderChildPageLink(block, marker, wrapper) {
|
|
369
|
+
const link$1 = link(block.child_page.title, `./${block.id}.md`);
|
|
370
|
+
return wrapper === void 0 ? `${marker} ${link$1}` : `${wrapper.head}${link$1}${wrapper.tail}`;
|
|
368
371
|
}
|
|
369
372
|
function renderTable(nodes, hasColumnHeader) {
|
|
370
373
|
return table(nodes.flatMap(({ block }) => {
|
|
@@ -391,6 +394,7 @@ function createContext(databasePageIds, reader, options) {
|
|
|
391
394
|
frontmatter: options.frontmatter,
|
|
392
395
|
recursive: options.recursive ?? true,
|
|
393
396
|
childPageMarker: options.childPageMarker ?? "⸎",
|
|
397
|
+
childPageWrapper: options.childPageWrapper,
|
|
394
398
|
transformers: options.transformers,
|
|
395
399
|
renderedPages: /* @__PURE__ */ new Map()
|
|
396
400
|
};
|
|
@@ -409,6 +413,7 @@ async function renderSinglePage(pageId, context, post) {
|
|
|
409
413
|
const rendered = await renderBlockTree(blockTree, {
|
|
410
414
|
pageId,
|
|
411
415
|
childPageMarker: context.childPageMarker,
|
|
416
|
+
...context.childPageWrapper !== void 0 ? { childPageWrapper: context.childPageWrapper } : {},
|
|
412
417
|
...context.transformers !== void 0 ? { transformers: context.transformers } : {}
|
|
413
418
|
});
|
|
414
419
|
return {
|
|
@@ -546,6 +551,6 @@ function delay(milliseconds) {
|
|
|
546
551
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
547
552
|
}
|
|
548
553
|
//#endregion
|
|
549
|
-
export {
|
|
554
|
+
export { extractPageMetadata as A, quote as C, toggle as D, todo as E, underline as O, link as S, table as T, heading4 as _, renderPages as a, inlineEquation as b, bold as c, codeBlock as d, divider as f, heading3 as g, heading2 as h, renderPage as i, renderFrontmatter as k, bullet as l, heading1 as m, resolveStoreLayoutPath as n, renderPlainText as o, equation as p, writePages as r, renderRichText as s, createNotionSource as t, callout as u, image as v, strikethrough as w, italic as x, inlineCode as y };
|
|
550
555
|
|
|
551
|
-
//# sourceMappingURL=client-
|
|
556
|
+
//# sourceMappingURL=client-BIBJQzBg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-BIBJQzBg.js","names":["md.toggle","md.callout","md.bullet","md.image","md.divider","md.equation","md.link","md.heading2","md.codeBlock","md.heading1","md.heading3","md.heading4","md.quote","md.todo","link","md.table"],"sources":["../src/lib/noblog/metadata.ts","../src/lib/noblog/frontmatter.ts","../src/lib/noblog/markdown.ts","../src/lib/noblog/rich-text.ts","../src/lib/noblog/blocks.ts","../src/lib/noblog/pages.ts","../src/lib/noblog/writer.ts","../src/lib/notion/client.ts"],"sourcesContent":["import type { PageObjectResponse } from \"@notionhq/client\";\nimport type { NotionPropertyMap } from \"./config.js\";\n\ntype NotionProperty = PageObjectResponse[\"properties\"][string];\n\nexport type MetadataValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined;\n\nexport interface PageMetadata {\n readonly title: string;\n readonly description?: string | undefined;\n readonly tags: readonly string[];\n readonly publishedAt?: string | undefined;\n readonly archived?: boolean | undefined;\n readonly values: Readonly<Record<string, MetadataValue>>;\n}\n\nconst DEFAULT_PROPERTIES = {\n description: \"description\",\n tags: \"tags\",\n publishedAt: \"date\",\n archived: \"archived\",\n} as const;\n\nexport function extractPageMetadata(\n page: PageObjectResponse,\n properties: NotionPropertyMap = {},\n): PageMetadata {\n const propertyNames = new Map<string, string>(Object.entries(properties));\n for (const [key, name] of Object.entries(DEFAULT_PROPERTIES)) {\n if (!propertyNames.has(key)) propertyNames.set(key, name);\n }\n\n const values: Record<string, MetadataValue> = {};\n if (!propertyNames.has(\"title\")) {\n const titleProperty = Object.values(page.properties).findLast(\n (property) => property.type === \"title\",\n );\n values[\"title\"] = normalizeProperty(titleProperty);\n }\n for (const [key, name] of propertyNames) {\n values[key] = normalizeProperty(page.properties[name]);\n }\n\n return {\n title: asString(values[\"title\"]) ?? \"\",\n description: asString(values[\"description\"]),\n tags: asStringArray(values[\"tags\"]) ?? [],\n publishedAt: asString(values[\"publishedAt\"]),\n archived: asBoolean(values[\"archived\"]),\n values,\n };\n}\n\nfunction normalizeProperty(property?: NotionProperty): MetadataValue {\n if (!property) return undefined;\n\n switch (property.type) {\n case \"title\":\n return plainText(property.title);\n case \"rich_text\":\n return plainText(property.rich_text);\n case \"multi_select\":\n return property.multi_select.map(({ name }) => name);\n case \"select\":\n return property.select?.name;\n case \"status\":\n return property.status?.name;\n case \"checkbox\":\n return property.checkbox;\n case \"number\":\n return property.number ?? undefined;\n case \"date\":\n return property.date?.start;\n case \"url\":\n return property.url ?? undefined;\n case \"email\":\n return property.email ?? undefined;\n case \"phone_number\":\n return property.phone_number ?? undefined;\n case \"people\":\n return property.people.map(entityName);\n case \"relation\":\n return property.relation.map(({ id }) => id);\n case \"files\":\n return property.files.map((file) =>\n \"file\" in file ? file.file.url : file.external.url,\n );\n case \"formula\":\n return normalizeFormula(property.formula);\n case \"created_time\":\n return property.created_time;\n case \"last_edited_time\":\n return property.last_edited_time;\n case \"created_by\":\n return entityName(property.created_by);\n case \"last_edited_by\":\n return entityName(property.last_edited_by);\n case \"unique_id\":\n return property.unique_id.prefix\n ? `${property.unique_id.prefix}-${property.unique_id.number}`\n : String(property.unique_id.number);\n default:\n return undefined;\n }\n}\n\nfunction normalizeFormula(\n formula: Extract<NotionProperty, { type: \"formula\" }>[\"formula\"],\n): MetadataValue {\n switch (formula.type) {\n case \"string\":\n return formula.string ?? undefined;\n case \"number\":\n return formula.number ?? undefined;\n case \"boolean\":\n return formula.boolean ?? undefined;\n case \"date\":\n return formula.date?.start;\n }\n}\n\nfunction plainText(\n richText: Extract<NotionProperty, { type: \"title\" }>[\"title\"],\n): string {\n return richText.map((item) => item.plain_text).join(\"\");\n}\n\nfunction entityName(entity: {\n readonly id: string;\n readonly name?: string | null;\n}): string {\n return entity.name ?? entity.id;\n}\n\nfunction asString(value: MetadataValue): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asBoolean(value: MetadataValue): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction asStringArray(value: MetadataValue): readonly string[] | undefined {\n if (typeof value === \"string\") return [value];\n return Array.isArray(value) ? value : undefined;\n}\n","import type { PageObjectResponse } from \"@notionhq/client\";\nimport { stringify } from \"yaml\";\nimport type { NotionPropertyMap } from \"./config.js\";\nimport { DEFAULT_LAYOUT_PATH } from \"./defaults.js\";\nimport { extractPageMetadata } from \"./metadata.js\";\nimport type { FrontmatterAdapter, FrontmatterRecord } from \"./types.js\";\n\nexport interface FrontmatterOptions {\n readonly layoutPath?: string;\n readonly propertyMap?: NotionPropertyMap;\n readonly frontmatter?: FrontmatterAdapter;\n readonly isDatabasePage?: boolean;\n}\n\nexport function renderFrontmatter(\n page: PageObjectResponse,\n options: FrontmatterOptions = {},\n): string {\n const { layoutPath = DEFAULT_LAYOUT_PATH } = options;\n if (options.frontmatter) {\n const metadata = extractPageMetadata(page, options.propertyMap);\n const values = options.frontmatter({\n page,\n metadata,\n layoutPath,\n isDatabasePage: options.isDatabasePage ?? true,\n });\n return serializeFrontmatter(values);\n }\n\n let title = \"\";\n let description = \"\";\n let tags: string[] = [];\n let pubDate = \"\";\n let archived = \"\";\n\n for (const [name, property] of Object.entries(page.properties)) {\n switch (property.type) {\n case \"title\":\n title = property.title.map((item) => item.plain_text).join(\"\");\n break;\n case \"multi_select\":\n if (name === \"tags\") {\n tags = property.multi_select.map((tag) => tag.name);\n }\n break;\n case \"date\":\n if (name === \"date\") {\n pubDate =\n property.date?.start ?? new Date().toISOString().slice(0, 10);\n }\n break;\n }\n\n if (name === \"archived\" && property.type === \"checkbox\") {\n archived = property.checkbox ? \"true\" : \"false\";\n }\n if (name === \"description\" && property.type === \"rich_text\") {\n description = property.rich_text\n .map((item) => item.plain_text)\n .join(\"\");\n }\n }\n\n return (\n \"---\\n\" +\n `layout: ${layoutPath}\\n` +\n `title: ${JSON.stringify(title)}\\n` +\n `description: ${JSON.stringify(description)}\\n` +\n `tags: ${JSON.stringify(tags)}\\n` +\n `pubDate: ${JSON.stringify(pubDate)}\\n` +\n `archived: ${JSON.stringify(archived)}\\n` +\n \"---\\n\"\n );\n}\n\nfunction serializeFrontmatter(values: FrontmatterRecord): string {\n if (\n values === null ||\n typeof values !== \"object\" ||\n Array.isArray(values) ||\n (Object.getPrototypeOf(values) !== Object.prototype &&\n Object.getPrototypeOf(values) !== null)\n ) {\n throw new Error(\"Frontmatter adapter must return a plain object\");\n }\n\n const entries = Object.entries(values).filter(\n ([, value]) => value !== undefined,\n );\n if (entries.length === 0) return \"---\\n---\\n\";\n\n const yaml = stringify(Object.fromEntries(entries), {\n aliasDuplicateObjects: false,\n schema: \"yaml-1.1\",\n });\n return `---\\n${yaml}---\\n`;\n}\n","import { markdownTable } from \"markdown-table\";\nimport type { CalloutIcon } from \"./types.js\";\n\nexport const inlineCode = (text: string) => `\\`${text}\\``;\nexport const inlineEquation = (text: string) => `$${text}$`;\nexport const bold = (text: string) => `**${text}**`;\nexport const italic = (text: string) => `_${text}_`;\nexport const strikethrough = (text: string) => `~~${text}~~`;\nexport const underline = (text: string) => `<u>${text}</u>`;\nexport const link = (text: string, href: string) => `[${text}](${href})`;\n\nexport function codeBlock(text: string, language = \"\"): string {\n const normalizedLanguage = language === \"plain text\" ? \"text\" : language;\n return `\\`\\`\\`${normalizedLanguage}\\n${text}\\n\\`\\`\\``;\n}\n\nexport const equation = (text: string) => `$$\\n${text}\\n$$`;\nexport const heading1 = (text: string) => `# ${text}`;\nexport const heading2 = (text: string) => `## ${text}`;\nexport const heading3 = (text: string) => `### ${text}`;\nexport const heading4 = (text: string) => `#### ${text}`;\nexport const quote = (text: string) => `> ${text.replace(/\\n/g, \" \\n> \")}`;\n\nexport function callout(text: string, icon?: CalloutIcon): string {\n const emoji = icon?.type === \"emoji\" ? `${icon.emoji} ` : \"\";\n return `> ${emoji}${text.replace(/\\n/g, \" \\n> \")}`;\n}\n\nexport function bullet(text: string, count?: number): string {\n const rendered = text.trim();\n return count === undefined ? `- ${rendered}` : `${count}. ${rendered}`;\n}\n\nexport const todo = (text: string, checked: boolean) =>\n checked ? `- [x] ${text}` : `- [ ] ${text}`;\n\nexport async function image(\n alt: string,\n href: string,\n convertToBase64 = false,\n): Promise<string> {\n if (!convertToBase64 || href.startsWith(\"data:\")) {\n if (href.startsWith(\"data:\")) {\n const base64 = href.split(\",\").pop();\n return ``;\n }\n return ``;\n }\n\n const response = await fetch(href);\n if (!response.ok) {\n throw new Error(\n `Failed to download image: ${response.status} ${response.statusText}`,\n );\n }\n const buffer = await response.arrayBuffer();\n return `.toString(\"base64\")})`;\n}\n\nexport const divider = () => \"---\";\n\nexport function toggle(summary?: string, children?: string): string {\n if (!summary) return children ?? \"\";\n return `<details>\\n<summary>${summary}</summary>\\n${children ?? \"\"}\\n</details>\\n\\n`;\n}\n\nexport function table(cells: string[][], hasColumnHeader = true): string {\n if (hasColumnHeader || cells.length === 0) return markdownTable(cells);\n\n const width = Math.max(...cells.map((row) => row.length));\n if (width === 0) return \"\";\n const emptyHeader = Array.from({ length: width }, () => \"\");\n return markdownTable([emptyHeader, ...cells]);\n}\n","import type { RichTextItemResponse } from \"@notionhq/client\";\nimport { inlineEquation, link } from \"./markdown.js\";\n\ntype AnnotationName = Exclude<\n keyof RichTextItemResponse[\"annotations\"],\n \"color\"\n>;\n\ninterface AnnotationFormat {\n readonly name: AnnotationName;\n readonly open: string;\n readonly close: string;\n}\n\n// Ordered from the outermost marker to the innermost marker. Stable sorting\n// keeps this order when annotations end on the same rich-text segment.\nconst ANNOTATION_FORMATS: readonly AnnotationFormat[] = [\n { name: \"strikethrough\", open: \"~~\", close: \"~~\" },\n { name: \"underline\", open: \"<u>\", close: \"</u>\" },\n { name: \"italic\", open: \"_\", close: \"_\" },\n { name: \"bold\", open: \"**\", close: \"**\" },\n { name: \"code\", open: \"`\", close: \"`\" },\n];\n\nexport function renderPlainText(\n richText: readonly RichTextItemResponse[],\n): string {\n return richText.map((item) => item.plain_text).join(\"\");\n}\n\nexport function renderRichText(\n richText: readonly RichTextItemResponse[],\n): string {\n let rendered = \"\";\n let active: AnnotationFormat[] = [];\n\n for (const [index, item] of richText.entries()) {\n const desired = getAnnotationFormats(richText, index, item);\n let shared = 0;\n while (\n shared < active.length &&\n shared < desired.length &&\n active[shared]?.name === desired[shared]?.name\n ) {\n shared++;\n }\n\n for (const format of active.slice(shared).toReversed()) {\n rendered += format.close;\n }\n for (const format of desired.slice(shared)) {\n rendered += format.open;\n }\n\n rendered += renderContent(item);\n active = desired;\n }\n\n for (const format of active.toReversed()) {\n rendered += format.close;\n }\n return rendered;\n}\n\nfunction getAnnotationFormats(\n richText: readonly RichTextItemResponse[],\n index: number,\n item: RichTextItemResponse,\n): AnnotationFormat[] {\n if (item.type === \"equation\") return [];\n\n return ANNOTATION_FORMATS.filter((format) => item.annotations[format.name])\n .map((format) => ({\n format,\n runEnd: getAnnotationRunEnd(richText, index, format.name),\n }))\n .sort((left, right) => right.runEnd - left.runEnd)\n .map(({ format }) => format);\n}\n\nfunction getAnnotationRunEnd(\n richText: readonly RichTextItemResponse[],\n start: number,\n name: AnnotationName,\n): number {\n let end = start;\n for (const [offset, next] of richText.slice(start + 1).entries()) {\n if (next.type === \"equation\" || !next.annotations[name]) break;\n end = start + offset + 1;\n }\n return end;\n}\n\nfunction renderContent(item: RichTextItemResponse): string {\n if (item.type === \"equation\") {\n return inlineEquation(item.equation.expression);\n }\n return item.href ? link(item.plain_text, item.href) : item.plain_text;\n}\n","import type { BlockObjectResponse } from \"@notionhq/client\";\nimport { DEFAULT_CHILD_PAGE_MARKER } from \"./defaults.js\";\nimport * as md from \"./markdown.js\";\nimport { renderPlainText, renderRichText } from \"./rich-text.js\";\nimport type {\n BlockTransformerContext,\n BlockTransformers,\n ChildPageWrapper,\n NoblogBlock,\n NotionReader,\n} from \"./types.js\";\n\nexport interface BlockNode {\n readonly block: NoblogBlock;\n readonly children: BlockNode[];\n}\n\nexport interface BlockRenderContext extends BlockTransformerContext {\n readonly childPageMarker?: string;\n readonly childPageWrapper?: ChildPageWrapper;\n readonly transformers?: BlockTransformers;\n}\n\nexport interface RenderedBlocks {\n content: string;\n childPageIds: string[];\n}\n\nexport async function loadBlockTree(\n blockId: string,\n reader: NotionReader,\n ancestors: ReadonlySet<string> = new Set(),\n): Promise<BlockNode[]> {\n if (ancestors.has(blockId)) return [];\n\n const blocks = await reader.getBlockChildren(blockId);\n const childAncestors = new Set(ancestors).add(blockId);\n const nodes: BlockNode[] = [];\n\n for (const block of blocks) {\n if (block.type === \"unsupported\") continue;\n\n const childSourceId = getChildSourceId(block);\n const children =\n childSourceId && !childAncestors.has(childSourceId)\n ? await loadBlockTree(childSourceId, reader, childAncestors)\n : [];\n nodes.push({ block, children });\n }\n\n return nodes;\n}\n\nfunction getChildSourceId(block: NoblogBlock): string | undefined {\n if (block.type === \"child_page\" || block.type === \"child_database\") {\n return undefined;\n }\n if (block.type === \"synced_block\") {\n return (\n block.synced_block.synced_from?.block_id ??\n (block.has_children ? block.id : undefined)\n );\n }\n return block.has_children ? block.id : undefined;\n}\n\nexport async function renderBlockTree(\n nodes: readonly BlockNode[],\n context: BlockRenderContext,\n): Promise<RenderedBlocks> {\n const result: RenderedBlocks = { content: \"\", childPageIds: [] };\n let numberedListIndex = 0;\n\n for (const node of nodes) {\n const { block } = node;\n numberedListIndex =\n block.type === \"numbered_list_item\" ? numberedListIndex + 1 : 0;\n\n const children =\n block.type === \"table\"\n ? { content: \"\", childPageIds: [] }\n : await renderBlockTree(node.children, context);\n const content = await renderBlockNode(\n node,\n children.content,\n numberedListIndex || undefined,\n context,\n );\n\n if (block.type === \"toggle\") {\n result.content += content;\n } else {\n const lineWrap = isListBlock(block) ? \"\" : \"\\n\";\n result.content += `${lineWrap}${content}\\n${lineWrap}`;\n if (!containsOwnChildren(block)) {\n result.content += children.content;\n }\n }\n\n if (block.type === \"child_page\") {\n result.childPageIds.push(block.id);\n } else {\n result.childPageIds.push(...children.childPageIds);\n }\n }\n\n return result;\n}\n\nfunction isListBlock(block: NoblogBlock): boolean {\n return (\n block.type === \"to_do\" ||\n block.type === \"bulleted_list_item\" ||\n block.type === \"numbered_list_item\"\n );\n}\n\nfunction containsOwnChildren(block: NoblogBlock): boolean {\n return (\n block.type === \"child_page\" ||\n block.type === \"callout\" ||\n block.type === \"bulleted_list_item\" ||\n block.type === \"numbered_list_item\" ||\n block.type === \"table\"\n );\n}\n\nfunction transformBlock<K extends NoblogBlock[\"type\"]>(\n type: K,\n block: Extract<NoblogBlock, { type: NoInfer<K> }>,\n context: BlockRenderContext,\n): string | undefined | Promise<string | undefined> {\n const transformer = context.transformers?.[type];\n return transformer?.(block, context);\n}\n\nasync function renderBlockNode(\n node: BlockNode,\n children: string,\n listNumber: number | undefined,\n context: BlockRenderContext,\n): Promise<string> {\n const { block } = node;\n const transformed = await transformBlock(block.type, block, context);\n const content =\n transformed ??\n (await renderDefaultBlock(\n node,\n context.childPageMarker ?? DEFAULT_CHILD_PAGE_MARKER,\n context.childPageWrapper,\n ));\n\n switch (block.type) {\n case \"toggle\":\n return md.toggle(content, children);\n case \"callout\":\n return md.callout(\n children ? `${content}\\n${children}`.trim() : content,\n block.callout.icon,\n );\n case \"bulleted_list_item\":\n return md.bullet(withIndentedChildren(content, children, 2));\n case \"numbered_list_item\":\n return md.bullet(\n withIndentedChildren(\n content,\n children,\n `${listNumber ?? 1}. `.length,\n ),\n listNumber,\n );\n default:\n return content;\n }\n}\n\nfunction withIndentedChildren(\n content: string,\n children: string,\n markerWidth: number,\n): string {\n const nested = children.trim();\n if (!nested) return content;\n\n const indentation = \" \".repeat(markerWidth);\n const indented = nested\n .split(\"\\n\")\n .map((line) => (line ? `${indentation}${line}` : \"\"))\n .join(\"\\n\");\n return `${content}\\n${indented}`;\n}\n\nasync function renderDefaultBlock(\n node: BlockNode,\n childPageMarker: string,\n childPageWrapper: ChildPageWrapper | undefined,\n): Promise<string> {\n const { block } = node;\n\n switch (block.type) {\n case \"image\": {\n const url = getFileUrl(block.image);\n const caption = renderPlainText(block.image.caption);\n const alt = caption.trim() || getFileName(url) || \"image\";\n return md.image(alt, url);\n }\n case \"divider\":\n return md.divider();\n case \"equation\":\n return md.equation(block.equation.expression);\n case \"pdf\":\n return renderFileLink(block.pdf, block.type);\n case \"file\":\n return renderFileLink(block.file, block.type);\n case \"video\":\n return renderFileLink(block.video, block.type);\n case \"audio\":\n return renderFileLink(block.audio, block.type);\n case \"embed\":\n return md.link(block.type, block.embed.url);\n case \"bookmark\":\n return md.link(block.type, block.bookmark.url);\n case \"link_preview\":\n return md.link(block.type, block.link_preview.url);\n case \"link_to_page\": {\n const target = block.link_to_page;\n if (target.type !== \"page_id\" && target.type !== \"database_id\") {\n return \"\";\n }\n const id = target.type === \"page_id\" ? target.page_id : target.database_id;\n return md.link(block.type, `https://www.notion.so/${id}`);\n }\n case \"child_page\":\n return renderChildPageLink(block, childPageMarker, childPageWrapper);\n case \"child_database\":\n return md.heading2(block.child_database.title || \"child_database\");\n case \"table\":\n return renderTable(node.children, block.table.has_column_header);\n case \"code\":\n return md.codeBlock(\n renderRichText(block.code.rich_text),\n block.code.language,\n );\n case \"heading_1\":\n return md.heading1(renderRichText(block.heading_1.rich_text));\n case \"heading_2\":\n return md.heading2(renderRichText(block.heading_2.rich_text));\n case \"heading_3\":\n return md.heading3(renderRichText(block.heading_3.rich_text));\n case \"heading_4\":\n return md.heading4(renderRichText(block.heading_4.rich_text));\n case \"quote\":\n return md.quote(renderRichText(block.quote.rich_text));\n case \"to_do\":\n return md.todo(\n renderRichText(block.to_do.rich_text),\n block.to_do.checked,\n );\n case \"paragraph\":\n return renderRichText(block.paragraph.rich_text);\n case \"toggle\":\n return renderRichText(block.toggle.rich_text);\n case \"callout\":\n return renderRichText(block.callout.rich_text);\n case \"bulleted_list_item\":\n return renderRichText(block.bulleted_list_item.rich_text);\n case \"numbered_list_item\":\n return renderRichText(block.numbered_list_item.rich_text);\n case \"template\":\n return renderRichText(block.template.rich_text);\n default:\n return \"\";\n }\n}\n\ntype FileContent =\n | Extract<BlockObjectResponse, { type: \"image\" }>[\"image\"]\n | Extract<BlockObjectResponse, { type: \"pdf\" }>[\"pdf\"]\n | Extract<BlockObjectResponse, { type: \"file\" }>[\"file\"]\n | Extract<BlockObjectResponse, { type: \"video\" }>[\"video\"]\n | Extract<BlockObjectResponse, { type: \"audio\" }>[\"audio\"];\n\nfunction getFileUrl(content: FileContent): string {\n if (content.type === \"external\") return content.external.url;\n return content.file.url;\n}\n\nfunction getFileName(url: string): string | undefined {\n return url.match(/[^\\/\\\\&?]+\\.\\w{3,4}(?=([?&].*$|$))/)?.[0];\n}\n\nfunction renderFileLink(content: FileContent, fallbackTitle: string): string {\n const url = getFileUrl(content);\n const caption = renderPlainText(content.caption);\n const title = caption.trim() || getFileName(url) || fallbackTitle;\n return md.link(title, url);\n}\n\nfunction renderChildPageLink(\n block: Extract<BlockObjectResponse, { type: \"child_page\" }>,\n marker: string,\n wrapper: ChildPageWrapper | undefined,\n): string {\n // The theme consumes the marker or wrapper to render subpage links.\n const link = md.link(block.child_page.title, `./${block.id}.md`);\n return wrapper === undefined\n ? `${marker} ${link}`\n : `${wrapper.head}${link}${wrapper.tail}`;\n}\n\nfunction renderTable(\n nodes: readonly BlockNode[],\n hasColumnHeader: boolean,\n): string {\n const rows = nodes.flatMap(({ block }) => {\n if (block.type !== \"table_row\") return [];\n return [\n block.table_row.cells.map((cell) => renderRichText(cell)),\n ];\n });\n return md.table(rows, hasColumnHeader);\n}\n","import type { PageObjectResponse } from \"@notionhq/client\";\nimport { loadBlockTree, renderBlockTree } from \"./blocks.js\";\nimport {\n DEFAULT_CHILD_PAGE_MARKER,\n DEFAULT_LAYOUT_PATH,\n} from \"./defaults.js\";\nimport { renderFrontmatter } from \"./frontmatter.js\";\nimport type { NotionPropertyMap } from \"./config.js\";\nimport type {\n BlockTransformers,\n ChildPageWrapper,\n FrontmatterAdapter,\n NotionReader,\n RenderedPage,\n RenderOptions,\n} from \"./types.js\";\n\ninterface PageRenderContext {\n readonly reader: NotionReader;\n readonly databasePageIds: ReadonlySet<string>;\n readonly layoutPath: string;\n readonly propertyMap: NotionPropertyMap | undefined;\n readonly frontmatter: FrontmatterAdapter | undefined;\n readonly recursive: boolean;\n readonly childPageMarker: string;\n readonly childPageWrapper: ChildPageWrapper | undefined;\n readonly transformers: BlockTransformers | undefined;\n readonly renderedPages: Map<string, Promise<RenderedPage>>;\n}\n\nexport async function renderPage(\n pageId: string,\n reader: NotionReader,\n options: RenderOptions = {},\n): Promise<RenderedPage> {\n const context = createContext([pageId], reader, options);\n return collectPage(pageId, context);\n}\n\nexport async function renderPages(\n posts: readonly PageObjectResponse[],\n reader: NotionReader,\n options: RenderOptions = {},\n): Promise<RenderedPage[]> {\n const context = createContext(\n posts.map((post) => post.id),\n reader,\n options,\n );\n\n for (const post of posts) {\n await collectPage(post.id, context, post);\n }\n\n return Promise.all([...context.renderedPages.values()]);\n}\n\nfunction createContext(\n databasePageIds: readonly string[],\n reader: NotionReader,\n options: RenderOptions,\n): PageRenderContext {\n return {\n reader,\n databasePageIds: new Set(databasePageIds),\n layoutPath: options.layoutPath ?? DEFAULT_LAYOUT_PATH,\n propertyMap: options.propertyMap,\n frontmatter: options.frontmatter,\n recursive: options.recursive ?? true,\n childPageMarker: options.childPageMarker ?? DEFAULT_CHILD_PAGE_MARKER,\n childPageWrapper: options.childPageWrapper,\n transformers: options.transformers,\n renderedPages: new Map(),\n };\n}\n\nasync function collectPage(\n pageId: string,\n context: PageRenderContext,\n post?: PageObjectResponse,\n): Promise<RenderedPage> {\n const cached = context.renderedPages.get(pageId);\n if (cached) return cached;\n\n const rendering = renderSinglePage(pageId, context, post);\n context.renderedPages.set(pageId, rendering);\n const rendered = await rendering;\n\n if (context.recursive) {\n for (const childPageId of rendered.childPageIds) {\n await collectPage(childPageId, context);\n }\n }\n\n return rendered;\n}\n\nasync function renderSinglePage(\n pageId: string,\n context: PageRenderContext,\n post?: PageObjectResponse,\n): Promise<RenderedPage> {\n const [page, blockTree] = await Promise.all([\n post ? Promise.resolve(post) : context.reader.getPage(pageId),\n loadBlockTree(pageId, context.reader),\n ]);\n const rendered = await renderBlockTree(blockTree, {\n pageId,\n childPageMarker: context.childPageMarker,\n ...(context.childPageWrapper !== undefined\n ? { childPageWrapper: context.childPageWrapper }\n : {}),\n ...(context.transformers !== undefined\n ? { transformers: context.transformers }\n : {}),\n });\n const frontmatter = renderFrontmatter(page, {\n layoutPath: context.layoutPath,\n ...(context.propertyMap !== undefined\n ? { propertyMap: context.propertyMap }\n : {}),\n ...(context.frontmatter !== undefined\n ? { frontmatter: context.frontmatter }\n : {}),\n isDatabasePage: context.databasePageIds.has(pageId),\n });\n\n return {\n id: pageId,\n content: frontmatter + rendered.content,\n childPageIds: [...new Set(rendered.childPageIds)],\n isDatabasePage: context.databasePageIds.has(pageId),\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport {\n lstat,\n mkdir,\n readlink,\n rename,\n rm,\n symlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { getErrorCode } from \"../errors.js\";\nimport {\n DEFAULT_LAYOUT_PATH,\n DEFAULT_SAVE_PATH,\n DEFAULT_STORE_PATH,\n} from \"./defaults.js\";\nimport type {\n RenderedPage,\n StoreLayoutOptions,\n WritePagesOptions,\n} from \"./types.js\";\n\nexport async function writePages(\n pages: readonly RenderedPage[],\n options: WritePagesOptions = {},\n): Promise<string[]> {\n const savePath = options.savePath ?? DEFAULT_SAVE_PATH;\n const storePath = options.storePath ?? DEFAULT_STORE_PATH;\n const writtenPaths: string[] = [];\n await mkdir(storePath, { recursive: true });\n\n for (const page of pages) {\n const storedPath = join(storePath, `${page.id}.md`);\n const storedStats = await getStats(storedPath);\n if (storedStats && !storedStats.isFile()) {\n throw new Error(`Page store path is not a regular file: ${storedPath}`);\n }\n await writeFile(storedPath, page.content, \"utf8\");\n\n if (!page.isDatabasePage) continue;\n\n const viewPath = join(savePath, `${page.id}.md`);\n await mkdir(savePath, { recursive: true });\n await linkStoredPage(storedPath, viewPath);\n writtenPaths.push(viewPath);\n }\n\n return writtenPaths;\n}\n\nexport function resolveStoreLayoutPath(\n options: StoreLayoutOptions = {},\n): string {\n const savePath = options.savePath ?? DEFAULT_SAVE_PATH;\n const storePath = options.storePath ?? DEFAULT_STORE_PATH;\n const layoutPath = options.layoutPath ?? DEFAULT_LAYOUT_PATH;\n const layoutTarget = resolve(savePath, layoutPath);\n return relative(resolve(storePath), layoutTarget).split(sep).join(\"/\");\n}\n\nasync function linkStoredPage(\n storedPath: string,\n viewPath: string,\n): Promise<void> {\n if (resolve(storedPath) === resolve(viewPath)) return;\n\n const viewStats = await getStats(viewPath);\n if (viewStats && !viewStats.isFile() && !viewStats.isSymbolicLink()) {\n throw new Error(`Refusing to replace non-file output: ${viewPath}`);\n }\n\n const target = relative(dirname(viewPath), storedPath);\n if (viewStats?.isSymbolicLink() && (await readlink(viewPath)) === target) {\n return;\n }\n\n const temporaryPath = `${viewPath}.noblog-${randomUUID()}.tmp`;\n try {\n await symlink(target, temporaryPath, \"file\");\n await rename(temporaryPath, viewPath);\n } catch (error) {\n await rm(temporaryPath, { force: true }).catch(() => {});\n throw error;\n }\n}\n\nasync function getStats(path: string) {\n try {\n return await lstat(path);\n } catch (error: unknown) {\n if (getErrorCode(error) === \"ENOENT\") return undefined;\n throw error;\n }\n}\n","import {\n Client,\n isFullBlock,\n isFullDatabase,\n isFullPage,\n isNotionClientError,\n} from \"@notionhq/client\";\nimport type {\n BlockObjectResponse,\n PageObjectResponse,\n} from \"@notionhq/client\";\nimport type { NotionReader } from \"../noblog/types.js\";\n\nexport interface NotionSourceConfig {\n readonly notionApiSecret: string;\n readonly databaseId: string;\n}\n\nexport interface NotionSource extends NotionReader {\n listPages(): Promise<PageObjectResponse[]>;\n}\n\nexport function createNotionSource(\n config: NotionSourceConfig,\n): NotionSource {\n const client = new Client({ auth: config.notionApiSecret });\n return {\n listPages: () => listPages(client, config.databaseId),\n getPage: (pageId) => getPage(client, pageId),\n getBlockChildren: (blockId) => getBlockChildren(client, blockId),\n };\n}\n\nasync function listPages(\n client: Client,\n databaseId: string,\n): Promise<PageObjectResponse[]> {\n const database = await withRetry(() =>\n client.databases.retrieve({ database_id: databaseId }),\n );\n if (!isFullDatabase(database)) {\n throw new Error(`Notion database ${databaseId} is not a full database`);\n }\n\n const pages: PageObjectResponse[] = [];\n for (const source of database.data_sources) {\n let startCursor: string | undefined;\n do {\n const response = await withRetry(() =>\n client.dataSources.query({\n data_source_id: source.id,\n filter: {\n property: \"publish\",\n checkbox: { equals: true },\n },\n sorts: [{ property: \"date\", direction: \"descending\" }],\n page_size: 100,\n ...(startCursor !== undefined\n ? { start_cursor: startCursor }\n : {}),\n }),\n );\n pages.push(...response.results.filter(isFullPage));\n startCursor = response.next_cursor ?? undefined;\n if (!response.has_more) break;\n } while (startCursor);\n }\n\n return pages;\n}\n\nasync function getPage(\n client: Client,\n pageId: string,\n): Promise<PageObjectResponse> {\n const page = await withRetry(() => client.pages.retrieve({ page_id: pageId }));\n if (!isFullPage(page)) {\n throw new Error(`Notion page ${pageId} is not a full page`);\n }\n return page;\n}\n\nasync function getBlockChildren(\n client: Client,\n blockId: string,\n): Promise<BlockObjectResponse[]> {\n const blocks: BlockObjectResponse[] = [];\n let startCursor: string | undefined;\n\n do {\n const response = await withRetry(() =>\n client.blocks.children.list({\n block_id: blockId,\n page_size: 100,\n ...(startCursor !== undefined ? { start_cursor: startCursor } : {}),\n }),\n );\n blocks.push(...response.results.filter(isFullBlock));\n startCursor = response.next_cursor ?? undefined;\n } while (startCursor);\n\n return blocks;\n}\n\nconst MAX_ATTEMPTS = 3;\nconst INITIAL_RETRY_DELAY_MS = 500;\n\nasync function withRetry<T>(operation: () => Promise<T>): Promise<T> {\n for (let attempt = 0; ; attempt++) {\n try {\n return await operation();\n } catch (error: unknown) {\n if (attempt === MAX_ATTEMPTS - 1 || !isRetryable(error)) throw error;\n await delay(INITIAL_RETRY_DELAY_MS * 2 ** attempt);\n }\n }\n}\n\nfunction isRetryable(error: unknown): boolean {\n if (!isNotionClientError(error) || !(\"status\" in error)) return true;\n return error.status === 408 || error.status === 429 || error.status >= 500;\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as loadNoblogConfig } from "./config-file-
|
|
1
|
+
import { t as loadNoblogConfig } from "./config-file-CZX2WJnz.js";
|
|
2
2
|
//#region src/commands/config-check.impl.ts
|
|
3
3
|
async function checkConfig(flags) {
|
|
4
4
|
try {
|
|
@@ -11,4 +11,4 @@ async function checkConfig(flags) {
|
|
|
11
11
|
//#endregion
|
|
12
12
|
export { checkConfig as default };
|
|
13
13
|
|
|
14
|
-
//# sourceMappingURL=config-check.impl-
|
|
14
|
+
//# sourceMappingURL=config-check.impl-NO--hbh0.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-check.impl-
|
|
1
|
+
{"version":3,"file":"config-check.impl-NO--hbh0.js","names":[],"sources":["../src/commands/config-check.impl.ts"],"sourcesContent":["import { loadNoblogConfig } from \"../config-file.js\";\nimport type { CliContext } from \"../context.js\";\n\ninterface ConfigCheckFlags {\n config: string;\n}\n\nexport default async function checkConfig(\n this: CliContext,\n flags: ConfigCheckFlags,\n): Promise<Error | void> {\n try {\n await loadNoblogConfig(flags.config);\n this.process.stdout.write(`Configuration valid: ${flags.config}\\n`);\n } catch (error) {\n return error instanceof Error\n ? error\n : new Error(\"Configuration check failed: an unknown error occurred\");\n }\n}\n"],"mappings":";;AAOA,eAA8B,YAE5B,OACuB;CACvB,IAAI;EACF,MAAM,iBAAiB,MAAM,MAAM;EACnC,KAAK,QAAQ,OAAO,MAAM,wBAAwB,MAAM,OAAO,GAAG;CACpE,SAAS,OAAO;EACd,OAAO,iBAAiB,QACpB,wBACA,IAAI,MAAM,uDAAuD;CACvE;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ConfigurationError } from "./config-csbquMhF.js";
|
|
2
|
-
import { a as noblogConfigSchema, t as getErrorCode } from "./errors-
|
|
2
|
+
import { a as noblogConfigSchema, t as getErrorCode } from "./errors-Bm4iVQVp.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { parse } from "yaml";
|
|
5
5
|
import { readFile } from "node:fs/promises";
|
|
@@ -24,4 +24,4 @@ async function loadNoblogConfig(path) {
|
|
|
24
24
|
//#endregion
|
|
25
25
|
export { loadNoblogConfig as t };
|
|
26
26
|
|
|
27
|
-
//# sourceMappingURL=config-file-
|
|
27
|
+
//# sourceMappingURL=config-file-CZX2WJnz.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-file-
|
|
1
|
+
{"version":3,"file":"config-file-CZX2WJnz.js","names":[],"sources":["../src/config-file.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { z } from \"zod\";\nimport { ConfigurationError } from \"./config.js\";\nimport { getErrorCode } from \"./lib/errors.js\";\nimport {\n noblogConfigSchema,\n type NoblogFileConfig,\n} from \"./lib/noblog/config.js\";\n\nexport async function loadNoblogConfig(\n path: string,\n): Promise<NoblogFileConfig> {\n let source: string;\n try {\n source = await readFile(path, \"utf8\");\n } catch (error) {\n const detail =\n getErrorCode(error) === \"ENOENT\"\n ? \"file not found\"\n : error instanceof Error\n ? error.message\n : \"unknown read error\";\n throw new ConfigurationError(\n `Cannot read Noblog config \"${path}\": ${detail}`,\n );\n }\n\n let input: unknown;\n try {\n input = parse(source, { prettyErrors: false });\n } catch (error) {\n throw new ConfigurationError(\n `Invalid YAML in Noblog config \"${path}\": ${\n error instanceof Error ? error.message : \"unknown parse error\"\n }`,\n );\n }\n\n const result = noblogConfigSchema.safeParse(input);\n if (!result.success) {\n throw new ConfigurationError(\n `Invalid Noblog config \"${path}\":\\n${z.prettifyError(result.error)}`,\n );\n }\n return result.data;\n}\n"],"mappings":";;;;;;AAUA,eAAsB,iBACpB,MAC2B;CAC3B,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,SAAS,MAAM,MAAM;CACtC,SAAS,OAAO;EAOd,MAAM,IAAI,mBACR,8BAA8B,KAAK,KANnC,aAAa,KAAK,MAAM,WACpB,mBACA,iBAAiB,QACf,MAAM,UACN,sBAGR;CACF;CAEA,IAAI;CACJ,IAAI;EACF,QAAQ,MAAM,QAAQ,EAAE,cAAc,MAAM,CAAC;CAC/C,SAAS,OAAO;EACd,MAAM,IAAI,mBACR,kCAAkC,KAAK,KACrC,iBAAiB,QAAQ,MAAM,UAAU,uBAE7C;CACF;CAEA,MAAM,SAAS,mBAAmB,UAAU,KAAK;CACjD,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,mBACR,0BAA0B,KAAK,MAAM,EAAE,cAAc,OAAO,KAAK,GACnE;CAEF,OAAO,OAAO;AAChB"}
|
|
@@ -23,6 +23,10 @@ const frontmatterFieldSchema = z.union([z.strictObject({
|
|
|
23
23
|
})]);
|
|
24
24
|
const frontmatterFieldsSchema = z.record(z.string().min(1), frontmatterFieldSchema);
|
|
25
25
|
const notionPropertiesSchema = z.record(z.string().min(1), z.string().min(1));
|
|
26
|
+
const childPageWrapperSchema = z.strictObject({
|
|
27
|
+
head: z.string().min(1).regex(/^[^\r\n]+$/, "must be a single line").describe("Opening wrapper emitted before the child-page Markdown link."),
|
|
28
|
+
tail: z.string().min(1).regex(/^[^\r\n]+$/, "must be a single line").describe("Closing wrapper emitted after the child-page Markdown link.")
|
|
29
|
+
});
|
|
26
30
|
const BUILT_IN_FRONTMATTER_SOURCES = [
|
|
27
31
|
"title",
|
|
28
32
|
"description",
|
|
@@ -42,7 +46,8 @@ const noblogConfigSchema = z.strictObject({
|
|
|
42
46
|
storePath: z.string().min(1).optional().describe("Flat directory containing every canonical Markdown file."),
|
|
43
47
|
layoutPath: z.string().min(1).optional().describe("Layout import path interpreted relative to savePath."),
|
|
44
48
|
recursive: z.boolean().optional().describe("Render child pages recursively (default: true)."),
|
|
45
|
-
childPageMarker: z.string().min(1).optional().describe("Marker prefixed to child-page links (default: ⸎, U+2E0E).")
|
|
49
|
+
childPageMarker: z.string().min(1).optional().describe("Marker prefixed to child-page links (default: ⸎, U+2E0E)."),
|
|
50
|
+
childPageWrapper: childPageWrapperSchema.optional().describe("Optional wrapper around child-page Markdown links; overrides childPageMarker.")
|
|
46
51
|
}).optional(),
|
|
47
52
|
frontmatter: z.strictObject({ fields: frontmatterFieldsSchema.optional() }).optional()
|
|
48
53
|
}).superRefine((config, context) => {
|
|
@@ -70,4 +75,4 @@ function getErrorCode(error) {
|
|
|
70
75
|
//#endregion
|
|
71
76
|
export { noblogConfigSchema as a, frontmatterFieldsSchema as i, BUILT_IN_FRONTMATTER_SOURCES as n, notionPropertiesSchema as o, frontmatterFieldSchema as r, getErrorCode as t };
|
|
72
77
|
|
|
73
|
-
//# sourceMappingURL=errors-
|
|
78
|
+
//# sourceMappingURL=errors-Bm4iVQVp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-Bm4iVQVp.js","names":[],"sources":["../src/lib/noblog/config.ts","../src/lib/errors.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport type ConfigValue =\n | string\n | number\n | boolean\n | null\n | ConfigValue[]\n | { [key: string]: ConfigValue };\n\nconst configValueSchema: z.ZodType<ConfigValue> = z.lazy(() =>\n z.union([\n z.string(),\n z.number().finite(),\n z.boolean(),\n z.null(),\n z.array(configValueSchema),\n z.record(z.string(), configValueSchema),\n ]),\n);\n\nconst fieldModifiers = {\n as: z\n .enum([\"string\", \"date\"])\n .optional()\n .describe(\n \"Convert to a string (quoting date-like strings) or a YAML date.\",\n ),\n default: configValueSchema\n .optional()\n .describe(\"Value used when the source is empty.\"),\n omitEmpty: z\n .boolean()\n .optional()\n .describe(\"Omit undefined, null, empty strings, and empty arrays.\"),\n required: z\n .boolean()\n .optional()\n .describe(\"Fail generation if the value is still empty after defaults.\"),\n};\n\nexport const frontmatterFieldSchema = z.union([\n z.strictObject({\n ...fieldModifiers,\n from: z\n .string()\n .min(1)\n .describe(\"Built-in source or a key declared under notion.properties.\"),\n }),\n z.strictObject({\n ...fieldModifiers,\n value: configValueSchema,\n }),\n]);\n\nexport const frontmatterFieldsSchema = z.record(\n z.string().min(1),\n frontmatterFieldSchema,\n);\n\nexport const notionPropertiesSchema = z.record(\n z.string().min(1),\n z.string().min(1),\n);\n\nconst childPageWrapperSchema = z.strictObject({\n head: z\n .string()\n .min(1)\n .regex(/^[^\\r\\n]+$/, \"must be a single line\")\n .describe(\"Opening wrapper emitted before the child-page Markdown link.\"),\n tail: z\n .string()\n .min(1)\n .regex(/^[^\\r\\n]+$/, \"must be a single line\")\n .describe(\"Closing wrapper emitted after the child-page Markdown link.\"),\n});\n\nexport const BUILT_IN_FRONTMATTER_SOURCES = [\n \"title\",\n \"description\",\n \"tags\",\n \"publishedAt\",\n \"archived\",\n \"layoutPath\",\n \"pageId\",\n \"isDatabasePage\",\n] as const;\n\nconst builtInSources: ReadonlySet<string> = new Set(\n BUILT_IN_FRONTMATTER_SOURCES,\n);\n\nexport const noblogConfigSchema = z\n .strictObject({\n version: z.literal(1),\n notion: z\n .strictObject({\n properties: notionPropertiesSchema.optional(),\n })\n .optional(),\n output: z\n .strictObject({\n savePath: z\n .string()\n .min(1)\n .optional()\n .describe(\"Public directory for database-post symlinks.\"),\n storePath: z\n .string()\n .min(1)\n .optional()\n .describe(\"Flat directory containing every canonical Markdown file.\"),\n layoutPath: z\n .string()\n .min(1)\n .optional()\n .describe(\"Layout import path interpreted relative to savePath.\"),\n recursive: z\n .boolean()\n .optional()\n .describe(\"Render child pages recursively (default: true).\"),\n childPageMarker: z\n .string()\n .min(1)\n .optional()\n .describe(\n \"Marker prefixed to child-page links (default: ⸎, U+2E0E).\",\n ),\n childPageWrapper: childPageWrapperSchema\n .optional()\n .describe(\n \"Optional wrapper around child-page Markdown links; overrides childPageMarker.\",\n ),\n })\n .optional(),\n frontmatter: z\n .strictObject({\n fields: frontmatterFieldsSchema.optional(),\n })\n .optional(),\n })\n .superRefine((config, context) => {\n const properties = config.notion?.properties ?? {};\n for (const [name, field] of Object.entries(\n config.frontmatter?.fields ?? {},\n )) {\n if (!(\"from\" in field)) continue;\n if (\n !builtInSources.has(field.from) &&\n !Object.hasOwn(properties, field.from)\n ) {\n context.addIssue({\n code: \"custom\",\n message: `Unknown frontmatter source \"${field.from}\"; declare it under notion.properties`,\n path: [\"frontmatter\", \"fields\", name, \"from\"],\n });\n }\n }\n })\n .describe(\n \"Noblog YAML configuration. Notion credentials remain in environment variables or .env files.\",\n );\n\nexport type FrontmatterField = z.infer<typeof frontmatterFieldSchema>;\nexport type FrontmatterFields = z.infer<typeof frontmatterFieldsSchema>;\nexport type NotionPropertyMap = z.infer<typeof notionPropertiesSchema>;\nexport type NoblogFileConfig = z.infer<typeof noblogConfigSchema>;\n","export function getErrorCode(error: unknown): string | undefined {\n if (\n typeof error !== \"object\" ||\n error === null ||\n !(\"code\" in error) ||\n typeof error.code !== \"string\"\n ) {\n return undefined;\n }\n return error.code;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as loadConfig, t as ConfigurationError } from "./config-csbquMhF.js";
|
|
2
2
|
import "./defaults-RGOB9tfi.js";
|
|
3
3
|
import { n as createFrontmatterAdapter, t as DEFAULT_FRONTMATTER_FIELDS } from "./frontmatter-fields-BkXq38CO.js";
|
|
4
|
-
import { t as loadNoblogConfig } from "./config-file-
|
|
4
|
+
import { t as loadNoblogConfig } from "./config-file-CZX2WJnz.js";
|
|
5
5
|
//#region src/commands/generate.impl.ts
|
|
6
6
|
async function generate(flags, savePath, legacySubPath) {
|
|
7
7
|
try {
|
|
@@ -10,6 +10,7 @@ async function generate(flags, savePath, legacySubPath) {
|
|
|
10
10
|
if (legacySubPath !== void 0) this.process.stderr.write("Warning: SUB_PATH is deprecated and ignored; child pages now live only in the canonical store.\n");
|
|
11
11
|
const propertyMap = fileConfig?.notion?.properties;
|
|
12
12
|
const fields = fileConfig?.frontmatter?.fields;
|
|
13
|
+
const childPageWrapper = fileConfig?.output?.childPageWrapper;
|
|
13
14
|
const frontmatter = fields || propertyMap ? createFrontmatterAdapter(fields ?? DEFAULT_FRONTMATTER_FIELDS) : void 0;
|
|
14
15
|
await this.generateBlog(config, {
|
|
15
16
|
savePath: savePath ?? fileConfig?.output?.savePath ?? "./src/pages/posts/",
|
|
@@ -17,6 +18,7 @@ async function generate(flags, savePath, legacySubPath) {
|
|
|
17
18
|
layoutPath: flags.layout ?? fileConfig?.output?.layoutPath ?? "../../layouts/MarkdownPostLayout.astro",
|
|
18
19
|
recursive: fileConfig?.output?.recursive ?? true,
|
|
19
20
|
childPageMarker: fileConfig?.output?.childPageMarker ?? "⸎",
|
|
21
|
+
...childPageWrapper !== void 0 ? { childPageWrapper } : {},
|
|
20
22
|
...propertyMap !== void 0 ? { propertyMap } : {},
|
|
21
23
|
...frontmatter !== void 0 ? { frontmatter } : {},
|
|
22
24
|
verbose: flags.verbose
|
|
@@ -31,4 +33,4 @@ async function generate(flags, savePath, legacySubPath) {
|
|
|
31
33
|
//#endregion
|
|
32
34
|
export { generate as default };
|
|
33
35
|
|
|
34
|
-
//# sourceMappingURL=generate.impl-
|
|
36
|
+
//# sourceMappingURL=generate.impl-zbCKiANA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.impl-zbCKiANA.js","names":[],"sources":["../src/commands/generate.impl.ts"],"sourcesContent":["import { ConfigurationError, loadConfig } from \"../config.js\";\nimport { loadNoblogConfig } from \"../config-file.js\";\nimport type { CliContext } from \"../context.js\";\nimport {\n DEFAULT_CHILD_PAGE_MARKER,\n DEFAULT_LAYOUT_PATH,\n DEFAULT_SAVE_PATH,\n DEFAULT_STORE_PATH,\n} from \"../lib/noblog/defaults.js\";\nimport {\n createFrontmatterAdapter,\n DEFAULT_FRONTMATTER_FIELDS,\n} from \"../lib/noblog/frontmatter-fields.js\";\n\ninterface GenerateFlags {\n verbose: boolean;\n config?: string;\n layout?: string;\n store?: string;\n}\n\nexport default async function generate(\n this: CliContext,\n flags: GenerateFlags,\n savePath?: string,\n legacySubPath?: string,\n): Promise<Error | void> {\n try {\n const fileConfig = flags.config\n ? await loadNoblogConfig(flags.config)\n : undefined;\n const config = loadConfig(this.process.env);\n if (legacySubPath !== undefined) {\n this.process.stderr.write(\n \"Warning: SUB_PATH is deprecated and ignored; child pages now live only in the canonical store.\\n\",\n );\n }\n\n const propertyMap = fileConfig?.notion?.properties;\n const fields = fileConfig?.frontmatter?.fields;\n const childPageWrapper = fileConfig?.output?.childPageWrapper;\n const frontmatter =\n fields || propertyMap\n ? createFrontmatterAdapter(fields ?? DEFAULT_FRONTMATTER_FIELDS)\n : undefined;\n\n await this.generateBlog(\n config,\n {\n savePath:\n savePath ?? fileConfig?.output?.savePath ?? DEFAULT_SAVE_PATH,\n storePath:\n flags.store ?? fileConfig?.output?.storePath ?? DEFAULT_STORE_PATH,\n layoutPath:\n flags.layout ?? fileConfig?.output?.layoutPath ?? DEFAULT_LAYOUT_PATH,\n recursive: fileConfig?.output?.recursive ?? true,\n childPageMarker:\n fileConfig?.output?.childPageMarker ?? DEFAULT_CHILD_PAGE_MARKER,\n ...(childPageWrapper !== undefined ? { childPageWrapper } : {}),\n ...(propertyMap !== undefined ? { propertyMap } : {}),\n ...(frontmatter !== undefined ? { frontmatter } : {}),\n verbose: flags.verbose,\n },\n this.process,\n );\n } catch (error) {\n if (error instanceof ConfigurationError) {\n return error;\n }\n if (!(error instanceof Error)) {\n return new Error(\"Generation failed: an unknown error occurred\");\n }\n\n const message = flags.verbose\n ? (error.stack ?? error.message)\n : error.message;\n return new Error(`Generation failed: ${message}`, { cause: error });\n }\n}\n"],"mappings":";;;;;AAqBA,eAA8B,SAE5B,OACA,UACA,eACuB;CACvB,IAAI;EACF,MAAM,aAAa,MAAM,SACrB,MAAM,iBAAiB,MAAM,MAAM,IACnC,KAAA;EACJ,MAAM,SAAS,WAAW,KAAK,QAAQ,GAAG;EAC1C,IAAI,kBAAkB,KAAA,GACpB,KAAK,QAAQ,OAAO,MAClB,kGACF;EAGF,MAAM,cAAc,YAAY,QAAQ;EACxC,MAAM,SAAS,YAAY,aAAa;EACxC,MAAM,mBAAmB,YAAY,QAAQ;EAC7C,MAAM,cACJ,UAAU,cACN,yBAAyB,UAAU,0BAA0B,IAC7D,KAAA;EAEN,MAAM,KAAK,aACT,QACA;GACE,UACE,YAAY,YAAY,QAAQ,YAAA;GAClC,WACE,MAAM,SAAS,YAAY,QAAQ,aAAA;GACrC,YACE,MAAM,UAAU,YAAY,QAAQ,cAAA;GACtC,WAAW,YAAY,QAAQ,aAAa;GAC5C,iBACE,YAAY,QAAQ,mBAAA;GACtB,GAAI,qBAAqB,KAAA,IAAY,EAAE,iBAAiB,IAAI,CAAC;GAC7D,GAAI,gBAAgB,KAAA,IAAY,EAAE,YAAY,IAAI,CAAC;GACnD,GAAI,gBAAgB,KAAA,IAAY,EAAE,YAAY,IAAI,CAAC;GACnD,SAAS,MAAM;EACjB,GACA,KAAK,OACP;CACF,SAAS,OAAO;EACd,IAAI,iBAAiB,oBACnB,OAAO;EAET,IAAI,EAAE,iBAAiB,QACrB,uBAAO,IAAI,MAAM,8CAA8C;EAGjE,MAAM,UAAU,MAAM,UACjB,MAAM,SAAS,MAAM,UACtB,MAAM;EACV,OAAO,IAAI,MAAM,sBAAsB,WAAW,EAAE,OAAO,MAAM,CAAC;CACpE;AACF"}
|
package/dist/generate.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as ConfigurationError } from "./config-csbquMhF.js";
|
|
3
|
-
import { a as renderPages, n as resolveStoreLayoutPath, r as writePages, t as createNotionSource } from "./client-
|
|
3
|
+
import { a as renderPages, n as resolveStoreLayoutPath, r as writePages, t as createNotionSource } from "./client-BIBJQzBg.js";
|
|
4
4
|
import { config } from "dotenv";
|
|
5
5
|
import { ExitCode, buildApplication, buildCommand, buildRouteMap, help, run, version } from "@stricli/core";
|
|
6
6
|
const app = buildApplication(buildRouteMap({
|
|
7
7
|
routes: {
|
|
8
8
|
config: buildRouteMap({
|
|
9
9
|
routes: { check: buildCommand({
|
|
10
|
-
loader: async () => import("./config-check.impl-
|
|
10
|
+
loader: async () => import("./config-check.impl-NO--hbh0.js"),
|
|
11
11
|
parameters: {
|
|
12
12
|
flags: { config: {
|
|
13
13
|
kind: "parsed",
|
|
@@ -25,7 +25,7 @@ const app = buildApplication(buildRouteMap({
|
|
|
25
25
|
docs: { brief: "Inspect Noblog configuration" }
|
|
26
26
|
}),
|
|
27
27
|
generate: buildCommand({
|
|
28
|
-
loader: async () => import("./generate.impl-
|
|
28
|
+
loader: async () => import("./generate.impl-zbCKiANA.js"),
|
|
29
29
|
parameters: {
|
|
30
30
|
flags: {
|
|
31
31
|
verbose: {
|
|
@@ -98,7 +98,7 @@ const app = buildApplication(buildRouteMap({
|
|
|
98
98
|
}),
|
|
99
99
|
version: version({
|
|
100
100
|
brief: "Show version information",
|
|
101
|
-
info: { currentVersion: `noblog v0.3.0-beta.
|
|
101
|
+
info: { currentVersion: `noblog v0.3.0-beta.3` },
|
|
102
102
|
alias: false
|
|
103
103
|
})
|
|
104
104
|
});
|
|
@@ -162,6 +162,7 @@ async function generateBlog(config, options, output) {
|
|
|
162
162
|
layoutPath: storeLayoutPath,
|
|
163
163
|
recursive: options.recursive,
|
|
164
164
|
childPageMarker: options.childPageMarker,
|
|
165
|
+
...options.childPageWrapper !== void 0 ? { childPageWrapper: options.childPageWrapper } : {},
|
|
165
166
|
...options.propertyMap !== void 0 ? { propertyMap: options.propertyMap } : {},
|
|
166
167
|
...options.frontmatter !== void 0 ? { frontmatter: options.frontmatter } : {}
|
|
167
168
|
}), {
|
package/dist/generate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","names":["packageJson.version"],"sources":["../package.json","../src/commands/config-check.ts","../src/commands/config.ts","../src/commands/generate.ts","../src/app.ts","../src/workflows/generate.ts","../src/main.ts","../src/cli.ts"],"sourcesContent":["","import { buildCommand } from \"@stricli/core\";\n\nexport const configCheckCommand = buildCommand({\n loader: async () => import(\"./config-check.impl.js\"),\n parameters: {\n flags: {\n config: {\n kind: \"parsed\",\n brief: \"YAML configuration file\",\n placeholder: \"PATH\",\n parse: (input) => input,\n },\n },\n positional: {\n kind: \"tuple\",\n parameters: [],\n },\n },\n docs: {\n brief: \"Validate a YAML configuration without network access\",\n },\n});\n","import { buildRouteMap } from \"@stricli/core\";\nimport { configCheckCommand } from \"./config-check.js\";\n\nexport const configCommand = buildRouteMap({\n routes: {\n check: configCheckCommand,\n },\n docs: {\n brief: \"Inspect Noblog configuration\",\n },\n});\n","import { buildCommand } from \"@stricli/core\";\n\nexport const generateCommand = buildCommand({\n loader: async () => import(\"./generate.impl.js\"),\n parameters: {\n flags: {\n verbose: {\n kind: \"boolean\",\n brief: \"Print diagnostic information\",\n default: false,\n withNegated: false,\n },\n config: {\n kind: \"parsed\",\n brief: \"YAML configuration file\",\n placeholder: \"PATH\",\n parse: (input) => input,\n optional: true,\n },\n layout: {\n kind: \"parsed\",\n brief: \"Layout path relative to SAVE_PATH\",\n placeholder: \"PATH\",\n parse: (input) => input,\n optional: true,\n },\n store: {\n kind: \"parsed\",\n brief: \"Directory for canonical Markdown files\",\n placeholder: \"PATH\",\n parse: (input) => input,\n optional: true,\n },\n },\n aliases: {\n v: \"verbose\",\n },\n positional: {\n kind: \"tuple\",\n parameters: [\n {\n brief: \"Public view directory for database posts\",\n placeholder: \"SAVE_PATH\",\n parse: (input) => input,\n optional: true,\n },\n {\n brief: \"Deprecated compatibility argument; ignored\",\n placeholder: \"SUB_PATH\",\n parse: (input) => input,\n optional: true,\n },\n ],\n },\n },\n docs: {\n brief: \"Generate blog content from Notion\",\n fullDescription:\n \"Fetch published pages from Notion and write Astro-compatible Markdown files. \" +\n \"Only database posts receive public symlinks; child pages live in the canonical store. \" +\n \"The legacy SUB_PATH argument is accepted but ignored.\",\n },\n});\n","import {\n buildApplication,\n buildRouteMap,\n ExitCode,\n help,\n run,\n version,\n} from \"@stricli/core\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport { configCommand } from \"./commands/config.js\";\nimport { generateCommand } from \"./commands/generate.js\";\nimport { ConfigurationError } from \"./config.js\";\nimport type { CliContext } from \"./context.js\";\n\nconst root = buildRouteMap({\n routes: {\n config: configCommand,\n generate: generateCommand,\n },\n docs: {\n brief: \"Generate static blog content from Notion\",\n fullDescription:\n \"Running noblog without a subcommand is equivalent to 'noblog generate'.\\n\" +\n \"The legacy 'help' and 'version' commands are also supported.\\n\\n\" +\n \"Generation requires environment variables:\\n\" +\n \" NOTION_API_SECRET Your Notion API secret\\n\" +\n \" NOBLOG_DATABASE_ID Your Notion database ID\",\n },\n});\n\nconst helpFormatting = {\n caseStyle: \"original\",\n useAliasInUsageLine: false,\n onlyRequiredInUsageLine: false,\n} as const;\n\nexport const app = buildApplication(\n root,\n {\n name: \"noblog\",\n scanner: {\n allowArgumentEscapeSequence: true,\n },\n determineExitCode: (error) =>\n error instanceof ConfigurationError ? 2 : ExitCode.CommandRunError,\n },\n {\n help: help({\n brief: \"Show help information\",\n defaultForRouteMap: true,\n formatting: helpFormatting,\n }),\n version: version({\n brief: \"Show version information\",\n info: { currentVersion: `noblog v${packageJson.version}` },\n alias: false,\n }),\n },\n);\n\nconst PATH_FLAGS = new Set([\"--config\", \"--layout\", \"--store\"]);\n\nexport async function runCli(\n inputs: readonly string[],\n context: CliContext,\n): Promise<void> {\n const escapeIndex = inputs.indexOf(\"--\");\n const commandInputs =\n escapeIndex === -1 ? inputs : inputs.slice(0, escapeIndex);\n const escapedInputs = escapeIndex === -1 ? [] : inputs.slice(escapeIndex);\n\n let normalizedInputs: readonly string[];\n if (hasLegacyControl(commandInputs, \"help\")) {\n normalizedInputs = [\"--help\"];\n } else if (\n hasLegacyControl(commandInputs, \"version\") ||\n hasLegacyControl(commandInputs, \"--version\")\n ) {\n normalizedInputs = [\"--version\"];\n } else {\n // Legacy control words were global. Keep the first explicit command and\n // skip later ones; escaped words and flag values remain positional data.\n const remainingInputs: string[] = [];\n for (let index = 0; index < commandInputs.length; index++) {\n const input = commandInputs[index];\n if (input === undefined) continue;\n if (input === \"generate\" && index !== 0) continue;\n\n remainingInputs.push(input);\n const flagValue = getFlagValue(commandInputs, index);\n if (PATH_FLAGS.has(input) && flagValue !== undefined) {\n remainingInputs.push(flagValue);\n index++;\n }\n }\n normalizedInputs = [...remainingInputs, ...escapedInputs];\n\n if (\n normalizedInputs[0] !== \"generate\" &&\n normalizedInputs[0] !== \"config\" &&\n normalizedInputs[0] !== \"-h\" &&\n normalizedInputs[0] !== \"--help\" &&\n normalizedInputs[0] !== \"--version\"\n ) {\n normalizedInputs = [\"generate\", ...normalizedInputs];\n }\n }\n\n await run(app, normalizedInputs, context);\n\n const exitCode = context.process.exitCode;\n if (typeof exitCode === \"number\" && exitCode < 0) {\n context.process.exitCode =\n exitCode === ExitCode.InvalidArgument ||\n exitCode === ExitCode.UnknownCommand\n ? 2\n : 1;\n }\n}\n\nfunction hasLegacyControl(\n inputs: readonly string[],\n control: \"help\" | \"version\" | \"--version\",\n): boolean {\n for (let index = 0; index < inputs.length; index++) {\n const input = inputs[index];\n if (input === undefined) continue;\n if (\n PATH_FLAGS.has(input) &&\n getFlagValue(inputs, index) !== undefined\n ) {\n index++;\n continue;\n }\n if (input === control) return true;\n }\n return false;\n}\n\nfunction getFlagValue(\n inputs: readonly string[],\n flagIndex: number,\n): string | undefined {\n const value = inputs[flagIndex + 1];\n return value !== undefined && !value.startsWith(\"-\") ? value : undefined;\n}\n","import type { NoblogConfig } from \"../config.js\";\nimport type { NotionPropertyMap } from \"../lib/noblog/config.js\";\nimport {\n renderPages,\n resolveStoreLayoutPath,\n writePages,\n} from \"../lib/noblog/index.js\";\nimport type { FrontmatterAdapter } from \"../lib/noblog/types.js\";\nimport { createNotionSource } from \"../lib/notion/client.js\";\n\nexport interface GenerateOptions {\n savePath: string;\n storePath: string;\n layoutPath: string;\n recursive: boolean;\n childPageMarker: string;\n propertyMap?: NotionPropertyMap;\n frontmatter?: FrontmatterAdapter;\n verbose: boolean;\n}\n\nexport interface GenerateOutput {\n stdout: { write(chunk: string): void };\n stderr: { write(chunk: string): void };\n}\n\nexport async function generateBlog(\n config: NoblogConfig,\n options: GenerateOptions,\n output: GenerateOutput,\n): Promise<void> {\n const notion = createNotionSource(config);\n const storeLayoutPath = resolveStoreLayoutPath(options);\n\n if (options.verbose) {\n output.stderr.write(\"Fetching posts from Notion...\\n\");\n }\n\n const posts = await notion.listPages();\n\n if (options.verbose) {\n output.stderr.write(\n `Found ${posts.length} pages\\n` +\n `Save path: ${options.savePath}\\n` +\n `Store path: ${options.storePath}\\n` +\n `Layout path: ${options.layoutPath}\\n`,\n );\n }\n\n const pages = await renderPages(posts, notion, {\n layoutPath: storeLayoutPath,\n recursive: options.recursive,\n childPageMarker: options.childPageMarker,\n ...(options.propertyMap !== undefined\n ? { propertyMap: options.propertyMap }\n : {}),\n ...(options.frontmatter !== undefined\n ? { frontmatter: options.frontmatter }\n : {}),\n });\n await writePages(pages, {\n savePath: options.savePath,\n storePath: options.storePath,\n });\n\n output.stdout.write(\"✅ Successfully generated blog content\\n\");\n}\n\nexport type GenerateBlog = typeof generateBlog;\n","import { config as loadDotenv } from \"dotenv\";\nimport type { DotenvPopulateInput } from \"dotenv\";\nimport { runCli } from \"./app.js\";\nimport type { CliContext } from \"./context.js\";\nimport { generateBlog } from \"./workflows/generate.js\";\n\nconst nodeProcess: CliContext[\"process\"] = {\n env: process.env,\n stdout: process.stdout,\n stderr: process.stderr,\n get exitCode() {\n const exitCode = process.exitCode;\n return typeof exitCode === \"number\" ? exitCode : null;\n },\n set exitCode(value: number | null) {\n process.exitCode = value ?? undefined;\n },\n};\n\nexport async function main(\n inputs: readonly string[] = process.argv.slice(2),\n context: CliContext = { process: nodeProcess, generateBlog },\n): Promise<void> {\n const environment = context.process.env ?? {};\n const processEnv: DotenvPopulateInput = Object.fromEntries(\n Object.entries(environment).filter(\n (entry): entry is [string, string] => entry[1] !== undefined,\n ),\n );\n loadDotenv({ processEnv, quiet: true });\n Object.assign(environment, processEnv);\n await runCli(inputs, context);\n}\n","#!/usr/bin/env node\n\nimport { main } from \"./main.js\";\n\nawait main();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generate.js","names":["packageJson.version"],"sources":["../package.json","../src/commands/config-check.ts","../src/commands/config.ts","../src/commands/generate.ts","../src/app.ts","../src/workflows/generate.ts","../src/main.ts","../src/cli.ts"],"sourcesContent":["","import { buildCommand } from \"@stricli/core\";\n\nexport const configCheckCommand = buildCommand({\n loader: async () => import(\"./config-check.impl.js\"),\n parameters: {\n flags: {\n config: {\n kind: \"parsed\",\n brief: \"YAML configuration file\",\n placeholder: \"PATH\",\n parse: (input) => input,\n },\n },\n positional: {\n kind: \"tuple\",\n parameters: [],\n },\n },\n docs: {\n brief: \"Validate a YAML configuration without network access\",\n },\n});\n","import { buildRouteMap } from \"@stricli/core\";\nimport { configCheckCommand } from \"./config-check.js\";\n\nexport const configCommand = buildRouteMap({\n routes: {\n check: configCheckCommand,\n },\n docs: {\n brief: \"Inspect Noblog configuration\",\n },\n});\n","import { buildCommand } from \"@stricli/core\";\n\nexport const generateCommand = buildCommand({\n loader: async () => import(\"./generate.impl.js\"),\n parameters: {\n flags: {\n verbose: {\n kind: \"boolean\",\n brief: \"Print diagnostic information\",\n default: false,\n withNegated: false,\n },\n config: {\n kind: \"parsed\",\n brief: \"YAML configuration file\",\n placeholder: \"PATH\",\n parse: (input) => input,\n optional: true,\n },\n layout: {\n kind: \"parsed\",\n brief: \"Layout path relative to SAVE_PATH\",\n placeholder: \"PATH\",\n parse: (input) => input,\n optional: true,\n },\n store: {\n kind: \"parsed\",\n brief: \"Directory for canonical Markdown files\",\n placeholder: \"PATH\",\n parse: (input) => input,\n optional: true,\n },\n },\n aliases: {\n v: \"verbose\",\n },\n positional: {\n kind: \"tuple\",\n parameters: [\n {\n brief: \"Public view directory for database posts\",\n placeholder: \"SAVE_PATH\",\n parse: (input) => input,\n optional: true,\n },\n {\n brief: \"Deprecated compatibility argument; ignored\",\n placeholder: \"SUB_PATH\",\n parse: (input) => input,\n optional: true,\n },\n ],\n },\n },\n docs: {\n brief: \"Generate blog content from Notion\",\n fullDescription:\n \"Fetch published pages from Notion and write Astro-compatible Markdown files. \" +\n \"Only database posts receive public symlinks; child pages live in the canonical store. \" +\n \"The legacy SUB_PATH argument is accepted but ignored.\",\n },\n});\n","import {\n buildApplication,\n buildRouteMap,\n ExitCode,\n help,\n run,\n version,\n} from \"@stricli/core\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\nimport { configCommand } from \"./commands/config.js\";\nimport { generateCommand } from \"./commands/generate.js\";\nimport { ConfigurationError } from \"./config.js\";\nimport type { CliContext } from \"./context.js\";\n\nconst root = buildRouteMap({\n routes: {\n config: configCommand,\n generate: generateCommand,\n },\n docs: {\n brief: \"Generate static blog content from Notion\",\n fullDescription:\n \"Running noblog without a subcommand is equivalent to 'noblog generate'.\\n\" +\n \"The legacy 'help' and 'version' commands are also supported.\\n\\n\" +\n \"Generation requires environment variables:\\n\" +\n \" NOTION_API_SECRET Your Notion API secret\\n\" +\n \" NOBLOG_DATABASE_ID Your Notion database ID\",\n },\n});\n\nconst helpFormatting = {\n caseStyle: \"original\",\n useAliasInUsageLine: false,\n onlyRequiredInUsageLine: false,\n} as const;\n\nexport const app = buildApplication(\n root,\n {\n name: \"noblog\",\n scanner: {\n allowArgumentEscapeSequence: true,\n },\n determineExitCode: (error) =>\n error instanceof ConfigurationError ? 2 : ExitCode.CommandRunError,\n },\n {\n help: help({\n brief: \"Show help information\",\n defaultForRouteMap: true,\n formatting: helpFormatting,\n }),\n version: version({\n brief: \"Show version information\",\n info: { currentVersion: `noblog v${packageJson.version}` },\n alias: false,\n }),\n },\n);\n\nconst PATH_FLAGS = new Set([\"--config\", \"--layout\", \"--store\"]);\n\nexport async function runCli(\n inputs: readonly string[],\n context: CliContext,\n): Promise<void> {\n const escapeIndex = inputs.indexOf(\"--\");\n const commandInputs =\n escapeIndex === -1 ? inputs : inputs.slice(0, escapeIndex);\n const escapedInputs = escapeIndex === -1 ? [] : inputs.slice(escapeIndex);\n\n let normalizedInputs: readonly string[];\n if (hasLegacyControl(commandInputs, \"help\")) {\n normalizedInputs = [\"--help\"];\n } else if (\n hasLegacyControl(commandInputs, \"version\") ||\n hasLegacyControl(commandInputs, \"--version\")\n ) {\n normalizedInputs = [\"--version\"];\n } else {\n // Legacy control words were global. Keep the first explicit command and\n // skip later ones; escaped words and flag values remain positional data.\n const remainingInputs: string[] = [];\n for (let index = 0; index < commandInputs.length; index++) {\n const input = commandInputs[index];\n if (input === undefined) continue;\n if (input === \"generate\" && index !== 0) continue;\n\n remainingInputs.push(input);\n const flagValue = getFlagValue(commandInputs, index);\n if (PATH_FLAGS.has(input) && flagValue !== undefined) {\n remainingInputs.push(flagValue);\n index++;\n }\n }\n normalizedInputs = [...remainingInputs, ...escapedInputs];\n\n if (\n normalizedInputs[0] !== \"generate\" &&\n normalizedInputs[0] !== \"config\" &&\n normalizedInputs[0] !== \"-h\" &&\n normalizedInputs[0] !== \"--help\" &&\n normalizedInputs[0] !== \"--version\"\n ) {\n normalizedInputs = [\"generate\", ...normalizedInputs];\n }\n }\n\n await run(app, normalizedInputs, context);\n\n const exitCode = context.process.exitCode;\n if (typeof exitCode === \"number\" && exitCode < 0) {\n context.process.exitCode =\n exitCode === ExitCode.InvalidArgument ||\n exitCode === ExitCode.UnknownCommand\n ? 2\n : 1;\n }\n}\n\nfunction hasLegacyControl(\n inputs: readonly string[],\n control: \"help\" | \"version\" | \"--version\",\n): boolean {\n for (let index = 0; index < inputs.length; index++) {\n const input = inputs[index];\n if (input === undefined) continue;\n if (\n PATH_FLAGS.has(input) &&\n getFlagValue(inputs, index) !== undefined\n ) {\n index++;\n continue;\n }\n if (input === control) return true;\n }\n return false;\n}\n\nfunction getFlagValue(\n inputs: readonly string[],\n flagIndex: number,\n): string | undefined {\n const value = inputs[flagIndex + 1];\n return value !== undefined && !value.startsWith(\"-\") ? value : undefined;\n}\n","import type { NoblogConfig } from \"../config.js\";\nimport type { NotionPropertyMap } from \"../lib/noblog/config.js\";\nimport {\n renderPages,\n resolveStoreLayoutPath,\n writePages,\n} from \"../lib/noblog/index.js\";\nimport type {\n ChildPageWrapper,\n FrontmatterAdapter,\n} from \"../lib/noblog/types.js\";\nimport { createNotionSource } from \"../lib/notion/client.js\";\n\nexport interface GenerateOptions {\n savePath: string;\n storePath: string;\n layoutPath: string;\n recursive: boolean;\n childPageMarker: string;\n childPageWrapper?: ChildPageWrapper;\n propertyMap?: NotionPropertyMap;\n frontmatter?: FrontmatterAdapter;\n verbose: boolean;\n}\n\nexport interface GenerateOutput {\n stdout: { write(chunk: string): void };\n stderr: { write(chunk: string): void };\n}\n\nexport async function generateBlog(\n config: NoblogConfig,\n options: GenerateOptions,\n output: GenerateOutput,\n): Promise<void> {\n const notion = createNotionSource(config);\n const storeLayoutPath = resolveStoreLayoutPath(options);\n\n if (options.verbose) {\n output.stderr.write(\"Fetching posts from Notion...\\n\");\n }\n\n const posts = await notion.listPages();\n\n if (options.verbose) {\n output.stderr.write(\n `Found ${posts.length} pages\\n` +\n `Save path: ${options.savePath}\\n` +\n `Store path: ${options.storePath}\\n` +\n `Layout path: ${options.layoutPath}\\n`,\n );\n }\n\n const pages = await renderPages(posts, notion, {\n layoutPath: storeLayoutPath,\n recursive: options.recursive,\n childPageMarker: options.childPageMarker,\n ...(options.childPageWrapper !== undefined\n ? { childPageWrapper: options.childPageWrapper }\n : {}),\n ...(options.propertyMap !== undefined\n ? { propertyMap: options.propertyMap }\n : {}),\n ...(options.frontmatter !== undefined\n ? { frontmatter: options.frontmatter }\n : {}),\n });\n await writePages(pages, {\n savePath: options.savePath,\n storePath: options.storePath,\n });\n\n output.stdout.write(\"✅ Successfully generated blog content\\n\");\n}\n\nexport type GenerateBlog = typeof generateBlog;\n","import { config as loadDotenv } from \"dotenv\";\nimport type { DotenvPopulateInput } from \"dotenv\";\nimport { runCli } from \"./app.js\";\nimport type { CliContext } from \"./context.js\";\nimport { generateBlog } from \"./workflows/generate.js\";\n\nconst nodeProcess: CliContext[\"process\"] = {\n env: process.env,\n stdout: process.stdout,\n stderr: process.stderr,\n get exitCode() {\n const exitCode = process.exitCode;\n return typeof exitCode === \"number\" ? exitCode : null;\n },\n set exitCode(value: number | null) {\n process.exitCode = value ?? undefined;\n },\n};\n\nexport async function main(\n inputs: readonly string[] = process.argv.slice(2),\n context: CliContext = { process: nodeProcess, generateBlog },\n): Promise<void> {\n const environment = context.process.env ?? {};\n const processEnv: DotenvPopulateInput = Object.fromEntries(\n Object.entries(environment).filter(\n (entry): entry is [string, string] => entry[1] !== undefined,\n ),\n );\n loadDotenv({ processEnv, quiet: true });\n Object.assign(environment, processEnv);\n await runCli(inputs, context);\n}\n","#!/usr/bin/env node\n\nimport { main } from \"./main.js\";\n\nawait main();\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,10 @@ declare const noblogConfigSchema: z.ZodObject<{
|
|
|
56
56
|
layoutPath: z.ZodOptional<z.ZodString>;
|
|
57
57
|
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
58
58
|
childPageMarker: z.ZodOptional<z.ZodString>;
|
|
59
|
+
childPageWrapper: z.ZodOptional<z.ZodObject<{
|
|
60
|
+
head: z.ZodString;
|
|
61
|
+
tail: z.ZodString;
|
|
62
|
+
}, z.core.$strict>>;
|
|
59
63
|
}, z.core.$strict>>;
|
|
60
64
|
frontmatter: z.ZodOptional<z.ZodObject<{
|
|
61
65
|
fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -107,9 +111,17 @@ declare function extractPageMetadata(page: PageObjectResponse, properties?: Noti
|
|
|
107
111
|
type CalloutIcon = Extract<BlockObjectResponse, {
|
|
108
112
|
type: "callout";
|
|
109
113
|
}>["callout"]["icon"];
|
|
114
|
+
type Heading1Block = Extract<BlockObjectResponse, {
|
|
115
|
+
type: "heading_1";
|
|
116
|
+
}>;
|
|
117
|
+
type Heading4BlockObjectResponse = Omit<Heading1Block, "type" | "heading_1"> & {
|
|
118
|
+
readonly type: "heading_4";
|
|
119
|
+
readonly heading_4: Heading1Block["heading_1"];
|
|
120
|
+
};
|
|
121
|
+
type NoblogBlock = BlockObjectResponse | Heading4BlockObjectResponse;
|
|
110
122
|
interface NotionReader {
|
|
111
123
|
getPage(pageId: string): Promise<PageObjectResponse>;
|
|
112
|
-
getBlockChildren(blockId: string): Promise<readonly
|
|
124
|
+
getBlockChildren(blockId: string): Promise<readonly NoblogBlock[]>;
|
|
113
125
|
}
|
|
114
126
|
interface FrontmatterContext {
|
|
115
127
|
readonly page: PageObjectResponse;
|
|
@@ -125,14 +137,19 @@ type FrontmatterAdapter = (context: FrontmatterContext) => FrontmatterRecord;
|
|
|
125
137
|
interface BlockTransformerContext {
|
|
126
138
|
readonly pageId: string;
|
|
127
139
|
}
|
|
128
|
-
type BlockTransformer<K extends
|
|
140
|
+
type BlockTransformer<K extends NoblogBlock["type"] = NoblogBlock["type"]> = (block: Extract<NoblogBlock, {
|
|
129
141
|
type: K;
|
|
130
142
|
}>, context: BlockTransformerContext) => string | undefined | Promise<string | undefined>;
|
|
131
|
-
type BlockTransformers = { readonly [K in
|
|
143
|
+
type BlockTransformers = { readonly [K in NoblogBlock["type"]]?: BlockTransformer<K> | undefined };
|
|
144
|
+
interface ChildPageWrapper {
|
|
145
|
+
readonly head: string;
|
|
146
|
+
readonly tail: string;
|
|
147
|
+
}
|
|
132
148
|
interface RenderOptions {
|
|
133
149
|
readonly layoutPath?: string;
|
|
134
150
|
readonly recursive?: boolean;
|
|
135
151
|
readonly childPageMarker?: string;
|
|
152
|
+
readonly childPageWrapper?: ChildPageWrapper;
|
|
136
153
|
readonly propertyMap?: NotionPropertyMap;
|
|
137
154
|
readonly frontmatter?: FrontmatterAdapter;
|
|
138
155
|
readonly transformers?: BlockTransformers;
|
|
@@ -179,6 +196,7 @@ declare const equation: (text: string) => string;
|
|
|
179
196
|
declare const heading1: (text: string) => string;
|
|
180
197
|
declare const heading2: (text: string) => string;
|
|
181
198
|
declare const heading3: (text: string) => string;
|
|
199
|
+
declare const heading4: (text: string) => string;
|
|
182
200
|
declare const quote: (text: string) => string;
|
|
183
201
|
declare function callout(text: string, icon?: CalloutIcon): string;
|
|
184
202
|
declare function bullet(text: string, count?: number): string;
|
|
@@ -210,5 +228,5 @@ interface NotionSource extends NotionReader {
|
|
|
210
228
|
}
|
|
211
229
|
declare function createNotionSource(config: NotionSourceConfig): NotionSource;
|
|
212
230
|
//#endregion
|
|
213
|
-
export { BUILT_IN_FRONTMATTER_SOURCES, BlockTransformer, BlockTransformerContext, BlockTransformers, CalloutIcon, ConfigValue, DEFAULT_CHILD_PAGE_MARKER, DEFAULT_FRONTMATTER_FIELDS, DEFAULT_LAYOUT_PATH, DEFAULT_SAVE_PATH, DEFAULT_STORE_PATH, FrontmatterAdapter, FrontmatterContext, FrontmatterField, FrontmatterFields, FrontmatterOptions, FrontmatterRecord, FrontmatterValue, MetadataValue, NoblogFileConfig, NotionPropertyMap, NotionReader, NotionSource, NotionSourceConfig, PageMetadata, RenderOptions, RenderedPage, StoreLayoutOptions, WritePagesOptions, bold, bullet, callout, codeBlock, createFrontmatterAdapter, createNotionSource, divider, equation, extractPageMetadata, frontmatterFieldSchema, frontmatterFieldsSchema, heading1, heading2, heading3, image, inlineCode, inlineEquation, italic, link, noblogConfigSchema, notionPropertiesSchema, quote, renderFrontmatter, renderPage, renderPages, renderPlainText, renderRichText, resolveStoreLayoutPath, strikethrough, table, todo, toggle, underline, writePages };
|
|
231
|
+
export { BUILT_IN_FRONTMATTER_SOURCES, BlockTransformer, BlockTransformerContext, BlockTransformers, CalloutIcon, ChildPageWrapper, ConfigValue, DEFAULT_CHILD_PAGE_MARKER, DEFAULT_FRONTMATTER_FIELDS, DEFAULT_LAYOUT_PATH, DEFAULT_SAVE_PATH, DEFAULT_STORE_PATH, FrontmatterAdapter, FrontmatterContext, FrontmatterField, FrontmatterFields, FrontmatterOptions, FrontmatterRecord, FrontmatterValue, Heading4BlockObjectResponse, MetadataValue, NoblogBlock, NoblogFileConfig, NotionPropertyMap, NotionReader, NotionSource, NotionSourceConfig, PageMetadata, RenderOptions, RenderedPage, StoreLayoutOptions, WritePagesOptions, bold, bullet, callout, codeBlock, createFrontmatterAdapter, createNotionSource, divider, equation, extractPageMetadata, frontmatterFieldSchema, frontmatterFieldsSchema, heading1, heading2, heading3, heading4, image, inlineCode, inlineEquation, italic, link, noblogConfigSchema, notionPropertiesSchema, quote, renderFrontmatter, renderPage, renderPages, renderPlainText, renderRichText, resolveStoreLayoutPath, strikethrough, table, todo, toggle, underline, writePages };
|
|
214
232
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as noblogConfigSchema, i as frontmatterFieldsSchema, n as BUILT_IN_FRONTMATTER_SOURCES, o as notionPropertiesSchema, r as frontmatterFieldSchema } from "./errors-
|
|
1
|
+
import { a as noblogConfigSchema, i as frontmatterFieldsSchema, n as BUILT_IN_FRONTMATTER_SOURCES, o as notionPropertiesSchema, r as frontmatterFieldSchema } from "./errors-Bm4iVQVp.js";
|
|
2
2
|
import { i as DEFAULT_STORE_PATH, n as DEFAULT_LAYOUT_PATH, r as DEFAULT_SAVE_PATH, t as DEFAULT_CHILD_PAGE_MARKER } from "./defaults-RGOB9tfi.js";
|
|
3
|
-
import { C as
|
|
3
|
+
import { A as extractPageMetadata, C as quote, D as toggle, E as todo, O as underline, S as link, T as table, _ as heading4, a as renderPages, b as inlineEquation, c as bold, d as codeBlock, f as divider, g as heading3, h as heading2, i as renderPage, k as renderFrontmatter, l as bullet, m as heading1, n as resolveStoreLayoutPath, o as renderPlainText, p as equation, r as writePages, s as renderRichText, t as createNotionSource, u as callout, v as image, w as strikethrough, x as italic, y as inlineCode } from "./client-BIBJQzBg.js";
|
|
4
4
|
import { n as createFrontmatterAdapter, t as DEFAULT_FRONTMATTER_FIELDS } from "./frontmatter-fields-BkXq38CO.js";
|
|
5
|
-
export { BUILT_IN_FRONTMATTER_SOURCES, DEFAULT_CHILD_PAGE_MARKER, DEFAULT_FRONTMATTER_FIELDS, DEFAULT_LAYOUT_PATH, DEFAULT_SAVE_PATH, DEFAULT_STORE_PATH, bold, bullet, callout, codeBlock, createFrontmatterAdapter, createNotionSource, divider, equation, extractPageMetadata, frontmatterFieldSchema, frontmatterFieldsSchema, heading1, heading2, heading3, image, inlineCode, inlineEquation, italic, link, noblogConfigSchema, notionPropertiesSchema, quote, renderFrontmatter, renderPage, renderPages, renderPlainText, renderRichText, resolveStoreLayoutPath, strikethrough, table, todo, toggle, underline, writePages };
|
|
5
|
+
export { BUILT_IN_FRONTMATTER_SOURCES, DEFAULT_CHILD_PAGE_MARKER, DEFAULT_FRONTMATTER_FIELDS, DEFAULT_LAYOUT_PATH, DEFAULT_SAVE_PATH, DEFAULT_STORE_PATH, bold, bullet, callout, codeBlock, createFrontmatterAdapter, createNotionSource, divider, equation, extractPageMetadata, frontmatterFieldSchema, frontmatterFieldsSchema, heading1, heading2, heading3, heading4, image, inlineCode, inlineEquation, italic, link, noblogConfigSchema, notionPropertiesSchema, quote, renderFrontmatter, renderPage, renderPages, renderPlainText, renderRichText, resolveStoreLayoutPath, strikethrough, table, todo, toggle, underline, writePages };
|
package/package.json
CHANGED
package/schema/config.json
CHANGED
|
@@ -49,6 +49,29 @@
|
|
|
49
49
|
"description": "Marker prefixed to child-page links (default: ⸎, U+2E0E).",
|
|
50
50
|
"type": "string",
|
|
51
51
|
"minLength": 1
|
|
52
|
+
},
|
|
53
|
+
"childPageWrapper": {
|
|
54
|
+
"description": "Optional wrapper around child-page Markdown links; overrides childPageMarker.",
|
|
55
|
+
"type": "object",
|
|
56
|
+
"properties": {
|
|
57
|
+
"head": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"minLength": 1,
|
|
60
|
+
"pattern": "^[^\\r\\n]+$",
|
|
61
|
+
"description": "Opening wrapper emitted before the child-page Markdown link."
|
|
62
|
+
},
|
|
63
|
+
"tail": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"minLength": 1,
|
|
66
|
+
"pattern": "^[^\\r\\n]+$",
|
|
67
|
+
"description": "Closing wrapper emitted after the child-page Markdown link."
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"required": [
|
|
71
|
+
"head",
|
|
72
|
+
"tail"
|
|
73
|
+
],
|
|
74
|
+
"additionalProperties": false
|
|
52
75
|
}
|
|
53
76
|
},
|
|
54
77
|
"additionalProperties": false
|
|
@@ -13,7 +13,7 @@ Create a `version: 1` Noblog YAML file that matches the installed theme, not a g
|
|
|
13
13
|
2. **Inspect the real content contract.** Read collection schemas, Zod/Valibot/TypeScript frontmatter definitions, Markdown layouts, and the code that lists or routes content. For Astro, check both `src/content.config.ts` and `src/content/config.ts`, plus `Astro.glob` or dynamic collection routes. A layout alone is not proof of validation rules.
|
|
14
14
|
3. **Record the contract before writing YAML.** Note required and optional fields, native types, defaults, date handling, collection glob patterns, and which directories produce routes. Distinguish file-based Markdown routes from content collections.
|
|
15
15
|
4. **Confirm Notion property names.** Use names supplied by the user or visible in existing configuration/code. Do not invent custom properties or request credentials. Map logical sources to exact Notion names under `notion.properties`.
|
|
16
|
-
5. **Choose output paths with routing in mind.** `savePath` receives database-post symlinks; `storePath` receives every real Markdown file, including children. Child links target `./<page-id>.md` inside the store and are prefixed by `output.childPageMarker` (default `⸎`, U+2E0E EDITORIAL CORONIS); set it if the theme expects a specific marker. Ensure the theme actually loads/routes the store if child pages must be public. Noblog does not create `nob_children` routes or remove old nested views.
|
|
16
|
+
5. **Choose output paths with routing in mind.** `savePath` receives database-post symlinks; `storePath` receives every real Markdown file, including children. Child links target `./<page-id>.md` inside the store and are prefixed by `output.childPageMarker` (default `⸎`, U+2E0E EDITORIAL CORONIS); set it if the theme expects a specific marker. If the theme expects a wrapper, use `output.childPageWrapper` with non-empty single-line `head`/`tail` values; it overrides the marker. Ensure the theme actually loads/routes the store if child pages must be public. Noblog does not create `nob_children` routes or remove old nested views.
|
|
17
17
|
6. **Write only the fields the theme consumes.** Custom `frontmatter.fields` replaces the legacy field set. Use exactly one of `from` or `value` per field. Keep booleans, numbers, arrays, and objects native unless the theme requires strings.
|
|
18
18
|
7. **Validate without generating.** Run:
|
|
19
19
|
|
|
@@ -31,8 +31,18 @@ output:
|
|
|
31
31
|
| `layoutPath` | `../../layouts/MarkdownPostLayout.astro` | Interpreted relative to `savePath`; Noblog writes the equivalent store-relative import. Override with `--layout`. |
|
|
32
32
|
| `recursive` | `true` | Collect and render child pages recursively. |
|
|
33
33
|
| `childPageMarker` | `⸎` (U+2E0E EDITORIAL CORONIS) | Non-empty prefix added to child-page links. Set it to the marker the theme recognizes. |
|
|
34
|
+
| `childPageWrapper` | — | Optional `{ head, tail }` wrapper around child-page links. Overrides `childPageMarker`. Both values must be non-empty single-line strings. |
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
Optional wrapper (overrides `childPageMarker`):
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
output:
|
|
40
|
+
childPageWrapper:
|
|
41
|
+
head: "<noblog-subpage>"
|
|
42
|
+
tail: "</noblog-subpage>"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
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)` or, when configured, `<head>[title](./<page-id>.md)<tail>`. The theme must load and route the canonical store itself when child pages should have routes.
|
|
36
46
|
|
|
37
47
|
## Notion property mapping
|
|
38
48
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
These examples are snapshots, not substitutes for inspecting the installed theme. The assets contain complete YAML starting points.
|
|
4
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.
|
|
5
|
+
Child-page links are prefixed by `output.childPageMarker`, which defaults to `⸎` (U+2E0E EDITORIAL CORONIS). Set it to the marker the theme recognizes. If the theme expects a wrapper element, configure `output.childPageWrapper` with `head` and `tail`; it overrides the marker.
|
|
6
6
|
|
|
7
7
|
## Nobloger
|
|
8
8
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-CzKR81Or.js","names":["md.toggle","md.callout","md.bullet","md.image","md.divider","md.equation","md.link","md.heading2","md.codeBlock","md.heading1","md.heading3","md.quote","md.todo","md.table"],"sources":["../src/lib/noblog/metadata.ts","../src/lib/noblog/frontmatter.ts","../src/lib/noblog/markdown.ts","../src/lib/noblog/rich-text.ts","../src/lib/noblog/blocks.ts","../src/lib/noblog/pages.ts","../src/lib/noblog/writer.ts","../src/lib/notion/client.ts"],"sourcesContent":["import type { PageObjectResponse } from \"@notionhq/client\";\nimport type { NotionPropertyMap } from \"./config.js\";\n\ntype NotionProperty = PageObjectResponse[\"properties\"][string];\n\nexport type MetadataValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined;\n\nexport interface PageMetadata {\n readonly title: string;\n readonly description?: string | undefined;\n readonly tags: readonly string[];\n readonly publishedAt?: string | undefined;\n readonly archived?: boolean | undefined;\n readonly values: Readonly<Record<string, MetadataValue>>;\n}\n\nconst DEFAULT_PROPERTIES = {\n description: \"description\",\n tags: \"tags\",\n publishedAt: \"date\",\n archived: \"archived\",\n} as const;\n\nexport function extractPageMetadata(\n page: PageObjectResponse,\n properties: NotionPropertyMap = {},\n): PageMetadata {\n const propertyNames = new Map<string, string>(Object.entries(properties));\n for (const [key, name] of Object.entries(DEFAULT_PROPERTIES)) {\n if (!propertyNames.has(key)) propertyNames.set(key, name);\n }\n\n const values: Record<string, MetadataValue> = {};\n if (!propertyNames.has(\"title\")) {\n const titleProperty = Object.values(page.properties).findLast(\n (property) => property.type === \"title\",\n );\n values[\"title\"] = normalizeProperty(titleProperty);\n }\n for (const [key, name] of propertyNames) {\n values[key] = normalizeProperty(page.properties[name]);\n }\n\n return {\n title: asString(values[\"title\"]) ?? \"\",\n description: asString(values[\"description\"]),\n tags: asStringArray(values[\"tags\"]) ?? [],\n publishedAt: asString(values[\"publishedAt\"]),\n archived: asBoolean(values[\"archived\"]),\n values,\n };\n}\n\nfunction normalizeProperty(property?: NotionProperty): MetadataValue {\n if (!property) return undefined;\n\n switch (property.type) {\n case \"title\":\n return plainText(property.title);\n case \"rich_text\":\n return plainText(property.rich_text);\n case \"multi_select\":\n return property.multi_select.map(({ name }) => name);\n case \"select\":\n return property.select?.name;\n case \"status\":\n return property.status?.name;\n case \"checkbox\":\n return property.checkbox;\n case \"number\":\n return property.number ?? undefined;\n case \"date\":\n return property.date?.start;\n case \"url\":\n return property.url ?? undefined;\n case \"email\":\n return property.email ?? undefined;\n case \"phone_number\":\n return property.phone_number ?? undefined;\n case \"people\":\n return property.people.map(entityName);\n case \"relation\":\n return property.relation.map(({ id }) => id);\n case \"files\":\n return property.files.map((file) =>\n \"file\" in file ? file.file.url : file.external.url,\n );\n case \"formula\":\n return normalizeFormula(property.formula);\n case \"created_time\":\n return property.created_time;\n case \"last_edited_time\":\n return property.last_edited_time;\n case \"created_by\":\n return entityName(property.created_by);\n case \"last_edited_by\":\n return entityName(property.last_edited_by);\n case \"unique_id\":\n return property.unique_id.prefix\n ? `${property.unique_id.prefix}-${property.unique_id.number}`\n : String(property.unique_id.number);\n default:\n return undefined;\n }\n}\n\nfunction normalizeFormula(\n formula: Extract<NotionProperty, { type: \"formula\" }>[\"formula\"],\n): MetadataValue {\n switch (formula.type) {\n case \"string\":\n return formula.string ?? undefined;\n case \"number\":\n return formula.number ?? undefined;\n case \"boolean\":\n return formula.boolean ?? undefined;\n case \"date\":\n return formula.date?.start;\n }\n}\n\nfunction plainText(\n richText: Extract<NotionProperty, { type: \"title\" }>[\"title\"],\n): string {\n return richText.map((item) => item.plain_text).join(\"\");\n}\n\nfunction entityName(entity: {\n readonly id: string;\n readonly name?: string | null;\n}): string {\n return entity.name ?? entity.id;\n}\n\nfunction asString(value: MetadataValue): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction asBoolean(value: MetadataValue): boolean | undefined {\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction asStringArray(value: MetadataValue): readonly string[] | undefined {\n if (typeof value === \"string\") return [value];\n return Array.isArray(value) ? value : undefined;\n}\n","import type { PageObjectResponse } from \"@notionhq/client\";\nimport { stringify } from \"yaml\";\nimport type { NotionPropertyMap } from \"./config.js\";\nimport { DEFAULT_LAYOUT_PATH } from \"./defaults.js\";\nimport { extractPageMetadata } from \"./metadata.js\";\nimport type { FrontmatterAdapter, FrontmatterRecord } from \"./types.js\";\n\nexport interface FrontmatterOptions {\n readonly layoutPath?: string;\n readonly propertyMap?: NotionPropertyMap;\n readonly frontmatter?: FrontmatterAdapter;\n readonly isDatabasePage?: boolean;\n}\n\nexport function renderFrontmatter(\n page: PageObjectResponse,\n options: FrontmatterOptions = {},\n): string {\n const { layoutPath = DEFAULT_LAYOUT_PATH } = options;\n if (options.frontmatter) {\n const metadata = extractPageMetadata(page, options.propertyMap);\n const values = options.frontmatter({\n page,\n metadata,\n layoutPath,\n isDatabasePage: options.isDatabasePage ?? true,\n });\n return serializeFrontmatter(values);\n }\n\n let title = \"\";\n let description = \"\";\n let tags: string[] = [];\n let pubDate = \"\";\n let archived = \"\";\n\n for (const [name, property] of Object.entries(page.properties)) {\n switch (property.type) {\n case \"title\":\n title = property.title.map((item) => item.plain_text).join(\"\");\n break;\n case \"multi_select\":\n if (name === \"tags\") {\n tags = property.multi_select.map((tag) => tag.name);\n }\n break;\n case \"date\":\n if (name === \"date\") {\n pubDate =\n property.date?.start ?? new Date().toISOString().slice(0, 10);\n }\n break;\n }\n\n if (name === \"archived\" && property.type === \"checkbox\") {\n archived = property.checkbox ? \"true\" : \"false\";\n }\n if (name === \"description\" && property.type === \"rich_text\") {\n description = property.rich_text\n .map((item) => item.plain_text)\n .join(\"\");\n }\n }\n\n return (\n \"---\\n\" +\n `layout: ${layoutPath}\\n` +\n `title: ${JSON.stringify(title)}\\n` +\n `description: ${JSON.stringify(description)}\\n` +\n `tags: ${JSON.stringify(tags)}\\n` +\n `pubDate: ${JSON.stringify(pubDate)}\\n` +\n `archived: ${JSON.stringify(archived)}\\n` +\n \"---\\n\"\n );\n}\n\nfunction serializeFrontmatter(values: FrontmatterRecord): string {\n if (\n values === null ||\n typeof values !== \"object\" ||\n Array.isArray(values) ||\n (Object.getPrototypeOf(values) !== Object.prototype &&\n Object.getPrototypeOf(values) !== null)\n ) {\n throw new Error(\"Frontmatter adapter must return a plain object\");\n }\n\n const entries = Object.entries(values).filter(\n ([, value]) => value !== undefined,\n );\n if (entries.length === 0) return \"---\\n---\\n\";\n\n const yaml = stringify(Object.fromEntries(entries), {\n aliasDuplicateObjects: false,\n schema: \"yaml-1.1\",\n });\n return `---\\n${yaml}---\\n`;\n}\n","import { markdownTable } from \"markdown-table\";\nimport type { CalloutIcon } from \"./types.js\";\n\nexport const inlineCode = (text: string) => `\\`${text}\\``;\nexport const inlineEquation = (text: string) => `$${text}$`;\nexport const bold = (text: string) => `**${text}**`;\nexport const italic = (text: string) => `_${text}_`;\nexport const strikethrough = (text: string) => `~~${text}~~`;\nexport const underline = (text: string) => `<u>${text}</u>`;\nexport const link = (text: string, href: string) => `[${text}](${href})`;\n\nexport function codeBlock(text: string, language = \"\"): string {\n const normalizedLanguage = language === \"plain text\" ? \"text\" : language;\n return `\\`\\`\\`${normalizedLanguage}\\n${text}\\n\\`\\`\\``;\n}\n\nexport const equation = (text: string) => `$$\\n${text}\\n$$`;\nexport const heading1 = (text: string) => `# ${text}`;\nexport const heading2 = (text: string) => `## ${text}`;\nexport const heading3 = (text: string) => `### ${text}`;\nexport const quote = (text: string) => `> ${text.replace(/\\n/g, \" \\n> \")}`;\n\nexport function callout(text: string, icon?: CalloutIcon): string {\n const emoji = icon?.type === \"emoji\" ? `${icon.emoji} ` : \"\";\n return `> ${emoji}${text.replace(/\\n/g, \" \\n> \")}`;\n}\n\nexport function bullet(text: string, count?: number): string {\n const rendered = text.trim();\n return count === undefined ? `- ${rendered}` : `${count}. ${rendered}`;\n}\n\nexport const todo = (text: string, checked: boolean) =>\n checked ? `- [x] ${text}` : `- [ ] ${text}`;\n\nexport async function image(\n alt: string,\n href: string,\n convertToBase64 = false,\n): Promise<string> {\n if (!convertToBase64 || href.startsWith(\"data:\")) {\n if (href.startsWith(\"data:\")) {\n const base64 = href.split(\",\").pop();\n return ``;\n }\n return ``;\n }\n\n const response = await fetch(href);\n if (!response.ok) {\n throw new Error(\n `Failed to download image: ${response.status} ${response.statusText}`,\n );\n }\n const buffer = await response.arrayBuffer();\n return `.toString(\"base64\")})`;\n}\n\nexport const divider = () => \"---\";\n\nexport function toggle(summary?: string, children?: string): string {\n if (!summary) return children ?? \"\";\n return `<details>\\n<summary>${summary}</summary>\\n${children ?? \"\"}\\n</details>\\n\\n`;\n}\n\nexport function table(cells: string[][], hasColumnHeader = true): string {\n if (hasColumnHeader || cells.length === 0) return markdownTable(cells);\n\n const width = Math.max(...cells.map((row) => row.length));\n if (width === 0) return \"\";\n const emptyHeader = Array.from({ length: width }, () => \"\");\n return markdownTable([emptyHeader, ...cells]);\n}\n","import type { RichTextItemResponse } from \"@notionhq/client\";\nimport { inlineEquation, link } from \"./markdown.js\";\n\ntype AnnotationName = Exclude<\n keyof RichTextItemResponse[\"annotations\"],\n \"color\"\n>;\n\ninterface AnnotationFormat {\n readonly name: AnnotationName;\n readonly open: string;\n readonly close: string;\n}\n\n// Ordered from the outermost marker to the innermost marker. Stable sorting\n// keeps this order when annotations end on the same rich-text segment.\nconst ANNOTATION_FORMATS: readonly AnnotationFormat[] = [\n { name: \"strikethrough\", open: \"~~\", close: \"~~\" },\n { name: \"underline\", open: \"<u>\", close: \"</u>\" },\n { name: \"italic\", open: \"_\", close: \"_\" },\n { name: \"bold\", open: \"**\", close: \"**\" },\n { name: \"code\", open: \"`\", close: \"`\" },\n];\n\nexport function renderPlainText(\n richText: readonly RichTextItemResponse[],\n): string {\n return richText.map((item) => item.plain_text).join(\"\");\n}\n\nexport function renderRichText(\n richText: readonly RichTextItemResponse[],\n): string {\n let rendered = \"\";\n let active: AnnotationFormat[] = [];\n\n for (const [index, item] of richText.entries()) {\n const desired = getAnnotationFormats(richText, index, item);\n let shared = 0;\n while (\n shared < active.length &&\n shared < desired.length &&\n active[shared]?.name === desired[shared]?.name\n ) {\n shared++;\n }\n\n for (const format of active.slice(shared).toReversed()) {\n rendered += format.close;\n }\n for (const format of desired.slice(shared)) {\n rendered += format.open;\n }\n\n rendered += renderContent(item);\n active = desired;\n }\n\n for (const format of active.toReversed()) {\n rendered += format.close;\n }\n return rendered;\n}\n\nfunction getAnnotationFormats(\n richText: readonly RichTextItemResponse[],\n index: number,\n item: RichTextItemResponse,\n): AnnotationFormat[] {\n if (item.type === \"equation\") return [];\n\n return ANNOTATION_FORMATS.filter((format) => item.annotations[format.name])\n .map((format) => ({\n format,\n runEnd: getAnnotationRunEnd(richText, index, format.name),\n }))\n .sort((left, right) => right.runEnd - left.runEnd)\n .map(({ format }) => format);\n}\n\nfunction getAnnotationRunEnd(\n richText: readonly RichTextItemResponse[],\n start: number,\n name: AnnotationName,\n): number {\n let end = start;\n for (const [offset, next] of richText.slice(start + 1).entries()) {\n if (next.type === \"equation\" || !next.annotations[name]) break;\n end = start + offset + 1;\n }\n return end;\n}\n\nfunction renderContent(item: RichTextItemResponse): string {\n if (item.type === \"equation\") {\n return inlineEquation(item.equation.expression);\n }\n return item.href ? link(item.plain_text, item.href) : item.plain_text;\n}\n","import type { BlockObjectResponse } from \"@notionhq/client\";\nimport { DEFAULT_CHILD_PAGE_MARKER } from \"./defaults.js\";\nimport * as md from \"./markdown.js\";\nimport { renderPlainText, renderRichText } from \"./rich-text.js\";\nimport type {\n BlockTransformerContext,\n BlockTransformers,\n NotionReader,\n} from \"./types.js\";\n\nexport interface BlockNode {\n readonly block: BlockObjectResponse;\n readonly children: BlockNode[];\n}\n\nexport interface BlockRenderContext extends BlockTransformerContext {\n readonly childPageMarker?: string;\n readonly transformers?: BlockTransformers;\n}\n\nexport interface RenderedBlocks {\n content: string;\n childPageIds: string[];\n}\n\nexport async function loadBlockTree(\n blockId: string,\n reader: NotionReader,\n ancestors: ReadonlySet<string> = new Set(),\n): Promise<BlockNode[]> {\n if (ancestors.has(blockId)) return [];\n\n const blocks = await reader.getBlockChildren(blockId);\n const childAncestors = new Set(ancestors).add(blockId);\n const nodes: BlockNode[] = [];\n\n for (const block of blocks) {\n if (block.type === \"unsupported\") continue;\n\n const childSourceId = getChildSourceId(block);\n const children =\n childSourceId && !childAncestors.has(childSourceId)\n ? await loadBlockTree(childSourceId, reader, childAncestors)\n : [];\n nodes.push({ block, children });\n }\n\n return nodes;\n}\n\nfunction getChildSourceId(block: BlockObjectResponse): string | undefined {\n if (block.type === \"child_page\" || block.type === \"child_database\") {\n return undefined;\n }\n if (block.type === \"synced_block\") {\n return (\n block.synced_block.synced_from?.block_id ??\n (block.has_children ? block.id : undefined)\n );\n }\n return block.has_children ? block.id : undefined;\n}\n\nexport async function renderBlockTree(\n nodes: readonly BlockNode[],\n context: BlockRenderContext,\n): Promise<RenderedBlocks> {\n const result: RenderedBlocks = { content: \"\", childPageIds: [] };\n let numberedListIndex = 0;\n\n for (const node of nodes) {\n const { block } = node;\n numberedListIndex =\n block.type === \"numbered_list_item\" ? numberedListIndex + 1 : 0;\n\n const children =\n block.type === \"table\"\n ? { content: \"\", childPageIds: [] }\n : await renderBlockTree(node.children, context);\n const content = await renderBlockNode(\n node,\n children.content,\n numberedListIndex || undefined,\n context,\n );\n\n if (block.type === \"toggle\") {\n result.content += content;\n } else {\n const lineWrap = isListBlock(block) ? \"\" : \"\\n\";\n result.content += `${lineWrap}${content}\\n${lineWrap}`;\n if (!containsOwnChildren(block)) {\n result.content += children.content;\n }\n }\n\n if (block.type === \"child_page\") {\n result.childPageIds.push(block.id);\n } else {\n result.childPageIds.push(...children.childPageIds);\n }\n }\n\n return result;\n}\n\nfunction isListBlock(block: BlockObjectResponse): boolean {\n return (\n block.type === \"to_do\" ||\n block.type === \"bulleted_list_item\" ||\n block.type === \"numbered_list_item\"\n );\n}\n\nfunction containsOwnChildren(block: BlockObjectResponse): boolean {\n return (\n block.type === \"child_page\" ||\n block.type === \"callout\" ||\n block.type === \"bulleted_list_item\" ||\n block.type === \"numbered_list_item\" ||\n block.type === \"table\"\n );\n}\n\nfunction transformBlock<K extends BlockObjectResponse[\"type\"]>(\n type: K,\n block: Extract<BlockObjectResponse, { type: NoInfer<K> }>,\n context: BlockRenderContext,\n): string | undefined | Promise<string | undefined> {\n const transformer = context.transformers?.[type];\n return transformer?.(block, context);\n}\n\nasync function renderBlockNode(\n node: BlockNode,\n children: string,\n listNumber: number | undefined,\n context: BlockRenderContext,\n): Promise<string> {\n const { block } = node;\n const transformed = await transformBlock(block.type, block, context);\n const content =\n transformed ??\n (await renderDefaultBlock(\n node,\n context.childPageMarker ?? DEFAULT_CHILD_PAGE_MARKER,\n ));\n\n switch (block.type) {\n case \"toggle\":\n return md.toggle(content, children);\n case \"callout\":\n return md.callout(\n children ? `${content}\\n${children}`.trim() : content,\n block.callout.icon,\n );\n case \"bulleted_list_item\":\n return md.bullet(withIndentedChildren(content, children, 2));\n case \"numbered_list_item\":\n return md.bullet(\n withIndentedChildren(\n content,\n children,\n `${listNumber ?? 1}. `.length,\n ),\n listNumber,\n );\n default:\n return content;\n }\n}\n\nfunction withIndentedChildren(\n content: string,\n children: string,\n markerWidth: number,\n): string {\n const nested = children.trim();\n if (!nested) return content;\n\n const indentation = \" \".repeat(markerWidth);\n const indented = nested\n .split(\"\\n\")\n .map((line) => (line ? `${indentation}${line}` : \"\"))\n .join(\"\\n\");\n return `${content}\\n${indented}`;\n}\n\nasync function renderDefaultBlock(\n node: BlockNode,\n childPageMarker: string,\n): Promise<string> {\n const { block } = node;\n\n switch (block.type) {\n case \"image\": {\n const url = getFileUrl(block.image);\n const caption = renderPlainText(block.image.caption);\n const alt = caption.trim() || getFileName(url) || \"image\";\n return md.image(alt, url);\n }\n case \"divider\":\n return md.divider();\n case \"equation\":\n return md.equation(block.equation.expression);\n case \"pdf\":\n return renderFileLink(block.pdf, block.type);\n case \"file\":\n return renderFileLink(block.file, block.type);\n case \"video\":\n return renderFileLink(block.video, block.type);\n case \"audio\":\n return renderFileLink(block.audio, block.type);\n case \"embed\":\n return md.link(block.type, block.embed.url);\n case \"bookmark\":\n return md.link(block.type, block.bookmark.url);\n case \"link_preview\":\n return md.link(block.type, block.link_preview.url);\n case \"link_to_page\": {\n const target = block.link_to_page;\n if (target.type !== \"page_id\" && target.type !== \"database_id\") {\n return \"\";\n }\n const id = target.type === \"page_id\" ? target.page_id : target.database_id;\n return md.link(block.type, `https://www.notion.so/${id}`);\n }\n case \"child_page\":\n return renderChildPageLink(block, childPageMarker);\n case \"child_database\":\n return md.heading2(block.child_database.title || \"child_database\");\n case \"table\":\n return renderTable(node.children, block.table.has_column_header);\n case \"code\":\n return md.codeBlock(\n renderRichText(block.code.rich_text),\n block.code.language,\n );\n case \"heading_1\":\n return md.heading1(renderRichText(block.heading_1.rich_text));\n case \"heading_2\":\n return md.heading2(renderRichText(block.heading_2.rich_text));\n case \"heading_3\":\n return md.heading3(renderRichText(block.heading_3.rich_text));\n case \"quote\":\n return md.quote(renderRichText(block.quote.rich_text));\n case \"to_do\":\n return md.todo(\n renderRichText(block.to_do.rich_text),\n block.to_do.checked,\n );\n case \"paragraph\":\n return renderRichText(block.paragraph.rich_text);\n case \"toggle\":\n return renderRichText(block.toggle.rich_text);\n case \"callout\":\n return renderRichText(block.callout.rich_text);\n case \"bulleted_list_item\":\n return renderRichText(block.bulleted_list_item.rich_text);\n case \"numbered_list_item\":\n return renderRichText(block.numbered_list_item.rich_text);\n case \"template\":\n return renderRichText(block.template.rich_text);\n default:\n return \"\";\n }\n}\n\ntype FileContent =\n | Extract<BlockObjectResponse, { type: \"image\" }>[\"image\"]\n | Extract<BlockObjectResponse, { type: \"pdf\" }>[\"pdf\"]\n | Extract<BlockObjectResponse, { type: \"file\" }>[\"file\"]\n | Extract<BlockObjectResponse, { type: \"video\" }>[\"video\"]\n | Extract<BlockObjectResponse, { type: \"audio\" }>[\"audio\"];\n\nfunction getFileUrl(content: FileContent): string {\n if (content.type === \"external\") return content.external.url;\n return content.file.url;\n}\n\nfunction getFileName(url: string): string | undefined {\n return url.match(/[^\\/\\\\&?]+\\.\\w{3,4}(?=([?&].*$|$))/)?.[0];\n}\n\nfunction renderFileLink(content: FileContent, fallbackTitle: string): string {\n const url = getFileUrl(content);\n const caption = renderPlainText(content.caption);\n const title = caption.trim() || getFileName(url) || fallbackTitle;\n return md.link(title, url);\n}\n\nfunction renderChildPageLink(\n block: Extract<BlockObjectResponse, { type: \"child_page\" }>,\n marker: string,\n): string {\n // The theme consumes this marker to render child pages as subpage links.\n return `${marker} ${md.link(block.child_page.title, `./${block.id}.md`)}`;\n}\n\nfunction renderTable(\n nodes: readonly BlockNode[],\n hasColumnHeader: boolean,\n): string {\n const rows = nodes.flatMap(({ block }) => {\n if (block.type !== \"table_row\") return [];\n return [\n block.table_row.cells.map((cell) => renderRichText(cell)),\n ];\n });\n return md.table(rows, hasColumnHeader);\n}\n","import type { PageObjectResponse } from \"@notionhq/client\";\nimport { loadBlockTree, renderBlockTree } from \"./blocks.js\";\nimport {\n DEFAULT_CHILD_PAGE_MARKER,\n DEFAULT_LAYOUT_PATH,\n} from \"./defaults.js\";\nimport { renderFrontmatter } from \"./frontmatter.js\";\nimport type { NotionPropertyMap } from \"./config.js\";\nimport type {\n BlockTransformers,\n FrontmatterAdapter,\n NotionReader,\n RenderedPage,\n RenderOptions,\n} from \"./types.js\";\n\ninterface PageRenderContext {\n readonly reader: NotionReader;\n readonly databasePageIds: ReadonlySet<string>;\n readonly layoutPath: string;\n readonly propertyMap: NotionPropertyMap | undefined;\n readonly frontmatter: FrontmatterAdapter | undefined;\n readonly recursive: boolean;\n readonly childPageMarker: string;\n readonly transformers: BlockTransformers | undefined;\n readonly renderedPages: Map<string, Promise<RenderedPage>>;\n}\n\nexport async function renderPage(\n pageId: string,\n reader: NotionReader,\n options: RenderOptions = {},\n): Promise<RenderedPage> {\n const context = createContext([pageId], reader, options);\n return collectPage(pageId, context);\n}\n\nexport async function renderPages(\n posts: readonly PageObjectResponse[],\n reader: NotionReader,\n options: RenderOptions = {},\n): Promise<RenderedPage[]> {\n const context = createContext(\n posts.map((post) => post.id),\n reader,\n options,\n );\n\n for (const post of posts) {\n await collectPage(post.id, context, post);\n }\n\n return Promise.all([...context.renderedPages.values()]);\n}\n\nfunction createContext(\n databasePageIds: readonly string[],\n reader: NotionReader,\n options: RenderOptions,\n): PageRenderContext {\n return {\n reader,\n databasePageIds: new Set(databasePageIds),\n layoutPath: options.layoutPath ?? DEFAULT_LAYOUT_PATH,\n propertyMap: options.propertyMap,\n frontmatter: options.frontmatter,\n recursive: options.recursive ?? true,\n childPageMarker: options.childPageMarker ?? DEFAULT_CHILD_PAGE_MARKER,\n transformers: options.transformers,\n renderedPages: new Map(),\n };\n}\n\nasync function collectPage(\n pageId: string,\n context: PageRenderContext,\n post?: PageObjectResponse,\n): Promise<RenderedPage> {\n const cached = context.renderedPages.get(pageId);\n if (cached) return cached;\n\n const rendering = renderSinglePage(pageId, context, post);\n context.renderedPages.set(pageId, rendering);\n const rendered = await rendering;\n\n if (context.recursive) {\n for (const childPageId of rendered.childPageIds) {\n await collectPage(childPageId, context);\n }\n }\n\n return rendered;\n}\n\nasync function renderSinglePage(\n pageId: string,\n context: PageRenderContext,\n post?: PageObjectResponse,\n): Promise<RenderedPage> {\n const [page, blockTree] = await Promise.all([\n post ? Promise.resolve(post) : context.reader.getPage(pageId),\n loadBlockTree(pageId, context.reader),\n ]);\n const rendered = await renderBlockTree(blockTree, {\n pageId,\n childPageMarker: context.childPageMarker,\n ...(context.transformers !== undefined\n ? { transformers: context.transformers }\n : {}),\n });\n const frontmatter = renderFrontmatter(page, {\n layoutPath: context.layoutPath,\n ...(context.propertyMap !== undefined\n ? { propertyMap: context.propertyMap }\n : {}),\n ...(context.frontmatter !== undefined\n ? { frontmatter: context.frontmatter }\n : {}),\n isDatabasePage: context.databasePageIds.has(pageId),\n });\n\n return {\n id: pageId,\n content: frontmatter + rendered.content,\n childPageIds: [...new Set(rendered.childPageIds)],\n isDatabasePage: context.databasePageIds.has(pageId),\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport {\n lstat,\n mkdir,\n readlink,\n rename,\n rm,\n symlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { getErrorCode } from \"../errors.js\";\nimport {\n DEFAULT_LAYOUT_PATH,\n DEFAULT_SAVE_PATH,\n DEFAULT_STORE_PATH,\n} from \"./defaults.js\";\nimport type {\n RenderedPage,\n StoreLayoutOptions,\n WritePagesOptions,\n} from \"./types.js\";\n\nexport async function writePages(\n pages: readonly RenderedPage[],\n options: WritePagesOptions = {},\n): Promise<string[]> {\n const savePath = options.savePath ?? DEFAULT_SAVE_PATH;\n const storePath = options.storePath ?? DEFAULT_STORE_PATH;\n const writtenPaths: string[] = [];\n await mkdir(storePath, { recursive: true });\n\n for (const page of pages) {\n const storedPath = join(storePath, `${page.id}.md`);\n const storedStats = await getStats(storedPath);\n if (storedStats && !storedStats.isFile()) {\n throw new Error(`Page store path is not a regular file: ${storedPath}`);\n }\n await writeFile(storedPath, page.content, \"utf8\");\n\n if (!page.isDatabasePage) continue;\n\n const viewPath = join(savePath, `${page.id}.md`);\n await mkdir(savePath, { recursive: true });\n await linkStoredPage(storedPath, viewPath);\n writtenPaths.push(viewPath);\n }\n\n return writtenPaths;\n}\n\nexport function resolveStoreLayoutPath(\n options: StoreLayoutOptions = {},\n): string {\n const savePath = options.savePath ?? DEFAULT_SAVE_PATH;\n const storePath = options.storePath ?? DEFAULT_STORE_PATH;\n const layoutPath = options.layoutPath ?? DEFAULT_LAYOUT_PATH;\n const layoutTarget = resolve(savePath, layoutPath);\n return relative(resolve(storePath), layoutTarget).split(sep).join(\"/\");\n}\n\nasync function linkStoredPage(\n storedPath: string,\n viewPath: string,\n): Promise<void> {\n if (resolve(storedPath) === resolve(viewPath)) return;\n\n const viewStats = await getStats(viewPath);\n if (viewStats && !viewStats.isFile() && !viewStats.isSymbolicLink()) {\n throw new Error(`Refusing to replace non-file output: ${viewPath}`);\n }\n\n const target = relative(dirname(viewPath), storedPath);\n if (viewStats?.isSymbolicLink() && (await readlink(viewPath)) === target) {\n return;\n }\n\n const temporaryPath = `${viewPath}.noblog-${randomUUID()}.tmp`;\n try {\n await symlink(target, temporaryPath, \"file\");\n await rename(temporaryPath, viewPath);\n } catch (error) {\n await rm(temporaryPath, { force: true }).catch(() => {});\n throw error;\n }\n}\n\nasync function getStats(path: string) {\n try {\n return await lstat(path);\n } catch (error: unknown) {\n if (getErrorCode(error) === \"ENOENT\") return undefined;\n throw error;\n }\n}\n","import {\n Client,\n isFullBlock,\n isFullDatabase,\n isFullPage,\n isNotionClientError,\n} from \"@notionhq/client\";\nimport type {\n BlockObjectResponse,\n PageObjectResponse,\n} from \"@notionhq/client\";\nimport type { NotionReader } from \"../noblog/types.js\";\n\nexport interface NotionSourceConfig {\n readonly notionApiSecret: string;\n readonly databaseId: string;\n}\n\nexport interface NotionSource extends NotionReader {\n listPages(): Promise<PageObjectResponse[]>;\n}\n\nexport function createNotionSource(\n config: NotionSourceConfig,\n): NotionSource {\n const client = new Client({ auth: config.notionApiSecret });\n return {\n listPages: () => listPages(client, config.databaseId),\n getPage: (pageId) => getPage(client, pageId),\n getBlockChildren: (blockId) => getBlockChildren(client, blockId),\n };\n}\n\nasync function listPages(\n client: Client,\n databaseId: string,\n): Promise<PageObjectResponse[]> {\n const database = await withRetry(() =>\n client.databases.retrieve({ database_id: databaseId }),\n );\n if (!isFullDatabase(database)) {\n throw new Error(`Notion database ${databaseId} is not a full database`);\n }\n\n const pages: PageObjectResponse[] = [];\n for (const source of database.data_sources) {\n let startCursor: string | undefined;\n do {\n const response = await withRetry(() =>\n client.dataSources.query({\n data_source_id: source.id,\n filter: {\n property: \"publish\",\n checkbox: { equals: true },\n },\n sorts: [{ property: \"date\", direction: \"descending\" }],\n page_size: 100,\n ...(startCursor !== undefined\n ? { start_cursor: startCursor }\n : {}),\n }),\n );\n pages.push(...response.results.filter(isFullPage));\n startCursor = response.next_cursor ?? undefined;\n if (!response.has_more) break;\n } while (startCursor);\n }\n\n return pages;\n}\n\nasync function getPage(\n client: Client,\n pageId: string,\n): Promise<PageObjectResponse> {\n const page = await withRetry(() => client.pages.retrieve({ page_id: pageId }));\n if (!isFullPage(page)) {\n throw new Error(`Notion page ${pageId} is not a full page`);\n }\n return page;\n}\n\nasync function getBlockChildren(\n client: Client,\n blockId: string,\n): Promise<BlockObjectResponse[]> {\n const blocks: BlockObjectResponse[] = [];\n let startCursor: string | undefined;\n\n do {\n const response = await withRetry(() =>\n client.blocks.children.list({\n block_id: blockId,\n page_size: 100,\n ...(startCursor !== undefined ? { start_cursor: startCursor } : {}),\n }),\n );\n blocks.push(...response.results.filter(isFullBlock));\n startCursor = response.next_cursor ?? undefined;\n } while (startCursor);\n\n return blocks;\n}\n\nconst MAX_ATTEMPTS = 3;\nconst INITIAL_RETRY_DELAY_MS = 500;\n\nasync function withRetry<T>(operation: () => Promise<T>): Promise<T> {\n for (let attempt = 0; ; attempt++) {\n try {\n return await operation();\n } catch (error: unknown) {\n if (attempt === MAX_ATTEMPTS - 1 || !isRetryable(error)) throw error;\n await delay(INITIAL_RETRY_DELAY_MS * 2 ** attempt);\n }\n }\n}\n\nfunction isRetryable(error: unknown): boolean {\n if (!isNotionClientError(error) || !(\"status\" in error)) return true;\n return error.status === 408 || error.status === 429 || error.status >= 500;\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors-BCRhKbgG.js","names":[],"sources":["../src/lib/noblog/config.ts","../src/lib/errors.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport type ConfigValue =\n | string\n | number\n | boolean\n | null\n | ConfigValue[]\n | { [key: string]: ConfigValue };\n\nconst configValueSchema: z.ZodType<ConfigValue> = z.lazy(() =>\n z.union([\n z.string(),\n z.number().finite(),\n z.boolean(),\n z.null(),\n z.array(configValueSchema),\n z.record(z.string(), configValueSchema),\n ]),\n);\n\nconst fieldModifiers = {\n as: z\n .enum([\"string\", \"date\"])\n .optional()\n .describe(\n \"Convert to a string (quoting date-like strings) or a YAML date.\",\n ),\n default: configValueSchema\n .optional()\n .describe(\"Value used when the source is empty.\"),\n omitEmpty: z\n .boolean()\n .optional()\n .describe(\"Omit undefined, null, empty strings, and empty arrays.\"),\n required: z\n .boolean()\n .optional()\n .describe(\"Fail generation if the value is still empty after defaults.\"),\n};\n\nexport const frontmatterFieldSchema = z.union([\n z.strictObject({\n ...fieldModifiers,\n from: z\n .string()\n .min(1)\n .describe(\"Built-in source or a key declared under notion.properties.\"),\n }),\n z.strictObject({\n ...fieldModifiers,\n value: configValueSchema,\n }),\n]);\n\nexport const frontmatterFieldsSchema = z.record(\n z.string().min(1),\n frontmatterFieldSchema,\n);\n\nexport const notionPropertiesSchema = z.record(\n z.string().min(1),\n z.string().min(1),\n);\n\nexport const BUILT_IN_FRONTMATTER_SOURCES = [\n \"title\",\n \"description\",\n \"tags\",\n \"publishedAt\",\n \"archived\",\n \"layoutPath\",\n \"pageId\",\n \"isDatabasePage\",\n] as const;\n\nconst builtInSources: ReadonlySet<string> = new Set(\n BUILT_IN_FRONTMATTER_SOURCES,\n);\n\nexport const noblogConfigSchema = z\n .strictObject({\n version: z.literal(1),\n notion: z\n .strictObject({\n properties: notionPropertiesSchema.optional(),\n })\n .optional(),\n output: z\n .strictObject({\n savePath: z\n .string()\n .min(1)\n .optional()\n .describe(\"Public directory for database-post symlinks.\"),\n storePath: z\n .string()\n .min(1)\n .optional()\n .describe(\"Flat directory containing every canonical Markdown file.\"),\n layoutPath: z\n .string()\n .min(1)\n .optional()\n .describe(\"Layout import path interpreted relative to savePath.\"),\n recursive: z\n .boolean()\n .optional()\n .describe(\"Render child pages recursively (default: true).\"),\n childPageMarker: z\n .string()\n .min(1)\n .optional()\n .describe(\n \"Marker prefixed to child-page links (default: ⸎, U+2E0E).\",\n ),\n })\n .optional(),\n frontmatter: z\n .strictObject({\n fields: frontmatterFieldsSchema.optional(),\n })\n .optional(),\n })\n .superRefine((config, context) => {\n const properties = config.notion?.properties ?? {};\n for (const [name, field] of Object.entries(\n config.frontmatter?.fields ?? {},\n )) {\n if (!(\"from\" in field)) continue;\n if (\n !builtInSources.has(field.from) &&\n !Object.hasOwn(properties, field.from)\n ) {\n context.addIssue({\n code: \"custom\",\n message: `Unknown frontmatter source \"${field.from}\"; declare it under notion.properties`,\n path: [\"frontmatter\", \"fields\", name, \"from\"],\n });\n }\n }\n })\n .describe(\n \"Noblog YAML configuration. Notion credentials remain in environment variables or .env files.\",\n );\n\nexport type FrontmatterField = z.infer<typeof frontmatterFieldSchema>;\nexport type FrontmatterFields = z.infer<typeof frontmatterFieldsSchema>;\nexport type NotionPropertyMap = z.infer<typeof notionPropertiesSchema>;\nexport type NoblogFileConfig = z.infer<typeof noblogConfigSchema>;\n","export function getErrorCode(error: unknown): string | undefined {\n if (\n typeof error !== \"object\" ||\n error === null ||\n !(\"code\" in error) ||\n typeof error.code !== \"string\"\n ) {\n return undefined;\n }\n return error.code;\n}\n"],"mappings":";;AAUA,MAAM,oBAA4C,EAAE,WAClD,EAAE,MAAM;CACN,EAAE,OAAO;CACT,EAAE,OAAO,CAAC,CAAC,OAAO;CAClB,EAAE,QAAQ;CACV,EAAE,KAAK;CACP,EAAE,MAAM,iBAAiB;CACzB,EAAE,OAAO,EAAE,OAAO,GAAG,iBAAiB;AACxC,CAAC,CACH;AAEA,MAAM,iBAAiB;CACrB,IAAI,EACD,KAAK,CAAC,UAAU,MAAM,CAAC,CAAC,CACxB,SAAS,CAAC,CACV,SACC,iEACF;CACF,SAAS,kBACN,SAAS,CAAC,CACV,SAAS,sCAAsC;CAClD,WAAW,EACR,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SAAS,wDAAwD;CACpE,UAAU,EACP,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SAAS,6DAA6D;AAC3E;AAEA,MAAa,yBAAyB,EAAE,MAAM,CAC5C,EAAE,aAAa;CACb,GAAG;CACH,MAAM,EACH,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,SAAS,4DAA4D;AAC1E,CAAC,GACD,EAAE,aAAa;CACb,GAAG;CACH,OAAO;AACT,CAAC,CACH,CAAC;AAED,MAAa,0BAA0B,EAAE,OACvC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,GAChB,sBACF;AAEA,MAAa,yBAAyB,EAAE,OACtC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,GAChB,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAClB;AAEA,MAAa,+BAA+B;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,iBAAsC,IAAI,IAC9C,4BACF;AAEA,MAAa,qBAAqB,EAC/B,aAAa;CACZ,SAAS,EAAE,QAAQ,CAAC;CACpB,QAAQ,EACL,aAAa,EACZ,YAAY,uBAAuB,SAAS,EAC9C,CAAC,CAAC,CACD,SAAS;CACZ,QAAQ,EACL,aAAa;EACZ,UAAU,EACP,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,SAAS,CAAC,CACV,SAAS,8CAA8C;EAC1D,WAAW,EACR,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,SAAS,CAAC,CACV,SAAS,0DAA0D;EACtE,YAAY,EACT,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,SAAS,CAAC,CACV,SAAS,sDAAsD;EAClE,WAAW,EACR,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SAAS,iDAAiD;EAC7D,iBAAiB,EACd,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,SAAS,CAAC,CACV,SACC,2DACF;CACJ,CAAC,CAAC,CACD,SAAS;CACZ,aAAa,EACV,aAAa,EACZ,QAAQ,wBAAwB,SAAS,EAC3C,CAAC,CAAC,CACD,SAAS;AACd,CAAC,CAAC,CACD,aAAa,QAAQ,YAAY;CAChC,MAAM,aAAa,OAAO,QAAQ,cAAc,CAAC;CACjD,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QACjC,OAAO,aAAa,UAAU,CAAC,CACjC,GAAG;EACD,IAAI,EAAE,UAAU,QAAQ;EACxB,IACE,CAAC,eAAe,IAAI,MAAM,IAAI,KAC9B,CAAC,OAAO,OAAO,YAAY,MAAM,IAAI,GAErC,QAAQ,SAAS;GACf,MAAM;GACN,SAAS,+BAA+B,MAAM,KAAK;GACnD,MAAM;IAAC;IAAe;IAAU;IAAM;GAAM;EAC9C,CAAC;CAEL;AACF,CAAC,CAAC,CACD,SACC,8FACF;;;AChJF,SAAgB,aAAa,OAAoC;CAC/D,IACE,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,UAAU,UACZ,OAAO,MAAM,SAAS,UAEtB;CAEF,OAAO,MAAM;AACf"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"generate.impl-ChFrtwtC.js","names":[],"sources":["../src/commands/generate.impl.ts"],"sourcesContent":["import { ConfigurationError, loadConfig } from \"../config.js\";\nimport { loadNoblogConfig } from \"../config-file.js\";\nimport type { CliContext } from \"../context.js\";\nimport {\n DEFAULT_CHILD_PAGE_MARKER,\n DEFAULT_LAYOUT_PATH,\n DEFAULT_SAVE_PATH,\n DEFAULT_STORE_PATH,\n} from \"../lib/noblog/defaults.js\";\nimport {\n createFrontmatterAdapter,\n DEFAULT_FRONTMATTER_FIELDS,\n} from \"../lib/noblog/frontmatter-fields.js\";\n\ninterface GenerateFlags {\n verbose: boolean;\n config?: string;\n layout?: string;\n store?: string;\n}\n\nexport default async function generate(\n this: CliContext,\n flags: GenerateFlags,\n savePath?: string,\n legacySubPath?: string,\n): Promise<Error | void> {\n try {\n const fileConfig = flags.config\n ? await loadNoblogConfig(flags.config)\n : undefined;\n const config = loadConfig(this.process.env);\n if (legacySubPath !== undefined) {\n this.process.stderr.write(\n \"Warning: SUB_PATH is deprecated and ignored; child pages now live only in the canonical store.\\n\",\n );\n }\n\n const propertyMap = fileConfig?.notion?.properties;\n const fields = fileConfig?.frontmatter?.fields;\n const frontmatter =\n fields || propertyMap\n ? createFrontmatterAdapter(fields ?? DEFAULT_FRONTMATTER_FIELDS)\n : undefined;\n\n await this.generateBlog(\n config,\n {\n savePath:\n savePath ?? fileConfig?.output?.savePath ?? DEFAULT_SAVE_PATH,\n storePath:\n flags.store ?? fileConfig?.output?.storePath ?? DEFAULT_STORE_PATH,\n layoutPath:\n flags.layout ?? fileConfig?.output?.layoutPath ?? DEFAULT_LAYOUT_PATH,\n recursive: fileConfig?.output?.recursive ?? true,\n childPageMarker:\n fileConfig?.output?.childPageMarker ?? DEFAULT_CHILD_PAGE_MARKER,\n ...(propertyMap !== undefined ? { propertyMap } : {}),\n ...(frontmatter !== undefined ? { frontmatter } : {}),\n verbose: flags.verbose,\n },\n this.process,\n );\n } catch (error) {\n if (error instanceof ConfigurationError) {\n return error;\n }\n if (!(error instanceof Error)) {\n return new Error(\"Generation failed: an unknown error occurred\");\n }\n\n const message = flags.verbose\n ? (error.stack ?? error.message)\n : error.message;\n return new Error(`Generation failed: ${message}`, { cause: error });\n }\n}\n"],"mappings":";;;;;AAqBA,eAA8B,SAE5B,OACA,UACA,eACuB;CACvB,IAAI;EACF,MAAM,aAAa,MAAM,SACrB,MAAM,iBAAiB,MAAM,MAAM,IACnC,KAAA;EACJ,MAAM,SAAS,WAAW,KAAK,QAAQ,GAAG;EAC1C,IAAI,kBAAkB,KAAA,GACpB,KAAK,QAAQ,OAAO,MAClB,kGACF;EAGF,MAAM,cAAc,YAAY,QAAQ;EACxC,MAAM,SAAS,YAAY,aAAa;EACxC,MAAM,cACJ,UAAU,cACN,yBAAyB,UAAU,0BAA0B,IAC7D,KAAA;EAEN,MAAM,KAAK,aACT,QACA;GACE,UACE,YAAY,YAAY,QAAQ,YAAA;GAClC,WACE,MAAM,SAAS,YAAY,QAAQ,aAAA;GACrC,YACE,MAAM,UAAU,YAAY,QAAQ,cAAA;GACtC,WAAW,YAAY,QAAQ,aAAa;GAC5C,iBACE,YAAY,QAAQ,mBAAA;GACtB,GAAI,gBAAgB,KAAA,IAAY,EAAE,YAAY,IAAI,CAAC;GACnD,GAAI,gBAAgB,KAAA,IAAY,EAAE,YAAY,IAAI,CAAC;GACnD,SAAS,MAAM;EACjB,GACA,KAAK,OACP;CACF,SAAS,OAAO;EACd,IAAI,iBAAiB,oBACnB,OAAO;EAET,IAAI,EAAE,iBAAiB,QACrB,uBAAO,IAAI,MAAM,8CAA8C;EAGjE,MAAM,UAAU,MAAM,UACjB,MAAM,SAAS,MAAM,UACtB,MAAM;EACV,OAAO,IAAI,MAAM,sBAAsB,WAAW,EAAE,OAAO,MAAM,CAAC;CACpE;AACF"}
|