2014-12-16 22:14:14 +01:00
/// <reference path="sys.ts" />
/// <reference path="emitter.ts" />
2015-07-29 04:26:18 +02:00
/// <reference path="core.ts" />
2014-12-16 22:14:14 +01:00
2015-06-12 18:01:48 +02:00
namespace ts {
2015-03-08 05:12:16 +01:00
/** The version of the TypeScript compiler release */
2016-07-12 05:53:12 +02:00
export const version = "2.1.0" ;
2015-10-01 01:10:52 +02:00
2015-11-04 23:02:33 +01:00
const emptyArray : any [ ] = [ ] ;
2015-10-01 01:10:52 +02:00
2016-06-11 00:44:11 +02:00
const defaultTypeRoots = [ "node_modules/@types" ] ;
2015-03-07 02:09:55 +01:00
2015-10-05 21:27:06 +02:00
export function findConfigFile ( searchPath : string , fileExists : ( fileName : string ) = > boolean ) : string {
2015-03-24 22:03:21 +01:00
while ( true ) {
2016-03-28 23:20:29 +02:00
const fileName = combinePaths ( searchPath , "tsconfig.json" ) ;
2015-10-05 21:27:06 +02:00
if ( fileExists ( fileName ) ) {
2015-03-24 22:03:21 +01:00
return fileName ;
}
2015-11-04 23:02:33 +01:00
const parentPath = getDirectoryPath ( searchPath ) ;
2015-03-24 22:03:21 +01:00
if ( parentPath === searchPath ) {
break ;
}
searchPath = parentPath ;
}
return undefined ;
}
2015-10-01 01:10:52 +02:00
2015-07-14 02:44:50 +02:00
export function resolveTripleslashReference ( module Name : string , containingFile : string ) : string {
2015-11-04 23:02:33 +01:00
const basePath = getDirectoryPath ( containingFile ) ;
const referencedFileName = isRootedDiskPath ( module Name ) ? module Name : combinePaths ( basePath , module Name ) ;
2015-07-14 02:44:50 +02:00
return normalizePath ( referencedFileName ) ;
}
2015-10-01 01:10:52 +02:00
2016-04-06 01:33:11 +02:00
/* @internal */
export function computeCommonSourceDirectoryOfFilenames ( fileNames : string [ ] , currentDirectory : string , getCanonicalFileName : ( fileName : string ) = > string ) : string {
2016-04-01 21:41:01 +02:00
let commonPathComponents : string [ ] ;
const failed = forEach ( fileNames , sourceFile = > {
// Each file contributes into common source file path
const sourcePathComponents = getNormalizedPathComponents ( sourceFile , currentDirectory ) ;
sourcePathComponents . pop ( ) ; // The base file name is not part of the common directory path
if ( ! commonPathComponents ) {
// first file
commonPathComponents = sourcePathComponents ;
return ;
}
for ( let i = 0 , n = Math . min ( commonPathComponents . length , sourcePathComponents . length ) ; i < n ; i ++ ) {
if ( getCanonicalFileName ( commonPathComponents [ i ] ) !== getCanonicalFileName ( sourcePathComponents [ i ] ) ) {
if ( i === 0 ) {
// Failed to find any common path component
return true ;
}
// New common path found that is 0 -> i-1
commonPathComponents . length = i ;
break ;
}
}
// If the sourcePathComponents was shorter than the commonPathComponents, truncate to the sourcePathComponents
if ( sourcePathComponents . length < commonPathComponents . length ) {
commonPathComponents . length = sourcePathComponents . length ;
}
} ) ;
// A common path can not be found when paths span multiple drives on windows, for example
if ( failed ) {
return "" ;
}
if ( ! commonPathComponents ) { // Can happen when all input files are .d.ts files
return currentDirectory ;
}
return getNormalizedPathFromPathComponents ( commonPathComponents ) ;
}
2015-11-20 06:33:33 +01:00
function trace ( host : ModuleResolutionHost , message : DiagnosticMessage , . . . args : any [ ] ) : void ;
function trace ( host : ModuleResolutionHost , message : DiagnosticMessage ) : void {
host . trace ( formatMessage . apply ( undefined , arguments ) ) ;
}
function isTraceEnabled ( compilerOptions : CompilerOptions , host : ModuleResolutionHost ) : boolean {
2016-04-01 21:41:01 +02:00
return compilerOptions . traceResolution && host . trace !== undefined ;
2015-11-20 06:33:33 +01:00
}
2016-06-03 15:22:34 +02:00
/* @internal */
2016-06-02 14:43:40 +02:00
export function hasZeroOrOneAsteriskCharacter ( str : string ) : boolean {
2016-01-25 20:49:26 +01:00
let seenAsterisk = false ;
for ( let i = 0 ; i < str . length ; i ++ ) {
if ( str . charCodeAt ( i ) === CharacterCodes . asterisk ) {
if ( ! seenAsterisk ) {
seenAsterisk = true ;
}
else {
// have already seen asterisk
return false ;
}
}
}
return true ;
}
function createResolvedModule ( resolvedFileName : string , isExternalLibraryImport : boolean , failedLookupLocations : string [ ] ) : ResolvedModuleWithFailedLookupLocations {
return { resolvedModule : resolvedFileName ? { resolvedFileName , isExternalLibraryImport } : undefined , failedLookupLocations } ;
}
function module HasNonRelativeName ( module Name : string ) : boolean {
2016-07-12 23:54:06 +02:00
return ! ( isRootedDiskPath ( module Name ) || isExternalModuleNameRelative ( module Name ) ) ;
2016-01-25 20:49:26 +01:00
}
interface ModuleResolutionState {
host : ModuleResolutionHost ;
compilerOptions : CompilerOptions ;
traceEnabled : boolean ;
2016-02-02 00:19:13 +01:00
// skip .tsx files if jsx is not enabled
skipTsx : boolean ;
2016-01-25 20:49:26 +01:00
}
2016-04-01 21:41:01 +02:00
function tryReadTypesSection ( packageJsonPath : string , baseDirectory : string , state : ModuleResolutionState ) : string {
2016-08-11 21:26:22 +02:00
const jsonContent = readJson ( packageJsonPath , state . host ) ;
function tryReadFromField ( fieldName : string ) {
if ( hasProperty ( jsonContent , fieldName ) ) {
const typesFile = ( < any > jsonContent ) [ fieldName ] ;
if ( typeof typesFile === "string" ) {
const typesFilePath = normalizePath ( combinePaths ( baseDirectory , typesFile ) ) ;
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . package_json_has_0_field_1_that_references_2 , fieldName , typesFile , typesFilePath ) ;
}
return typesFilePath ;
2016-04-01 21:41:01 +02:00
}
2016-08-11 21:26:22 +02:00
else {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Expected_type_of_0_field_in_package_json_to_be_string_got_1 , fieldName , typeof typesFile ) ;
}
2016-04-01 21:41:01 +02:00
}
}
}
2016-08-11 21:26:22 +02:00
const typesFilePath = tryReadFromField ( "typings" ) || tryReadFromField ( "types" ) ;
if ( typesFilePath ) {
2016-04-01 21:41:01 +02:00
return typesFilePath ;
}
2016-08-11 21:26:22 +02:00
2016-05-24 02:00:10 +02:00
// Use the main module for inferring types if no types package specified and the allowJs is set
if ( state . compilerOptions . allowJs && jsonContent . main && typeof jsonContent . main === "string" ) {
if ( state . traceEnabled ) {
2016-05-24 02:06:48 +02:00
trace ( state . host , Diagnostics . No_types_specified_in_package_json_but_allowJs_is_set_so_returning_main_value_of_0 , jsonContent . main ) ;
2016-05-24 02:00:10 +02:00
}
const mainFilePath = normalizePath ( combinePaths ( baseDirectory , jsonContent . main ) ) ;
return mainFilePath ;
}
2016-04-01 21:41:01 +02:00
return undefined ;
}
2016-08-11 21:26:22 +02:00
function readJson ( path : string , host : ModuleResolutionHost ) : { typings? : string , types? : string , main? : string } {
try {
const jsonText = host . readFile ( path ) ;
return jsonText ? JSON . parse ( jsonText ) : { } ;
}
catch ( e ) {
// gracefully handle if readFile fails or returns not JSON
return { } ;
}
}
2016-04-05 20:28:50 +02:00
const typeReferenceExtensions = [ ".d.ts" ] ;
2016-04-06 01:33:11 +02:00
2016-06-13 23:37:07 +02:00
function getEffectiveTypeRoots ( options : CompilerOptions , host : ModuleResolutionHost ) {
2016-06-28 20:43:07 +02:00
if ( options . typeRoots ) {
return options . typeRoots ;
}
let currentDirectory : string ;
if ( options . configFilePath ) {
currentDirectory = getDirectoryPath ( options . configFilePath ) ;
}
else if ( host . getCurrentDirectory ) {
currentDirectory = host . getCurrentDirectory ( ) ;
}
if ( ! currentDirectory ) {
return undefined ;
}
return map ( defaultTypeRoots , d = > combinePaths ( currentDirectory , d ) ) ;
2016-06-13 23:37:07 +02:00
}
2016-04-06 22:49:25 +02:00
/ * *
* @param { string | undefined } containingFile - file that contains type reference directive , can be undefined if containing file is unknown .
* This is possible in case if resolution is performed for directives specified via 'types' parameter . In this case initial path for secondary lookups
* is assumed to be the same as root directory of the project .
* /
2016-04-06 01:33:11 +02:00
export function resolveTypeReferenceDirective ( typeReferenceDirectiveName : string , containingFile : string , options : CompilerOptions , host : ModuleResolutionHost ) : ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
2016-04-01 21:41:01 +02:00
const traceEnabled = isTraceEnabled ( options , host ) ;
const module ResolutionState : ModuleResolutionState = {
compilerOptions : options ,
host : host ,
skipTsx : true ,
traceEnabled
} ;
2016-06-13 23:37:07 +02:00
const typeRoots = getEffectiveTypeRoots ( options , host ) ;
2016-04-01 21:41:01 +02:00
if ( traceEnabled ) {
2016-04-06 22:49:25 +02:00
if ( containingFile === undefined ) {
2016-06-11 00:44:11 +02:00
if ( typeRoots === undefined ) {
2016-04-06 22:49:25 +02:00
trace ( host , Diagnostics . Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set , typeReferenceDirectiveName ) ;
}
else {
2016-06-11 00:44:11 +02:00
trace ( host , Diagnostics . Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1 , typeReferenceDirectiveName , typeRoots ) ;
2016-04-06 22:49:25 +02:00
}
2016-04-06 01:33:11 +02:00
}
else {
2016-06-11 00:44:11 +02:00
if ( typeRoots === undefined ) {
2016-04-06 22:49:25 +02:00
trace ( host , Diagnostics . Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set , typeReferenceDirectiveName , containingFile ) ;
}
else {
2016-06-11 00:44:11 +02:00
trace ( host , Diagnostics . Resolving_type_reference_directive_0_containing_file_1_root_directory_2 , typeReferenceDirectiveName , containingFile , typeRoots ) ;
2016-04-06 22:49:25 +02:00
}
2016-04-06 01:33:11 +02:00
}
2016-04-01 21:41:01 +02:00
}
2016-04-06 01:33:11 +02:00
2016-04-01 21:41:01 +02:00
const failedLookupLocations : string [ ] = [ ] ;
2016-04-05 20:28:50 +02:00
2016-04-06 01:33:11 +02:00
// Check primary library paths
2016-06-28 21:10:26 +02:00
if ( typeRoots && typeRoots . length ) {
2016-06-11 00:44:11 +02:00
if ( traceEnabled ) {
2016-06-13 18:33:49 +02:00
trace ( host , Diagnostics . Resolving_with_primary_search_path_0 , typeRoots . join ( ", " ) ) ;
2016-06-11 00:44:11 +02:00
}
2016-06-13 18:33:49 +02:00
const primarySearchPaths = typeRoots ;
2016-06-11 00:44:11 +02:00
for ( const typeRoot of primarySearchPaths ) {
const candidate = combinePaths ( typeRoot , typeReferenceDirectiveName ) ;
2016-04-06 01:33:11 +02:00
const candidateDirectory = getDirectoryPath ( candidate ) ;
const resolvedFile = loadNodeModuleFromDirectory ( typeReferenceExtensions , candidate , failedLookupLocations ,
! directoryProbablyExists ( candidateDirectory , host ) , module ResolutionState ) ;
if ( resolvedFile ) {
if ( traceEnabled ) {
trace ( host , Diagnostics . Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2 , typeReferenceDirectiveName , resolvedFile , true ) ;
}
return {
resolvedTypeReferenceDirective : { primary : true , resolvedFileName : resolvedFile } ,
failedLookupLocations
} ;
2016-04-01 21:41:01 +02:00
}
2016-04-06 01:33:11 +02:00
}
}
else {
if ( traceEnabled ) {
trace ( host , Diagnostics . Root_directory_cannot_be_determined_skipping_primary_search_paths ) ;
2016-04-01 21:41:01 +02:00
}
}
2016-04-06 22:49:25 +02:00
let resolvedFile : string ;
let initialLocationForSecondaryLookup : string ;
if ( containingFile ) {
initialLocationForSecondaryLookup = getDirectoryPath ( containingFile ) ;
2016-04-01 21:41:01 +02:00
}
2016-04-06 22:49:25 +02:00
if ( initialLocationForSecondaryLookup !== undefined ) {
// check secondary locations
if ( traceEnabled ) {
trace ( host , Diagnostics . Looking_up_in_node_modules_folder_initial_location_0 , initialLocationForSecondaryLookup ) ;
2016-04-01 21:41:01 +02:00
}
2016-04-06 22:49:25 +02:00
resolvedFile = loadModuleFromNodeModules ( typeReferenceDirectiveName , initialLocationForSecondaryLookup , failedLookupLocations , module ResolutionState ) ;
if ( traceEnabled ) {
if ( resolvedFile ) {
trace ( host , Diagnostics . Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2 , typeReferenceDirectiveName , resolvedFile , false ) ;
}
else {
trace ( host , Diagnostics . Type_reference_directive_0_was_not_resolved , typeReferenceDirectiveName ) ;
}
}
}
else {
if ( traceEnabled ) {
trace ( host , Diagnostics . Containing_file_is_not_specified_and_root_directory_cannot_be_determined_skipping_lookup_in_node_modules_folder ) ;
2016-04-01 21:41:01 +02:00
}
}
return {
resolvedTypeReferenceDirective : resolvedFile
? { primary : false , resolvedFileName : resolvedFile }
: undefined ,
failedLookupLocations
} ;
}
2015-09-10 20:36:31 +02:00
export function resolveModuleName ( module Name : string , containingFile : string , compilerOptions : CompilerOptions , host : ModuleResolutionHost ) : ResolvedModuleWithFailedLookupLocations {
2015-11-20 06:33:33 +01:00
const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
if ( traceEnabled ) {
trace ( host , Diagnostics . Resolving_module_0_from_1 , module Name , containingFile ) ;
}
2015-11-19 06:46:45 +01:00
let module Resolution = compilerOptions . module Resolution ;
if ( module Resolution === undefined ) {
2016-02-13 00:40:47 +01:00
module Resolution = getEmitModuleKind ( compilerOptions ) === ModuleKind . CommonJS ? ModuleResolutionKind.NodeJs : ModuleResolutionKind.Classic ;
2015-11-20 06:33:33 +01:00
if ( traceEnabled ) {
trace ( host , Diagnostics . Module_resolution_kind_is_not_specified_using_0 , ModuleResolutionKind [ module Resolution ] ) ;
}
}
else {
if ( traceEnabled ) {
trace ( host , Diagnostics . Explicitly_specified_module_resolution_kind_Colon_0 , ModuleResolutionKind [ module Resolution ] ) ;
}
2015-11-19 06:46:45 +01:00
}
2015-10-01 01:10:52 +02:00
2015-11-20 06:33:33 +01:00
let result : ResolvedModuleWithFailedLookupLocations ;
2015-08-21 01:13:49 +02:00
switch ( module Resolution ) {
2015-11-20 06:33:33 +01:00
case ModuleResolutionKind . NodeJs :
result = nodeModuleNameResolver ( module Name , containingFile , compilerOptions , host ) ;
break ;
case ModuleResolutionKind . Classic :
result = classicNameResolver ( module Name , containingFile , compilerOptions , host ) ;
break ;
}
if ( traceEnabled ) {
if ( result . resolvedModule ) {
trace ( host , Diagnostics . Module_name_0_was_successfully_resolved_to_1 , module Name , result . resolvedModule . resolvedFileName ) ;
}
else {
trace ( host , Diagnostics . Module_name_0_was_not_resolved , module Name ) ;
}
2015-11-19 06:46:45 +01:00
}
2015-11-20 06:33:33 +01:00
return result ;
2015-11-19 06:46:45 +01:00
}
2016-01-25 20:49:26 +01:00
/ *
* Every module resolution kind can has its specific understanding how to load module from a specific path on disk
* I . e . for path '/a/b/c' :
* - Node loader will first to try to check if '/a/b/c' points to a file with some supported extension and if this fails
* it will try to load module from directory : directory '/a/b/c' should exist and it should have either 'package.json' with
* 'typings' entry or file 'index' with some supported extension
* - Classic loader will only try to interpret '/a/b/c' as file .
* /
2016-02-11 17:56:45 +01:00
type ResolutionKindSpecificLoader = ( candidate : string , extensions : string [ ] , failedLookupLocations : string [ ] , onlyRecordFailures : boolean , state : ModuleResolutionState ) = > string ;
2015-11-19 06:46:45 +01:00
2016-01-25 20:49:26 +01:00
/ * *
2016-01-30 20:37:02 +01:00
* Any module resolution kind can be augmented with optional settings : 'baseUrl' , 'paths' and 'rootDirs' - they are used to
* mitigate differences between design time structure of the project and its runtime counterpart so the same import name
* can be resolved successfully by TypeScript compiler and runtime module loader.
2016-01-25 20:49:26 +01:00
* If these settings are set then loading procedure will try to use them to resolve module name and it can of failure it will
* fallback to standard resolution routine .
2016-01-30 20:37:02 +01:00
*
2016-01-25 20:49:26 +01:00
* - baseUrl - this setting controls how non - relative module names are resolved . If this setting is specified then non - relative
2016-02-11 17:56:45 +01:00
* names will be resolved relative to baseUrl : i.e. if baseUrl is '/a/b' then candidate location to resolve module name 'c/d' will
2016-01-25 20:49:26 +01:00
* be '/a/b/c/d'
2016-01-30 20:37:02 +01:00
* - paths - this setting can only be used when baseUrl is specified . allows to tune how non - relative module names
* will be resolved based on the content of the module name.
2016-01-25 20:49:26 +01:00
* Structure of 'paths' compiler options
* 'paths' : {
* pattern - 1 : [ . . . substitutions ] ,
* pattern - 2 : [ . . . substitutions ] ,
* . . .
* pattern - n : [ . . . substitutions ]
* }
2016-01-30 20:37:02 +01:00
* Pattern here is a string that can contain zero or one '*' character . During module resolution module name will be matched against
2016-01-25 20:49:26 +01:00
* all patterns in the list . Matching for patterns that don 't contain ' * ' means that module name must be equal to pattern respecting the case .
2016-01-30 20:37:02 +01:00
* If pattern contains '*' then to match pattern "<prefix>*<suffix>" module name must start with the < prefix > and end with < suffix > .
* < MatchedStar > denotes part of the module name between < prefix > and < suffix > .
2016-01-25 20:49:26 +01:00
* If module name can be matches with multiple patterns then pattern with the longest prefix will be picked .
2016-01-30 20:37:02 +01:00
* After selecting pattern we ' ll use list of substitutions to get candidate locations of the module and the try to load module
* from the candidate location .
2016-02-11 17:56:45 +01:00
* Substitution is a string that can contain zero or one '*' . To get candidate location from substitution we ' ll pick every
2016-01-30 20:37:02 +01:00
* substitution in the list and replace '*' with < MatchedStar > string . If candidate location is not rooted it
2016-01-25 20:49:26 +01:00
* will be converted to absolute using baseUrl .
* For example :
* baseUrl : / a / b / c
* "paths" : {
* // match all module names
2016-01-30 20:37:02 +01:00
* "*" : [
2016-01-25 20:49:26 +01:00
* "*" , // use matched name as is,
* // <matched name> will be looked as /a/b/c/<matched name>
*
* "folder1/*" // substitution will convert matched name to 'folder1/<matched name>',
2016-01-30 20:37:02 +01:00
* // since it is not rooted then final candidate location will be /a/b/c/folder1/<matched name>
2016-01-25 20:49:26 +01:00
* ] ,
* // match module names that start with 'components/'
* "components/*" : [ "/root/components/*" ] // substitution will convert /components/folder1/<matched name> to '/root/components/folder1/<matched name>',
* // it is rooted so it will be final candidate location
* }
*
2016-01-30 20:37:02 +01:00
* 'rootDirs' allows the project to be spreaded across multiple locations and resolve module s with relative names as if
2016-01-25 20:49:26 +01:00
* they were in the same location . For example lets say there are two files
* '/local/src/content/file1.ts'
* '/shared/components/contracts/src/content/protocols/file2.ts'
2016-01-30 20:37:02 +01:00
* After bundling content of '/shared/components/contracts/src' will be merged with '/local/src' so
2016-01-25 20:49:26 +01:00
* if file1 has the following import 'import {x} from "./protocols/file2"' it will be resolved successfully in runtime .
* 'rootDirs' provides the way to tell compiler that in order to get the whole project it should behave as if content of all
* root dirs were merged together .
* I . e . for the example above 'rootDirs' will have two entries : [ '/local/src' , '/shared/components/contracts/src' ] .
2016-02-11 17:56:45 +01:00
* Compiler will first convert './protocols/file2' into absolute path relative to the location of containing file :
2016-01-25 20:49:26 +01:00
* '/local/src/content/protocols/file2' and try to load it - failure .
* Then it will search 'rootDirs' looking for a longest matching prefix of this absolute path and if such prefix is found - absolute path will
2016-02-11 17:56:45 +01:00
* be converted to a path relative to found rootDir entry './content/protocols/file2' ( * ) . As a last step compiler will check all remaining
2016-01-25 20:49:26 +01:00
* entries in 'rootDirs' , use them to build absolute path out of ( * ) and try to resolve module from this location .
* /
function tryLoadModuleUsingOptionalResolutionSettings ( module Name : string , containingDirectory : string , loader : ResolutionKindSpecificLoader ,
failedLookupLocations : string [ ] , supportedExtensions : string [ ] , state : ModuleResolutionState ) : string {
2015-11-20 06:33:33 +01:00
2016-01-25 20:49:26 +01:00
if ( module HasNonRelativeName ( module Name ) ) {
return tryLoadModuleUsingBaseUrl ( module Name , loader , failedLookupLocations , supportedExtensions , state ) ;
}
else {
return tryLoadModuleUsingRootDirs ( module Name , containingDirectory , loader , failedLookupLocations , supportedExtensions , state ) ;
2015-11-26 01:41:09 +01:00
}
2016-01-25 20:49:26 +01:00
}
2015-11-26 01:41:09 +01:00
2016-01-25 20:49:26 +01:00
function tryLoadModuleUsingRootDirs ( module Name : string , containingDirectory : string , loader : ResolutionKindSpecificLoader ,
failedLookupLocations : string [ ] , supportedExtensions : string [ ] , state : ModuleResolutionState ) : string {
2015-11-20 06:33:33 +01:00
2016-01-25 20:49:26 +01:00
if ( ! state . compilerOptions . rootDirs ) {
return undefined ;
2015-11-19 06:46:45 +01:00
}
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . rootDirs_option_is_set_using_it_to_resolve_relative_module_name_0 , module Name ) ;
2015-11-19 06:46:45 +01:00
}
const candidate = normalizePath ( combinePaths ( containingDirectory , module Name ) ) ;
2015-11-20 06:33:33 +01:00
2016-01-25 20:49:26 +01:00
let matchedRootDir : string ;
let matchedNormalizedPrefix : string ;
for ( const rootDir of state . compilerOptions . rootDirs ) {
// rootDirs are expected to be absolute
2016-01-30 20:37:02 +01:00
// in case of tsconfig.json this will happen automatically - compiler will expand relative names
2016-02-11 17:56:45 +01:00
// using location of tsconfig.json as base location
2016-01-25 20:49:26 +01:00
let normalizedRoot = normalizePath ( rootDir ) ;
if ( ! endsWith ( normalizedRoot , directorySeparator ) ) {
normalizedRoot += directorySeparator ;
}
const isLongestMatchingPrefix =
startsWith ( candidate , normalizedRoot ) &&
( matchedNormalizedPrefix === undefined || matchedNormalizedPrefix . length < normalizedRoot . length ) ;
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Checking_if_0_is_the_longest_matching_prefix_for_1_2 , normalizedRoot , candidate , isLongestMatchingPrefix ) ;
}
if ( isLongestMatchingPrefix ) {
matchedNormalizedPrefix = normalizedRoot ;
matchedRootDir = rootDir ;
}
2015-11-20 06:33:33 +01:00
}
2016-01-25 20:49:26 +01:00
if ( matchedNormalizedPrefix ) {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Longest_matching_prefix_for_0_is_1 , candidate , matchedNormalizedPrefix ) ;
}
const suffix = candidate . substr ( matchedNormalizedPrefix . length ) ;
2015-11-19 06:46:45 +01:00
2016-01-25 20:49:26 +01:00
// first - try to load from a initial location
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Loading_0_from_the_root_dir_1_candidate_location_2 , suffix , matchedNormalizedPrefix , candidate ) ;
}
const resolvedFileName = loader ( candidate , supportedExtensions , failedLookupLocations , ! directoryProbablyExists ( containingDirectory , state . host ) , state ) ;
if ( resolvedFileName ) {
return resolvedFileName ;
2015-11-20 06:33:33 +01:00
}
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Trying_other_entries_in_rootDirs ) ;
}
// then try to resolve using remaining entries in rootDirs
for ( const rootDir of state . compilerOptions . rootDirs ) {
if ( rootDir === matchedRootDir ) {
2016-01-30 20:37:02 +01:00
// skip the initially matched entry
2016-01-25 20:49:26 +01:00
continue ;
2015-11-19 06:46:45 +01:00
}
2016-01-25 20:49:26 +01:00
const candidate = combinePaths ( normalizePath ( rootDir ) , suffix ) ;
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Loading_0_from_the_root_dir_1_candidate_location_2 , suffix , rootDir , candidate ) ;
2015-11-26 01:41:09 +01:00
}
2016-01-25 20:49:26 +01:00
const baseDirectory = getDirectoryPath ( candidate ) ;
const resolvedFileName = loader ( candidate , supportedExtensions , failedLookupLocations , ! directoryProbablyExists ( baseDirectory , state . host ) , state ) ;
if ( resolvedFileName ) {
return resolvedFileName ;
2015-11-19 06:46:45 +01:00
}
}
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Module_resolution_using_rootDirs_has_failed ) ;
2015-11-19 06:46:45 +01:00
}
2016-01-25 20:49:26 +01:00
}
return undefined ;
}
2015-11-26 01:41:09 +01:00
2016-01-25 20:49:26 +01:00
function tryLoadModuleUsingBaseUrl ( module Name : string , loader : ResolutionKindSpecificLoader , failedLookupLocations : string [ ] ,
supportedExtensions : string [ ] , state : ModuleResolutionState ) : string {
if ( ! state . compilerOptions . baseUrl ) {
return undefined ;
2015-11-19 06:46:45 +01:00
}
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1 , state . compilerOptions . baseUrl , module Name ) ;
2015-11-19 06:46:45 +01:00
}
2015-11-26 01:41:09 +01:00
2016-06-02 14:43:40 +02:00
// string is for exact match
let matchedPattern : Pattern | string | undefined = undefined ;
2016-01-25 20:49:26 +01:00
if ( state . compilerOptions . paths ) {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0 , module Name ) ;
2015-11-20 06:33:33 +01:00
}
2016-06-03 15:22:34 +02:00
matchedPattern = matchPatternOrExact ( getKeys ( state . compilerOptions . paths ) , module Name ) ;
2015-11-19 06:46:45 +01:00
}
if ( matchedPattern ) {
2016-06-02 14:43:40 +02:00
const matchedStar = typeof matchedPattern === "string" ? undefined : matchedText ( matchedPattern , module Name ) ;
const matchedPatternText = typeof matchedPattern === "string" ? matchedPattern : patternText ( matchedPattern ) ;
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
2016-06-02 14:43:40 +02:00
trace ( state . host , Diagnostics . Module_name_0_matched_pattern_1 , module Name , matchedPatternText ) ;
2015-11-20 06:33:33 +01:00
}
2016-06-02 14:43:40 +02:00
for ( const subst of state . compilerOptions . paths [ matchedPatternText ] ) {
const path = matchedStar ? subst . replace ( "*" , matchedStar ) : subst ;
2016-01-25 20:49:26 +01:00
const candidate = normalizePath ( combinePaths ( state . compilerOptions . baseUrl , path ) ) ;
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Trying_substitution_0_candidate_module_location_Colon_1 , subst , path ) ;
2015-11-20 06:33:33 +01:00
}
2016-01-25 20:49:26 +01:00
const resolvedFileName = loader ( candidate , supportedExtensions , failedLookupLocations , ! directoryProbablyExists ( getDirectoryPath ( candidate ) , state . host ) , state ) ;
2015-11-19 06:46:45 +01:00
if ( resolvedFileName ) {
2016-01-25 20:49:26 +01:00
return resolvedFileName ;
2015-11-19 06:46:45 +01:00
}
}
2016-01-25 20:49:26 +01:00
return undefined ;
2015-11-19 06:46:45 +01:00
}
else {
2016-01-25 20:49:26 +01:00
const candidate = normalizePath ( combinePaths ( state . compilerOptions . baseUrl , module Name ) ) ;
2015-11-20 06:33:33 +01:00
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Resolving_module_name_0_relative_to_base_url_1_2 , module Name , state . compilerOptions . baseUrl , candidate ) ;
2015-11-20 06:33:33 +01:00
}
2016-01-25 20:49:26 +01:00
return loader ( candidate , supportedExtensions , failedLookupLocations , ! directoryProbablyExists ( getDirectoryPath ( candidate ) , state . host ) , state ) ;
2015-08-18 03:31:12 +02:00
}
}
2015-10-01 01:10:52 +02:00
2016-06-02 14:43:40 +02:00
/ * *
* patternStrings contains both pattern strings ( containing "*" ) and regular strings .
* Return an exact match if possible , or a pattern match , or undefined .
* ( These are verified by verifyCompilerOptions to have 0 or 1 "*" characters . )
* /
function matchPatternOrExact ( patternStrings : string [ ] , candidate : string ) : string | Pattern | undefined {
const patterns : Pattern [ ] = [ ] ;
for ( const patternString of patternStrings ) {
const pattern = tryParsePattern ( patternString ) ;
if ( pattern ) {
patterns . push ( pattern ) ;
}
else if ( patternString === candidate ) {
// pattern was matched as is - no need to search further
return patternString ;
}
}
return findBestPatternMatch ( patterns , _ = > _ , candidate ) ;
}
function patternText ( { prefix , suffix } : Pattern ) : string {
return ` ${ prefix } * ${ suffix } ` ;
}
/ * *
* Given that candidate matches pattern , returns the text matching the '*' .
* E.g. : matchedText ( tryParsePattern ( "foo*baz" ) , "foobarbaz" ) === "bar"
* /
function matchedText ( pattern : Pattern , candidate : string ) : string {
Debug . assert ( isPatternMatch ( pattern , candidate ) ) ;
return candidate . substr ( pattern . prefix . length , candidate . length - pattern . suffix . length ) ;
}
/** Return the object corresponding to the best pattern to match `candidate`. */
2016-06-03 15:22:34 +02:00
/* @internal */
2016-06-02 14:43:40 +02:00
export function findBestPatternMatch < T > ( values : T [ ] , getPattern : ( value : T ) = > Pattern , candidate : string ) : T | undefined {
let matchedValue : T | undefined = undefined ;
// use length of prefix as betterness criteria
let longestMatchPrefixLength = - 1 ;
for ( const v of values ) {
const pattern = getPattern ( v ) ;
if ( isPatternMatch ( pattern , candidate ) && pattern . prefix . length > longestMatchPrefixLength ) {
longestMatchPrefixLength = pattern . prefix . length ;
matchedValue = v ;
}
}
return matchedValue ;
}
function isPatternMatch ( { prefix , suffix } : Pattern , candidate : string ) {
return candidate . length >= prefix . length + suffix . length &&
startsWith ( candidate , prefix ) &&
endsWith ( candidate , suffix ) ;
}
2016-06-03 15:22:34 +02:00
/* @internal */
2016-06-02 14:43:40 +02:00
export function tryParsePattern ( pattern : string ) : Pattern | undefined {
// This should be verified outside of here and a proper error thrown.
Debug . assert ( hasZeroOrOneAsteriskCharacter ( pattern ) ) ;
const indexOfStar = pattern . indexOf ( "*" ) ;
return indexOfStar === - 1 ? undefined : {
prefix : pattern.substr ( 0 , indexOfStar ) ,
suffix : pattern.substr ( indexOfStar + 1 )
} ;
}
2015-11-16 20:49:26 +01:00
export function nodeModuleNameResolver ( module Name : string , containingFile : string , compilerOptions : CompilerOptions , host : ModuleResolutionHost ) : ResolvedModuleWithFailedLookupLocations {
2015-11-04 23:02:33 +01:00
const containingDirectory = getDirectoryPath ( containingFile ) ;
2015-11-16 20:49:26 +01:00
const supportedExtensions = getSupportedExtensions ( compilerOptions ) ;
2015-11-20 06:33:33 +01:00
const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
2015-10-01 01:10:52 +02:00
2016-01-25 20:49:26 +01:00
const failedLookupLocations : string [ ] = [ ] ;
2016-02-23 21:48:31 +01:00
const state = { compilerOptions , host , traceEnabled , skipTsx : false } ;
2016-01-25 20:49:26 +01:00
let resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings ( module Name , containingDirectory , nodeLoadModuleByRelativeName ,
failedLookupLocations , supportedExtensions , state ) ;
2015-10-01 01:10:52 +02:00
2016-05-05 22:38:09 +02:00
let isExternalLibraryImport = false ;
2016-05-24 02:00:10 +02:00
if ( ! resolvedFileName ) {
2016-05-05 22:38:09 +02:00
if ( module HasNonRelativeName ( module Name ) ) {
if ( traceEnabled ) {
trace ( host , Diagnostics . Loading_module_0_from_node_modules_folder , module Name ) ;
}
resolvedFileName = loadModuleFromNodeModules ( module Name , containingDirectory , failedLookupLocations , state ) ;
isExternalLibraryImport = resolvedFileName !== undefined ;
}
else {
const candidate = normalizePath ( combinePaths ( containingDirectory , module Name ) ) ;
resolvedFileName = nodeLoadModuleByRelativeName ( candidate , supportedExtensions , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
}
2015-08-18 03:31:12 +02:00
}
2015-10-01 01:10:52 +02:00
2016-05-05 22:38:09 +02:00
if ( resolvedFileName && host . realpath ) {
const originalFileName = resolvedFileName ;
resolvedFileName = normalizePath ( host . realpath ( resolvedFileName ) ) ;
2015-11-20 06:33:33 +01:00
if ( traceEnabled ) {
2016-05-05 22:38:09 +02:00
trace ( host , Diagnostics . Resolving_real_path_for_0_result_1 , originalFileName , resolvedFileName ) ;
2015-11-20 06:33:33 +01:00
}
2016-01-25 20:49:26 +01:00
}
2016-05-05 22:38:09 +02:00
2016-01-25 20:49:26 +01:00
return createResolvedModule ( resolvedFileName , isExternalLibraryImport , failedLookupLocations ) ;
}
function nodeLoadModuleByRelativeName ( candidate : string , supportedExtensions : string [ ] , failedLookupLocations : string [ ] ,
onlyRecordFailures : boolean , state : ModuleResolutionState ) : string {
2015-11-20 06:33:33 +01:00
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Loading_module_as_file_Slash_folder_candidate_module_location_0 , candidate ) ;
2015-08-18 03:31:12 +02:00
}
2016-01-25 20:49:26 +01:00
const resolvedFileName = loadModuleFromFile ( candidate , supportedExtensions , failedLookupLocations , onlyRecordFailures , state ) ;
return resolvedFileName || loadNodeModuleFromDirectory ( supportedExtensions , candidate , failedLookupLocations , onlyRecordFailures , state ) ;
2015-08-18 03:31:12 +02:00
}
2015-10-01 01:10:52 +02:00
2016-01-06 21:37:52 +01:00
/* @internal */
2016-02-23 21:48:31 +01:00
export function directoryProbablyExists ( directoryName : string , host : { directoryExists ? : ( directoryName : string ) = > boolean } ) : boolean {
2016-01-06 21:37:52 +01:00
// if host does not support 'directoryExists' assume that directory will exist
return ! host . directoryExists || host . directoryExists ( directoryName ) ;
}
/ * *
* @param { boolean } onlyRecordFailures - if true then function won ' t try to actually load files but instead record all attempts as failures . This flag is necessary
2016-01-30 20:37:02 +01:00
* in cases when we know upfront that all load attempts will fail ( because containing folder does not exists ) however we still need to record all failed lookup locations .
2016-01-06 21:37:52 +01:00
* /
2016-01-25 20:49:26 +01:00
function loadModuleFromFile ( candidate : string , extensions : string [ ] , failedLookupLocation : string [ ] , onlyRecordFailures : boolean , state : ModuleResolutionState ) : string {
2016-05-31 20:39:11 +02:00
// First try to keep/add an extension: importing "./foo.ts" can be matched by a file "./foo.ts", and "./foo" by "./foo.d.ts"
2016-05-31 21:58:05 +02:00
const resolvedByAddingOrKeepingExtension = loadModuleFromFileWorker ( candidate , extensions , failedLookupLocation , onlyRecordFailures , state ) ;
if ( resolvedByAddingOrKeepingExtension ) {
return resolvedByAddingOrKeepingExtension ;
2016-05-31 20:39:11 +02:00
}
// Then try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one, e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
if ( hasJavaScriptFileExtension ( candidate ) ) {
const extensionless = removeFileExtension ( candidate ) ;
if ( state . traceEnabled ) {
const extension = candidate . substring ( extensionless . length ) ;
trace ( state . host , Diagnostics . File_name_0_has_a_1_extension_stripping_it , candidate , extension ) ;
}
return loadModuleFromFileWorker ( extensionless , extensions , failedLookupLocation , onlyRecordFailures , state ) ;
}
}
2016-05-31 21:58:05 +02:00
2016-05-31 20:39:11 +02:00
function loadModuleFromFileWorker ( candidate : string , extensions : string [ ] , failedLookupLocation : string [ ] , onlyRecordFailures : boolean , state : ModuleResolutionState ) : string {
2016-04-01 21:41:01 +02:00
if ( ! onlyRecordFailures ) {
2016-05-31 21:58:05 +02:00
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
2016-04-01 21:41:01 +02:00
const directory = getDirectoryPath ( candidate ) ;
if ( directory ) {
onlyRecordFailures = ! directoryProbablyExists ( directory , state . host ) ;
}
}
2015-11-09 21:49:36 +01:00
return forEach ( extensions , tryLoad ) ;
2015-10-01 01:10:52 +02:00
2015-08-21 01:13:49 +02:00
function tryLoad ( ext : string ) : string {
2016-06-06 21:17:11 +02:00
if ( state . skipTsx && isJsxOrTsxExtension ( ext ) ) {
2016-02-02 00:19:13 +01:00
return undefined ;
}
2015-11-04 23:02:33 +01:00
const fileName = fileExtensionIs ( candidate , ext ) ? candidate : candidate + ext ;
2016-01-25 20:49:26 +01:00
if ( ! onlyRecordFailures && state . host . fileExists ( fileName ) ) {
if ( state . traceEnabled ) {
2016-04-01 21:41:01 +02:00
trace ( state . host , Diagnostics . File_0_exist_use_it_as_a_name_resolution_result , fileName ) ;
2015-11-20 06:33:33 +01:00
}
2015-08-21 01:13:49 +02:00
return fileName ;
}
else {
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . File_0_does_not_exist , fileName ) ;
2015-11-20 06:33:33 +01:00
}
2015-08-21 01:13:49 +02:00
failedLookupLocation . push ( fileName ) ;
return undefined ;
}
}
2015-08-18 03:31:12 +02:00
}
2015-10-01 01:10:52 +02:00
2016-01-25 20:49:26 +01:00
function loadNodeModuleFromDirectory ( extensions : string [ ] , candidate : string , failedLookupLocation : string [ ] , onlyRecordFailures : boolean , state : ModuleResolutionState ) : string {
2016-08-11 21:26:22 +02:00
const packageJsonPath = pathToPackageJson ( candidate ) ;
2016-01-25 20:49:26 +01:00
const directoryExists = ! onlyRecordFailures && directoryProbablyExists ( candidate , state . host ) ;
if ( directoryExists && state . host . fileExists ( packageJsonPath ) ) {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
2015-11-20 06:33:33 +01:00
}
2016-04-01 21:41:01 +02:00
const typesFile = tryReadTypesSection ( packageJsonPath , candidate , state ) ;
if ( typesFile ) {
const result = loadModuleFromFile ( typesFile , extensions , failedLookupLocation , ! directoryProbablyExists ( getDirectoryPath ( typesFile ) , state . host ) , state ) ;
if ( result ) {
return result ;
2015-08-18 03:31:12 +02:00
}
}
2015-11-20 06:33:33 +01:00
else {
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
2016-04-01 21:41:01 +02:00
trace ( state . host , Diagnostics . package_json_does_not_have_types_field ) ;
2015-08-18 03:31:12 +02:00
}
}
}
else {
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . File_0_does_not_exist , packageJsonPath ) ;
2015-11-20 06:33:33 +01:00
}
2015-08-18 03:31:12 +02:00
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
failedLookupLocation . push ( packageJsonPath ) ;
}
2015-10-01 01:10:52 +02:00
2016-01-25 20:49:26 +01:00
return loadModuleFromFile ( combinePaths ( candidate , "index" ) , extensions , failedLookupLocation , ! directoryExists , state ) ;
2015-08-18 03:31:12 +02:00
}
2015-10-01 01:10:52 +02:00
2016-08-11 21:26:22 +02:00
function pathToPackageJson ( directory : string ) : string {
return combinePaths ( directory , "package.json" ) ;
}
2016-04-01 21:41:01 +02:00
function loadModuleFromNodeModulesFolder ( module Name : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string {
const nodeModulesFolder = combinePaths ( directory , "node_modules" ) ;
const nodeModulesFolderExists = directoryProbablyExists ( nodeModulesFolder , state . host ) ;
const candidate = normalizePath ( combinePaths ( nodeModulesFolder , module Name ) ) ;
2016-05-24 02:00:10 +02:00
const supportedExtensions = getSupportedExtensions ( state . compilerOptions ) ;
let result = loadModuleFromFile ( candidate , supportedExtensions , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
2016-04-01 21:41:01 +02:00
if ( result ) {
return result ;
}
2016-05-24 02:00:10 +02:00
result = loadNodeModuleFromDirectory ( supportedExtensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
2016-04-01 21:41:01 +02:00
if ( result ) {
return result ;
}
}
2016-01-25 20:49:26 +01:00
function loadModuleFromNodeModules ( module Name : string , directory : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) : string {
2015-08-18 03:31:12 +02:00
directory = normalizeSlashes ( directory ) ;
while ( true ) {
2015-11-04 23:02:33 +01:00
const baseName = getBaseFileName ( directory ) ;
2015-08-18 03:31:12 +02:00
if ( baseName !== "node_modules" ) {
2016-06-30 02:04:42 +02:00
// Try to load source from the package
const packageResult = loadModuleFromNodeModulesFolder ( module Name , directory , failedLookupLocations , state ) ;
if ( packageResult && hasTypeScriptFileExtension ( packageResult ) ) {
// Always prefer a TypeScript (.ts, .tsx, .d.ts) file shipped with the package
return packageResult ;
}
else {
// Else prefer a types package over non-TypeScript results (e.g. JavaScript files)
const typesResult = loadModuleFromNodeModulesFolder ( combinePaths ( "@types" , module Name ) , directory , failedLookupLocations , state ) ;
if ( typesResult || packageResult ) {
return typesResult || packageResult ;
}
2015-08-18 03:31:12 +02:00
}
}
2015-10-01 01:10:52 +02:00
2015-11-04 23:02:33 +01:00
const parentPath = getDirectoryPath ( directory ) ;
2015-08-18 03:31:12 +02:00
if ( parentPath === directory ) {
break ;
}
2015-10-01 01:10:52 +02:00
2015-08-18 03:31:12 +02:00
directory = parentPath ;
}
2016-01-25 20:49:26 +01:00
return undefined ;
2015-08-18 03:31:12 +02:00
}
2015-07-14 02:44:50 +02:00
2015-09-10 20:36:31 +02:00
export function classicNameResolver ( module Name : string , containingFile : string , compilerOptions : CompilerOptions , host : ModuleResolutionHost ) : ResolvedModuleWithFailedLookupLocations {
2015-11-20 06:33:33 +01:00
const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
2016-02-02 00:19:13 +01:00
const state = { compilerOptions , host , traceEnabled , skipTsx : ! compilerOptions . jsx } ;
2016-01-25 20:49:26 +01:00
const failedLookupLocations : string [ ] = [ ] ;
const supportedExtensions = getSupportedExtensions ( compilerOptions ) ;
let containingDirectory = getDirectoryPath ( containingFile ) ;
2015-10-01 01:10:52 +02:00
2016-01-25 20:49:26 +01:00
const resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings ( module Name , containingDirectory , loadModuleFromFile , failedLookupLocations , supportedExtensions , state ) ;
if ( resolvedFileName ) {
return createResolvedModule ( resolvedFileName , /*isExternalLibraryImport*/ false , failedLookupLocations ) ;
2015-07-30 01:24:16 +02:00
}
2015-10-01 01:10:52 +02:00
2015-07-14 02:44:50 +02:00
let referencedSourceFile : string ;
2016-02-13 01:30:19 +01:00
if ( module HasNonRelativeName ( module Name ) ) {
while ( true ) {
const searchName = normalizePath ( combinePaths ( containingDirectory , module Name ) ) ;
referencedSourceFile = loadModuleFromFile ( searchName , supportedExtensions , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
if ( referencedSourceFile ) {
break ;
}
const parentPath = getDirectoryPath ( containingDirectory ) ;
if ( parentPath === containingDirectory ) {
break ;
}
containingDirectory = parentPath ;
2015-07-14 02:44:50 +02:00
}
}
2016-02-13 01:30:19 +01:00
else {
const candidate = normalizePath ( combinePaths ( containingDirectory , module Name ) ) ;
referencedSourceFile = loadModuleFromFile ( candidate , supportedExtensions , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
}
2015-07-14 02:44:50 +02:00
2015-09-10 20:36:31 +02:00
return referencedSourceFile
2016-02-23 21:48:31 +01:00
? { resolvedModule : { resolvedFileName : referencedSourceFile } , failedLookupLocations }
2015-09-10 20:36:31 +02:00
: { resolvedModule : undefined , failedLookupLocations } ;
2015-07-14 02:44:50 +02:00
}
2015-03-24 22:03:21 +01:00
2015-08-25 23:34:34 +02:00
/* @internal */
2015-07-29 04:26:18 +02:00
export const defaultInitCompilerOptions : CompilerOptions = {
module : ModuleKind.CommonJS ,
2015-11-04 18:08:33 +01:00
target : ScriptTarget.ES5 ,
2015-07-29 04:26:18 +02:00
noImplicitAny : false ,
sourceMap : false ,
2015-08-26 02:42:39 +02:00
} ;
2015-07-27 13:52:57 +02:00
2016-02-09 15:23:43 +01:00
interface OutputFingerprint {
hash : string ;
byteOrderMark : boolean ;
mtime : Date ;
}
2015-03-18 22:11:50 +01:00
export function createCompilerHost ( options : CompilerOptions , setParentNodes? : boolean ) : CompilerHost {
2016-08-11 01:47:06 +02:00
const existingDirectories = createMap < boolean > ( ) ;
2014-12-16 22:14:14 +01:00
function getCanonicalFileName ( fileName : string ) : string {
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
// otherwise use toLowerCase as a canonical form.
return sys . useCaseSensitiveFileNames ? fileName : fileName.toLowerCase ( ) ;
}
2015-06-26 01:24:41 +02:00
2014-12-16 22:14:14 +01:00
// returned by CScript sys environment
2015-11-04 23:02:33 +01:00
const unsupportedFileEncodingErrorCode = - 2147024809 ;
2014-12-16 22:14:14 +01:00
2015-02-04 01:08:46 +01:00
function getSourceFile ( fileName : string , languageVersion : ScriptTarget , onError ? : ( message : string ) = > void ) : SourceFile {
2015-03-13 23:03:17 +01:00
let text : string ;
2014-12-16 22:14:14 +01:00
try {
2016-08-15 20:07:49 +02:00
performance . mark ( "beforeIORead" ) ;
2015-03-13 23:03:17 +01:00
text = sys . readFile ( fileName , options . charset ) ;
2016-08-15 20:07:49 +02:00
performance . mark ( "afterIORead" ) ;
performance . measure ( "I/O Read" , "beforeIORead" , "afterIORead" ) ;
2014-12-16 22:14:14 +01:00
}
catch ( e ) {
if ( onError ) {
2015-02-05 08:20:26 +01:00
onError ( e . number === unsupportedFileEncodingErrorCode
? createCompilerDiagnostic ( Diagnostics . Unsupported_file_encoding ) . messageText
: e . message ) ;
2014-12-16 22:14:14 +01:00
}
text = "" ;
}
2015-04-12 23:02:58 +02:00
2015-03-18 22:11:50 +01:00
return text !== undefined ? createSourceFile ( fileName , text , languageVersion , setParentNodes ) : undefined ;
2014-12-16 22:14:14 +01:00
}
2015-03-13 22:49:32 +01:00
function directoryExists ( directoryPath : string ) : boolean {
if ( hasProperty ( existingDirectories , directoryPath ) ) {
return true ;
2014-12-16 22:14:14 +01:00
}
2015-03-13 22:49:32 +01:00
if ( sys . directoryExists ( directoryPath ) ) {
existingDirectories [ directoryPath ] = true ;
return true ;
2014-12-16 22:14:14 +01:00
}
2015-03-13 22:49:32 +01:00
return false ;
}
2014-12-16 22:14:14 +01:00
2015-03-13 22:49:32 +01:00
function ensureDirectoriesExist ( directoryPath : string ) {
if ( directoryPath . length > getRootLength ( directoryPath ) && ! directoryExists ( directoryPath ) ) {
2015-11-04 23:02:33 +01:00
const parentDirectory = getDirectoryPath ( directoryPath ) ;
2015-03-13 22:49:32 +01:00
ensureDirectoriesExist ( parentDirectory ) ;
sys . createDirectory ( directoryPath ) ;
2014-12-16 22:14:14 +01:00
}
2015-03-13 22:49:32 +01:00
}
2014-12-16 22:14:14 +01:00
2016-02-11 09:38:21 +01:00
let outputFingerprints : Map < OutputFingerprint > ;
function writeFileIfUpdated ( fileName : string , data : string , writeByteOrderMark : boolean ) : void {
if ( ! outputFingerprints ) {
2016-08-11 01:47:06 +02:00
outputFingerprints = createMap < OutputFingerprint > ( ) ;
2016-02-11 09:38:21 +01:00
}
const hash = sys . createHash ( data ) ;
const mtimeBefore = sys . getModifiedTime ( fileName ) ;
if ( mtimeBefore && hasProperty ( outputFingerprints , fileName ) ) {
const fingerprint = outputFingerprints [ fileName ] ;
// If output has not been changed, and the file has no external modification
if ( fingerprint . byteOrderMark === writeByteOrderMark &&
fingerprint . hash === hash &&
fingerprint . mtime . getTime ( ) === mtimeBefore . getTime ( ) ) {
return ;
2016-02-09 15:23:43 +01:00
}
2016-02-11 09:38:21 +01:00
}
2016-02-09 15:23:43 +01:00
2016-02-11 09:38:21 +01:00
sys . writeFile ( fileName , data , writeByteOrderMark ) ;
2016-02-09 15:23:43 +01:00
2016-02-11 09:38:21 +01:00
const mtimeAfter = sys . getModifiedTime ( fileName ) ;
2016-02-09 15:23:43 +01:00
2016-02-11 09:38:21 +01:00
outputFingerprints [ fileName ] = {
hash ,
byteOrderMark : writeByteOrderMark ,
mtime : mtimeAfter
} ;
}
2016-02-09 15:23:43 +01:00
2015-03-13 22:49:32 +01:00
function writeFile ( fileName : string , data : string , writeByteOrderMark : boolean , onError ? : ( message : string ) = > void ) {
2014-12-16 22:14:14 +01:00
try {
2016-08-15 20:07:49 +02:00
performance . mark ( "beforeIOWrite" ) ;
2014-12-16 22:14:14 +01:00
ensureDirectoriesExist ( getDirectoryPath ( normalizePath ( fileName ) ) ) ;
2016-02-11 09:38:21 +01:00
2016-04-04 23:51:16 +02:00
if ( isWatchSet ( options ) && sys . createHash && sys . getModifiedTime ) {
2016-02-11 09:38:21 +01:00
writeFileIfUpdated ( fileName , data , writeByteOrderMark ) ;
}
else {
sys . writeFile ( fileName , data , writeByteOrderMark ) ;
}
2016-08-15 20:07:49 +02:00
performance . mark ( "afterIOWrite" ) ;
performance . measure ( "I/O Write" , "beforeIOWrite" , "afterIOWrite" ) ;
2014-12-16 22:14:14 +01:00
}
catch ( e ) {
if ( onError ) {
onError ( e . message ) ;
}
}
}
2016-03-29 01:24:16 +02:00
function getDefaultLibLocation ( ) : string {
return getDirectoryPath ( normalizePath ( sys . getExecutingFilePath ( ) ) ) ;
2016-03-28 23:20:29 +02:00
}
2015-05-27 05:18:13 +02:00
const newLine = getNewLineCharacter ( options ) ;
2016-05-05 22:38:09 +02:00
const realpath = sys . realpath && ( ( path : string ) = > sys . realpath ( path ) ) ;
2015-10-01 01:10:52 +02:00
2014-12-16 22:14:14 +01:00
return {
getSourceFile ,
2016-03-29 01:24:16 +02:00
getDefaultLibLocation ,
2016-03-30 19:26:39 +02:00
getDefaultLibFileName : options = > combinePaths ( getDefaultLibLocation ( ) , getDefaultLibFileName ( options ) ) ,
2014-12-16 22:14:14 +01:00
writeFile ,
2015-10-15 23:43:51 +02:00
getCurrentDirectory : memoize ( ( ) = > sys . getCurrentDirectory ( ) ) ,
2014-12-16 22:14:14 +01:00
useCaseSensitiveFileNames : ( ) = > sys . useCaseSensitiveFileNames ,
getCanonicalFileName ,
2015-07-14 02:44:50 +02:00
getNewLine : ( ) = > newLine ,
2015-08-05 06:22:37 +02:00
fileExists : fileName = > sys . fileExists ( fileName ) ,
2016-01-06 21:37:52 +01:00
readFile : fileName = > sys . readFile ( fileName ) ,
2016-01-06 23:16:56 +01:00
trace : ( s : string ) = > sys . write ( s + newLine ) ,
2016-05-05 22:38:09 +02:00
directoryExists : directoryName = > sys . directoryExists ( directoryName ) ,
2016-06-11 00:44:11 +02:00
getDirectories : ( path : string ) = > sys . getDirectories ( path ) ,
2016-05-05 22:38:09 +02:00
realpath
2014-12-16 22:14:14 +01:00
} ;
}
2015-06-18 21:04:26 +02:00
export function getPreEmitDiagnostics ( program : Program , sourceFile? : SourceFile , cancellationToken? : CancellationToken ) : Diagnostic [ ] {
2015-11-06 21:39:42 +01:00
let diagnostics = program . getOptionsDiagnostics ( cancellationToken ) . concat (
2016-02-23 21:48:31 +01:00
program . getSyntacticDiagnostics ( sourceFile , cancellationToken ) ,
program . getGlobalDiagnostics ( cancellationToken ) ,
program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ) ;
2015-03-20 00:55:07 +01:00
if ( program . getCompilerOptions ( ) . declaration ) {
2015-10-21 00:51:37 +02:00
diagnostics = diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile , cancellationToken ) ) ;
2015-03-20 00:55:07 +01:00
}
2015-02-05 10:47:29 +01:00
return sortAndDeduplicateDiagnostics ( diagnostics ) ;
}
2016-07-15 08:02:56 +02:00
export interface FormatDiagnosticsHost {
getCurrentDirectory ( ) : string ;
getCanonicalFileName ( fileName : string ) : string ;
getNewLine ( ) : string ;
}
export function formatDiagnostics ( diagnostics : Diagnostic [ ] , host : FormatDiagnosticsHost ) : string {
2016-07-13 18:13:55 +02:00
let output = "" ;
for ( const diagnostic of diagnostics ) {
if ( diagnostic . file ) {
const { line , character } = getLineAndCharacterOfPosition ( diagnostic . file , diagnostic . start ) ;
const fileName = diagnostic . file . fileName ;
const relativeFileName = convertToRelativePath ( fileName , host . getCurrentDirectory ( ) , fileName = > host . getCanonicalFileName ( fileName ) ) ;
output += ` ${ relativeFileName } ( ${ line + 1 } , ${ character + 1 } ): ` ;
}
const category = DiagnosticCategory [ diagnostic . category ] . toLowerCase ( ) ;
2016-07-14 00:25:15 +02:00
output += ` ${ category } TS ${ diagnostic . code } : ${ flattenDiagnosticMessageText ( diagnostic . messageText , host . getNewLine ( ) ) } ${ host . getNewLine ( ) } ` ;
2016-07-13 18:13:55 +02:00
}
return output ;
}
2015-02-05 10:47:29 +01:00
export function flattenDiagnosticMessageText ( messageText : string | DiagnosticMessageChain , newLine : string ) : string {
if ( typeof messageText === "string" ) {
return messageText ;
}
else {
2015-03-13 23:03:17 +01:00
let diagnosticChain = messageText ;
let result = "" ;
2015-02-05 10:47:29 +01:00
2015-03-13 23:03:17 +01:00
let indent = 0 ;
2015-02-05 10:47:29 +01:00
while ( diagnosticChain ) {
if ( indent ) {
result += newLine ;
2015-03-13 23:03:17 +01:00
for ( let i = 0 ; i < indent ; i ++ ) {
2015-02-05 10:47:29 +01:00
result += " " ;
}
}
result += diagnosticChain . messageText ;
indent ++ ;
diagnosticChain = diagnosticChain . next ;
}
return result ;
}
}
2016-04-01 21:41:01 +02:00
function loadWithLocalCache < T > ( names : string [ ] , containingFile : string , loader : ( name : string , containingFile : string ) = > T ) : T [ ] {
if ( names . length === 0 ) {
return [ ] ;
}
const resolutions : T [ ] = [ ] ;
2016-08-11 01:47:06 +02:00
const cache = createMap < T > ( ) ;
2016-04-01 21:41:01 +02:00
for ( const name of names ) {
let result : T ;
if ( hasProperty ( cache , name ) ) {
result = cache [ name ] ;
}
else {
result = loader ( name , containingFile ) ;
cache [ name ] = result ;
}
resolutions . push ( result ) ;
}
return resolutions ;
}
2016-06-11 00:44:11 +02:00
/ * *
2016-08-04 16:43:54 +02:00
* Given a set of options , returns the set of type directive names
2016-06-11 00:44:11 +02:00
* that should be included for this program automatically .
* This list could either come from the config file ,
* or from enumerating the types root + initial secondary types lookup location .
* More type directives might appear in the program later as a result of loading actual source files ;
* this list is only the set of defaults that are implicitly included .
* /
2016-08-04 16:43:54 +02:00
export function getAutomaticTypeDirectiveNames ( options : CompilerOptions , host : ModuleResolutionHost ) : string [ ] {
2016-05-23 23:51:39 +02:00
// Use explicit type list from tsconfig.json
if ( options . types ) {
return options . types ;
}
2016-06-11 00:44:11 +02:00
// Walk the primary type lookup locations
2016-08-11 21:26:22 +02:00
const result : string [ ] = [ ] ;
2016-06-11 00:44:11 +02:00
if ( host . directoryExists && host . getDirectories ) {
2016-06-13 23:37:07 +02:00
const typeRoots = getEffectiveTypeRoots ( options , host ) ;
2016-06-28 21:10:26 +02:00
if ( typeRoots ) {
for ( const root of typeRoots ) {
if ( host . directoryExists ( root ) ) {
2016-08-04 16:43:54 +02:00
for ( const typeDirectivePath of host . getDirectories ( root ) ) {
2016-08-11 21:26:22 +02:00
const normalized = normalizePath ( typeDirectivePath ) ;
const packageJsonPath = pathToPackageJson ( combinePaths ( root , normalized ) ) ;
// tslint:disable-next-line:no-null-keyword
const isNotNeededPackage = host . fileExists ( packageJsonPath ) && readJson ( packageJsonPath , host ) . typings === null ;
if ( ! isNotNeededPackage ) {
// Return just the type directive names
result . push ( getBaseFileName ( normalized ) ) ;
}
2016-08-04 16:43:54 +02:00
}
2016-06-28 21:10:26 +02:00
}
2016-06-11 00:44:11 +02:00
}
2016-05-23 23:51:39 +02:00
}
}
2016-06-11 00:44:11 +02:00
return result ;
2016-05-23 23:51:39 +02:00
}
2015-06-23 02:48:44 +02:00
export function createProgram ( rootNames : string [ ] , options : CompilerOptions , host? : CompilerHost , oldProgram? : Program ) : Program {
2015-03-13 23:03:17 +01:00
let program : Program ;
let files : SourceFile [ ] = [ ] ;
2015-11-18 23:10:53 +01:00
let commonSourceDirectory : string ;
2015-03-17 14:26:24 +01:00
let diagnosticsProducingTypeChecker : TypeChecker ;
let noDiagnosticsTypeChecker : TypeChecker ;
2015-06-12 21:53:24 +02:00
let classifiableNames : Map < string > ;
2014-12-16 22:14:14 +01:00
2016-08-11 01:47:06 +02:00
let resolvedTypeReferenceDirectives = createMap < ResolvedTypeReferenceDirective > ( ) ;
2016-04-01 21:41:01 +02:00
let fileProcessingDiagnostics = createDiagnosticCollection ( ) ;
2015-05-01 03:14:53 +02:00
2016-06-21 22:42:02 +02:00
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
// This works as imported modules are discovered recursively in a depth first manner, specifically:
// - For each root file, findSourceFile is called.
// - This calls processImportedModules for each module imported in the source file.
// - This calls resolveModuleNames, and then calls findSourceFile for each resolved module.
// As all these operations happen - and are nested - within the createProgram call, they close over the below variables.
// The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses.
2016-06-27 05:48:22 +02:00
const maxNodeModulesJsDepth = typeof options . maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth : 2 ;
2016-07-11 01:11:42 +02:00
let currentNodeModulesDepth = 0 ;
2016-06-21 22:42:02 +02:00
2016-06-27 05:48:22 +02:00
// If a module has some of its imports skipped due to being at the depth limit under node_modules, then track
// this, as it may be imported at a shallower depth later, and then it will need its skipped imports processed.
2016-08-11 01:47:06 +02:00
const module sWithElidedImports = createMap < boolean > ( ) ;
2016-06-27 05:48:22 +02:00
2016-07-11 01:11:42 +02:00
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
2016-08-11 01:47:06 +02:00
const sourceFilesFoundSearchingNodeModules = createMap < boolean > ( ) ;
2016-06-27 05:48:22 +02:00
2016-08-15 20:07:49 +02:00
performance . mark ( "beforeProgram" ) ;
2014-12-16 22:14:14 +01:00
2015-03-17 14:26:24 +01:00
host = host || createCompilerHost ( options ) ;
2016-04-01 21:41:01 +02:00
2016-04-11 05:42:22 +02:00
let skipDefaultLib = options . noLib ;
const programDiagnostics = createDiagnosticCollection ( ) ;
const currentDirectory = host . getCurrentDirectory ( ) ;
const supportedExtensions = getSupportedExtensions ( options ) ;
2015-10-30 23:54:31 +01:00
// Map storing if there is emit blocking diagnostics for given input
2015-11-18 19:48:03 +01:00
const hasEmitBlockingDiagnostics = createFileMap < boolean > ( getCanonicalFileName ) ;
2015-10-01 01:10:52 +02:00
2016-04-01 21:41:01 +02:00
let resolveModuleNamesWorker : ( module Names : string [ ] , containingFile : string ) = > ResolvedModule [ ] ;
if ( host . resolveModuleNames ) {
resolveModuleNamesWorker = ( module Names , containingFile ) = > host . resolveModuleNames ( module Names , containingFile ) ;
}
else {
const loader = ( module Name : string , containingFile : string ) = > resolveModuleName ( module Name , containingFile , options , host ) . resolvedModule ;
resolveModuleNamesWorker = ( module Names , containingFile ) = > loadWithLocalCache ( module Names , containingFile , loader ) ;
}
let resolveTypeReferenceDirectiveNamesWorker : ( typeDirectiveNames : string [ ] , containingFile : string ) = > ResolvedTypeReferenceDirective [ ] ;
if ( host . resolveTypeReferenceDirectives ) {
resolveTypeReferenceDirectiveNamesWorker = ( typeDirectiveNames , containingFile ) = > host . resolveTypeReferenceDirectives ( typeDirectiveNames , containingFile ) ;
}
else {
2016-04-06 01:33:11 +02:00
const loader = ( typesRef : string , containingFile : string ) = > resolveTypeReferenceDirective ( typesRef , containingFile , options , host ) . resolvedTypeReferenceDirective ;
2016-04-01 21:41:01 +02:00
resolveTypeReferenceDirectiveNamesWorker = ( typeReferenceDirectiveNames , containingFile ) = > loadWithLocalCache ( typeReferenceDirectiveNames , containingFile , loader ) ;
}
2015-05-01 03:14:53 +02:00
2015-11-04 23:02:33 +01:00
const filesByName = createFileMap < SourceFile > ( ) ;
2015-10-15 23:43:51 +02:00
// stores 'filename -> file association' ignoring case
2016-01-30 20:37:02 +01:00
// used to track cases when two file names differ only in casing
2015-11-04 23:02:33 +01:00
const filesByNameIgnoreCase = host . useCaseSensitiveFileNames ( ) ? createFileMap < SourceFile > ( fileName = > fileName . toLowerCase ( ) ) : undefined ;
2015-10-01 01:10:52 +02:00
2016-04-06 22:49:25 +02:00
if ( ! tryReuseStructureFromOldProgram ( ) ) {
2016-05-18 20:30:40 +02:00
forEach ( rootNames , name = > processRootFile ( name , /*isDefaultLib*/ false ) ) ;
2016-06-11 00:44:11 +02:00
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
2016-08-04 16:43:54 +02:00
const typeReferences : string [ ] = getAutomaticTypeDirectiveNames ( options , host ) ;
2016-05-18 00:41:31 +02:00
if ( typeReferences ) {
2016-08-04 16:43:54 +02:00
// This containingFilename needs to match with the one used in managed-side
const containingFilename = combinePaths ( host . getCurrentDirectory ( ) , "__inferred type names__.ts" ) ;
2016-06-11 00:44:11 +02:00
const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeReferences , containingFilename ) ;
2016-05-18 00:41:31 +02:00
for ( let i = 0 ; i < typeReferences . length ; i ++ ) {
processTypeReferenceDirective ( typeReferences [ i ] , resolutions [ i ] ) ;
2016-04-06 22:49:25 +02:00
}
2015-06-25 02:40:04 +02:00
}
2015-10-01 01:10:52 +02:00
2015-06-23 02:48:44 +02:00
// Do not process the default library if:
// - The '--noLib' flag is used.
// - A 'no-default-lib' reference comment is encountered in
// processing the root files.
if ( ! skipDefaultLib ) {
2016-03-28 23:20:29 +02:00
// If '--lib' is not specified, include default library file according to '--target'
// otherwise, using options specified in '--lib' instead of '--target' default library file
if ( ! options . lib ) {
processRootFile ( host . getDefaultLibFileName ( options ) , /*isDefaultLib*/ true ) ;
}
else {
2016-03-29 01:24:16 +02:00
const libDirectory = host . getDefaultLibLocation ? host . getDefaultLibLocation ( ) : getDirectoryPath ( host . getDefaultLibFileName ( options ) ) ;
forEach ( options . lib , libFileName = > {
processRootFile ( combinePaths ( libDirectory , libFileName ) , /*isDefaultLib*/ true ) ;
2016-03-28 23:20:29 +02:00
} ) ;
}
2015-06-23 02:48:44 +02:00
}
2014-12-16 22:14:14 +01:00
}
2015-05-01 03:14:53 +02:00
2015-07-09 23:45:39 +02:00
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
oldProgram = undefined ;
2014-12-16 22:14:14 +01:00
program = {
2015-06-23 02:48:44 +02:00
getRootFileNames : ( ) = > rootNames ,
2015-10-29 22:54:56 +01:00
getSourceFile ,
2016-05-11 08:43:26 +02:00
getSourceFileByPath ,
2014-12-16 22:14:14 +01:00
getSourceFiles : ( ) = > files ,
getCompilerOptions : ( ) = > options ,
2015-02-05 10:47:29 +01:00
getSyntacticDiagnostics ,
2015-06-18 18:32:52 +02:00
getOptionsDiagnostics ,
2015-02-04 23:29:25 +01:00
getGlobalDiagnostics ,
2015-02-05 10:47:29 +01:00
getSemanticDiagnostics ,
2015-02-04 23:29:25 +01:00
getDeclarationDiagnostics ,
2014-12-16 22:14:14 +01:00
getTypeChecker ,
2015-06-12 21:53:24 +02:00
getClassifiableNames ,
2015-02-05 01:11:38 +01:00
getDiagnosticsProducingTypeChecker ,
2015-11-19 02:10:22 +01:00
getCommonSourceDirectory ,
2015-02-05 01:53:14 +01:00
emit ,
2015-10-15 23:43:51 +02:00
getCurrentDirectory : ( ) = > currentDirectory ,
2015-02-05 01:11:38 +01:00
getNodeCount : ( ) = > getDiagnosticsProducingTypeChecker ( ) . getNodeCount ( ) ,
getIdentifierCount : ( ) = > getDiagnosticsProducingTypeChecker ( ) . getIdentifierCount ( ) ,
getSymbolCount : ( ) = > getDiagnosticsProducingTypeChecker ( ) . getSymbolCount ( ) ,
getTypeCount : ( ) = > getDiagnosticsProducingTypeChecker ( ) . getTypeCount ( ) ,
2016-04-01 21:41:01 +02:00
getFileProcessingDiagnostics : ( ) = > fileProcessingDiagnostics ,
2016-04-12 06:36:07 +02:00
getResolvedTypeReferenceDirectives : ( ) = > resolvedTypeReferenceDirectives
2014-12-16 22:14:14 +01:00
} ;
2015-10-12 21:25:13 +02:00
verifyCompilerOptions ( ) ;
2016-08-15 20:07:49 +02:00
performance . mark ( "afterProgram" ) ;
performance . measure ( "Program" , "beforeProgram" , "afterProgram" ) ;
2015-10-12 22:10:54 +02:00
2014-12-16 22:14:14 +01:00
return program ;
2015-11-19 02:10:22 +01:00
function getCommonSourceDirectory() {
if ( typeof commonSourceDirectory === "undefined" ) {
if ( options . rootDir && checkSourceFilesBelongToPath ( files , options . rootDir ) ) {
// If a rootDir is specified and is valid use it as the commonSourceDirectory
commonSourceDirectory = getNormalizedAbsolutePath ( options . rootDir , currentDirectory ) ;
}
else {
commonSourceDirectory = computeCommonSourceDirectory ( files ) ;
}
if ( commonSourceDirectory && commonSourceDirectory [ commonSourceDirectory . length - 1 ] !== directorySeparator ) {
// Make sure directory path ends with directory separator so this string can directly
// used to replace with "" to get the relative path of the source file and the relative path doesn't
// start with / making it rooted path
commonSourceDirectory += directorySeparator ;
}
}
return commonSourceDirectory ;
}
2015-06-12 21:53:24 +02:00
function getClassifiableNames() {
if ( ! classifiableNames ) {
2015-06-11 03:18:37 +02:00
// Initialize a checker so that all our files are bound.
getTypeChecker ( ) ;
2016-08-11 01:47:06 +02:00
classifiableNames = createMap < string > ( ) ;
2015-06-11 03:18:37 +02:00
2015-11-04 23:02:33 +01:00
for ( const sourceFile of files ) {
2015-06-12 21:53:24 +02:00
copyMap ( sourceFile . classifiableNames , classifiableNames ) ;
2015-06-11 03:18:37 +02:00
}
}
2015-06-12 21:53:24 +02:00
return classifiableNames ;
2015-06-11 03:18:37 +02:00
}
2015-06-23 02:48:44 +02:00
function tryReuseStructureFromOldProgram ( ) : boolean {
if ( ! oldProgram ) {
return false ;
}
2015-10-01 01:10:52 +02:00
2016-04-06 22:49:25 +02:00
// check properties that can affect structure of the program or module resolution strategy
// if any of these properties has changed - structure cannot be reused
const oldOptions = oldProgram . getCompilerOptions ( ) ;
if ( ( oldOptions . module !== options . module ) ||
2016-06-08 00:08:46 +02:00
( oldOptions . module Resolution !== options . module Resolution ) ||
2016-04-06 22:49:25 +02:00
( oldOptions . noResolve !== options . noResolve ) ||
( oldOptions . target !== options . target ) ||
( oldOptions . noLib !== options . noLib ) ||
( oldOptions . jsx !== options . jsx ) ||
( oldOptions . allowJs !== options . allowJs ) ||
( oldOptions . rootDir !== options . rootDir ) ||
2016-05-11 08:43:26 +02:00
( oldOptions . configFilePath !== options . configFilePath ) ||
( oldOptions . baseUrl !== options . baseUrl ) ||
2016-06-27 05:48:22 +02:00
( oldOptions . maxNodeModuleJsDepth !== options . maxNodeModuleJsDepth ) ||
2016-06-13 23:37:07 +02:00
! arrayIsEqualTo ( oldOptions . typeRoots , oldOptions . typeRoots ) ||
2016-05-11 08:43:26 +02:00
! arrayIsEqualTo ( oldOptions . rootDirs , options . rootDirs ) ||
! mapIsEqualTo ( oldOptions . paths , options . paths ) ) {
2016-04-06 22:49:25 +02:00
return false ;
}
2015-06-24 06:06:57 +02:00
Debug . assert ( ! oldProgram . structureIsReused ) ;
2015-06-23 02:48:44 +02:00
// there is an old program, check if we can reuse its structure
2015-11-04 23:02:33 +01:00
const oldRootNames = oldProgram . getRootFileNames ( ) ;
2015-06-25 02:40:04 +02:00
if ( ! arrayIsEqualTo ( oldRootNames , rootNames ) ) {
2015-06-23 02:48:44 +02:00
return false ;
}
2015-10-01 01:10:52 +02:00
2016-04-06 22:49:25 +02:00
if ( ! arrayIsEqualTo ( options . types , oldOptions . types ) ) {
return false ;
}
2015-06-23 02:48:44 +02:00
// check if program source files has changed in the way that can affect structure of the program
2015-11-04 23:02:33 +01:00
const newSourceFiles : SourceFile [ ] = [ ] ;
const filePaths : Path [ ] = [ ] ;
const modifiedSourceFiles : SourceFile [ ] = [ ] ;
2015-10-15 23:43:51 +02:00
2015-11-04 23:02:33 +01:00
for ( const oldSourceFile of oldProgram . getSourceFiles ( ) ) {
2016-05-11 08:43:26 +02:00
let newSourceFile = host . getSourceFileByPath
? host . getSourceFileByPath ( oldSourceFile . fileName , oldSourceFile . path , options . target )
: host . getSourceFile ( oldSourceFile . fileName , options . target ) ;
2015-06-25 02:40:04 +02:00
if ( ! newSourceFile ) {
return false ;
}
2015-10-29 22:54:56 +01:00
newSourceFile . path = oldSourceFile . path ;
filePaths . push ( newSourceFile . path ) ;
2015-10-15 23:43:51 +02:00
2015-10-01 01:10:52 +02:00
if ( oldSourceFile !== newSourceFile ) {
2015-07-09 23:40:33 +02:00
if ( oldSourceFile . hasNoDefaultLib !== newSourceFile . hasNoDefaultLib ) {
// value of no-default-lib has changed
// this will affect if default library is injected into the list of files
return false ;
}
2015-06-23 02:48:44 +02:00
// check tripleslash references
if ( ! arrayIsEqualTo ( oldSourceFile . referencedFiles , newSourceFile . referencedFiles , fileReferenceIsEqualTo ) ) {
// tripleslash references has changed
return false ;
}
2015-10-01 01:10:52 +02:00
2015-12-22 22:21:51 +01:00
// check imports and module augmentations
2015-08-20 00:37:37 +02:00
collectExternalModuleReferences ( newSourceFile ) ;
2015-06-23 02:48:44 +02:00
if ( ! arrayIsEqualTo ( oldSourceFile . imports , newSourceFile . imports , module NameIsEqualTo ) ) {
// imports has changed
return false ;
}
2015-12-22 22:21:51 +01:00
if ( ! arrayIsEqualTo ( oldSourceFile . module Augmentations , newSourceFile . module Augmentations , module NameIsEqualTo ) ) {
// moduleAugmentations has changed
return false ;
}
2015-10-01 01:10:52 +02:00
2016-04-01 21:41:01 +02:00
if ( ! arrayIsEqualTo ( oldSourceFile . typeReferenceDirectives , newSourceFile . typeReferenceDirectives , fileReferenceIsEqualTo ) ) {
// 'types' references has changed
return false ;
}
const newSourceFilePath = getNormalizedAbsolutePath ( newSourceFile . fileName , currentDirectory ) ;
2015-08-04 02:42:29 +02:00
if ( resolveModuleNamesWorker ) {
2016-01-14 19:56:49 +01:00
const module Names = map ( concatenate ( newSourceFile . imports , newSourceFile . module Augmentations ) , getTextOfLiteral ) ;
2016-04-01 21:41:01 +02:00
const resolutions = resolveModuleNamesWorker ( module Names , newSourceFilePath ) ;
2015-08-03 20:06:23 +02:00
// ensure that module resolution results are still correct
2016-04-01 21:41:01 +02:00
const resolutionsChanged = hasChangesInResolutions ( module Names , resolutions , oldSourceFile . resolvedModules , module ResolutionIsEqualTo ) ;
if ( resolutionsChanged ) {
return false ;
}
}
if ( resolveTypeReferenceDirectiveNamesWorker ) {
const typesReferenceDirectives = map ( newSourceFile . typeReferenceDirectives , x = > x . fileName ) ;
const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typesReferenceDirectives , newSourceFilePath ) ;
// ensure that types resolutions are still correct
const resolutionsChanged = hasChangesInResolutions ( typesReferenceDirectives , resolutions , oldSourceFile . resolvedTypeReferenceDirectiveNames , typeDirectiveIsEqualTo ) ;
if ( resolutionsChanged ) {
return false ;
2015-08-04 02:42:29 +02:00
}
2015-08-03 20:06:23 +02:00
}
2016-04-01 21:41:01 +02:00
// pass the cache of module/types resolutions from the old source file
2015-06-24 06:06:57 +02:00
newSourceFile . resolvedModules = oldSourceFile . resolvedModules ;
2016-04-01 21:41:01 +02:00
newSourceFile . resolvedTypeReferenceDirectiveNames = oldSourceFile . resolvedTypeReferenceDirectiveNames ;
2015-09-10 19:46:39 +02:00
modifiedSourceFiles . push ( newSourceFile ) ;
2015-06-23 02:48:44 +02:00
}
else {
// file has no changes - use it as is
newSourceFile = oldSourceFile ;
}
2015-10-01 01:10:52 +02:00
2015-06-23 02:48:44 +02:00
// if file has passed all checks it should be safe to reuse it
newSourceFiles . push ( newSourceFile ) ;
}
2015-10-01 01:10:52 +02:00
2015-06-23 02:48:44 +02:00
// update fileName -> file mapping
2015-12-23 00:45:00 +01:00
for ( let i = 0 , len = newSourceFiles . length ; i < len ; i ++ ) {
2015-10-30 00:43:12 +01:00
filesByName . set ( filePaths [ i ] , newSourceFiles [ i ] ) ;
2015-06-23 02:48:44 +02:00
}
2015-10-01 01:10:52 +02:00
2015-06-23 02:48:44 +02:00
files = newSourceFiles ;
2015-09-10 19:46:39 +02:00
fileProcessingDiagnostics = oldProgram . getFileProcessingDiagnostics ( ) ;
2015-10-01 01:10:52 +02:00
2015-11-04 23:02:33 +01:00
for ( const modifiedFile of modifiedSourceFiles ) {
2015-09-10 19:46:39 +02:00
fileProcessingDiagnostics . reattachFileDiagnostics ( modifiedFile ) ;
}
2016-04-12 06:36:07 +02:00
resolvedTypeReferenceDirectives = oldProgram . getResolvedTypeReferenceDirectives ( ) ;
2015-06-24 06:06:57 +02:00
oldProgram . structureIsReused = true ;
2015-10-01 01:10:52 +02:00
2015-06-23 02:48:44 +02:00
return true ;
}
2015-02-05 10:47:29 +01:00
function getEmitHost ( writeFileCallback? : WriteFileCallback ) : EmitHost {
2015-02-05 01:53:14 +01:00
return {
2015-10-15 23:43:51 +02:00
getCanonicalFileName ,
2015-02-05 01:53:14 +01:00
getCommonSourceDirectory : program.getCommonSourceDirectory ,
getCompilerOptions : program.getCompilerOptions ,
2015-10-15 23:43:51 +02:00
getCurrentDirectory : ( ) = > currentDirectory ,
2015-03-24 18:05:24 +01:00
getNewLine : ( ) = > host . getNewLine ( ) ,
2015-02-05 01:53:14 +01:00
getSourceFile : program.getSourceFile ,
2016-05-11 08:43:26 +02:00
getSourceFileByPath : program.getSourceFileByPath ,
2015-02-05 01:53:14 +01:00
getSourceFiles : program.getSourceFiles ,
2016-06-30 02:05:55 +02:00
isSourceFileFromExternalLibrary : ( file : SourceFile ) = > ! ! lookUp ( sourceFilesFoundSearchingNodeModules , file . path ) ,
2015-03-24 18:05:24 +01:00
writeFile : writeFileCallback || (
2016-03-15 21:25:18 +01:00
( fileName , data , writeByteOrderMark , onError , sourceFiles ) = > host . writeFile ( fileName , data , writeByteOrderMark , onError , sourceFiles ) ) ,
2015-10-20 20:22:46 +02:00
isEmitBlocked ,
2015-02-05 01:53:14 +01:00
} ;
2014-12-16 23:42:58 +01:00
}
2014-12-16 23:12:17 +01:00
function getDiagnosticsProducingTypeChecker() {
return diagnosticsProducingTypeChecker || ( diagnosticsProducingTypeChecker = createTypeChecker ( program , /*produceDiagnostics:*/ true ) ) ;
}
2015-02-05 01:11:38 +01:00
function getTypeChecker() {
return noDiagnosticsTypeChecker || ( noDiagnosticsTypeChecker = createTypeChecker ( program , /*produceDiagnostics:*/ false ) ) ;
2014-12-16 23:12:17 +01:00
}
2015-06-18 21:04:26 +02:00
function emit ( sourceFile? : SourceFile , writeFileCallback? : WriteFileCallback , cancellationToken? : CancellationToken ) : EmitResult {
2016-07-11 22:49:36 +02:00
return runWithCancellationToken ( ( ) = > emitWorker ( program , sourceFile , writeFileCallback , cancellationToken ) ) ;
2015-06-18 19:52:19 +02:00
}
2015-10-20 20:22:46 +02:00
function isEmitBlocked ( emitFileName : string ) : boolean {
2015-10-30 23:54:31 +01:00
return hasEmitBlockingDiagnostics . contains ( toPath ( emitFileName , currentDirectory , getCanonicalFileName ) ) ;
2015-10-20 20:22:46 +02:00
}
2015-06-18 21:04:26 +02:00
function emitWorker ( program : Program , sourceFile : SourceFile , writeFileCallback : WriteFileCallback , cancellationToken : CancellationToken ) : EmitResult {
2016-02-17 07:01:28 +01:00
let declarationDiagnostics : Diagnostic [ ] = [ ] ;
if ( options . noEmit ) {
2016-04-08 00:29:11 +02:00
return { diagnostics : declarationDiagnostics , sourceMaps : undefined , emittedFiles : undefined , emitSkipped : true } ;
2016-02-17 07:01:28 +01:00
}
2015-02-05 23:41:04 +01:00
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
2015-07-09 00:35:49 +02:00
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
// get any preEmit diagnostics, not just the ones
2015-12-22 06:43:51 +01:00
if ( options . noEmitOnError ) {
2016-02-17 07:57:27 +01:00
const diagnostics = program . getOptionsDiagnostics ( cancellationToken ) . concat (
2016-02-17 07:01:28 +01:00
program . getSyntacticDiagnostics ( sourceFile , cancellationToken ) ,
program . getGlobalDiagnostics ( cancellationToken ) ,
program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ) ;
if ( diagnostics . length === 0 && program . getCompilerOptions ( ) . declaration ) {
declarationDiagnostics = program . getDeclarationDiagnostics ( /*sourceFile*/ undefined , cancellationToken ) ;
}
if ( diagnostics . length > 0 || declarationDiagnostics . length > 0 ) {
2016-03-03 02:13:51 +01:00
return {
diagnostics : concatenate ( diagnostics , declarationDiagnostics ) ,
sourceMaps : undefined ,
2016-04-08 00:29:11 +02:00
emittedFiles : undefined ,
2016-03-03 02:13:51 +01:00
emitSkipped : true
} ;
2015-12-22 06:43:51 +01:00
}
2014-12-16 22:52:47 +01:00
}
2015-02-05 23:41:04 +01:00
2015-02-26 01:45:45 +01:00
// Create the emit resolver outside of the "emitTime" tracking code below. That way
// any cost associated with it (like type checking) are appropriate associated with
// the type-checking counter.
2015-05-08 22:58:20 +02:00
//
// If the -out option is specified, we should not pass the source file to getEmitResolver.
// This is because in the -out scenario all files need to be emitted, and therefore all
// files need to be type checked. And the way to specify that all files need to be type
// checked is to not pass the file to getEmitResolver.
2015-11-04 23:02:33 +01:00
const emitResolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( ( options . outFile || options . out ) ? undefined : sourceFile ) ;
2015-02-26 01:45:45 +01:00
2016-08-15 20:07:49 +02:00
performance . mark ( "beforeEmit" ) ;
2015-02-05 03:42:44 +01:00
2015-11-04 23:02:33 +01:00
const emitResult = emitFiles (
2015-02-26 01:45:45 +01:00
emitResolver ,
2015-02-05 23:41:04 +01:00
getEmitHost ( writeFileCallback ) ,
sourceFile ) ;
2015-02-05 03:42:44 +01:00
2016-08-15 20:07:49 +02:00
performance . mark ( "afterEmit" ) ;
performance . measure ( "Emit" , "beforeEmit" , "afterEmit" ) ;
2015-02-06 00:50:18 +01:00
return emitResult ;
2015-01-15 22:22:23 +01:00
}
2015-02-06 00:50:18 +01:00
2015-10-15 23:43:51 +02:00
function getSourceFile ( fileName : string ) : SourceFile {
2016-05-11 08:43:26 +02:00
return getSourceFileByPath ( toPath ( fileName , currentDirectory , getCanonicalFileName ) ) ;
}
function getSourceFileByPath ( path : Path ) : SourceFile {
return filesByName . get ( path ) ;
2014-12-16 22:14:14 +01:00
}
2015-06-18 19:52:19 +02:00
function getDiagnosticsHelper (
2016-02-23 21:48:31 +01:00
sourceFile : SourceFile ,
getDiagnostics : ( sourceFile : SourceFile , cancellationToken : CancellationToken ) = > Diagnostic [ ] ,
cancellationToken : CancellationToken ) : Diagnostic [ ] {
2015-02-05 10:47:29 +01:00
if ( sourceFile ) {
2015-06-18 19:52:19 +02:00
return getDiagnostics ( sourceFile , cancellationToken ) ;
2014-12-16 22:52:47 +01:00
}
2015-02-05 10:47:29 +01:00
2015-11-04 23:02:33 +01:00
const allDiagnostics : Diagnostic [ ] = [ ] ;
2015-02-05 10:47:29 +01:00
forEach ( program . getSourceFiles ( ) , sourceFile = > {
2015-06-18 19:52:19 +02:00
if ( cancellationToken ) {
cancellationToken . throwIfCancellationRequested ( ) ;
}
addRange ( allDiagnostics , getDiagnostics ( sourceFile , cancellationToken ) ) ;
2015-02-05 10:47:29 +01:00
} ) ;
return sortAndDeduplicateDiagnostics ( allDiagnostics ) ;
2014-12-16 22:52:47 +01:00
}
2015-06-18 21:04:26 +02:00
function getSyntacticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
2015-06-18 19:52:19 +02:00
return getDiagnosticsHelper ( sourceFile , getSyntacticDiagnosticsForFile , cancellationToken ) ;
2014-12-16 22:14:14 +01:00
}
2015-06-18 21:04:26 +02:00
function getSemanticDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
2015-06-18 19:52:19 +02:00
return getDiagnosticsHelper ( sourceFile , getSemanticDiagnosticsForFile , cancellationToken ) ;
2015-01-15 22:22:23 +01:00
}
2015-02-05 11:15:38 +01:00
2015-06-18 21:04:26 +02:00
function getDeclarationDiagnostics ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
2016-02-24 23:21:30 +01:00
const options = program . getCompilerOptions ( ) ;
2016-02-24 23:30:21 +01:00
// collect diagnostics from the program only once if either no source file was specified or out/outFile is set (bundled emit)
2016-02-24 23:21:30 +01:00
if ( ! sourceFile || options . out || options . outFile ) {
return getDeclarationDiagnosticsWorker ( sourceFile , cancellationToken ) ;
}
else {
return getDiagnosticsHelper ( sourceFile , getDeclarationDiagnosticsForFile , cancellationToken ) ;
}
2015-03-20 00:55:07 +01:00
}
2015-06-18 21:04:26 +02:00
function getSyntacticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
2015-02-05 22:38:11 +01:00
return sourceFile . parseDiagnostics ;
2014-12-16 22:14:14 +01:00
}
2015-06-18 19:52:19 +02:00
function runWithCancellationToken < T > ( func : ( ) = > T ) : T {
try {
return func ( ) ;
}
catch ( e ) {
if ( e instanceof OperationCanceledException ) {
2015-07-09 00:35:49 +02:00
// We were canceled while performing the operation. Because our type checker
2015-06-18 19:52:19 +02:00
// might be a bad state, we need to throw it away.
2015-07-07 00:31:22 +02:00
//
2016-02-11 17:56:45 +01:00
// Note: we are overly aggressive here. We do not actually *have* to throw away
2015-07-07 00:31:22 +02:00
// the "noDiagnosticsTypeChecker". However, for simplicity, i'd like to keep
// the lifetimes of these two TypeCheckers the same. Also, we generally only
// cancel when the user has made a change anyways. And, in that case, we (the
2015-07-09 00:35:49 +02:00
// program instance) will get thrown away anyways. So trying to keep one of
2015-07-07 00:31:22 +02:00
// these type checkers alive doesn't serve much purpose.
2015-06-18 19:52:19 +02:00
noDiagnosticsTypeChecker = undefined ;
diagnosticsProducingTypeChecker = undefined ;
}
2015-02-05 10:47:29 +01:00
2015-06-18 19:52:19 +02:00
throw e ;
}
}
2015-02-05 10:47:29 +01:00
2015-06-18 21:04:26 +02:00
function getSemanticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
2015-06-18 19:52:19 +02:00
return runWithCancellationToken ( ( ) = > {
2015-11-04 23:02:33 +01:00
const typeChecker = getDiagnosticsProducingTypeChecker ( ) ;
2015-02-05 10:47:29 +01:00
2015-06-18 19:52:19 +02:00
Debug . assert ( ! ! sourceFile . bindDiagnostics ) ;
2015-11-04 23:02:33 +01:00
const bindDiagnostics = sourceFile . bindDiagnostics ;
2015-11-30 22:26:00 +01:00
// For JavaScript files, we don't want to report the normal typescript semantic errors.
// Instead, we just report errors for using TypeScript-only constructs from within a
// JavaScript file.
const checkDiagnostics = isSourceFileJavaScript ( sourceFile ) ?
getJavaScriptSemanticDiagnosticsForFile ( sourceFile , cancellationToken ) :
typeChecker . getDiagnostics ( sourceFile , cancellationToken ) ;
2015-11-04 23:02:33 +01:00
const fileProcessingDiagnosticsInFile = fileProcessingDiagnostics . getDiagnostics ( sourceFile . fileName ) ;
const programDiagnosticsInFile = programDiagnostics . getDiagnostics ( sourceFile . fileName ) ;
2015-06-18 19:52:19 +02:00
2015-09-10 19:46:39 +02:00
return bindDiagnostics . concat ( checkDiagnostics ) . concat ( fileProcessingDiagnosticsInFile ) . concat ( programDiagnosticsInFile ) ;
2015-06-18 19:52:19 +02:00
} ) ;
2014-12-16 22:14:14 +01:00
}
2015-09-09 23:41:19 +02:00
function getJavaScriptSemanticDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
return runWithCancellationToken ( ( ) = > {
2015-11-06 21:39:42 +01:00
const diagnostics : Diagnostic [ ] = [ ] ;
2015-09-09 23:41:19 +02:00
walk ( sourceFile ) ;
return diagnostics ;
function walk ( node : Node ) : boolean {
if ( ! node ) {
return false ;
}
switch ( node . kind ) {
case SyntaxKind . ImportEqualsDeclaration :
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . import_can_only_be_used_in_a_ts_file ) ) ;
return true ;
case SyntaxKind . ExportAssignment :
2016-02-01 22:28:58 +01:00
if ( ( < ExportAssignment > node ) . isExportEquals ) {
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . export_can_only_be_used_in_a_ts_file ) ) ;
return true ;
}
break ;
2015-09-09 23:41:19 +02:00
case SyntaxKind . ClassDeclaration :
let classDeclaration = < ClassDeclaration > node ;
if ( checkModifiers ( classDeclaration . modifiers ) ||
checkTypeParameters ( classDeclaration . typeParameters ) ) {
return true ;
}
break ;
case SyntaxKind . HeritageClause :
let heritageClause = < HeritageClause > node ;
if ( heritageClause . token === SyntaxKind . ImplementsKeyword ) {
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . implements_clauses_can_only_be_used_in_a_ts_file ) ) ;
return true ;
}
break ;
case SyntaxKind . InterfaceDeclaration :
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . interface_declarations_can_only_be_used_in_a_ts_file ) ) ;
return true ;
case SyntaxKind . ModuleDeclaration :
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . module _declarations_can_only_be_used_in_a_ts_file ) ) ;
return true ;
case SyntaxKind . TypeAliasDeclaration :
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . type_aliases_can_only_be_used_in_a_ts_file ) ) ;
return true ;
case SyntaxKind . MethodDeclaration :
case SyntaxKind . MethodSignature :
case SyntaxKind . Constructor :
case SyntaxKind . GetAccessor :
case SyntaxKind . SetAccessor :
case SyntaxKind . FunctionExpression :
case SyntaxKind . FunctionDeclaration :
case SyntaxKind . ArrowFunction :
case SyntaxKind . FunctionDeclaration :
2015-11-06 21:39:42 +01:00
const functionDeclaration = < FunctionLikeDeclaration > node ;
2015-09-09 23:41:19 +02:00
if ( checkModifiers ( functionDeclaration . modifiers ) ||
checkTypeParameters ( functionDeclaration . typeParameters ) ||
checkTypeAnnotation ( functionDeclaration . type ) ) {
return true ;
}
break ;
case SyntaxKind . VariableStatement :
2015-11-06 21:39:42 +01:00
const variableStatement = < VariableStatement > node ;
2015-09-09 23:41:19 +02:00
if ( checkModifiers ( variableStatement . modifiers ) ) {
return true ;
}
break ;
case SyntaxKind . VariableDeclaration :
2015-11-06 21:39:42 +01:00
const variableDeclaration = < VariableDeclaration > node ;
2015-09-09 23:41:19 +02:00
if ( checkTypeAnnotation ( variableDeclaration . type ) ) {
return true ;
}
break ;
case SyntaxKind . CallExpression :
case SyntaxKind . NewExpression :
2015-11-06 21:39:42 +01:00
const expression = < CallExpression > node ;
2015-09-09 23:41:19 +02:00
if ( expression . typeArguments && expression . typeArguments . length > 0 ) {
2015-11-06 21:39:42 +01:00
const start = expression . typeArguments . pos ;
2015-09-09 23:41:19 +02:00
diagnostics . push ( createFileDiagnostic ( sourceFile , start , expression . typeArguments . end - start ,
Diagnostics . type_arguments_can_only_be_used_in_a_ts_file ) ) ;
return true ;
}
break ;
case SyntaxKind . Parameter :
2015-11-06 21:39:42 +01:00
const parameter = < ParameterDeclaration > node ;
2015-09-09 23:41:19 +02:00
if ( parameter . modifiers ) {
2015-11-06 21:39:42 +01:00
const start = parameter . modifiers . pos ;
2015-09-09 23:41:19 +02:00
diagnostics . push ( createFileDiagnostic ( sourceFile , start , parameter . modifiers . end - start ,
Diagnostics . parameter_modifiers_can_only_be_used_in_a_ts_file ) ) ;
return true ;
}
if ( parameter . questionToken ) {
2015-10-06 01:42:37 +02:00
diagnostics . push ( createDiagnosticForNode ( parameter . questionToken , Diagnostics . _0_can_only_be_used_in_a_ts_file , "?" ) ) ;
2015-09-09 23:41:19 +02:00
return true ;
}
if ( parameter . type ) {
diagnostics . push ( createDiagnosticForNode ( parameter . type , Diagnostics . types_can_only_be_used_in_a_ts_file ) ) ;
return true ;
}
break ;
case SyntaxKind . PropertyDeclaration :
2016-06-15 18:42:52 +02:00
const propertyDeclaration = < PropertyDeclaration > node ;
if ( propertyDeclaration . modifiers ) {
for ( const modifier of propertyDeclaration . modifiers ) {
if ( modifier . kind !== SyntaxKind . StaticKeyword ) {
diagnostics . push ( createDiagnosticForNode ( modifier , Diagnostics . _0_can_only_be_used_in_a_ts_file , tokenToString ( modifier . kind ) ) ) ;
return true ;
}
}
}
if ( checkTypeAnnotation ( ( < PropertyDeclaration > node ) . type ) ) {
return true ;
}
break ;
2015-09-09 23:41:19 +02:00
case SyntaxKind . EnumDeclaration :
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . enum_declarations_can_only_be_used_in_a_ts_file ) ) ;
return true ;
case SyntaxKind . TypeAssertionExpression :
let typeAssertionExpression = < TypeAssertion > node ;
diagnostics . push ( createDiagnosticForNode ( typeAssertionExpression . type , Diagnostics . type_assertion_expressions_can_only_be_used_in_a_ts_file ) ) ;
return true ;
2016-02-13 04:19:23 +01:00
case SyntaxKind . Decorator :
if ( ! options . experimentalDecorators ) {
2016-02-13 17:02:16 +01:00
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning ) ) ;
2016-02-13 04:19:23 +01:00
}
return true ;
2015-09-09 23:41:19 +02:00
}
return forEachChild ( node , walk ) ;
}
function checkTypeParameters ( typeParameters : NodeArray < TypeParameterDeclaration > ) : boolean {
if ( typeParameters ) {
2015-11-06 21:39:42 +01:00
const start = typeParameters . pos ;
2015-09-09 23:41:19 +02:00
diagnostics . push ( createFileDiagnostic ( sourceFile , start , typeParameters . end - start , Diagnostics . type_parameter_declarations_can_only_be_used_in_a_ts_file ) ) ;
return true ;
}
return false ;
}
function checkTypeAnnotation ( type : TypeNode ) : boolean {
if ( type ) {
diagnostics . push ( createDiagnosticForNode ( type , Diagnostics . types_can_only_be_used_in_a_ts_file ) ) ;
return true ;
}
return false ;
}
function checkModifiers ( modifiers : ModifiersArray ) : boolean {
if ( modifiers ) {
2015-11-06 21:39:42 +01:00
for ( const modifier of modifiers ) {
2015-09-09 23:41:19 +02:00
switch ( modifier . kind ) {
case SyntaxKind . PublicKeyword :
case SyntaxKind . PrivateKeyword :
case SyntaxKind . ProtectedKeyword :
2016-01-14 03:34:38 +01:00
case SyntaxKind . ReadonlyKeyword :
2015-09-09 23:41:19 +02:00
case SyntaxKind . DeclareKeyword :
diagnostics . push ( createDiagnosticForNode ( modifier , Diagnostics . _0_can_only_be_used_in_a_ts_file , tokenToString ( modifier . kind ) ) ) ;
return true ;
// These are all legal modifiers.
case SyntaxKind . StaticKeyword :
case SyntaxKind . ExportKeyword :
case SyntaxKind . ConstKeyword :
case SyntaxKind . DefaultKeyword :
case SyntaxKind . AbstractKeyword :
}
}
}
return false ;
}
} ) ;
}
2016-02-24 23:21:30 +01:00
function getDeclarationDiagnosticsWorker ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
2015-06-18 19:52:19 +02:00
return runWithCancellationToken ( ( ) = > {
2016-02-24 23:21:30 +01:00
const resolver = getDiagnosticsProducingTypeChecker ( ) . getEmitResolver ( sourceFile , cancellationToken ) ;
// Don't actually write any files since we're just getting diagnostics.
const writeFile : WriteFileCallback = ( ) = > { } ;
return ts . getDeclarationDiagnostics ( getEmitHost ( writeFile ) , resolver , sourceFile ) ;
2015-06-18 19:52:19 +02:00
} ) ;
2015-03-20 00:55:07 +01:00
}
2016-02-24 23:21:30 +01:00
function getDeclarationDiagnosticsForFile ( sourceFile : SourceFile , cancellationToken : CancellationToken ) : Diagnostic [ ] {
return isDeclarationFile ( sourceFile ) ? [ ] : getDeclarationDiagnosticsWorker ( sourceFile , cancellationToken ) ;
}
2015-06-18 18:32:52 +02:00
function getOptionsDiagnostics ( ) : Diagnostic [ ] {
2015-11-04 23:02:33 +01:00
const allDiagnostics : Diagnostic [ ] = [ ] ;
2015-10-01 01:10:52 +02:00
addRange ( allDiagnostics , fileProcessingDiagnostics . getGlobalDiagnostics ( ) ) ;
2015-09-10 19:46:39 +02:00
addRange ( allDiagnostics , programDiagnostics . getGlobalDiagnostics ( ) ) ;
2015-05-27 05:18:13 +02:00
return sortAndDeduplicateDiagnostics ( allDiagnostics ) ;
}
2014-12-16 22:14:14 +01:00
function getGlobalDiagnostics ( ) : Diagnostic [ ] {
2015-11-04 23:02:33 +01:00
const allDiagnostics : Diagnostic [ ] = [ ] ;
2015-06-18 18:32:52 +02:00
addRange ( allDiagnostics , getDiagnosticsProducingTypeChecker ( ) . getGlobalDiagnostics ( ) ) ;
2015-02-05 10:47:29 +01:00
return sortAndDeduplicateDiagnostics ( allDiagnostics ) ;
2014-12-16 22:14:14 +01:00
}
2015-02-04 01:08:46 +01:00
function hasExtension ( fileName : string ) : boolean {
return getBaseFileName ( fileName ) . indexOf ( "." ) >= 0 ;
2014-12-16 22:14:14 +01:00
}
2015-02-04 01:08:46 +01:00
function processRootFile ( fileName : string , isDefaultLib : boolean ) {
2016-03-02 19:52:16 +01:00
processSourceFile ( normalizePath ( fileName ) , isDefaultLib , /*isReference*/ true ) ;
2015-10-01 01:10:52 +02:00
}
2015-06-23 02:48:44 +02:00
function fileReferenceIsEqualTo ( a : FileReference , b : FileReference ) : boolean {
return a . fileName === b . fileName ;
}
2015-10-01 01:10:52 +02:00
2015-06-23 02:48:44 +02:00
function module NameIsEqualTo ( a : LiteralExpression , b : LiteralExpression ) : boolean {
2015-06-25 02:40:04 +02:00
return a . text === b . text ;
2015-06-23 02:48:44 +02:00
}
2015-10-01 01:10:52 +02:00
2016-01-14 19:56:49 +01:00
function getTextOfLiteral ( literal : LiteralExpression ) : string {
return literal . text ;
}
2015-06-23 02:48:44 +02:00
function collectExternalModuleReferences ( file : SourceFile ) : void {
if ( file . imports ) {
return ;
}
2015-10-01 01:10:52 +02:00
2015-11-09 21:49:36 +01:00
const isJavaScriptFile = isSourceFileJavaScript ( file ) ;
2015-12-22 22:21:51 +01:00
const isExternalModuleFile = isExternalModule ( file ) ;
2015-10-15 02:36:03 +02:00
2015-06-23 02:48:44 +02:00
let imports : LiteralExpression [ ] ;
2015-12-22 22:21:51 +01:00
let module Augmentations : LiteralExpression [ ] ;
2015-11-04 23:02:33 +01:00
for ( const node of file . statements ) {
2015-12-22 22:21:51 +01:00
collectModuleReferences ( node , /*inAmbientModule*/ false ) ;
if ( isJavaScriptFile ) {
collectRequireCalls ( node ) ;
}
2015-09-30 00:06:03 +02:00
}
file . imports = imports || emptyArray ;
2015-12-22 22:21:51 +01:00
file . module Augmentations = module Augmentations || emptyArray ;
2015-10-01 01:10:52 +02:00
2015-10-22 23:12:57 +02:00
return ;
2015-12-22 22:21:51 +01:00
function collectModuleReferences ( node : Node , inAmbientModule : boolean ) : void {
switch ( node . kind ) {
case SyntaxKind . ImportDeclaration :
case SyntaxKind . ImportEqualsDeclaration :
case SyntaxKind . ExportDeclaration :
let module NameExpr = getExternalModuleName ( node ) ;
if ( ! module NameExpr || module NameExpr.kind !== SyntaxKind . StringLiteral ) {
break ;
}
if ( ! ( < LiteralExpression > module NameExpr ) . text ) {
break ;
}
2015-06-23 02:48:44 +02:00
2015-12-22 22:21:51 +01:00
// TypeScript 1.0 spec (April 2014): 12.1.6
2016-01-30 20:37:02 +01:00
// An ExternalImportDeclaration in an AmbientExternalModuleDeclaration may reference other external modules
2015-12-22 22:21:51 +01:00
// only through top - level external module names. Relative external module names are not permitted.
if ( ! inAmbientModule || ! isExternalModuleNameRelative ( ( < LiteralExpression > module NameExpr ) . text ) ) {
( imports || ( imports = [ ] ) ) . push ( < LiteralExpression > module NameExpr ) ;
}
break ;
case SyntaxKind . ModuleDeclaration :
2015-12-28 21:03:54 +01:00
if ( isAmbientModule ( < ModuleDeclaration > node ) && ( inAmbientModule || node . flags & NodeFlags . Ambient || isDeclarationFile ( file ) ) ) {
2015-12-22 22:21:51 +01:00
const module Name = < LiteralExpression > ( < ModuleDeclaration > node ) . name ;
// Ambient module declarations can be interpreted as augmentations for some existing external modules.
// This will happen in two cases:
// - if current file is external module then module augmentation is a ambient module declaration defined in the top level scope
// - if current file is not external module then module augmentation is an ambient module declaration with non-relative module name
// immediately nested in top level ambient module declaration .
if ( isExternalModuleFile || ( inAmbientModule && ! isExternalModuleNameRelative ( module Name.text ) ) ) {
( module Augmentations || ( module Augmentations = [ ] ) ) . push ( module Name ) ;
2015-10-15 02:36:03 +02:00
}
2015-12-22 22:21:51 +01:00
else if ( ! inAmbientModule ) {
2016-01-30 20:37:02 +01:00
// An AmbientExternalModuleDeclaration declares an external module.
2015-10-22 23:12:57 +02:00
// This type of declaration is permitted only in the global module.
// The StringLiteral must specify a top - level external module name.
// Relative external module names are not permitted
2015-12-22 22:21:51 +01:00
2016-06-02 18:15:48 +02:00
// NOTE: body of ambient module is always a module block, if it exists
const body = < ModuleBlock > ( < ModuleDeclaration > node ) . body ;
if ( body ) {
for ( const statement of body . statements ) {
collectModuleReferences ( statement , /*inAmbientModule*/ true ) ;
}
2015-12-22 22:21:51 +01:00
}
2015-10-22 23:12:57 +02:00
}
2015-12-22 22:21:51 +01:00
}
2015-06-23 02:48:44 +02:00
}
2015-12-22 22:21:51 +01:00
}
2015-06-23 02:48:44 +02:00
2015-12-22 22:21:51 +01:00
function collectRequireCalls ( node : Node ) : void {
2016-01-28 23:18:23 +01:00
if ( isRequireCall ( node , /*checkArgumentIsStringLiteral*/ true ) ) {
2015-12-22 22:21:51 +01:00
( imports || ( imports = [ ] ) ) . push ( < StringLiteral > ( < CallExpression > node ) . arguments [ 0 ] ) ;
}
else {
forEachChild ( node , collectRequireCalls ) ;
2015-06-23 02:48:44 +02:00
}
}
2014-12-16 22:14:14 +01:00
}
2016-03-02 19:52:16 +01:00
/ * *
* 'isReference' indicates whether the file was brought in via a reference directive ( rather than an import declaration )
* /
function processSourceFile ( fileName : string , isDefaultLib : boolean , isReference : boolean , refFile? : SourceFile , refPos? : number , refEnd? : number ) {
2015-05-05 08:30:43 +02:00
let diagnosticArgument : string [ ] ;
2015-03-13 23:03:17 +01:00
let diagnostic : DiagnosticMessage ;
2015-02-04 01:08:46 +01:00
if ( hasExtension ( fileName ) ) {
2015-03-27 00:48:17 +01:00
if ( ! options . allowNonTsExtensions && ! forEach ( supportedExtensions , extension = > fileExtensionIs ( host . getCanonicalFileName ( fileName ) , extension ) ) ) {
2015-05-05 08:30:43 +02:00
diagnostic = Diagnostics . File_0_has_unsupported_extension_The_only_supported_extensions_are_1 ;
diagnosticArgument = [ fileName , "'" + supportedExtensions . join ( "', '" ) + "'" ] ;
2014-12-16 22:14:14 +01:00
}
2016-03-02 19:52:16 +01:00
else if ( ! findSourceFile ( fileName , toPath ( fileName , currentDirectory , getCanonicalFileName ) , isDefaultLib , isReference , refFile , refPos , refEnd ) ) {
2014-12-16 22:14:14 +01:00
diagnostic = Diagnostics . File_0_not_found ;
2015-05-05 08:30:43 +02:00
diagnosticArgument = [ fileName ] ;
2014-12-16 22:14:14 +01:00
}
2015-02-04 01:08:46 +01:00
else if ( refFile && host . getCanonicalFileName ( fileName ) === host . getCanonicalFileName ( refFile . fileName ) ) {
2014-12-16 22:14:14 +01:00
diagnostic = Diagnostics . A_file_cannot_have_a_reference_to_itself ;
2015-05-05 08:30:43 +02:00
diagnosticArgument = [ fileName ] ;
2014-12-16 22:14:14 +01:00
}
}
else {
2016-03-02 19:52:16 +01:00
const nonTsFile : SourceFile = options . allowNonTsExtensions && findSourceFile ( fileName , toPath ( fileName , currentDirectory , getCanonicalFileName ) , isDefaultLib , isReference , refFile , refPos , refEnd ) ;
2015-06-11 23:30:58 +02:00
if ( ! nonTsFile ) {
if ( options . allowNonTsExtensions ) {
diagnostic = Diagnostics . File_0_not_found ;
diagnosticArgument = [ fileName ] ;
}
2016-03-02 19:52:16 +01:00
else if ( ! forEach ( supportedExtensions , extension = > findSourceFile ( fileName + extension , toPath ( fileName + extension , currentDirectory , getCanonicalFileName ) , isDefaultLib , isReference , refFile , refPos , refEnd ) ) ) {
2015-06-11 23:30:58 +02:00
diagnostic = Diagnostics . File_0_not_found ;
fileName += ".ts" ;
diagnosticArgument = [ fileName ] ;
}
2014-12-16 22:14:14 +01:00
}
}
if ( diagnostic ) {
2015-08-12 22:04:10 +02:00
if ( refFile !== undefined && refEnd !== undefined && refPos !== undefined ) {
2015-09-10 19:46:39 +02:00
fileProcessingDiagnostics . add ( createFileDiagnostic ( refFile , refPos , refEnd - refPos , diagnostic , . . . diagnosticArgument ) ) ;
2014-12-16 22:14:14 +01:00
}
else {
2015-09-10 19:46:39 +02:00
fileProcessingDiagnostics . add ( createCompilerDiagnostic ( diagnostic , . . . diagnosticArgument ) ) ;
2014-12-16 22:14:14 +01:00
}
}
}
2015-10-15 23:43:51 +02:00
function reportFileNamesDifferOnlyInCasingError ( fileName : string , existingFileName : string , refFile : SourceFile , refPos : number , refEnd : number ) : void {
if ( refFile !== undefined && refPos !== undefined && refEnd !== undefined ) {
fileProcessingDiagnostics . add ( createFileDiagnostic ( refFile , refPos , refEnd - refPos ,
Diagnostics . File_name_0_differs_from_already_included_file_name_1_only_in_casing , fileName , existingFileName ) ) ;
2014-12-16 22:14:14 +01:00
}
2015-10-15 23:43:51 +02:00
else {
fileProcessingDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . File_name_0_differs_from_already_included_file_name_1_only_in_casing , fileName , existingFileName ) ) ;
2015-09-27 06:29:07 +02:00
}
2015-10-15 23:43:51 +02:00
}
2015-10-01 01:10:52 +02:00
2015-10-15 23:43:51 +02:00
// Get source file from normalized fileName
2016-03-02 19:52:16 +01:00
function findSourceFile ( fileName : string , path : Path , isDefaultLib : boolean , isReference : boolean , refFile? : SourceFile , refPos? : number , refEnd? : number ) : SourceFile {
2015-11-16 18:49:58 +01:00
if ( filesByName . contains ( path ) ) {
const file = filesByName . get ( path ) ;
2015-10-15 23:43:51 +02:00
// try to check if we've already seen this file but with a different casing in path
// NOTE: this only makes sense for case-insensitive file systems
2015-11-16 18:49:58 +01:00
if ( file && options . forceConsistentCasingInFileNames && getNormalizedAbsolutePath ( file . fileName , currentDirectory ) !== getNormalizedAbsolutePath ( fileName , currentDirectory ) ) {
2015-10-15 23:43:51 +02:00
reportFileNamesDifferOnlyInCasingError ( fileName , file . fileName , refFile , refPos , refEnd ) ;
}
2016-07-11 01:11:42 +02:00
// If the file was previously found via a node_modules search, but is now being processed as a root file,
// then everything it sucks in may also be marked incorrectly, and needs to be checked again.
if ( file && lookUp ( sourceFilesFoundSearchingNodeModules , file . path ) && currentNodeModulesDepth == 0 ) {
2016-07-11 05:54:07 +02:00
sourceFilesFoundSearchingNodeModules [ file . path ] = false ;
2016-07-11 01:11:42 +02:00
if ( ! options . noResolve ) {
processReferencedFiles ( file , getDirectoryPath ( fileName ) , isDefaultLib ) ;
processTypeReferenceDirectives ( file ) ;
}
module sWithElidedImports [ file . path ] = false ;
processImportedModules ( file , getDirectoryPath ( fileName ) ) ;
}
2016-06-27 05:48:22 +02:00
// See if we need to reprocess the imports due to prior skipped imports
2016-07-11 01:11:42 +02:00
else if ( file && lookUp ( module sWithElidedImports , file . path ) ) {
if ( currentNodeModulesDepth < maxNodeModulesJsDepth ) {
2016-06-27 05:48:22 +02:00
module sWithElidedImports [ file . path ] = false ;
processImportedModules ( file , getDirectoryPath ( fileName ) ) ;
}
}
2015-09-27 06:29:07 +02:00
return file ;
2014-12-16 22:14:14 +01:00
}
2015-09-27 06:29:07 +02:00
// We haven't looked for this file, do so now and cache result
2015-11-04 23:02:33 +01:00
const file = host . getSourceFile ( fileName , options . target , hostErrorMessage = > {
2015-09-27 06:29:07 +02:00
if ( refFile !== undefined && refPos !== undefined && refEnd !== undefined ) {
fileProcessingDiagnostics . add ( createFileDiagnostic ( refFile , refPos , refEnd - refPos ,
Diagnostics . Cannot_read_file_0_Colon_1 , fileName , hostErrorMessage ) ) ;
}
else {
fileProcessingDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Cannot_read_file_0_Colon_1 , fileName , hostErrorMessage ) ) ;
}
} ) ;
2015-10-01 01:10:52 +02:00
2015-11-16 18:49:58 +01:00
filesByName . set ( path , file ) ;
2015-09-27 06:29:07 +02:00
if ( file ) {
2016-07-11 05:54:07 +02:00
sourceFilesFoundSearchingNodeModules [ path ] = ( currentNodeModulesDepth > 0 ) ;
2015-11-16 18:49:58 +01:00
file . path = path ;
2015-10-29 22:54:56 +01:00
2015-10-15 23:43:51 +02:00
if ( host . useCaseSensitiveFileNames ( ) ) {
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
2015-11-16 18:49:58 +01:00
const existingFile = filesByNameIgnoreCase . get ( path ) ;
2015-10-15 23:43:51 +02:00
if ( existingFile ) {
reportFileNamesDifferOnlyInCasingError ( fileName , existingFile . fileName , refFile , refPos , refEnd ) ;
}
else {
2015-11-16 18:49:58 +01:00
filesByNameIgnoreCase . set ( path , file ) ;
2015-10-15 23:43:51 +02:00
}
}
2014-12-16 22:14:14 +01:00
2015-10-15 23:43:51 +02:00
skipDefaultLib = skipDefaultLib || file . hasNoDefaultLib ;
2015-10-01 01:10:52 +02:00
2015-11-04 23:02:33 +01:00
const basePath = getDirectoryPath ( fileName ) ;
2015-09-27 06:29:07 +02:00
if ( ! options . noResolve ) {
2016-04-01 21:41:01 +02:00
processReferencedFiles ( file , basePath , isDefaultLib ) ;
2016-04-06 01:33:11 +02:00
processTypeReferenceDirectives ( file ) ;
2015-09-27 06:29:07 +02:00
}
2015-08-19 20:58:02 +02:00
2015-09-27 06:29:07 +02:00
// always process imported modules to record module name resolutions
processImportedModules ( file , basePath ) ;
2015-08-19 20:58:02 +02:00
2015-09-27 06:29:07 +02:00
if ( isDefaultLib ) {
files . unshift ( file ) ;
}
else {
files . push ( file ) ;
2014-12-16 22:14:14 +01:00
}
}
2015-09-27 06:29:07 +02:00
return file ;
2014-12-16 22:14:14 +01:00
}
2016-03-28 23:20:29 +02:00
function processReferencedFiles ( file : SourceFile , basePath : string , isDefaultLib : boolean ) {
2014-12-16 22:14:14 +01:00
forEach ( file . referencedFiles , ref = > {
2015-11-04 23:02:33 +01:00
const referencedFileName = resolveTripleslashReference ( ref . fileName , file . fileName ) ;
2016-03-28 23:20:29 +02:00
processSourceFile ( referencedFileName , isDefaultLib , /*isReference*/ true , file , ref . pos , ref . end ) ;
2014-12-16 22:14:14 +01:00
} ) ;
}
2015-10-01 01:10:52 +02:00
2016-04-06 01:33:11 +02:00
function processTypeReferenceDirectives ( file : SourceFile ) {
2016-04-01 21:41:01 +02:00
const typeDirectives = map ( file . typeReferenceDirectives , l = > l . fileName ) ;
const resolutions = resolveTypeReferenceDirectiveNamesWorker ( typeDirectives , file . fileName ) ;
2016-02-23 21:48:31 +01:00
2016-04-01 21:41:01 +02:00
for ( let i = 0 ; i < typeDirectives . length ; i ++ ) {
const ref = file . typeReferenceDirectives [ i ] ;
const resolvedTypeReferenceDirective = resolutions [ i ] ;
// store resolved type directive on the file
setResolvedTypeReferenceDirective ( file , ref . fileName , resolvedTypeReferenceDirective ) ;
2016-04-06 22:49:25 +02:00
processTypeReferenceDirective ( ref . fileName , resolvedTypeReferenceDirective , file , ref . pos , ref . end ) ;
}
}
function processTypeReferenceDirective ( typeReferenceDirective : string , resolvedTypeReferenceDirective : ResolvedTypeReferenceDirective ,
refFile? : SourceFile , refPos? : number , refEnd? : number ) : void {
// If we already found this library as a primary reference - nothing to do
const previousResolution = resolvedTypeReferenceDirectives [ typeReferenceDirective ] ;
if ( previousResolution && previousResolution . primary ) {
return ;
}
let saveResolution = true ;
if ( resolvedTypeReferenceDirective ) {
if ( resolvedTypeReferenceDirective . primary ) {
// resolved from the primary path
processSourceFile ( resolvedTypeReferenceDirective . resolvedFileName , /*isDefaultLib*/ false , /*isReference*/ true , refFile , refPos , refEnd ) ;
2016-02-23 21:48:31 +01:00
}
2016-04-06 22:49:25 +02:00
else {
// If we already resolved to this file, it must have been a secondary reference. Check file contents
// for sameness and possibly issue an error
if ( previousResolution ) {
const otherFileText = host . readFile ( resolvedTypeReferenceDirective . resolvedFileName ) ;
if ( otherFileText !== getSourceFile ( previousResolution . resolvedFileName ) . text ) {
fileProcessingDiagnostics . add ( createDiagnostic ( refFile , refPos , refEnd ,
Diagnostics . Conflicting_library_definitions_for_0_found_at_1_and_2_Copy_the_correct_file_to_the_typings_folder_to_resolve_this_conflict ,
typeReferenceDirective ,
resolvedTypeReferenceDirective . resolvedFileName ,
previousResolution . resolvedFileName
) ) ;
}
// don't overwrite previous resolution result
saveResolution = false ;
2016-02-23 21:48:31 +01:00
}
2016-04-01 21:41:01 +02:00
else {
2016-04-06 22:49:25 +02:00
// First resolution of this library
processSourceFile ( resolvedTypeReferenceDirective . resolvedFileName , /*isDefaultLib*/ false , /*isReference*/ true , refFile , refPos , refEnd ) ;
2016-02-23 21:48:31 +01:00
}
}
2016-04-06 22:49:25 +02:00
}
else {
2016-06-11 00:44:11 +02:00
fileProcessingDiagnostics . add ( createDiagnostic ( refFile , refPos , refEnd , Diagnostics . Cannot_find_type_definition_file_for_0 , typeReferenceDirective ) ) ;
2016-04-06 22:49:25 +02:00
}
2016-02-23 21:48:31 +01:00
2016-04-06 22:49:25 +02:00
if ( saveResolution ) {
resolvedTypeReferenceDirectives [ typeReferenceDirective ] = resolvedTypeReferenceDirective ;
}
}
function createDiagnostic ( refFile : SourceFile , refPos : number , refEnd : number , message : DiagnosticMessage , . . . args : any [ ] ) : Diagnostic {
if ( refFile === undefined || refPos === undefined || refEnd === undefined ) {
return createCompilerDiagnostic ( message , . . . args ) ;
}
else {
return createFileDiagnostic ( refFile , refPos , refEnd - refPos , message , . . . args ) ;
2016-04-01 21:41:01 +02:00
}
2016-02-23 21:48:31 +01:00
}
2015-10-15 23:43:51 +02:00
function getCanonicalFileName ( fileName : string ) : string {
return host . getCanonicalFileName ( fileName ) ;
}
2015-08-20 00:37:37 +02:00
function processImportedModules ( file : SourceFile , basePath : string ) {
collectExternalModuleReferences ( file ) ;
2015-12-22 22:21:51 +01:00
if ( file . imports . length || file . module Augmentations.length ) {
2016-08-11 01:47:06 +02:00
file . resolvedModules = createMap < ResolvedModule > ( ) ;
2016-01-14 19:56:49 +01:00
const module Names = map ( concatenate ( file . imports , file . module Augmentations ) , getTextOfLiteral ) ;
2015-11-04 23:02:33 +01:00
const resolutions = resolveModuleNamesWorker ( module Names , getNormalizedAbsolutePath ( file . fileName , currentDirectory ) ) ;
2016-01-12 07:34:38 +01:00
for ( let i = 0 ; i < module Names.length ; i ++ ) {
2015-11-04 23:02:33 +01:00
const resolution = resolutions [ i ] ;
2015-09-10 20:36:31 +02:00
setResolvedModule ( file , module Names [ i ] , resolution ) ;
2016-06-27 05:48:22 +02:00
const resolvedPath = resolution ? toPath ( resolution . resolvedFileName , currentDirectory , getCanonicalFileName ) : undefined ;
2015-12-22 22:21:51 +01:00
// add file to program only if:
2016-02-11 17:56:45 +01:00
// - resolution was successful
2015-12-22 22:21:51 +01:00
// - noResolve is falsy
2016-05-10 07:05:57 +02:00
// - module name comes from the list of imports
2016-02-13 16:48:25 +01:00
// - it's not a top level JavaScript module that exceeded the search max
2016-06-29 17:44:06 +02:00
const isFromNodeModulesSearch = resolution && resolution . isExternalLibraryImport ;
const isJsFileFromNodeModules = isFromNodeModulesSearch && hasJavaScriptFileExtension ( resolution . resolvedFileName ) ;
2016-06-27 05:48:22 +02:00
2016-06-29 17:44:06 +02:00
if ( isFromNodeModulesSearch ) {
2016-07-11 01:11:42 +02:00
currentNodeModulesDepth ++ ;
2016-06-29 17:44:06 +02:00
}
2016-07-11 01:11:42 +02:00
const elideImport = isJsFileFromNodeModules && currentNodeModulesDepth > maxNodeModulesJsDepth ;
2016-06-27 05:48:22 +02:00
const shouldAddFile = resolution && ! options . noResolve && i < file . imports . length && ! elideImport ;
if ( elideImport ) {
module sWithElidedImports [ file . path ] = true ;
}
else if ( shouldAddFile ) {
2016-06-21 22:42:02 +02:00
findSourceFile ( resolution . resolvedFileName ,
2016-06-27 05:48:22 +02:00
resolvedPath ,
2016-06-21 22:42:02 +02:00
/*isDefaultLib*/ false , /*isReference*/ false ,
file ,
skipTrivia ( file . text , file . imports [ i ] . pos ) ,
file . imports [ i ] . end ) ;
}
2015-12-22 22:21:51 +01:00
2016-07-11 01:11:42 +02:00
if ( isFromNodeModulesSearch ) {
currentNodeModulesDepth -- ;
2015-08-04 02:42:29 +02:00
}
2015-08-19 20:58:02 +02:00
}
2015-06-23 02:48:44 +02:00
}
else {
// no imports - drop cached module resolutions
file . resolvedModules = undefined ;
}
return ;
2014-12-16 22:14:14 +01:00
}
2016-02-23 21:48:31 +01:00
function computeCommonSourceDirectory ( sourceFiles : SourceFile [ ] ) : string {
const fileNames : string [ ] = [ ] ;
for ( const file of sourceFiles ) {
if ( ! file . isDeclarationFile ) {
fileNames . push ( file . fileName ) ;
}
}
2016-04-01 21:41:01 +02:00
return computeCommonSourceDirectoryOfFilenames ( fileNames , currentDirectory , getCanonicalFileName ) ;
2016-02-23 21:48:31 +01:00
}
2015-04-19 22:24:39 +02:00
function checkSourceFilesBelongToPath ( sourceFiles : SourceFile [ ] , rootDirectory : string ) : boolean {
2015-04-15 07:11:25 +02:00
let allFilesBelongToPath = true ;
2015-04-19 22:24:39 +02:00
if ( sourceFiles ) {
2015-11-04 23:02:33 +01:00
const absoluteRootDirectoryPath = host . getCanonicalFileName ( getNormalizedAbsolutePath ( rootDirectory , currentDirectory ) ) ;
2015-04-15 07:11:25 +02:00
2016-01-16 23:05:46 +01:00
for ( const sourceFile of sourceFiles ) {
2015-04-15 07:11:25 +02:00
if ( ! isDeclarationFile ( sourceFile ) ) {
2015-11-04 23:02:33 +01:00
const absoluteSourceFilePath = host . getCanonicalFileName ( getNormalizedAbsolutePath ( sourceFile . fileName , currentDirectory ) ) ;
2015-04-15 07:11:25 +02:00
if ( absoluteSourceFilePath . indexOf ( absoluteRootDirectoryPath ) !== 0 ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files , sourceFile . fileName , options . rootDir ) ) ;
2015-04-15 07:11:25 +02:00
allFilesBelongToPath = false ;
}
}
}
2015-04-15 00:05:08 +02:00
}
2015-04-15 07:11:25 +02:00
return allFilesBelongToPath ;
2015-04-15 00:05:08 +02:00
}
2014-12-16 22:14:14 +01:00
function verifyCompilerOptions() {
2015-05-19 06:49:41 +02:00
if ( options . isolatedModules ) {
2015-03-31 04:33:15 +02:00
if ( options . declaration ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "declaration" , "isolatedModules" ) ) ;
2015-03-31 04:33:15 +02:00
}
if ( options . noEmitOnError ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "noEmitOnError" , "isolatedModules" ) ) ;
2015-03-31 04:33:15 +02:00
}
if ( options . out ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "out" , "isolatedModules" ) ) ;
2015-03-31 04:33:15 +02:00
}
2015-08-21 02:37:56 +02:00
if ( options . outFile ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "outFile" , "isolatedModules" ) ) ;
2015-03-31 04:33:15 +02:00
}
}
2015-04-08 09:14:23 +02:00
if ( options . inlineSourceMap ) {
if ( options . sourceMap ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "sourceMap" , "inlineSourceMap" ) ) ;
2015-04-08 09:14:23 +02:00
}
if ( options . mapRoot ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "mapRoot" , "inlineSourceMap" ) ) ;
2015-04-08 09:14:23 +02:00
}
2015-04-21 05:33:31 +02:00
}
2016-01-25 20:49:26 +01:00
if ( options . paths && options . baseUrl === undefined ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_paths_cannot_be_used_without_specifying_baseUrl_option ) ) ;
2015-11-19 06:46:45 +01:00
}
if ( options . paths ) {
for ( const key in options . paths ) {
if ( ! hasProperty ( options . paths , key ) ) {
continue ;
}
if ( ! hasZeroOrOneAsteriskCharacter ( key ) ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Pattern_0_can_have_at_most_one_Asterisk_character , key ) ) ;
}
2016-04-14 06:16:39 +02:00
if ( isArray ( options . paths [ key ] ) ) {
2016-07-23 08:05:36 +02:00
if ( options . paths [ key ] . length === 0 ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Substitutions_for_pattern_0_shouldn_t_be_an_empty_array , key ) ) ;
}
2016-04-14 06:16:39 +02:00
for ( const subst of options . paths [ key ] ) {
const typeOfSubst = typeof subst ;
if ( typeOfSubst === "string" ) {
if ( ! hasZeroOrOneAsteriskCharacter ( subst ) ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character , subst , key ) ) ;
}
}
else {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2 , subst , key , typeOfSubst ) ) ;
}
2015-11-19 06:46:45 +01:00
}
}
2016-04-14 06:16:39 +02:00
else {
2016-05-19 02:12:59 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Substitutions_for_pattern_0_should_be_an_array , key ) ) ;
2016-04-14 06:16:39 +02:00
}
2015-11-19 06:46:45 +01:00
}
}
2016-06-09 20:51:53 +02:00
if ( ! options . sourceMap && ! options . inlineSourceMap ) {
if ( options . inlineSources ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided , "inlineSources" ) ) ;
2015-04-08 09:14:23 +02:00
}
2015-11-11 21:58:31 +01:00
if ( options . sourceRoot ) {
2016-06-09 20:51:53 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided , "sourceRoot" ) ) ;
2015-11-11 21:58:31 +01:00
}
2015-04-08 09:14:23 +02:00
}
2015-08-21 02:37:56 +02:00
if ( options . out && options . outFile ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "out" , "outFile" ) ) ;
2015-08-21 02:37:56 +02:00
}
2016-06-09 20:51:53 +02:00
if ( options . mapRoot && ! options . sourceMap ) {
// Error to specify --mapRoot without --sourcemap
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_without_specifying_option_1 , "mapRoot" , "sourceMap" ) ) ;
2014-12-16 22:14:14 +01:00
}
2016-02-23 21:12:52 +01:00
if ( options . declarationDir ) {
if ( ! options . declaration ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_without_specifying_option_1 , "declarationDir" , "declaration" ) ) ;
}
if ( options . out || options . outFile ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "declarationDir" , options . out ? "out" : "outFile" ) ) ;
}
2016-02-20 23:40:39 +01:00
}
2016-03-28 23:20:29 +02:00
if ( options . lib && options . noLib ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "lib" , "noLib" ) ) ;
}
2015-11-04 23:02:33 +01:00
const languageVersion = options . target || ScriptTarget . ES3 ;
const outFile = options . outFile || options . out ;
2015-02-13 02:54:30 +01:00
2016-07-23 00:41:52 +02:00
const firstNonAmbientExternalModuleSourceFile = forEach ( files , f = > isExternalModule ( f ) && ! isDeclarationFile ( f ) ? f : undefined ) ;
2015-05-19 06:49:41 +02:00
if ( options . isolatedModules ) {
2016-02-11 20:53:10 +01:00
if ( options . module === ModuleKind . None && languageVersion < ScriptTarget . ES6 ) {
2016-02-11 20:01:10 +01:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher ) ) ;
}
2015-11-04 23:02:33 +01:00
const firstNonExternalModuleSourceFile = forEach ( files , f = > ! isExternalModule ( f ) && ! isDeclarationFile ( f ) ? f : undefined ) ;
2015-03-31 04:33:15 +02:00
if ( firstNonExternalModuleSourceFile ) {
2015-11-04 23:02:33 +01:00
const span = getErrorSpanForNode ( firstNonExternalModuleSourceFile , firstNonExternalModuleSourceFile ) ;
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createFileDiagnostic ( firstNonExternalModuleSourceFile , span . start , span . length , Diagnostics . Cannot_compile_namespaces_when_the_isolatedModules_flag_is_provided ) ) ;
2015-03-31 04:33:15 +02:00
}
}
2016-07-23 00:41:52 +02:00
else if ( firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget . ES6 && options . module === ModuleKind . None ) {
2016-02-11 20:01:10 +01:00
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
2016-07-23 00:41:52 +02:00
const span = getErrorSpanForNode ( firstNonAmbientExternalModuleSourceFile , firstNonAmbientExternalModuleSourceFile . externalModuleIndicator ) ;
programDiagnostics . add ( createFileDiagnostic ( firstNonAmbientExternalModuleSourceFile , span . start , span . length , Diagnostics . Cannot_use_imports_exports_or_module_augmentations_when_module_is_none ) ) ;
2016-02-11 20:01:10 +01:00
}
2015-03-12 06:53:36 +01:00
2015-10-05 23:25:48 +02:00
// Cannot specify module gen that isn't amd or system with --out
2016-05-18 02:14:51 +02:00
if ( outFile ) {
if ( options . module && ! ( options . module === ModuleKind . AMD || options . module === ModuleKind . System ) ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Only_amd_and_system_modules_are_supported_alongside_0 , options . out ? "out" : "outFile" ) ) ;
}
2016-07-23 00:41:52 +02:00
else if ( options . module === undefined && firstNonAmbientExternalModuleSourceFile ) {
const span = getErrorSpanForNode ( firstNonAmbientExternalModuleSourceFile , firstNonAmbientExternalModuleSourceFile . externalModuleIndicator ) ;
programDiagnostics . add ( createFileDiagnostic ( firstNonAmbientExternalModuleSourceFile , span . start , span . length , Diagnostics . Cannot_compile_modules_using_option_0_unless_the_module_flag_is_amd_or_system , options . out ? "out" : "outFile" ) ) ;
2016-05-18 02:14:51 +02:00
}
2015-10-03 02:03:29 +02:00
}
2015-10-22 00:27:33 +02:00
// there has to be common source directory if user specified --outdir || --sourceRoot
// if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
if ( options . outDir || // there is --outDir specified
options . sourceRoot || // there is --sourceRoot specified
options . mapRoot ) { // there is --mapRoot specified
2015-11-19 02:10:22 +01:00
// Precalculate and cache the common source directory
const dir = getCommonSourceDirectory ( ) ;
2015-10-22 00:27:33 +02:00
2015-11-19 02:10:22 +01:00
// If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
if ( options . outDir && dir === "" && forEach ( files , file = > getRootLength ( file . fileName ) > 1 ) ) {
2016-02-23 21:48:31 +01:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Cannot_find_the_common_subdirectory_path_for_the_input_files ) ) ;
2015-11-18 22:19:56 +01:00
}
2015-10-22 00:27:33 +02:00
}
2016-03-12 21:14:00 +01:00
if ( ! options . noEmit && options . allowJs && options . declaration ) {
2015-10-30 19:50:07 +01:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "allowJs" , "declaration" ) ) ;
}
2015-06-26 01:24:41 +02:00
2015-06-02 00:01:24 +02:00
if ( options . emitDecoratorMetadata &&
! options . experimentalDecorators ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_without_specifying_option_1 , "emitDecoratorMetadata" , "experimentalDecorators" ) ) ;
2015-06-02 00:01:24 +02:00
}
2015-07-09 00:35:49 +02:00
2016-01-08 00:00:50 +01:00
if ( options . reactNamespace && ! isIdentifier ( options . reactNamespace , languageVersion ) ) {
2016-01-30 20:37:02 +01:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier , options . reactNamespace ) ) ;
2016-01-08 00:00:50 +01:00
}
2015-11-06 05:09:40 +01:00
// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
2016-02-01 19:36:47 +01:00
if ( ! options . noEmit && ! options . suppressOutputPathCheck ) {
2015-11-06 21:39:42 +01:00
const emitHost = getEmitHost ( ) ;
const emitFilesSeen = createFileMap < boolean > ( ! host . useCaseSensitiveFileNames ( ) ? key = > key . toLocaleLowerCase ( ) : undefined ) ;
2015-10-30 21:22:23 +01:00
forEachExpectedEmitFile ( emitHost , ( emitFileNames , sourceFiles , isBundledEmit ) = > {
verifyEmitFilePath ( emitFileNames . jsFilePath , emitFilesSeen ) ;
verifyEmitFilePath ( emitFileNames . declarationFilePath , emitFilesSeen ) ;
} ) ;
}
2015-10-12 21:25:13 +02:00
2015-11-12 01:10:23 +01:00
// Verify that all the emit files are unique and don't overwrite input files
2015-10-30 23:54:31 +01:00
function verifyEmitFilePath ( emitFileName : string , emitFilesSeen : FileMap < boolean > ) {
if ( emitFileName ) {
2015-11-06 21:39:42 +01:00
const emitFilePath = toPath ( emitFileName , currentDirectory , getCanonicalFileName ) ;
2015-10-12 21:25:13 +02:00
// Report error if the output overwrites input file
2015-11-18 19:48:03 +01:00
if ( filesByName . contains ( emitFilePath ) ) {
createEmitBlockingDiagnostics ( emitFileName , emitFilePath , Diagnostics . Cannot_write_file_0_because_it_would_overwrite_input_file ) ;
2015-10-12 21:25:13 +02:00
}
2015-10-30 21:22:23 +01:00
// Report error if multiple files write into same file
2015-10-30 23:54:31 +01:00
if ( emitFilesSeen . contains ( emitFilePath ) ) {
2015-10-30 21:22:23 +01:00
// Already seen the same emit file - report error
2015-11-18 19:48:03 +01:00
createEmitBlockingDiagnostics ( emitFileName , emitFilePath , Diagnostics . Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files ) ;
2015-10-12 21:25:13 +02:00
}
else {
2015-10-30 23:54:31 +01:00
emitFilesSeen . set ( emitFilePath , true ) ;
2015-10-12 21:25:13 +02:00
}
2015-10-30 21:22:23 +01:00
}
2015-10-12 21:25:13 +02:00
}
}
2015-11-18 19:48:03 +01:00
function createEmitBlockingDiagnostics ( emitFileName : string , emitFilePath : Path , message : DiagnosticMessage ) {
2015-10-30 23:54:31 +01:00
hasEmitBlockingDiagnostics . set ( toPath ( emitFileName , currentDirectory , getCanonicalFileName ) , true ) ;
2015-11-12 01:10:23 +01:00
programDiagnostics . add ( createCompilerDiagnostic ( message , emitFileName ) ) ;
2014-12-16 22:14:14 +01:00
}
}
2015-06-17 20:08:13 +02:00
}