├── .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://www.npmjs.com/package/tsx) | [](https://www.npmjs.com/package/@swc/register) | [](https://www.npmjs.com/package/esbuild-runner) | [](https://www.npmjs.com/package/jiti) | [](https://www.npmjs.com/package/sucrase) | [](https://www.npmjs.com/package/ts-node) | [](https://www.npmjs.com/package/tsm) |
38 | | Install size | [](https://packagephobia.com/result?p=tsx) | [](https://packagephobia.com/result?p=@swc/register) | [](https://packagephobia.com/result?p=esbuild-runner) | [](https://packagephobia.com/result?p=jiti) | [](https://packagephobia.com/result?p=sucrase) | [](https://packagephobia.com/result?p=ts-node) | [](https://packagephobia.com/result?p=tsm) |
39 | | GitHub stars | [](https://github.com/esbuild-kit/tsx/stargazers) | [](https://github.com/swc-project/register/stargazers) | [](https://github.com/folke/esbuild-runner/stargazers) | [](https://github.com/unjs/jiti/stargazers) | [](https://github.com/alangpierce/sucrase/stargazers) | [](https://github.com/TypeStrong/ts-node/stargazers) | [](https://github.com/lukeed/tsm/stargazers) |
40 | | Issues open | [](https://github.com/esbuild-kit/tsx/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [](https://github.com/swc-project/register/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [](https://github.com/folke/esbuild-runner/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [](https://github.com/unjs/jiti/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [](https://github.com/alangpierce/sucrase/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [](https://github.com/TypeStrong/ts-node/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) | [](https://github.com/lukeed/tsm/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) |
41 | | Issues closed | [](https://github.com/esbuild-kit/tsx/issues?q=is%3Aissue+is%3Aclosed) | [](https://github.com/swc-project/register/issues?q=is%3Aissue+is%3Aclosed) | [](https://github.com/folke/esbuild-runner/issues?q=is%3Aissue+is%3Aclosed) | [](https://github.com/unjs/jiti/issues?q=is%3Aissue+is%3Aclosed) | [](https://github.com/alangpierce/sucrase/issues?q=is%3Aissue+is%3Aclosed) | [](https://github.com/TypeStrong/ts-node/issues?q=is%3Aissue+is%3Aclosed) | [](https://github.com/lukeed/tsm/issues?q=is%3Aissue+is%3Aclosed) |
42 | | Last commit |  |  |  |  |  |  |  |
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) => ``;
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 |
--------------------------------------------------------------------------------