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-17 14:26:24 +01:00
/* @internal */ export let programTime = 0 ;
2015-03-13 23:03:17 +01:00
/* @internal */ export let emitTime = 0 ;
/* @internal */ export let ioReadTime = 0 ;
2015-03-17 14:26:24 +01:00
/* @internal */ export let ioWriteTime = 0 ;
2015-02-05 03:42:44 +01:00
2015-03-08 05:12:16 +01:00
/** The version of the TypeScript compiler release */
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-02-23 21:48:31 +01:00
const defaultLibrarySearchPaths = < Path [ ] > [
2016-04-01 21:41:01 +02:00
"types/" ,
2016-02-23 21:48:31 +01:00
"node_modules/" ,
2016-04-01 21:41:01 +02:00
"node_modules/@types/" ,
2016-02-23 21:48:31 +01:00
] ;
2016-01-26 02:08:15 +01:00
export const version = "1.9.0" ;
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-01 21:41:01 +02:00
export function computeCompilationRoot ( rootFileNames : string [ ] , currentDirectory : string , options : CompilerOptions , getCanonicalFileName : ( fileName : string ) = > string ) : string {
const rootDirOrConfigFilePath = options . rootDir || ( options . configFilePath && getDirectoryPath ( options . configFilePath ) ) ;
return rootDirOrConfigFilePath
? getNormalizedAbsolutePath ( rootDirOrConfigFilePath , currentDirectory )
: computeCommonSourceDirectoryOfFilenames ( rootFileNames , currentDirectory , getCanonicalFileName ) ;
}
function computeCommonSourceDirectoryOfFilenames ( fileNames : string [ ] , currentDirectory : string , getCanonicalFileName : ( fileName : string ) = > string ) : string {
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-01-25 20:49:26 +01:00
function startsWith ( str : string , prefix : string ) : boolean {
return str . lastIndexOf ( prefix , 0 ) === 0 ;
}
function endsWith ( str : string , suffix : string ) : boolean {
const expectedPos = str . length - suffix . length ;
return str . indexOf ( suffix , expectedPos ) === expectedPos ;
}
function hasZeroOrOneAsteriskCharacter ( str : string ) : boolean {
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 {
if ( isRootedDiskPath ( module Name ) ) {
return false ;
}
const i = module Name.lastIndexOf ( "./" , 1 ) ;
const startsWithDotSlashOrDotDotSlash = i === 0 || ( i === 1 && module Name.charCodeAt ( 0 ) === CharacterCodes . dot ) ;
return ! startsWithDotSlashOrDotDotSlash ;
}
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 {
let jsonContent : { typings? : string , types? : string } ;
try {
const jsonText = state . host . readFile ( packageJsonPath ) ;
jsonContent = jsonText ? < { typings? : string , types? : string } > JSON . parse ( jsonText ) : { } ;
}
catch ( e ) {
// gracefully handle if readFile fails or returns not JSON
jsonContent = { } ;
}
let typesFile : string ;
let fieldName : string ;
// first try to read content of 'typings' section (backward compatibility)
if ( jsonContent . typings ) {
if ( typeof jsonContent . typings === "string" ) {
fieldName = "typings" ;
typesFile = jsonContent . typings ;
}
else {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Expected_type_of_0_field_in_package_json_to_be_string_got_1 , "typings" , typeof jsonContent . typings ) ;
}
}
}
// then read 'types'
if ( ! typesFile && jsonContent . types ) {
if ( typeof jsonContent . types === "string" ) {
fieldName = "types" ;
typesFile = jsonContent . types ;
}
else {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Expected_type_of_0_field_in_package_json_to_be_string_got_1 , "types" , typeof jsonContent . types ) ;
}
}
}
if ( typesFile ) {
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 ;
}
return undefined ;
}
function tryLoadTypeDeclarationFile ( searchPath : string , failedLookupLocations : string [ ] , state : ModuleResolutionState ) {
let typesFile : string ;
const packageJsonPath = combinePaths ( searchPath , "package.json" ) ;
if ( state . host . fileExists ( packageJsonPath ) ) {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
}
typesFile = tryReadTypesSection ( packageJsonPath , searchPath , state ) ;
if ( ! typesFile ) {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . package_json_does_not_have_types_field ) ;
}
}
}
else {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . File_0_does_not_exist , packageJsonPath ) ;
}
failedLookupLocations . push ( packageJsonPath ) ;
}
if ( ! typesFile ) {
typesFile = "index.d.ts" ;
}
const combinedPath = normalizePath ( combinePaths ( searchPath , typesFile ) ) ;
if ( state . host . fileExists ( combinedPath ) ) {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . File_0_exist_use_it_as_a_name_resolution_result , combinedPath ) ;
}
return combinedPath ;
}
else {
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . File_0_does_not_exist , combinedPath ) ;
}
failedLookupLocations . push ( combinedPath ) ;
return undefined ;
}
}
function getEffectiveTypesPrimarySearchPaths ( options : CompilerOptions ) : string [ ] {
if ( options . typesSearchPaths ) {
return options . typesSearchPaths ;
}
return options . configFilePath
? [ getDirectoryPath ( options . configFilePath ) ] . concat ( defaultLibrarySearchPaths )
: defaultLibrarySearchPaths ;
}
export function resolveTypeReferenceDirective ( typeReferenceDirectiveName : string , containingFile : string , compilationRoot : string , options : CompilerOptions , host : ModuleResolutionHost ) : ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
const traceEnabled = isTraceEnabled ( options , host ) ;
const module ResolutionState : ModuleResolutionState = {
compilerOptions : options ,
host : host ,
skipTsx : true ,
traceEnabled
} ;
if ( traceEnabled ) {
trace ( host , Diagnostics . Resolving_type_reference_directive_0_from_1_with_compilation_root_dir_2 , typeReferenceDirectiveName , containingFile , compilationRoot ) ;
}
const failedLookupLocations : string [ ] = [ ] ;
// Check primary library paths
for ( const searchPath of getEffectiveTypesPrimarySearchPaths ( options ) ) {
const primaryPath = combinePaths ( compilationRoot , searchPath ) ;
if ( traceEnabled ) {
trace ( host , Diagnostics . Resolving_with_primary_search_path_0 , primaryPath ) ;
}
const resolvedFile = tryLoadTypeDeclarationFile ( combinePaths ( primaryPath , typeReferenceDirectiveName ) , failedLookupLocations , 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
} ;
}
}
if ( traceEnabled ) {
trace ( host , Diagnostics . Resolving_from_node_modules_folder ) ;
}
// check secondary locations
const resolvedFile = loadModuleFromNodeModules ( typeReferenceDirectiveName , getDirectoryPath ( containingFile ) , 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 ) ;
}
}
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
2015-11-19 06:46:45 +01:00
let longestMatchPrefixLength = - 1 ;
let matchedPattern : string ;
let matchedStar : string ;
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-01-25 20:49:26 +01:00
for ( const key in state . compilerOptions . paths ) {
2015-11-19 06:46:45 +01:00
const pattern : string = key ;
const indexOfStar = pattern . indexOf ( "*" ) ;
if ( indexOfStar !== - 1 ) {
const prefix = pattern . substr ( 0 , indexOfStar ) ;
const suffix = pattern . substr ( indexOfStar + 1 ) ;
if ( module Name.length >= prefix . length + suffix . length &&
startsWith ( module Name , prefix ) &&
endsWith ( module Name , suffix ) ) {
// use length of prefix as betterness criteria
if ( prefix . length > longestMatchPrefixLength ) {
longestMatchPrefixLength = prefix . length ;
matchedPattern = pattern ;
matchedStar = module Name.substr ( prefix . length , module Name.length - suffix . length ) ;
}
}
}
else if ( pattern === module Name ) {
2016-02-11 17:56:45 +01:00
// pattern was matched as is - no need to search further
2015-11-19 06:46:45 +01:00
matchedPattern = pattern ;
matchedStar = undefined ;
break ;
}
}
}
if ( matchedPattern ) {
2016-01-25 20:49:26 +01:00
if ( state . traceEnabled ) {
trace ( state . host , Diagnostics . Module_name_0_matched_pattern_1 , module Name , matchedPattern ) ;
2015-11-20 06:33:33 +01:00
}
2016-01-25 20:49:26 +01:00
for ( const subst of state . compilerOptions . paths [ matchedPattern ] ) {
2015-11-19 06:46:45 +01:00
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
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-01-25 20:49:26 +01:00
if ( resolvedFileName ) {
return createResolvedModule ( resolvedFileName , /*isExternalLibraryImport*/ false , failedLookupLocations ) ;
2015-08-18 03:31:12 +02:00
}
2015-10-01 01:10:52 +02:00
2016-01-25 20:49:26 +01:00
let isExternalLibraryImport = false ;
if ( module HasNonRelativeName ( module Name ) ) {
2015-11-20 06:33:33 +01:00
if ( traceEnabled ) {
trace ( host , Diagnostics . Loading_module_0_from_node_modules_folder , module Name ) ;
}
2016-01-25 20:49:26 +01:00
resolvedFileName = loadModuleFromNodeModules ( module Name , containingDirectory , failedLookupLocations , state ) ;
isExternalLibraryImport = resolvedFileName !== undefined ;
2015-08-18 03:31:12 +02:00
}
else {
2016-01-25 20:49:26 +01:00
const candidate = normalizePath ( combinePaths ( containingDirectory , module Name ) ) ;
resolvedFileName = nodeLoadModuleByRelativeName ( candidate , supportedExtensions , failedLookupLocations , /*onlyRecordFailures*/ false , state ) ;
}
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-04-01 21:41:01 +02:00
if ( ! onlyRecordFailures ) {
// check if containig folder exists - if it doesn't then just record failures for all supported extensions without disk probing
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-02-02 00:19:13 +01:00
if ( ext === ".tsx" && state . skipTsx ) {
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 {
2015-11-04 23:02:33 +01:00
const packageJsonPath = combinePaths ( candidate , "package.json" ) ;
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-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 ) ) ;
// Load only typescript files irrespective of allowJs option if loading from node modules
let result = loadModuleFromFile ( candidate , supportedTypeScriptExtensions , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
if ( result ) {
return result ;
}
result = loadNodeModuleFromDirectory ( supportedTypeScriptExtensions , candidate , failedLookupLocations , ! nodeModulesFolderExists , state ) ;
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-04-01 21:41:01 +02:00
const result =
// first: try to load module as-is
loadModuleFromNodeModulesFolder ( module Name , directory , failedLookupLocations , state ) ||
// second: try to load module from the scope '@types'
loadModuleFromNodeModulesFolder ( combinePaths ( "@types" , module Name ) , directory , failedLookupLocations , state ) ;
2015-08-18 03:31:12 +02:00
if ( result ) {
2016-01-25 20:49:26 +01:00
return result ;
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
2015-03-18 22:11:50 +01:00
export function createCompilerHost ( options : CompilerOptions , setParentNodes? : boolean ) : CompilerHost {
2015-11-04 23:02:33 +01:00
const existingDirectories : Map < 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 {
2015-11-04 23:02:33 +01:00
const start = new Date ( ) . getTime ( ) ;
2015-03-13 23:03:17 +01:00
text = sys . readFile ( fileName , options . charset ) ;
2015-02-26 23:51:04 +01:00
ioReadTime += new Date ( ) . getTime ( ) - start ;
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
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 {
2015-11-04 23:02:33 +01:00
const start = new Date ( ) . getTime ( ) ;
2014-12-16 22:14:14 +01:00
ensureDirectoriesExist ( getDirectoryPath ( normalizePath ( fileName ) ) ) ;
sys . writeFile ( fileName , data , writeByteOrderMark ) ;
2015-03-13 22:49:32 +01:00
ioWriteTime += new Date ( ) . getTime ( ) - start ;
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 ) ;
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-01-06 21:37:52 +01:00
directoryExists : directoryName = > sys . directoryExists ( directoryName )
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 ) ;
}
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 [ ] = [ ] ;
const cache : Map < T > = { } ;
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 ;
}
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-04-01 21:41:01 +02:00
let resolvedTypeReferenceDirectives : Map < ResolvedTypeReferenceDirective > = { } ;
let fileProcessingDiagnostics = createDiagnosticCollection ( ) ;
2015-06-08 23:45:38 +02:00
let skipDefaultLib = options . noLib ;
2016-04-01 21:41:01 +02:00
const programDiagnostics = createDiagnosticCollection ( ) ;
const currentDirectory = host . getCurrentDirectory ( ) ;
2015-11-06 21:39:42 +01:00
const supportedExtensions = getSupportedExtensions ( options ) ;
2015-05-01 03:14:53 +02:00
2015-11-04 23:02:33 +01:00
const start = new Date ( ) . getTime ( ) ;
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
const compilationRoot = computeCompilationRoot ( rootNames , currentDirectory , options , getCanonicalFileName ) ;
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 {
const loader = ( typesRef : string , containingFile : string ) = > resolveTypeReferenceDirective ( typesRef , containingFile , compilationRoot , options , host ) . resolvedTypeReferenceDirective ;
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
2015-06-25 02:40:04 +02:00
if ( oldProgram ) {
2015-07-09 23:40:33 +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
2015-11-04 23:02:33 +01:00
const oldOptions = oldProgram . getCompilerOptions ( ) ;
2015-10-01 01:10:52 +02:00
if ( ( oldOptions . module !== options . module ) ||
( oldOptions . noResolve !== options . noResolve ) ||
( oldOptions . target !== options . target ) ||
2015-08-05 06:22:37 +02:00
( oldOptions . noLib !== options . noLib ) ||
2015-10-06 01:42:37 +02:00
( oldOptions . jsx !== options . jsx ) ||
2016-04-01 21:41:01 +02:00
( oldOptions . allowJs !== options . allowJs ) ||
( oldOptions . rootDir !== options . rootDir ) ||
( oldOptions . typesSearchPaths !== options . typesSearchPaths ) ||
( oldOptions . configFilePath !== options . configFilePath ) ) {
2015-06-25 02:40:04 +02:00
oldProgram = undefined ;
}
2015-06-24 06:06:57 +02:00
}
2015-10-01 01:10:52 +02:00
2015-06-24 06:06:57 +02:00
if ( ! tryReuseStructureFromOldProgram ( ) ) {
2015-11-14 02:43:53 +01:00
forEach ( rootNames , name = > processRootFile ( name , /*isDefaultLib*/ false ) ) ;
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 ,
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 ,
resolvedTypeReferenceDirectives
2014-12-16 22:14:14 +01:00
} ;
2015-10-12 21:25:13 +02:00
verifyCompilerOptions ( ) ;
programTime += new Date ( ) . getTime ( ) - start ;
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 ( ) ;
2015-06-12 21:53:24 +02:00
classifiableNames = { } ;
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
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
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 ( ) ) {
2015-06-25 02:40:04 +02:00
let newSourceFile = host . getSourceFile ( oldSourceFile . fileName , options . target ) ;
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-01 21:41:01 +02:00
resolvedTypeReferenceDirectives = oldProgram . resolvedTypeReferenceDirectives ;
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 ,
getSourceFiles : program.getSourceFiles ,
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 {
2015-06-18 19:52:19 +02:00
return runWithCancellationToken ( ( ) = > emitWorker ( this , sourceFile , writeFileCallback , cancellationToken ) ) ;
}
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-02-18 21:06:17 +01:00
return { diagnostics : declarationDiagnostics , sourceMaps : 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 ,
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
2015-11-04 23:02:33 +01:00
const start = new Date ( ) . getTime ( ) ;
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
emitTime += new Date ( ) . getTime ( ) - start ;
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 {
2015-10-30 00:43:12 +01:00
return filesByName . get ( toPath ( fileName , currentDirectory , getCanonicalFileName ) ) ;
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 :
diagnostics . push ( createDiagnosticForNode ( node , Diagnostics . property_declarations_can_only_be_used_in_a_ts_file ) ) ;
return true ;
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
// NOTE: body of ambient module is always a module block
for ( const statement of ( < ModuleBlock > ( < ModuleDeclaration > node ) . body ) . statements ) {
collectModuleReferences ( statement , /*inAmbientModule*/ true ) ;
}
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-03-02 19:52:16 +01:00
if ( file ) {
file . wasReferenced = file . wasReferenced || isReference ;
}
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-03-02 19:52:16 +01:00
file . wasReferenced = file . wasReferenced || isReference ;
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 ) ;
processTypeReferenceDirectives ( file , compilationRoot ) ;
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-01 21:41:01 +02:00
function processTypeReferenceDirectives ( file : SourceFile , compilationRoot : string ) {
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-02-23 21:48:31 +01:00
// If we already found this library as a primary reference, or failed to find it, nothing to do
2016-04-01 21:41:01 +02:00
const previousResolution = resolvedTypeReferenceDirectives [ ref . fileName ] ;
2016-02-23 21:48:31 +01:00
if ( previousResolution && ( previousResolution . primary || ( previousResolution . resolvedFileName === undefined ) ) ) {
continue ;
}
2016-04-01 21:41:01 +02:00
let saveResolution = true ;
if ( resolvedTypeReferenceDirective ) {
if ( resolvedTypeReferenceDirective . primary ) {
// resolved from the primary path
processSourceFile ( resolvedTypeReferenceDirective . resolvedFileName , /*isDefaultLib*/ false , /*isReference*/ true , file , ref . pos , ref . end ) ;
2016-02-23 21:48:31 +01:00
}
2016-04-01 21:41:01 +02:00
else {
2016-02-23 21:48:31 +01:00
// 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 ) {
2016-04-01 21:41:01 +02:00
const otherFileText = host . readFile ( resolvedTypeReferenceDirective . resolvedFileName ) ;
2016-02-23 21:48:31 +01:00
if ( otherFileText !== getSourceFile ( previousResolution . resolvedFileName ) . text ) {
fileProcessingDiagnostics . add ( createFileDiagnostic ( file , ref . pos , ref . end - ref . pos ,
2016-03-23 19:41:34 +01:00
Diagnostics . Conflicting_library_definitions_for_0_found_at_1_and_2_Copy_the_correct_file_to_the_typings_folder_to_resolve_this_conflict ,
2016-02-23 21:48:31 +01:00
ref . fileName ,
2016-04-01 21:41:01 +02:00
resolvedTypeReferenceDirective . resolvedFileName ,
2016-02-23 21:48:31 +01:00
previousResolution . resolvedFileName ) ) ;
}
2016-04-01 21:41:01 +02:00
// don't overwrite previous resolution result
saveResolution = false ;
2016-02-23 21:48:31 +01:00
}
else {
// First resolution of this library
2016-04-01 21:41:01 +02:00
processSourceFile ( resolvedTypeReferenceDirective . resolvedFileName , /*isDefaultLib*/ false , /*isReference*/ true , file , ref . pos , ref . end ) ;
2016-02-23 21:48:31 +01:00
}
}
}
2016-04-01 21:41:01 +02:00
else {
2016-02-23 21:48:31 +01:00
fileProcessingDiagnostics . add ( createFileDiagnostic ( file , ref . pos , ref . end - ref . pos , Diagnostics . Cannot_find_name_0 , ref . fileName ) ) ;
}
2016-04-01 21:41:01 +02:00
if ( saveResolution ) {
resolvedTypeReferenceDirectives [ ref . fileName ] = resolvedTypeReferenceDirective ;
}
}
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 ) {
2015-06-25 03:12:02 +02:00
file . resolvedModules = { } ;
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 ) ;
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
// - module name come from the list fo imports
const shouldAddFile = resolution &&
! options . noResolve &&
i < file . imports . length ;
if ( shouldAddFile ) {
2016-03-02 19:52:16 +01:00
const importedFile = findSourceFile ( resolution . resolvedFileName , toPath ( resolution . resolvedFileName , currentDirectory , getCanonicalFileName ) , /*isDefaultLib*/ false , /*isReference*/ false , file , skipTrivia ( file . text , file . imports [ i ] . pos ) , file . imports [ i ] . end ) ;
2015-10-15 23:43:51 +02:00
2015-09-11 01:42:02 +02:00
if ( importedFile && resolution . isExternalLibraryImport ) {
2015-11-30 22:59:03 +01:00
// Since currently irrespective of allowJs, we only look for supportedTypeScript extension external module files,
// this check is ok. Otherwise this would be never true for javascript file
2016-02-02 20:36:38 +01:00
if ( ! isExternalModule ( importedFile ) && importedFile . statements . length ) {
2015-11-04 23:02:33 +01:00
const start = getTokenPosOfNode ( file . imports [ i ] , file ) ;
2015-09-27 06:29:07 +02:00
fileProcessingDiagnostics . add ( createFileDiagnostic ( file , start , file . imports [ i ] . end - start , Diagnostics . Exported_external_package_typings_file_0_is_not_a_module_Please_contact_the_package_author_to_update_the_package_definition , importedFile . fileName ) ) ;
2015-09-10 20:36:31 +02:00
}
else if ( importedFile . referencedFiles . length ) {
2015-11-04 23:02:33 +01:00
const firstRef = importedFile . referencedFiles [ 0 ] ;
2015-09-11 02:00:29 +02:00
fileProcessingDiagnostics . add ( createFileDiagnostic ( importedFile , firstRef . pos , firstRef . end - firstRef . pos , Diagnostics . Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition ) ) ;
2015-09-10 20:36:31 +02:00
}
}
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 ) ) ;
}
for ( const subst of options . paths [ key ] ) {
if ( ! hasZeroOrOneAsteriskCharacter ( subst ) ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character , subst , key ) ) ;
}
}
}
}
2015-04-21 05:33:31 +02:00
if ( options . inlineSources ) {
if ( ! options . sourceMap && ! options . inlineSourceMap ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_inlineSources_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided ) ) ;
2015-04-08 09:14:23 +02:00
}
2015-11-11 21:58:31 +01:00
if ( options . sourceRoot ) {
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_with_option_1 , "sourceRoot" , "inlineSources" ) ) ;
}
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
}
2014-12-16 22:14:14 +01:00
if ( ! options . sourceMap && ( options . mapRoot || options . sourceRoot ) ) {
// Error to specify --mapRoot or --sourceRoot without mapSourceFiles
if ( options . mapRoot ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_without_specifying_option_1 , "mapRoot" , "sourceMap" ) ) ;
2014-12-16 22:14:14 +01:00
}
2015-11-11 21:58:31 +01:00
if ( options . sourceRoot && ! options . inlineSourceMap ) {
2015-09-10 19:46:39 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Option_0_cannot_be_specified_without_specifying_option_1 , "sourceRoot" , "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
2015-11-04 23:02:33 +01:00
const firstExternalModuleSourceFile = forEach ( files , f = > isExternalModule ( 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-02-11 20:53:10 +01:00
else if ( firstExternalModuleSourceFile && 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
const span = getErrorSpanForNode ( firstExternalModuleSourceFile , firstExternalModuleSourceFile . externalModuleIndicator ) ;
2016-02-11 21:45:52 +01:00
programDiagnostics . add ( createFileDiagnostic ( firstExternalModuleSourceFile , span . start , span . length , Diagnostics . Cannot_compile_modules_unless_the_module_flag_is_provided_with_a_valid_module_type_Consider_setting_the_module_compiler_option_in_a_tsconfig_json_file ) ) ;
2016-02-11 20:01:10 +01:00
}
2015-03-12 06:53:36 +01:00
2015-09-17 22:14:31 +02:00
// Cannot specify module gen target of es6 when below es6
if ( options . module === ModuleKind . ES6 && languageVersion < ScriptTarget . ES6 ) {
2015-10-22 22:23:12 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Cannot_compile_modules_into_es2015_when_targeting_ES5_or_lower ) ) ;
2015-09-17 22:14:31 +02:00
}
2015-10-05 23:25:48 +02:00
// Cannot specify module gen that isn't amd or system with --out
2015-10-30 22:52:45 +01:00
if ( outFile && options . module && ! ( options . module === ModuleKind . AMD || options . module === ModuleKind . System ) ) {
2015-10-03 02:43:58 +02:00
programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Only_amd_and_system_modules_are_supported_alongside_0 , options . out ? "out" : "outFile" ) ) ;
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
}