diff --git a/hugo/hugo.toml b/hugo/hugo.toml index b66c9eca7..13f0e960f 100644 --- a/hugo/hugo.toml +++ b/hugo/hugo.toml @@ -88,6 +88,14 @@ enableRobotsTXT = false # we ship our own via the robots output format [markup.goldmark.renderer] unsafe = true [markup.goldmark.parser] + # #directive-hotspots: a standalone image with a following block-attribute + # line (`![](img)\n{hotspots=…}`) only has its attributes delivered to the + # image render hook's .Attributes when the image is NOT wrapped in a

. + # With the default (true) goldmark wraps it and the attribute block never + # attaches, so `{hotspots=…}` leaked as literal text and no overlay rendered. + # The render hooks already emit

/
wrappers, so dropping the + # redundant

is also cleaner HTML. No CSS depends on p>img (checked). + wrapStandAloneImageWithinParagraph = false [markup.goldmark.parser.attribute] block = true title = true diff --git a/scripts/fetch-tutorials.ts b/scripts/fetch-tutorials.ts index 6f68b5b48..c0b8835fd 100644 --- a/scripts/fetch-tutorials.ts +++ b/scripts/fetch-tutorials.ts @@ -651,6 +651,8 @@ export function writeHugoPage( variables?: import('./parsers/variables.js').TutorialVariable[], syncKeysUsed?: Set, syncGroups?: import('./parsers/types.js').TutorialFrontmatter['syncGroups'], + testedWith?: import('./parsers/types.js').TutorialFrontmatter['testedWith'], + requires?: import('./parsers/types.js').TutorialFrontmatter['requires'], ): void { const content = renderHugoFrontmatter({ slug, @@ -679,6 +681,8 @@ export function writeHugoPage( variables, syncKeysUsed, syncGroups, + testedWith, + requires, }) mkdirSync(outputDir, { recursive: true }) @@ -1721,6 +1725,8 @@ async function main() { composed.variables, composed.syncKeysUsed.size > 0 ? composed.syncKeysUsed : undefined, composed.syncGroups, + composed.testedWith, + composed.requires, ) authorRows.push({ authorProfile: frontmatter.author_profile ?? '', diff --git a/scripts/parsers/__tests__/render-frontmatter-testedwith.test.ts b/scripts/parsers/__tests__/render-frontmatter-testedwith.test.ts new file mode 100644 index 000000000..6bc6b9080 --- /dev/null +++ b/scripts/parsers/__tests__/render-frontmatter-testedwith.test.ts @@ -0,0 +1,63 @@ +import { describe, it, expect } from 'vitest' +import { parse as parseYaml } from 'yaml' +import { renderHugoFrontmatter } from '../render-frontmatter.js' +import type { RenderHugoFrontmatterArgs } from '../render-frontmatter.js' +import type { TutorialNavEntry } from '../types.js' + +// #directive-demos: testedWith + requires were parsed, composed, and accepted by +// renderHugoFrontmatter — but writeHugoPage (fetch-tutorials.ts) never forwarded +// them, so .Params.testedWith was always empty and the "Tested with" panel never +// rendered. The only prior testedWith test covered checkTestedWithFreshness, not +// the generated frontmatter — which is why the drop went unnoticed. These lock +// the rendered-frontmatter contract the u1 layout + prereq card depend on. + +const minimalNav: TutorialNavEntry = { + slug: 'demo', title: 'Demo', description: '', time: 5, level: 'beginner', + stepCount: 1, primaryTag: '', displayTags: [], displayTagSlugs: [], + repo: 'sap-tutorials/demo', branch: 'main', prev: null, next: null, +} + +function fmFrom(content: string): Record { + const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---/) + if (!m) throw new Error('no frontmatter') + return parseYaml(m[1]) as Record +} + +describe('renderHugoFrontmatter — testedWith + requires', () => { + const baseArgs: RenderHugoFrontmatterArgs = { + slug: 'demo', title: 'Demo', description: '', time: 5, level: 'beginner', + tags: [], primaryTag: '', author: 'Thomas Jung', + authorProfile: 'https://github.com/jung-thomas', youWillLearn: [], + prerequisites: '', steps: [{ number: 1, title: 'Step 1', content: '' }], + nav: minimalNav, lastUpdated: '', createdAt: '', contributors: [], + } + + it('emits testedWith map into the frontmatter (→ .Params.testedWith)', () => { + const content = renderHugoFrontmatter({ + ...baseArgs, + testedWith: { '@sap/cds': '10.x', node: '22' }, + }) + expect(content).toContain('testedWith:') + const fm = fmFrom(content) + expect(fm.testedWith).toEqual({ '@sap/cds': '10.x', node: '22' }) + }) + + it('emits requires list into the frontmatter (→ .Params.requires)', () => { + const content = renderHugoFrontmatter({ + ...baseArgs, + requires: ['hana-cloud-mission-trial-1'], + }) + const fm = fmFrom(content) + expect(fm.requires).toEqual(['hana-cloud-mission-trial-1']) + }) + + it('omits testedWith when empty/unset', () => { + expect('testedWith' in fmFrom(renderHugoFrontmatter(baseArgs))).toBe(false) + expect('testedWith' in fmFrom(renderHugoFrontmatter({ ...baseArgs, testedWith: {} }))).toBe(false) + }) + + it('omits requires when empty/unset', () => { + expect('requires' in fmFrom(renderHugoFrontmatter(baseArgs))).toBe(false) + expect('requires' in fmFrom(renderHugoFrontmatter({ ...baseArgs, requires: [] }))).toBe(false) + }) +})