Skip to content

Commit 375cfe7

Browse files
feat(pkg): optimize attw and publint packing (#736)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 954f7bc commit 375cfe7

File tree

8 files changed

+71
-41
lines changed

8 files changed

+71
-41
lines changed

dts.snapshot.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"config-!~{00i}~.d.mts": {
2+
"config-!~{00m}~.d.mts": {
33
"defineConfig": "declare function defineConfig(_: UserConfigExport): UserConfigExport",
44
"mergeConfig": "declare function mergeConfig(_: InlineConfig, _: InlineConfig): InlineConfig",
55
"resolveUserConfig": "declare function resolveUserConfig(_: UserConfig, _: InlineConfig): Promise<ResolvedConfig[]>"
@@ -83,7 +83,7 @@
8383
"run.d.mts": {
8484
"#exports": []
8585
},
86-
"types-!~{00g}~.d.mts": {
86+
"types-!~{00k}~.d.mts": {
8787
"Arrayable": "type Arrayable<T> = T | T[]",
8888
"AttwOptions": "interface AttwOptions extends CheckPackageOptions {\n profile?: 'strict' | 'node16' | 'esm-only'\n level?: 'error' | 'warn'\n ignoreRules?: string[]\n}",
8989
"Awaitable": "type Awaitable<T> = T | Promise<T>",
@@ -126,7 +126,7 @@
126126
"PackageJsonScriptWithPreAndPost": "type PackageJsonScriptWithPreAndPost<S extends string> = S | `${'pre' | 'post'}${S}`",
127127
"PackageJsonWithPath": "interface PackageJsonWithPath extends PackageJson {\n packageJsonPath: string\n}",
128128
"PackageType": "type PackageType = 'module' | 'commonjs' | undefined",
129-
"PublintOptions": "interface PublintOptions extends Options {}",
129+
"PublintOptions": "interface PublintOptions extends Omit<Options, 'pack' | 'pkgDir'> {}",
130130
"ReportOptions": "interface ReportOptions {\n gzip?: boolean\n brotli?: boolean\n maxCompressSize?: number\n}",
131131
"ReportPlugin": "declare function ReportPlugin(_: ReportOptions, _: Logger, _: string, _: boolean, _: string, _: boolean): Plugin",
132132
"ResolvedConfig": "type ResolvedConfig = Overwrite<MarkPartial<Omit<UserConfig, 'workspace' | 'fromVite' | 'publicDir' | 'bundle' | 'removeNodeProtocol' | 'logLevel' | 'failOnWarn' | 'customLogger' | 'envFile' | 'envPrefix'>, 'globalName' | 'inputOptions' | 'outputOptions' | 'minify' | 'define' | 'alias' | 'external' | 'onSuccess' | 'outExtensions' | 'hooks' | 'copy' | 'loader' | 'name' | 'banner' | 'footer' | 'checks'>, { entry: Record<string, string>; nameLabel: string | undefined; format: NormalizedFormat; target?: string[]; clean: string[]; pkg?: PackageJsonWithPath; nodeProtocol: 'strip' | boolean; logger: Logger; ignoreWatch: Array<string | RegExp>; noExternal?: NoExternalFn; inlineOnly?: Array<string | RegExp> | false; css: Required<CssOptions>; dts: false | DtsOptions; report: false | ReportOptions; tsconfig: false | string; exports: false | ExportsOptions; devtools: false | DevtoolsOptions; publint: false | PublintOptions; attw: false | AttwOptions; unused: false | UnusedOptions }>",

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
},
109109
"devDependencies": {
110110
"@arethetypeswrong/core": "catalog:peer",
111+
"@publint/pack": "catalog:dev",
111112
"@sxzz/eslint-config": "catalog:dev",
112113
"@sxzz/prettier-config": "catalog:dev",
113114
"@sxzz/test-utils": "catalog:dev",
@@ -126,6 +127,7 @@
126127
"is-in-ci": "catalog:prod",
127128
"lightningcss": "catalog:dev",
128129
"memfs": "catalog:dev",
130+
"package-manager-detector": "catalog:prod",
129131
"pkg-types": "catalog:dev",
130132
"prettier": "catalog:dev",
131133
"publint": "catalog:peer",

pnpm-lock.yaml

Lines changed: 9 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
@@ -12,6 +12,7 @@ catalogs:
1212
'@clack/prompts': ^0.11.0
1313
giget: ^3.1.1
1414
dev:
15+
'@publint/pack': ^0.1.3
1516
'@sxzz/eslint-config': ^7.5.1
1617
'@sxzz/prettier-config': ^2.2.6
1718
'@sxzz/test-utils': ^0.5.15

src/features/pkg/attw.ts

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
import { mkdtemp, readFile } from 'node:fs/promises'
2-
import { tmpdir } from 'node:os'
31
import path from 'node:path'
42
import { dim } from 'ansis'
53
import { createDebug } from 'obug'
6-
import { exec } from 'tinyexec'
7-
import { fsRemove } from '../../utils/fs.ts'
84
import { importWithError, slash } from '../../utils/general.ts'
95
import type { ResolvedConfig } from '../../config/index.ts'
106
import type {
117
CheckPackageOptions,
12-
CheckResult,
138
Problem,
149
ProblemKind,
1510
} from '@arethetypeswrong/core'
11+
import type { Buffer } from 'node:buffer'
1612

1713
const debug = createDebug('tsdown:attw')
1814
const label = dim`[attw]`
@@ -96,7 +92,10 @@ const profiles: Record<Required<AttwOptions>['profile'], string[]> = {
9692
'esm-only': ['node10', 'node16-cjs'],
9793
}
9894

99-
export async function attw(options: ResolvedConfig): Promise<void> {
95+
export async function attw(
96+
options: ResolvedConfig,
97+
tarball: Buffer<ArrayBuffer>,
98+
): Promise<void> {
10099
if (!options.attw) return
101100
if (!options.pkg) {
102101
options.logger.warn('attw is enabled but package.json is not found')
@@ -121,34 +120,12 @@ export async function attw(options: ResolvedConfig): Promise<void> {
121120
const t = performance.now()
122121
debug('Running attw check')
123122

124-
const tempDir = await mkdtemp(path.join(tmpdir(), 'tsdown-attw-'))
125-
126123
const attwCore = await importWithError<
127124
typeof import('@arethetypeswrong/core')
128125
>('@arethetypeswrong/core', options.attw.resolvePaths)
129-
let checkResult: CheckResult
130-
131-
try {
132-
const { stdout: tarballInfo } = await exec(
133-
'npm',
134-
['pack', '--json', '--ignore-scripts', '--pack-destination', tempDir],
135-
{ nodeOptions: { cwd: options.cwd } },
136-
)
137-
const parsed = JSON.parse(tarballInfo)
138-
if (!Array.isArray(parsed) || !parsed[0]?.filename) {
139-
throw new Error('Invalid npm pack output format')
140-
}
141-
const tarballPath = path.join(tempDir, parsed[0].filename as string)
142-
const tarball = await readFile(tarballPath)
143126

144-
const pkg = attwCore.createPackageFromTarballData(tarball)
145-
checkResult = await attwCore.checkPackage(pkg, attwOptions)
146-
} catch (error) {
147-
options.logger.error('ATTW check failed:', error)
148-
return
149-
} finally {
150-
await fsRemove(tempDir)
151-
}
127+
const pkg = attwCore.createPackageFromTarballData(tarball)
128+
const checkResult = await attwCore.checkPackage(pkg, attwOptions)
152129

153130
let errorMessage: string | undefined
154131
if (checkResult.types) {

src/features/pkg/index.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import { mkdtemp, readFile } from 'node:fs/promises'
2+
import { tmpdir } from 'node:os'
3+
import path from 'node:path'
14
import { formatWithOptions } from 'node:util'
5+
import { fsRemove } from '../../utils/fs.ts'
26
import { promiseWithResolvers } from '../../utils/general.ts'
37
import { attw } from './attw.ts'
48
import { writeExports } from './exports.ts'
59
import { publint } from './publint.ts'
610
import type { ResolvedConfig } from '../../config/types.ts'
711
import type { ChunksByFormat, TsdownBundle } from '../../utils/chunks.ts'
12+
import type { Buffer } from 'node:buffer'
813

914
export type BundleByPkg = Record<
1015
string, // pkgPath
@@ -91,14 +96,45 @@ export async function bundleDone(
9196
)
9297
}
9398

94-
await Promise.all([
95-
...publintConfigs.map((config) => publint(config)),
96-
...attwConfigs.map((config) => attw(config)),
97-
])
99+
try {
100+
if (publintConfigs.length || attwConfigs.length) {
101+
const tarball = await packTarball(pkg.packageJsonPath)
102+
await Promise.all([
103+
...publintConfigs.map((config) => publint(config, tarball)),
104+
...attwConfigs.map((config) => attw(config, tarball)),
105+
])
106+
}
107+
} catch (error) {
108+
configs[0].logger.error('Pack failed:', error)
109+
}
98110

99111
ctx.resolve()
100112
}
101113

114+
async function packTarball(
115+
packageJsonPath: string,
116+
): Promise<Buffer<ArrayBuffer>> {
117+
const pkgDir = path.dirname(packageJsonPath)
118+
const destination = await mkdtemp(path.join(tmpdir(), 'tsdown-pack-'))
119+
const [{ detect }, { pack }] = await Promise.all([
120+
import('package-manager-detector/detect'),
121+
import('@publint/pack'),
122+
])
123+
try {
124+
const detected = await detect({ cwd: pkgDir })
125+
if (detected?.name === 'deno') {
126+
throw new Error(`Cannot pack tarball for Deno projects at ${pkgDir}`)
127+
}
128+
const tarballPath = await pack(pkgDir, {
129+
destination,
130+
packageManager: detected?.name,
131+
})
132+
return readFile(tarballPath)
133+
} finally {
134+
await fsRemove(destination)
135+
}
136+
}
137+
102138
function dedupeConfigs<K extends 'publint' | 'attw' | 'exports'>(
103139
configs: Array<ResolvedConfig>,
104140
key: K,

src/features/pkg/publint.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
import path from 'node:path'
21
import { dim } from 'ansis'
32
import { createDebug } from 'obug'
43
import { importWithError } from '../../utils/general.ts'
54
import type { ResolvedConfig } from '../../config/index.ts'
5+
import type { Buffer } from 'node:buffer'
66
import type { Options } from 'publint'
77

88
const debug = createDebug('tsdown:publint')
99
const label = dim`[publint]`
1010

11-
export interface PublintOptions extends Options {
11+
export interface PublintOptions extends Omit<Options, 'pack' | 'pkgDir'> {
1212
/** @internal */
1313
resolvePaths?: string[]
1414
}
1515

16-
export async function publint(options: ResolvedConfig): Promise<void> {
16+
export async function publint(
17+
options: ResolvedConfig,
18+
tarball: Buffer<ArrayBuffer>,
19+
): Promise<void> {
1720
if (!options.publint) return
1821
if (!options.pkg) {
1922
options.logger.warn(
@@ -36,7 +39,7 @@ export async function publint(options: ResolvedConfig): Promise<void> {
3639

3740
const { messages } = await publint({
3841
...options.publint,
39-
pkgDir: path.dirname(options.pkg.packageJsonPath),
42+
pack: { tarball: tarball.buffer },
4043
})
4144
debug('Found %d issues', messages.length)
4245

tsdown.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ export default defineConfig([
1010
entry: ['./src/{index,run,plugins,config}.ts'],
1111
name: 'tsdown',
1212
inlineOnly: [
13+
'@publint/pack',
1314
'is-in-ci',
15+
'package-manager-detector',
1416
'pkg-types', // type-only
1517
],
1618
platform: 'node',

0 commit comments

Comments
 (0)