test: update test426-fixtures to fae1fa49815813088c433e8486e330e8d953a44

PR-URL: https://github.com/nodejs/node/pull/66815
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
Node.js GitHub Bot authored and GitHub committed 2026-10-27 21:17:42 +00:00
1 parent 37c6a1f0a3
commit 628fd73a88
17 files changed
+1065 -7

No files matched your search

+70
View File
@@ -0,0 +1,70 @@
name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
name: Validate tests and build npm package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
# Fetch all to count number of commits and compute pkg version
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: lts/*
cache: npm
- name: Install dependencies
run: npm ci
- name: Build npm package
run: node scripts/build-npm-package.js
- name: Check that JSON files match their TypeScript types
run: node scripts/check-types.js
- name: Pack npm package
run: mkdir -p dist && npm pack ./npm-package --pack-destination dist
- name: Upload package tarball
uses: actions/upload-artifact@v7
with:
name: npm-package
path: dist/*.tgz
if-no-files-found: error
retention-days: 7
publish:
name: Publish to npm
needs: build
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && github.repository == 'tc39/source-map-tests'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # for npm trusted publishing
concurrency:
group: npm-publish
cancel-in-progress: false
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-node@v6
with:
node-version: lts/*
registry-url: https://registry.npmjs.org
- name: Build npm package
run: node scripts/build-npm-package.js
- name: Publish
run: |
name=$(node -p "require('./npm-package/package.json').name")
version=$(node -p "require('./npm-package/package.json').version")
if [ -n "$(npm view "$name@$version" version 2>/dev/null)" ]; then
echo "$name@$version is already published, skipping."
else
npm publish ./npm-package --access public
fi
+6
View File
@@ -0,0 +1,6 @@
npm-package/*
!npm-package/README.md
!npm-package/package.template.json
!npm-package/types/
node_modules/
.tmp/
+39
View File
@@ -58,3 +58,42 @@ More information about running Chrome Devtools without building Chromium can be
Follow the [running Node.js tests guide](https://github.com/nodejs/node/blob/main/BUILDING.md#running-tests) to build Node.js and run tests locally.
Read more about running the source map tests at [here](https://github.com/nodejs/node/tree/main/test/test426).
## npm package
The test cases are published to npm as [`@tc39/source-map-tests`](https://www.npmjs.com/package/@tc39/source-map-tests), so that source map implementations can run them in their own test suites. A new version is published for every commit to `main`.
```sh
npm install --save-dev --save-exact @tc39/source-map-tests
```
### Usage
`@tc39/source-map-tests/suites.json` lists the test suites:
```json
{
"suites": [
{ "kind": "interpreting", "file": "interpreting/source-map-spec.json" },
{ "kind": "decoding", "file": "decoding/scopes.json" }
]
}
```
There are two types of test suites: `interpreting` and `decoding`:
- **interpreting** provided a source map to apply to a generated file, together with some actions to perform through it to check that it has been applied correctly.
- **decoding** suites check that a source map is correctly decoded into a [Decoded Source Map Record](https://tc39.es/ecma426/#decoded-source-map-record).
### TypeScript
The package's root exports the types of the JSON files:
```ts
import type { InterpretingSuite, DecodingSuite, TestAction } from "@tc39/source-map-tests";
```
With TypeScript 7.1 or later, you can load type definitions for the various suites by adding `"types": ["@tc39/source-map-tests"]` to your `tsconfig.json`. Imported JSON modules then will be typed appropriately:
```ts
import spec from "@tc39/source-map-tests/interpreting/source-map-spec.json" with { type: "json" };
spec.tests[0].testActions; // TestAction[]
```
@@ -4,7 +4,7 @@
"sections": [{
"offset": {
"line": 0,
"column": 0,
"column": 0
},
"map": {
"version": 3,
@@ -16,7 +16,7 @@
}, {
"offset": {
"line": 1,
"column": 0,
"column": 0
},
"map": {
"version": 3,
@@ -1,5 +1,5 @@
{
"file": "app.js",
"sources": [],
"mappings": [],
"mappings": []
}
+2 -2
View File
@@ -5,7 +5,7 @@
"sections": [{
"offset": {
"line": 0,
"column": 0,
"column": 0
},
"map": {
"version": 3,
@@ -17,7 +17,7 @@
}, {
"offset": {
"line": 1,
"column": 0,
"column": 0
},
"map": {
"version": 3,
+1 -1
View File
@@ -2,5 +2,5 @@
/// <reference path="../source-map-record.d.ts" />
interface SourceMapRecord {
debugId: string|null;
debugId?: string|null;
}
+5
View File
@@ -0,0 +1,5 @@
# @tc39/source-map-tests
Cross-implementation test cases for the [ECMA-426 source map specification](https://tc39.es/ecma426/).
See the [tc39/source-map-tests README](https://github.com/tc39/source-map-tests#npm-package) for the package contents and usage.
+26
View File
@@ -0,0 +1,26 @@
{
"name": "@tc39/source-map-tests",
"version": "X.X.X",
"description": "Cross-implementation test cases for the ECMA-426 source map specification",
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "git+https://github.com/tc39/source-map-tests.git"
},
"homepage": "https://github.com/tc39/source-map-tests#readme",
"bugs": "https://github.com/tc39/source-map-tests/issues",
"keywords": [
"source-map",
"sourcemap",
"ecma-426",
"test-suite",
"tests"
],
"files": [
"suites.json",
"interpreting/",
"decoding/",
"types/",
"LICENSE.md"
]
}
+2
View File
@@ -0,0 +1,2 @@
/// <reference path="./modules.d.ts" />
export * from "./types.js";
+14
View File
@@ -0,0 +1,14 @@
declare module "@tc39/source-map-tests/suites*.json" with { type: "json" } {
const index: import("./types.js").SuitesIndex;
export default index;
}
declare module "@tc39/source-map-tests/interpreting/*.json" with { type: "json" } {
const suite: import("./types.js").InterpretingSuite;
export default suite;
}
declare module "@tc39/source-map-tests/decoding/*.json" with { type: "json" } {
const suite: import("./types.js").DecodingSuite;
export default suite;
}
+90
View File
@@ -0,0 +1,90 @@
/**
* Types for the JSON files in this package.
*
* All paths are relative to the package root.
*/
/** The format of `suites.json`. */
export interface SuitesIndex {
suites: SuiteInfo[];
}
export type SuiteInfo =
| { kind: "interpreting"; file: string }
| { kind: "decoding"; file: string };
/** A file from the test suite, with its contents inlined. */
export interface TestFile {
path: string;
content: string;
}
/** The format of interpreting suite files (`interpreting/<name>.json`). */
export interface InterpretingSuite {
tests: InterpretingTest[];
}
export interface InterpretingTest {
name: string;
description: string;
sourceMapIsValid: boolean;
testActions: TestAction[];
/**
* The transpiled source that the source map refers to.
*/
baseFile: TestFile;
sourceMapFile: TestFile;
}
export type TestAction =
| CheckMappingAction
| CheckMappingTransitiveAction
| CheckIgnoreListAction;
export interface CheckMappingAction {
actionType: "checkMapping";
/** 0-based. */
generatedLine: number;
/** 0-based. */
generatedColumn: number;
originalSource: string | null;
/** 0-based. */
originalLine: number | null;
/** 0-based. */
originalColumn: number | null;
mappedName: string | null;
}
export interface CheckMappingTransitiveAction
extends Omit<CheckMappingAction, "actionType"> {
actionType: "checkMappingTransitive";
/** Source maps to apply after `sourceMapFile`, in order. */
intermediateMaps: TestFile[];
}
export interface CheckIgnoreListAction {
actionType: "checkIgnoreList";
/** Sources that must be in the ignore list. */
present: string[];
}
/** The format of decoding suite files (`decoding/<name>.json`). */
export interface DecodingSuite {
tests: DecodingTest[];
}
export interface DecodingTest {
name: string;
sourceMapFile: TestFile;
/**
* The expected Decoded Source Map Record, as JSON in the format described by
* `decoding/source-map-record.d.ts` (and extended by the proposal-specific
* `decoding/<suite>/<suite>.d.ts` files).
*/
goldenFile: TestFile;
/**
* Whether decoding this source map should optionally report an error
* (https://tc39.es/ecma426/#sec-optional-errors).
*/
optionalErrors: boolean;
}
+405
View File
@@ -0,0 +1,405 @@
{
"name": "source-map-tests",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"devDependencies": {
"typescript": "7.1.0-beta"
}
},
"node_modules/@typescript/typescript-aix-ppc64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.1.0-beta.tgz",
"integrity": "sha512-DXDG+jIWxBHGdoO70tcHON33rCnSzsEZj9P13oyf/r/KEGIo6awsdSNVNjAw0uMwEpqRu75IrgCcW58YcVkZHg==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-android-arm64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-android-arm64/-/typescript-android-arm64-7.1.0-beta.tgz",
"integrity": "sha512-UZx6PxoQavuvaVTrSf3aw0Oy/J/uJpRylipA0kzc038jMvZXh0UtE8vnQp20FqtdgD5bhXZ0aJrRJyoTSUO58Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-darwin-arm64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.1.0-beta.tgz",
"integrity": "sha512-q7mxblcyX0E7hXsY4k+Q6KWKK5mGmfVq+BDesdTgRVgjodk27aIxER77Zyj9+TgSTlCje8F7+JM6f6hl2BuNdw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-darwin-x64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.1.0-beta.tgz",
"integrity": "sha512-D5EYqG5Wm/guw9+0j8+Mn1Jbr/gfS/VtFTuoH8PJtFbcqeDaQGMulc7SW8q51QG6Y3wGOGX3nbsTOw6fIKWWAA==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-freebsd-arm64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.1.0-beta.tgz",
"integrity": "sha512-9A0XX0tcnH9qPdolSKKzSjTb93dlB0UEcAJbHYEsrFX2fkFNSum9+dvkQQJ9vLc+7vxHetDPujq9Qe6wx+Xhow==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-freebsd-x64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.1.0-beta.tgz",
"integrity": "sha512-EDf/dBHfY0TxX3NmUTek0hbffeyZlh3+ls6WQW3ICB8vYxwYLFnzg7wkgEUvl9eRlpiJ/nmc2S8arPMzINJ7rg==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-arm": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.1.0-beta.tgz",
"integrity": "sha512-AvN9HmzOQh46G4312ooSgMHhbB7DtnLwg8D9mo324X49B7weMwtJrBG1MxT9IyI8kzDd7YRtW+1hWGun7WG7Qw==",
"cpu": [
"arm"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-arm64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.1.0-beta.tgz",
"integrity": "sha512-hNqQBgQ5b5oGqN76QqbAU6CwYhJZ6iOcWc2kPTUs2OentgpxZktETziH6KIyRFJPaiBncognwn2ZLu3DNhHiWw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-loong64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.1.0-beta.tgz",
"integrity": "sha512-xbUustlBrFflt2pNEyG5ye+d4WGPc/rfr2xK29MXeobPSw297JqwuKRrvbKM5o3fE/eUM/c+urVm6jQ3IaMVTw==",
"cpu": [
"loong64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-mips64el": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.1.0-beta.tgz",
"integrity": "sha512-fS4/G7/0bXZ3NSq3nBMAXyg65I3tO4S7j08VNQ2g1aNC/qq79gE7Qne1BNjVsjMFfHBVBFjQYoTQCjmVU2iFlg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-ppc64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.1.0-beta.tgz",
"integrity": "sha512-0upCCxYPX8X6gOwkvfv+Ee7/ufyy7k97mTrGE0e5BxLlnUEa+w+rtgnv2dsKcxFdwdeZYVlZKCqgN/xCBV08+A==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-riscv64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.1.0-beta.tgz",
"integrity": "sha512-0jKU9YRgOPRgiy5V/UWv37kB53PaTpIbwGCbbOMUPPAkrjVRNOIAJaz7Wa7s3H7mdDebX1LopUEPEJR+7Xa7zg==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-s390x": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.1.0-beta.tgz",
"integrity": "sha512-j+d04s2kxaPQh6DLPb01sknAQfzsrdSZy15jBRHyLEZoaaQ19dVjbFRlkNVvYwUG7ZdP8+y5b/7RmPxdtHUKdQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-linux-x64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.1.0-beta.tgz",
"integrity": "sha512-kcD51ihf+pnI5KT4uQQYG04OpwznaZYBlIQhDhl8fflFd27NktxXsUeguxZyvUMyWfum7IF2bBS6Jv7ox0AgFQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-netbsd-arm64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.1.0-beta.tgz",
"integrity": "sha512-8W85YyoGK+rgGoSU9jJQUpELbrKcZcbdJk2jPNQ6UKDKI7ryPlPFTrV2jCE5RQuv4Tt96hMDTc33s4YfRrLFBA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-netbsd-x64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.1.0-beta.tgz",
"integrity": "sha512-iGsTE0ve2PG0AcyZinwAR0LnGEZhu/y4dceS0hZsYCaKdYETvQtvtlNWlmYKempsBr6C7Il7dMXHVk+VFm9u0g==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-openbsd-arm64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.1.0-beta.tgz",
"integrity": "sha512-Z2FERdHB9fAKI+KGqdWn04O7uNlnB+VYiEm6INE1aZuzzLNd3KBqQ6IpKUJF2ny4GigGU6nVu75XD9tAUODPng==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-openbsd-x64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.1.0-beta.tgz",
"integrity": "sha512-NVG3qeyCq/rJEOhaRjR3LsWgjrjo5vJW25omVLeHAVnpKIG4pE4cenwwKGR06DiJ1s0QTOymcJeKXMEpsiNBVg==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-sunos-x64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.1.0-beta.tgz",
"integrity": "sha512-ovAdoWXEn2B5/fyWG69pLU3FWmQwPWOjQV5TFbcxtpnOv+R3g8ySGHl1NYRq7Lb/GYdFDvaGcZ+SiU7iKuiMsA==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-win32-arm64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.1.0-beta.tgz",
"integrity": "sha512-lJbo71IEOfL7ZZIZnArRaOLqjn9BAfoSzyUQn0aSjfSpDZL4ru0afUsdBfo6PQEjD6ssdmi0n/RwaPADX6bsvQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/@typescript/typescript-win32-x64": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.1.0-beta.tgz",
"integrity": "sha512-UKcHvbybY2tDTvFW2b1vwiAvDlIRooo69lh8CXWVhOQejcvpM5+IgbiFW9EIwR5Wi5X/v+BdN7gdWbigBuJ3rw==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=16.20.0"
}
},
"node_modules/typescript": {
"version": "7.1.0-beta",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-7.1.0-beta.tgz",
"integrity": "sha512-cjWjZAJDsmZzsNC5GwHNlW0YPM65jZa5oR0KyQcYX3KSVIfTvtBq//vewISyatKk4OLi5grZjHhIVE9fdrw1UQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc"
},
"engines": {
"node": ">=16.20.0"
},
"optionalDependencies": {
"@typescript/typescript-aix-ppc64": "7.1.0-beta",
"@typescript/typescript-android-arm64": "7.1.0-beta",
"@typescript/typescript-darwin-arm64": "7.1.0-beta",
"@typescript/typescript-darwin-x64": "7.1.0-beta",
"@typescript/typescript-freebsd-arm64": "7.1.0-beta",
"@typescript/typescript-freebsd-x64": "7.1.0-beta",
"@typescript/typescript-linux-arm": "7.1.0-beta",
"@typescript/typescript-linux-arm64": "7.1.0-beta",
"@typescript/typescript-linux-loong64": "7.1.0-beta",
"@typescript/typescript-linux-mips64el": "7.1.0-beta",
"@typescript/typescript-linux-ppc64": "7.1.0-beta",
"@typescript/typescript-linux-riscv64": "7.1.0-beta",
"@typescript/typescript-linux-s390x": "7.1.0-beta",
"@typescript/typescript-linux-x64": "7.1.0-beta",
"@typescript/typescript-netbsd-arm64": "7.1.0-beta",
"@typescript/typescript-netbsd-x64": "7.1.0-beta",
"@typescript/typescript-openbsd-arm64": "7.1.0-beta",
"@typescript/typescript-openbsd-x64": "7.1.0-beta",
"@typescript/typescript-sunos-x64": "7.1.0-beta",
"@typescript/typescript-win32-arm64": "7.1.0-beta",
"@typescript/typescript-win32-x64": "7.1.0-beta"
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"private": true,
"type": "module",
"scripts": {
"build": "node scripts/build-npm-package.js",
"check-types": "node scripts/build-npm-package.js && node scripts/check-types.js"
},
"devDependencies": {
"typescript": "7.1.0-beta"
}
}
+240
View File
@@ -0,0 +1,240 @@
// Builds the contents for the @tc39/source-map-tests npm package,
// in the `npm-package` folder.
import { execFileSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
const root = path.resolve(import.meta.dirname, "..");
const outDir = path.join(root, "npm-package");
const committedFiles = new Set([
"README.md",
"package.template.json",
"types",
]);
const errors = [];
const error = msg => errors.push(msg);
const rel = abs => path.relative(root, abs).split(path.sep).join("/");
const abs = relPath => path.join(root, relPath);
const out = relPath => path.join(outDir, relPath);
function walk(dir) {
return fs
.readdirSync(dir, { withFileTypes: true })
.flatMap(e =>
e.isDirectory() ? walk(path.join(dir, e.name)) : [path.join(dir, e.name)]
);
}
/**
* Returns `{ path, content }` for a repo-relative path, or null if missing.
* `packagePath` is where the file ends up in the npm package.
*/
function fileEntry(relPath, context, packagePath = relPath) {
if (!fs.existsSync(abs(relPath))) {
error(`${context}: referenced file ${relPath} does not exist`);
return null;
}
return { path: packagePath, content: fs.readFileSync(abs(relPath), "utf8") };
}
function checkUniqueNames(suiteName, tests) {
const seen = new Set();
for (const { name } of tests) {
if (seen.has(name)) error(`${suiteName}: duplicate test name ${name}`);
seen.add(name);
}
}
// Interpreting suites: <name>[-proposal]-tests.json manifests in the repo root,
// whose files live in resources/<resourceBasePath>. In the package, resources/
// is copied to interpreting/resources/.
const referencedResources = new Set();
function buildInterpretingSuite(manifestFile) {
const name = manifestFile.replace(/-tests\.json$/, "").replace(/-proposal$/, "");
const manifest = JSON.parse(fs.readFileSync(abs(manifestFile), "utf8"));
const base = path.posix.join("resources", manifest.resourceBasePath ?? "");
const resource = (file, context) => {
const relPath = path.posix.join(base, file);
referencedResources.add(relPath);
return fileEntry(relPath, context, `interpreting/${relPath}`);
};
const tests = manifest.tests.map(test => {
const context = `${manifestFile} (${test.name})`;
return {
name: test.name,
description: test.description,
sourceMapIsValid: test.sourceMapIsValid,
baseFile: resource(test.baseFile, context),
sourceMapFile: resource(test.sourceMapFile, context),
testActions: (test.testActions ?? []).map(action =>
action.intermediateMaps
? {
...action,
intermediateMaps: action.intermediateMaps.map(m =>
resource(m, context)
),
}
: action
),
};
});
checkUniqueNames(name, tests);
return { name, kind: "interpreting", tests };
}
// Decoding suites: each directory under decoding/ containing <name>.map files,
// each with a <name>.map.golden and an optional <name>.error/<name>.map.error.
function buildDecodingSuite(dir) {
const name = path.basename(dir);
const files = fs.readdirSync(dir).sort();
const used = new Set();
const tests = [];
for (const file of files.filter(f => f.endsWith(".map"))) {
const testName = file.slice(0, -".map".length);
const context = `${rel(dir)} (${testName})`;
const sourceMapFile = fileEntry(rel(path.join(dir, file)), context);
const goldenFile = fileEntry(rel(path.join(dir, `${file}.golden`)), context);
const errorFile = [`${testName}.error`, `${file}.error`].find(f =>
files.includes(f)
);
used.add(file).add(`${file}.golden`).add(errorFile);
if (goldenFile) {
try {
JSON.parse(goldenFile.content);
} catch (e) {
error(`${goldenFile.path}: invalid JSON (${e.message})`);
}
}
tests.push({
name: testName,
sourceMapFile,
goldenFile,
optionalErrors: errorFile !== undefined,
});
}
for (const file of files) {
if (/\.(golden|error)$/.test(file) && !used.has(file)) {
error(`${rel(path.join(dir, file))}: no matching .map file`);
}
}
checkUniqueNames(name, tests);
return { name, kind: "decoding", tests };
}
// Stable spec tests come first, followed by proposals.
const isProposal = f => f.endsWith("-proposal-tests.json");
const interpretingSuites = fs
.readdirSync(root)
.filter(f => f.endsWith("-tests.json"))
.sort((a, b) => isProposal(a) - isProposal(b) || a.localeCompare(b))
.map(buildInterpretingSuite);
const decodingDirs = [
path.join(root, "decoding"),
...fs
.readdirSync(path.join(root, "decoding"), { withFileTypes: true })
.filter(e => e.isDirectory())
.map(e => path.join(root, "decoding", e.name))
.sort(),
];
const decodingSuites = decodingDirs
.filter(dir => fs.readdirSync(dir).some(f => f.endsWith(".map")))
.map(buildDecodingSuite);
const suites = [...interpretingSuites, ...decodingSuites];
// Suites go in <kind>/<name>.json, next to the directory with their files.
const suiteFile = ({ name, kind }) => `${kind}/${name}.json`;
const suiteFiles = new Set();
for (const suite of suites) {
const file = suiteFile(suite);
if (suiteFiles.has(file)) error(`two suites would be written to ${file}`);
suiteFiles.add(file);
}
for (const file of walk(path.join(root, "resources"))) {
if (file.endsWith(".map") && !referencedResources.has(rel(file))) {
error(`${rel(file)}: source map not referenced by any test`);
}
}
if (errors.length > 0) {
console.error(`Found ${errors.length} problem(s) in the test data:`);
for (const msg of errors) console.error(` - ${msg}`);
process.exit(1);
}
// Write the package.
const writeJSON = (relPath, data) => {
fs.mkdirSync(path.dirname(out(relPath)), { recursive: true });
fs.writeFileSync(out(relPath), JSON.stringify(data, null, 2) + "\n");
};
const git = (...gitArgs) =>
execFileSync("git", gitArgs, { cwd: root, encoding: "utf8" }).trim();
const version = `0.0.${git("rev-list", "--count", "HEAD")}`;
const gitHead = git("rev-parse", "HEAD");
for (const entry of fs.readdirSync(outDir)) {
if (!committedFiles.has(entry)) {
fs.rmSync(out(entry), { recursive: true, force: true });
}
}
fs.cpSync(abs("resources"), out("interpreting/resources"), { recursive: true });
fs.cpSync(abs("decoding"), out("decoding"), { recursive: true });
fs.copyFileSync(abs("LICENSE.md"), out("LICENSE.md"));
for (const suite of suites) {
writeJSON(suiteFile(suite), { tests: suite.tests });
}
const packageJson = JSON.parse(
fs.readFileSync(out("package.template.json"), "utf8")
);
const decodingTypes = walk(abs("decoding"))
.filter(f => f.endsWith(".d.ts"))
.map(rel)
.sort();
const exportedFiles = [
"package.json",
"suites.json",
...suites.map(suiteFile),
...decodingTypes,
];
writeJSON("package.json", {
...packageJson,
version,
gitHead,
exports: {
".": {
"types@>=7.1.0-0": "./types/index.d.ts",
types: "./types/types.d.ts",
},
...Object.fromEntries(exportedFiles.map(f => [`./${f}`, `./${f}`])),
},
});
writeJSON("suites.json", {
suites: suites.map(suite => ({
kind: suite.kind,
file: suiteFile(suite),
})),
});
console.log(`Built ${packageJson.name}@${version} in ${rel(outDir)}/`);
for (const { name, kind, tests } of suites) {
console.log(` ${name} (${kind}): ${tests.length} tests`);
}
+150
View File
@@ -0,0 +1,150 @@
// Checks that the JSON files in the generated npm package match
// the TS definitions. Run build-npm-package.js first.
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
const root = path.resolve(import.meta.dirname, "..");
const outDir = path.join(root, ".tmp", "check-types");
const tsc = path.join(root, "node_modules", ".bin", "tsc");
const compilerOptions = {
strict: true,
noEmit: true,
skipLibCheck: false,
module: "nodenext",
moduleResolution: "nodenext",
target: "esnext",
types: [],
};
const relFrom = (from, to) => {
const rel = path.relative(path.dirname(from), to).split(path.sep).join("/");
return rel.startsWith(".") ? rel : `./${rel}`;
};
function writeCheck(tsFile, header, type, jsonFile) {
const json = fs.readFileSync(jsonFile, "utf8");
fs.mkdirSync(path.dirname(tsFile), { recursive: true });
fs.writeFileSync(
tsFile,
`${header}\nexport default ${json.trim()} satisfies ${type};\n`
);
}
function runTsc(name, projectDir, files) {
const tsconfig = path.join(projectDir, "tsconfig.json");
fs.writeFileSync(tsconfig, JSON.stringify({ compilerOptions, files }, null, 2));
const { status } = spawnSync(tsc, ["-p", tsconfig, "--pretty"], {
stdio: "inherit",
});
console.log(`${status === 0 ? "ok" : "FAIL"} ${name}`);
return status === 0;
}
fs.rmSync(outDir, { recursive: true, force: true });
let ok = true;
// npm package files.
const pkgDir = path.join(root, "npm-package");
if (!fs.existsSync(path.join(pkgDir, "suites.json"))) {
console.error("npm-package/suites.json not found, run scripts/build-npm-package.js first.");
process.exit(1);
}
{
const projectDir = path.join(outDir, "npm-package");
const typesFile = path.join(pkgDir, "types", "types.d.ts");
const files = [];
const check = (jsonRel, type) => {
const tsFile = path.join(projectDir, `${jsonRel}.ts`);
const header = `import type { ${type} } from "${relFrom(tsFile, typesFile)}";`;
writeCheck(tsFile, header, type, path.join(pkgDir, jsonRel));
files.push(path.relative(projectDir, tsFile));
};
const index = JSON.parse(fs.readFileSync(path.join(pkgDir, "suites.json"), "utf8"));
const expectedTypes = new Map([["suites.json", "SuitesIndex"]]);
for (const { kind, file } of index.suites) {
expectedTypes.set(file, kind === "interpreting" ? "InterpretingSuite" : "DecodingSuite");
}
for (const [file, type] of expectedTypes) check(file, type);
// Check that importing each exported JSON file `with { type: "json" }` gets
// its declared type from modules.d.ts.
const { name: pkgName, exports } = JSON.parse(
fs.readFileSync(path.join(pkgDir, "package.json"), "utf8")
);
const exportedJSON = Object.keys(exports)
.filter(key => key.endsWith(".json") && key !== "./package.json")
.map(key => key.slice(2));
const importsFile = path.join(projectDir, "imports.ts");
const typeNames = [...new Set(expectedTypes.values())];
fs.writeFileSync(
importsFile,
[
`import type { ${typeNames.join(", ")} } from "${relFrom(importsFile, path.join(pkgDir, "types", "index.js"))}";`,
"type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;",
...exportedJSON.flatMap((file, i) => {
const type = expectedTypes.get(file);
if (!type) throw new Error(`Exported ${file} is not a known suite file`);
return [
`import json${i} from "${pkgName}/${file}" with { type: "json" };`,
`export const check${i}: Equals<typeof json${i}, ${type}> = true; // ${file}`,
];
}),
].join("\n") + "\n"
);
files.push(path.relative(projectDir, importsFile));
ok = runTsc("npm-package", projectDir, files) && ok;
// Check that each exported decoding/**/*.d.ts file can be loaded through the
// package's exports. Each one is checked separately, because they extend
// the same global interfaces.
for (const key of Object.keys(exports).filter(k => k.endsWith(".d.ts"))) {
const name = `npm-package ${key.slice(2)}`;
const dtsDir = path.join(outDir, "exports", key.slice(2));
const linkDir = path.join(dtsDir, "node_modules", ...pkgName.split("/"));
fs.mkdirSync(path.dirname(linkDir), { recursive: true });
fs.symlinkSync(pkgDir, linkDir, "dir");
fs.writeFileSync(
path.join(dtsDir, "index.ts"),
`/// <reference types="${pkgName}/${key.slice(2)}" />\nexport type T = SourceMapRecord;\n`
);
ok = runTsc(name, dtsDir, ["index.ts"]) && ok;
}
}
// Check golden files
const decodingDir = path.join(root, "decoding");
const decodingSuiteDirs = [
decodingDir,
...fs
.readdirSync(decodingDir, { withFileTypes: true })
.filter(e => e.isDirectory())
.map(e => path.join(decodingDir, e.name)),
];
for (const dir of decodingSuiteDirs) {
const goldens = fs.readdirSync(dir).filter(f => f.endsWith(".golden")).sort();
if (goldens.length === 0) continue;
const name = path.relative(root, dir).split(path.sep).join("/");
const projectDir = path.join(outDir, name);
const suiteTypes = path.join(dir, `${path.basename(dir)}.d.ts`);
const typesFile = fs.existsSync(suiteTypes)
? suiteTypes
: path.join(decodingDir, "source-map-record.d.ts");
const files = goldens.map(golden => {
const tsFile = path.join(projectDir, `${golden}.ts`);
const header = `/// <reference path="${relFrom(tsFile, typesFile)}" />`;
writeCheck(tsFile, header, "SourceMapRecord", path.join(dir, golden));
return path.relative(projectDir, tsFile);
});
ok = runTsc(name, projectDir, files) && ok;
}
process.exit(ok ? 0 : 1);
+1 -1
View File
@@ -7,7 +7,7 @@ suite ensures that the Node.js source map implementation conforms to the
The [`test/fixtures/test426`](../fixtures/test426/) contains a copy of the set of
[Source Map Tests][] suite. The last updated hash is:
* <https://github.com/tc39/source-map-tests/commit/9ea66b466fd37e8a4050033d23b3e1480973c3dc>
* <https://github.com/tc39/source-map-tests/commit/fae1fa49815813088c433e8486e330e8d953a444>
See the json files in [the `status` folder](./status) for prerequisites,
expected failures, and support status for specific tests.