@sanity/tsdoc
Version:
Generate API reference docs from TypeScript projects and store in a Sanity-friendly JSON format. Render a static frontend, or as React components.
177 lines (156 loc) • 4.34 kB
text/typescript
import {Extractor, ExtractorConfig, type ExtractorMessage} from '@microsoft/api-extractor'
import {ApiPackage} from '@microsoft/api-extractor-model'
import {
createLogger,
getExtractMessagesConfig,
loadConfig,
loadPkgWithReporting,
type PackageJSON,
parseExports,
parseStrictOptions,
type PkgConfigOptions,
} from '@sanity/pkg-utils'
import path from 'path'
import {createApiExtractorConfig} from './apiExtractorConfig'
import {createTempDir} from './helpers'
import {createTSDocConfig} from './tsDocConfig'
import type {TSDocCustomTag} from './types'
/**
* @public
*/
export interface ExtractResult {
apiPackage?: ApiPackage
exportPath: string
messages: ExtractorMessage[]
succeeded: boolean
tempDirPath: string
typesPath: string
}
/**
* Extract API information
*
* @public
*/
export async function extract(options: {
customTags?: TSDocCustomTag[]
packagePath: string
rules?: NonNullable<PkgConfigOptions['extract']>['rules']
strict: boolean
tsconfig?: string
bundledPackages?: string[]
}): Promise<{pkg: PackageJSON; results: ExtractResult[]}> {
const {
customTags,
packagePath,
rules,
strict,
tsconfig: tsconfigPath = 'tsconfig.json',
bundledPackages = [],
} = options
const tempDir = await createTempDir()
const tempDirPath = tempDir.path
const packageJsonFullPath = path.resolve(packagePath, 'package.json')
// pkg utils
const cwd = packagePath
const config = await loadConfig({cwd})
const strictOptions = parseStrictOptions(config?.strictOptions ?? {})
const logger = createLogger()
const pkg = await loadPkgWithReporting({cwd, logger, strict})
logger.info('Using tsconfig: ', path.resolve(packagePath, tsconfigPath))
// const exports = _resolveExports({pkg})
const exports = parseExports({
cwd,
pkg,
strict,
logger,
strictOptions,
})
try {
const results: ExtractResult[] = []
for (const exp of exports) {
if (!exp.source || !exp.default) {
continue
}
const typesPath = exp.default.replace(/\.[mc]?js$/, '.d.ts')
const result = await _doExtract({
customTags,
rules: rules ?? config?.extract?.rules,
mainEntryPointFilePath: typesPath,
packagePath,
tempDirPath,
tsconfigPath,
packageJsonFullPath,
bundledPackages,
})
results.push({
exportPath: exp._path,
tempDirPath,
typesPath: typesPath,
...result,
})
}
// Clean up temporary directory
tempDir.cleanup()
return {pkg, results}
} catch (err) {
// Clean up temporary directory
tempDir.cleanup()
throw err
}
}
async function _doExtract(options: {
customTags: NonNullable<PkgConfigOptions['extract']>['customTags']
rules: NonNullable<PkgConfigOptions['extract']>['rules']
mainEntryPointFilePath: string
packagePath: string
tempDirPath: string
tsconfigPath: string
packageJsonFullPath: string
bundledPackages: string[]
}) {
const {
customTags,
rules,
mainEntryPointFilePath,
packagePath,
tempDirPath,
tsconfigPath,
packageJsonFullPath,
bundledPackages,
} = options
const tsdocConfigFile = await createTSDocConfig({customTags: customTags || []})
// Load the API Extractor configuration
const extractorConfig: ExtractorConfig = ExtractorConfig.prepare({
configObject: createApiExtractorConfig({
mainEntryPointFilePath,
messagesConfig: getExtractMessagesConfig({rules}),
packagePath,
tempDirPath,
tsconfigPath,
bundledPackages,
}),
configObjectFullPath: undefined,
packageJson: undefined,
packageJsonFullPath,
tsdocConfigFile,
})
const messages: ExtractorMessage[] = []
// Invoke API Extractor
const extractorResult = Extractor.invoke(extractorConfig, {
// Equivalent to the "--local" command-line parameter
localBuild: true,
// Equivalent to the "--verbose" command-line parameter
showVerboseMessages: true,
// handle messages
messageCallback(message: ExtractorMessage) {
messages.push(message)
message.handled = true
},
})
const apiPackage = ApiPackage.loadFromJsonFile(path.resolve(tempDirPath, 'api.json'))
return {
apiPackage,
messages,
succeeded: extractorResult.succeeded,
}
}