@@ -109,6 +109,11 @@ namespace ts.server {
109109 "smart" : IndentStyle . Smart
110110 } ) ;
111111
112+ export interface TypesMapFile {
113+ typesMap : SafeList ;
114+ simpleMap : string [ ] ;
115+ }
116+
112117 /**
113118 * How to understand this block:
114119 * * The 'match' property is a regexp that matches a filename.
@@ -330,6 +335,7 @@ namespace ts.server {
330335 globalPlugins ?: ReadonlyArray < string > ;
331336 pluginProbeLocations ?: ReadonlyArray < string > ;
332337 allowLocalPluginLoads ?: boolean ;
338+ typesMapLocation ?: string ;
333339 }
334340
335341 export class ProjectService {
@@ -391,6 +397,7 @@ namespace ts.server {
391397 public readonly globalPlugins : ReadonlyArray < string > ;
392398 public readonly pluginProbeLocations : ReadonlyArray < string > ;
393399 public readonly allowLocalPluginLoads : boolean ;
400+ public readonly typesMapLocation : string | undefined ;
394401
395402 /** Tracks projects that we have already sent telemetry for. */
396403 private readonly seenProjects = createMap < true > ( ) ;
@@ -407,13 +414,18 @@ namespace ts.server {
407414 this . globalPlugins = opts . globalPlugins || emptyArray ;
408415 this . pluginProbeLocations = opts . pluginProbeLocations || emptyArray ;
409416 this . allowLocalPluginLoads = ! ! opts . allowLocalPluginLoads ;
417+ this . typesMapLocation = ( opts . typesMapLocation === undefined ) ? combinePaths ( this . host . getExecutingFilePath ( ) , "../typesMap.json" ) : opts . typesMapLocation ;
410418
411419 Debug . assert ( ! ! this . host . createHash , "'ServerHost.createHash' is required for ProjectService" ) ;
412420
413421 this . toCanonicalFileName = createGetCanonicalFileName ( this . host . useCaseSensitiveFileNames ) ;
414422 this . directoryWatchers = new DirectoryWatchers ( this ) ;
415423 this . throttledOperations = new ThrottledOperations ( this . host ) ;
416424
425+ if ( opts . typesMapLocation ) {
426+ this . loadTypesMap ( ) ;
427+ }
428+
417429 this . typingsInstaller . attach ( this ) ;
418430
419431 this . typingsCache = new TypingsCache ( this . typingsInstaller ) ;
@@ -451,6 +463,27 @@ namespace ts.server {
451463 this . eventHandler ( event ) ;
452464 }
453465
466+ private loadTypesMap ( ) {
467+ try {
468+ const fileContent = this . host . readFile ( this . typesMapLocation ) ;
469+ if ( fileContent === undefined ) {
470+ this . logger . info ( `Provided types map file "${ this . typesMapLocation } " doesn't exist` ) ;
471+ return ;
472+ }
473+ const raw : TypesMapFile = JSON . parse ( fileContent ) ;
474+ // Parse the regexps
475+ for ( const k of Object . keys ( raw . typesMap ) ) {
476+ raw . typesMap [ k ] . match = new RegExp ( raw . typesMap [ k ] . match as { } as string , "i" ) ;
477+ }
478+ // raw is now fixed and ready
479+ this . safelist = raw . typesMap ;
480+ }
481+ catch ( e ) {
482+ this . logger . info ( `Error loading types map: ${ e } ` ) ;
483+ this . safelist = defaultTypeSafeList ;
484+ }
485+ }
486+
454487 updateTypingsForProject ( response : SetTypings | InvalidateCachedTypings ) : void {
455488 const project = this . findProject ( response . projectName ) ;
456489 if ( ! project ) {
@@ -1712,23 +1745,14 @@ namespace ts.server {
17121745 this . safelist = defaultTypeSafeList ;
17131746 }
17141747
1715- loadSafeList ( fileName : string ) : void {
1716- const raw : SafeList = JSON . parse ( this . host . readFile ( fileName , "utf-8" ) ) ;
1717- // Parse the regexps
1718- for ( const k of Object . keys ( raw ) ) {
1719- raw [ k ] . match = new RegExp ( raw [ k ] . match as { } as string , "i" ) ;
1720- }
1721- // raw is now fixed and ready
1722- this . safelist = raw ;
1723- }
1724-
1725- applySafeList ( proj : protocol . ExternalProject ) : void {
1748+ applySafeList ( proj : protocol . ExternalProject ) : NormalizedPath [ ] {
17261749 const { rootFiles, typeAcquisition } = proj ;
17271750 const types = ( typeAcquisition && typeAcquisition . include ) || [ ] ;
17281751
17291752 const excludeRules : string [ ] = [ ] ;
17301753
1731- const normalizedNames = rootFiles . map ( f => normalizeSlashes ( f . fileName ) ) ;
1754+ const normalizedNames = rootFiles . map ( f => normalizeSlashes ( f . fileName ) ) as NormalizedPath [ ] ;
1755+ const excludedFiles : NormalizedPath [ ] = [ ] ;
17321756
17331757 for ( const name of Object . keys ( this . safelist ) ) {
17341758 const rule = this . safelist [ name ] ;
@@ -1787,7 +1811,17 @@ namespace ts.server {
17871811 }
17881812
17891813 const excludeRegexes = excludeRules . map ( e => new RegExp ( e , "i" ) ) ;
1790- proj . rootFiles = proj . rootFiles . filter ( ( _file , index ) => ! excludeRegexes . some ( re => re . test ( normalizedNames [ index ] ) ) ) ;
1814+ const filesToKeep : ts . server . protocol . ExternalFile [ ] = [ ] ;
1815+ for ( let i = 0 ; i < proj . rootFiles . length ; i ++ ) {
1816+ if ( excludeRegexes . some ( re => re . test ( normalizedNames [ i ] ) ) ) {
1817+ excludedFiles . push ( normalizedNames [ i ] ) ;
1818+ }
1819+ else {
1820+ filesToKeep . push ( proj . rootFiles [ i ] ) ;
1821+ }
1822+ }
1823+ proj . rootFiles = filesToKeep ;
1824+ return excludedFiles ;
17911825 }
17921826
17931827 openExternalProject ( proj : protocol . ExternalProject , suppressRefreshOfInferredProjects = false ) : void {
@@ -1798,7 +1832,7 @@ namespace ts.server {
17981832 proj . typeAcquisition = typeAcquisition ;
17991833 }
18001834
1801- this . applySafeList ( proj ) ;
1835+ const excludedFiles = this . applySafeList ( proj ) ;
18021836
18031837 let tsConfigFiles : NormalizedPath [ ] ;
18041838 const rootFiles : protocol . ExternalFile [ ] = [ ] ;
@@ -1822,6 +1856,7 @@ namespace ts.server {
18221856 const externalProject = this . findExternalProjectByProjectName ( proj . projectFileName ) ;
18231857 let exisingConfigFiles : string [ ] ;
18241858 if ( externalProject ) {
1859+ externalProject . excludedFiles = excludedFiles ;
18251860 if ( ! tsConfigFiles ) {
18261861 const compilerOptions = convertCompilerOptions ( proj . options ) ;
18271862 if ( this . exceededTotalSizeLimitForNonTsFiles ( proj . projectFileName , compilerOptions , proj . rootFiles , externalFilePropertyReader ) ) {
@@ -1891,7 +1926,8 @@ namespace ts.server {
18911926 else {
18921927 // no config files - remove the item from the collection
18931928 this . externalProjectToConfiguredProjectMap . delete ( proj . projectFileName ) ;
1894- this . createAndAddExternalProject ( proj . projectFileName , rootFiles , proj . options , proj . typeAcquisition ) ;
1929+ const newProj = this . createAndAddExternalProject ( proj . projectFileName , rootFiles , proj . options , proj . typeAcquisition ) ;
1930+ newProj . excludedFiles = excludedFiles ;
18951931 }
18961932 if ( ! suppressRefreshOfInferredProjects ) {
18971933 this . refreshInferredProjects ( ) ;
0 commit comments