noblog 0.3.0-beta.1 → 0.3.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/{client-CkOIgSvW.js → client-CzKR81Or.js} +10 -8
- package/dist/client-CzKR81Or.js.map +1 -0
- package/dist/{config-check.impl-BQvIrgNe.js → config-check.impl-C5FM7uWi.js} +2 -2
- package/dist/{config-check.impl-BQvIrgNe.js.map → config-check.impl-C5FM7uWi.js.map} +1 -1
- package/dist/{config-file-BF0G2iJq.js → config-file-C07nmm45.js} +2 -2
- package/dist/{config-file-BF0G2iJq.js.map → config-file-C07nmm45.js.map} +1 -1
- package/dist/defaults-RGOB9tfi.js +10 -0
- package/dist/defaults-RGOB9tfi.js.map +1 -0
- package/dist/{errors-DgJ15MsB.js → errors-BCRhKbgG.js} +3 -2
- package/dist/errors-BCRhKbgG.js.map +1 -0
- package/dist/{generate.impl-BKu-Ix4a.js → generate.impl-ChFrtwtC.js} +4 -3
- package/dist/generate.impl-ChFrtwtC.js.map +1 -0
- package/dist/generate.js +5 -4
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +4 -4
- package/package.json +1 -1
- package/schema/config.json +5 -0
- package/skills/noblog-config/SKILL.md +1 -1
- package/skills/noblog-config/references/config-schema.md +3 -1
- package/skills/noblog-config/references/theme-examples.md +2 -0
- package/dist/client-CkOIgSvW.js.map +0 -1
- package/dist/defaults-D9BbNYsd.js +0 -8
- package/dist/defaults-D9BbNYsd.js.map +0 -1
- package/dist/errors-DgJ15MsB.js.map +0 -1
- package/dist/generate.impl-BKu-Ix4a.js.map +0 -1
package/README.md
CHANGED
|
@@ -129,6 +129,7 @@ output:
|
|
|
129
129
|
storePath: .noblog/pages/
|
|
130
130
|
layoutPath: ../../layouts/MarkdownPostLayout.astro
|
|
131
131
|
recursive: true
|
|
132
|
+
childPageMarker: "⸎"
|
|
132
133
|
frontmatter:
|
|
133
134
|
fields:
|
|
134
135
|
title:
|
|
@@ -151,6 +152,8 @@ frontmatter:
|
|
|
151
152
|
value: true
|
|
152
153
|
```
|
|
153
154
|
|
|
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
|
+
|
|
154
157
|
The keys under `notion.properties` are logical source names; their values must exactly match Notion property names. Custom sources such as `series` must be declared there before frontmatter can reference them. Built-in sources need no declaration.
|
|
155
158
|
|
|
156
159
|
Validate a file without Notion credentials, a Notion client, or network access:
|
|
@@ -185,7 +188,7 @@ project-root/
|
|
|
185
188
|
└── <database-page-id>.md # relative symlink
|
|
186
189
|
```
|
|
187
190
|
|
|
188
|
-
Only database posts receive public views. Child pages live exclusively in the canonical store, and child links
|
|
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.
|
|
189
192
|
|
|
190
193
|
**Routing migration:** Noblog no longer creates `/nob_children/` routes. Configure the theme to load and route child pages from `.noblog/pages/` (or the custom store). Existing nested view files are not deleted; remove or redirect them separately after updating the theme. Existing `SUB_PATH` arguments are ignored with a warning.
|
|
191
194
|
|
|
@@ -269,7 +272,7 @@ const pages = await renderPages(posts, notion, { layoutPath });
|
|
|
269
272
|
await writePages(pages, { savePath, storePath });
|
|
270
273
|
```
|
|
271
274
|
|
|
272
|
-
`renderPages` recursively collects child pages by default and returns complete Markdown documents with frontmatter. Set `recursive: false` to render only the supplied database pages. `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.
|
|
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.
|
|
273
276
|
|
|
274
277
|
Use `renderPage` for a single page, or supply any implementation of the `NotionReader` interface instead of the built-in adapter. Lower-level helpers such as `renderRichText` and `renderFrontmatter` are exported as well. To customize a block, pass a `transformers` map in `RenderOptions`; return a string to override the default renderer or `undefined` to fall back to it. Each key narrows its handler's block payload to the corresponding Notion block type, so a `paragraph` transformer can access `block.paragraph` directly. The programmatic API does not load `.env`; load environment variables yourself or pass explicit configuration.
|
|
275
278
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as getErrorCode } from "./errors-
|
|
2
|
-
import {
|
|
1
|
+
import { t as getErrorCode } from "./errors-BCRhKbgG.js";
|
|
2
|
+
import { n as DEFAULT_LAYOUT_PATH } from "./defaults-RGOB9tfi.js";
|
|
3
3
|
import { stringify } from "yaml";
|
|
4
4
|
import { markdownTable } from "markdown-table";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
@@ -296,7 +296,7 @@ function transformBlock(type, block, context) {
|
|
|
296
296
|
}
|
|
297
297
|
async function renderBlockNode(node, children, listNumber, context) {
|
|
298
298
|
const { block } = node;
|
|
299
|
-
const content = await transformBlock(block.type, block, context) ?? await renderDefaultBlock(node);
|
|
299
|
+
const content = await transformBlock(block.type, block, context) ?? await renderDefaultBlock(node, context.childPageMarker ?? "⸎");
|
|
300
300
|
switch (block.type) {
|
|
301
301
|
case "toggle": return toggle(content, children);
|
|
302
302
|
case "callout": return callout(children ? `${content}\n${children}`.trim() : content, block.callout.icon);
|
|
@@ -311,7 +311,7 @@ function withIndentedChildren(content, children, markerWidth) {
|
|
|
311
311
|
const indentation = " ".repeat(markerWidth);
|
|
312
312
|
return `${content}\n${nested.split("\n").map((line) => line ? `${indentation}${line}` : "").join("\n")}`;
|
|
313
313
|
}
|
|
314
|
-
async function renderDefaultBlock(node) {
|
|
314
|
+
async function renderDefaultBlock(node, childPageMarker) {
|
|
315
315
|
const { block } = node;
|
|
316
316
|
switch (block.type) {
|
|
317
317
|
case "image": {
|
|
@@ -333,7 +333,7 @@ async function renderDefaultBlock(node) {
|
|
|
333
333
|
const id = target.type === "page_id" ? target.page_id : target.database_id;
|
|
334
334
|
return link(block.type, `https://www.notion.so/${id}`);
|
|
335
335
|
}
|
|
336
|
-
case "child_page": return renderChildPageLink(block);
|
|
336
|
+
case "child_page": return renderChildPageLink(block, childPageMarker);
|
|
337
337
|
case "child_database": return heading2(block.child_database.title || "child_database");
|
|
338
338
|
case "table": return renderTable(node.children, block.table.has_column_header);
|
|
339
339
|
case "code": return codeBlock(renderRichText(block.code.rich_text), block.code.language);
|
|
@@ -363,8 +363,8 @@ function renderFileLink(content, fallbackTitle) {
|
|
|
363
363
|
const title = renderPlainText(content.caption).trim() || getFileName(url) || fallbackTitle;
|
|
364
364
|
return link(title, url);
|
|
365
365
|
}
|
|
366
|
-
function renderChildPageLink(block) {
|
|
367
|
-
return
|
|
366
|
+
function renderChildPageLink(block, marker) {
|
|
367
|
+
return `${marker} ${link(block.child_page.title, `./${block.id}.md`)}`;
|
|
368
368
|
}
|
|
369
369
|
function renderTable(nodes, hasColumnHeader) {
|
|
370
370
|
return table(nodes.flatMap(({ block }) => {
|
|
@@ -390,6 +390,7 @@ function createContext(databasePageIds, reader, options) {
|
|
|
390
390
|
propertyMap: options.propertyMap,
|
|
391
391
|
frontmatter: options.frontmatter,
|
|
392
392
|
recursive: options.recursive ?? true,
|
|
393
|
+
childPageMarker: options.childPageMarker ?? "⸎",
|
|
393
394
|
transformers: options.transformers,
|
|
394
395
|
renderedPages: /* @__PURE__ */ new Map()
|
|
395
396
|
};
|
|
@@ -407,6 +408,7 @@ async function renderSinglePage(pageId, context, post) {
|
|
|
407
408
|
const [page, blockTree] = await Promise.all([post ? Promise.resolve(post) : context.reader.getPage(pageId), loadBlockTree(pageId, context.reader)]);
|
|
408
409
|
const rendered = await renderBlockTree(blockTree, {
|
|
409
410
|
pageId,
|
|
411
|
+
childPageMarker: context.childPageMarker,
|
|
410
412
|
...context.transformers !== void 0 ? { transformers: context.transformers } : {}
|
|
411
413
|
});
|
|
412
414
|
return {
|
|
@@ -546,4 +548,4 @@ function delay(milliseconds) {
|
|
|
546
548
|
//#endregion
|
|
547
549
|
export { strikethrough as C, underline as D, toggle as E, renderFrontmatter as O, quote as S, todo as T, image as _, renderPages as a, italic as b, bold as c, codeBlock as d, divider as f, heading3 as g, heading2 as h, renderPage as i, extractPageMetadata 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, inlineCode as v, table as w, link as x, inlineEquation as y };
|
|
548
550
|
|
|
549
|
-
//# sourceMappingURL=client-
|
|
551
|
+
//# sourceMappingURL=client-CzKR81Or.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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,4 +1,4 @@
|
|
|
1
|
-
import { t as loadNoblogConfig } from "./config-file-
|
|
1
|
+
import { t as loadNoblogConfig } from "./config-file-C07nmm45.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-C5FM7uWi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-check.impl-
|
|
1
|
+
{"version":3,"file":"config-check.impl-C5FM7uWi.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-BCRhKbgG.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-C07nmm45.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-file-
|
|
1
|
+
{"version":3,"file":"config-file-C07nmm45.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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/lib/noblog/defaults.ts
|
|
2
|
+
const DEFAULT_SAVE_PATH = "./src/pages/posts/";
|
|
3
|
+
const DEFAULT_STORE_PATH = ".noblog/pages/";
|
|
4
|
+
const DEFAULT_LAYOUT_PATH = "../../layouts/MarkdownPostLayout.astro";
|
|
5
|
+
/** U+2E0E EDITORIAL CORONIS, a rare marker for theme child-page links. */
|
|
6
|
+
const DEFAULT_CHILD_PAGE_MARKER = "⸎";
|
|
7
|
+
//#endregion
|
|
8
|
+
export { DEFAULT_STORE_PATH as i, DEFAULT_LAYOUT_PATH as n, DEFAULT_SAVE_PATH as r, DEFAULT_CHILD_PAGE_MARKER as t };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=defaults-RGOB9tfi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults-RGOB9tfi.js","names":[],"sources":["../src/lib/noblog/defaults.ts"],"sourcesContent":["export const DEFAULT_SAVE_PATH = \"./src/pages/posts/\";\nexport const DEFAULT_STORE_PATH = \".noblog/pages/\";\nexport const DEFAULT_LAYOUT_PATH = \"../../layouts/MarkdownPostLayout.astro\";\n\n/** U+2E0E EDITORIAL CORONIS, a rare marker for theme child-page links. */\nexport const DEFAULT_CHILD_PAGE_MARKER = \"⸎\";\n"],"mappings":";AAAA,MAAa,oBAAoB;AACjC,MAAa,qBAAqB;AAClC,MAAa,sBAAsB;;AAGnC,MAAa,4BAA4B"}
|
|
@@ -41,7 +41,8 @@ const noblogConfigSchema = z.strictObject({
|
|
|
41
41
|
savePath: z.string().min(1).optional().describe("Public directory for database-post symlinks."),
|
|
42
42
|
storePath: z.string().min(1).optional().describe("Flat directory containing every canonical Markdown file."),
|
|
43
43
|
layoutPath: z.string().min(1).optional().describe("Layout import path interpreted relative to savePath."),
|
|
44
|
-
recursive: z.boolean().optional().describe("Render child pages recursively (default: true).")
|
|
44
|
+
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).")
|
|
45
46
|
}).optional(),
|
|
46
47
|
frontmatter: z.strictObject({ fields: frontmatterFieldsSchema.optional() }).optional()
|
|
47
48
|
}).superRefine((config, context) => {
|
|
@@ -69,4 +70,4 @@ function getErrorCode(error) {
|
|
|
69
70
|
//#endregion
|
|
70
71
|
export { noblogConfigSchema as a, frontmatterFieldsSchema as i, BUILT_IN_FRONTMATTER_SOURCES as n, notionPropertiesSchema as o, frontmatterFieldSchema as r, getErrorCode as t };
|
|
71
72
|
|
|
72
|
-
//# sourceMappingURL=errors-
|
|
73
|
+
//# sourceMappingURL=errors-BCRhKbgG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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,7 +1,7 @@
|
|
|
1
1
|
import { n as loadConfig, t as ConfigurationError } from "./config-csbquMhF.js";
|
|
2
|
-
import "./defaults-
|
|
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-C07nmm45.js";
|
|
5
5
|
//#region src/commands/generate.impl.ts
|
|
6
6
|
async function generate(flags, savePath, legacySubPath) {
|
|
7
7
|
try {
|
|
@@ -16,6 +16,7 @@ async function generate(flags, savePath, legacySubPath) {
|
|
|
16
16
|
storePath: flags.store ?? fileConfig?.output?.storePath ?? ".noblog/pages/",
|
|
17
17
|
layoutPath: flags.layout ?? fileConfig?.output?.layoutPath ?? "../../layouts/MarkdownPostLayout.astro",
|
|
18
18
|
recursive: fileConfig?.output?.recursive ?? true,
|
|
19
|
+
childPageMarker: fileConfig?.output?.childPageMarker ?? "⸎",
|
|
19
20
|
...propertyMap !== void 0 ? { propertyMap } : {},
|
|
20
21
|
...frontmatter !== void 0 ? { frontmatter } : {},
|
|
21
22
|
verbose: flags.verbose
|
|
@@ -30,4 +31,4 @@ async function generate(flags, savePath, legacySubPath) {
|
|
|
30
31
|
//#endregion
|
|
31
32
|
export { generate as default };
|
|
32
33
|
|
|
33
|
-
//# sourceMappingURL=generate.impl-
|
|
34
|
+
//# sourceMappingURL=generate.impl-ChFrtwtC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
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-CzKR81Or.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-C5FM7uWi.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-ChFrtwtC.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.2` },
|
|
102
102
|
alias: false
|
|
103
103
|
})
|
|
104
104
|
});
|
|
@@ -161,6 +161,7 @@ async function generateBlog(config, options, output) {
|
|
|
161
161
|
await writePages(await renderPages(posts, notion, {
|
|
162
162
|
layoutPath: storeLayoutPath,
|
|
163
163
|
recursive: options.recursive,
|
|
164
|
+
childPageMarker: options.childPageMarker,
|
|
164
165
|
...options.propertyMap !== void 0 ? { propertyMap: options.propertyMap } : {},
|
|
165
166
|
...options.frontmatter !== void 0 ? { frontmatter: options.frontmatter } : {}
|
|
166
167
|
}), {
|
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 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 ...(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 { 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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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ declare const noblogConfigSchema: z.ZodObject<{
|
|
|
55
55
|
storePath: z.ZodOptional<z.ZodString>;
|
|
56
56
|
layoutPath: z.ZodOptional<z.ZodString>;
|
|
57
57
|
recursive: z.ZodOptional<z.ZodBoolean>;
|
|
58
|
+
childPageMarker: z.ZodOptional<z.ZodString>;
|
|
58
59
|
}, z.core.$strict>>;
|
|
59
60
|
frontmatter: z.ZodOptional<z.ZodObject<{
|
|
60
61
|
fields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -87,6 +88,8 @@ type NoblogFileConfig = z.infer<typeof noblogConfigSchema>;
|
|
|
87
88
|
declare const DEFAULT_SAVE_PATH = "./src/pages/posts/";
|
|
88
89
|
declare const DEFAULT_STORE_PATH = ".noblog/pages/";
|
|
89
90
|
declare const DEFAULT_LAYOUT_PATH = "../../layouts/MarkdownPostLayout.astro";
|
|
91
|
+
/** U+2E0E EDITORIAL CORONIS, a rare marker for theme child-page links. */
|
|
92
|
+
declare const DEFAULT_CHILD_PAGE_MARKER = "\u2E0E";
|
|
90
93
|
//#endregion
|
|
91
94
|
//#region src/lib/noblog/metadata.d.ts
|
|
92
95
|
type MetadataValue = string | number | boolean | readonly string[] | undefined;
|
|
@@ -129,6 +132,7 @@ type BlockTransformers = { readonly [K in BlockObjectResponse["type"]]?: BlockTr
|
|
|
129
132
|
interface RenderOptions {
|
|
130
133
|
readonly layoutPath?: string;
|
|
131
134
|
readonly recursive?: boolean;
|
|
135
|
+
readonly childPageMarker?: string;
|
|
132
136
|
readonly propertyMap?: NotionPropertyMap;
|
|
133
137
|
readonly frontmatter?: FrontmatterAdapter;
|
|
134
138
|
readonly transformers?: BlockTransformers;
|
|
@@ -206,5 +210,5 @@ interface NotionSource extends NotionReader {
|
|
|
206
210
|
}
|
|
207
211
|
declare function createNotionSource(config: NotionSourceConfig): NotionSource;
|
|
208
212
|
//#endregion
|
|
209
|
-
export { BUILT_IN_FRONTMATTER_SOURCES, BlockTransformer, BlockTransformerContext, BlockTransformers, CalloutIcon, ConfigValue, 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 };
|
|
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 };
|
|
210
214
|
//# 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-
|
|
2
|
-
import { n as
|
|
3
|
-
import { C as strikethrough, D as underline, E as toggle, O as renderFrontmatter, S as quote, T as todo, _ as image, a as renderPages, b as italic, c as bold, d as codeBlock, f as divider, g as heading3, h as heading2, i as renderPage, k as extractPageMetadata, 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 inlineCode, w as table, x as link, y as inlineEquation } from "./client-
|
|
1
|
+
import { a as noblogConfigSchema, i as frontmatterFieldsSchema, n as BUILT_IN_FRONTMATTER_SOURCES, o as notionPropertiesSchema, r as frontmatterFieldSchema } from "./errors-BCRhKbgG.js";
|
|
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 strikethrough, D as underline, E as toggle, O as renderFrontmatter, S as quote, T as todo, _ as image, a as renderPages, b as italic, c as bold, d as codeBlock, f as divider, g as heading3, h as heading2, i as renderPage, k as extractPageMetadata, 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 inlineCode, w as table, x as link, y as inlineEquation } from "./client-CzKR81Or.js";
|
|
4
4
|
import { n as createFrontmatterAdapter, t as DEFAULT_FRONTMATTER_FIELDS } from "./frontmatter-fields-BkXq38CO.js";
|
|
5
|
-
export { BUILT_IN_FRONTMATTER_SOURCES, 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, 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
|
@@ -44,6 +44,11 @@
|
|
|
44
44
|
"recursive": {
|
|
45
45
|
"description": "Render child pages recursively (default: true).",
|
|
46
46
|
"type": "boolean"
|
|
47
|
+
},
|
|
48
|
+
"childPageMarker": {
|
|
49
|
+
"description": "Marker prefixed to child-page links (default: ⸎, U+2E0E).",
|
|
50
|
+
"type": "string",
|
|
51
|
+
"minLength": 1
|
|
47
52
|
}
|
|
48
53
|
},
|
|
49
54
|
"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. 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. 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
|
|
|
@@ -21,6 +21,7 @@ output:
|
|
|
21
21
|
storePath: .noblog/pages/
|
|
22
22
|
layoutPath: ../../layouts/MarkdownPostLayout.astro
|
|
23
23
|
recursive: true
|
|
24
|
+
childPageMarker: "⸎"
|
|
24
25
|
```
|
|
25
26
|
|
|
26
27
|
| Key | Default | Meaning |
|
|
@@ -29,8 +30,9 @@ output:
|
|
|
29
30
|
| `storePath` | `.noblog/pages/` | Receives every real Markdown file in a flat page-ID layout. Override with `--store`. |
|
|
30
31
|
| `layoutPath` | `../../layouts/MarkdownPostLayout.astro` | Interpreted relative to `savePath`; Noblog writes the equivalent store-relative import. Override with `--layout`. |
|
|
31
32
|
| `recursive` | `true` | Collect and render child pages recursively. |
|
|
33
|
+
| `childPageMarker` | `⸎` (U+2E0E EDITORIAL CORONIS) | Non-empty prefix added to child-page links. Set it to the marker the theme recognizes. |
|
|
32
34
|
|
|
33
|
-
All paths are resolved from the generation working directory. Child pages have no public symlinks. The theme must load and route the canonical store itself when child pages should have routes.
|
|
35
|
+
All paths are resolved from the generation working directory. Child pages have no public symlinks. Child-page links are written as `<marker> [title](./<page-id>.md)`. The theme must load and route the canonical store itself when child pages should have routes.
|
|
34
36
|
|
|
35
37
|
## Notion property mapping
|
|
36
38
|
|
|
@@ -2,6 +2,8 @@
|
|
|
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.
|
|
6
|
+
|
|
5
7
|
## Nobloger
|
|
6
8
|
|
|
7
9
|
Evidence inspected: `src/layouts/MarkdownPostLayout.astro` and `src/pages/blog/index.astro` in [humbornjo/nobloger](https://github.com/humbornjo/nobloger).
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-CkOIgSvW.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 * 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 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 = transformed ?? (await renderDefaultBlock(node));\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(node: BlockNode): 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);\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): string {\n return `(」゚ロ゚)」 ${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 { DEFAULT_LAYOUT_PATH } 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 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 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 ...(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":";;;;;;;;;AAqBA,MAAM,qBAAqB;CACzB,aAAa;CACb,MAAM;CACN,aAAa;CACb,UAAU;AACZ;AAEA,SAAgB,oBACd,MACA,aAAgC,CAAC,GACnB;CACd,MAAM,gBAAgB,IAAI,IAAoB,OAAO,QAAQ,UAAU,CAAC;CACxE,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,kBAAkB,GACzD,IAAI,CAAC,cAAc,IAAI,GAAG,GAAG,cAAc,IAAI,KAAK,IAAI;CAG1D,MAAM,SAAwC,CAAC;CAC/C,IAAI,CAAC,cAAc,IAAI,OAAO,GAI5B,OAAO,WAAW,kBAHI,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,UAClD,aAAa,SAAS,SAAS,OAEc,CAAC;CAEnD,KAAK,MAAM,CAAC,KAAK,SAAS,eACxB,OAAO,OAAO,kBAAkB,KAAK,WAAW,KAAK;CAGvD,OAAO;EACL,OAAO,SAAS,OAAO,QAAQ,KAAK;EACpC,aAAa,SAAS,OAAO,cAAc;EAC3C,MAAM,cAAc,OAAO,OAAO,KAAK,CAAC;EACxC,aAAa,SAAS,OAAO,cAAc;EAC3C,UAAU,UAAU,OAAO,WAAW;EACtC;CACF;AACF;AAEA,SAAS,kBAAkB,UAA0C;CACnE,IAAI,CAAC,UAAU,OAAO,KAAA;CAEtB,QAAQ,SAAS,MAAjB;EACE,KAAK,SACH,OAAO,UAAU,SAAS,KAAK;EACjC,KAAK,aACH,OAAO,UAAU,SAAS,SAAS;EACrC,KAAK,gBACH,OAAO,SAAS,aAAa,KAAK,EAAE,WAAW,IAAI;EACrD,KAAK,UACH,OAAO,SAAS,QAAQ;EAC1B,KAAK,UACH,OAAO,SAAS,QAAQ;EAC1B,KAAK,YACH,OAAO,SAAS;EAClB,KAAK,UACH,OAAO,SAAS,UAAU,KAAA;EAC5B,KAAK,QACH,OAAO,SAAS,MAAM;EACxB,KAAK,OACH,OAAO,SAAS,OAAO,KAAA;EACzB,KAAK,SACH,OAAO,SAAS,SAAS,KAAA;EAC3B,KAAK,gBACH,OAAO,SAAS,gBAAgB,KAAA;EAClC,KAAK,UACH,OAAO,SAAS,OAAO,IAAI,UAAU;EACvC,KAAK,YACH,OAAO,SAAS,SAAS,KAAK,EAAE,SAAS,EAAE;EAC7C,KAAK,SACH,OAAO,SAAS,MAAM,KAAK,SACzB,UAAU,OAAO,KAAK,KAAK,MAAM,KAAK,SAAS,GACjD;EACF,KAAK,WACH,OAAO,iBAAiB,SAAS,OAAO;EAC1C,KAAK,gBACH,OAAO,SAAS;EAClB,KAAK,oBACH,OAAO,SAAS;EAClB,KAAK,cACH,OAAO,WAAW,SAAS,UAAU;EACvC,KAAK,kBACH,OAAO,WAAW,SAAS,cAAc;EAC3C,KAAK,aACH,OAAO,SAAS,UAAU,SACtB,GAAG,SAAS,UAAU,OAAO,GAAG,SAAS,UAAU,WACnD,OAAO,SAAS,UAAU,MAAM;EACtC,SACE;CACJ;AACF;AAEA,SAAS,iBACP,SACe;CACf,QAAQ,QAAQ,MAAhB;EACE,KAAK,UACH,OAAO,QAAQ,UAAU,KAAA;EAC3B,KAAK,UACH,OAAO,QAAQ,UAAU,KAAA;EAC3B,KAAK,WACH,OAAO,QAAQ,WAAW,KAAA;EAC5B,KAAK,QACH,OAAO,QAAQ,MAAM;CACzB;AACF;AAEA,SAAS,UACP,UACQ;CACR,OAAO,SAAS,KAAK,SAAS,KAAK,UAAU,CAAC,CAAC,KAAK,EAAE;AACxD;AAEA,SAAS,WAAW,QAGT;CACT,OAAO,OAAO,QAAQ,OAAO;AAC/B;AAEA,SAAS,SAAS,OAA0C;CAC1D,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;AAC7C;AAEA,SAAS,UAAU,OAA2C;CAC5D,OAAO,OAAO,UAAU,YAAY,QAAQ,KAAA;AAC9C;AAEA,SAAS,cAAc,OAAqD;CAC1E,IAAI,OAAO,UAAU,UAAU,OAAO,CAAC,KAAK;CAC5C,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,KAAA;AACxC;;;ACxIA,SAAgB,kBACd,MACA,UAA8B,CAAC,GACvB;CACR,MAAM,EAAE,aAAa,wBAAwB;CAC7C,IAAI,QAAQ,aAAa;EACvB,MAAM,WAAW,oBAAoB,MAAM,QAAQ,WAAW;EAO9D,OAAO,qBANQ,QAAQ,YAAY;GACjC;GACA;GACA;GACA,gBAAgB,QAAQ,kBAAkB;EAC5C,CACiC,CAAC;CACpC;CAEA,IAAI,QAAQ;CACZ,IAAI,cAAc;CAClB,IAAI,OAAiB,CAAC;CACtB,IAAI,UAAU;CACd,IAAI,WAAW;CAEf,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,KAAK,UAAU,GAAG;EAC9D,QAAQ,SAAS,MAAjB;GACE,KAAK;IACH,QAAQ,SAAS,MAAM,KAAK,SAAS,KAAK,UAAU,CAAC,CAAC,KAAK,EAAE;IAC7D;GACF,KAAK;IACH,IAAI,SAAS,QACX,OAAO,SAAS,aAAa,KAAK,QAAQ,IAAI,IAAI;IAEpD;GACF,KAAK;IACH,IAAI,SAAS,QACX,UACE,SAAS,MAAM,0BAAS,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC,CAAC,MAAM,GAAG,EAAE;IAEhE;EACJ;EAEA,IAAI,SAAS,cAAc,SAAS,SAAS,YAC3C,WAAW,SAAS,WAAW,SAAS;EAE1C,IAAI,SAAS,iBAAiB,SAAS,SAAS,aAC9C,cAAc,SAAS,UACpB,KAAK,SAAS,KAAK,UAAU,CAAC,CAC9B,KAAK,EAAE;CAEd;CAEA,OACE;UACW,WAAW,WACZ,KAAK,UAAU,KAAK,EAAE,iBAChB,KAAK,UAAU,WAAW,EAAE,UACnC,KAAK,UAAU,IAAI,EAAE,aAClB,KAAK,UAAU,OAAO,EAAE,cACvB,KAAK,UAAU,QAAQ,EAAE;;AAG1C;AAEA,SAAS,qBAAqB,QAAmC;CAC/D,IACE,WAAW,QACX,OAAO,WAAW,YAClB,MAAM,QAAQ,MAAM,KACnB,OAAO,eAAe,MAAM,MAAM,OAAO,aACxC,OAAO,eAAe,MAAM,MAAM,MAEpC,MAAM,IAAI,MAAM,gDAAgD;CAGlE,MAAM,UAAU,OAAO,QAAQ,MAAM,CAAC,CAAC,QACpC,GAAG,WAAW,UAAU,KAAA,CAC3B;CACA,IAAI,QAAQ,WAAW,GAAG,OAAO;CAMjC,OAAO,QAJM,UAAU,OAAO,YAAY,OAAO,GAAG;EAClD,uBAAuB;EACvB,QAAQ;CACV,CACkB,EAAE;AACtB;;;AC9FA,MAAa,cAAc,SAAiB,KAAK,KAAK;AACtD,MAAa,kBAAkB,SAAiB,IAAI,KAAK;AACzD,MAAa,QAAQ,SAAiB,KAAK,KAAK;AAChD,MAAa,UAAU,SAAiB,IAAI,KAAK;AACjD,MAAa,iBAAiB,SAAiB,KAAK,KAAK;AACzD,MAAa,aAAa,SAAiB,MAAM,KAAK;AACtD,MAAa,QAAQ,MAAc,SAAiB,IAAI,KAAK,IAAI,KAAK;AAEtE,SAAgB,UAAU,MAAc,WAAW,IAAY;CAE7D,OAAO,SADoB,aAAa,eAAe,SAAS,SAC7B,IAAI,KAAK;AAC9C;AAEA,MAAa,YAAY,SAAiB,OAAO,KAAK;AACtD,MAAa,YAAY,SAAiB,KAAK;AAC/C,MAAa,YAAY,SAAiB,MAAM;AAChD,MAAa,YAAY,SAAiB,OAAO;AACjD,MAAa,SAAS,SAAiB,KAAK,KAAK,QAAQ,OAAO,QAAQ;AAExE,SAAgB,QAAQ,MAAc,MAA4B;CAEhE,OAAO,KADO,MAAM,SAAS,UAAU,GAAG,KAAK,MAAM,KAAK,KACtC,KAAK,QAAQ,OAAO,QAAQ;AAClD;AAEA,SAAgB,OAAO,MAAc,OAAwB;CAC3D,MAAM,WAAW,KAAK,KAAK;CAC3B,OAAO,UAAU,KAAA,IAAY,KAAK,aAAa,GAAG,MAAM,IAAI;AAC9D;AAEA,MAAa,QAAQ,MAAc,YACjC,UAAU,SAAS,SAAS,SAAS;AAEvC,eAAsB,MACpB,KACA,MACA,kBAAkB,OACD;CACjB,IAAI,CAAC,mBAAmB,KAAK,WAAW,OAAO,GAAG;EAChD,IAAI,KAAK,WAAW,OAAO,GAEzB,OAAO,KAAK,IAAI,0BADD,KAAK,MAAM,GAAG,CAAC,CAAC,IACgB,EAAE;EAEnD,OAAO,KAAK,IAAI,IAAI,KAAK;CAC3B;CAEA,MAAM,WAAW,MAAM,MAAM,IAAI;CACjC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MACR,6BAA6B,SAAS,OAAO,GAAG,SAAS,YAC3D;CAEF,MAAM,SAAS,MAAM,SAAS,YAAY;CAC1C,OAAO,KAAK,IAAI,0BAA0B,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,QAAQ,EAAE;AACnF;AAEA,MAAa,gBAAgB;AAE7B,SAAgB,OAAO,SAAkB,UAA2B;CAClE,IAAI,CAAC,SAAS,OAAO,YAAY;CACjC,OAAO,uBAAuB,QAAQ,cAAc,YAAY,GAAG;AACrE;AAEA,SAAgB,MAAM,OAAmB,kBAAkB,MAAc;CACvE,IAAI,mBAAmB,MAAM,WAAW,GAAG,OAAO,cAAc,KAAK;CAErE,MAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC;CACxD,IAAI,UAAU,GAAG,OAAO;CAExB,OAAO,cAAc,CADD,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,EACxB,GAAG,GAAG,KAAK,CAAC;AAC9C;;;ACxDA,MAAM,qBAAkD;CACtD;EAAE,MAAM;EAAiB,MAAM;EAAM,OAAO;CAAK;CACjD;EAAE,MAAM;EAAa,MAAM;EAAO,OAAO;CAAO;CAChD;EAAE,MAAM;EAAU,MAAM;EAAK,OAAO;CAAI;CACxC;EAAE,MAAM;EAAQ,MAAM;EAAM,OAAO;CAAK;CACxC;EAAE,MAAM;EAAQ,MAAM;EAAK,OAAO;CAAI;AACxC;AAEA,SAAgB,gBACd,UACQ;CACR,OAAO,SAAS,KAAK,SAAS,KAAK,UAAU,CAAC,CAAC,KAAK,EAAE;AACxD;AAEA,SAAgB,eACd,UACQ;CACR,IAAI,WAAW;CACf,IAAI,SAA6B,CAAC;CAElC,KAAK,MAAM,CAAC,OAAO,SAAS,SAAS,QAAQ,GAAG;EAC9C,MAAM,UAAU,qBAAqB,UAAU,OAAO,IAAI;EAC1D,IAAI,SAAS;EACb,OACE,SAAS,OAAO,UAChB,SAAS,QAAQ,UACjB,OAAO,OAAO,EAAE,SAAS,QAAQ,OAAO,EAAE,MAE1C;EAGF,KAAK,MAAM,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC,WAAW,GACnD,YAAY,OAAO;EAErB,KAAK,MAAM,UAAU,QAAQ,MAAM,MAAM,GACvC,YAAY,OAAO;EAGrB,YAAY,cAAc,IAAI;EAC9B,SAAS;CACX;CAEA,KAAK,MAAM,UAAU,OAAO,WAAW,GACrC,YAAY,OAAO;CAErB,OAAO;AACT;AAEA,SAAS,qBACP,UACA,OACA,MACoB;CACpB,IAAI,KAAK,SAAS,YAAY,OAAO,CAAC;CAEtC,OAAO,mBAAmB,QAAQ,WAAW,KAAK,YAAY,OAAO,KAAK,CAAC,CACxE,KAAK,YAAY;EAChB;EACA,QAAQ,oBAAoB,UAAU,OAAO,OAAO,IAAI;CAC1D,EAAE,CAAC,CACF,MAAM,MAAM,UAAU,MAAM,SAAS,KAAK,MAAM,CAAC,CACjD,KAAK,EAAE,aAAa,MAAM;AAC/B;AAEA,SAAS,oBACP,UACA,OACA,MACQ;CACR,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,QAAQ,SAAS,SAAS,MAAM,QAAQ,CAAC,CAAC,CAAC,QAAQ,GAAG;EAChE,IAAI,KAAK,SAAS,cAAc,CAAC,KAAK,YAAY,OAAO;EACzD,MAAM,QAAQ,SAAS;CACzB;CACA,OAAO;AACT;AAEA,SAAS,cAAc,MAAoC;CACzD,IAAI,KAAK,SAAS,YAChB,OAAO,eAAe,KAAK,SAAS,UAAU;CAEhD,OAAO,KAAK,OAAO,KAAK,KAAK,YAAY,KAAK,IAAI,IAAI,KAAK;AAC7D;;;AC3EA,eAAsB,cACpB,SACA,QACA,4BAAiC,IAAI,IAAI,GACnB;CACtB,IAAI,UAAU,IAAI,OAAO,GAAG,OAAO,CAAC;CAEpC,MAAM,SAAS,MAAM,OAAO,iBAAiB,OAAO;CACpD,MAAM,iBAAiB,IAAI,IAAI,SAAS,CAAC,CAAC,IAAI,OAAO;CACrD,MAAM,QAAqB,CAAC;CAE5B,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,MAAM,SAAS,eAAe;EAElC,MAAM,gBAAgB,iBAAiB,KAAK;EAC5C,MAAM,WACJ,iBAAiB,CAAC,eAAe,IAAI,aAAa,IAC9C,MAAM,cAAc,eAAe,QAAQ,cAAc,IACzD,CAAC;EACP,MAAM,KAAK;GAAE;GAAO;EAAS,CAAC;CAChC;CAEA,OAAO;AACT;AAEA,SAAS,iBAAiB,OAAgD;CACxE,IAAI,MAAM,SAAS,gBAAgB,MAAM,SAAS,kBAChD;CAEF,IAAI,MAAM,SAAS,gBACjB,OACE,MAAM,aAAa,aAAa,aAC/B,MAAM,eAAe,MAAM,KAAK,KAAA;CAGrC,OAAO,MAAM,eAAe,MAAM,KAAK,KAAA;AACzC;AAEA,eAAsB,gBACpB,OACA,SACyB;CACzB,MAAM,SAAyB;EAAE,SAAS;EAAI,cAAc,CAAC;CAAE;CAC/D,IAAI,oBAAoB;CAExB,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,EAAE,UAAU;EAClB,oBACE,MAAM,SAAS,uBAAuB,oBAAoB,IAAI;EAEhE,MAAM,WACJ,MAAM,SAAS,UACX;GAAE,SAAS;GAAI,cAAc,CAAC;EAAE,IAChC,MAAM,gBAAgB,KAAK,UAAU,OAAO;EAClD,MAAM,UAAU,MAAM,gBACpB,MACA,SAAS,SACT,qBAAqB,KAAA,GACrB,OACF;EAEA,IAAI,MAAM,SAAS,UACjB,OAAO,WAAW;OACb;GACL,MAAM,WAAW,YAAY,KAAK,IAAI,KAAK;GAC3C,OAAO,WAAW,GAAG,WAAW,QAAQ,IAAI;GAC5C,IAAI,CAAC,oBAAoB,KAAK,GAC5B,OAAO,WAAW,SAAS;EAE/B;EAEA,IAAI,MAAM,SAAS,cACjB,OAAO,aAAa,KAAK,MAAM,EAAE;OAEjC,OAAO,aAAa,KAAK,GAAG,SAAS,YAAY;CAErD;CAEA,OAAO;AACT;AAEA,SAAS,YAAY,OAAqC;CACxD,OACE,MAAM,SAAS,WACf,MAAM,SAAS,wBACf,MAAM,SAAS;AAEnB;AAEA,SAAS,oBAAoB,OAAqC;CAChE,OACE,MAAM,SAAS,gBACf,MAAM,SAAS,aACf,MAAM,SAAS,wBACf,MAAM,SAAS,wBACf,MAAM,SAAS;AAEnB;AAEA,SAAS,eACP,MACA,OACA,SACkD;CAClD,MAAM,cAAc,QAAQ,eAAe;CAC3C,OAAO,cAAc,OAAO,OAAO;AACrC;AAEA,eAAe,gBACb,MACA,UACA,YACA,SACiB;CACjB,MAAM,EAAE,UAAU;CAElB,MAAM,UAAU,MADU,eAAe,MAAM,MAAM,OAAO,OAAO,KACnC,MAAM,mBAAmB,IAAI;CAE7D,QAAQ,MAAM,MAAd;EACE,KAAK,UACH,OAAOA,OAAU,SAAS,QAAQ;EACpC,KAAK,WACH,OAAOC,QACL,WAAW,GAAG,QAAQ,IAAI,WAAW,KAAK,IAAI,SAC9C,MAAM,QAAQ,IAChB;EACF,KAAK,sBACH,OAAOC,OAAU,qBAAqB,SAAS,UAAU,CAAC,CAAC;EAC7D,KAAK,sBACH,OAAOA,OACL,qBACE,SACA,UACA,GAAG,cAAc,EAAE,IAAI,MACzB,GACA,UACF;EACF,SACE,OAAO;CACX;AACF;AAEA,SAAS,qBACP,SACA,UACA,aACQ;CACR,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,QAAQ,OAAO;CAEpB,MAAM,cAAc,IAAI,OAAO,WAAW;CAK1C,OAAO,GAAG,QAAQ,IAJD,OACd,MAAM,IAAI,CAAC,CACX,KAAK,SAAU,OAAO,GAAG,cAAc,SAAS,EAAG,CAAC,CACpD,KAAK,IACqB;AAC/B;AAEA,eAAe,mBAAmB,MAAkC;CAClE,MAAM,EAAE,UAAU;CAElB,QAAQ,MAAM,MAAd;EACE,KAAK,SAAS;GACZ,MAAM,MAAM,WAAW,MAAM,KAAK;GAGlC,OAAOC,MAFS,gBAAgB,MAAM,MAAM,OAC1B,CAAC,CAAC,KAAK,KAAK,YAAY,GAAG,KAAK,SAC7B,GAAG;EAC1B;EACA,KAAK,WACH,OAAOC,QAAW;EACpB,KAAK,YACH,OAAOC,SAAY,MAAM,SAAS,UAAU;EAC9C,KAAK,OACH,OAAO,eAAe,MAAM,KAAK,MAAM,IAAI;EAC7C,KAAK,QACH,OAAO,eAAe,MAAM,MAAM,MAAM,IAAI;EAC9C,KAAK,SACH,OAAO,eAAe,MAAM,OAAO,MAAM,IAAI;EAC/C,KAAK,SACH,OAAO,eAAe,MAAM,OAAO,MAAM,IAAI;EAC/C,KAAK,SACH,OAAOC,KAAQ,MAAM,MAAM,MAAM,MAAM,GAAG;EAC5C,KAAK,YACH,OAAOA,KAAQ,MAAM,MAAM,MAAM,SAAS,GAAG;EAC/C,KAAK,gBACH,OAAOA,KAAQ,MAAM,MAAM,MAAM,aAAa,GAAG;EACnD,KAAK,gBAAgB;GACnB,MAAM,SAAS,MAAM;GACrB,IAAI,OAAO,SAAS,aAAa,OAAO,SAAS,eAC/C,OAAO;GAET,MAAM,KAAK,OAAO,SAAS,YAAY,OAAO,UAAU,OAAO;GAC/D,OAAOA,KAAQ,MAAM,MAAM,yBAAyB,IAAI;EAC1D;EACA,KAAK,cACH,OAAO,oBAAoB,KAAK;EAClC,KAAK,kBACH,OAAOC,SAAY,MAAM,eAAe,SAAS,gBAAgB;EACnE,KAAK,SACH,OAAO,YAAY,KAAK,UAAU,MAAM,MAAM,iBAAiB;EACjE,KAAK,QACH,OAAOC,UACL,eAAe,MAAM,KAAK,SAAS,GACnC,MAAM,KAAK,QACb;EACF,KAAK,aACH,OAAOC,SAAY,eAAe,MAAM,UAAU,SAAS,CAAC;EAC9D,KAAK,aACH,OAAOF,SAAY,eAAe,MAAM,UAAU,SAAS,CAAC;EAC9D,KAAK,aACH,OAAOG,SAAY,eAAe,MAAM,UAAU,SAAS,CAAC;EAC9D,KAAK,SACH,OAAOC,MAAS,eAAe,MAAM,MAAM,SAAS,CAAC;EACvD,KAAK,SACH,OAAOC,KACL,eAAe,MAAM,MAAM,SAAS,GACpC,MAAM,MAAM,OACd;EACF,KAAK,aACH,OAAO,eAAe,MAAM,UAAU,SAAS;EACjD,KAAK,UACH,OAAO,eAAe,MAAM,OAAO,SAAS;EAC9C,KAAK,WACH,OAAO,eAAe,MAAM,QAAQ,SAAS;EAC/C,KAAK,sBACH,OAAO,eAAe,MAAM,mBAAmB,SAAS;EAC1D,KAAK,sBACH,OAAO,eAAe,MAAM,mBAAmB,SAAS;EAC1D,KAAK,YACH,OAAO,eAAe,MAAM,SAAS,SAAS;EAChD,SACE,OAAO;CACX;AACF;AASA,SAAS,WAAW,SAA8B;CAChD,IAAI,QAAQ,SAAS,YAAY,OAAO,QAAQ,SAAS;CACzD,OAAO,QAAQ,KAAK;AACtB;AAEA,SAAS,YAAY,KAAiC;CACpD,OAAO,IAAI,MAAM,oCAAoC,CAAC,GAAG;AAC3D;AAEA,SAAS,eAAe,SAAsB,eAA+B;CAC3E,MAAM,MAAM,WAAW,OAAO;CAE9B,MAAM,QADU,gBAAgB,QAAQ,OACpB,CAAC,CAAC,KAAK,KAAK,YAAY,GAAG,KAAK;CACpD,OAAON,KAAQ,OAAO,GAAG;AAC3B;AAEA,SAAS,oBACP,OACQ;CACR,OAAO,WAAWA,KAAQ,MAAM,WAAW,OAAO,KAAK,MAAM,GAAG,IAAI;AACtE;AAEA,SAAS,YACP,OACA,iBACQ;CAOR,OAAOO,MANM,MAAM,SAAS,EAAE,YAAY;EACxC,IAAI,MAAM,SAAS,aAAa,OAAO,CAAC;EACxC,OAAO,CACL,MAAM,UAAU,MAAM,KAAK,SAAS,eAAe,IAAI,CAAC,CAC1D;CACF,CACgB,GAAM,eAAe;AACvC;;;AClRA,eAAsB,WACpB,QACA,QACA,UAAyB,CAAC,GACH;CAEvB,OAAO,YAAY,QADH,cAAc,CAAC,MAAM,GAAG,QAAQ,OACf,CAAC;AACpC;AAEA,eAAsB,YACpB,OACA,QACA,UAAyB,CAAC,GACD;CACzB,MAAM,UAAU,cACd,MAAM,KAAK,SAAS,KAAK,EAAE,GAC3B,QACA,OACF;CAEA,KAAK,MAAM,QAAQ,OACjB,MAAM,YAAY,KAAK,IAAI,SAAS,IAAI;CAG1C,OAAO,QAAQ,IAAI,CAAC,GAAG,QAAQ,cAAc,OAAO,CAAC,CAAC;AACxD;AAEA,SAAS,cACP,iBACA,QACA,SACmB;CACnB,OAAO;EACL;EACA,iBAAiB,IAAI,IAAI,eAAe;EACxC,YAAY,QAAQ,cAAA;EACpB,aAAa,QAAQ;EACrB,aAAa,QAAQ;EACrB,WAAW,QAAQ,aAAa;EAChC,cAAc,QAAQ;EACtB,+BAAe,IAAI,IAAI;CACzB;AACF;AAEA,eAAe,YACb,QACA,SACA,MACuB;CACvB,MAAM,SAAS,QAAQ,cAAc,IAAI,MAAM;CAC/C,IAAI,QAAQ,OAAO;CAEnB,MAAM,YAAY,iBAAiB,QAAQ,SAAS,IAAI;CACxD,QAAQ,cAAc,IAAI,QAAQ,SAAS;CAC3C,MAAM,WAAW,MAAM;CAEvB,IAAI,QAAQ,WACV,KAAK,MAAM,eAAe,SAAS,cACjC,MAAM,YAAY,aAAa,OAAO;CAI1C,OAAO;AACT;AAEA,eAAe,iBACb,QACA,SACA,MACuB;CACvB,MAAM,CAAC,MAAM,aAAa,MAAM,QAAQ,IAAI,CAC1C,OAAO,QAAQ,QAAQ,IAAI,IAAI,QAAQ,OAAO,QAAQ,MAAM,GAC5D,cAAc,QAAQ,QAAQ,MAAM,CACtC,CAAC;CACD,MAAM,WAAW,MAAM,gBAAgB,WAAW;EAChD;EACA,GAAI,QAAQ,iBAAiB,KAAA,IACzB,EAAE,cAAc,QAAQ,aAAa,IACrC,CAAC;CACP,CAAC;CAYD,OAAO;EACL,IAAI;EACJ,SAbkB,kBAAkB,MAAM;GAC1C,YAAY,QAAQ;GACpB,GAAI,QAAQ,gBAAgB,KAAA,IACxB,EAAE,aAAa,QAAQ,YAAY,IACnC,CAAC;GACL,GAAI,QAAQ,gBAAgB,KAAA,IACxB,EAAE,aAAa,QAAQ,YAAY,IACnC,CAAC;GACL,gBAAgB,QAAQ,gBAAgB,IAAI,MAAM;EACpD,CAIqB,IAAI,SAAS;EAChC,cAAc,CAAC,GAAG,IAAI,IAAI,SAAS,YAAY,CAAC;EAChD,gBAAgB,QAAQ,gBAAgB,IAAI,MAAM;CACpD;AACF;;;AClGA,eAAsB,WACpB,OACA,UAA6B,CAAC,GACX;CACnB,MAAM,WAAW,QAAQ,YAAA;CACzB,MAAM,YAAY,QAAQ,aAAA;CAC1B,MAAM,eAAyB,CAAC;CAChC,MAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;CAE1C,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,KAAK,WAAW,GAAG,KAAK,GAAG,IAAI;EAClD,MAAM,cAAc,MAAM,SAAS,UAAU;EAC7C,IAAI,eAAe,CAAC,YAAY,OAAO,GACrC,MAAM,IAAI,MAAM,0CAA0C,YAAY;EAExE,MAAM,UAAU,YAAY,KAAK,SAAS,MAAM;EAEhD,IAAI,CAAC,KAAK,gBAAgB;EAE1B,MAAM,WAAW,KAAK,UAAU,GAAG,KAAK,GAAG,IAAI;EAC/C,MAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;EACzC,MAAM,eAAe,YAAY,QAAQ;EACzC,aAAa,KAAK,QAAQ;CAC5B;CAEA,OAAO;AACT;AAEA,SAAgB,uBACd,UAA8B,CAAC,GACvB;CACR,MAAM,WAAW,QAAQ,YAAA;CACzB,MAAM,YAAY,QAAQ,aAAA;CAE1B,MAAM,eAAe,QAAQ,UADV,QAAQ,cAAA,wCACsB;CACjD,OAAO,SAAS,QAAQ,SAAS,GAAG,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG;AACvE;AAEA,eAAe,eACb,YACA,UACe;CACf,IAAI,QAAQ,UAAU,MAAM,QAAQ,QAAQ,GAAG;CAE/C,MAAM,YAAY,MAAM,SAAS,QAAQ;CACzC,IAAI,aAAa,CAAC,UAAU,OAAO,KAAK,CAAC,UAAU,eAAe,GAChE,MAAM,IAAI,MAAM,wCAAwC,UAAU;CAGpE,MAAM,SAAS,SAAS,QAAQ,QAAQ,GAAG,UAAU;CACrD,IAAI,WAAW,eAAe,KAAM,MAAM,SAAS,QAAQ,MAAO,QAChE;CAGF,MAAM,gBAAgB,GAAG,SAAS,UAAU,WAAW,EAAE;CACzD,IAAI;EACF,MAAM,QAAQ,QAAQ,eAAe,MAAM;EAC3C,MAAM,OAAO,eAAe,QAAQ;CACtC,SAAS,OAAO;EACd,MAAM,GAAG,eAAe,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;EACvD,MAAM;CACR;AACF;AAEA,eAAe,SAAS,MAAc;CACpC,IAAI;EACF,OAAO,MAAM,MAAM,IAAI;CACzB,SAAS,OAAgB;EACvB,IAAI,aAAa,KAAK,MAAM,UAAU,OAAO,KAAA;EAC7C,MAAM;CACR;AACF;;;ACxEA,SAAgB,mBACd,QACc;CACd,MAAM,SAAS,IAAI,OAAO,EAAE,MAAM,OAAO,gBAAgB,CAAC;CAC1D,OAAO;EACL,iBAAiB,UAAU,QAAQ,OAAO,UAAU;EACpD,UAAU,WAAW,QAAQ,QAAQ,MAAM;EAC3C,mBAAmB,YAAY,iBAAiB,QAAQ,OAAO;CACjE;AACF;AAEA,eAAe,UACb,QACA,YAC+B;CAC/B,MAAM,WAAW,MAAM,gBACrB,OAAO,UAAU,SAAS,EAAE,aAAa,WAAW,CAAC,CACvD;CACA,IAAI,CAAC,eAAe,QAAQ,GAC1B,MAAM,IAAI,MAAM,mBAAmB,WAAW,wBAAwB;CAGxE,MAAM,QAA8B,CAAC;CACrC,KAAK,MAAM,UAAU,SAAS,cAAc;EAC1C,IAAI;EACJ,GAAG;GACD,MAAM,WAAW,MAAM,gBACrB,OAAO,YAAY,MAAM;IACvB,gBAAgB,OAAO;IACvB,QAAQ;KACN,UAAU;KACV,UAAU,EAAE,QAAQ,KAAK;IAC3B;IACA,OAAO,CAAC;KAAE,UAAU;KAAQ,WAAW;IAAa,CAAC;IACrD,WAAW;IACX,GAAI,gBAAgB,KAAA,IAChB,EAAE,cAAc,YAAY,IAC5B,CAAC;GACP,CAAC,CACH;GACA,MAAM,KAAK,GAAG,SAAS,QAAQ,OAAO,UAAU,CAAC;GACjD,cAAc,SAAS,eAAe,KAAA;GACtC,IAAI,CAAC,SAAS,UAAU;EAC1B,SAAS;CACX;CAEA,OAAO;AACT;AAEA,eAAe,QACb,QACA,QAC6B;CAC7B,MAAM,OAAO,MAAM,gBAAgB,OAAO,MAAM,SAAS,EAAE,SAAS,OAAO,CAAC,CAAC;CAC7E,IAAI,CAAC,WAAW,IAAI,GAClB,MAAM,IAAI,MAAM,eAAe,OAAO,oBAAoB;CAE5D,OAAO;AACT;AAEA,eAAe,iBACb,QACA,SACgC;CAChC,MAAM,SAAgC,CAAC;CACvC,IAAI;CAEJ,GAAG;EACD,MAAM,WAAW,MAAM,gBACrB,OAAO,OAAO,SAAS,KAAK;GAC1B,UAAU;GACV,WAAW;GACX,GAAI,gBAAgB,KAAA,IAAY,EAAE,cAAc,YAAY,IAAI,CAAC;EACnE,CAAC,CACH;EACA,OAAO,KAAK,GAAG,SAAS,QAAQ,OAAO,WAAW,CAAC;EACnD,cAAc,SAAS,eAAe,KAAA;CACxC,SAAS;CAET,OAAO;AACT;AAEA,MAAM,eAAe;AACrB,MAAM,yBAAyB;AAE/B,eAAe,UAAa,WAAyC;CACnE,KAAK,IAAI,UAAU,IAAK,WACtB,IAAI;EACF,OAAO,MAAM,UAAU;CACzB,SAAS,OAAgB;EACvB,IAAI,YAAY,eAAe,KAAK,CAAC,YAAY,KAAK,GAAG,MAAM;EAC/D,MAAM,MAAM,yBAAyB,KAAK,OAAO;CACnD;AAEJ;AAEA,SAAS,YAAY,OAAyB;CAC5C,IAAI,CAAC,oBAAoB,KAAK,KAAK,EAAE,YAAY,QAAQ,OAAO;CAChE,OAAO,MAAM,WAAW,OAAO,MAAM,WAAW,OAAO,MAAM,UAAU;AACzE;AAEA,SAAS,MAAM,cAAqC;CAClD,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,YAAY,CAAC;AACnE"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
//#region src/lib/noblog/defaults.ts
|
|
2
|
-
const DEFAULT_SAVE_PATH = "./src/pages/posts/";
|
|
3
|
-
const DEFAULT_STORE_PATH = ".noblog/pages/";
|
|
4
|
-
const DEFAULT_LAYOUT_PATH = "../../layouts/MarkdownPostLayout.astro";
|
|
5
|
-
//#endregion
|
|
6
|
-
export { DEFAULT_SAVE_PATH as n, DEFAULT_STORE_PATH as r, DEFAULT_LAYOUT_PATH as t };
|
|
7
|
-
|
|
8
|
-
//# sourceMappingURL=defaults-D9BbNYsd.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"defaults-D9BbNYsd.js","names":[],"sources":["../src/lib/noblog/defaults.ts"],"sourcesContent":["export const DEFAULT_SAVE_PATH = \"./src/pages/posts/\";\nexport const DEFAULT_STORE_PATH = \".noblog/pages/\";\nexport const DEFAULT_LAYOUT_PATH = \"../../layouts/MarkdownPostLayout.astro\";\n"],"mappings":";AAAA,MAAa,oBAAoB;AACjC,MAAa,qBAAqB;AAClC,MAAa,sBAAsB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors-DgJ15MsB.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 })\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;CAC/D,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;;;ACzIF,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-BKu-Ix4a.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_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 ...(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":";;;;;AAoBA,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,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"}
|