1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
*This guide is best-effort and will be improved as necessary.*
## Features, bugfixes, and other code
We use npm scripts for building, testing, and linting. Read the scripts to become familiar with our build process. The big ones are:
```
npm install
npm run build
npm run test-local
npm run lint-fix
```
`npm prepare` is maintained so that anyone can install `ts-node` from git, which is useful for testing experimental branches and unreleased features.
Source lives in `src` and is compiled to `dist`. Some shim files live outside of `src` so that they can be imported at
certain paths. For example, to allow users to import `ts-node/register`, we have `register/index.js` which is a shim to
compiled code in `dist`.
`dist-raw` is for larger chunks of code which are not compiled nor linted because they have been copy-pasted from `node`'s source code.
## Tests
Test cases are declared in `src/test/*.spec.ts`, and test fixtures live in `./tests`. They can be run with `npm run test-local`.
To run a subset of tests:
```
# Use ava's --match flag to match the name of a test or suite
# https://github.com/avajs/ava/blob/main/docs/05-command-line.md
# Don't forget the * wildcards
npm run test-local -- --match '*esm loader*'
```
Tests are run with AVA, but using a custom wrapper API to enable some TS-friendly features and grouped test suites.
The tests `npm pack` ts-node into a tarball and `npm install` it into `./tests/node_modules`. This makes `./tests` a better testing environment
because it more closely matches the end-user's environment. Complex `require()` / `import` / `--require` / `--loader` invocations behave
the way they would in a users's project.
Historically, it has been difficult to test ts-node in-process because it mutates the node environment: installing require hooks, stack trace formatters, etc.
`nyc`, `ava`, and `ts-node` all mutate the node environment, so it is tricky to setup and teardown individual tests in isolation, because ts-node's hooks need to be
reset without disturbing `nyc` or `ava` hooks. For this reason, many tests are integration style, spawning ts-node's CLI in an external process, asking it to
execute one of the fixture projects in `./tests`.
Over time, I've gradually added setup and teardown logic so that more components can be tested in-process.
We have a debug configuration for VSCode.
1. Open a `*.spec.ts` so it is the active/focused file.
2. (optional) set breakpoints.
3. Invoke debugger with F5.
Note that some tests might misbehave in the debugger. REPL tests in particular. I'm not sure why, but I think it is related to how `console` does not write to
stdout when in a debug session.
### Test Context
Ava has the concept of test "context", an object which can store reusable fields common across many tests.
By convention, any functions that setup reusable context start with `ctx`, making them easier to tab-complete and auto-import while writing tests.
See `ctxTsNode` for an example.
Context setup functions are re-executed for each test case. If you don't want this, wrap the context function in lodash `once()`. Each test will still get a unique context object, but the values placed onto each context will be identical.
Every `ctx*` function has a namespace with `Ctx` and `T` types. These make it easier/cleaner to write tests.
### Test Macros
Ava has the concept of test "macros", reusable functions which can declare a type of test many times with different inputs.
Macro functions are created with `test.macro()`.
By convention, if a macro function is meant to be imported and reused in multiple files, its name should start with `macro`.
Macros can also be declared to require a certain "context," thanks to the namespace types described in "Test Context" above.
See examples in `helpers.ts`.
## Documentation
Documentation is written in markdown in `website/docs` and rendered into a website by Docusaurus. The README is also generated from these markdown files.
To edit documentation, modify the markdown files in `./website/docs` and the sidebar declaration in `./website/sidebars.js`
Docs for the latest stable release live in a `docs` branch. The "Edit this page" links on the website link to the `docs`
branch so that the website can be improved in parallel with new feature work.
Docs changes for unreleased features are merged to `main` in the same PR which implements the feature, adds tests, etc.
When we release a new version, we merge `main` with `docs`, unifying the two.
```shell
cd ./website
yarn
yarn start
# Will host live website locally
yarn build-readme # will rebuild the README.md
```
This site was used to generate the favicon from a high-res PNG export of the SVG. https://realfavicongenerator.net/
## Release checklist
We publish using `np`: https://npm.im/np
1. Merge `docs` into `main` using a pull request, ensuring a consistent squash-merge
2. Rebuild the README (see instructions above, necessary because npmjs.com renders the readme)
3. (optional) Update the api-extractor report; check for unexpected changes. See below
4. Publish with `np`
- `np --branch main --no-tests`
- `--no-tests` because we must rely on CI to test ts-node. Even if you *did* run the tests locally, you would only be testing a single operating system, node version, and TypeScript version, so locally-run tests are insufficient.
5. Add changelog to the Github Release; match formatting from previous releases
6. Move `docs` branch to head of `main`
- this rebuilds the website
- `git push --force origin main:docs`
- avoids merge messiness due to earlier squash-merge from `docs` to `main`
7. If tsconfig schema has changed, send a pull request to schemastore. [Example](https://github.com/SchemaStore/schemastore/pull/1208)
## APIExtractor
`npm run api-extractor` will update an API report generated by [`api-extractor`](https://api-extractor.com/pages/overview/intro/) which may be useful
when generating release notes to detect (breaking) changes in our API surface.
I configured it for my own convenience; it is not a necessary part of our development process.
|