Skip to content

Commit 2caf875

Browse files
committed
feat: add TypeScript API docs generator and workflow
Adds a script that generates crawlable HTML API reference pages from @openui5/types and @sapui5/types npm packages using TypeDoc. Pipeline: 1. Install types package (pinned, --ignore-scripts, allowlisted) 2. Preprocess .d.ts (rename default exports to named, collect export map) 3. Run TypeDoc with markdown plugin 4. Strip inherited members (reduces ~300MB to ~47MB) 5. Render minimal static HTML with import hints, breadcrumbs, sitemap GitHub Actions workflow: - Nightly cron (cheap version check via .version marker files) - Fetches LTS + latest versions from versionoverview.json (hard floor: 1.120) - Generates only versions with new patches, skips up-to-date ones - Resilient: one failure does not block other versions - Manual workflow_dispatch for on-demand generation Security: - .npmrc: registry pin, ignore-scripts, allow-git=none, min-release-age - All deps pinned to exact versions with committed lockfile - Actions pinned to SHA digests with version comments - Workflow permissions scoped (contents:read default, write at job level) - Node version pinned to exact patch - No npx in generator (local bin path only) - Types packages allowlisted
1 parent ef8c6ec commit 2caf875

6 files changed

Lines changed: 1631 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
Add TypeScript API docs generator and GitHub Actions workflow (infrastructure only, no package changes).
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
name: Generate TypeScript API Docs
2+
3+
on:
4+
schedule:
5+
# Check nightly — generation only runs if new versions are detected
6+
- cron: "17 4 * * *"
7+
workflow_dispatch:
8+
inputs:
9+
versions:
10+
description: "Specific versions to generate (comma-separated, e.g. '1.148.1,1.120.25'). Leave empty for auto-detect from maintenance versions."
11+
required: false
12+
default: ""
13+
14+
permissions:
15+
contents: read
16+
17+
concurrency:
18+
group: generate-api-docs
19+
cancel-in-progress: false
20+
21+
jobs:
22+
generate:
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 90
25+
permissions:
26+
contents: write
27+
steps:
28+
- name: Checkout main (scripts + workflow)
29+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
30+
with:
31+
ref: main
32+
path: main
33+
34+
- name: Checkout gh-pages (published site)
35+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
36+
with:
37+
ref: gh-pages
38+
path: gh-pages
39+
40+
- name: Setup Node.js
41+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
42+
with:
43+
node-version: "22.16.0"
44+
45+
- name: Install generator dependencies
46+
working-directory: main/scripts/generate-api-docs
47+
run: npm ci --ignore-scripts
48+
49+
- name: Determine versions to generate
50+
id: versions
51+
run: |
52+
if [ -n "${{ inputs.versions }}" ]; then
53+
# Manual dispatch with explicit versions
54+
echo "versions=${{ inputs.versions }}" >> "$GITHUB_OUTPUT"
55+
echo "Manual versions: ${{ inputs.versions }}"
56+
else
57+
# Auto-detect: fetch LTS + latest versions from version overview APIs
58+
# Then find the latest patch of each that has a types package on npm
59+
VERSIONS=""
60+
61+
for OVERVIEW_URL in "https://sdk.openui5.org/versionoverview.json" "https://ui5.sap.com/versionoverview.json"; do
62+
# Get LTS versions + the latest (highest) maintenance version
63+
# Filter: lts===true OR highest minor. Hard floor: minor >= 120.
64+
MAINT_LINES=$(curl -sf "$OVERVIEW_URL" | node -e "
65+
const data = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
66+
const maintained = data.versions.filter(v => v.support === 'Maintenance');
67+
const latest = maintained[0]; // first entry is always the newest
68+
const lines = maintained
69+
.filter(v => v.lts === true || v === latest)
70+
.map(v => v.version.replace('.*',''))
71+
.filter(v => parseInt(v.split('.')[1]) >= 120);
72+
console.log(lines.join(' '));
73+
")
74+
75+
PKG=$( [[ "$OVERVIEW_URL" == *"openui5"* ]] && echo "@openui5/types" || echo "@sapui5/types" )
76+
77+
for LINE in $MAINT_LINES; do
78+
# Get the latest published patch for this minor line
79+
LATEST=$(npm show "${PKG}@~${LINE}.0" version 2>/dev/null | tail -1)
80+
if [ -n "$LATEST" ]; then
81+
VERSIONS="${VERSIONS}${VERSIONS:+,}${PKG}@${LATEST}"
82+
fi
83+
done
84+
done
85+
86+
echo "versions=$VERSIONS" >> "$GITHUB_OUTPUT"
87+
echo "Detected versions: $VERSIONS"
88+
fi
89+
90+
- name: Generate API docs
91+
working-directory: main/scripts/generate-api-docs
92+
run: |
93+
IFS=',' read -ra ENTRIES <<< "${{ steps.versions.outputs.versions }}"
94+
GENERATED=""
95+
96+
for ENTRY in "${ENTRIES[@]}"; do
97+
# Skip empty entries (from trailing commas or empty versions output)
98+
[[ -z "$ENTRY" ]] && continue
99+
100+
# Parse: either "@openui5/types@1.148.1" or just "1.148.1" (defaults to @openui5/types)
101+
if [[ "$ENTRY" == @* ]]; then
102+
PKG=$(echo "$ENTRY" | sed 's/@[^@]*$//')
103+
VERSION=$(echo "$ENTRY" | sed 's/.*@//')
104+
else
105+
PKG="@openui5/types"
106+
VERSION="$ENTRY"
107+
fi
108+
109+
FRAMEWORK=$( [[ "$PKG" == *"openui5"* ]] && echo "openui5" || echo "sapui5" )
110+
DIR=$(echo "$VERSION" | sed 's/\([0-9]*\.[0-9]*\).*/\1/')
111+
112+
# Validate VERSION looks like semver and DIR like major.minor
113+
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
114+
echo "⚠ Invalid version format: '$VERSION' — skipping"
115+
continue
116+
fi
117+
118+
# Check if this exact version is already generated
119+
VERSION_FILE="../../../gh-pages/api/${FRAMEWORK}/${DIR}/.version"
120+
if [ -f "$VERSION_FILE" ]; then
121+
EXISTING=$(cat "$VERSION_FILE")
122+
if [ "$EXISTING" = "$VERSION" ]; then
123+
echo "✓ ${FRAMEWORK} ${VERSION} already up to date — skipping"
124+
continue
125+
else
126+
echo "↻ ${FRAMEWORK} ${EXISTING} → ${VERSION} (updating)"
127+
fi
128+
else
129+
echo "+ ${FRAMEWORK} ${VERSION} (new)"
130+
fi
131+
132+
# Generate into a temp directory; only replace target on success
133+
TEMP_OUT="../../../gh-pages/api/${FRAMEWORK}/${DIR}.tmp"
134+
TARGET="../../../gh-pages/api/${FRAMEWORK}/${DIR}"
135+
if node generate.mjs \
136+
--package "$PKG" \
137+
--version "$VERSION" \
138+
--out "$TEMP_OUT" \
139+
--base-url "https://ui5.github.io/typescript/api/${FRAMEWORK}/${DIR}/"; then
140+
rm -rf "$TARGET"
141+
mv "$TEMP_OUT" "$TARGET"
142+
GENERATED="${GENERATED}${GENERATED:+, }${FRAMEWORK}@${VERSION}"
143+
else
144+
echo "⚠ FAILED: ${FRAMEWORK} ${VERSION} — keeping existing docs"
145+
rm -rf "$TEMP_OUT"
146+
fi
147+
done
148+
149+
echo "generated=$GENERATED" >> "$GITHUB_OUTPUT"
150+
if [ -z "$GENERATED" ]; then
151+
echo "All versions up to date — nothing to generate"
152+
fi
153+
154+
- name: Commit and push to gh-pages
155+
working-directory: gh-pages
156+
run: |
157+
git config user.name "github-actions[bot]"
158+
git config user.email "github-actions[bot]@users.noreply.github.com"
159+
git add api/
160+
if git diff --cached --quiet; then
161+
echo "No changes to commit"
162+
else
163+
git commit -m "docs: update TypeScript API reference"
164+
git push
165+
fi

scripts/generate-api-docs/.npmrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
registry=https://registry.npmjs.org/
2+
ignore-scripts=true
3+
allow-git=none
4+
min-release-age=7
5+
save-exact=true

0 commit comments

Comments
 (0)