import { findPackageDir } from "@rnx-kit/tools-node" ; import { AllPlatforms , platformExtensions , } from "@rnx-kit/tools-react-native/platform" ; import { changeHostToUseReactNativeResolver } from "@rnx-kit/typescript-react-native-resolver" ; import { createDiagnosticWriter , Project , readConfigFile , } from "@rnx-kit/typescript-service" ; import path from "path" ; import ts from "typescript" ; export type ProjectInfo = { tsproject : Project ; tssourceFiles : Set < string > ; } ; /**
 * Collection of TypeScript projects, separated by their target platform.
 *
 * Target platform is a react-native concept, not a TypeScript concept.
 * However, each project is configured with react-native module resolution,
 * which means the module file graph could vary by platform. And that means
 * each platform could yield different type errors.
 *
 * For example, `import { f } from "./utils"` could load `./utils.android.ts`
 * for Android and `./utils.ios.ts` iOS.
 */ export interface ProjectCache { param platform clearPlatform ( platform ) : void ; param platform param sourceFile returns getProjectInfo ( sourceFile , platform ) : ProjectInfo ; } param print returns export function createProjectCache ( print ? ) { const documentRegistry = ts . createDocumentRegistry ( ) ; const diagnosticWriter = createDiagnosticWriter ( print ) ; const projects = { } ; function findProjectRoot ( sourceFile ) { for ( const root of Object . keys ( projects ) ) { if ( sourceFile . startsWith ( root ) ) { return root ; } } const root = findPackageDir ( path . dirname ( sourceFile ) ) ; if ( ! root ) { throw new Error ( `Cannot find project root for source file '${ sourceFile }'` ) ; } return root ; } function readTSConfig ( root ) { const configFileName = path . join ( root , "tsconfig.json" ) ; const cmdLine = readConfigFile ( configFileName ) ; if ( ! cmdLine ) { throw new Error ( `Failed to load '${ configFileName }'` ) ; } else if ( cmdLine . errors . length > 0 ) { const writer = createDiagnosticWriter ( ) ; cmdLine . errors . forEach ( ( e ) => writer . print ( e ) ) ; throw new Error ( `Failed to load '${ configFileName }'` ) ; } return cmdLine ; } function createProjectInfo ( root , platform ) { const cmdLine = readTSConfig ( root ) ; const tssourceFiles = new Set ( cmdLine . fileNames ) ; cmdLine . fileNames = cmdLine . fileNames . filter ( ( f ) => f . endsWith ( ".d.ts" ) ) ; const enhanceLanguageServiceHost = ( host ) : void => { const platformExtensionNames = platformExtensions ( platform ) ; const disableReactNativePackageSubstitution = true ; const traceReactNativeModuleResolutionErrors = false ; const traceResolutionLog = undefined ; changeHostToUseReactNativeResolver ( { host , options : cmdLine . options , platform , platformExtensionNames , disableReactNativePackageSubstitution , traceReactNativeModuleResolutionErrors , traceResolutionLog } ) ; } ; const tsproject = new Project ( documentRegistry , diagnosticWriter , cmdLine , enhanceLanguageServiceHost ) ; return { tsproject , tssourceFiles } ; } function getProjectInfo ( sourceFile , platform ) { const root = findProjectRoot ( sourceFile ) ; projects [ root ] ||= { } ; let info = projects [ root ] [ platform ] ; if ( ! info ) { info = createProjectInfo ( root , platform ) ; projects [ root ] [ platform ] = info ; } return info ; } function clearPlatform ( platform ) { Object . values ( projects ) . forEach ( ( projectsByPlatform ) => { const info = projectsByPlatform [ platform ] ; if ( info ) { if ( info . tsproject ) { info . tsproject . dispose ( ) ; } delete projectsByPlatform [ platform ] ; } } ) ; } return { clearPlatform , getProjectInfo } ; }