From 697d22e806ac43f2b53e3b9b58d2e13fa8c76440 Mon Sep 17 00:00:00 2001 From: Kai Moritz Date: Sun, 14 Jun 2026 11:59:50 +0000 Subject: [PATCH] =?utf8?q?Projects:=20Content=20Collection=20+=20Helper-Bi?= =?utf8?q?bliothek=20f=C3=BCr=20Hibernate=20Maven=20Plugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - js-yaml als explizite Dev-Dependency hinzugefügt (war transitive Dep) - Custom Content Layer Loader in content.config.ts: liest HTML+YAML-Frontmatter aus src/content/projects/ und stellt sie als 'projects'-Collection bereit - src/lib/projects.ts: buildNavTree(), getActiveProject(), getVisibleProjectNavTrees() - Repräsentativer Subset: hibernate-maven-plugin 2.1.1 (sichtbar) + 2.1.2-SNAPSHOT (nicht-sichtbar), je 6 Seiten: Index, Configuration, Project Information, Project Reports, Plugin Documentation, Goal:create Co-Authored-By: Claude Sonnet 4.6 --- package-lock.json | 9 + package.json | 2 + src/content.config.ts | 72 ++++++- .../hibernate-maven-plugin/2.1.1/_index.html | 54 ++++++ .../2.1.1/configuration.html | 32 ++++ .../2.1.1/project-info/_index.html | 32 ++++ .../2.1.1/project-reports/_index.html | 29 +++ .../project-reports/plugin-info/_index.html | 27 +++ .../plugin-info/create-mojo.html | 25 +++ .../2.1.2-SNAPSHOT/_index.html | 30 +++ .../2.1.2-SNAPSHOT/configuration.html | 33 ++++ .../2.1.2-SNAPSHOT/project-info/_index.html | 33 ++++ .../project-reports/_index.html | 30 +++ .../project-reports/plugin-info/_index.html | 28 +++ .../plugin-info/create-mojo.html | 18 ++ src/lib/projects.ts | 175 ++++++++++++++++++ 16 files changed, 628 insertions(+), 1 deletion(-) create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.1/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.1/configuration.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.1/project-info/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/create-mojo.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/configuration.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-info/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/_index.html create mode 100644 src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/create-mojo.html create mode 100644 src/lib/projects.ts diff --git a/package-lock.json b/package-lock.json index 74795f1f..001519a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,8 @@ "astro": "^6.4.4" }, "devDependencies": { + "@types/js-yaml": "^4.0.9", + "js-yaml": "^4.2.0", "sass": "^1.100.0" }, "engines": { @@ -1978,6 +1980,13 @@ "@types/unist": "*" } }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", diff --git a/package.json b/package.json index 6dd8a2e5..47e7e9a9 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "astro": "^6.4.4" }, "devDependencies": { + "@types/js-yaml": "^4.0.9", + "js-yaml": "^4.2.0", "sass": "^1.100.0" } } diff --git a/src/content.config.ts b/src/content.config.ts index 8f780751..3896f88a 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -1,5 +1,8 @@ import { defineCollection, z } from 'astro:content'; import { glob } from 'astro/loaders'; +import { load as yamlLoad } from 'js-yaml'; +import { readFileSync, readdirSync } from 'node:fs'; +import { resolve, relative, dirname, basename } from 'node:path'; const blog = defineCollection({ loader: glob({ pattern: '**/*.md', base: './src/content/blog' }), @@ -20,4 +23,71 @@ const blog = defineCollection({ }), }); -export const collections = { blog }; +const projectPageSchema = z.object({ + title: z.string(), + weight: z.number().default(999), + url: z.string(), + layout: z.string().optional(), + outputs: z.array(z.string()).optional(), + params: z.object({ + current: z.boolean(), + canonical: z.string().optional(), + }), +}); + +function findHtmlFiles(dir: string, baseDir: string): string[] { + const results: string[] = []; + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const fullPath = resolve(dir, entry.name); + if (entry.isDirectory()) { + results.push(...findHtmlFiles(fullPath, baseDir)); + } else if (entry.name.endsWith('.html')) { + results.push(relative(baseDir, fullPath)); + } + } + return results; +} + +function parseHtmlWithFrontmatter(content: string): { data: Record; body: string } { + if (!content.startsWith('---')) return { data: {}, body: content }; + const end = content.indexOf('\n---', 3); + if (end === -1) return { data: {}, body: content }; + const frontmatter = content.slice(3, end).trim(); + const body = content.slice(end + 4).trim(); + return { data: yamlLoad(frontmatter) as Record, body }; +} + +const projects = defineCollection({ + loader: { + name: 'project-pages-loader', + load: async ({ store, parseData, logger }) => { + const baseDir = resolve('./src/content/projects'); + let files: string[]; + try { + files = findHtmlFiles(baseDir, baseDir); + } catch { + logger.warn('No src/content/projects/ directory found — skipping projects loader'); + return; + } + + for (const relPath of files) { + const fullPath = resolve(baseDir, relPath); + const raw = readFileSync(fullPath, 'utf-8'); + const { data, body } = parseHtmlWithFrontmatter(raw); + + // Normalise id: use forward slashes, strip leading ./ + const id = relPath.replace(/\\/g, '/'); + + try { + const parsed = await parseData({ id, data }); + store.set({ id, data: parsed, body }); + } catch (e) { + logger.warn(`Skipping ${id}: ${e}`); + } + } + }, + }, + schema: projectPageSchema, +}); + +export const collections = { blog, projects }; diff --git a/src/content/projects/hibernate-maven-plugin/2.1.1/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.1/_index.html new file mode 100644 index 00000000..6c3ce3b5 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.1/_index.html @@ -0,0 +1,54 @@ +--- +title: Hibernate Maven Plugin +weight: 0 +outputs: + - html +url: /hibernate-maven-plugin/ +layout: article +params: + current: true +--- +
+

Hibernate Maven Plugin

+

A simple plugin for generating a database-schema from Hibernate-Mappings

+

The hibernate-maven-plugin is a plugin for generating a database-schema +from your Hibernate-Mappings and create or update your database accordingly. +Its main usage is to automatically create and populate a test-database for +unit-tests in cooperation with the +dbunit-maven-plugin.

+

The plugin was designed with three main goals in mind:

+
    +
  • It should be easy to use.
  • +
  • It should be maximal unlikely, to erase a producation-database by accident.
  • +
  • It should not slow down the development cycle.
  • +
+

To achieve the first goal, the convention-over-configuration paradigma was applied +and the plugin was stuffed with usefull logging-messages. So, if in doubt, just turn +on the debugging output with the mvn -X ....

+

To achieve the second goal, the precedence in which the configuration locations are +consulted was layouted in a way that makes it possible, to prevent overwrites of the +wrong database by accident.

+

Last but not least, in order to not slow down the development cycle, the +hibernate-maven-plugin only executes the generated SQL, if the mapping or the +configuration has changed (or if you force it to do so).

+
+

Documentation

+ +
+

Releases

+ +
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.1/configuration.html b/src/content/projects/hibernate-maven-plugin/2.1.1/configuration.html new file mode 100644 index 00000000..a9f1a36e --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.1/configuration.html @@ -0,0 +1,32 @@ +--- +title: Configuration Examples +weight: 20 +outputs: + - html +url: /hibernate-maven-plugin/configuration.html +layout: article +params: + current: true +--- +
+

Configuration Examples

+

Configuration Through A Configuration-File

+

The most simple way to configure the plugin is, to put all the hibernate-configuration +in a hibernate.properties- or a hibernate.cfg.xml-file on your classpath +or in the persistence.xml-file of your JPA-configuration, just like you would +do, if you are not using the hibernate-maven-plugin at all.

+

In that case, the only configuration needed in the pom.xml is:

+
<plugin>
+  <groupId>de.juplo</groupId>
+  <artifactId>hibernate-maven-plugin</artifactId>
+  <version>2.1.1</version>
+  <executions>
+    <execution>
+      <goals>
+        <goal>create</goal>
+      </goals>
+    </execution>
+  </executions>
+</plugin>
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.1/project-info/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.1/project-info/_index.html new file mode 100644 index 00000000..a0f906aa --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.1/project-info/_index.html @@ -0,0 +1,32 @@ +--- +title: Project Information +weight: 1 +outputs: + - html +url: /hibernate-maven-plugin/project-info.html +layout: article +params: + current: true +--- +
+
+

Project Information

+

This document provides an overview of the various documents and links that are part +of this project's general information. All of this content is automatically generated +by Maven on behalf of the project.

+
+

Overview

+ + + + + + + + + + +
DocumentDescription
CI ManagementThis document lists the continuous integration management system of this project.
DependenciesThis document lists the project's dependencies and provides information on each dependency.
LicensesThis document lists the project license(s).
TeamThis document provides information on the members of this project.
+
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/_index.html new file mode 100644 index 00000000..35290517 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/_index.html @@ -0,0 +1,29 @@ +--- +title: Project Reports +weight: 12 +outputs: + - html +url: /hibernate-maven-plugin/project-reports.html +layout: article +params: + current: true +--- +
+
+

Generated Reports

+

This document provides an overview of the various reports that are automatically +generated by Maven.

+
+

Overview

+ + + + + + + + +
DocumentDescription
JavaDocsThis document contains the JavaDoc API documentation.
Test JavaDocsThis document contains the test JavaDoc API documentation.
Plugin DocumentationThis document lists the plugins goals and their parameters.
+
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/_index.html new file mode 100644 index 00000000..a0d81047 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/_index.html @@ -0,0 +1,27 @@ +--- +title: Plugin Documentation +weight: 19 +outputs: + - html +url: /hibernate-maven-plugin/plugin-info.html +layout: article +params: + current: true +--- +
+
+

Plugin Documentation

+

Goals available for this plugin:

+ + + + + + + + + + +
GoalDescription
hibernate:createCreates the database schema using Hibernate.
hibernate:dropDrops the database schema using Hibernate.
hibernate:updateUpdates the database schema using Hibernate.
hibernate:helpDisplay help information on hibernate-maven-plugin.
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/create-mojo.html b/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/create-mojo.html new file mode 100644 index 00000000..d241a922 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.1/project-reports/plugin-info/create-mojo.html @@ -0,0 +1,25 @@ +--- +title: "Goal — hibernate:create" +weight: 21 +outputs: + - html +url: /hibernate-maven-plugin/create-mojo.html +layout: article +params: + current: true +--- +
+
+

hibernate:create

+

Full name: de.juplo:hibernate-maven-plugin:2.1.1:create

+

Description: Creates the database-schema from Hibernate-Mappings. +This goal executes the generated DDL-SQL, if the mapping or the configuration +has changed since the last run (or if forced).

+

Attributes:

+
    +
  • Requires a Maven project to be executed.
  • +
  • Executes as an aggregator goal.
  • +
  • Binds by default to the lifecycle phase: process-test-resources.
  • +
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/_index.html new file mode 100644 index 00000000..3c4f9711 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/_index.html @@ -0,0 +1,30 @@ +--- +title: Hibernate Maven Plugin +weight: 0 +outputs: + - html +url: /projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/ +layout: article +params: + current: false + canonical: /hibernate-maven-plugin/ +--- +
+

Hibernate Maven Plugin

+

This is a development snapshot (2.1.2-SNAPSHOT). +The current stable release is 2.1.1.

+
+

A simple plugin for generating a database-schema from Hibernate-Mappings

+

The hibernate-maven-plugin is a plugin for generating a database-schema +from your Hibernate-Mappings and create or update your database accordingly. +Its main usage is to automatically create and populate a test-database for +unit-tests in cooperation with the +dbunit-maven-plugin.

+
+

Releases

+ +
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/configuration.html b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/configuration.html new file mode 100644 index 00000000..0664763d --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/configuration.html @@ -0,0 +1,33 @@ +--- +title: Configuration Examples +weight: 20 +outputs: + - html +url: /projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/configuration.html +layout: article +params: + current: false + canonical: /hibernate-maven-plugin/configuration.html +--- +
+

Configuration Examples

+

Configuration Through A Configuration-File

+

The most simple way to configure the plugin is, to put all the hibernate-configuration +in a hibernate.properties- or a hibernate.cfg.xml-file on your classpath +or in the persistence.xml-file of your JPA-configuration, just like you would +do, if you are not using the hibernate-maven-plugin at all.

+

In that case, the only configuration needed in the pom.xml is:

+
<plugin>
+  <groupId>de.juplo</groupId>
+  <artifactId>hibernate-maven-plugin</artifactId>
+  <version>2.1.2-SNAPSHOT</version>
+  <executions>
+    <execution>
+      <goals>
+        <goal>create</goal>
+      </goals>
+    </execution>
+  </executions>
+</plugin>
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-info/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-info/_index.html new file mode 100644 index 00000000..fd01d861 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-info/_index.html @@ -0,0 +1,33 @@ +--- +title: Project Information +weight: 1 +outputs: + - html +url: /projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-info.html +layout: article +params: + current: false + canonical: /hibernate-maven-plugin/project-info.html +--- +
+
+

Project Information

+

This document provides an overview of the various documents and links that are part +of this project's general information. All of this content is automatically generated +by Maven on behalf of the project.

+
+

Overview

+ + + + + + + + + + +
DocumentDescription
CI ManagementThis document lists the continuous integration management system of this project.
DependenciesThis document lists the project's dependencies and provides information on each dependency.
LicensesThis document lists the project license(s).
TeamThis document provides information on the members of this project.
+
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/_index.html new file mode 100644 index 00000000..ba8a8362 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/_index.html @@ -0,0 +1,30 @@ +--- +title: Project Reports +weight: 12 +outputs: + - html +url: /projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports.html +layout: article +params: + current: false + canonical: /hibernate-maven-plugin/project-reports.html +--- +
+
+

Generated Reports

+

This document provides an overview of the various reports that are automatically +generated by Maven.

+
+

Overview

+ + + + + + + + +
DocumentDescription
JavaDocsThis document contains the JavaDoc API documentation.
Test JavaDocsThis document contains the test JavaDoc API documentation.
Plugin DocumentationThis document lists the plugins goals and their parameters.
+
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/_index.html b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/_index.html new file mode 100644 index 00000000..7ec2fe33 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/_index.html @@ -0,0 +1,28 @@ +--- +title: Plugin Documentation +weight: 19 +outputs: + - html +url: /projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/plugin-info.html +layout: article +params: + current: false + canonical: /hibernate-maven-plugin/plugin-info.html +--- +
+
+

Plugin Documentation

+

Goals available for this plugin:

+ + + + + + + + + + +
GoalDescription
hibernate:createCreates the database schema using Hibernate.
hibernate:dropDrops the database schema using Hibernate.
hibernate:updateUpdates the database schema using Hibernate.
hibernate:helpDisplay help information on hibernate-maven-plugin.
+
+
diff --git a/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/create-mojo.html b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/create-mojo.html new file mode 100644 index 00000000..8d4bd7e7 --- /dev/null +++ b/src/content/projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/project-reports/plugin-info/create-mojo.html @@ -0,0 +1,18 @@ +--- +title: "Goal — hibernate:create" +weight: 21 +outputs: + - html +url: /projects/hibernate-maven-plugin/2.1.2-SNAPSHOT/create-mojo.html +layout: article +params: + current: false + canonical: /hibernate-maven-plugin/create-mojo.html +--- +
+
+

hibernate:create

+

Full name: de.juplo:hibernate-maven-plugin:2.1.2-SNAPSHOT:create

+

Description: Creates the database-schema from Hibernate-Mappings.

+
+
diff --git a/src/lib/projects.ts b/src/lib/projects.ts new file mode 100644 index 00000000..79abcf9b --- /dev/null +++ b/src/lib/projects.ts @@ -0,0 +1,175 @@ +import { getCollection, type CollectionEntry } from 'astro:content'; +import { readdirSync } from 'node:fs'; +import { resolve } from 'node:path'; + +export type ProjectPage = CollectionEntry<'projects'>; + +export interface ProjectNavNode { + title: string; + url: string; + weight: number; + isNode: boolean; // true when this entry is a section (_index.html) + children: ProjectNavNode[]; +} + +export interface ProjectInfo { + slug: string; // e.g. 'hibernate-maven-plugin' + version: string; // e.g. '2.1.1' or '2.1.2-SNAPSHOT' + isCurrent: boolean; + navRoot: ProjectNavNode; +} + +// Detect generated-content dirs (apidocs, xref, etc.) in public/projects/X/Y/ +const GENERATED_DOC_NAMES: Record = { + apidocs: 'JavaDocs', + testapidocs: 'Test JavaDocs', + xref: 'Source Xref', + 'xref-test': 'Test Source Xref', +}; + +function generatedDocNodes(projectSlug: string, version: string, isCurrent: boolean): ProjectNavNode[] { + const baseUrl = `/projects/${projectSlug}/${version}/`; + const nodes: ProjectNavNode[] = []; + const pubDir = resolve(`./public/projects/${projectSlug}/${version}`); + let entries: string[] = []; + try { entries = readdirSync(pubDir); } catch { return []; } + for (const [dirName, title] of Object.entries(GENERATED_DOC_NAMES)) { + if (entries.includes(dirName)) { + nodes.push({ title, url: `${baseUrl}${dirName}/`, weight: -1, isNode: false, children: [] }); + } + } + return nodes; +} + +// Build a nav tree for a single version from the collection entries. +// The hierarchy is derived from the filesystem path (id): +// X/Y/_index.html → root node +// X/Y/page.html → direct child of root +// X/Y/sub/_index.html → direct child of root (section node) +// X/Y/sub/page.html → child of sub +function buildNavTree( + pages: ProjectPage[], + projectSlug: string, + version: string, +): ProjectNavNode | null { + // Find the root entry (_index.html at version level) + const rootEntry = pages.find(p => p.id === `${projectSlug}/${version}/_index.html`); + if (!rootEntry) return null; + + function makeNode(entry: ProjectPage): ProjectNavNode { + const idPath = entry.id; // e.g. "hibernate-maven-plugin/2.1.1/project-reports/plugin-info/_index.html" + const versionPrefix = `${projectSlug}/${version}/`; + const rel = idPath.slice(versionPrefix.length); // e.g. "project-reports/plugin-info/_index.html" + const isNode = rel.endsWith('/_index.html') || rel === '_index.html'; + + // Find direct children: entries whose path is one level deeper inside the same dir + const relDir = isNode + ? (rel === '_index.html' ? '' : rel.replace('/_index.html', '/')) + : null; + + const children: ProjectNavNode[] = []; + if (relDir !== null) { + for (const child of pages) { + if (child.id === entry.id) continue; + const childRel = child.id.slice(versionPrefix.length); + if (!childRel.startsWith(relDir)) continue; + const remainder = childRel.slice(relDir.length); // e.g. "sub/_index.html" or "page.html" + // Direct child: either "page.html" (no slash) or "sub/_index.html" (one slash, ends with _index.html) + const isDirectChild = + (!remainder.includes('/')) || + (remainder.indexOf('/') === remainder.lastIndexOf('/') && remainder.endsWith('/_index.html')); + if (isDirectChild) { + children.push(makeNode(child)); + } + } + // Add generated-content nodes under root or under project-reports + const isReports = rel === 'project-reports/_index.html' || rel === '_index.html'; + if (rel === 'project-reports/_index.html') { + children.push(...generatedDocNodes(projectSlug, version, entry.data.params.current)); + } + } + + children.sort((a, b) => a.weight - b.weight); + + return { + title: entry.data.title, + url: entry.data.url, + weight: entry.data.weight, + isNode, + children, + }; + } + + return makeNode(rootEntry); +} + +let _cachedPages: ProjectPage[] | null = null; + +export async function getAllProjectPages(): Promise { + if (!_cachedPages) _cachedPages = await getCollection('projects'); + return _cachedPages; +} + +// Returns ProjectInfo for the version the user is currently browsing, +// or null if currentUrl is not a project page. +export async function getActiveProject(currentUrl: string): Promise { + const pages = await getAllProjectPages(); + + // Non-visible: URL matches /projects/X/Y/... + const nonVisibleMatch = currentUrl.match(/^\/projects\/([^/]+)\/([^/]+)\//); + if (nonVisibleMatch) { + const [, projectSlug, version] = nonVisibleMatch; + const versionPages = pages.filter(p => p.id.startsWith(`${projectSlug}/${version}/`)); + if (versionPages.length === 0) return null; + const navRoot = buildNavTree(versionPages, projectSlug, version); + if (!navRoot) return null; + return { slug: projectSlug, version, isCurrent: false, navRoot }; + } + + // Visible: currentUrl matches the url of a current: true page + const visibleRoot = pages.find( + p => p.data.params.current && p.id.endsWith('/_index.html') && p.data.url === currentUrl + ); + if (visibleRoot) { + const [projectSlug, version] = visibleRoot.id.split('/'); + const versionPages = pages.filter(p => p.id.startsWith(`${projectSlug}/${version}/`)); + const navRoot = buildNavTree(versionPages, projectSlug, version); + if (!navRoot) return null; + return { slug: projectSlug, version, isCurrent: true, navRoot }; + } + + // Also handle sub-pages of a visible project + const visiblePage = pages.find(p => p.data.params.current && p.data.url === currentUrl); + if (visiblePage) { + const [projectSlug, version] = visiblePage.id.split('/'); + const versionPages = pages.filter(p => p.id.startsWith(`${projectSlug}/${version}/`)); + const navRoot = buildNavTree(versionPages, projectSlug, version); + if (!navRoot) return null; + return { slug: projectSlug, version, isCurrent: true, navRoot }; + } + + return null; +} + +// Returns the nav tree for ALL visible projects (for the normal-case nav). +export async function getVisibleProjectNavTrees(): Promise { + const pages = await getAllProjectPages(); + const seen = new Set(); + const result: ProjectInfo[] = []; + + for (const page of pages) { + if (!page.data.params.current) continue; + if (!page.id.endsWith('/_index.html')) continue; + const parts = page.id.split('/'); + if (parts.length < 3) continue; // must be X/Y/_index.html + const [projectSlug, version] = parts; + const key = `${projectSlug}/${version}`; + if (seen.has(key)) continue; + seen.add(key); + const versionPages = pages.filter(p => p.id.startsWith(`${key}/`)); + const navRoot = buildNavTree(versionPages, projectSlug, version); + if (navRoot) result.push({ slug: projectSlug, version, isCurrent: true, navRoot }); + } + + return result; +} -- 2.39.5