Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions hugo/hugo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 <p>.
# 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 <figure>/<div> wrappers, so dropping the
# redundant <p> is also cleaner HTML. No CSS depends on p>img (checked).
wrapStandAloneImageWithinParagraph = false
[markup.goldmark.parser.attribute]
block = true
title = true
Expand Down
6 changes: 6 additions & 0 deletions scripts/fetch-tutorials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,8 @@ export function writeHugoPage(
variables?: import('./parsers/variables.js').TutorialVariable[],
syncKeysUsed?: Set<string>,
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,
Expand Down Expand Up @@ -679,6 +681,8 @@ export function writeHugoPage(
variables,
syncKeysUsed,
syncGroups,
testedWith,
requires,
})

mkdirSync(outputDir, { recursive: true })
Expand Down Expand Up @@ -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 ?? '',
Expand Down
63 changes: 63 additions & 0 deletions scripts/parsers/__tests__/render-frontmatter-testedwith.test.ts
Original file line number Diff line number Diff line change
@@ -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<string, unknown> {
const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---/)
if (!m) throw new Error('no frontmatter')
return parseYaml(m[1]) as Record<string, unknown>
}

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)
})
})
Loading