From 888b4fad028b8a48acb43dffe25f027ded30174f Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:39:28 +0100 Subject: [PATCH 1/2] feat!: replaces the `copyStarlightFrontmatter` option in favor of the new `copyFrontmatter` option --- docs/src/content/docs/configuration.md | 11 +++-- docs/src/content/docs/guides/features.md | 2 +- fixtures/basics/Starlight properties.md | 6 +++ packages/starlight-obsidian/index.ts | 31 +++++++++--- packages/starlight-obsidian/libs/plugin.ts | 5 +- packages/starlight-obsidian/libs/remark.ts | 24 ++++++---- packages/starlight-obsidian/libs/starlight.ts | 2 +- .../starlight-obsidian/tests/embeds.test.ts | 4 +- .../tests/properties.test.ts | 48 ++++++++++++++++++- packages/starlight-obsidian/tests/utils.ts | 4 +- 10 files changed, 109 insertions(+), 28 deletions(-) diff --git a/docs/src/content/docs/configuration.md b/docs/src/content/docs/configuration.md index 3d3fcc6..f74d927 100644 --- a/docs/src/content/docs/configuration.md +++ b/docs/src/content/docs/configuration.md @@ -89,14 +89,15 @@ Add links to Starlight headings to make it easier to share a link to a specific By default, Starlight will include an “Overview” heading at the top of each page’s table of contents. If your Obsidian vault pages already include a top-level heading named “Overview”, you can set this option to `'title'` to instead use the page title as the top-level heading in the table of contents. -### `copyStarlightFrontmatter` +### `copyFrontmatter` -**Type:** `boolean` -**Default:** `false` +**Type:** `'none' | 'starlight' | 'all'` +**Default:** `'none'` -By default, all unsupported [properties](/guides/features/#properties) are ignored and not exported. Set this option to `true` to copy all known [Starlight frontmatter fields](https://starlight.astro.build/reference/frontmatter/) from an Obsidian note to the associated generated page. +By default (`none`), all unsupported [properties](/guides/features/#properties) are ignored and not exported. +Set this option to `starlight` to copy all known [Starlight frontmatter fields](https://starlight.astro.build/reference/frontmatter/) from an Obsidian note to the associated generated page or to `all` to copy all frontmatter fields. -This is useful if you want to customize the generated Starlight pages from Obsidian. +This option is useful if you want to customize the generated Starlight pages from Obsidian. Note that the values are not validated and are copied as-is so it's up to you to ensure they are compatible with Starlight. ## Sidebar configuration diff --git a/docs/src/content/docs/guides/features.md b/docs/src/content/docs/guides/features.md index 0bba068..0b17bcf 100644 --- a/docs/src/content/docs/guides/features.md +++ b/docs/src/content/docs/guides/features.md @@ -82,7 +82,7 @@ Some features may never be supported due to various reasons, e.g. accessibility ## Properties By deault, all unsupported properties are ignored and not exported. -This behavior can be changed by setting the [`copyStarlightFrontmatter`](/configuration/#copystarlightfrontmatter) option to `true` to include all known [Starlight frontmatter fields](https://starlight.astro.build/reference/frontmatter/). +This behavior can be changed by setting the [`copyFrontmatter`](/configuration/#copyfrontmatter) option to `starlight` to include all known [Starlight frontmatter fields](https://starlight.astro.build/reference/frontmatter/) or `all` to include all frontmatter fields. | Name | Supported | | :------------------------------------------------------------------------------------------------ | :-------: | diff --git a/fixtures/basics/Starlight properties.md b/fixtures/basics/Starlight properties.md index cfa4729..dde90b3 100644 --- a/fixtures/basics/Starlight properties.md +++ b/fixtures/basics/Starlight properties.md @@ -5,6 +5,12 @@ unknown: this is a custom property title: Custom Starlight Title tableOfContents: false lastUpdated: 2024-09-21 +cover: https://history-computer.com/ModernComputer/Basis/images/Engelbart.jpg +head: + - tag: meta + attrs: + property: 'og:image' + content: 'https://example.com/og-image.png' --- Test diff --git a/packages/starlight-obsidian/index.ts b/packages/starlight-obsidian/index.ts index b72b2e6..5c46e55 100644 --- a/packages/starlight-obsidian/index.ts +++ b/packages/starlight-obsidian/index.ts @@ -22,16 +22,24 @@ const starlightObsidianConfigSchema = z.object({ */ configFolder: z.string().startsWith('.').default('.obsidian'), /** - * Whether the Starlight Obsidian plugin should copy known Starlight frontmatter fields from Obsidian notes to the - * generated pages. + * Defines which frontmatter fields the Starlight Obsidian plugin should copy from Obsidian notes to the generated + * pages. * - * This is useful if you want to customize the generated Starlight pages from Obsidian. Note that the values are not - * validated and are copied as-is so it's up to you to ensure they are compatible with Starlight. + * By default (`none`), all unsupported properties are ignored and not exported. Set this option to `starlight` to + * copy all known Starlight frontmatter fields from an Obsidian note to the associated generated page or to `all` to + * copy all frontmatter fields. * - * @default false + * This option is useful if you want to customize the generated Starlight pages from Obsidian. Note that the values + * are not validated and are copied as-is so it's up to you to ensure they are compatible with Starlight. + * + * @default 'none' * @see https://starlight.astro.build/reference/frontmatter/ */ - copyStarlightFrontmatter: z.boolean().default(false), + copyFrontmatter: z.union([z.literal('none'), z.literal('starlight'), z.literal('all')]).default('none'), + /** + * @deprecated Use the {@link StarlightObsidianUserConfig.copyFrontmatter} option instead. + */ + copyStarlightFrontmatter: z.never().optional(), /** * A list of glob patterns to ignore when generating the Obsidian vault pages. * This option can be used to ignore files or folders. @@ -102,6 +110,17 @@ export default function starlightObsidianPlugin(userConfig: StarlightObsidianUse const parsedConfig = starlightObsidianConfigSchema.safeParse(userConfig) if (!parsedConfig.success) { + const isUsingDeprecatedCopyStarlightFrontmatter = parsedConfig.error.issues.some( + (issue) => issue.path.join('.') === 'copyStarlightFrontmatter', + ) + + if (isUsingDeprecatedCopyStarlightFrontmatter) { + throwUserError( + 'The `copyStarlightFrontmatter` option has been deprecated in favor of the `copyFrontmatter` option.', + 'For more information see https://starlight-obsidian.vercel.app/configuration/#copyfrontmatter', + ) + } + throwUserError( `The provided plugin configuration is invalid.\n${parsedConfig.error.issues.map((issue) => issue.message).join('\n')}`, ) diff --git a/packages/starlight-obsidian/libs/plugin.ts b/packages/starlight-obsidian/libs/plugin.ts index a278f90..d1c9240 100644 --- a/packages/starlight-obsidian/libs/plugin.ts +++ b/packages/starlight-obsidian/libs/plugin.ts @@ -1,8 +1,9 @@ import { AstroError } from 'astro/errors' -export function throwUserError(message: string): never { +export function throwUserError(message: string, hint?: string): never { throw new AstroError( message, - `See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/HiDeoo/starlight-obsidian/issues/new/choose`, + hint ?? + `See the error report above for more informations.\n\nIf you believe this is a bug, please file an issue at https://github.com/HiDeoo/starlight-obsidian/issues/new/choose`, ) } diff --git a/packages/starlight-obsidian/libs/remark.ts b/packages/starlight-obsidian/libs/remark.ts index 82565f3..c969749 100644 --- a/packages/starlight-obsidian/libs/remark.ts +++ b/packages/starlight-obsidian/libs/remark.ts @@ -453,9 +453,14 @@ function getFrontmatterNodeValue(file: VFile, obsidianFrontmatter?: ObsidianFron editUrl: false, } - if (obsidianFrontmatter && file.data.copyStarlightFrontmatter) { - const starlightLikeFrontmatter = getStarlightLikeFrontmatter(obsidianFrontmatter.raw) - frontmatter = { ...frontmatter, ...starlightLikeFrontmatter } + if (obsidianFrontmatter && (file.data.copyFrontmatter === 'starlight' || file.data.copyFrontmatter === 'all')) { + if (file.data.copyFrontmatter === 'starlight') { + const starlightLikeFrontmatter = getStarlightLikeFrontmatter(obsidianFrontmatter.raw) + frontmatter = { ...frontmatter, ...starlightLikeFrontmatter } + } else { + const { cover, image, description, permalink, tags, ...restFrontmatter } = obsidianFrontmatter.raw + frontmatter = { ...frontmatter, ...restFrontmatter } + } } if (file.data.includeKatexStyles) { @@ -479,10 +484,13 @@ function getFrontmatterNodeValue(file: VFile, obsidianFrontmatter?: ObsidianFron frontmatter.head = [] } - frontmatter.head.push( - { tag: 'meta', attrs: { property: 'og:image', content: ogImage } }, - { tag: 'meta', attrs: { name: 'twitter:image', content: ogImage } }, - ) + if (!frontmatter.head.some((tag) => tag.attrs['property'] === 'og:image')) { + frontmatter.head.push({ tag: 'meta', attrs: { property: 'og:image', content: ogImage } }) + } + + if (!frontmatter.head.some((tag) => tag.attrs['property'] === 'twitter:image')) { + frontmatter.head.push({ tag: 'meta', attrs: { name: 'twitter:image', content: ogImage } }) + } } if (obsidianFrontmatter?.description && obsidianFrontmatter.description.length > 0) { @@ -674,7 +682,7 @@ function ensureTransformContext(file: VFile): asserts file is VFile & { data: Tr export interface TransformContext { aliases?: string[] assetImports?: [id: string, path: string][] - copyStarlightFrontmatter?: boolean + copyFrontmatter: StarlightObsidianConfig['copyFrontmatter'] embedded?: boolean files: VaultFile[] includeKatexStyles?: boolean diff --git a/packages/starlight-obsidian/libs/starlight.ts b/packages/starlight-obsidian/libs/starlight.ts index 4307272..160f5e5 100644 --- a/packages/starlight-obsidian/libs/starlight.ts +++ b/packages/starlight-obsidian/libs/starlight.ts @@ -181,7 +181,7 @@ async function addContent( type, } = await transformMarkdownToString(vaultFile.fsPath, obsidianContent, { files: vaultFiles, - copyStarlightFrontmatter: config.copyStarlightFrontmatter, + copyFrontmatter: config.copyFrontmatter, output: config.output, vault, }) diff --git a/packages/starlight-obsidian/tests/embeds.test.ts b/packages/starlight-obsidian/tests/embeds.test.ts index 8d3fb44..679573d 100644 --- a/packages/starlight-obsidian/tests/embeds.test.ts +++ b/packages/starlight-obsidian/tests/embeds.test.ts @@ -56,7 +56,7 @@ test.each(linkSyntaxAndFormats)('transforms embed URLs in %s with the %s format' const vault = await getVault(getFixtureConfig(fixtureName)) const paths = await getObsidianPaths(vault) const files = getObsidianVaultFiles(vault, paths) - const options = { context: { files, output: 'notes', vault } } + const options = { context: { copyFrontmatter: 'none', files, output: 'notes', vault } as const } let result = await transformFixtureMdFile(fixtureName, 'root embeds.md', options) @@ -142,7 +142,7 @@ test('applies transformers to embedded notes', async () => { const paths = await getObsidianPaths(vault) const files = getObsidianVaultFiles(vault, paths) const options = { - context: { copyStarlightFrontmatter: true, files, output: 'notes', vault }, + context: { copyFrontmatter: 'starlight', files, output: 'notes', vault } as const, includeFrontmatter: true, } diff --git a/packages/starlight-obsidian/tests/properties.test.ts b/packages/starlight-obsidian/tests/properties.test.ts index 138f517..6cc4166 100644 --- a/packages/starlight-obsidian/tests/properties.test.ts +++ b/packages/starlight-obsidian/tests/properties.test.ts @@ -55,7 +55,7 @@ test('includes known Starlight frontmatter fields if the option is enabled', asy const paths = await getObsidianPaths(vault) const files = getObsidianVaultFiles(vault, paths) const options = { - context: { copyStarlightFrontmatter: true, files, output: 'notes', vault }, + context: { copyFrontmatter: 'starlight', files, output: 'notes', vault } as const, includeFrontmatter: true, } @@ -66,6 +66,15 @@ test('includes known Starlight frontmatter fields if the option is enabled', asy title: Custom Starlight Title editUrl: false slug: custom-starlight-slug + head: + - tag: meta + attrs: + property: og:image + content: https://example.com/og-image.png + - tag: meta + attrs: + name: twitter:image + content: https://history-computer.com/ModernComputer/Basis/images/Engelbart.jpg tableOfContents: false lastUpdated: 2024-09-21 description: This is a custom description @@ -75,3 +84,40 @@ test('includes known Starlight frontmatter fields if the option is enabled', asy " `) }) + +test('includes all frontmatter fields if the option is enabled', async () => { + const fixtureName = 'basics' + const vault = await getVault(getFixtureConfig(fixtureName)) + const paths = await getObsidianPaths(vault) + const files = getObsidianVaultFiles(vault, paths) + const options = { + context: { copyFrontmatter: 'all', files, output: 'notes', vault } as const, + includeFrontmatter: true, + } + + const result = await transformFixtureMdFile(fixtureName, 'Starlight properties.md', options) + + expect(result.content).toMatchInlineSnapshot(` + "--- + title: Custom Starlight Title + editUrl: false + slug: custom-starlight-slug + unknown: this is a custom property + tableOfContents: false + lastUpdated: 2024-09-21 + head: + - tag: meta + attrs: + property: og:image + content: https://example.com/og-image.png + - tag: meta + attrs: + name: twitter:image + content: https://history-computer.com/ModernComputer/Basis/images/Engelbart.jpg + description: This is a custom description + --- + + Test + " + `) +}) diff --git a/packages/starlight-obsidian/tests/utils.ts b/packages/starlight-obsidian/tests/utils.ts index 5a2730d..351b209 100644 --- a/packages/starlight-obsidian/tests/utils.ts +++ b/packages/starlight-obsidian/tests/utils.ts @@ -27,7 +27,7 @@ export function getFixtureConfig( return { autoLinkHeadings: false, configFolder: '.obsidian', - copyStarlightFrontmatter: false, + copyFrontmatter: 'none', ignore: [], skipGeneration: false, tableOfContentsOverview: 'default', @@ -61,7 +61,7 @@ export async function transformFixtureMdFile( const md = await getFixtureFile(fixtureName, filePath) const fileName = path.basename(filePath) const result = await transformMarkdownToString(fixtureFilePath, md, { - copyStarlightFrontmatter: options.context?.copyStarlightFrontmatter ?? false, + copyFrontmatter: options.context?.copyFrontmatter ?? 'none', files: options.context?.files ?? [ createVaultFile({ fileName, From 6969fe22f282107af1032d0bfced1118756e1fc6 Mon Sep 17 00:00:00 2001 From: HiDeoo <494699+HiDeoo@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:41:54 +0100 Subject: [PATCH 2/2] fix: ensures the `draft` frontmatter field is copied when the `copyFrontmatter` option is set to `starlight` or `all` --- packages/starlight-obsidian/libs/starlight.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/starlight-obsidian/libs/starlight.ts b/packages/starlight-obsidian/libs/starlight.ts index 160f5e5..58a4076 100644 --- a/packages/starlight-obsidian/libs/starlight.ts +++ b/packages/starlight-obsidian/libs/starlight.ts @@ -62,6 +62,7 @@ const starlightFrontmatterKeys = [ 'prev', 'next', 'pagefind', + 'draft', 'sidebar', ]