diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index de378d5..345bcb6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -8,6 +8,9 @@ concurrency:
group: ci-${{ github.head_ref }}
cancel-in-progress: true
+permissions:
+ contents: read
+
jobs:
validate:
name: Validate
@@ -19,4 +22,6 @@ jobs:
with:
node-version: 22
+ - run: npm ci --ignore-scripts
+
- run: npm test
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 847c1e9..c1dbcbe 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -34,6 +34,8 @@ jobs:
quality:
name: Quality Gates
runs-on: ubuntu-latest
+ permissions:
+ contents: read
steps:
- uses: actions/checkout@v4
@@ -41,6 +43,8 @@ jobs:
with:
node-version: 22
+ - run: npm ci --ignore-scripts
+
- run: npm test
canary:
@@ -59,6 +63,8 @@ jobs:
node-version: 22
registry-url: https://registry.npmjs.org
+ - run: npm ci --ignore-scripts
+
- name: Upgrade npm for OIDC support
run: npm install -g npm@latest
@@ -92,6 +98,8 @@ jobs:
node-version: 22
registry-url: https://registry.npmjs.org
+ - run: npm ci --ignore-scripts
+
- name: Bump version
id: version
run: |
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c2658d7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/CLAUDE.md b/CLAUDE.md
index 21e27ff..012fdd8 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -32,7 +32,7 @@ Uses npm OIDC provenance — no `NPM_TOKEN` secret needed. Requires npm trusted
## Project structure
```
-base.json ← foundation (strict, isolatedModules, noUncheckedIndexedAccess)
+base.json ← foundation (strict, explicit ambient types, stable type ordering)
nodejs.json ← Node.js apps (NodeNext, ES2024)
node-library.json ← publishable npm packages (NodeNext, ES2024, declarationMap)
react.json ← React apps (Bundler, ES2022, react-jsx)
@@ -43,6 +43,6 @@ nextjs.json ← Next.js apps (Bundler, ES2022, noEmit, next plugin)
| Command | What |
|---------|------|
-| `npm test` | Run smoke tests (JSON validation) |
+| `npm test` | Validate every preset with the supported TypeScript 6 and 7 compilers |
| `npm pack --dry-run` | Preview tarball contents |
| `npm view @vllnt/typescript` | Check published version |
diff --git a/README.md b/README.md
index 133912f..4fac59a 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
# @vllnt/typescript
-Shared TypeScript configurations for vllnt projects. Strict, modern, Node 22+.
+Shared TypeScript configurations for vllnt projects. Strict, modern, Node 22+, and validated with TypeScript 6 and 7.
## Install
```sh
-npm install -D @vllnt/typescript
+npm install -D @vllnt/typescript typescript
```
## Presets
@@ -78,14 +78,49 @@ All presets extend `base.json` which enforces:
- `strict: true`
- `isolatedModules: true`
- `noUncheckedIndexedAccess: true`
+- `noUncheckedSideEffectImports: true`
- `skipLibCheck: true`
- `esModuleInterop: true`
- `resolveJsonModule: true`
+- `stableTypeOrdering: true`
+- `types: []` (ambient type packages must be listed explicitly)
+
+On TypeScript 6, `stableTypeOrdering` can make type-checking slower (up to 25% according to the [TypeScript 6 release notes](https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/)). It is enabled here so TypeScript 6 uses TypeScript 7's deterministic type ordering during migration; TypeScript 7 always uses this behavior.
+
+## TypeScript 7
+
+Version 2 supports TypeScript 6 and 7, drops TypeScript 5, and makes ambient type packages opt-in. TypeScript 7 is a native compiler and no longer exposes the JavaScript compiler API used by tools such as `typescript-eslint` and legacy `tsserver` integrations. Use TypeScript 7 directly when every tool in the project invokes the compiler CLI:
+
+```sh
+npm install -D @vllnt/typescript typescript@^7
+```
+
+During the ecosystem transition, install TypeScript 7 for `tsc` and keep the TypeScript 6 API available under the canonical `typescript` package name:
+
+```json
+{
+ "devDependencies": {
+ "@typescript/native": "npm:typescript@^7.0.2",
+ "@vllnt/typescript": "^2.0.0",
+ "typescript": "npm:@typescript/typescript6@^6.0.2"
+ }
+}
+```
+
+This arrangement follows the [official TypeScript 7 side-by-side guidance](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/). It provides TypeScript 7 as `tsc`, TypeScript 6 as `tsc6`, and the TypeScript 6 JavaScript API to dependent tooling.
+
+Before switching a consumer to TypeScript 7:
+
+- Remove `baseUrl`; make every `paths` target relative to the project root.
+- Replace `moduleResolution: "node"` with `"NodeNext"` for Node.js or `"Bundler"` for bundled applications.
+- Set `rootDir` explicitly for emitting projects.
+- List required ambient packages in `types`, for example `types: ["node", "vitest/globals"]`.
+- Use Next.js 16.3 or newer. Next.js 16.2.12 requires `experimental.useTypeScriptCli: true`.
## Requirements
- Node.js >= 22
-- TypeScript >= 5.0
+- TypeScript >= 6.0.2 and < 8
## License
diff --git a/base.json b/base.json
index 414ba9e..59500e6 100644
--- a/base.json
+++ b/base.json
@@ -8,6 +8,9 @@
"isolatedModules": true,
"skipLibCheck": true,
"noUncheckedIndexedAccess": true,
+ "noUncheckedSideEffectImports": true,
+ "stableTypeOrdering": true,
+ "types": [],
"resolveJsonModule": true
}
}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..d7584bb
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,428 @@
+{
+ "name": "@vllnt/typescript",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@vllnt/typescript",
+ "version": "1.0.0",
+ "license": "MIT",
+ "devDependencies": {
+ "@typescript/native": "npm:typescript@7.0.2",
+ "typescript": "npm:@typescript/typescript6@6.0.2"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "peerDependencies": {
+ "typescript": ">=6.0.2 <8"
+ }
+ },
+ "node_modules/@typescript/native": {
+ "name": "typescript",
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz",
+ "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc"
+ },
+ "engines": {
+ "node": ">=16.20.0"
+ },
+ "optionalDependencies": {
+ "@typescript/typescript-aix-ppc64": "7.0.2",
+ "@typescript/typescript-darwin-arm64": "7.0.2",
+ "@typescript/typescript-darwin-x64": "7.0.2",
+ "@typescript/typescript-freebsd-arm64": "7.0.2",
+ "@typescript/typescript-freebsd-x64": "7.0.2",
+ "@typescript/typescript-linux-arm": "7.0.2",
+ "@typescript/typescript-linux-arm64": "7.0.2",
+ "@typescript/typescript-linux-loong64": "7.0.2",
+ "@typescript/typescript-linux-mips64el": "7.0.2",
+ "@typescript/typescript-linux-ppc64": "7.0.2",
+ "@typescript/typescript-linux-riscv64": "7.0.2",
+ "@typescript/typescript-linux-s390x": "7.0.2",
+ "@typescript/typescript-linux-x64": "7.0.2",
+ "@typescript/typescript-netbsd-arm64": "7.0.2",
+ "@typescript/typescript-netbsd-x64": "7.0.2",
+ "@typescript/typescript-openbsd-arm64": "7.0.2",
+ "@typescript/typescript-openbsd-x64": "7.0.2",
+ "@typescript/typescript-sunos-x64": "7.0.2",
+ "@typescript/typescript-win32-arm64": "7.0.2",
+ "@typescript/typescript-win32-x64": "7.0.2"
+ }
+ },
+ "node_modules/@typescript/old": {
+ "name": "typescript",
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/@typescript/typescript-aix-ppc64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz",
+ "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/@typescript/typescript-darwin-arm64": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz",
+ "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz",
+ "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz",
+ "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz",
+ "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz",
+ "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz",
+ "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz",
+ "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz",
+ "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz",
+ "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz",
+ "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz",
+ "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz",
+ "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz",
+ "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz",
+ "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz",
+ "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz",
+ "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==",
+ "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.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz",
+ "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
+ "node_modules/typescript": {
+ "name": "@typescript/typescript6",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@typescript/typescript6/-/typescript6-6.0.2.tgz",
+ "integrity": "sha512-mbCddXd+jm7hfx7w2YU64/Av4/NqqeG3GoRZgxPcgoTxYjhrcfJRw9ULch71SS4G+Q3bOXFhRvPqjguN0Hyp5w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@typescript/old": "npm:typescript@^6"
+ },
+ "bin": {
+ "tsc6": "bin/tsc6"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index ea442a8..b913af4 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"homepage": "https://github.com/vllnt/typescript#readme",
"repository": {
"type": "git",
- "url": "https://github.com/vllnt/typescript.git"
+ "url": "git+https://github.com/vllnt/typescript.git"
},
"keywords": [
"typescript",
@@ -29,6 +29,13 @@
"test": "node --test tests/smoke.test.js",
"prepublishOnly": "node --test tests/smoke.test.js"
},
+ "peerDependencies": {
+ "typescript": ">=6.0.2 <8"
+ },
+ "devDependencies": {
+ "@typescript/native": "npm:typescript@7.0.2",
+ "typescript": "npm:@typescript/typescript6@6.0.2"
+ },
"publishConfig": {
"access": "public"
}
diff --git a/tests/fixtures/base/src/index.ts b/tests/fixtures/base/src/index.ts
new file mode 100644
index 0000000..e2f6240
--- /dev/null
+++ b/tests/fixtures/base/src/index.ts
@@ -0,0 +1,3 @@
+const greeting: string = "hello"
+
+export { greeting }
diff --git a/tests/fixtures/base/tsconfig.json b/tests/fixtures/base/tsconfig.json
new file mode 100644
index 0000000..6f8fc72
--- /dev/null
+++ b/tests/fixtures/base/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../../base.json",
+ "compilerOptions": {
+ "noEmit": true
+ },
+ "include": ["src"]
+}
diff --git a/tests/fixtures/nextjs/src/jsx-runtime.d.ts b/tests/fixtures/nextjs/src/jsx-runtime.d.ts
new file mode 100644
index 0000000..8addab5
--- /dev/null
+++ b/tests/fixtures/nextjs/src/jsx-runtime.d.ts
@@ -0,0 +1,21 @@
+declare namespace JSX {
+ interface IntrinsicElements {
+ main: {
+ children?: unknown
+ }
+ }
+}
+
+declare module "react/jsx-runtime" {
+ namespace JSX {
+ interface IntrinsicElements {
+ main: {
+ children?: unknown
+ }
+ }
+ }
+
+ export const Fragment: unique symbol
+ export function jsx(type: unknown, props: unknown): unknown
+ export function jsxs(type: unknown, props: unknown): unknown
+}
diff --git a/tests/fixtures/nextjs/src/page.tsx b/tests/fixtures/nextjs/src/page.tsx
new file mode 100644
index 0000000..edb168e
--- /dev/null
+++ b/tests/fixtures/nextjs/src/page.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return Ready
+}
diff --git a/tests/fixtures/nextjs/tsconfig.json b/tests/fixtures/nextjs/tsconfig.json
new file mode 100644
index 0000000..30ebc4d
--- /dev/null
+++ b/tests/fixtures/nextjs/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../../nextjs.json",
+ "compilerOptions": {
+ "rootDir": "src"
+ },
+ "include": ["src"]
+}
diff --git a/tests/fixtures/node-library/src/index.ts b/tests/fixtures/node-library/src/index.ts
new file mode 100644
index 0000000..3ded969
--- /dev/null
+++ b/tests/fixtures/node-library/src/index.ts
@@ -0,0 +1,3 @@
+export function double(value: number): number {
+ return value * 2
+}
diff --git a/tests/fixtures/node-library/tsconfig.json b/tests/fixtures/node-library/tsconfig.json
new file mode 100644
index 0000000..8ca7245
--- /dev/null
+++ b/tests/fixtures/node-library/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../../node-library.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "src"
+ },
+ "include": ["src"]
+}
diff --git a/tests/fixtures/nodejs/src/index.ts b/tests/fixtures/nodejs/src/index.ts
new file mode 100644
index 0000000..8627fb8
--- /dev/null
+++ b/tests/fixtures/nodejs/src/index.ts
@@ -0,0 +1,3 @@
+const environment = process.env.NODE_ENV ?? "development"
+
+export { environment }
diff --git a/tests/fixtures/nodejs/src/node.d.ts b/tests/fixtures/nodejs/src/node.d.ts
new file mode 100644
index 0000000..bc4f2d0
--- /dev/null
+++ b/tests/fixtures/nodejs/src/node.d.ts
@@ -0,0 +1,3 @@
+declare const process: {
+ env: Record
+}
diff --git a/tests/fixtures/nodejs/tsconfig.json b/tests/fixtures/nodejs/tsconfig.json
new file mode 100644
index 0000000..cb3cbba
--- /dev/null
+++ b/tests/fixtures/nodejs/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../../nodejs.json",
+ "compilerOptions": {
+ "noEmit": true,
+ "rootDir": "src"
+ },
+ "include": ["src"]
+}
diff --git a/tests/fixtures/react/src/index.tsx b/tests/fixtures/react/src/index.tsx
new file mode 100644
index 0000000..db63b9f
--- /dev/null
+++ b/tests/fixtures/react/src/index.tsx
@@ -0,0 +1,3 @@
+export function Button() {
+ return
+}
diff --git a/tests/fixtures/react/src/jsx-runtime.d.ts b/tests/fixtures/react/src/jsx-runtime.d.ts
new file mode 100644
index 0000000..d4358b7
--- /dev/null
+++ b/tests/fixtures/react/src/jsx-runtime.d.ts
@@ -0,0 +1,14 @@
+declare module "react/jsx-runtime" {
+ namespace JSX {
+ interface IntrinsicElements {
+ button: {
+ children?: unknown
+ disabled?: boolean
+ }
+ }
+ }
+
+ export const Fragment: unique symbol
+ export function jsx(type: unknown, props: unknown): unknown
+ export function jsxs(type: unknown, props: unknown): unknown
+}
diff --git a/tests/fixtures/react/tsconfig.json b/tests/fixtures/react/tsconfig.json
new file mode 100644
index 0000000..17e1caf
--- /dev/null
+++ b/tests/fixtures/react/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../../react.json",
+ "compilerOptions": {
+ "noEmit": true,
+ "rootDir": "src"
+ },
+ "include": ["src"]
+}
diff --git a/tests/smoke.test.js b/tests/smoke.test.js
index bc1f4a6..6298ac8 100644
--- a/tests/smoke.test.js
+++ b/tests/smoke.test.js
@@ -1,14 +1,60 @@
const { test } = require('node:test')
const assert = require('node:assert/strict')
-const { readFileSync, readdirSync } = require('node:fs')
-const { join } = require('node:path')
+const { mkdtempSync, readFileSync, readdirSync, rmSync } = require('node:fs')
+const { tmpdir } = require('node:os')
+const { dirname, join } = require('node:path')
+const { spawnSync } = require('node:child_process')
const root = join(__dirname, '..')
+const fixtures = join(__dirname, 'fixtures')
const configs = readdirSync(root).filter(
- (f) => f.endsWith('.json') && f !== 'package.json',
+ (file) =>
+ file.endsWith('.json') &&
+ file !== 'package.json' &&
+ file !== 'package-lock.json',
)
+const compilers = [
+ {
+ binary: 'tsc6',
+ label: 'TypeScript 6',
+ packageName: 'typescript',
+ versionPrefix: 'Version 6.',
+ },
+ {
+ binary: 'tsc',
+ label: 'TypeScript 7',
+ packageName: '@typescript/native',
+ versionPrefix: 'Version 7.',
+ },
+]
+
+function compilerPath(compiler) {
+ const packagePath = require.resolve(`${compiler.packageName}/package.json`)
+ const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'))
+ return join(dirname(packagePath), packageJson.bin[compiler.binary])
+}
+
+function runCompiler(compiler, args) {
+ const result = spawnSync(process.execPath, [compilerPath(compiler), ...args], {
+ cwd: root,
+ encoding: 'utf-8',
+ timeout: 30_000,
+ })
+ assert.equal(
+ result.error,
+ undefined,
+ `${compiler.label} could not run: ${result.error?.message}`,
+ )
+ assert.equal(
+ result.status,
+ 0,
+ `${compiler.label} failed (${args.join(' ')}):\n${result.stdout}${result.stderr}`,
+ )
+ return result.stdout.trim()
+}
+
test('all config files are valid JSON with compilerOptions', () => {
for (const config of configs) {
const raw = readFileSync(join(root, config), 'utf-8')
@@ -33,3 +79,68 @@ test('package.json files array includes all configs', () => {
assert.ok(pkg.files.includes(config), `${config} must be in package.json files`)
}
})
+
+test('integration tests use the supported compiler majors', () => {
+ for (const compiler of compilers) {
+ assert.ok(
+ runCompiler(compiler, ['--version']).startsWith(compiler.versionPrefix),
+ `${compiler.label} must report ${compiler.versionPrefix}`,
+ )
+ }
+})
+
+test('TypeScript 6 compatibility package exposes the JavaScript API', () => {
+ const typescript = require('typescript')
+ assert.match(typescript.version, /^6\./)
+ assert.equal(typeof typescript.createProgram, 'function')
+})
+
+for (const compiler of compilers) {
+ test(`${compiler.label} type-checks every preset fixture`, () => {
+ const buildInfoDirectory = mkdtempSync(
+ join(tmpdir(), 'vllnt-typescript-build-info-'),
+ )
+ try {
+ for (const preset of configs.map((config) => config.replace('.json', ''))) {
+ runCompiler(compiler, [
+ '--project',
+ join(fixtures, preset, 'tsconfig.json'),
+ '--noEmit',
+ '--incremental',
+ '--tsBuildInfoFile',
+ join(buildInfoDirectory, `${preset}.tsbuildinfo`),
+ ])
+ }
+ } finally {
+ rmSync(buildInfoDirectory, { force: true, recursive: true })
+ }
+ })
+
+ test(`${compiler.label} preserves node-library emit behavior`, () => {
+ const outputDirectory = mkdtempSync(
+ join(tmpdir(), 'vllnt-typescript-node-library-'),
+ )
+ try {
+ runCompiler(compiler, [
+ '--project',
+ join(fixtures, 'node-library', 'tsconfig.json'),
+ '--outDir',
+ outputDirectory,
+ ])
+
+ for (const output of [
+ 'index.js',
+ 'index.js.map',
+ 'index.d.ts',
+ 'index.d.ts.map',
+ ]) {
+ assert.ok(
+ readdirSync(outputDirectory).includes(output),
+ `${compiler.label} must emit ${output} for node-library.json`,
+ )
+ }
+ } finally {
+ rmSync(outputDirectory, { force: true, recursive: true })
+ }
+ })
+}