Skip to content

feat(superdoc): scrollToHeading API + fix scrollToComment / scrollToElement in flow layout #3945

feat(superdoc): scrollToHeading API + fix scrollToComment / scrollToElement in flow layout

feat(superdoc): scrollToHeading API + fix scrollToComment / scrollToElement in flow layout #3945

Workflow file for this run

name: CI SuperDoc
permissions:
contents: read
on:
pull_request:
branches: [main, stable, 'release/**']
merge_group:
workflow_dispatch:
concurrency:
group: ci-superdoc-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
detect:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
superdoc: ${{ steps.set.outputs.superdoc }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
id: filter
if: github.event_name == 'pull_request'
with:
filters: |
superdoc:
- 'apps/cli/**'
- 'packages/superdoc/**'
- 'packages/super-editor/**'
- 'packages/layout-engine/**'
- 'packages/word-layout/**'
- 'packages/preset-geometry/**'
- 'packages/document-api/**'
- 'packages/collaboration-yjs/**'
- 'packages/docx-evidence-contracts/**'
- 'shared/**'
- 'tests/**'
- 'scripts/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- 'patches/**'
- '.nvmrc'
- '.prettierrc'
- '.prettierignore'
- 'tsconfig.base.json'
- 'tsconfig.references.json'
- 'vite.sourceResolve.ts'
- 'vitest.baseConfig.ts'
- 'vitest.config.mjs'
- 'eslint.config.mjs'
- '.github/workflows/ci-superdoc.yml'
- id: set
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "superdoc=${{ steps.filter.outputs.superdoc }}" >> "$GITHUB_OUTPUT"
else
echo "superdoc=true" >> "$GITHUB_OUTPUT"
fi
build:
needs: detect
if: needs.detect.outputs.superdoc == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.13
- name: Install canvas system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
libcairo2-dev \
libpango1.0-dev \
libjpeg-dev \
libgif-dev \
librsvg2-dev \
libpixman-1-dev
- name: Install dependencies
run: pnpm install
- name: Lint
run: pnpm run lint
- name: Format check
run: pnpm run format --check
- name: Build
run: pnpm run build
- name: Validate command types
run: node scripts/validate-command-types.mjs
- name: Typecheck
run: pnpm run type-check
- name: Public-contract checkJs (SD-2863)
# Gated subset of public-contract files run with `// @ts-check`. The
# script greps tsc output for errors in the curated file list and
# ignores the wider 1500+ errors from the broader super-editor source
# tree (those are tracked under SD-2863 follow-up tickets).
run: pnpm --filter superdoc run check:jsdoc
- name: Consumer typecheck (matrix)
# The matrix script owns the published-package validation path:
# it packs superdoc, installs the tarball into the standalone
# fixture (`pnpm install --ignore-workspace`), then runs every
# scenario under its declared resolution mode and strictness
# settings. Replaces the pre-SD-2831 bare `tsc --noEmit` step
# so the new pack-and-install scenarios are actually exercised
# in CI, not just locally.
run: |
cd tests/consumer-typecheck
node typecheck-matrix.mjs
- name: Deep public-type audit (report-only)
# Recursive walk of every type reachable from superdoc's public
# exports in the installed tarball. Reports inventory by tier and
# top files. Always exits 0 in default mode; the `--strict` flag
# turns it into a hard gate but is not used in CI yet because the
# current public surface is the accidental declaration graph, not
# a deliberate facade. SD-2966 will define that facade; once it
# lands, this step gets `--strict` added and an allowlist file is
# seeded against the facade-scoped findings. Until then, the step
# provides visibility without the maintenance burden of a giant
# public allowlist.
run: |
cd tests/consumer-typecheck
node deep-type-audit.mjs
- name: Package shape gates
# External package-shape linters (publint + attw) running against
# the packed tarball. Catches manifest issues that the in-repo
# consumer matrix does not see: condition ordering, masquerading
# ESM, missing CDN files, unpublished `source` paths.
run: node tests/consumer-typecheck/package-shape-gate.mjs
unit-tests:
needs: build
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: super-editor-1
shard: '1/4'
- name: super-editor-2
shard: '2/4'
- name: super-editor-3
shard: '3/4'
- name: super-editor-4
shard: '4/4'
- name: other-packages
shard: ''
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.13
- name: Install canvas system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
libcairo2-dev \
libpango1.0-dev \
libjpeg-dev \
libgif-dev \
librsvg2-dev \
libpixman-1-dev
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm run build
- name: Run super-editor tests (shard ${{ matrix.shard }})
if: matrix.name != 'other-packages'
working-directory: packages/super-editor
env:
NODE_OPTIONS: '--max-old-space-size=4096'
run: >-
pnpm exec vitest run --pool forks --minWorkers 1 --maxWorkers 1
--shard=${{ matrix.shard }}
--exclude='**/decrypt-docx.integration*'
--exclude='**/contract-conformance*'
- name: Run other package vitest tests
if: matrix.name == 'other-packages'
env:
NODE_OPTIONS: '--max-old-space-size=4096'
VITEST_MAX_WORKERS: '1'
VITEST_MIN_WORKERS: '1'
run: pnpm exec vitest run '--project=!*super-editor*'
- name: Run bun tests
if: matrix.name == 'other-packages'
run: |
pnpm -r --parallel \
--filter @superdoc/document-api \
--filter @superdoc/layout-engine --filter @superdoc/style-engine \
--filter @superdoc/geometry-utils --filter @superdoc/word-layout \
--filter @superdoc/common --filter @font-utils \
--filter @locale-utils --filter @url-validation \
test
- name: Run SDK scripts tests
if: matrix.name == 'other-packages'
run: pnpm --prefix packages/sdk run test:scripts
- name: Run memory profiling tests (non-blocking)
if: matrix.name == 'other-packages'
continue-on-error: true
run: pnpm --filter @superdoc/layout-tests run test:memory
- name: Run slow tests
if: matrix.name == 'other-packages'
run: pnpm test:slow
- name: Install Playwright for CDN smoke test
if: matrix.name == 'other-packages'
run: pnpm --filter @superdoc/cdn-smoke-test exec playwright install --with-deps chromium
- name: Run CDN smoke test
if: matrix.name == 'other-packages'
working-directory: packages/superdoc/tests/cdn-smoke
run: pnpm test
cli-tests:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.13
- name: Install dependencies
run: pnpm install
- name: Build superdoc (CLI runtime dependency)
run: pnpm run build:superdoc
- name: Run CLI tests
run: pnpm run test:cli
coverage:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install
- run: pnpm --filter @superdoc-dev/superdoc-yjs-collaboration build
- run: pnpm --filter superdoc exec vitest run --coverage
- uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: packages/superdoc/coverage/lcov.info
flags: superdoc
validate:
name: CI SuperDoc / validate
if: always()
needs: [detect, build, unit-tests, cli-tests, coverage]
runs-on: ubuntu-latest
steps:
- name: Check results
run: |
if [[ "${{ needs.detect.result }}" != "success" ]]; then
echo "Detect job did not succeed (result: ${{ needs.detect.result }})."
exit 1
fi
if [[ "${{ needs.detect.outputs.superdoc }}" != "true" ]]; then
echo "SuperDoc CI skipped: no relevant paths changed."
exit 0
fi
for job_result in \
"build:${{ needs.build.result }}" \
"unit-tests:${{ needs.unit-tests.result }}" \
"cli-tests:${{ needs.cli-tests.result }}" \
"coverage:${{ needs.coverage.result }}"; do
name="${job_result%%:*}"
result="${job_result##*:}"
if [[ "$result" != "success" ]]; then
echo "Job '$name' was required but did not succeed (result: $result)."
exit 1
fi
done