diff --git a/.changeset/add-api-docs-generator.md b/.changeset/add-api-docs-generator.md new file mode 100644 index 0000000..9591545 --- /dev/null +++ b/.changeset/add-api-docs-generator.md @@ -0,0 +1,4 @@ +--- +--- + +Add TypeScript API docs generator and GitHub Actions workflow (infrastructure only, no package changes). diff --git a/.github/workflows/generate-api-docs.yml b/.github/workflows/generate-api-docs.yml new file mode 100644 index 0000000..3384e48 --- /dev/null +++ b/.github/workflows/generate-api-docs.yml @@ -0,0 +1,165 @@ +name: Generate TypeScript API Docs + +on: + schedule: + # Check nightly — generation only runs if new versions are detected + - cron: "17 4 * * *" + workflow_dispatch: + inputs: + versions: + description: "Specific versions to generate (comma-separated, e.g. '1.148.1,1.120.25'). Leave empty for auto-detect from maintenance versions." + required: false + default: "" + +permissions: + contents: read + +concurrency: + group: generate-api-docs + cancel-in-progress: false + +jobs: + generate: + runs-on: ubuntu-latest + timeout-minutes: 90 + permissions: + contents: write + steps: + - name: Checkout main (scripts + workflow) + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + ref: main + path: main + + - name: Checkout gh-pages (published site) + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + with: + ref: gh-pages + path: gh-pages + + - name: Setup Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22.16.0" + + - name: Install generator dependencies + working-directory: main/scripts/generate-api-docs + run: npm ci --ignore-scripts + + - name: Determine versions to generate + id: versions + run: | + if [ -n "${{ inputs.versions }}" ]; then + # Manual dispatch with explicit versions + echo "versions=${{ inputs.versions }}" >> "$GITHUB_OUTPUT" + echo "Manual versions: ${{ inputs.versions }}" + else + # Auto-detect: fetch LTS + latest versions from version overview APIs + # Then find the latest patch of each that has a types package on npm + VERSIONS="" + + for OVERVIEW_URL in "https://sdk.openui5.org/versionoverview.json" "https://ui5.sap.com/versionoverview.json"; do + # Get LTS versions + the latest (highest) maintenance version + # Filter: lts===true OR highest minor. Hard floor: minor >= 120. + MAINT_LINES=$(curl -sf "$OVERVIEW_URL" | node -e " + const data = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); + const maintained = data.versions.filter(v => v.support === 'Maintenance'); + const latest = maintained[0]; // first entry is always the newest + const lines = maintained + .filter(v => v.lts === true || v === latest) + .map(v => v.version.replace('.*','')) + .filter(v => parseInt(v.split('.')[1]) >= 120); + console.log(lines.join(' ')); + ") + + PKG=$( [[ "$OVERVIEW_URL" == *"openui5"* ]] && echo "@openui5/types" || echo "@sapui5/types" ) + + for LINE in $MAINT_LINES; do + # Get the latest published patch for this minor line + LATEST=$(npm show "${PKG}@~${LINE}.0" version 2>/dev/null | tail -1) + if [ -n "$LATEST" ]; then + VERSIONS="${VERSIONS}${VERSIONS:+,}${PKG}@${LATEST}" + fi + done + done + + echo "versions=$VERSIONS" >> "$GITHUB_OUTPUT" + echo "Detected versions: $VERSIONS" + fi + + - name: Generate API docs + working-directory: main/scripts/generate-api-docs + run: | + IFS=',' read -ra ENTRIES <<< "${{ steps.versions.outputs.versions }}" + GENERATED="" + + for ENTRY in "${ENTRIES[@]}"; do + # Skip empty entries (from trailing commas or empty versions output) + [[ -z "$ENTRY" ]] && continue + + # Parse: either "@openui5/types@1.148.1" or just "1.148.1" (defaults to @openui5/types) + if [[ "$ENTRY" == @* ]]; then + PKG=$(echo "$ENTRY" | sed 's/@[^@]*$//') + VERSION=$(echo "$ENTRY" | sed 's/.*@//') + else + PKG="@openui5/types" + VERSION="$ENTRY" + fi + + FRAMEWORK=$( [[ "$PKG" == *"openui5"* ]] && echo "openui5" || echo "sapui5" ) + DIR=$(echo "$VERSION" | sed 's/\([0-9]*\.[0-9]*\).*/\1/') + + # Validate VERSION looks like semver and DIR like major.minor + if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "⚠ Invalid version format: '$VERSION' — skipping" + continue + fi + + # Check if this exact version is already generated + VERSION_FILE="../../../gh-pages/api/${FRAMEWORK}/${DIR}/.version" + if [ -f "$VERSION_FILE" ]; then + EXISTING=$(cat "$VERSION_FILE") + if [ "$EXISTING" = "$VERSION" ]; then + echo "✓ ${FRAMEWORK} ${VERSION} already up to date — skipping" + continue + else + echo "↻ ${FRAMEWORK} ${EXISTING} → ${VERSION} (updating)" + fi + else + echo "+ ${FRAMEWORK} ${VERSION} (new)" + fi + + # Generate into a temp directory; only replace target on success + TEMP_OUT="../../../gh-pages/api/${FRAMEWORK}/${DIR}.tmp" + TARGET="../../../gh-pages/api/${FRAMEWORK}/${DIR}" + if node generate.mjs \ + --package "$PKG" \ + --version "$VERSION" \ + --out "$TEMP_OUT" \ + --base-url "https://ui5.github.io/typescript/api/${FRAMEWORK}/${DIR}/"; then + rm -rf "$TARGET" + mv "$TEMP_OUT" "$TARGET" + GENERATED="${GENERATED}${GENERATED:+, }${FRAMEWORK}@${VERSION}" + else + echo "⚠ FAILED: ${FRAMEWORK} ${VERSION} — keeping existing docs" + rm -rf "$TEMP_OUT" + fi + done + + echo "generated=$GENERATED" >> "$GITHUB_OUTPUT" + if [ -z "$GENERATED" ]; then + echo "All versions up to date — nothing to generate" + fi + + - name: Commit and push to gh-pages + working-directory: gh-pages + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add api/ + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "docs: update TypeScript API reference" + git push + fi diff --git a/scripts/generate-api-docs/.npmrc b/scripts/generate-api-docs/.npmrc new file mode 100644 index 0000000..61c3c63 --- /dev/null +++ b/scripts/generate-api-docs/.npmrc @@ -0,0 +1,5 @@ +registry=https://registry.npmjs.org/ +ignore-scripts=true +allow-git=none +min-release-age=7 +save-exact=true diff --git a/scripts/generate-api-docs/generate.mjs b/scripts/generate-api-docs/generate.mjs new file mode 100644 index 0000000..53d4b9d --- /dev/null +++ b/scripts/generate-api-docs/generate.mjs @@ -0,0 +1,518 @@ +#!/usr/bin/env node +/** + * Generates crawlable HTML API documentation from @openui5/types or @sapui5/types. + * + * Pipeline: + * 1. Preprocess .d.ts files (rename default exports to named exports) + * 2. Run TypeDoc with markdown plugin + * 3. Strip inherited members from markdown + * 4. Render markdown to minimal semantic HTML + * + * Usage: + * node generate.mjs --package @openui5/types --version 1.149.0 --out ../../api/openui5/1.149 + * node generate.mjs --package @sapui5/types --version 1.148.1 --out ../../api/sapui5/1.148 + */ + +import { execSync, spawnSync } from "child_process"; +import { + readFileSync, + writeFileSync, + mkdirSync, + readdirSync, + statSync, + rmSync, + existsSync, + cpSync, +} from "fs"; +import { join, dirname, relative, basename } from "path"; +import { marked } from "marked"; +import { fileURLToPath } from "url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +// Sanitize: strip raw HTML from markdown to prevent XSS in published pages +const renderer = new marked.Renderer(); +renderer.html = () => ""; // strip raw HTML blocks to prevent XSS +marked.use({ renderer }); + +// Normalize path separators to POSIX (for Windows compatibility) +const posix = (p) => p.split("\\").join("/"); + +// Parse args +const args = process.argv.slice(2); +function getArg(name) { + const idx = args.indexOf(`--${name}`); + return idx >= 0 ? args[idx + 1] : undefined; +} + +const PKG = getArg("package") || "@openui5/types"; +const VERSION = getArg("version") || "latest"; +const OUT_DIR = getArg("out") || join(__dirname, "../../api/openui5/latest"); +const BASE_URL = getArg("base-url") || "https://ui5.github.io/typescript/api/openui5/latest/"; + +const WORK_DIR = join(__dirname, ".work"); +const TYPES_DIR = join(WORK_DIR, "types-modified"); +const MD_DIR = join(WORK_DIR, "docs-md"); + +console.log(`Generating docs for ${PKG}@${VERSION}`); +console.log(`Output: ${OUT_DIR}`); +console.log(); + +// --- Step 0: Install the types package --- +// Only @openui5/types and @sapui5/types are allowed — they are pure .d.ts packages +// with no install scripts, no native dependencies, no transitive deps. +const ALLOWED_PACKAGES = ["@openui5/types", "@sapui5/types"]; +if (!ALLOWED_PACKAGES.includes(PKG)) { + console.error(`Error: Only ${ALLOWED_PACKAGES.join(", ")} are supported. Got: ${PKG}`); + process.exit(1); +} + +console.log("Step 0: Installing types package..."); +mkdirSync(WORK_DIR, { recursive: true }); +writeFileSync( + join(WORK_DIR, "package.json"), + JSON.stringify({ name: "work", private: true, dependencies: { [PKG]: VERSION } }) +); +// --ignore-scripts: never run install hooks from the types package +// --no-audit: don't phone home +// --no-fund: suppress noise +execSync("npm install --ignore-scripts --no-audit --no-fund", { cwd: WORK_DIR, stdio: "pipe" }); + +// Find the types directory +const pkgDir = join(WORK_DIR, "node_modules", ...PKG.split("/")); +const typesDir = join(pkgDir, "types"); +if (!existsSync(typesDir)) { + console.error(`Types directory not found: ${typesDir}`); + process.exit(1); +} + +// Get actual installed version +const pkgJson = JSON.parse(readFileSync(join(pkgDir, "package.json"), "utf8")); +const actualVersion = pkgJson.version; +console.log(` Installed: ${PKG}@${actualVersion}`); + +// --- Step 1: Preprocess .d.ts files --- +console.log("\nStep 1: Preprocessing .d.ts files (rename default exports)..."); +if (existsSync(TYPES_DIR)) rmSync(TYPES_DIR, { recursive: true }); +cpSync(typesDir, TYPES_DIR, { recursive: true }); + +const dtsFiles = readdirSync(TYPES_DIR).filter((f) => f.endsWith(".d.ts")); +let totalReplacements = 0; + +// First pass: collect which names are default exports per module +// Maps module path → default export name, e.g. "sap/m/Button" → "Button", "sap/ui/core/Element" → "UI5Element" +const defaultExports = new Map(); + +for (const file of dtsFiles) { + const filePath = join(TYPES_DIR, file); + const content = readFileSync(filePath, "utf8"); + + // Find: declare module "sap/m/Button" { ... export default class Button + const moduleRegex = /^declare module "([^"]+)"/gm; + let moduleMatch; + while ((moduleMatch = moduleRegex.exec(content)) !== null) { + const moduleName = moduleMatch[1]; + const moduleStart = moduleMatch.index; + // Find the next declare module to bound our search + const nextModule = content.indexOf("\ndeclare module ", moduleStart + 1); + const moduleBody = content.slice(moduleStart, nextModule > 0 ? nextModule : undefined); + + // Look for "export default class X" or "export default abstract class X" + const defaultClassMatch = moduleBody.match(/export default (?:abstract )?class ([A-Z][A-Za-z0-9_]*)/); + if (defaultClassMatch) { + defaultExports.set(moduleName, defaultClassMatch[1]); + continue; + } + // Look for "export default enum X" + const defaultEnumMatch = moduleBody.match(/export default enum ([A-Z][A-Za-z0-9_]*)/); + if (defaultEnumMatch) { + defaultExports.set(moduleName, defaultEnumMatch[1]); + continue; + } + // Look for "export default function X" + const defaultFuncMatch = moduleBody.match(/export default function ([A-Za-z_][A-Za-z0-9_]*)/); + if (defaultFuncMatch) { + defaultExports.set(moduleName, defaultFuncMatch[1]); + continue; + } + // Look for "export default interface X" + const defaultIfaceMatch = moduleBody.match(/export default interface ([A-Z][A-Za-z0-9_]*)/); + if (defaultIfaceMatch) { + defaultExports.set(moduleName, defaultIfaceMatch[1]); + continue; + } + // Look for "export default X;" (re-export) + const defaultReexportMatch = moduleBody.match(/^\s*export default ([A-Z][A-Za-z0-9_]*);/m); + if (defaultReexportMatch) { + defaultExports.set(moduleName, defaultReexportMatch[1]); + } + } +} +console.log(` Found ${defaultExports.size} default exports`); + +// Second pass: rewrite the files +for (const file of dtsFiles) { + const filePath = join(TYPES_DIR, file); + let content = readFileSync(filePath, "utf8"); + const original = content; + // Rename all forms of default exports to named exports + content = content.replace(/export default class /g, "export class "); + content = content.replace(/export default abstract class /g, "export abstract class "); + content = content.replace(/export default enum /g, "export enum "); + content = content.replace(/export default function /g, "export function "); + content = content.replace(/export default interface /g, "export interface "); + // "export default Foo;" (re-export of a value/type) → remove the line + content = content.replace(/^\s*export default [A-Z][A-Za-z0-9_]*;\s*$/gm, ""); + // Fix destructured default imports: { default as Foo } → { Foo } + // Handles both single-line and multi-line cases + content = content.replace(/\{ default as ([A-Za-z_][A-Za-z0-9_]*)/g, "{ $1"); + content = content.replace(/^\s*default as ([A-Za-z_][A-Za-z0-9_]*),?/gm, " $1,"); + // Fix bare default imports: import Foo from "..." → import { Foo } from "..." + content = content.replace(/^(\s*)import ([A-Z][A-Za-z0-9_]*) from (".*");/gm, '$1import { $2 } from $3;'); + if (content !== original) totalReplacements++; + writeFileSync(filePath, content); +} +console.log(` Modified ${totalReplacements}/${dtsFiles.length} files`); + +// --- Step 2: Run TypeDoc with markdown plugin --- +console.log("\nStep 2: Running TypeDoc (markdown output)..."); +if (existsSync(MD_DIR)) rmSync(MD_DIR, { recursive: true }); + +// Write tsconfig for TypeDoc +writeFileSync( + join(WORK_DIR, "tsconfig.json"), + JSON.stringify({ + compilerOptions: { + target: "ES2020", + module: "ES2020", + moduleResolution: "bundler", + skipLibCheck: true, + noEmit: true, + strict: false, + }, + include: ["./types-modified/**/*.d.ts"], + }) +); + +// Write TypeDoc config +writeFileSync( + join(WORK_DIR, "typedoc.json"), + JSON.stringify({ + $schema: "https://typedoc.org/schema.json", + entryPoints: ["./types-modified"], + entryPointStrategy: "expand", + tsconfig: "./tsconfig.json", + skipErrorChecking: true, + out: "./docs-md", + name: `${PKG.includes("openui5") ? "OpenUI5" : "SAPUI5"} TypeScript API (${actualVersion})`, + readme: "none", + disableSources: true, + includeVersion: false, + excludeExternals: false, + excludePrivate: true, + excludeProtected: true, + plugin: ["typedoc-plugin-markdown"], + }) +); + +// Run TypeDoc via its CLI entry point (cross-platform, no npx) +const typedocCli = join(__dirname, "node_modules/typedoc/bin/typedoc"); +const typedocResult = spawnSync(process.execPath, [typedocCli], { + cwd: WORK_DIR, + stdio: ["pipe", "pipe", "pipe"], + maxBuffer: 100 * 1024 * 1024, // 100 MB buffer for warnings +}); +if (typedocResult.status !== 0 && !typedocResult.stdout.toString().includes("generated at")) { + console.error("TypeDoc failed:", typedocResult.stderr?.toString().slice(-500)); + process.exit(1); +} +console.log(" TypeDoc complete"); + +// --- Step 3: Strip inherited members --- +console.log("\nStep 3: Stripping inherited members..."); +let strippedCount = 0; + +function stripInherited(content) { + const lines = content.split("\n"); + const output = []; + let i = 0; + + while (i < lines.length) { + const line = lines[i]; + + // Check if this is a method/property section (### heading) + if (line.startsWith("### ")) { + // Collect the full section until next ### or EOF + let j = i + 1; + const sectionLines = [line]; + let hasInherited = false; + + while (j < lines.length && !lines[j].startsWith("### ")) { + sectionLines.push(lines[j]); + if ( + lines[j].trim().startsWith("#### Inherited from") || + lines[j].trim().startsWith("##### Inherited from") + ) { + hasInherited = true; + } + j++; + } + + if (hasInherited) { + // Skip this entire section + strippedCount++; + i = j; + continue; + } else { + output.push(...sectionLines); + i = j; + continue; + } + } else { + output.push(line); + i++; + } + } + + return output.join("\n"); +} + +function stripDefaultListEntries(content) { + // Remove list items linking to "default" from module READMEs + // These are ghost entries from the original default export + // Handles plain, deprecated (~~), and any markdown formatting around "default" + return content.replace(/^-\s*\[(?:~~)?default(?:~~)?\]\([^)]*default[^)]*\)\s*$/gm, ""); +} + +function processMarkdownDir(dir) { + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + const stat = statSync(full); + if (stat.isDirectory()) { + processMarkdownDir(full); + } else if (entry.endsWith(".md")) { + let content = readFileSync(full, "utf8"); + content = stripInherited(content); + content = stripDefaultListEntries(content); + writeFileSync(full, content); + } + } +} + +processMarkdownDir(MD_DIR); +console.log(` Stripped ${strippedCount} inherited sections`); + +// --- Step 4: Render to minimal HTML --- +console.log("\nStep 4: Rendering to minimal HTML..."); +if (existsSync(OUT_DIR)) rmSync(OUT_DIR, { recursive: true }); +mkdirSync(OUT_DIR, { recursive: true }); + +const frameworkName = PKG.includes("openui5") ? "OpenUI5" : "SAPUI5"; + +const CSS = `body{font-family:system-ui,-apple-system,sans-serif;max-width:56em;margin:0 auto;padding:1.5em;line-height:1.6;color:#1a1a2e} +pre{background:#f6f8fa;padding:1em;overflow-x:auto;border-radius:6px;border:1px solid #e1e4e8} +code{font-size:0.88em;background:#f6f8fa;padding:0.15em 0.4em;border-radius:3px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace} +pre code{background:none;padding:0;font-size:0.85em} +a{color:#0366d6;text-decoration:none}a:hover{text-decoration:underline} +h1{border-bottom:2px solid #e1e4e8;padding-bottom:0.3em;margin-top:0} +h2{border-bottom:1px solid #e8e8e8;padding-bottom:0.2em;margin-top:2em} +h3{margin-top:1.8em;color:#24292e} +h4,h5{margin-top:1em} +nav{font-size:0.85em;color:#586069;margin-bottom:1.5em;padding:0.5em 0;border-bottom:1px solid #e1e4e8} +nav a{margin-right:0.3em} +ul{padding-left:1.5em} +blockquote{border-left:3px solid #dfe2e5;padding-left:1em;color:#6a737d;margin:1em 0} +blockquote code{color:#005cc5} +hr{border:none;border-top:1px solid #e1e4e8;margin:2em 0} +footer{margin-top:3em;padding-top:1em;border-top:1px solid #e1e4e8;font-size:0.8em;color:#6a737d} +/* Syntax highlighting for TypeScript signatures */ +.sig{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:0.88em;background:#f6f8fa;border:1px solid #e1e4e8;border-radius:6px;padding:0.6em 1em;display:block;overflow-x:auto;margin:0.5em 0} +.kw{color:#d73a49}.tp{color:#6f42c1}.fn{color:#6f42c1}.str{color:#032f62}.cm{color:#6a737d}`; + +function htmlTemplate(title, breadcrumb, content, canonicalUrl) { + return ` + +
+ +default → just the text content
+ htmlFixed = htmlFixed.replace(/([^<]*)<\/a>/g, "$1");
+ htmlFixed = htmlFixed.replace(/([^<]*)<\/code><\/a>/g, "$1");
+
+ // Add import hint for class/interface/type-alias pages
+ // Path pattern: sap.m/sap/m/Button/classes/Button.html → module "sap/m/Button", class "Button"
+ const classMatch = rel.match(/^[^/]+\/(.+)\/(classes|interfaces|type-aliases)\/([^/]+)\.html$/);
+ if (classMatch) {
+ const modulePath = classMatch[1]; // e.g. "sap/m/Button"
+ const exportName = classMatch[3]; // e.g. "Button" or "$AppSettings"
+
+ // Check the actual default export map (collected from the original .d.ts before rewriting)
+ // A name is the default export if it matches what was declared as "export default" in that module
+ const moduleDefaultExport = defaultExports.get(modulePath);
+ const isDefaultExport = exportName === moduleDefaultExport;
+
+ let importHint;
+ if (isDefaultExport) {
+ importHint = `import ${exportName} from "${modulePath}";
`;
+ } else {
+ importHint = `import { ${exportName} } from "${modulePath}";
`;
+ }
+ // Insert after the first ...
(h1 may contain for deprecated items)
+ htmlFixed = htmlFixed.replace(/(.*?<\/h1>)/, `$1\n${importHint}`);
+ }
+
+ writeFileSync(outPath, htmlTemplate(title, breadcrumb, htmlFixed, canonicalUrl));
+ fileCount++;
+ }
+ }
+}
+
+renderDir(MD_DIR);
+console.log(` Rendered ${fileCount} HTML files (skipped ${skippedCount} jQuery-related)`);
+
+// --- Step 5: Generate sitemap ---
+console.log("\nStep 5: Generating sitemap...");
+const sitemapEntries = [];
+
+function collectUrls(dir) {
+ for (const entry of readdirSync(dir)) {
+ const full = join(dir, entry);
+ const stat = statSync(full);
+ if (stat.isDirectory()) {
+ collectUrls(full);
+ } else if (entry.endsWith(".html")) {
+ const rel = posix(relative(OUT_DIR, full));
+ sitemapEntries.push(BASE_URL + rel);
+ }
+ }
+}
+
+collectUrls(OUT_DIR);
+
+const sitemap = `
+
+${sitemapEntries.map((url) => ` ${url} `).join("\n")}
+ `;
+
+writeFileSync(join(OUT_DIR, "sitemap.xml"), sitemap);
+console.log(` Sitemap: ${sitemapEntries.length} URLs`);
+
+// --- Step 6: Generate index page ---
+console.log("\nStep 6: Generating index page...");
+
+// Collect top-level library modules
+const topLibs = readdirSync(OUT_DIR)
+ .filter((d) => d.startsWith("sap.") && statSync(join(OUT_DIR, d)).isDirectory())
+ .sort();
+
+const indexHtml = htmlTemplate(
+ `${frameworkName} TypeScript API (${actualVersion})`,
+ `${frameworkName} versions`,
+ `${frameworkName} TypeScript API
+
Version ${actualVersion} — generated from ${PKG}
+Libraries
+
+${topLibs.map((lib) => ` - ${lib}
`).join("\n")}
+
+`,
+ BASE_URL
+);
+writeFileSync(join(OUT_DIR, "index.html"), indexHtml);
+
+// --- Cleanup ---
+console.log("\nStep 7: Cleanup...");
+rmSync(WORK_DIR, { recursive: true });
+
+// Write version marker (used by CI to detect if regeneration is needed)
+writeFileSync(join(OUT_DIR, ".version"), actualVersion);
+
+// Final stats
+let totalSize = "?";
+try { totalSize = execSync(`du -sh "${OUT_DIR}"`).toString().trim().split("\t")[0]; } catch {}
+console.log(`\n✓ Done! Output: ${OUT_DIR} (${totalSize}, ${fileCount} files)`);
diff --git a/scripts/generate-api-docs/package-lock.json b/scripts/generate-api-docs/package-lock.json
new file mode 100644
index 0000000..a27d240
--- /dev/null
+++ b/scripts/generate-api-docs/package-lock.json
@@ -0,0 +1,921 @@
+{
+ "name": "@ui5/generate-api-docs",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@ui5/generate-api-docs",
+ "dependencies": {
+ "marked": "15.0.12",
+ "typedoc": "0.28.19",
+ "typedoc-plugin-markdown": "4.12.0",
+ "typescript": "5.8.3"
+ },
+ "devDependencies": {
+ "http-server": "14.1.1"
+ }
+ },
+ "node_modules/@gerrit0/mini-shiki": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.23.0.tgz",
+ "integrity": "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/engine-oniguruma": "^3.23.0",
+ "@shikijs/langs": "^3.23.0",
+ "@shikijs/themes": "^3.23.0",
+ "@shikijs/types": "^3.23.0",
+ "@shikijs/vscode-textmate": "^10.0.2"
+ }
+ },
+ "node_modules/@shikijs/engine-oniguruma": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz",
+ "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "3.23.0",
+ "@shikijs/vscode-textmate": "^10.0.2"
+ }
+ },
+ "node_modules/@shikijs/langs": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz",
+ "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "3.23.0"
+ }
+ },
+ "node_modules/@shikijs/themes": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz",
+ "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/types": "3.23.0"
+ }
+ },
+ "node_modules/@shikijs/types": {
+ "version": "3.23.0",
+ "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz",
+ "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@shikijs/vscode-textmate": "^10.0.2",
+ "@types/hast": "^3.0.4"
+ }
+ },
+ "node_modules/@shikijs/vscode-textmate": {
+ "version": "10.0.2",
+ "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
+ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/hast": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
+ "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/unist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
+ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+ "license": "MIT"
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "license": "Python-2.0"
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/basic-auth": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
+ "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/corser": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
+ "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
+ "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
+ "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-encoding": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/http-proxy": {
+ "version": "1.18.1",
+ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eventemitter3": "^4.0.0",
+ "follow-redirects": "^1.0.0",
+ "requires-port": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/http-server": {
+ "version": "14.1.1",
+ "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz",
+ "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "basic-auth": "^2.0.1",
+ "chalk": "^4.1.2",
+ "corser": "^2.0.1",
+ "he": "^1.2.0",
+ "html-encoding-sniffer": "^3.0.0",
+ "http-proxy": "^1.18.1",
+ "mime": "^1.6.0",
+ "minimist": "^1.2.6",
+ "opener": "^1.5.1",
+ "portfinder": "^1.0.28",
+ "secure-compare": "3.0.1",
+ "union": "~0.5.0",
+ "url-join": "^4.0.1"
+ },
+ "bin": {
+ "http-server": "bin/http-server"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/linkify-it": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz",
+ "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^2.0.0"
+ }
+ },
+ "node_modules/lunr": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
+ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
+ "license": "MIT"
+ },
+ "node_modules/markdown-it": {
+ "version": "14.2.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
+ "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "^4.4.0",
+ "linkify-it": "^5.0.1",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.mjs"
+ }
+ },
+ "node_modules/marked": {
+ "version": "15.0.12",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz",
+ "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+ "license": "MIT"
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true,
+ "license": "(WTFPL OR MIT)",
+ "bin": {
+ "opener": "bin/opener-bin.js"
+ }
+ },
+ "node_modules/portfinder": {
+ "version": "1.0.38",
+ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz",
+ "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async": "^3.2.6",
+ "debug": "^4.3.6"
+ },
+ "engines": {
+ "node": ">= 10.12"
+ }
+ },
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.15.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
+ "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/secure-compare": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz",
+ "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+ "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/typedoc": {
+ "version": "0.28.19",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.19.tgz",
+ "integrity": "sha512-wKh+lhdmMFivMlc6vRRcMGXeGEHGU2g8a2CkPTJjJlwRf1iXbimWIPcFolCqe4E0d/FRtGszpIrsp3WLpDB8Pw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@gerrit0/mini-shiki": "^3.23.0",
+ "lunr": "^2.3.9",
+ "markdown-it": "^14.1.1",
+ "minimatch": "^10.2.5",
+ "yaml": "^2.8.3"
+ },
+ "bin": {
+ "typedoc": "bin/typedoc"
+ },
+ "engines": {
+ "node": ">= 18",
+ "pnpm": ">= 10"
+ },
+ "peerDependencies": {
+ "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x"
+ }
+ },
+ "node_modules/typedoc-plugin-markdown": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.12.0.tgz",
+ "integrity": "sha512-eJDEMAfxCmede22c/Jw7d0FA13ggAQv+KkwQYKYCdqI02cin6Rc9QRwbG/7XvvHWinuFejySnZVUWDtvGk3Vbg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "typedoc": "0.28.x"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.8.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+ "license": "MIT"
+ },
+ "node_modules/union": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz",
+ "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==",
+ "dev": true,
+ "dependencies": {
+ "qs": "^6.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/url-join": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+ "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
+ "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+ "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yaml": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
+ "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/eemeli"
+ }
+ }
+ }
+}
diff --git a/scripts/generate-api-docs/package.json b/scripts/generate-api-docs/package.json
new file mode 100644
index 0000000..9f7da4e
--- /dev/null
+++ b/scripts/generate-api-docs/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "@ui5/generate-api-docs",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "generate": "node generate.mjs",
+ "start": "http-server ../../api -o -c-1"
+ },
+ "dependencies": {
+ "marked": "15.0.12",
+ "typedoc": "0.28.19",
+ "typedoc-plugin-markdown": "4.12.0",
+ "typescript": "5.8.3"
+ },
+ "devDependencies": {
+ "http-server": "14.1.1"
+ }
+}