Skip to content

Commit f332803

Browse files
authored
feat: add ts cmd (#671)
This PR adds support for TS type check, .d.ts generations and docs from .d.ts
1 parent bff4c44 commit f332803

File tree

15 files changed

+523
-128
lines changed

15 files changed

+523
-128
lines changed

README.md

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
1-
# AEgir
1+
# AEgir <!-- omit in toc -->
22

33
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
44
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/ipfs/aegir/ci/master?style=flat-square)
5-
[![Dependency Status](https://david-dm.org/ipfs/aegir.svg?style=flat-square)](https://david-dm.org/ipfs/aegir)
65

76
> Automated JavaScript project management.
87
9-
## Lead Maintainer
8+
## Lead Maintainer <!-- omit in toc -->
109

1110
[Hugo Dias](https://github.com/hugomrdias)
1211

12+
## ToC <!-- omit in toc -->
13+
- [Project Structure](#project-structure)
14+
- [CI](#ci)
15+
- [Travis Setup](#travis-setup)
16+
- [Github Action Setup](#github-action-setup)
17+
- [Stack Requirements](#stack-requirements)
18+
- [Testing helpers](#testing-helpers)
19+
- [Fixtures](#fixtures)
20+
- [Echo Server](#echo-server)
21+
- [Get Port](#get-port)
22+
- [Tasks](#tasks)
23+
- [Linting](#linting)
24+
- [Testing](#testing)
25+
- [Coverage](#coverage)
26+
- [Node](#node)
27+
- [Browser](#browser)
28+
- [Building](#building)
29+
- [Generating Webpack stats.json](#generating-webpack-statsjson)
30+
- [Typescript](#typescript)
31+
- [JSDoc Typescript support](#jsdoc-typescript-support)
32+
- [Releasing](#releasing)
33+
- [Scoped Github Token](#scoped-github-token)
34+
- [Documentation](#documentation)
35+
- [License](#license)
1336

1437
## Project Structure
1538

@@ -39,10 +62,12 @@ Your `package.json` should have the following entries and should pass `aegir lin
3962
"test:browser": "aegir test --target browser"
4063
}
4164
```
42-
## Travis Setup
65+
66+
## CI
67+
### Travis Setup
4368
Check this tutorial https://github.com/ipfs/aegir/wiki/Travis-Setup
4469

45-
## Github Action Setup
70+
### Github Action Setup
4671
Check this tutorial https://github.com/ipfs/aegir/wiki/Github-Actions-Setup
4772

4873
## Stack Requirements
@@ -200,18 +225,15 @@ after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codeco
200225
```
201226
202227
### Building
203-
204-
205-
You can run it using
228+
The build command builds a browser bundle and TS type declarations from the `src` folder.
206229

207230
```bash
208-
$ aegir build
231+
$ aegir build --help
209232
```
210233
This will build a browser ready version into `dist`, so after publishing the results will be available under
211234

212235
```
213236
https://unpkg.com/<module-name>/dist/index.js
214-
https://unpkg.com/<module-name>/dist/index.min.js
215237
```
216238
217239
**Specifying a custom entry file for Webpack**
@@ -235,6 +257,14 @@ Pass the `--analyze` option to have Webpack generate a `stats.json` file for the
235257
```bash
236258
aegir build --analyze
237259
```
260+
### Typescript
261+
262+
#### JSDoc Typescript support
263+
```bash
264+
aegir ts --help
265+
```
266+
The `ts` command provides type checking (via typescript) in javascript files with [JSDoc](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html) annotations.
267+
238268

239269
### Releasing
240270

@@ -290,12 +320,10 @@ Be aware that by storing it in `~/.profile` or similar you will make it availabl
290320

291321
### Documentation
292322

293-
You can use `aegir docs` to generate documentation. This uses [documentation.js](http://documentation.js.org/) with the theme [clean-documentation-theme](https://github.com/dignifiedquire/clean-documentation-theme).
294-
295-
To publish the documentation automatically to the `gh-pages` branch you can run
323+
You can use `aegir docs` to generate documentation, this command uses `aegir ts --preset docs` internally.
296324

297325
```bash
298-
$ aegir docs --publish
326+
$ aegir docs --help
299327
```
300328

301329
## License

cmds/build.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use strict'
22
const EPILOG = `
3-
This command outputs two bundles, one in development mode (index.js) and another in production mode (index.min.js) plus respective source-maps, files are written to ./dist folder.
3+
Output files will go into a "./dist" folder.
44
Supports options forwarding with '--' for more info check https://webpack.js.org/api/cli/
55
`
66
module.exports = {
77
command: 'build',
8-
desc: 'Builds browser bundles with Webpack.',
8+
desc: 'Builds a browser bundle and TS type declarations from the `src` folder.',
99
builder: (yargs) => {
1010
yargs
1111
.epilog(EPILOG)

cmds/docs.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
'use strict'
22

33
const EPILOG = `
4-
Supports options forwarding with '--' for more info check https://github.com/documentationjs/documentation/blob/master/docs/USAGE.md
4+
Typescript config file is required to generated docs. Try \`aegir ts --preset config > tsconfig.json\`
55
`
66

77
module.exports = {
88
command: 'docs',
9-
desc: 'Generate documentation from JSDoc.',
9+
desc: 'Generate documentation from TS type declarations.',
1010
builder: yargs => {
1111
yargs
1212
.epilog(EPILOG)
13-
.example('aegir docs -- --format md -o docs.md', 'Build markdown documentation.')
13+
.example('aegir docs', 'Build HTML documentation.')
14+
.example('aegir docs -p', 'Build HTML documentation and publish to Github Pages.')
1415
.options(
1516
{
1617
publish: {
@@ -24,7 +25,6 @@ module.exports = {
2425
},
2526
handler (argv) {
2627
const docs = require('../src/docs')
27-
const onError = require('../src/error-handler')
28-
docs.run(argv).catch(onError)
28+
return docs.run(argv)
2929
}
3030
}

cmds/ts.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict'
2+
3+
const EPILOG = `
4+
Presets:
5+
\`check\` Runs the type checker with your local config (without writing any files). .
6+
\`types\` Emits type declarations for \`['src/**/*', 'package.json']\` to \`dist\` folder.
7+
\`docs\` Generates documentation based on type declarations to the \`docs\` folder.
8+
\`config\` Prints base config to stdout.
9+
10+
Note:
11+
To provide users types declarations with 0-configuration add following to package.json:
12+
13+
\`\`\`json
14+
"typesVersions": {
15+
"*": { "src/*": ["dist/src/*", "dist/src/*/index"] }
16+
},
17+
\`\`\`
18+
19+
Supports options forwarding with '--' for more info check https://www.typescriptlang.org/docs/handbook/compiler-options.html
20+
`
21+
module.exports = {
22+
command: 'ts',
23+
desc: 'Typescript command with presets for specific tasks.',
24+
builder: (yargs) => {
25+
yargs
26+
.epilog(EPILOG)
27+
.example('aegir ts --preset config > tsconfig.json', 'Add a base tsconfig.json to the current repo.')
28+
.options({
29+
preset: {
30+
type: 'string',
31+
choices: ['config', 'check', 'types', 'docs'],
32+
describe: 'Preset to run',
33+
alias: 'p'
34+
},
35+
include: {
36+
type: 'array',
37+
describe: 'Values are merged into the local TS config include property.',
38+
default: []
39+
}
40+
})
41+
},
42+
handler (argv) {
43+
const ts = require('../src/ts')
44+
return ts(argv)
45+
}
46+
}

md/ts-jsdoc.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Documentation for JSDoc based TS types
2+
3+
## Getting Started
4+
5+
Add a `tsconfig.json` to your repo:
6+
```bash
7+
aegir ts -p config > tsconfig.json
8+
```
9+
10+
Add types configuration to your package.json:
11+
```json
12+
"typesVersions": {
13+
"*": { "src/*": ["dist/src/*", "dist/src/*/index"] }
14+
},
15+
```
16+
`types` will tell `tsc` where to look for the entry point type declarations and `typeVersions` for every other files inside the `src` folder.
17+
18+
> The `ts` command follows aegir folder conventions, source code inside `./src`, test inside `./test` and documentation inside `./docs`.
19+
20+
21+
## CLI `ts` command
22+
23+
Run `aegir ts --help` and check the help text. There's presets for common TS use cases.
24+
25+
```md
26+
Presets:
27+
`check` Runs the type checker with your local config and doesn't not emit output.
28+
`types` Emits type declarations for `['src/**/*', 'package.json']` to `dist` folder.
29+
`docs` Generates documentation based on type declarations to the `docs` folder.
30+
`config` Prints base config to stdout.
31+
```
32+
33+
34+
## Adding types with JSDoc
35+
36+
Typescript can infere lots of the types without any help, but you can improve your code types by using just JSDoc for that follow the official TS documentation https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html.
37+
38+
### Rules for optimal type declarations and documentation
39+
40+
This list is a WIP, more rules will be added as we identify them.
41+
42+
#### 1. Commonjs default exports
43+
When using `commonjs` modules, only use default exports when exporting a single `class`.
44+
45+
```js
46+
// GOOD
47+
48+
class IPFS {}
49+
50+
module.exports = IPFS
51+
52+
// GOOD
53+
IPFS.hash = ()=>{}
54+
55+
module.exports = IPFS
56+
57+
// BAD
58+
function hash() {}
59+
60+
module.exports = hash
61+
62+
// REALLY BAD
63+
64+
function hash() {}
65+
function hash2() {}
66+
67+
module.exports = hash
68+
exports.hash2 = hash2
69+
70+
71+
```
72+
73+
#### 2. Commons js named exports
74+
When using `commonjs` modules, always use named exports if you want to export multiple references.
75+
```js
76+
// GOOD
77+
function hash() {}
78+
function hash2() {}
79+
class IPFS {}
80+
module.exports = {
81+
IPFS
82+
hash,
83+
hash2,
84+
...
85+
}
86+
87+
// BAD
88+
exports.hash2 = hash2() {}
89+
exports.hash = hash() {}
90+
exports.IPFS = IPFS
91+
```
92+
93+
#### 3. Use a `types.ts` file
94+
When writing types sometimes JSDoc can be cumbersome, impossible, it can output weird type declarations or even broken documentation. Most of these problems can be solved by defining some complex types in typescript in a `types.ts` file.
95+
96+
```ts
97+
// types.ts
98+
export type IntersectionType = Type1 & Type2
99+
```
100+
101+
```js
102+
// index.js
103+
/** @type { import('./types').IntersectionType } */
104+
const list
105+
```

package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
"@commitlint/travis-cli": "^11.0.0",
5959
"@electron/get": "^1.10.0",
6060
"@polka/send-type": "^0.5.2",
61+
"@types/mocha": "^8.0.4",
62+
"@types/node": "^14.14.7",
63+
"aegir-typedoc-theme": "^0.1.0",
6164
"babel-loader": "^8.0.5",
6265
"buffer": "^5.6.0",
6366
"bytes": "^3.1.0",
@@ -106,13 +109,17 @@
106109
"pascalcase": "^1.0.0",
107110
"pify": "^5.0.0",
108111
"polka": "^0.5.2",
112+
"premove": "^3.0.1",
109113
"prompt-promise": "^1.0.3",
110114
"read-pkg-up": "^7.0.1",
111115
"rimraf": "^3.0.1",
112116
"semver": "^7.3.2",
113117
"simple-git": "^2.7.0",
118+
"strip-bom": "^4.0.0",
119+
"strip-json-comments": "^3.1.1",
114120
"terser-webpack-plugin": "^3.0.5",
115-
"typescript": "^4.0.3",
121+
"typedoc": "^0.19.2",
122+
"typescript": "^4.0.5",
116123
"update-notifier": "^5.0.0",
117124
"webpack": "^4.43.0",
118125
"webpack-bundle-analyzer": "^3.7.0",

src/build/index.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ const fs = require('fs')
66
const bytes = require('bytes')
77
const execa = require('execa')
88
const rimraf = require('rimraf')
9-
const { fromAegir, gzipSize, pkg } = require('./../utils')
9+
const { fromAegir, gzipSize, pkg, hasTsconfig } = require('./../utils')
1010
const userConfig = require('../config/user')
11+
const tsCmd = require('../ts')
1112

1213
const config = userConfig()
1314

@@ -41,15 +42,8 @@ module.exports = async (argv) => {
4142
stdio: 'inherit'
4243
})
4344

44-
if (argv.ts) {
45-
await execa('tsc', [
46-
'--outDir', './dist/src',
47-
'--declaration'
48-
], {
49-
localDir: path.join(__dirname, '../..'),
50-
preferLocal: true,
51-
stdio: 'inherit'
52-
})
45+
if (hasTsconfig) {
46+
await tsCmd({ preset: 'types' })
5347
}
5448

5549
if (argv.bundlesize) {

src/clean.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)