11import ts from 'typescript' ;
22import consola from 'consola' ;
3- import { performance } from 'perf_hooks' ;
4- import { timeFrom , normalizePath } from '../utils.js' ;
5- import { createLogger } from './logger.js' ;
6- import formatAliasToTSPathsConfig from './formatAliasToTSPathsConfig.js' ;
7- import type { TaskConfig } from '../types.js' ;
3+ import { normalizePath } from '../utils.js' ;
4+ import { TaskConfig } from '../types.js' ;
85import { prepareSingleFileReplaceTscAliasPaths } from 'tsc-alias' ;
96import fse from 'fs-extra' ;
107import * as path from 'path' ;
@@ -23,8 +20,8 @@ export interface DtsInputFile extends File {
2320 dtsPath ?: string ;
2421}
2522
26- const normalizeDtsInput = ( file : File , rootDir : string , outputDir : string ) : DtsInputFile => {
27- const { filePath , ext } = file ;
23+ const normalizeDtsInput = ( filePath : string , rootDir : string , outputDir : string ) : DtsInputFile => {
24+ const ext = path . extname ( filePath ) as FileExt ;
2825 // https://www.typescriptlang.org/docs/handbook/esm-node.html#new-file-extensions
2926 // a.js -> a.d.ts
3027 // a.cjs -> a.d.cts
@@ -34,59 +31,106 @@ const normalizeDtsInput = (file: File, rootDir: string, outputDir: string): DtsI
3431 // a.mts -> a.d.mts
3532 const dtsPath = filePath . replace ( path . join ( rootDir , 'src' ) , outputDir ) . replace ( ext , `.d.${ / ^ \. [ j t ] / . test ( ext ) ? '' : ext [ 1 ] } ts` ) ;
3633 return {
37- ...file ,
34+ filePath,
35+ ext,
3836 dtsPath,
3937 } ;
4038} ;
4139
42- interface DtsCompileOptions {
40+ export interface DtsCompileOptions {
4341 // In watch mode, it only contains the updated file names. In build mode, it contains all file names.
44- files : File [ ] ;
42+ files : string [ ] ;
4543 alias : TaskConfig [ 'alias' ] ;
4644 rootDir : string ;
4745 outputDir : string ;
46+ }
47+
48+ function formatAliasToTSPathsConfig ( alias : TaskConfig [ 'alias' ] ) {
49+ const paths : { [ from : string ] : [ string ] } = { } ;
50+
51+ Object . entries ( alias || { } )
52+ . forEach ( ( [ key , value ] ) => {
53+ const [ pathKey , pathValue ] = formatPath ( key , value ) ;
54+ paths [ pathKey ] = [ pathValue ] ;
55+ } ) ;
4856
57+ return paths ;
4958}
5059
51- export async function dtsCompile ( { files , alias , rootDir , outputDir } : DtsCompileOptions ) : Promise < DtsInputFile [ ] > {
52- if ( ! files . length ) {
53- return ;
60+ function formatPath ( key : string , value : string ) {
61+ if ( key . endsWith ( '$' ) ) {
62+ return [ key . replace ( / \$ $ / , '' ) , value ] ;
5463 }
64+ // abc -> abc/*
65+ // abc/ -> abc/*
66+ return [ addWildcard ( key ) , addWildcard ( value ) ] ;
67+ }
5568
56- const tsConfig = await getTSConfig ( rootDir , outputDir , alias ) ;
69+ function addWildcard ( str : string ) {
70+ return `${ str . endsWith ( '/' ) ? str : `${ str } /` } *` ;
71+ }
5772
58- const logger = createLogger ( 'dts' ) ;
73+ async function getTSConfig (
74+ rootDir : string ,
75+ outputDir : string ,
76+ alias : TaskConfig [ 'alias' ] ,
77+ ) {
78+ const defaultTSCompilerOptions : ts . CompilerOptions = {
79+ allowJs : true ,
80+ declaration : true ,
81+ emitDeclarationOnly : true ,
82+ incremental : true ,
83+ skipLibCheck : true ,
84+ paths : formatAliasToTSPathsConfig ( alias ) , // default add alias to paths
85+ } ;
86+ const projectTSConfig = await getProjectTSConfig ( rootDir ) ;
87+ const tsConfig : ts . ParsedCommandLine = merge (
88+ { options : defaultTSCompilerOptions } ,
89+ projectTSConfig ,
90+ {
91+ options : {
92+ outDir : outputDir ,
93+ rootDir : path . join ( rootDir , 'src' ) ,
94+ } ,
95+ } ,
96+ ) ;
5997
60- logger . debug ( 'Start Compiling typescript declarations...' ) ;
98+ return tsConfig ;
99+ }
61100
62- const dtsCompileStart = performance . now ( ) ;
101+ async function getProjectTSConfig ( rootDir : string ) : Promise < ts . ParsedCommandLine > {
102+ const tsconfigPath = ts . findConfigFile ( rootDir , ts . sys . fileExists ) ;
103+ if ( tsconfigPath ) {
104+ const tsconfigFile = ts . readConfigFile ( tsconfigPath , ts . sys . readFile ) ;
105+ return ts . parseJsonConfigFileContent (
106+ tsconfigFile . config ,
107+ ts . sys ,
108+ path . dirname ( tsconfigPath ) ,
109+ ) ;
110+ }
63111
64- const _files = files
65- . map ( ( file ) => normalizeDtsInput ( file , rootDir , outputDir ) )
66- . map ( ( { filePath, dtsPath, ...rest } ) => ( {
67- ...rest ,
68- // Be compatible with Windows env.
69- filePath : normalizePath ( filePath ) ,
70- dtsPath : normalizePath ( dtsPath ) ,
71- } ) ) ;
112+ return {
113+ options : { } ,
114+ fileNames : [ ] ,
115+ errors : [ ] ,
116+ } ;
117+ }
72118
73- const dtsFiles = { } ;
119+ export async function dtsCompile ( { files, rootDir, outputDir, alias } : DtsCompileOptions ) : Promise < DtsInputFile [ ] > {
120+ if ( ! files . length ) {
121+ return [ ] ;
122+ }
74123
75- // Create ts host and custom the writeFile and readFile.
76- const host = ts . createCompilerHost ( tsConfig . options ) ;
77- host . writeFile = ( fileName , contents ) => {
78- dtsFiles [ fileName ] = contents ;
79- } ;
124+ const tsConfig = await getTSConfig ( rootDir , outputDir , alias ) ;
80125
81- const _readFile = host . readFile ;
82- // Hijack `readFile` to prevent reading file twice
83- host . readFile = ( fileName ) => {
84- const foundItem = files . find ( ( file ) => file . filePath === fileName ) ;
85- if ( foundItem && foundItem . srcCode ) {
86- return foundItem . srcCode ;
87- }
88- return _readFile ( fileName ) ;
89- } ;
126+ const _files = files
127+ . map ( ( file ) => normalizeDtsInput ( file , rootDir , outputDir ) )
128+ . map < DtsInputFile > ( ( { filePath, dtsPath, ...rest } ) => ( {
129+ ...rest ,
130+ // Be compatible with Windows env.
131+ filePath : normalizePath ( filePath ) ,
132+ dtsPath : normalizePath ( dtsPath ) ,
133+ } ) ) ;
90134
91135 // In order to only include the update files instead of all the files in the watch mode.
92136 function getProgramRootNames ( originalFilenames : string [ ] ) {
@@ -97,7 +141,13 @@ export async function dtsCompile({ files, alias, rootDir, outputDir }: DtsCompil
97141 return [ ...needCompileFileNames , ...dtsFilenames ] ;
98142 }
99143
100- // Create ts program.
144+ const dtsFiles = { } ;
145+ const host = ts . createCompilerHost ( tsConfig . options ) ;
146+
147+ host . writeFile = ( fileName , contents ) => {
148+ dtsFiles [ fileName ] = contents ;
149+ } ;
150+
101151 const programOptions : ts . CreateProgramOptions = {
102152 rootNames : getProgramRootNames ( tsConfig . fileNames ) ,
103153 options : tsConfig . options ,
@@ -107,8 +157,6 @@ export async function dtsCompile({ files, alias, rootDir, outputDir }: DtsCompil
107157 } ;
108158 const program = ts . createProgram ( programOptions ) ;
109159
110- logger . debug ( `Initializing program takes ${ timeFrom ( dtsCompileStart ) } ` ) ;
111-
112160 const emitResult = program . emit ( ) ;
113161
114162 if ( emitResult . diagnostics && emitResult . diagnostics . length > 0 ) {
@@ -123,9 +171,17 @@ export async function dtsCompile({ files, alias, rootDir, outputDir }: DtsCompil
123171 } ) ;
124172 }
125173
174+ if ( ! Object . keys ( alias ) . length ) {
175+ // no alias config
176+ return _files . map ( ( file ) => ( {
177+ ...file ,
178+ dtsContent : dtsFiles [ file . dtsPath ] ,
179+ } ) ) ;
180+ }
181+
126182 // We use tsc-alias to resolve d.ts alias.
127183 // Reason: https://github.com/microsoft/TypeScript/issues/30952#issuecomment-1114225407
128- const tsConfigLocalPath = path . join ( rootDir , 'node_modules/pkg/tsconfig.json' ) ;
184+ const tsConfigLocalPath = path . join ( rootDir , 'node_modules/.cache/ice- pkg/tsconfig.json' ) ;
129185 await fse . ensureFile ( tsConfigLocalPath ) ;
130186 await fse . writeJSON ( tsConfigLocalPath , {
131187 ...tsConfig ,
@@ -142,53 +198,5 @@ export async function dtsCompile({ files, alias, rootDir, outputDir }: DtsCompil
142198 dtsContent : dtsFiles [ file . dtsPath ] ? runFile ( { fileContents : dtsFiles [ file . dtsPath ] , filePath : file . dtsPath } ) : '' ,
143199 } ) ) ;
144200
145- logger . debug ( `Generating declaration files take ${ timeFrom ( dtsCompileStart ) } ` ) ;
146-
147201 return result ;
148202}
149-
150- async function getTSConfig (
151- rootDir : string ,
152- outputDir : string ,
153- alias : TaskConfig [ 'alias' ] ,
154- ) {
155- const defaultTSCompilerOptions : ts . CompilerOptions = {
156- allowJs : true ,
157- declaration : true ,
158- emitDeclarationOnly : true ,
159- incremental : true ,
160- skipLibCheck : true ,
161- paths : formatAliasToTSPathsConfig ( alias ) , // default add alias to paths
162- } ;
163- const projectTSConfig = await getProjectTSConfig ( rootDir ) ;
164- const tsConfig : ts . ParsedCommandLine = merge (
165- { options : defaultTSCompilerOptions } ,
166- projectTSConfig ,
167- {
168- options : {
169- outDir : outputDir ,
170- rootDir : path . join ( rootDir , 'src' ) ,
171- } ,
172- } ,
173- ) ;
174-
175- return tsConfig ;
176- }
177-
178- async function getProjectTSConfig ( rootDir : string ) : Promise < ts . ParsedCommandLine > {
179- const tsconfigPath = ts . findConfigFile ( rootDir , ts . sys . fileExists ) ;
180- if ( tsconfigPath ) {
181- const tsconfigFile = ts . readConfigFile ( tsconfigPath , ts . sys . readFile ) ;
182- return ts . parseJsonConfigFileContent (
183- tsconfigFile . config ,
184- ts . sys ,
185- path . dirname ( tsconfigPath ) ,
186- ) ;
187- }
188-
189- return {
190- options : { } ,
191- fileNames : [ ] ,
192- errors : [ ] ,
193- } ;
194- }
0 commit comments