import glob from "glob" ; import path from "path" ; import ts from "typescript" ; import { findComponents } from "./findComponents" ; import { ProcessedFile } from "./types" ; import { ComponentInfo } from "../types" ; import { flatMap } from "../utils" ; param files param tsConfigPath export async function analyzeTypeScript ( files , tsConfigPath ? ) { const processed = files . map ( t => ( { components : [ ] , srcFile : t , } ) ) ; const patterns = files . map ( file => { const dir = path . dirname ( file ) ; return path . join ( dir , "**/*.{tsx,ts,jsx,d.ts,js}" ) ; } ) ; const rootNames = flatMap ( patterns , pattern => glob . sync ( pattern ) ) ; const program = createProgram ( { rootNames , tsConfigPath } ) ; if ( process . env . NODE_ENV !== "test" ) { program . getSemanticDiagnostics ( ) . forEach ( diag => { if ( ! diag . file ) { return ; } console . warn ( diag . file . fileName , ts . getLineAndCharacterOfPosition ( diag . file , diag . start ! ) , ts . flattenDiagnosticMessageText ( diag . messageText , "\n" ) ) ; } ) ; } program . getTypeChecker ( ) ; for ( const file of processed ) { const sourceFile = program . getSourceFile ( file . srcFile ) ; if ( ! sourceFile ) throw new Error ( `File ${ file . srcFile } not found. If you're importing an NPM package, make sure the package has been installed by running "yarn add <package name>". Alternatively, make sure you've run "yarn install".` ) ; await analyze ( sourceFile , file , program ) ; } return flatMap ( processed , p => p . components ) ; } function analyze ( sourceFile , processedFile , program ) { processedFile . components = Array . from ( findComponents ( sourceFile , program ) ) . filter ( comp => comp . name . match ( /^[A-Z]/ ) ) ; } export function parseTsConfig ( tsConfigPath ) { const parseConfigHost = { fileExists : ts . sys . fileExists , readFile : ts . sys . readFile , readDirectory : ts . sys . readDirectory , useCaseSensitiveFileNames : true , } ; const configFileName = ts . findConfigFile ( path . dirname ( tsConfigPath ) , ts . sys . fileExists , "tsconfig.json" ) ; const configFile = ts . readConfigFile ( configFileName , ts . sys . readFile ) ; const parsedConfigFile = ts . parseJsonConfigFileContent ( configFile . config , parseConfigHost , path . dirname ( tsConfigPath ) ) ; if ( parsedConfigFile . errors . length > 0 ) { for ( const diagnostic of parsedConfigFile . errors ) { console . error ( ts . flattenDiagnosticMessageText ( diagnostic . messageText , "\n" ) ) ; } } return { ... parsedConfigFile . options , removeComments : false } ; } export function createFramerXProgram ( projectRoot ) { const tsConfigPath = path . join ( projectRoot , "tsconfig.json" ) ; const options = parseTsConfig ( tsConfigPath ) ; const components = glob . sync ( path . join ( projectRoot , "code/**/*.tsx" ) ) ; return ts . createProgram ( { rootNames : components , options , } ) ; } export function createProgram ( { tsConfigPath , rootNames } ) { const defaultConfig = { target : ts . ScriptTarget . ESNext , allowSyntheticDefaultImports : true , jsx : ts . JsxEmit . Preserve , noEmit : true , allowJs : true , moduleResolution : ts . ModuleResolutionKind . NodeJs , } ; const config = tsConfigPath ? parseTsConfig ( tsConfigPath ) : defaultConfig ; return ts . createProgram ( { rootNames , options : config } ) ; }