import { CompilerState , ConsoleMessageId , Extractor , ExtractorConfig , ExtractorLogLevel , ExtractorMessage , ExtractorMessageId , ExtractorResult , IConfigFile , } from '@microsoft/api-extractor' ; import debugFactory from 'debug' ; import fs from 'fs-extra' ; import path from 'path' ; import { DEFAULT_APIDOCS_EXTRACTION_PATH , ExtractorOptions , getPackagesWithTsDocs , LernaPackage , typeScriptPath , } from './helper' ; const debug = debugFactory ( 'loopback:tsdocs' ) ; remarks param options export async function runExtractorForMonorepo ( options = { } ) { debug ( 'Extractor options:' , options ) ; options = Object . assign ( { rootDir : process . cwd ( ) , apiDocsExtractionPath : DEFAULT_APIDOCS_EXTRACTION_PATH , typescriptCompilerFolder : typeScriptPath , tsconfigFilePath : 'tsconfig.json' , mainEntryPointFilePath : 'dist/index.d.ts' } , options ) ; const packages = await getPackagesWithTsDocs ( options . rootDir ) ; if ( ! packages . length ) return ; const lernaRootDir = packages [ 0 ] . rootPath ; if ( ! options . silent ) { console . log ( 'Running api-extractor for lerna repo: %s' , lernaRootDir ) ; } setupApiDocsDirs ( lernaRootDir , options ) ; const errors = { } ; for ( const pkg of packages ) { const err = invokeExtractorForPackage ( pkg , options ) ; if ( err != null ) { if ( options . ignoreErrors ) { errors [ pkg . name ] = err ; } else { throw err ; } } } if ( Object . keys ( errors ) . length === 0 ) return ; console . error ( '****************************************' + '****************************************' ) ; for ( const p in errors ) { const err = errors [ p ] as { message : string ; } ; console . error ( '%s: %s' , p , err ?. message ?? err ) ; } console . error ( '****************************************' + '****************************************' ) ; } export function runExtractorForPackage ( pkgDir = process . cwd ( ) , options = { } ) { options = Object . assign ( { rootDir : pkgDir , apiDocsExtractionPath : DEFAULT_APIDOCS_EXTRACTION_PATH , typescriptCompilerFolder : typeScriptPath , tsconfigFilePath : 'tsconfig.json' , mainEntryPointFilePath : 'dist/index.d.ts' } , options ) ; const pkgJson = require ( path . join ( pkgDir , 'package.json' ) ) ; setupApiDocsDirs ( pkgDir , options ) ; const pkg = { private : pkgJson . private , name : pkgJson . name , location : pkgDir , manifestLocation : path . join ( pkgDir , 'package.json' ) , rootPath : pkgDir } ; const err = invokeExtractorForPackage ( pkg , options ) ; if ( err == null ) return ; if ( ! options . ignoreErrors ) { throw err ; } console . error ( err ) ; } param pkg param options function invokeExtractorForPackage ( pkg , options ) { if ( ! options . silent ) { console . log ( '> %s' , pkg . name ) ; } debug ( 'Package: %s (%s)' , pkg . name , pkg . location ) ; process . chdir ( pkg . location ) ; const extractorConfig = buildExtractorConfig ( pkg , options ) ; debug ( 'Resolved extractor config:' , extractorConfig ) ; try { invokeExtractor ( extractorConfig , options ) ; } catch ( err ) { debug ( 'Error in extracting API docs for %s' , pkg . name , err ) ; return err ; } } param lernaRootDir param options function setupApiDocsDirs ( lernaRootDir , options ) { if ( options . dryRun ) return ; const apiDocsExtractionPath = options . apiDocsExtractionPath ! ; fs . emptyDirSync ( path . join ( lernaRootDir , `${ apiDocsExtractionPath }/models` ) ) ; if ( ! options . apiReportEnabled ) return ; fs . ensureDirSync ( path . join ( lernaRootDir , `${ apiDocsExtractionPath }/reports` ) ) ; fs . emptyDirSync ( path . join ( lernaRootDir , `${ apiDocsExtractionPath }/reports-temp` ) ) ; } param pkg param options function createRawExtractorConfig ( pkg , options ) { const entryPoint = path . join ( pkg . location , options . mainEntryPointFilePath ! ) ; const apiDocsExtractionPath = options . apiDocsExtractionPath ! ; let configObj = { projectFolder : pkg . location , mainEntryPointFilePath : entryPoint , apiReport : { enabled : ! ! options . apiReportEnabled , reportFolder : path . join ( pkg . rootPath , `${ apiDocsExtractionPath }/reports` ) , reportTempFolder : path . join ( pkg . rootPath , `${ apiDocsExtractionPath }/reports-temp` ) , reportFileName : '<unscopedPackageName>.api.md' } , docModel : { enabled : true , apiJsonFilePath : path . join ( pkg . rootPath , `${ apiDocsExtractionPath }/models/<unscopedPackageName>.api.json` ) } , messages : { extractorMessageReporting : { [ ExtractorMessageId . MissingReleaseTag ] : { logLevel : ExtractorLogLevel . None , addToApiReportFile : false } } } , compiler : { tsconfigFilePath : options . tsconfigFilePath ! } } ; if ( options . config ) { configObj = Object . assign ( configObj , options . config ) ; } debug ( 'Extractor config options:' , configObj ) ; return configObj ; } param pkg param options function buildExtractorConfig ( pkg , options ) { const configObj = createRawExtractorConfig ( pkg , options ) ; const extractorConfig = ExtractorConfig . prepare ( { configObject : configObj , configObjectFullPath : '' , packageJsonFullPath : pkg . manifestLocation } ) ; return extractorConfig ; } param extractorConfig param options function invokeExtractor ( extractorConfig , options ) { const compilerState = CompilerState . create ( extractorConfig , { } ) ; if ( options . dryRun ) return ; const extractorResult = Extractor . invoke ( extractorConfig , { typescriptCompilerFolder : options . typescriptCompilerFolder , localBuild : true , showVerboseMessages : ! options . silent , messageCallback : ( message ) => { if ( message . messageId === ConsoleMessageId . ApiReportCreated ) { message . logLevel = ExtractorLogLevel . None ; } } , compilerState } ) ; debug ( extractorResult ) ; }