├── .gitignore ├── .nvmrc ├── README.md ├── package-commonjs ├── import-log.js ├── import.js ├── import.ts ├── interops │ ├── cjs.cjs │ ├── cts.cts │ ├── esm.js │ ├── mjs.mjs │ ├── mts.mts │ └── ts.ts ├── package.json ├── require-log.js ├── require.js ├── require.ts ├── resolution │ ├── cts.cts │ ├── directory │ │ └── index.ts │ ├── mts.mts │ └── ts.ts ├── transformation │ ├── cjs-scope.cjs │ ├── cjs-scope.cts │ ├── cjs-scope.js │ ├── cjs-scope.mjs │ ├── cjs-scope.mts │ ├── cjs-scope.ts │ ├── esm-export.js │ ├── esm-import.js │ ├── import-meta-url.js │ ├── source-maps.ts │ └── ts.ts └── tsconfig.json ├── package-module ├── import-log.js ├── import.js ├── import.ts ├── interops │ ├── cjs.cjs │ ├── cts.cts │ ├── esm.js │ ├── mjs.mjs │ ├── mts.mts │ └── ts.ts ├── package.json ├── require-log.js ├── require.js ├── require.ts ├── transformation │ ├── cjs-scope.cjs │ ├── cjs-scope.cts │ ├── cjs-scope.js │ ├── cjs-scope.mjs │ ├── cjs-scope.mts │ ├── cjs-scope.ts │ ├── source-maps.ts │ └── ts.ts └── tsconfig.json ├── package.json ├── pnpm-lock.yaml ├── scripts └── compare │ ├── index.ts │ ├── runtime-binaries │ ├── esbuild-runner.ts │ ├── index.ts │ ├── jiti.ts │ ├── sucrase.ts │ ├── swc-register.ts │ ├── ts-node.ts │ ├── tsm.ts │ └── tsx.ts │ ├── tests │ ├── dx.ts │ ├── index.ts │ ├── interop-commonjs.ts │ ├── interop-module.ts │ ├── performance.ts │ ├── project-stats.ts │ ├── resolution-import.ts │ ├── resolution-require.ts │ ├── testing.ts │ ├── transformation-commonjs.ts │ └── transformation-module.ts │ ├── types.ts │ └── utils │ ├── create-runtime.ts │ ├── markdown.ts │ ├── test.ts │ └── update-markdown.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | # Dependency directories 13 | /node_modules/ 14 | 15 | # Output of 'npm pack' 16 | *.tgz 17 | 18 | # dotenv environment variables file 19 | .env 20 | .env.test 21 | 22 | # VSCode 23 | .vscode 24 | 25 | # Cache 26 | .eslintcache 27 | 28 | # Distribution 29 | dist 30 | 31 | # Link config 32 | link.config.json 33 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.14.2 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeScript runtime comparisons 2 | 3 | Comparison of Node.js TypeScript runtimes. 4 | 5 | > **Disclaimer:** This comparison is by the author & maintainer of [tsx] 6 | 7 | ## Compared runtimes 8 | 9 | - [tsx] 10 | - [@swc/register] 11 | - [esbuild-runner] 12 | - [jiti] 13 | - [sucrase] 14 | - [ts-node] 15 | - [tsm] 16 | 17 | 18 | ## Methodology 19 | - Tested on Node.js v12.20.0 because they all support it, and the `node:` prefix is not supported in `require()` 20 | 21 | - Tested in both [package types](https://nodejs.org/api/packages.html#type) `commonjs` & `module` when applicable 22 | 23 | 24 | ### Symbols 25 | 26 | | Symbol | Description | 27 | | :----: | ----------- | 28 | | ✅ | Pass (Sometimes clickable) | 29 | | ❌ | Fail | 30 | | ⛔️ | Error (Hover to see error message) | 31 | 32 | ## Project stats 33 | 34 | 35 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 36 | | :------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------: | 37 | | npm downloads | [![](https://img.shields.io/npm/dm/tsx?label)](https://www.npmjs.com/package/tsx) | [![](https://img.shields.io/npm/dm/@swc/register?label)](https://www.npmjs.com/package/@swc/register) | [![](https://img.shields.io/npm/dm/esbuild-runner?label)](https://www.npmjs.com/package/esbuild-runner) | [![](https://img.shields.io/npm/dm/jiti?label)](https://www.npmjs.com/package/jiti) | [![](https://img.shields.io/npm/dm/sucrase?label)](https://www.npmjs.com/package/sucrase) | [![](https://img.shields.io/npm/dm/ts-node?label)](https://www.npmjs.com/package/ts-node) | [![](https://img.shields.io/npm/dm/tsm?label)](https://www.npmjs.com/package/tsm) | 38 | | Install size | [![](https://badgen.net/packagephobia/install/tsx?color=blue&label)](https://packagephobia.com/result?p=tsx) | [![](https://badgen.net/packagephobia/install/@swc/register?color=blue&label)](https://packagephobia.com/result?p=@swc/register) | [![](https://badgen.net/packagephobia/install/esbuild-runner?color=blue&label)](https://packagephobia.com/result?p=esbuild-runner) | [![](https://badgen.net/packagephobia/install/jiti?color=blue&label)](https://packagephobia.com/result?p=jiti) | [![](https://badgen.net/packagephobia/install/sucrase?color=blue&label)](https://packagephobia.com/result?p=sucrase) | [![](https://badgen.net/packagephobia/install/ts-node?color=blue&label)](https://packagephobia.com/result?p=ts-node) | [![](https://badgen.net/packagephobia/install/tsm?color=blue&label)](https://packagephobia.com/result?p=tsm) | 39 | | GitHub stars | [![](https://img.shields.io/github/stars/esbuild-kit/tsx?color=gray&label)](https://github.com/esbuild-kit/tsx/stargazers) | [![](https://img.shields.io/github/stars/swc-project/register?color=gray&label)](https://github.com/swc-project/register/stargazers) | [![](https://img.shields.io/github/stars/folke/esbuild-runner?color=gray&label)](https://github.com/folke/esbuild-runner/stargazers) | [![](https://img.shields.io/github/stars/unjs/jiti?color=gray&label)](https://github.com/unjs/jiti/stargazers) | [![](https://img.shields.io/github/stars/alangpierce/sucrase?color=gray&label)](https://github.com/alangpierce/sucrase/stargazers) | [![](https://img.shields.io/github/stars/TypeStrong/ts-node?color=gray&label)](https://github.com/TypeStrong/ts-node/stargazers) | [![](https://img.shields.io/github/stars/lukeed/tsm?color=gray&label)](https://github.com/lukeed/tsm/stargazers) | 40 | | Issues open | [![](https://img.shields.io/github/issues-raw/esbuild-kit/tsx?color=orange&label)](https://github.com/esbuild-kit/tsx/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [![](https://img.shields.io/github/issues-raw/swc-project/register?color=orange&label)](https://github.com/swc-project/register/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [![](https://img.shields.io/github/issues-raw/folke/esbuild-runner?color=orange&label)](https://github.com/folke/esbuild-runner/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [![](https://img.shields.io/github/issues-raw/unjs/jiti?color=orange&label)](https://github.com/unjs/jiti/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [![](https://img.shields.io/github/issues-raw/alangpierce/sucrase?color=orange&label)](https://github.com/alangpierce/sucrase/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [![](https://img.shields.io/github/issues-raw/TypeStrong/ts-node?color=orange&label)](https://github.com/TypeStrong/ts-node/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [![](https://img.shields.io/github/issues-raw/lukeed/tsm?color=orange&label)](https://github.com/lukeed/tsm/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | 41 | | Issues closed | [![](https://img.shields.io/github/issues-closed-raw/esbuild-kit/tsx?color=blue&label)](https://github.com/esbuild-kit/tsx/issues?q=is%3Aissue+is%3Aclosed) | [![](https://img.shields.io/github/issues-closed-raw/swc-project/register?color=blue&label)](https://github.com/swc-project/register/issues?q=is%3Aissue+is%3Aclosed) | [![](https://img.shields.io/github/issues-closed-raw/folke/esbuild-runner?color=blue&label)](https://github.com/folke/esbuild-runner/issues?q=is%3Aissue+is%3Aclosed) | [![](https://img.shields.io/github/issues-closed-raw/unjs/jiti?color=blue&label)](https://github.com/unjs/jiti/issues?q=is%3Aissue+is%3Aclosed) | [![](https://img.shields.io/github/issues-closed-raw/alangpierce/sucrase?color=blue&label)](https://github.com/alangpierce/sucrase/issues?q=is%3Aissue+is%3Aclosed) | [![](https://img.shields.io/github/issues-closed-raw/TypeStrong/ts-node?color=blue&label)](https://github.com/TypeStrong/ts-node/issues?q=is%3Aissue+is%3Aclosed) | [![](https://img.shields.io/github/issues-closed-raw/lukeed/tsm?color=blue&label)](https://github.com/lukeed/tsm/issues?q=is%3Aissue+is%3Aclosed) | 42 | | Last commit | ![](https://img.shields.io/github/last-commit/esbuild-kit/tsx?label) | ![](https://img.shields.io/github/last-commit/swc-project/register?label) | ![](https://img.shields.io/github/last-commit/folke/esbuild-runner?label) | ![](https://img.shields.io/github/last-commit/unjs/jiti?label) | ![](https://img.shields.io/github/last-commit/alangpierce/sucrase?label) | ![](https://img.shields.io/github/last-commit/TypeStrong/ts-node?label) | ![](https://img.shields.io/github/last-commit/lukeed/tsm?label) | 43 | 44 | 45 | 46 | ## Transformation 47 | 48 | Supported transformation features and code tranformation correctness. 49 | 50 | 51 | #### Package type: CommonJS 52 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 53 | | :-------------------------------- | :---: | :-------------: | :--------------: | :----: | :-------: | :-------: | :---: | 54 | | TypeScript syntax | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 55 | | ESM → CJS: import/export syntax | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | 56 | | ESM → CJS: `import.meta.url` shim | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | 57 | | CJS scope in `.js` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 58 | | CJS scope in `.ts` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | 59 | | CJS scope in `.cjs` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 60 | | CJS scope in `.cts` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | 61 | | No CJS scope in `.mjs` file | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | 62 | | No CJS scope in `.mts` file | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | 63 | | Source maps | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | 64 | 65 | 66 | 67 | #### Package type: Module 68 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 69 | | :-------------------------- | :---: | :---------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------: | :----: | :---------------------------------------------------------------------------------------------------------------------------------------------: | :-------: | :---: | 70 | | TypeScript syntax | ✅ | ⛔️ | ⛔️ | ✅ | ⛔️ | ✅ | ✅ | 71 | | CJS scope in `.cjs` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 72 | | CJS scope in `.cts` file | ✅ | ⛔️ | ⛔️ | ✅ | ⛔️ | ✅ | ❌ | 73 | | No CJS scope in `.js` file | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | 74 | | No CJS scope in `.ts` file | ✅ | ⛔️ | ⛔️ | ❌ | ⛔️ | ✅ | ✅ | 75 | | No CJS scope in `.mjs` file | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | 76 | | No CJS scope in `.mts` file | ✅ | ⛔️ | ⛔️ | ❌ | ⛔️ | ✅ | ✅ | 77 | | Source maps | ✅ | ⛔️ | ⛔️ | ❌ | ⛔️ | ✅ | ✅ | 78 | 79 | 80 | 81 | _* [CommonJS scope](https://nodejs.org/api/modules.html#the-module-scope) (CJS scope) refers to having the following variables available in the module scope: `module`, `exports`, `require`, `__filename`, `__dirname`._ 82 | 83 | 84 | ## Resolution 85 | Whether `require()`/`import()` can resolve a given specifier. 86 | 87 | 88 | #### `require()` 89 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 90 | | :------------------------------------------------------------------------------------------------------- | :---: | :-------------: | :--------------: | :----: | :-------: | :-------: | :---: | 91 | | `.ts` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 92 | | `.ts` file [via `.js`](https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | 93 | | `.ts` file without extension | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | 94 | | `index.ts` file via directory | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | 95 | | `.cts` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 96 | | `.cts` file [via `.cjs`](https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | 97 | | `.mts` file | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | 98 | | `.mts` file [via `.mjs`](https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | 99 | | `node:` prefix | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | 100 | | tsconfig.json [paths](https://www.typescriptlang.org/tsconfig#paths) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | 101 | 102 | 103 | 104 | #### `import()` 105 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 106 | | :------------------------------------------------------------------------------------------------------- | :---: | :-------------: | :--------------: | :----: | :-------: | :-------: | :---: | 107 | | `.ts` file | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | 108 | | `.ts` file [via `.js`](https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | 109 | | `.ts` file without extension | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | 110 | | `index.ts` file via directory | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | 111 | | `.cts` file | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | 112 | | `.cts` file [via `.cjs`](https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | 113 | | `.mts` file | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | 114 | | `.mts` file [via `.mjs`](https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions) | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | 115 | | tsconfig.json [paths](https://www.typescriptlang.org/tsconfig#paths) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | 116 | 117 | 118 | 119 | ## Interoperability 120 | 121 | Whether it can correctly load a file for interoperability. 122 | 123 | 124 | #### Package type: CommonJS 125 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 126 | | :-------------------------------- | :---: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: | 127 | | require() `.js` file (ESM export) | ✅ | ⛔️ | ✅ | ✅ | ✅ | ✅ | ⛔️ | 128 | | require() `.ts` file (ESM export) | ✅ | ⛔️ | ✅ | ✅ | ✅ | ✅ | ⛔️ | 129 | | require() `.cjs` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 130 | | require() `.cts` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 131 | | require() `.mjs` file | ✅ | ⛔️ | ✅ | ✅ | ⛔️ | ⛔️ | ⛔️ | 132 | | require() `.mts` file | ✅ | ⛔️ | ⛔️ | ✅ | ⛔️ | ⛔️ | ⛔️ | 133 | | import() `.js` file (ESM export) | ✅ | ⛔️ | ❌ | ⛔️ | ✅ | ❌ | ⛔️ | 134 | | import() `.ts` file (ESM export) | ✅ | ⛔️ | ⛔️ | ⛔️ | ✅ | ❌ | ✅ | 135 | | import() `.cjs` file | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | 136 | | import() `.cts` file | ✅ | ⛔️ | ⛔️ | ⛔️ | ❌ | ✅ | ✅ | 137 | | import() `.mjs` file | ✅ | ✅ | ✅ | ✅ | ⛔️ | ✅ | ✅ | 138 | | import() `.mts` file | ✅ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | ✅ | ✅ | 139 | 140 | 141 | 142 | #### Package type: Module 143 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 144 | | :-------------------------------- | :---: | :---------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | 145 | | require() `.js` file (ESM export) | ✅ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | 146 | | require() `.ts` file (ESM export) | ✅ | ⛔️ | ✅ | ⛔️ | ✅ | ⛔️ | ⛔️ | 147 | | require() `.cjs` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 148 | | require() `.cts` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 149 | | require() `.mjs` file | ✅ | ⛔️ | ✅ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | 150 | | require() `.mts` file | ✅ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | ⛔️ | 151 | | import() `.js` file (ESM export) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 152 | | import() `.ts` file (ESM export) | ✅ | ⛔️ | ⛔️ | ✅ | ⛔️ | ✅ | ✅ | 153 | | import() `.cjs` file | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | 154 | | import() `.cts` file | ✅ | ⛔️ | ⛔️ | ❌ | ⛔️ | ✅ | ✅ | 155 | | import() `.mjs` file | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 156 | | import() `.mts` file | ✅ | ⛔️ | ⛔️ | ✅ | ⛔️ | ✅ | ✅ | 157 | 158 | 159 | 160 | ## Performance features 161 | 162 | 163 | 164 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 165 | | :--------- | :--------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------: | :-----------------------------------: | 166 | | Compiler | [esbuild](https://esbuild.github.io/) | [SWC](https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/package.json#L38) | [esbuild](https://esbuild.github.io/) | [Babel](https://github.com/unjs/jiti/blob/main/package.json#L26) | [Sucrase (Babel fork)](https://github.com/alangpierce/sucrase#:~:text=sucrase's%20parser%20is%20forked%20from%20babel's%20parser) | [TypeScript](https://github.com/TypeStrong/ts-node#compiler) / [SWC](https://github.com/TypeStrong/ts-node#swc-1) | [esbuild](https://esbuild.github.io/) | 167 | | Disk cache | [✅ ?](https://github.com/esbuild-kit/tsx#cache) | ❌ | [✅ ?](https://github.com/folke/esbuild-runner/blob/9dfb19f8fdead4d56abe4b70fe16bde745fd4d9c/src/cli.ts#L12) | [✅ ?](https://github.com/unjs/jiti#cache) | ❌ | [❌ ?](https://github.com/TypeStrong/ts-node/issues/908#issuecomment-1060214613) | ❌ | 168 | 169 | 170 | ## DX features 171 | 172 | 173 | 174 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 175 | | :---------------------------------- | :------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------: | 176 | | TypeScript REPL | [✅ ?](https://github.com/esbuild-kit/tsx#repl) | ❌ | ❌ | ❌ | ❌ | [✅ ?](https://github.com/TypeStrong/ts-node#:~:text=Typechecking%20(optional)-,REPL,-Write%20standalone%20scripts) | ❌ | 177 | | Watch mode | [✅ ?](https://github.com/esbuild-kit/tsx#watch-mode) | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | 178 | | Type checking | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | 179 | | Hides experimental feature warnings | ✅ | - | - | - | - | [✅ ?](https://github.com/TypeStrong/ts-node/blob/599f28bbed574003aea08cffab098a3348475649/src/child/child-require.ts#L19-L24) | ❌ | 180 | | Binaries | [tsx](https://github.com/esbuild-kit/tsx/blob/3e81d19bf759b512eb74360861f5abeb9d638ef0/package.json#L30) | [swc-node](https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/package.json#L54) | [esr](https://github.com/folke/esbuild-runner/blob/949c847e413f5ce32aa2b06eab2a80ea99c221d3/package.json#L21) | [jiti](https://github.com/unjs/jiti/blob/912645967d095b7d1a97829e2013019b948a9761/package.json#L9) | [sucrase-node](https://github.com/alangpierce/sucrase/blob/c01f429ddc86e0d819396170981284b8593cdb29/package.json#L10-L13) | [ts-node, ts-node-esm, +4](https://github.com/TypeStrong/ts-node/blob/14323f9d00d5c7051ac09b944c7f423e442145ea/package.json#L38-L43) | [tsm](https://github.com/lukeed/tsm/blob/d65d835a8a9fc3bb60dae7336eabdd713bfed0fc/package.json#L7) | 181 | 182 | 183 | 184 | ## Testing 185 | 186 | 187 | 188 | | | [tsx] | [@swc/register] | [esbuild-runner] | [jiti] | [sucrase] | [ts-node] | [tsm] | 189 | | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | :--------------: | :------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------: | 190 | | Operating systems | [Linux & Windows](https://github.com/esbuild-kit/tsx/blob/3e81d19bf759b512eb74360861f5abeb9d638ef0/.github/workflows/test.yml#L13) | [Linux](https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/.github/workflows/test.yml#L6) | No tests | [Linux & Windows](https://github.com/unjs/jiti/blob/912645967d095b7d1a97829e2013019b948a9761/.github/workflows/ci.yml#L17) | [Linux](https://github.com/alangpierce/sucrase/blob/2a3f723/.github/workflows/build.yml) | [Linux & Windows](https://github.com/TypeStrong/ts-node/blob/14323f9d00d5c7051ac09b944c7f423e442145ea/.github/workflows/continuous-integration.yml#L52) | [Linux & Windows](https://github.com/lukeed/tsm/blob/d65d835a8a9fc3bb60dae7336eabdd713bfed0fc/.github/workflows/ci.yml#L19) | 191 | | Node.js versions | [12.20 ~ 18](https://github.com/esbuild-kit/tsx/blob/3e81d19bf759b512eb74360861f5abeb9d638ef0/tests/index.ts#L12-L25) | [Latest LTS](https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/.github/workflows/test.yml#L11) | No tests | [16](https://github.com/unjs/jiti/blob/912645967d095b7d1a97829e2013019b948a9761/.github/workflows/ci.yml#L18) | [14 & 16](https://github.com/alangpierce/sucrase/blob/2a3f723/.github/workflows/build.yml) | [12 ~ 18 + Nightly](https://github.com/TypeStrong/ts-node/blob/14323f9d00d5c7051ac09b944c7f423e442145ea/.github/workflows/continuous-integration.yml#L55-L143) | [12.22.10 ~ 16.14](https://github.com/lukeed/tsm/blob/d65d835a8a9fc3bb60dae7336eabdd713bfed0fc/.github/workflows/ci.yml#L18) | 192 | 193 | 194 | 195 | 196 | 197 | 198 | [tsx]: https://github.com/esbuild-kit/tsx 199 | [@swc/register]: https://github.com/swc-project/register 200 | [esbuild-runner]: https://github.com/folke/esbuild-runner 201 | [jiti]: https://github.com/unjs/jiti 202 | [sucrase]: https://github.com/alangpierce/sucrase 203 | [ts-node]: https://github.com/TypeStrong/ts-node 204 | [tsm]: https://github.com/lukeed/tsm 205 | 206 | -------------------------------------------------------------------------------- /package-commonjs/import-log.js: -------------------------------------------------------------------------------- 1 | import(process.argv[2]).then(m => console.log(JSON.stringify(m))); 2 | -------------------------------------------------------------------------------- /package-commonjs/import.js: -------------------------------------------------------------------------------- 1 | import(process.argv[2]); 2 | -------------------------------------------------------------------------------- /package-commonjs/import.ts: -------------------------------------------------------------------------------- 1 | import(process.argv[2]); 2 | -------------------------------------------------------------------------------- /package-commonjs/interops/cjs.cjs: -------------------------------------------------------------------------------- 1 | module.exports = true; 2 | -------------------------------------------------------------------------------- /package-commonjs/interops/cts.cts: -------------------------------------------------------------------------------- 1 | module.exports = true; 2 | -------------------------------------------------------------------------------- /package-commonjs/interops/esm.js: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-commonjs/interops/mjs.mjs: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-commonjs/interops/mts.mts: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-commonjs/interops/ts.ts: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-commonjs/package.json: -------------------------------------------------------------------------------- 1 | { "type": "commonjs" } 2 | -------------------------------------------------------------------------------- /package-commonjs/require-log.js: -------------------------------------------------------------------------------- 1 | console.log(JSON.stringify(require(process.argv[2]))); 2 | -------------------------------------------------------------------------------- /package-commonjs/require.js: -------------------------------------------------------------------------------- 1 | require(process.argv[2]); 2 | -------------------------------------------------------------------------------- /package-commonjs/require.ts: -------------------------------------------------------------------------------- 1 | require(process.argv[2]); 2 | -------------------------------------------------------------------------------- /package-commonjs/resolution/cts.cts: -------------------------------------------------------------------------------- 1 | console.log(true); 2 | -------------------------------------------------------------------------------- /package-commonjs/resolution/directory/index.ts: -------------------------------------------------------------------------------- 1 | console.log(true); 2 | -------------------------------------------------------------------------------- /package-commonjs/resolution/mts.mts: -------------------------------------------------------------------------------- 1 | console.log(true); 2 | -------------------------------------------------------------------------------- /package-commonjs/resolution/ts.ts: -------------------------------------------------------------------------------- 1 | console.log(true); 2 | -------------------------------------------------------------------------------- /package-commonjs/transformation/cjs-scope.cjs: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined' 7 | ); 8 | -------------------------------------------------------------------------------- /package-commonjs/transformation/cjs-scope.cts: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-commonjs/transformation/cjs-scope.js: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-commonjs/transformation/cjs-scope.mjs: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined' 7 | ); 8 | -------------------------------------------------------------------------------- /package-commonjs/transformation/cjs-scope.mts: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-commonjs/transformation/cjs-scope.ts: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-commonjs/transformation/esm-export.js: -------------------------------------------------------------------------------- 1 | export default 1234; 2 | -------------------------------------------------------------------------------- /package-commonjs/transformation/esm-import.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | console.log(Boolean(fs)); 4 | 5 | export default 1234; 6 | -------------------------------------------------------------------------------- /package-commonjs/transformation/import-meta-url.js: -------------------------------------------------------------------------------- 1 | console.log( 2 | import.meta.url 3 | && import.meta.url.endsWith('import-meta-url.js'), 4 | ); 5 | -------------------------------------------------------------------------------- /package-commonjs/transformation/source-maps.ts: -------------------------------------------------------------------------------- 1 | type A = number; console.log(/:1:43/.test(new Error().stack.split('\n\n').pop())); 2 | -------------------------------------------------------------------------------- /package-commonjs/transformation/ts.ts: -------------------------------------------------------------------------------- 1 | function log(value: boolean) { 2 | console.log(value); 3 | } 4 | 5 | log(true); 6 | -------------------------------------------------------------------------------- /package-commonjs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "node16", 4 | "allowJs": true, 5 | "esModuleInterop": true, 6 | "paths": { 7 | "prefix/*": ["./resolution/*"] 8 | } 9 | }, 10 | "ts-node": { 11 | "transpileOnly": true, 12 | "experimentalResolver": true, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /package-module/import-log.js: -------------------------------------------------------------------------------- 1 | import(process.argv[2]).then(m => console.log(JSON.stringify(m))); 2 | -------------------------------------------------------------------------------- /package-module/import.js: -------------------------------------------------------------------------------- 1 | import(process.argv[2]); 2 | -------------------------------------------------------------------------------- /package-module/import.ts: -------------------------------------------------------------------------------- 1 | import(process.argv[2]); 2 | -------------------------------------------------------------------------------- /package-module/interops/cjs.cjs: -------------------------------------------------------------------------------- 1 | module.exports = true; 2 | -------------------------------------------------------------------------------- /package-module/interops/cts.cts: -------------------------------------------------------------------------------- 1 | module.exports = true; 2 | -------------------------------------------------------------------------------- /package-module/interops/esm.js: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-module/interops/mjs.mjs: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-module/interops/mts.mts: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-module/interops/ts.ts: -------------------------------------------------------------------------------- 1 | export default true; 2 | -------------------------------------------------------------------------------- /package-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /package-module/require-log.js: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'module'; 2 | 3 | const require = createRequire(import.meta.url); 4 | console.log(JSON.stringify(require(process.argv[2]))); 5 | -------------------------------------------------------------------------------- /package-module/require.js: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'module'; 2 | 3 | const require = createRequire(import.meta.url); 4 | require(process.argv[2]); 5 | -------------------------------------------------------------------------------- /package-module/require.ts: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'module'; 2 | 3 | const require = createRequire(import.meta.url); 4 | require(process.argv[2]); 5 | -------------------------------------------------------------------------------- /package-module/transformation/cjs-scope.cjs: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined' 7 | ); 8 | -------------------------------------------------------------------------------- /package-module/transformation/cjs-scope.cts: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-module/transformation/cjs-scope.js: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-module/transformation/cjs-scope.mjs: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined' 7 | ); 8 | -------------------------------------------------------------------------------- /package-module/transformation/cjs-scope.mts: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-module/transformation/cjs-scope.ts: -------------------------------------------------------------------------------- 1 | console.log( 2 | typeof exports !== 'undefined' 3 | && typeof require !== 'undefined' 4 | && typeof module !== 'undefined' 5 | && typeof __filename !== 'undefined' 6 | && typeof __dirname !== 'undefined', 7 | ); 8 | -------------------------------------------------------------------------------- /package-module/transformation/source-maps.ts: -------------------------------------------------------------------------------- 1 | type A = number; console.log(/:1:43/.test(new Error().stack.split('\n\n').pop())); 2 | -------------------------------------------------------------------------------- /package-module/transformation/ts.ts: -------------------------------------------------------------------------------- 1 | function log(value: boolean) { 2 | console.log(value); 3 | } 4 | 5 | log(true); 6 | -------------------------------------------------------------------------------- /package-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "allowJs": true, 5 | }, 6 | "ts-node": { 7 | "transpileOnly": true, 8 | "experimentalResolver": true, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "files": [], 4 | "scripts": { 5 | "start": "tsx scripts/compare", 6 | "lint": "eslint ." 7 | }, 8 | "dependencies": { 9 | "@pvtnbr/eslint-config": "^0.33.0", 10 | "@swc/core": "^1.3.34", 11 | "@swc/register": "^0.1.10", 12 | "@types/node": "^18.13.0", 13 | "comment-mark": "^1.1.1", 14 | "esbuild": "^0.17.7", 15 | "esbuild-runner": "^2.2.2", 16 | "eslint": "^8.33.0", 17 | "execa": "^6.1.0", 18 | "get-node": "^13.5.0", 19 | "jiti": "^1.17.0", 20 | "markdown-table": "^3.0.3", 21 | "sucrase": "^3.29.0", 22 | "ts-node": "^10.9.1", 23 | "tsm": "^2.3.0", 24 | "tsx": "^3.12.3", 25 | "typescript": "^4.9.5" 26 | }, 27 | "eslintConfig": { 28 | "extends": "@pvtnbr" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /scripts/compare/index.ts: -------------------------------------------------------------------------------- 1 | // import { inspect } from 'util'; 2 | import getNode from 'get-node'; 3 | import { loadRuntimeBinaries } from './runtime-binaries'; 4 | import { loadTests } from './tests'; 5 | import { RuntimeTested } from './types'; 6 | import { updateMarkdown } from './utils/update-markdown'; 7 | 8 | (async () => { 9 | // Test with 12.20.0 because it doesn't support node: prefix in imports 10 | const node = await getNode('12.20.0'); 11 | const runtimes = await loadRuntimeBinaries(); 12 | const tests = await loadTests(); 13 | const allTestResults = await Promise.all( 14 | runtimes.map(async (runtime) => { 15 | runtime.nodePath = node.path; 16 | 17 | const testResults = await Promise.all( 18 | tests.map( 19 | async ([name, testSuite]) => [ 20 | name, 21 | await testSuite(runtime), 22 | ] as const, 23 | ), 24 | ); 25 | 26 | return { 27 | runtime, 28 | ...Object.fromEntries(testResults), 29 | } as RuntimeTested; 30 | }), 31 | ); 32 | 33 | // console.log(inspect(results, { 34 | // colors: true, 35 | // depth: null, 36 | // })); 37 | 38 | await updateMarkdown( 39 | './README.md', 40 | runtimes, 41 | allTestResults, 42 | ); 43 | })(); 44 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/esbuild-runner.ts: -------------------------------------------------------------------------------- 1 | import { createRuntime } from '../utils/create-runtime'; 2 | import { link, PASS, CLICKABLE } from '../utils/markdown'; 3 | 4 | export default createRuntime({ 5 | name: 'esbuild-runner', 6 | npmName: 'esbuild-runner', 7 | githubRepo: 'folke/esbuild-runner', 8 | binaryPath: './node_modules/esbuild-runner/bin/esr.js', 9 | performance: { 10 | compiler: link('esbuild', 'https://esbuild.github.io/'), 11 | diskCache: link(PASS + CLICKABLE, 'https://github.com/folke/esbuild-runner/blob/9dfb19f8fdead4d56abe4b70fe16bde745fd4d9c/src/cli.ts#L12'), 12 | }, 13 | dx: { 14 | tsRepl: false, 15 | watchMode: false, 16 | typeChecking: false, 17 | hidesWarnings: '-', 18 | binaries: link('esr', 'https://github.com/folke/esbuild-runner/blob/949c847e413f5ce32aa2b06eab2a80ea99c221d3/package.json#L21'), 19 | }, 20 | testing: { 21 | os: 'No tests', 22 | nodeVersions: 'No tests', 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/index.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs/promises'; 2 | import path from 'path'; 3 | import type { Runtime } from '../types'; 4 | 5 | export async function loadRuntimeBinaries() { 6 | const files = await fs.readdir(__dirname); 7 | const runtimeBinaryPaths = files.filter(file => file !== 'index.ts' && file.endsWith('.ts')); 8 | 9 | const binaries = await Promise.all( 10 | runtimeBinaryPaths.map(async (binaryPath) => { 11 | const { default: runtime } = await import(path.join(__dirname, binaryPath)); 12 | 13 | return runtime as Runtime; 14 | }), 15 | ); 16 | 17 | binaries.sort((a, b) => ( 18 | a.name === 'tsx' 19 | ? -1 20 | : a.name.localeCompare(b.name) 21 | )); 22 | 23 | return binaries; 24 | } 25 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/jiti.ts: -------------------------------------------------------------------------------- 1 | import { createRuntime } from '../utils/create-runtime'; 2 | import { link, PASS, CLICKABLE } from '../utils/markdown'; 3 | 4 | export default createRuntime({ 5 | name: 'jiti', 6 | npmName: 'jiti', 7 | githubRepo: 'unjs/jiti', 8 | binaryPath: './node_modules/jiti/bin/jiti.js', 9 | performance: { 10 | compiler: link('Babel', 'https://github.com/unjs/jiti/blob/main/package.json#L26'), 11 | diskCache: link(PASS + CLICKABLE, 'https://github.com/unjs/jiti#cache'), 12 | }, 13 | dx: { 14 | tsRepl: false, 15 | watchMode: false, 16 | typeChecking: false, 17 | hidesWarnings: '-', 18 | binaries: link('jiti', 'https://github.com/unjs/jiti/blob/912645967d095b7d1a97829e2013019b948a9761/package.json#L9'), 19 | }, 20 | testing: { 21 | os: link('Linux & Windows', 'https://github.com/unjs/jiti/blob/912645967d095b7d1a97829e2013019b948a9761/.github/workflows/ci.yml#L17'), 22 | nodeVersions: link('16', 'https://github.com/unjs/jiti/blob/912645967d095b7d1a97829e2013019b948a9761/.github/workflows/ci.yml#L18'), 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/sucrase.ts: -------------------------------------------------------------------------------- 1 | import { createRuntime } from '../utils/create-runtime'; 2 | import { link } from '../utils/markdown'; 3 | 4 | export default createRuntime({ 5 | name: 'sucrase', 6 | npmName: 'sucrase', 7 | githubRepo: 'alangpierce/sucrase', 8 | binaryPath: './node_modules/sucrase/bin/sucrase-node', 9 | performance: { 10 | compiler: link('Sucrase (Babel fork)', "https://github.com/alangpierce/sucrase#:~:text=sucrase's%20parser%20is%20forked%20from%20babel's%20parser"), 11 | diskCache: false, 12 | }, 13 | dx: { 14 | tsRepl: false, 15 | watchMode: false, 16 | typeChecking: false, 17 | hidesWarnings: '-', 18 | binaries: link('sucrase-node', 'https://github.com/alangpierce/sucrase/blob/c01f429ddc86e0d819396170981284b8593cdb29/package.json#L10-L13'), 19 | }, 20 | testing: { 21 | os: link('Linux', 'https://github.com/alangpierce/sucrase/blob/2a3f723/.github/workflows/build.yml'), 22 | nodeVersions: link('14 & 16', 'https://github.com/alangpierce/sucrase/blob/2a3f723/.github/workflows/build.yml'), 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/swc-register.ts: -------------------------------------------------------------------------------- 1 | import { createRuntime } from '../utils/create-runtime'; 2 | import { link } from '../utils/markdown'; 3 | 4 | export default createRuntime({ 5 | name: '@swc/register', 6 | npmName: '@swc/register', 7 | githubRepo: 'swc-project/register', 8 | binaryPath: 'node_modules/@swc/register/bin/swc-node', 9 | performance: { 10 | compiler: link('SWC', 'https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/package.json#L38'), 11 | diskCache: false, 12 | }, 13 | dx: { 14 | tsRepl: false, 15 | watchMode: false, 16 | typeChecking: false, 17 | hidesWarnings: '-', 18 | binaries: link('swc-node', 'https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/package.json#L54'), 19 | }, 20 | testing: { 21 | os: link('Linux', 'https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/.github/workflows/test.yml#L6'), 22 | nodeVersions: link('Latest LTS', 'https://github.com/swc-project/register/blob/3b17c954386bbbe01100ac00a80ced68d6e10281/.github/workflows/test.yml#L11'), 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/ts-node.ts: -------------------------------------------------------------------------------- 1 | import { createRuntime } from '../utils/create-runtime'; 2 | import { 3 | link, PASS, FAIL, CLICKABLE, 4 | } from '../utils/markdown'; 5 | 6 | export default createRuntime({ 7 | name: 'ts-node', 8 | npmName: 'ts-node', 9 | githubRepo: 'TypeStrong/ts-node', 10 | binaryPath: 'node_modules/ts-node/dist/bin-esm.js', 11 | performance: { 12 | compiler: `${link('TypeScript', 'https://github.com/TypeStrong/ts-node#compiler')} / ${link('SWC', 'https://github.com/TypeStrong/ts-node#swc-1')}`, 13 | diskCache: link(FAIL + CLICKABLE, 'https://github.com/TypeStrong/ts-node/issues/908#issuecomment-1060214613'), 14 | }, 15 | dx: { 16 | tsRepl: link(PASS + CLICKABLE, 'https://github.com/TypeStrong/ts-node#:~:text=Typechecking%20(optional)-,REPL,-Write%20standalone%20scripts'), 17 | watchMode: false, 18 | typeChecking: PASS, 19 | hidesWarnings: link(PASS + CLICKABLE, 'https://github.com/TypeStrong/ts-node/blob/599f28bbed574003aea08cffab098a3348475649/src/child/child-require.ts#L19-L24'), 20 | binaries: link('ts-node, ts-node-esm, +4', 'https://github.com/TypeStrong/ts-node/blob/14323f9d00d5c7051ac09b944c7f423e442145ea/package.json#L38-L43'), 21 | }, 22 | testing: { 23 | os: link('Linux & Windows', 'https://github.com/TypeStrong/ts-node/blob/14323f9d00d5c7051ac09b944c7f423e442145ea/.github/workflows/continuous-integration.yml#L52'), 24 | nodeVersions: link('12 ~ 18 + Nightly', 'https://github.com/TypeStrong/ts-node/blob/14323f9d00d5c7051ac09b944c7f423e442145ea/.github/workflows/continuous-integration.yml#L55-L143'), 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/tsm.ts: -------------------------------------------------------------------------------- 1 | import { createRuntime } from '../utils/create-runtime'; 2 | import { link } from '../utils/markdown'; 3 | 4 | export default createRuntime({ 5 | name: 'tsm', 6 | npmName: 'tsm', 7 | githubRepo: 'lukeed/tsm', 8 | binaryPath: './node_modules/tsm/bin.js', 9 | performance: { 10 | compiler: link('esbuild', 'https://esbuild.github.io/'), 11 | diskCache: false, 12 | }, 13 | dx: { 14 | tsRepl: false, 15 | watchMode: false, 16 | typeChecking: false, 17 | hidesWarnings: false, 18 | binaries: link('tsm', 'https://github.com/lukeed/tsm/blob/d65d835a8a9fc3bb60dae7336eabdd713bfed0fc/package.json#L7'), 19 | }, 20 | testing: { 21 | os: link('Linux & Windows', 'https://github.com/lukeed/tsm/blob/d65d835a8a9fc3bb60dae7336eabdd713bfed0fc/.github/workflows/ci.yml#L19'), 22 | nodeVersions: link('12.22.10 ~ 16.14', 'https://github.com/lukeed/tsm/blob/d65d835a8a9fc3bb60dae7336eabdd713bfed0fc/.github/workflows/ci.yml#L18'), 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/compare/runtime-binaries/tsx.ts: -------------------------------------------------------------------------------- 1 | import { createRuntime } from '../utils/create-runtime'; 2 | import { 3 | link, PASS, FAIL, CLICKABLE, 4 | } from '../utils/markdown'; 5 | 6 | export default createRuntime({ 7 | name: 'tsx', 8 | npmName: 'tsx', 9 | githubRepo: 'esbuild-kit/tsx', 10 | binaryPath: './node_modules/tsx/dist/cli.js', 11 | performance: { 12 | compiler: link('esbuild', 'https://esbuild.github.io/'), 13 | diskCache: link(PASS + CLICKABLE, 'https://github.com/esbuild-kit/tsx#cache'), 14 | }, 15 | dx: { 16 | tsRepl: link(PASS + CLICKABLE, 'https://tsx.is/usage#repl'), 17 | watchMode: link(PASS + CLICKABLE, 'https://tsx.is/watch-mode'), 18 | typeChecking: FAIL, 19 | hidesWarnings: PASS, 20 | binaries: link('tsx', 'https://github.com/esbuild-kit/tsx/blob/3e81d19bf759b512eb74360861f5abeb9d638ef0/package.json#L30'), 21 | }, 22 | testing: { 23 | os: link('Linux & Windows', 'https://github.com/esbuild-kit/tsx/blob/3e81d19bf759b512eb74360861f5abeb9d638ef0/.github/workflows/test.yml#L13'), 24 | nodeVersions: link('12.20 ~ 18', 'https://github.com/esbuild-kit/tsx/blob/3e81d19bf759b512eb74360861f5abeb9d638ef0/tests/index.ts#L12-L25'), 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /scripts/compare/tests/dx.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | 3 | export default createTest(binary => describe( 4 | 'DX', 5 | (test) => { 6 | test( 7 | 'TypeScript REPL', 8 | () => binary.dx.tsRepl, 9 | ); 10 | 11 | test( 12 | 'Watch mode', 13 | () => binary.dx.watchMode, 14 | ); 15 | 16 | test( 17 | 'Type checking', 18 | () => binary.dx.typeChecking, 19 | ); 20 | 21 | test( 22 | 'Hides experimental feature warnings', 23 | () => binary.dx.hidesWarnings, 24 | ); 25 | 26 | test( 27 | 'Binaries', 28 | () => binary.dx.binaries, 29 | ); 30 | }, 31 | )); 32 | -------------------------------------------------------------------------------- /scripts/compare/tests/index.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs/promises'; 2 | import path from 'path'; 3 | import type { TestSuite } from '../utils/test'; 4 | 5 | export async function loadTests() { 6 | const files = await fs.readdir(__dirname); 7 | const testFiles = files.filter(file => file !== 'index.ts' && file.endsWith('.ts')); 8 | 9 | const testsLoaded = await Promise.all( 10 | testFiles.map(async (testPath) => { 11 | const { default: testSuite } = await import(path.join(__dirname, testPath)); 12 | 13 | return [testPath.slice(0, -3), testSuite as TestSuite] as const; 14 | }), 15 | ); 16 | 17 | return testsLoaded; 18 | } 19 | -------------------------------------------------------------------------------- /scripts/compare/tests/interop-commonjs.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | 3 | export default createTest(binary => describe( 4 | 'Package type: CommonJS', 5 | (test) => { 6 | test( 7 | 'require() `.js` file (ESM export)', 8 | async () => (await binary.run('package-commonjs', './require-log.js', './interops/esm.js')) === '{"default":true}', 9 | ); 10 | 11 | test( 12 | 'require() `.ts` file (ESM export)', 13 | async () => (await binary.run('package-commonjs', './require-log.js', './interops/ts.ts')) === '{"default":true}', 14 | ); 15 | 16 | test( 17 | 'require() `.cjs` file', 18 | async () => (await binary.run('package-commonjs', './require-log.js', './interops/cjs.cjs')) === 'true', 19 | ); 20 | 21 | test( 22 | 'require() `.cts` file', 23 | async () => (await binary.run('package-commonjs', './require-log.js', './interops/cts.cts')) === 'true', 24 | ); 25 | 26 | test( 27 | 'require() `.mjs` file', 28 | async () => (await binary.run('package-commonjs', './require-log.js', './interops/mjs.mjs')) === '{"default":true}', 29 | ); 30 | 31 | test( 32 | 'require() `.mts` file', 33 | async () => (await binary.run('package-commonjs', './require-log.js', './interops/mts.mts')) === '{"default":true}', 34 | ); 35 | 36 | test( 37 | 'import() `.js` file (ESM export)', 38 | async () => (await binary.run('package-commonjs', './import-log.js', './interops/esm.js')) === '{"default":true}', 39 | ); 40 | 41 | test( 42 | 'import() `.ts` file (ESM export)', 43 | async () => (await binary.run('package-commonjs', './import-log.js', './interops/ts.ts')) === '{"default":true}', 44 | ); 45 | 46 | test( 47 | 'import() `.cjs` file', 48 | async () => (await binary.run('package-commonjs', './import-log.js', './interops/cjs.cjs')) === '{"default":true}', 49 | ); 50 | 51 | test( 52 | 'import() `.cts` file', 53 | async () => (await binary.run('package-commonjs', './import-log.js', './interops/cts.cts')) === '{"default":true}', 54 | ); 55 | 56 | test( 57 | 'import() `.mjs` file', 58 | async () => (await binary.run('package-commonjs', './import-log.js', './interops/mjs.mjs')) === '{"default":true}', 59 | ); 60 | 61 | test( 62 | 'import() `.mts` file', 63 | async () => (await binary.run('package-commonjs', './import-log.js', './interops/mts.mts')) === '{"default":true}', 64 | ); 65 | }, 66 | )); 67 | -------------------------------------------------------------------------------- /scripts/compare/tests/interop-module.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | 3 | export default createTest(binary => describe( 4 | 'Package type: Module', 5 | (test) => { 6 | test( 7 | 'require() `.js` file (ESM export)', 8 | async () => (await binary.run('package-module', './require-log.js', './interops/esm.js')) === '{"default":true}', 9 | ); 10 | 11 | test( 12 | 'require() `.ts` file (ESM export)', 13 | async () => (await binary.run('package-module', './require-log.js', './interops/ts.ts')) === '{"default":true}', 14 | ); 15 | 16 | test( 17 | 'require() `.cjs` file', 18 | async () => (await binary.run('package-module', './require-log.js', './interops/cjs.cjs')) === 'true', 19 | ); 20 | 21 | test( 22 | 'require() `.cts` file', 23 | async () => (await binary.run('package-module', './require-log.js', './interops/cts.cts')) === 'true', 24 | ); 25 | 26 | test( 27 | 'require() `.mjs` file', 28 | async () => (await binary.run('package-module', './require-log.js', './interops/mjs.mjs')) === '{"default":true}', 29 | ); 30 | 31 | test( 32 | 'require() `.mts` file', 33 | async () => (await binary.run('package-module', './require-log.js', './interops/mts.mts')) === '{"default":true}', 34 | ); 35 | 36 | test( 37 | 'import() `.js` file (ESM export)', 38 | async () => (await binary.run('package-module', './import-log.js', './interops/esm.js')) === '{"default":true}', 39 | ); 40 | 41 | test( 42 | 'import() `.ts` file (ESM export)', 43 | async () => (await binary.run('package-module', './import-log.js', './interops/ts.ts')) === '{"default":true}', 44 | ); 45 | 46 | test( 47 | 'import() `.cjs` file', 48 | async () => (await binary.run('package-module', './import-log.js', './interops/cjs.cjs')) === '{"default":true}', 49 | ); 50 | 51 | test( 52 | 'import() `.cts` file', 53 | async () => (await binary.run('package-module', './import-log.js', './interops/cts.cts')) === '{"default":true}', 54 | ); 55 | 56 | test( 57 | 'import() `.mjs` file', 58 | async () => (await binary.run('package-module', './import-log.js', './interops/mjs.mjs')) === '{"default":true}', 59 | ); 60 | 61 | test( 62 | 'import() `.mts` file', 63 | async () => (await binary.run('package-module', './import-log.js', './interops/mts.mts')) === '{"default":true}', 64 | ); 65 | }, 66 | )); 67 | -------------------------------------------------------------------------------- /scripts/compare/tests/performance.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | 3 | export default createTest(binary => describe( 4 | 'Performance', 5 | (test) => { 6 | test( 7 | 'Compiler', 8 | () => binary.performance.compiler, 9 | ); 10 | 11 | test( 12 | 'Disk cache', 13 | () => binary.performance.diskCache, 14 | ); 15 | }, 16 | )); 17 | -------------------------------------------------------------------------------- /scripts/compare/tests/project-stats.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | import { img, link } from '../utils/markdown'; 3 | 4 | export default createTest(binary => describe( 5 | 'Project stats', 6 | (test) => { 7 | test( 8 | 'npm downloads', 9 | () => link( 10 | img(`https://img.shields.io/npm/dm/${binary.npmName}?label`), 11 | `https://www.npmjs.com/package/${binary.npmName}`, 12 | ), 13 | ); 14 | 15 | test( 16 | 'Install size', 17 | () => link( 18 | img(`https://badgen.net/packagephobia/install/${binary.npmName}?color=blue&label`), 19 | `https://packagephobia.com/result?p=${binary.npmName}`, 20 | ), 21 | ); 22 | 23 | test( 24 | 'GitHub stars', 25 | () => link( 26 | img(`https://img.shields.io/github/stars/${binary.githubRepo}?color=gray&label`), 27 | `https://github.com/${binary.githubRepo}/stargazers`, 28 | ), 29 | ); 30 | 31 | test( 32 | 'Issues open', 33 | () => link( 34 | img(`https://img.shields.io/github/issues-raw/${binary.githubRepo}?color=orange&label`), 35 | `https://github.com/${binary.githubRepo}/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc`, 36 | ), 37 | ); 38 | 39 | test( 40 | 'Issues closed', 41 | () => link( 42 | img(`https://img.shields.io/github/issues-closed-raw/${binary.githubRepo}?color=blue&label`), 43 | `https://github.com/${binary.githubRepo}/issues?q=is%3Aissue+is%3Aclosed`, 44 | ), 45 | ); 46 | test( 47 | 'Last commit', 48 | () => img(`https://img.shields.io/github/last-commit/${binary.githubRepo}?label`), 49 | ); 50 | }, 51 | )); 52 | -------------------------------------------------------------------------------- /scripts/compare/tests/resolution-import.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | import { link } from '../utils/markdown'; 3 | 4 | export default createTest(binary => describe( 5 | '`import()`', 6 | (test) => { 7 | // 8 | test( 9 | '`.ts` file', 10 | async () => (await binary.run('package-commonjs', './import.js', './resolution/ts.ts').catch(() => {})) === 'true', 11 | ); 12 | 13 | test( 14 | `\`.ts\` file ${link('via `.js`', 'https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions')}`, 15 | async () => (await binary.run('package-commonjs', './import.ts', './resolution/ts.js').catch(() => {})) === 'true', 16 | ); 17 | 18 | test( 19 | '`.ts` file without extension', 20 | async () => (await binary.run('package-commonjs', './import.js', './resolution/ts').catch(() => {})) === 'true', 21 | ); 22 | 23 | test( 24 | '`index.ts` file via directory', 25 | async () => (await binary.run('package-commonjs', './import.js', './resolution/directory').catch(() => {})) === 'true', 26 | ); 27 | 28 | test( 29 | '`.cts` file', 30 | async () => (await binary.run('package-commonjs', './import.js', './resolution/cts.cts').catch(() => {})) === 'true', 31 | ); 32 | 33 | test( 34 | `\`.cts\` file ${link('via `.cjs`', 'https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions')}`, 35 | async () => (await binary.run('package-commonjs', './import.ts', './resolution/cts.cjs').catch(() => {})) === 'true', 36 | ); 37 | 38 | test( 39 | '`.mts` file', 40 | async () => (await binary.run('package-commonjs', './import.js', './resolution/mts.mts').catch(() => {})) === 'true', 41 | ); 42 | 43 | test( 44 | `\`.mts\` file ${link('via `.mjs`', 'https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions')}`, 45 | async () => (await binary.run('package-commonjs', './import.ts', './resolution/mts.mjs').catch(() => {})) === 'true', 46 | ); 47 | 48 | test( 49 | `tsconfig.json ${link('paths', 'https://www.typescriptlang.org/tsconfig#paths')}`, 50 | async () => (await binary.run('package-commonjs', './import.ts', 'prefix/ts').catch(() => {})) === 'true', 51 | ); 52 | }, 53 | )); 54 | -------------------------------------------------------------------------------- /scripts/compare/tests/resolution-require.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | import { link } from '../utils/markdown'; 3 | 4 | export default createTest(binary => describe( 5 | '`require()`', 6 | (test) => { 7 | test( 8 | '`.ts` file', 9 | async () => (await binary.run('package-commonjs', './require.js', './resolution/ts.ts').catch(() => {})) === 'true', 10 | ); 11 | 12 | test( 13 | `\`.ts\` file ${link('via `.js`', 'https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions')}`, 14 | async () => (await binary.run('package-commonjs', './require.ts', './resolution/ts.js').catch(() => {})) === 'true', 15 | ); 16 | 17 | test( 18 | '`.ts` file without extension', 19 | async () => (await binary.run('package-commonjs', './require.js', './resolution/ts').catch(() => {})) === 'true', 20 | ); 21 | 22 | test( 23 | '`index.ts` file via directory', 24 | async () => (await binary.run('package-commonjs', './require.js', './resolution/directory').catch(() => {})) === 'true', 25 | ); 26 | 27 | test( 28 | '`.cts` file', 29 | async () => (await binary.run('package-commonjs', './require.js', './resolution/cts.cts').catch(() => {})) === 'true', 30 | ); 31 | 32 | test( 33 | `\`.cts\` file ${link('via `.cjs`', 'https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions')}`, 34 | async () => (await binary.run('package-commonjs', './require.ts', './resolution/cts.cjs').catch(() => {})) === 'true', 35 | ); 36 | 37 | test( 38 | '`.mts` file', 39 | async () => (await binary.run('package-commonjs', './require.js', './resolution/mts.mts').catch(() => {})) === 'true', 40 | ); 41 | 42 | test( 43 | `\`.mts\` file ${link('via `.mjs`', 'https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions')}`, 44 | async () => (await binary.run('package-commonjs', './require.ts', './resolution/mts.mjs').catch(() => {})) === 'true', 45 | ); 46 | 47 | test( 48 | '`node:` prefix', 49 | async () => (await binary.run('package-commonjs', './require-log.js', 'node:fs').catch(() => '')).includes('F_OK'), 50 | ); 51 | 52 | test( 53 | `tsconfig.json ${link('paths', 'https://www.typescriptlang.org/tsconfig#paths')}`, 54 | async () => (await binary.run('package-commonjs', './require.js', 'prefix/ts').catch(() => {})) === 'true', 55 | ); 56 | }, 57 | )); 58 | -------------------------------------------------------------------------------- /scripts/compare/tests/testing.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | 3 | export default createTest(binary => describe( 4 | 'Testing', 5 | (test) => { 6 | test( 7 | 'Operating systems', 8 | () => binary.testing.os, 9 | ); 10 | 11 | test( 12 | 'Node.js versions', 13 | () => binary.testing.nodeVersions, 14 | ); 15 | }, 16 | )); 17 | -------------------------------------------------------------------------------- /scripts/compare/tests/transformation-commonjs.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | 3 | export default createTest(binary => describe( 4 | 'Package type: CommonJS', 5 | (test) => { 6 | test( 7 | 'TypeScript syntax', 8 | async () => (await binary.run('package-commonjs', './transformation/ts.ts')) === 'true', 9 | ); 10 | 11 | test( 12 | 'ESM → CJS: import/export syntax', 13 | async () => { 14 | try { 15 | return (await binary.run('package-commonjs', './transformation/esm-import.js')) === 'true'; 16 | } catch (error) { 17 | if (error.message.match('SyntaxError')) { 18 | return false; 19 | } 20 | throw error; 21 | } 22 | }, 23 | ); 24 | 25 | test( 26 | 'ESM → CJS: `import.meta.url` shim', 27 | async () => { 28 | try { 29 | return (await binary.run('package-commonjs', './transformation/import-meta-url.js')) === 'true'; 30 | } catch (error) { 31 | if (error.message.match('SyntaxError')) { 32 | return false; 33 | } 34 | throw error; 35 | } 36 | }, 37 | ); 38 | 39 | test( 40 | 'CJS scope in `.js` file', 41 | async () => (await binary.run('package-commonjs', './transformation/cjs-scope.js')) === 'true', 42 | ); 43 | 44 | test( 45 | 'CJS scope in `.ts` file', 46 | async () => (await binary.run('package-commonjs', './transformation/cjs-scope.ts')) === 'true', 47 | ); 48 | 49 | test( 50 | 'CJS scope in `.cjs` file', 51 | async () => (await binary.run('package-commonjs', './transformation/cjs-scope.cjs')) === 'true', 52 | ); 53 | 54 | test( 55 | 'CJS scope in `.cts` file', 56 | async () => (await binary.run('package-commonjs', './transformation/cjs-scope.cts')) === 'true', 57 | ); 58 | 59 | test( 60 | 'No CJS scope in `.mjs` file', 61 | async () => (await binary.run('package-commonjs', './transformation/cjs-scope.mjs')) === 'false', 62 | ); 63 | 64 | test( 65 | 'No CJS scope in `.mts` file', 66 | async () => (await binary.run('package-commonjs', './transformation/cjs-scope.mts')) === 'false', 67 | ); 68 | 69 | test( 70 | 'Source maps', 71 | async () => (await binary.run('package-commonjs', './transformation/source-maps.ts')) === 'true', 72 | ); 73 | }, 74 | )); 75 | -------------------------------------------------------------------------------- /scripts/compare/tests/transformation-module.ts: -------------------------------------------------------------------------------- 1 | import { createTest, describe } from '../utils/test'; 2 | 3 | export default createTest(binary => describe( 4 | 'Package type: Module', 5 | (test) => { 6 | test( 7 | 'TypeScript syntax', 8 | async () => (await binary.run('package-module', './transformation/ts.ts')) === 'true', 9 | ); 10 | 11 | test( 12 | 'CJS scope in `.cjs` file', 13 | async () => (await binary.run('package-module', './transformation/cjs-scope.cjs')) === 'true', 14 | ); 15 | 16 | test( 17 | 'CJS scope in `.cts` file', 18 | async () => (await binary.run('package-module', './transformation/cjs-scope.cts')) === 'true', 19 | ); 20 | 21 | test( 22 | 'No CJS scope in `.js` file', 23 | async () => (await binary.run('package-module', './transformation/cjs-scope.js')) === 'false', 24 | ); 25 | 26 | test( 27 | 'No CJS scope in `.ts` file', 28 | async () => (await binary.run('package-module', './transformation/cjs-scope.ts')) === 'false', 29 | ); 30 | 31 | test( 32 | 'No CJS scope in `.mjs` file', 33 | async () => (await binary.run('package-module', './transformation/cjs-scope.mjs')) === 'false', 34 | ); 35 | 36 | test( 37 | 'No CJS scope in `.mts` file', 38 | async () => (await binary.run('package-module', './transformation/cjs-scope.mts')) === 'false', 39 | ); 40 | 41 | test( 42 | 'Source maps', 43 | async () => (await binary.run('package-module', './transformation/source-maps.ts')) === 'true', 44 | ); 45 | }, 46 | )); 47 | -------------------------------------------------------------------------------- /scripts/compare/types.ts: -------------------------------------------------------------------------------- 1 | import { type TestSuiteResult } from './utils/test'; 2 | 3 | export type RuntimeData = { 4 | name: string; 5 | 6 | npmName: string; 7 | 8 | githubRepo: string; 9 | 10 | binaryPath: string; 11 | 12 | nodePath?: string; 13 | 14 | performance: { 15 | compiler: string; 16 | diskCache: string | false; 17 | }; 18 | 19 | dx: { 20 | tsRepl: string | false; 21 | watchMode: string | false; 22 | typeChecking: string | false; 23 | hidesWarnings: string | false; 24 | binaries: string; 25 | }; 26 | 27 | testing: { 28 | os: string; 29 | nodeVersions: string; 30 | }; 31 | }; 32 | 33 | export type RuntimeBinary = ( 34 | this: RuntimeData, 35 | ...args: string[] 36 | ) => Promise; 37 | 38 | export type Runtime = RuntimeData & { 39 | run: RuntimeBinary; 40 | }; 41 | 42 | export type RuntimeTested = { 43 | runtime: Runtime; 44 | } & { 45 | [k: string]: TestSuiteResult; 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/compare/utils/create-runtime.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { execaNode } from 'execa'; 3 | import type { RuntimeData, Runtime } from '../types'; 4 | 5 | export function createRuntime( 6 | runtimeData: RuntimeData, 7 | ): Runtime { 8 | return { 9 | ...runtimeData, 10 | async run( 11 | this: RuntimeData, 12 | cwd: string, 13 | ...args: string[] 14 | ) { 15 | const result = await execaNode( 16 | path.resolve(this.binaryPath), 17 | args, 18 | { 19 | cwd, 20 | nodePath: this.nodePath, 21 | nodeOptions: [], 22 | }, 23 | ); 24 | 25 | if (result.stderr.includes('UnhandledPromiseRejectionWarning')) { 26 | throw result; 27 | } 28 | 29 | return result.stdout; 30 | }, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /scripts/compare/utils/markdown.ts: -------------------------------------------------------------------------------- 1 | export const link = (label: string, href?: string) => `[${label}]${href ? `(${href})` : ''}`; 2 | 3 | export const img = (url: string) => `![](${url})`; 4 | 5 | export const PASS = '✅'; 6 | 7 | export const FAIL = '❌'; 8 | 9 | export const CLICKABLE = ' ?'; 10 | -------------------------------------------------------------------------------- /scripts/compare/utils/test.ts: -------------------------------------------------------------------------------- 1 | import type { Runtime } from '../types'; 2 | import { PASS, FAIL } from './markdown'; 3 | 4 | type TestResult = { 5 | label: string; 6 | value: string; 7 | }; 8 | 9 | export type TestSuiteResult = { 10 | title: string; 11 | results: TestResult[]; 12 | }; 13 | 14 | export type TestSuite = (runtime: Runtime) => Promise; 15 | 16 | export const createTest = ( 17 | testSuite: TestSuite, 18 | ) => testSuite; 19 | 20 | type MaybePromise = T | Promise 21 | 22 | type Test = ( 23 | label: string, 24 | testFunction: () => MaybePromise, 25 | ) => void; 26 | 27 | const cwd = process.cwd(); 28 | 29 | export async function describe( 30 | title: string, 31 | tests: (test: Test) => void, 32 | ): Promise { 33 | const promises: Promise[] = []; 34 | 35 | tests((label, testFunction) => { 36 | promises.push((async () => { 37 | let value; 38 | try { 39 | const result = await testFunction(); 40 | if (typeof result === 'boolean') { 41 | value = result ? PASS : FAIL; 42 | } else { 43 | value = result; 44 | } 45 | } catch (error) { 46 | let { message } = error; 47 | if ('stderr' in error) { 48 | const foundError = error.stderr.match(/\w*Error.*:.+/); 49 | if (foundError) { 50 | [message] = foundError; 51 | } 52 | } 53 | 54 | if (message) { 55 | message = message.replace(/"/g, '\'').replace(cwd, '.'); 56 | value = `⛔️`; 57 | } else { 58 | value = '⚠️'; 59 | } 60 | } 61 | 62 | return { 63 | label, 64 | value, 65 | }; 66 | })()); 67 | }); 68 | 69 | return { 70 | title, 71 | results: await Promise.all(promises), 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /scripts/compare/utils/update-markdown.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs/promises'; 2 | import { markdownTable } from 'markdown-table'; 3 | import commentMark from 'comment-mark'; 4 | import type { Runtime, RuntimeTested } from '../types'; 5 | import { link } from './markdown'; 6 | 7 | function renderTable( 8 | results: RuntimeTested[], 9 | property: string, 10 | showTestTitle = false, 11 | ) { 12 | const headings = ['']; 13 | const rows = new Map(); 14 | 15 | for (const result of results) { 16 | headings.push(link(result.runtime.name)); 17 | for (const { label, value } of result[property].results) { 18 | if (!rows.has(label)) { 19 | rows.set(label, []); 20 | } 21 | 22 | rows.get(label).push(value); 23 | } 24 | } 25 | 26 | const table = markdownTable([ 27 | headings, 28 | ...Array.from(rows).map(row => row.flat()), 29 | ], { 30 | align: headings.map(column => (column ? 'c' : 'l')), 31 | }); 32 | 33 | return `${showTestTitle ? `#### ${results[0][property].title}` : ''}\n${table}`; 34 | } 35 | 36 | export async function updateMarkdown( 37 | filePath: string, 38 | runtimes: Runtime[], 39 | results: RuntimeTested[], 40 | ) { 41 | let mdFile = await fs.readFile(filePath, 'utf8'); 42 | 43 | mdFile = commentMark(mdFile, { 44 | links: runtimes.map(runtime => `[${runtime.name}]: https://github.com/${runtime.githubRepo}`).join('\n'), 45 | runtimes: runtimes.map(runtime => `- ${link(runtime.name)}`).join('\n'), 46 | projectStats: renderTable(results, 'project-stats'), 47 | transformCommonjs: renderTable(results, 'transformation-commonjs', true), 48 | transformModule: renderTable(results, 'transformation-module', true), 49 | resolutionRequire: renderTable(results, 'resolution-require', true), 50 | resolutionImport: renderTable(results, 'resolution-import', true), 51 | interopCommonjs: renderTable(results, 'interop-commonjs', true), 52 | interopModule: renderTable(results, 'interop-module', true), 53 | performance: renderTable(results, 'performance'), 54 | dx: renderTable(results, 'dx'), 55 | testing: renderTable(results, 'testing'), 56 | }); 57 | 58 | await fs.writeFile(filePath, mdFile); 59 | } 60 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | }, 8 | "include": ["lib"] 9 | } 10 | --------------------------------------------------------------------------------