tsup/src/api-extractor.ts

156 lines
4.2 KiB
TypeScript

import type {
ExtractorResult,
IConfigFile,
IExtractorConfigPrepareOptions,
} from '@microsoft/api-extractor'
import path from 'path'
import { handleError } from './errors'
import {
formatAggregationExports,
formatDistributionExports,
type ExportDeclaration,
} from './exports'
import { loadPkg } from './load'
import { createLogger } from './log'
import { Format, NormalizedOptions } from './options'
import {
defaultOutExtension,
ensureTempDeclarationDir,
getApiExtractor,
toAbsolutePath,
writeFileSync,
} from './utils'
const logger = createLogger()
function rollupDtsFile(
inputFilePath: string,
outputFilePath: string,
tsconfigFilePath: string
) {
let cwd = process.cwd()
let packageJsonFullPath = path.join(cwd, 'package.json')
let configObject: IConfigFile = {
mainEntryPointFilePath: inputFilePath,
apiReport: {
enabled: false,
// `reportFileName` is not been used. It's just to fit the requirement of API Extractor.
reportFileName: 'tsup-report.api.md',
},
docModel: { enabled: false },
dtsRollup: {
enabled: true,
untrimmedFilePath: outputFilePath,
},
tsdocMetadata: { enabled: false },
compiler: {
tsconfigFilePath: tsconfigFilePath,
},
projectFolder: cwd,
}
const prepareOptions: IExtractorConfigPrepareOptions = {
configObject,
configObjectFullPath: undefined,
packageJsonFullPath,
}
const imported = getApiExtractor()
if (!imported) {
throw new Error(
`@microsoft/api-extractor is not installed. Please install it first.`
)
}
const { ExtractorConfig, Extractor } = imported
const extractorConfig = ExtractorConfig.prepare(prepareOptions)
// Invoke API Extractor
const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, {
// Equivalent to the "--local" command-line parameter
localBuild: true,
// Equivalent to the "--verbose" command-line parameter
showVerboseMessages: true,
})
if (!extractorResult.succeeded) {
throw new Error(
`API Extractor completed with ${extractorResult.errorCount} errors and ${extractorResult.warningCount} warnings when processing ${inputFilePath}`
)
}
}
async function rollupDtsFiles(
options: NormalizedOptions,
exports: ExportDeclaration[],
format: Format
) {
let declarationDir = ensureTempDeclarationDir()
let outDir = options.outDir || 'dist'
let pkg = await loadPkg(process.cwd())
let dtsExtension = defaultOutExtension({ format, pkgType: pkg.type }).dts
let dtsInputFilePath = path.join(
declarationDir,
'_tsup-dts-aggregation' + dtsExtension
)
// @microsoft/api-extractor doesn't support `.d.mts` and `.d.cts` file as a
// entrypoint yet. So we replace the extension here as a temporary workaround.
//
// See the issue for more details:
// https://github.com/microsoft/rushstack/pull/4196
dtsInputFilePath = dtsInputFilePath
.replace(/\.d\.mts$/, '.dmts.d.ts')
.replace(/\.d\.cts$/, '.dcts.d.ts')
let dtsOutputFilePath = path.join(outDir, '_tsup-dts-rollup' + dtsExtension)
writeFileSync(
dtsInputFilePath,
formatAggregationExports(exports, declarationDir)
)
rollupDtsFile(
dtsInputFilePath,
dtsOutputFilePath,
options.tsconfig || 'tsconfig.json'
)
for (let [out, sourceFileName] of Object.entries(
options.experimentalDts!.entry
)) {
sourceFileName = toAbsolutePath(sourceFileName)
const outFileName = path.join(outDir, out + dtsExtension)
writeFileSync(
outFileName,
formatDistributionExports(exports, outFileName, dtsOutputFilePath)
)
}
}
export async function runDtsRollup(
options: NormalizedOptions,
exports?: ExportDeclaration[]
) {
try {
const start = Date.now()
const getDuration = () => {
return `${Math.floor(Date.now() - start)}ms`
}
logger.info('dts', 'Build start')
if (!exports) {
throw new Error('Unexpected internal error: dts exports is not define')
}
for (const format of options.format) {
await rollupDtsFiles(options, exports, format)
}
logger.success('dts', `⚡️ Build success in ${getDuration()}`)
} catch (error) {
handleError(error)
logger.error('dts', 'Build error')
}
}