diff --git a/.c8rc.json b/.c8rc.json new file mode 100644 index 0000000..63f2e73 --- /dev/null +++ b/.c8rc.json @@ -0,0 +1,9 @@ +{ + "all": true, + "include": "index.js", + "reporter": [ + "html", + "lcov", + "text" + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2f8fd4..5ac228e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,9 +3,14 @@ on: push: branches: - main + tags: + - 'v*' pull_request: paths-ignore: - '*.md' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: nodejs: name: Node.js @@ -13,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [^18.18, ^20.8, ^21, ^22, ^24] + node-version: [^20.8, ^22, ^24] os: [ubuntu-latest, windows-latest] steps: - uses: actions/checkout@v4 @@ -26,3 +31,4 @@ jobs: with: files: coverage/lcov.info name: ${{ matrix.os }}/${{ matrix.node-version }} + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7e77450 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,89 @@ +name: Release +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + tag: + description: 'Release tag (e.g., v1.2.3)' + required: true + type: string + skip_ci_check: + description: 'Skip CI status check' + required: false + type: boolean + default: false + +permissions: + contents: write + id-token: write + +jobs: + release: + name: Release + runs-on: ubuntu-latest + environment: npm + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }} + fetch-depth: 0 + + - name: Verify tag matches package.json version + run: | + jq --raw-output --exit-status --arg tag "$RELEASE_TAG" ' + if (.version == ($tag | ltrimstr("v"))) then + "Package version (\(.version)) matches tag version (\($tag | ltrimstr("v")))" + else + "Package version (\(.version)) does not match tag version (\($tag | ltrimstr("v")))" | halt_error(1) + end' package.json + env: + RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} + + - name: Verify commit is in main branch + run: | + # Check if the tagged commit is included in the main branch + if git merge-base --is-ancestor ${{ github.sha }} origin/main; then + echo "Tagged commit is properly included in main branch" + else + echo "Tagged commit is not included in the main branch" + echo "Please push the commit to main before releasing" + exit 1 + fi + + - name: Check CI status + if: ${{ !inputs.skip_ci_check }} + run: | + # Check if CI has completed successfully for this commit + gh run list --commit ${{ github.sha }} --status success --json workflowName | jq --raw-output --exit-status ' + if any(.[]; .workflowName == "Install and test @ava/typescript") then + "All CI checks have passed!" + else + "CI has not completed successfully for this commit" | halt_error(1) + end' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: package.json + cache: npm + registry-url: https://registry.npmjs.org + + - name: Publish to npm with provenance + run: npm publish --provenance + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Create GitHub Release + run: | + gh release create "$RELEASE_TAG" \ + --title "$RELEASE_TAG" \ + --draft \ + --generate-notes + env: + RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/ava.config.js b/ava.config.js new file mode 100644 index 0000000..3fb7964 --- /dev/null +++ b/ava.config.js @@ -0,0 +1,14 @@ +const avaConfig = { + files: [ + '!test/broken-fixtures/**', + ], + watchMode: { + ignoreChanges: [ + 'test/fixtures/**', + 'test/broken-fixtures/**', + ], + }, + timeout: '60s', +}; + +export default avaConfig; diff --git a/index.js b/index.js index 6590eab..dd1fc94 100644 --- a/index.js +++ b/index.js @@ -37,7 +37,7 @@ function validate(target, properties) { } async function compileTypeScript(projectDirectory) { - return execa('tsc', ['--incremental'], {preferLocal: true, cwd: projectDirectory}); + return execa({preferLocal: true, cwd: projectDirectory})`tsc --incremental`; } const configProperties = { diff --git a/package.json b/package.json index 624cf18..838a1b4 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "5.0.0", "description": "TypeScript provider for AVA", "engines": { - "node": "^18.18 || ^20.8 || ^21 || ^22 || >=24" + "node": "^20.8 || ^22 || >=24" }, "files": [ "index.js" @@ -24,38 +24,17 @@ }, "dependencies": { "escape-string-regexp": "^5.0.0", - "execa": "^8.0.1" + "execa": "^9.6.0" }, "devDependencies": { - "ava": "^6.1.2", - "c8": "^9.1.0", - "del": "^7.1.0", - "typescript": "^5.4.5", - "xo": "^0.58.0" + "ava": "^6.4.0", + "c8": "^10.1.3", + "del": "^8.0.0", + "typescript": "^5.8.3", + "xo": "^1.1.0" }, - "c8": { - "reporter": [ - "html", - "lcov", - "text" - ] - }, - "ava": { - "files": [ - "!test/broken-fixtures/**" - ], - "watcher": { - "ignoreChanges": [ - "test/fixtures/**", - "test/broken-fixtures/**" - ] - }, - "timeout": "60s" - }, - "xo": { - "ignores": [ - "test/broken-fixtures", - "test/fixtures/**/compiled/**" - ] + "volta": { + "node": "22.16.0", + "npm": "11.4.2" } } diff --git a/test/broken-fixtures/tsconfig.json b/test/broken-fixtures/tsconfig.json index 47d862c..e9b2017 100644 --- a/test/broken-fixtures/tsconfig.json +++ b/test/broken-fixtures/tsconfig.json @@ -1,6 +1,9 @@ { "compilerOptions": { - "outDir": "typescript/compiled" + "outDir": "typescript/compiled", + "lib": [ + "es2022" + ] }, "include": [ "typescript" diff --git a/test/fixtures/load/tsconfig.json b/test/fixtures/load/tsconfig.json index f4488d1..a00ea6f 100644 --- a/test/fixtures/load/tsconfig.json +++ b/test/fixtures/load/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "strictNullChecks": true, - "module": "Node16", + "module": "node18", "outDir": "compiled" }, "include": [ diff --git a/test/fixtures/tsconfig.json b/test/fixtures/tsconfig.json index 317eedd..5051a16 100644 --- a/test/fixtures/tsconfig.json +++ b/test/fixtures/tsconfig.json @@ -1,6 +1,10 @@ { "compilerOptions": { "strictNullChecks": true, + "lib": [ + "es2022", + "dom" + ], "outDir": "typescript/compiled" }, "include": [ diff --git a/test/protocol-ava-6.js b/test/protocol-ava-6.js index 773f596..b0ce7fa 100644 --- a/test/protocol-ava-6.js +++ b/test/protocol-ava-6.js @@ -121,17 +121,27 @@ test('main() resolvePossibleOutOfBandCompilationSources() .js but .ts not config test('main() resolvePossibleOutOfBandCompilationSources() .cjs and .cjs and .cts configured', withProvider, (t, provider) => { const main = provider.main({config: {extensions: ['cjs', 'cts'], rewritePaths: {'src/': 'build/'}, compile: false}}); - t.deepEqual(main.resolvePossibleOutOfBandCompilationSources(path.join(projectDirectory, 'build/foo.cjs')), [path.join(projectDirectory, 'src/foo.cjs'), path.join(projectDirectory, 'src/foo.cts')]); + t.deepEqual(main.resolvePossibleOutOfBandCompilationSources(path.join(projectDirectory, 'build/foo.cjs')), [ + path.join(projectDirectory, 'src/foo.cjs'), + path.join(projectDirectory, 'src/foo.cts'), + ]); }); test('main() resolvePossibleOutOfBandCompilationSources() .mjs and .mjs and .mts configured', withProvider, (t, provider) => { const main = provider.main({config: {extensions: ['mjs', 'mts'], rewritePaths: {'src/': 'build/'}, compile: false}}); - t.deepEqual(main.resolvePossibleOutOfBandCompilationSources(path.join(projectDirectory, 'build/foo.mjs')), [path.join(projectDirectory, 'src/foo.mjs'), path.join(projectDirectory, 'src/foo.mts')]); + t.deepEqual(main.resolvePossibleOutOfBandCompilationSources(path.join(projectDirectory, 'build/foo.mjs')), [ + path.join(projectDirectory, 'src/foo.mjs'), + path.join(projectDirectory, 'src/foo.mts'), + ]); }); test('main() resolvePossibleOutOfBandCompilationSources() .js and .js, .ts and .tsx configured', withProvider, (t, provider) => { const main = provider.main({config: {extensions: ['js', 'ts', 'tsx'], rewritePaths: {'src/': 'build/'}, compile: false}}); - t.deepEqual(main.resolvePossibleOutOfBandCompilationSources(path.join(projectDirectory, 'build/foo.js')), [path.join(projectDirectory, 'src/foo.js'), path.join(projectDirectory, 'src/foo.ts'), path.join(projectDirectory, 'src/foo.tsx')]); + t.deepEqual(main.resolvePossibleOutOfBandCompilationSources(path.join(projectDirectory, 'build/foo.js')), [ + path.join(projectDirectory, 'src/foo.js'), + path.join(projectDirectory, 'src/foo.ts'), + path.join(projectDirectory, 'src/foo.tsx'), + ]); }); test('main() resolvePossibleOutOfBandCompilationSources() returns the first possible path that exists', withProvider, (t, provider) => { diff --git a/test/snapshots/compilation.js.md b/test/snapshots/compilation.js.md index 1b54123..f036173 100644 --- a/test/snapshots/compilation.js.md +++ b/test/snapshots/compilation.js.md @@ -21,4 +21,5 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 `Command failed with exit code 2: tsc --incremental␊ + ␊ typescript/typescript.ts(1,1): error TS2304: Cannot find name 'a'.` diff --git a/test/snapshots/compilation.js.snap b/test/snapshots/compilation.js.snap index 9171aa3..ae9adce 100644 Binary files a/test/snapshots/compilation.js.snap and b/test/snapshots/compilation.js.snap differ diff --git a/test/snapshots/protocol-ava-6.js.snap b/test/snapshots/protocol-ava-6.js.snap index 6f7ecc7..b1c0239 100644 Binary files a/test/snapshots/protocol-ava-6.js.snap and b/test/snapshots/protocol-ava-6.js.snap differ diff --git a/xo.config.js b/xo.config.js new file mode 100644 index 0000000..f922e10 --- /dev/null +++ b/xo.config.js @@ -0,0 +1,11 @@ +/** @type {import('xo').FlatXoConfig} */ +const xoConfig = [ + { + ignores: [ + 'test/broken-fixtures', + 'test/fixtures/**/compiled/**', + ], + }, +]; + +export default xoConfig;