Skip to content

Commit 9ea3715

Browse files
gaoachaosxzz
andauthored
feat: integrate attw (#279)
Co-authored-by: Kevin Deng <sxzz@sxzz.moe>
1 parent 874e2d7 commit 9ea3715

File tree

8 files changed

+165
-3
lines changed

8 files changed

+165
-3
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,16 @@
5959
"docs:generate": "node --import @oxc-node/core/register ./docs/.vitepress/scripts/docs-generate.ts"
6060
},
6161
"peerDependencies": {
62+
"@arethetypeswrong/core": "^0.18.1",
6263
"publint": "^0.3.0",
6364
"typescript": "^5.0.0",
6465
"unplugin-lightningcss": "^0.4.0",
6566
"unplugin-unused": "^0.5.0"
6667
},
6768
"peerDependenciesMeta": {
69+
"@arethetypeswrong/core": {
70+
"optional": true
71+
},
6872
"publint": {
6973
"optional": true
7074
},
@@ -94,6 +98,7 @@
9498
"unconfig": "catalog:prod"
9599
},
96100
"devDependencies": {
101+
"@arethetypeswrong/core": "catalog:dev",
97102
"@oxc-node/core": "catalog:dev",
98103
"@sxzz/eslint-config": "catalog:dev",
99104
"@sxzz/prettier-config": "catalog:dev",

pnpm-lock.yaml

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
catalogs:
22
dev:
3+
'@arethetypeswrong/core': ^0.18.1
34
'@oxc-node/core': ^0.0.27
45
'@sxzz/eslint-config': ^7.0.1
56
'@sxzz/prettier-config': ^2.2.1

src/cli.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ cli
3636
})
3737
.option('--dts', 'Generate dts files')
3838
.option('--publint', 'Enable publint', { default: false })
39+
.option('--attw', 'Enable Are the types wrong integration', {
40+
default: false,
41+
})
3942
.option('--unused', 'Enable unused dependencies check', { default: false })
4043
.option('-w, --watch [path]', 'Watch mode')
4144
.option('--ignore-watch <path>', 'Ignore custom paths in watch mode')

src/features/attw.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import child_process from 'node:child_process'
2+
import { mkdtemp, readFile } from 'node:fs/promises'
3+
import { tmpdir } from 'node:os'
4+
import path from 'node:path'
5+
import process from 'node:process'
6+
import { promisify } from 'node:util'
7+
import { blue, dim } from 'ansis'
8+
import Debug from 'debug'
9+
import { fsRemove } from '../utils/fs'
10+
import { logger } from '../utils/logger'
11+
import type { ResolvedOptions } from '../options'
12+
13+
const debug = Debug('tsdown:attw')
14+
const exec = promisify(child_process.exec)
15+
16+
export async function attw(options: ResolvedOptions): Promise<void> {
17+
if (!options.attw) return
18+
if (!options.pkg) {
19+
logger.warn('attw is enabled but package.json is not found')
20+
return
21+
}
22+
23+
const t = performance.now()
24+
debug('Running attw check')
25+
26+
const tempDir = await mkdtemp(path.join(tmpdir(), 'tsdown-attw-'))
27+
28+
let attwCore: typeof import('@arethetypeswrong/core')
29+
try {
30+
attwCore = await import('@arethetypeswrong/core')
31+
} catch {
32+
logger.error(
33+
`ATTW check requires ${blue`@arethetypeswrong/core`} to be installed.`,
34+
)
35+
return
36+
}
37+
38+
try {
39+
const { stdout: tarballInfo } = await exec(
40+
`npm pack --json ----pack-destination ${tempDir}`,
41+
{ encoding: 'utf-8' },
42+
)
43+
const parsed = JSON.parse(tarballInfo)
44+
if (!Array.isArray(parsed) || !parsed[0]?.filename) {
45+
throw new Error('Invalid npm pack output format')
46+
}
47+
const tarballPath = path.join(tempDir, parsed[0].filename as string)
48+
const tarball = await readFile(tarballPath)
49+
50+
const pkg = attwCore.createPackageFromTarballData(tarball)
51+
const checkResult = await attwCore.checkPackage(
52+
pkg,
53+
options.attw === true ? {} : options.attw,
54+
)
55+
56+
if (checkResult.types !== false && checkResult.problems) {
57+
for (const problem of checkResult.problems) {
58+
logger.warn('Are the types wrong problem:', problem)
59+
}
60+
} else {
61+
logger.success(
62+
`No Are the types wrong problems found`,
63+
dim`(${Math.round(performance.now() - t)}ms)`,
64+
)
65+
}
66+
} catch (error) {
67+
logger.error('ATTW check failed:', error)
68+
debug('Found errors, setting exit code to 1')
69+
process.exitCode = 1
70+
} finally {
71+
await fsRemove(tempDir)
72+
}
73+
}

src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
type RolldownPluginOption,
1212
} from 'rolldown'
1313
import { exec } from 'tinyexec'
14+
import { attw } from './features/attw'
1415
import { cleanOutDir } from './features/clean'
1516
import { copy } from './features/copy'
1617
import { writeExports } from './features/exports'
@@ -155,9 +156,8 @@ export async function buildSingle(
155156
return
156157
}
157158

158-
await writeExports(config, chunks)
159-
await publint(config)
160-
await copy(config)
159+
await Promise.all([writeExports(config, chunks), copy(config)])
160+
await Promise.all([publint(config), attw(config)])
161161

162162
await hooks.callHook('build:done', context)
163163

src/options/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ async function resolveConfig(
190190
shims = false,
191191
skipNodeModulesBundle = false,
192192
publint = false,
193+
attw = false,
193194
fromVite,
194195
alias,
195196
tsconfig,
@@ -228,6 +229,7 @@ async function resolveConfig(
228229
}
229230

230231
if (publint === true) publint = {}
232+
if (attw === true) attw = {}
231233
if (exports === true) exports = {}
232234

233235
if (publicDir) {
@@ -289,6 +291,7 @@ async function resolveConfig(
289291
shims,
290292
skipNodeModulesBundle,
291293
publint,
294+
attw,
292295
alias,
293296
tsconfig,
294297
cwd,

src/options/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
MarkPartial,
1010
Overwrite,
1111
} from '../utils/types'
12+
import type { CheckPackageOptions as AttwOptions } from '@arethetypeswrong/core'
1213
import type { Hookable } from 'hookable'
1314
import type { PackageJson } from 'pkg-types'
1415
import type { Options as PublintOptions } from 'publint'
@@ -268,6 +269,15 @@ export interface Options {
268269
*/
269270
publint?: boolean | PublintOptions
270271

272+
/**
273+
* Run `arethetypeswrong` after bundling.
274+
* Requires `@arethetypeswrong/core` to be installed.
275+
*
276+
* @default false
277+
* @see https://github.com/arethetypeswrong/arethetypeswrong.github.io
278+
*/
279+
attw?: boolean | AttwOptions
280+
271281
/**
272282
* Enable size reporting after bundling.
273283
* @default true

0 commit comments

Comments
 (0)