feat: align dev tooling with actions/typescript-action template (Scope B)#126
Merged
Merged
Conversation
…plate Bump versions to match the official actions/typescript-action template where possible without breaking changes: - eslint: 8.51.0 -> 10.0.0 (with new @eslint/js, @eslint/compat, @eslint/eslintrc) - jest: 29.7.0 -> 30.2.0; ts-jest: 29.1.1 -> 29.4.6; @types/jest: 29.5.6 -> 30.0.0 - typescript: 5.2.2 -> 5.9.3; @types/node: 24.5.2 -> 25.2.3 - prettier: 3.2.5 -> 3.8.1; eslint-plugin-prettier: 5.0.1 -> 5.5.5 - eslint-plugin-jest: 27.4.2 -> 29.15.0 - add @typescript-eslint/eslint-plugin@8.56.0 and eslint-config-prettier@10.1.8 - drop eslint-plugin-github, jest-circus (default in Jest 30), js-yaml (unused) - rename format scripts to format:write / format:check; lint now scans '.' instead of 'src/**/*.ts' - bump version to 2.2.0
Replace .eslintrc.json + .eslintignore with eslint.config.mjs to match the actions/typescript-action template and ESLint v10 requirements. - extends eslint:recommended, @typescript-eslint/recommended, jest/recommended, prettier/recommended - preserves the existing project-specific TypeScript rules (no-explicit-any, explicit-member-accessibility, etc.) - drops parserOptions.project since no type-aware rules are used (also speeds up lint)
- switch to ts-jest preset - drop explicit testRunner: 'jest-circus/runner' (default since Jest 27) - tighten testMatch to **/__tests__/**/*.test.ts
- remove unused 'catch (e)' parameter (use optional catch binding) - replace 'catch (error: any)' with 'catch (error)' plus instanceof Error narrowing - both flagged by @typescript-eslint/no-unused-vars and no-explicit-any under the new flat config
- replace Array<T> with T[] in WebhookBody interface and test type assertions (@typescript-eslint/array-type) - extract empty-string commit message case into its own test (jest/no-conditional-expect)
Output of 'prettier --write .' which now formats every file instead of only *.ts. Touched files: renovate configs, CHANGELOG, README, action.yml, tsconfig.json.
Regenerate dist/main/index.js via 'npm run package' after the source and tooling changes above. Bundle size grew ~79KB / 4.8% purely from TypeScript 5.9 emitting additional ESM/CJS interop helpers (__exportStar, __createBinding, accessor helpers) and a slightly larger ncc runtime preamble; production dependencies are unchanged.
ahanoff
added a commit
that referenced
this pull request
Jun 22, 2026
…core@3) (#129) ## What Complete the template alignment by migrating from CJS+ncc to ESM+rollup. This is **Scope C** — the remaining work after [PR #126 (Scope B)](#126) which covered ESLint flat config + Jest 30 + dep version bumps. ## Breaking changes | Area | Before | After | |---|---|---| | Module system | CommonJS | **ESM** (`"type": "module"`) | | Bundler | `@vercel/ncc` → `dist/main/index.js` (CJS) | **rollup** → `dist/index.js` (ESM) | | `@actions/core` | `^1.10.1` (CJS) | **`^3.0.1`** (pure ESM) | | `@actions/github` | `^6.0.0` (CJS, http-client v2 conflict) | **`^9.0.0`** (pure ESM, eliminates conflict) | | tsconfig | `es6` / `commonjs` | **`ES2022` / `NodeNext`** | | Action entry | `dist/main/index.js` | `dist/index.js` | | Version | 2.2.0 | **3.0.0** | **For action consumers**: no change needed. Same inputs, same outputs, same `node24` runtime. The only visible difference is the `main:` path in action.yml. ## Why Stay current with the official [actions/typescript-action](https://github.com/actions/typescript-action) template, which is now ESM-only: - `@actions/core@3` is pure ESM (no `require()` support) - `@actions/github@9` is pure ESM - Template uses rollup, not ncc - All new `@actions/*` releases will be ESM-only ## How ### Rollup bundler - `rollup-plugin-esbuild` for TypeScript transpilation (uses `transform` hook — `@rollup/plugin-typescript` v11/v12 use `resolveId`+`load` hooks which silently skip entry points, a known issue) - `@rollup/plugin-commonjs` converts CJS deps (adaptivecards stack) to ESM at build time - `@rollup/plugin-json` — **critical**: adaptivecards-templating's source does `require('./../package.json')` which rollup cannot handle natively - `@rollup/plugin-node-resolve` for module resolution ### Source changes (minimal) - 2 relative imports get `.js` extensions for NodeNext: `'./card'` → `'./card.js'` - No other source changes — `@actions/core@3` APIs (`getInput`, `info`, `warning`, `error`, `setFailed`) are byte-identical to v1 ### Jest ESM mode - `export default` config (was `module.exports`) - `extensionsToTreatAsEsm: ['.ts']`, `useESM: true`, `ts-jest-resolver` - `NODE_OPTIONS=--experimental-vm-modules` in test script ## Compatibility research Before implementing, investigated all runtime deps for ESM compatibility: | Package | Format | Bundles via commonjs plugin? | |---|---|---| | `adaptive-expressions` | CJS-only | ✅ | | `adaptivecards` | CJS-only (broken for native ESM import — [issue #9155](microsoft/AdaptiveCards#9155)) | ✅ (commonjs plugin sidesteps the bug) | | `adaptivecards-templating` | CJS-only + `require('./../package.json')` | ✅ + `@rollup/plugin-json` | | `cockatiel` | Dual (has `module` field) | ✅ (rollup picks ESM automatically) | ## Bundle size | Metric | ncc (before) | rollup (after) | |---|---|---| | `dist/index.js` | 1.7 MB (minified CJS) | 3.8 MB (ESM + sourcemap) | | Build time | 4.0s | 2.1s | Larger because rollup doesn't minify by default (template doesn't either). Functionally irrelevant for GitHub Actions runtime. Can add minification later if desired. ## Verification | Check | Result | |---|---| | `npm run lint` | ✅ clean | | `npm run build` (`tsc --noEmit`) | ✅ clean | | `npm test` (Jest 30 ESM mode) | ✅ 28/28 pass in 0.43s | | `npm run package` (rollup) | ✅ builds in 2.1s | | `npm run all` | ✅ full pipeline passes | ## Deviation from template | Template uses | We use | Reason | |---|---|---| | `@rollup/plugin-typescript` | `rollup-plugin-esbuild` | Plugin's `resolveId`+`load` hooks don't intercept entry points (confirmed broken in v11.0.0–v12.3.0 with rollup 4.x). esbuild uses `transform` hook which works reliably. Type checking handled by `tsc --noEmit`. | | `rollup.config.ts` | `rollup.config.mjs` | Eliminates need for `--configPlugin` flag (which would require `@rollup/plugin-typescript` we dropped). Config is a plain object, doesn't need TypeScript types. | | No `@actions/github` | `@actions/github@9` | Our action needs Octokit for workflow/job status queries. | ## Not in scope - Minification (rollup output is unminified, matching template behavior) - `@github/local-action` for local testing (can add separately) - Coverage badge generation (can add separately)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Align the repo's dev tooling with the official actions/typescript-action template, Scope B (medium): dep version bumps + Jest 30 + ESLint 10 flat config migration. Keeps
@vercel/nccbundler, CommonJS output,@actions/corev1, and the existing tsconfig target — those are deferred to a future Scope C migration.Why
The official template has moved to ESLint 10 (flat config) and Jest 30. Staying on ESLint 8 / Jest 29 leaves the repo on unsupported major versions and makes it harder to consume template updates.
Changes
Dependencies
eslint^8.51.0^10.0.0jest^29.7.0^30.2.0@types/jest^29.5.6^30.0.0typescript^5.2.2^5.9.3@types/node^24.5.2^25.2.3prettier3.2.5^3.8.1ts-jest^29.1.1^29.4.6eslint-plugin-jest^27.4.2^29.15.0eslint-plugin-prettier^5.0.1^5.5.5Added:
@eslint/compat,@eslint/eslintrc,@eslint/js,@typescript-eslint/eslint-plugin,eslint-config-prettierRemoved:
eslint-plugin-github(not in template),jest-circus(default in Jest 30),js-yaml(not used in source)Tooling
eslint.config.mjs(flat config) replaces.eslintrc.json+.eslintignorejest.config.jssimplified:preset: 'ts-jest', dropped explicitjest-circus/runnerformat→format:write,format-check→format:check,lintnow scans.(whole project)**/*.tsonly) — touchesREADME.md,action.yml,tsconfig.json, renovate configs,CHANGELOG.mdSource (driven by stricter lint rules)
src/main.ts: removed unusedcatch (e)param;catch (error: any)→catch (error)+instanceof Errornarrowing (noas any)src/card.ts+src/__tests__/card.test.ts:Array<T>→T[]; extracted empty-string commit case into its own test (jest/no-conditional-expect)Version
2.1.0→2.2.0(minor: developer tooling changed, action runtime behavior unchanged)Bundle size note
dist/main/index.jsgrew 1,633,205 → 1,712,720 bytes (+79KB / 4.8%). Cause: TypeScript 5.9 emits additional ESM↔CJS interop helpers (__exportStar,__createBinding,__defineGetter/__defineSetter/__lookupGetter/__lookupSetter,__moduleExports,__namespace) and thencc0.38.0 → 0.38.4 runtime preamble is slightly larger. All production deps are byte-identical — no runtime code was added.Verification
npm run lintnpm run build(tsc)npm test(Jest 30)npm run package(ncc)npm run allOut of scope (deferred to future Scope C PR)
@actions/corev1 → v3 (breaking API changes)@vercel/ncc→rollupbundler swap"type": "module"ESM migrationtsconfig.json→ES2022/NodeNext