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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .github/workflows/package-dry-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,17 @@ jobs:
- name: Validate compat-management schema
run: npm run validate:registry

- name: Verify pinned web-features dataset
run: npm run verify:dataset

- name: Regenerate baseline
run: npm run generate

- name: Stage publishable baseline package and create npm tarball
run: npm run pack:baseline:tarball
- name: Compute release decision and prepare exact tarball
run: npm run release:dry-run

- name: Run packed consumer smoke
if: ${{ hashFiles('release-artifact/package.tgz') != '' }}
env:
BASELINE_PACKAGE_TARBALL: release-artifact/package.tgz
run: node --test test/packed-consumer-smoke.test.mjs

- name: Compute release decision
run: npm run release:dry-run
147 changes: 94 additions & 53 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@ on:
workflow_dispatch:
inputs:
version:
description: "Explicit package version for reviewed Baseline year contract changes"
description: "Explicit version for reviewed declaration or year contract changes"
required: false
type: string

permissions:
contents: write
# Issue an OIDC token for npm provenance (Sigstore).
id-token: write

# Serialize concurrent release runs (don't cancel).
concurrency:
group: release
cancel-in-progress: false
Expand All @@ -23,11 +17,14 @@ defaults:
shell: bash

jobs:
release:
verify:
runs-on: ubuntu-latest
# Create a `release` environment in repo settings with required reviewers
# to gate publishes behind human approval (see README).
environment: release
timeout-minutes: 90
permissions:
contents: read
outputs:
changed: ${{ steps.release-plan.outputs.changed }}
artifact-integrity: ${{ steps.prepare-artifact.outputs.artifact-integrity }}

steps:
- name: Ensure release runs from main
Expand All @@ -39,84 +36,128 @@ jobs:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22"
node-version: "24"
cache: "npm"

# OIDC publishing needs npm >= 11.5.1; Node 22 bundles npm 10.
- name: Upgrade npm
run: npm install -g npm@latest

- name: Resolve trusted release tools
id: release-tools
run: |
echo "node=$(command -v node)" >> "$GITHUB_OUTPUT"
echo "npm=$(command -v npm)" >> "$GITHUB_OUTPUT"
echo "tar=$(command -v tar)" >> "$GITHUB_OUTPUT"
- run: npm ci
- run: npm run validate

- name: Run static JS checks
run: npm run lint

- name: Validate compat-management schema
run: npm run validate:registry

- name: Regenerate baseline
run: npm run generate

# Block publishing when checked-in artifacts don't match the regenerated
# output (i.e. publishing unreviewed content).
- name: Verify checked-in generated artifacts
run: |
git diff --exit-code -- derived/current generated/current
status="$(git status --porcelain --untracked-files=all -- derived/current generated/current)"
if [[ -n "$status" ]]; then
printf '%s\n' "$status"
exit 1
fi

- name: Run validation and smoke tests
run: npm test
test -z "$(git status --porcelain --untracked-files=all -- derived/current generated/current)"

- name: Checkout pinned TypeScript source
run: npm run checkout:typescript-source -- --out .tmp/TypeScript --force

- name: Run pinned TypeScript integration gate
run: npm run test:typescript:full -- --typescript-dir ./.tmp/TypeScript --summary-out .tmp/typescript-integration-summary.md --baseline-diff-out .tmp/typescript-baseline-changes.diff --focused-baselines-out .tmp/typescript-focused-artifact --local-baselines-out .tmp/typescript-raw-local-baselines
- name: Run blocking TypeScript integration
run: npm run test:typescript:full -- --typescript-dir ./.tmp/TypeScript --summary-out typescript-integration-artifacts/summary.md --baseline-diff-out typescript-integration-artifacts/baseline-changes.diff --focused-baselines-out typescript-integration-artifacts/focused --local-baselines-out typescript-integration-artifacts/raw-local-baselines

- name: Stage publishable baseline package
- name: Prepare immutable release artifact
id: prepare-artifact
env:
RELEASE_VERSION: ${{ inputs.version }}
RELEASE_GIT_EXECUTABLE: /usr/bin/git
RELEASE_NODE_EXECUTABLE: ${{ steps.release-tools.outputs.node }}
RELEASE_NPM_EXECUTABLE: ${{ steps.release-tools.outputs.npm }}
RELEASE_TAR_EXECUTABLE: ${{ steps.release-tools.outputs.tar }}
run: |
args=()
if [[ -n "$RELEASE_VERSION" ]]; then
args+=(--version "$RELEASE_VERSION")
fi
npm run pack:baseline -- "${args[@]}"
"$RELEASE_NODE_EXECUTABLE" deploy/prepareReleaseArtifact.mjs "${args[@]}"

- name: Test exact release tarball
if: ${{ hashFiles('release-artifact/package.tgz') != '' }}
env:
BASELINE_PACKAGE_TARBALL: release-artifact/package.tgz
RELEASE_NODE_EXECUTABLE: ${{ steps.release-tools.outputs.node }}
RELEASE_NPM_EXECUTABLE: ${{ steps.release-tools.outputs.npm }}
run: "$RELEASE_NODE_EXECUTABLE" --test test/packed-consumer-smoke.test.mjs

- name: Verify immutable release artifact
id: release-plan
env:
RELEASE_NODE_EXECUTABLE: ${{ steps.release-tools.outputs.node }}
RELEASE_TAR_EXECUTABLE: ${{ steps.release-tools.outputs.tar }}
EXPECTED_ARTIFACT_INTEGRITY: ${{ steps.prepare-artifact.outputs.artifact-integrity }}
run: "$RELEASE_NODE_EXECUTABLE" deploy/verifyReleaseArtifact.mjs --artifact-dir release-artifact

- name: Upload release artifact
if: steps.release-plan.outputs.changed == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: npm-release-artifact
path: release-artifact
if-no-files-found: error

- name: Upload integration summary and focused artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-typescript-integration
path: |
.tmp/typescript-integration-summary.md
.tmp/typescript-baseline-changes.diff
.tmp/typescript-focused-artifact
if-no-files-found: ignore
typescript-integration-artifacts/summary.md
typescript-integration-artifacts/baseline-changes.diff
typescript-integration-artifacts/focused
if-no-files-found: error

- name: Upload raw local baselines
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-typescript-integration-raw-local-baselines
path: .tmp/typescript-raw-local-baselines
if-no-files-found: ignore
path: typescript-integration-artifacts/raw-local-baselines
if-no-files-found: error

# Tokenless publish via OIDC trusted publishing; provenance only on public repos.
- name: Publish changed package and create GitHub release
publish:
needs: verify
if: needs.verify.outputs.changed == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
environment: release
permissions:
contents: write
id-token: write

steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"

- name: Resolve trusted publish tools
id: publish-tools
run: |
echo "node=$(command -v node)" >> "$GITHUB_OUTPUT"
echo "npm=$(command -v npm)" >> "$GITHUB_OUTPUT"

- name: Require npm trusted-publishing support
env:
RELEASE_NPM_EXECUTABLE: ${{ steps.publish-tools.outputs.npm }}
run: test "$(printf '11.5.1\n%s\n' "$("$RELEASE_NPM_EXECUTABLE" --version)" | sort -V | head -n1)" = "11.5.1"

- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: npm-release-artifact
path: release-artifact

- name: Publish verified tarball and create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_VERSION: ${{ inputs.version }}
EXPECTED_ARTIFACT_INTEGRITY: ${{ needs.verify.outputs.artifact-integrity }}
RELEASE_NODE_EXECUTABLE: ${{ steps.publish-tools.outputs.node }}
RELEASE_NPM_EXECUTABLE: ${{ steps.publish-tools.outputs.npm }}
RELEASE_TAR_EXECUTABLE: /usr/bin/tar
run: |
args=()
if [[ -n "$RELEASE_VERSION" ]]; then
args+=(--version "$RELEASE_VERSION")
fi
if [[ "${{ github.event.repository.private }}" != "true" ]]; then
args+=(--provenance)
fi
npm run release:publish -- "${args[@]}"
"$RELEASE_NODE_EXECUTABLE" deploy/publishReleaseArtifact.mjs --artifact-dir release-artifact "${args[@]}"
9 changes: 6 additions & 3 deletions .github/workflows/test-typescript-go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ jobs:
cache: "npm"
- run: npm ci

- name: Verify pinned web-features dataset
run: npm run verify:dataset

- name: Regenerate baseline
run: npm run generate

Expand All @@ -56,12 +59,12 @@ jobs:
cache-dependency-path: .tmp/typescript-go/go.sum

- name: Run tsgo --lib baseline integration
run: npm run test:typescript-go -- --typescript-go-dir .tmp/typescript-go --out .tmp/typescript-go-integration-summary.md
run: npm run test:typescript-go -- --typescript-go-dir .tmp/typescript-go --out typescript-integration-artifacts/typescript-go-summary.md

- name: Upload integration summary
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: typescript-go-integration
path: .tmp/typescript-go-integration-summary.md
if-no-files-found: ignore
path: typescript-integration-artifacts/typescript-go-summary.md
if-no-files-found: error
23 changes: 13 additions & 10 deletions .github/workflows/test-typescript.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ jobs:
cache: "npm"
- run: npm ci

- name: Verify pinned web-features dataset
run: npm run verify:dataset

- name: Regenerate baseline
run: npm run generate

# PRs run a gate of blocking checks only; push to main / dispatch runs the
# full suite with diagnostics.
# PRs run the focused gate; push to main / dispatch also requires the full
# suite to pass after accepting the generated baselines.
- name: Select integration mode
id: mode
run: |
Expand Down Expand Up @@ -70,23 +73,23 @@ jobs:
run: npm run checkout:typescript-source -- --out .tmp/TypeScript --force

- name: Run TypeScript integration checks
run: npm run test:typescript:${{ steps.mode.outputs.mode }} -- --typescript-dir ./.tmp/TypeScript --summary-out .tmp/typescript-integration-summary.md --baseline-diff-out .tmp/typescript-baseline-changes.diff --focused-baselines-out .tmp/typescript-focused-artifact --local-baselines-out .tmp/typescript-raw-local-baselines
run: npm run test:typescript:${{ steps.mode.outputs.mode }} -- --typescript-dir ./.tmp/TypeScript --summary-out typescript-integration-artifacts/summary.md --baseline-diff-out typescript-integration-artifacts/baseline-changes.diff --focused-baselines-out typescript-integration-artifacts/focused --local-baselines-out typescript-integration-artifacts/raw-local-baselines

- name: Upload integration summary and focused artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: typescript-integration
path: |
.tmp/typescript-integration-summary.md
.tmp/typescript-baseline-changes.diff
.tmp/typescript-focused-artifact
if-no-files-found: ignore
typescript-integration-artifacts/summary.md
typescript-integration-artifacts/baseline-changes.diff
typescript-integration-artifacts/focused
if-no-files-found: error

- name: Upload raw local baselines
if: always()
if: always() && steps.mode.outputs.mode == 'full'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: typescript-integration-raw-local-baselines
path: .tmp/typescript-raw-local-baselines
if-no-files-found: ignore
path: typescript-integration-artifacts/raw-local-baselines
if-no-files-found: error
3 changes: 3 additions & 0 deletions .github/workflows/typescript-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ jobs:
- name: Pin latest TypeScript toolchain
run: npm run update:typescript-toolchain

- name: Verify pinned web-features dataset
run: npm run verify:dataset

- name: Regenerate baseline
run: npm run generate

Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ jobs:
- name: Validate compat-management schema
run: npm run validate:registry

- name: Verify pinned web-features dataset
run: npm run verify:dataset

- name: Regenerate baseline
run: npm run generate

Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/weekly-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
- name: Validate compat-management schema
run: npm run validate:registry

- name: Verify pinned web-features dataset
run: npm run verify:dataset

- name: Regenerate baseline
run: npm run generate

Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ deploy/generated/
coverage/
npm-debug.log*
.DS_Store
.tmp
.tmp
release-artifact/
typescript-integration-artifacts/
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@

Generates `baseline.d.ts`, a TypeScript lib for TypeScript-declarable JavaScript features that are [Baseline widely available](https://web.dev/baseline). It currently classifies `javascript.builtins.*` and the `arguments` object from `web-features`.

## Using the lib
## Best-practice setup

Stock TypeScript doesn't treat `"baseline"` as a built-in `lib` yet, so install the package and list it under `compilerOptions.types`:
Stock TypeScript doesn't treat `"baseline"` as a built-in `lib` yet. Install the current supported TypeScript major with this package:

```sh
npm install --save-dev typescript-baseline-lib
npm install --save-dev typescript@^7 typescript-baseline-lib
```

Use the package as the complete global lib:

```json
{
"compilerOptions": {
"noLib": true,
"strict": true,
"types": ["typescript-baseline-lib"]
}
}
```

```sh
npx tsc --noEmit
```

Now only the supported Baseline widely available JavaScript surfaces type-check. APIs that haven't reached Baseline yet (`Promise.withResolvers`, `Array.fromAsync` until it promotes, and so on) are reported as errors. The end goal is first-class `--lib baseline` support upstream in TypeScript.

This package replaces TypeScript's default libs; do not set `compilerOptions.lib` or combine it with the standard `es*` libs. Add other ambient type packages to `types` only when the project needs them. Those packages can require APIs that are intentionally outside the selected Baseline target. The generator preserves audited erased compiler-support declarations, but it does not add unavailable runtime APIs merely to satisfy a third-party package.

## Allow a polyfilled feature

When the runtime loads an audited polyfill, add its generated web-features entry after the base package. For example, core-js can provide `Promise.withResolvers` at runtime:
Expand Down
Loading