@@ -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.
@@ -329,6 +334,7 @@ namespace ts.server {
329334 globalPlugins ?: string [ ] ;
330335 pluginProbeLocations ?: string [ ] ;
331336 allowLocalPluginLoads ?: boolean ;
337+ typesMapLocation ?: string ;
332338 }
333339
334340 export class ProjectService {
@@ -389,6 +395,7 @@ namespace ts.server {
389395 public readonly globalPlugins : ReadonlyArray < string > ;
390396 public readonly pluginProbeLocations : ReadonlyArray < string > ;
391397 public readonly allowLocalPluginLoads : boolean ;
398+ public readonly typesMapLocation : string | undefined ;
392399
393400 /** Tracks projects that we have already sent telemetry for. */
394401 private readonly seenProjects = createMap < true > ( ) ;
@@ -404,13 +411,18 @@ namespace ts.server {
404411 this . globalPlugins = opts . globalPlugins || emptyArray ;
405412 this . pluginProbeLocations = opts . pluginProbeLocations || emptyArray ;
406413 this . allowLocalPluginLoads = ! ! opts . allowLocalPluginLoads ;
414+ this . typesMapLocation = ( opts . typesMapLocation === undefined ) ? combinePaths ( this . host . getExecutingFilePath ( ) , '../typesMap.json' ) : opts . typesMapLocation ;
407415
408416 Debug . assert ( ! ! this . host . createHash , "'ServerHost.createHash' is required for ProjectService" ) ;
409417
410418 this . toCanonicalFileName = createGetCanonicalFileName ( this . host . useCaseSensitiveFileNames ) ;
411419 this . directoryWatchers = new DirectoryWatchers ( this ) ;
412420 this . throttledOperations = new ThrottledOperations ( this . host ) ;
413421
422+ if ( opts . typesMapLocation ) {
423+ this . loadTypesMap ( ) ;
424+ }
425+
414426 this . typingsInstaller . attach ( this ) ;
415427
416428 this . typingsCache = new TypingsCache ( this . typingsInstaller ) ;
@@ -447,6 +459,25 @@ namespace ts.server {
447459 } ) ;
448460 }
449461
462+ private loadTypesMap ( ) {
463+ if ( ! this . host . fileExists ( this . typesMapLocation ) ) {
464+ this . logger . info ( `Provided types map file "${ this . typesMapLocation } " doesn't exist` ) ;
465+ return ;
466+ }
467+ try {
468+ const raw : TypesMapFile = JSON . parse ( this . host . readFile ( this . typesMapLocation ) ) ;
469+ // Parse the regexps
470+ for ( const k of Object . keys ( raw . typesMap ) ) {
471+ raw . typesMap [ k ] . match = new RegExp ( raw . typesMap [ k ] . match as { } as string , "i" ) ;
472+ }
473+ // raw is now fixed and ready
474+ this . safelist = raw . typesMap ;
475+ } catch ( e ) {
476+ this . logger . info ( `Error loading types map: ${ e } ` ) ;
477+ this . safelist = defaultTypeSafeList ;
478+ }
479+ }
480+
450481 updateTypingsForProject ( response : SetTypings | InvalidateCachedTypings ) : void {
451482 const project = this . findProject ( response . projectName ) ;
452483 if ( ! project ) {
@@ -1623,23 +1654,14 @@ namespace ts.server {
16231654 this . safelist = defaultTypeSafeList ;
16241655 }
16251656
1626- loadSafeList ( fileName : string ) : void {
1627- const raw : SafeList = JSON . parse ( this . host . readFile ( fileName , "utf-8" ) ) ;
1628- // Parse the regexps
1629- for ( const k of Object . keys ( raw ) ) {
1630- raw [ k ] . match = new RegExp ( raw [ k ] . match as { } as string , "i" ) ;
1631- }
1632- // raw is now fixed and ready
1633- this . safelist = raw ;
1634- }
1635-
1636- applySafeList ( proj : protocol . ExternalProject ) : void {
1657+ applySafeList ( proj : protocol . ExternalProject ) : NormalizedPath [ ] {
16371658 const { rootFiles, typeAcquisition } = proj ;
16381659 const types = ( typeAcquisition && typeAcquisition . include ) || [ ] ;
16391660
16401661 const excludeRules : string [ ] = [ ] ;
16411662
1642- const normalizedNames = rootFiles . map ( f => normalizeSlashes ( f . fileName ) ) ;
1663+ const normalizedNames = rootFiles . map ( f => normalizeSlashes ( f . fileName ) ) as NormalizedPath [ ] ;
1664+ const excludedFiles : NormalizedPath [ ] = [ ] ;
16431665
16441666 for ( const name of Object . keys ( this . safelist ) ) {
16451667 const rule = this . safelist [ name ] ;
@@ -1698,7 +1720,17 @@ namespace ts.server {
16981720 }
16991721
17001722 const excludeRegexes = excludeRules . map ( e => new RegExp ( e , "i" ) ) ;
1701- proj . rootFiles = proj . rootFiles . filter ( ( _file , index ) => ! excludeRegexes . some ( re => re . test ( normalizedNames [ index ] ) ) ) ;
1723+ const filesToKeep : ts . server . protocol . ExternalFile [ ] = [ ] ;
1724+ for ( let i = 0 ; i < proj . rootFiles . length ; i ++ ) {
1725+ if ( excludeRegexes . some ( re => re . test ( normalizedNames [ i ] ) ) ) {
1726+ excludedFiles . push ( normalizedNames [ i ] ) ;
1727+ }
1728+ else {
1729+ filesToKeep . push ( proj . rootFiles [ i ] ) ;
1730+ }
1731+ }
1732+ proj . rootFiles = filesToKeep ;
1733+ return excludedFiles ;
17021734 }
17031735
17041736 openExternalProject ( proj : protocol . ExternalProject , suppressRefreshOfInferredProjects = false ) : void {
@@ -1709,7 +1741,7 @@ namespace ts.server {
17091741 proj . typeAcquisition = typeAcquisition ;
17101742 }
17111743
1712- this . applySafeList ( proj ) ;
1744+ const excludedFiles = this . applySafeList ( proj ) ;
17131745
17141746 let tsConfigFiles : NormalizedPath [ ] ;
17151747 const rootFiles : protocol . ExternalFile [ ] = [ ] ;
@@ -1733,6 +1765,7 @@ namespace ts.server {
17331765 const externalProject = this . findExternalProjectByProjectName ( proj . projectFileName ) ;
17341766 let exisingConfigFiles : string [ ] ;
17351767 if ( externalProject ) {
1768+ externalProject . excludedFiles = excludedFiles ;
17361769 if ( ! tsConfigFiles ) {
17371770 const compilerOptions = convertCompilerOptions ( proj . options ) ;
17381771 if ( this . exceededTotalSizeLimitForNonTsFiles ( proj . projectFileName , compilerOptions , proj . rootFiles , externalFilePropertyReader ) ) {
@@ -1802,7 +1835,8 @@ namespace ts.server {
18021835 else {
18031836 // no config files - remove the item from the collection
18041837 this . externalProjectToConfiguredProjectMap . delete ( proj . projectFileName ) ;
1805- this . createAndAddExternalProject ( proj . projectFileName , rootFiles , proj . options , proj . typeAcquisition ) ;
1838+ const newProj = this . createAndAddExternalProject ( proj . projectFileName , rootFiles , proj . options , proj . typeAcquisition ) ;
1839+ newProj . excludedFiles = excludedFiles ;
18061840 }
18071841 if ( ! suppressRefreshOfInferredProjects ) {
18081842 this . refreshInferredProjects ( ) ;
0 commit comments