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-06-23 02:48:44 +02:00
|
|
|
|
2015-07-30 02:16:58 +02:00
|
|
|
let emptyArray: any[] = [];
|
2015-06-23 02:48:44 +02:00
|
|
|
|
2015-07-15 02:25:34 +02:00
|
|
|
export const version = "1.6.0";
|
2015-03-07 02:09:55 +01:00
|
|
|
|
2015-03-24 22:03:21 +01:00
|
|
|
export function findConfigFile(searchPath: string): string {
|
2015-06-26 02:36:19 +02:00
|
|
|
let fileName = "tsconfig.json";
|
2015-03-24 22:03:21 +01:00
|
|
|
while (true) {
|
|
|
|
if (sys.fileExists(fileName)) {
|
|
|
|
return fileName;
|
|
|
|
}
|
2015-06-26 02:36:19 +02:00
|
|
|
let parentPath = getDirectoryPath(searchPath);
|
2015-03-24 22:03:21 +01:00
|
|
|
if (parentPath === searchPath) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
searchPath = parentPath;
|
|
|
|
fileName = "../" + fileName;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
2015-07-14 02:44:50 +02:00
|
|
|
|
|
|
|
export function resolveTripleslashReference(moduleName: string, containingFile: string): string {
|
|
|
|
let basePath = getDirectoryPath(containingFile);
|
|
|
|
let referencedFileName = isRootedDiskPath(moduleName) ? moduleName : combinePaths(basePath, moduleName);
|
|
|
|
return normalizePath(referencedFileName);
|
|
|
|
}
|
2015-08-05 23:30:41 +02:00
|
|
|
|
|
|
|
export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
|
2015-08-21 01:13:49 +02:00
|
|
|
let moduleResolution = compilerOptions.moduleResolution !== undefined
|
|
|
|
? compilerOptions.moduleResolution
|
|
|
|
: compilerOptions.module === ModuleKind.CommonJS ? ModuleResolutionKind.NodeJs : ModuleResolutionKind.Classic;
|
|
|
|
|
|
|
|
switch (moduleResolution) {
|
2015-08-18 22:36:08 +02:00
|
|
|
case ModuleResolutionKind.NodeJs: return nodeModuleNameResolver(moduleName, containingFile, host);
|
2015-08-21 01:13:49 +02:00
|
|
|
case ModuleResolutionKind.Classic: return classicNameResolver(moduleName, containingFile, compilerOptions, host);
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-18 22:36:08 +02:00
|
|
|
export function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModule {
|
2015-08-18 03:31:12 +02:00
|
|
|
let containingDirectory = getDirectoryPath(containingFile);
|
|
|
|
|
|
|
|
if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) {
|
|
|
|
let failedLookupLocations: string[] = [];
|
|
|
|
let candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
2015-08-21 01:13:49 +02:00
|
|
|
let resolvedFileName = loadNodeModuleFromFile(candidate, /* loadOnlyDts */ false, failedLookupLocations, host);
|
2015-08-18 03:31:12 +02:00
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
if (resolvedFileName) {
|
|
|
|
return { resolvedFileName, failedLookupLocations };
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
resolvedFileName = loadNodeModuleFromDirectory(candidate, /* loadOnlyDts */ false, failedLookupLocations, host);
|
|
|
|
return { resolvedFileName, failedLookupLocations };
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
else {
|
2015-08-21 01:13:49 +02:00
|
|
|
return loadModuleFromNodeModules(moduleName, containingDirectory, host);
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
function loadNodeModuleFromFile(candidate: string, loadOnlyDts: boolean, failedLookupLocation: string[], host: ModuleResolutionHost): string {
|
|
|
|
if (loadOnlyDts) {
|
|
|
|
return tryLoad(".d.ts");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return forEach(supportedExtensions, tryLoad);
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
function tryLoad(ext: string): string {
|
|
|
|
let fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
|
|
|
|
if (host.fileExists(fileName)) {
|
|
|
|
return fileName;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
failedLookupLocation.push(fileName);
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
function loadNodeModuleFromDirectory(candidate: string, loadOnlyDts: boolean, failedLookupLocation: string[], host: ModuleResolutionHost): string {
|
2015-08-18 03:31:12 +02:00
|
|
|
let packageJsonPath = combinePaths(candidate, "package.json");
|
|
|
|
if (host.fileExists(packageJsonPath)) {
|
2015-08-21 01:13:49 +02:00
|
|
|
|
|
|
|
let jsonContent: { typings?: string };
|
|
|
|
|
|
|
|
try {
|
|
|
|
let jsonText = host.readFile(packageJsonPath);
|
|
|
|
jsonContent = jsonText ? <{ typings?: string }>JSON.parse(jsonText) : { typings: undefined };
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
// gracefully handle if readFile fails or returns not JSON
|
|
|
|
jsonContent = { typings: undefined };
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
if (jsonContent.typings) {
|
|
|
|
let result = loadNodeModuleFromFile(normalizePath(combinePaths(candidate, jsonContent.typings)), loadOnlyDts, failedLookupLocation, host);
|
2015-08-18 03:31:12 +02:00
|
|
|
if (result) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// 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-08-21 01:13:49 +02:00
|
|
|
return loadNodeModuleFromFile(combinePaths(candidate, "index"), loadOnlyDts, failedLookupLocation, host);
|
2015-08-18 03:31:12 +02:00
|
|
|
}
|
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModule {
|
2015-08-18 03:31:12 +02:00
|
|
|
let failedLookupLocations: string[] = [];
|
|
|
|
directory = normalizeSlashes(directory);
|
|
|
|
while (true) {
|
|
|
|
let baseName = getBaseFileName(directory);
|
|
|
|
if (baseName !== "node_modules") {
|
|
|
|
let nodeModulesFolder = combinePaths(directory, "node_modules");
|
|
|
|
let candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
2015-08-21 01:13:49 +02:00
|
|
|
let result = loadNodeModuleFromFile(candidate, /* loadOnlyDts */ true, failedLookupLocations, host);
|
2015-08-18 03:31:12 +02:00
|
|
|
if (result) {
|
|
|
|
return { resolvedFileName: result, failedLookupLocations };
|
|
|
|
}
|
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
result = loadNodeModuleFromDirectory(candidate, /* loadOnlyDts */ true, failedLookupLocations, host);
|
2015-08-18 03:31:12 +02:00
|
|
|
if (result) {
|
|
|
|
return { resolvedFileName: result, failedLookupLocations };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let parentPath = getDirectoryPath(directory);
|
|
|
|
if (parentPath === directory) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
directory = parentPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
return { resolvedFileName: undefined, failedLookupLocations };
|
|
|
|
}
|
|
|
|
|
2015-08-18 22:36:08 +02:00
|
|
|
export function baseUrlModuleNameResolver(moduleName: string, containingFile: string, baseUrl: string, host: ModuleResolutionHost): ResolvedModule {
|
|
|
|
Debug.assert(baseUrl !== undefined);
|
2015-08-18 03:31:12 +02:00
|
|
|
|
2015-08-18 22:36:08 +02:00
|
|
|
let normalizedModuleName = normalizeSlashes(moduleName);
|
|
|
|
let basePart = useBaseUrl(moduleName) ? baseUrl : getDirectoryPath(containingFile);
|
2015-08-18 03:31:12 +02:00
|
|
|
let candidate = normalizePath(combinePaths(basePart, moduleName));
|
|
|
|
|
|
|
|
let failedLookupLocations: string[] = [];
|
2015-08-18 22:36:08 +02:00
|
|
|
|
2015-08-18 23:52:21 +02:00
|
|
|
return forEach(supportedExtensions, ext => tryLoadFile(candidate + ext)) || { resolvedFileName: undefined, failedLookupLocations };
|
2015-08-18 03:31:12 +02:00
|
|
|
|
|
|
|
function tryLoadFile(location: string): ResolvedModule {
|
|
|
|
if (host.fileExists(location)) {
|
|
|
|
return { resolvedFileName: location, failedLookupLocations };
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
failedLookupLocations.push(location);
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function nameStartsWithDotSlashOrDotDotSlash(name: string) {
|
|
|
|
let i = name.lastIndexOf("./", 1);
|
|
|
|
return i === 0 || (i === 1 && name.charCodeAt(0) === CharacterCodes.dot);
|
|
|
|
}
|
|
|
|
|
|
|
|
function useBaseUrl(moduleName: string): boolean {
|
2015-08-18 23:52:21 +02:00
|
|
|
// path is not rooted
|
|
|
|
// module name does not start with './' or '../'
|
|
|
|
return getRootLength(moduleName) === 0 && !nameStartsWithDotSlashOrDotDotSlash(moduleName);
|
2015-08-05 23:30:41 +02:00
|
|
|
}
|
2015-07-14 02:44:50 +02:00
|
|
|
|
2015-08-21 01:13:49 +02:00
|
|
|
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
|
2015-07-30 01:24:16 +02:00
|
|
|
|
|
|
|
// module names that contain '!' are used to reference resources and are not resolved to actual files on disk
|
|
|
|
if (moduleName.indexOf('!') != -1) {
|
|
|
|
return { resolvedFileName: undefined, failedLookupLocations: [] };
|
|
|
|
}
|
|
|
|
|
2015-07-14 02:44:50 +02:00
|
|
|
let searchPath = getDirectoryPath(containingFile);
|
|
|
|
let searchName: string;
|
|
|
|
|
|
|
|
let failedLookupLocations: string[] = [];
|
|
|
|
|
|
|
|
let referencedSourceFile: string;
|
|
|
|
while (true) {
|
|
|
|
searchName = normalizePath(combinePaths(searchPath, moduleName));
|
|
|
|
referencedSourceFile = forEach(supportedExtensions, extension => {
|
2015-07-30 01:24:16 +02:00
|
|
|
if (extension === ".tsx" && !compilerOptions.jsx) {
|
|
|
|
// resolve .tsx files only if jsx support is enabled
|
|
|
|
// 'logical not' handles both undefined and None cases
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2015-07-14 02:44:50 +02:00
|
|
|
let candidate = searchName + extension;
|
|
|
|
if (host.fileExists(candidate)) {
|
|
|
|
return candidate;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
failedLookupLocations.push(candidate);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (referencedSourceFile) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let parentPath = getDirectoryPath(searchPath);
|
|
|
|
if (parentPath === searchPath) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
searchPath = parentPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
return { resolvedFileName: referencedSourceFile, failedLookupLocations };
|
|
|
|
}
|
2015-03-24 22:03:21 +01:00
|
|
|
|
2015-07-29 04:26:18 +02:00
|
|
|
export const defaultInitCompilerOptions: CompilerOptions = {
|
|
|
|
module: ModuleKind.CommonJS,
|
|
|
|
target: ScriptTarget.ES3,
|
|
|
|
noImplicitAny: false,
|
|
|
|
outDir: "built",
|
|
|
|
rootDir: ".",
|
|
|
|
sourceMap: false,
|
|
|
|
}
|
|
|
|
|
2015-08-25 09:05:02 +02:00
|
|
|
export function scriptTargetToString(target: ScriptTarget): string {
|
|
|
|
switch (target) {
|
|
|
|
case ScriptTarget.ES5:
|
|
|
|
return "es5";
|
|
|
|
case ScriptTarget.ES6:
|
|
|
|
return "es6";
|
|
|
|
default:
|
|
|
|
return "es3";
|
2015-07-29 04:26:18 +02:00
|
|
|
}
|
2015-08-25 09:05:02 +02:00
|
|
|
}
|
2015-07-29 04:26:18 +02:00
|
|
|
|
2015-08-25 09:05:02 +02:00
|
|
|
export function moduleKindToString(kind: ModuleKind): string {
|
|
|
|
switch (kind) {
|
|
|
|
case ModuleKind.None:
|
|
|
|
return undefined;
|
|
|
|
case ModuleKind.CommonJS:
|
|
|
|
return "commonjs";
|
|
|
|
case ModuleKind.System:
|
|
|
|
return "system";
|
|
|
|
case ModuleKind.UMD:
|
|
|
|
return "umd";
|
|
|
|
default:
|
|
|
|
return "amd";
|
2015-07-29 04:26:18 +02:00
|
|
|
}
|
2015-08-25 09:05:02 +02:00
|
|
|
}
|
2015-07-29 04:26:18 +02:00
|
|
|
|
2015-08-25 09:05:02 +02:00
|
|
|
export function newLineKindToString(kind: NewLineKind): string {
|
|
|
|
switch (kind) {
|
|
|
|
case NewLineKind.CarriageReturnLineFeed:
|
|
|
|
return "CRLF";
|
|
|
|
default:
|
|
|
|
return "LF";
|
2015-07-29 04:26:18 +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-03-13 23:03:17 +01:00
|
|
|
let currentDirectory: string;
|
|
|
|
let 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-03-13 23:03:17 +01:00
|
|
|
let 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-03-13 23:03:17 +01:00
|
|
|
let start = new Date().getTime();
|
|
|
|
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-03-17 14:26:24 +01:00
|
|
|
let 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-06-26 02:36:19 +02:00
|
|
|
let 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-27 05:18:13 +02:00
|
|
|
const newLine = getNewLineCharacter(options);
|
2015-07-14 02:44:50 +02:00
|
|
|
|
2015-08-05 06:22:37 +02:00
|
|
|
|
2014-12-16 22:14:14 +01:00
|
|
|
return {
|
|
|
|
getSourceFile,
|
2015-02-04 01:08:46 +01:00
|
|
|
getDefaultLibFileName: options => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), getDefaultLibFileName(options)),
|
2014-12-16 22:14:14 +01:00
|
|
|
writeFile,
|
|
|
|
getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()),
|
|
|
|
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),
|
|
|
|
readFile: fileName => sys.readFile(fileName)
|
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-06-18 20:23:14 +02:00
|
|
|
let diagnostics = program.getOptionsDiagnostics(cancellationToken).concat(
|
|
|
|
program.getSyntacticDiagnostics(sourceFile, cancellationToken),
|
|
|
|
program.getGlobalDiagnostics(cancellationToken),
|
2015-06-18 19:52:19 +02:00
|
|
|
program.getSemanticDiagnostics(sourceFile, cancellationToken));
|
2015-03-20 00:55:07 +01:00
|
|
|
|
|
|
|
if (program.getCompilerOptions().declaration) {
|
2015-06-18 19:52:19 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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[] = [];
|
|
|
|
let diagnostics = createDiagnosticCollection();
|
2015-06-17 20:08:13 +02:00
|
|
|
|
2015-03-13 23:03:17 +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
|
|
|
|
2015-06-08 23:45:38 +02:00
|
|
|
let skipDefaultLib = options.noLib;
|
2015-05-01 03:14:53 +02:00
|
|
|
|
2015-03-17 14:26:24 +01:00
|
|
|
let start = new Date().getTime();
|
2014-12-16 22:14:14 +01:00
|
|
|
|
2015-03-17 14:26:24 +01:00
|
|
|
host = host || createCompilerHost(options);
|
2015-07-14 02:44:50 +02:00
|
|
|
|
2015-08-19 20:58:02 +02:00
|
|
|
const resolveModuleNamesWorker =
|
|
|
|
host.resolveModuleNames ||
|
|
|
|
((moduleNames, containingFile) => map(moduleNames, moduleName => resolveModuleName(moduleName, containingFile, options, host).resolvedFileName));
|
2015-05-01 03:14:53 +02:00
|
|
|
|
2015-06-05 21:00:53 +02:00
|
|
|
let filesByName = createFileMap<SourceFile>(fileName => host.getCanonicalFileName(fileName));
|
2015-06-23 02:48:44 +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-06-25 02:40:04 +02:00
|
|
|
let oldOptions = oldProgram.getCompilerOptions();
|
|
|
|
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) ||
|
|
|
|
(oldOptions.jsx !== options.jsx)) {
|
2015-06-25 02:40:04 +02:00
|
|
|
oldProgram = undefined;
|
|
|
|
}
|
2015-06-24 06:06:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!tryReuseStructureFromOldProgram()) {
|
2015-06-23 02:48:44 +02:00
|
|
|
forEach(rootNames, name => processRootFile(name, false));
|
|
|
|
// 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) {
|
|
|
|
processRootFile(host.getDefaultLibFileName(options), true);
|
|
|
|
}
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
2015-05-01 03:14:53 +02:00
|
|
|
|
2014-12-16 22:14:14 +01:00
|
|
|
verifyCompilerOptions();
|
2014-12-18 09:39:56 +01:00
|
|
|
|
2015-07-09 23:45:39 +02:00
|
|
|
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
|
|
|
|
oldProgram = undefined;
|
|
|
|
|
2015-03-17 14:26:24 +01:00
|
|
|
programTime += new Date().getTime() - start;
|
2014-12-16 22:14:14 +01:00
|
|
|
|
|
|
|
program = {
|
2015-06-23 02:48:44 +02:00
|
|
|
getRootFileNames: () => rootNames,
|
2014-12-16 22:14:14 +01:00
|
|
|
getSourceFile: getSourceFile,
|
|
|
|
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,
|
2014-12-16 22:14:14 +01:00
|
|
|
getCommonSourceDirectory: () => commonSourceDirectory,
|
2015-02-05 01:53:14 +01:00
|
|
|
emit,
|
2015-03-24 18:05:24 +01:00
|
|
|
getCurrentDirectory: () => host.getCurrentDirectory(),
|
2015-02-05 01:11:38 +01:00
|
|
|
getNodeCount: () => getDiagnosticsProducingTypeChecker().getNodeCount(),
|
|
|
|
getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(),
|
|
|
|
getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(),
|
|
|
|
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
|
2014-12-16 22:14:14 +01:00
|
|
|
};
|
|
|
|
return program;
|
|
|
|
|
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
|
|
|
|
|
|
|
for (let 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-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
|
|
|
|
let 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if program source files has changed in the way that can affect structure of the program
|
|
|
|
let newSourceFiles: SourceFile[] = [];
|
|
|
|
for (let 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-07-09 23:40:33 +02:00
|
|
|
if (oldSourceFile !== newSourceFile) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check imports
|
2015-08-20 00:37:37 +02:00
|
|
|
collectExternalModuleReferences(newSourceFile);
|
2015-06-23 02:48:44 +02:00
|
|
|
if (!arrayIsEqualTo(oldSourceFile.imports, newSourceFile.imports, moduleNameIsEqualTo)) {
|
|
|
|
// imports has changed
|
|
|
|
return false;
|
|
|
|
}
|
2015-08-03 20:06:23 +02:00
|
|
|
|
2015-08-04 02:42:29 +02:00
|
|
|
if (resolveModuleNamesWorker) {
|
|
|
|
let moduleNames = map(newSourceFile.imports, name => name.text);
|
|
|
|
let resolutions = resolveModuleNamesWorker(moduleNames, newSourceFile.fileName);
|
2015-08-03 20:06:23 +02:00
|
|
|
// ensure that module resolution results are still correct
|
2015-08-04 02:42:29 +02:00
|
|
|
for (let i = 0; i < moduleNames.length; ++i) {
|
|
|
|
let oldResolution = getResolvedModuleFileName(oldSourceFile, moduleNames[i]);
|
|
|
|
if (oldResolution !== resolutions[i]) {
|
2015-08-03 20:06:23 +02:00
|
|
|
return false;
|
2015-08-04 02:42:29 +02:00
|
|
|
}
|
|
|
|
}
|
2015-08-03 20:06:23 +02:00
|
|
|
}
|
2015-06-24 06:06:57 +02:00
|
|
|
// pass the cache of module resolutions from the old source file
|
|
|
|
newSourceFile.resolvedModules = oldSourceFile.resolvedModules;
|
2015-06-23 02:48:44 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// file has no changes - use it as is
|
|
|
|
newSourceFile = oldSourceFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if file has passed all checks it should be safe to reuse it
|
|
|
|
newSourceFiles.push(newSourceFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
// update fileName -> file mapping
|
|
|
|
for (let file of newSourceFiles) {
|
|
|
|
filesByName.set(file.fileName, file);
|
|
|
|
}
|
|
|
|
|
|
|
|
files = newSourceFiles;
|
|
|
|
|
2015-06-24 06:06:57 +02:00
|
|
|
oldProgram.structureIsReused = true;
|
|
|
|
|
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-03-24 18:05:24 +01:00
|
|
|
getCanonicalFileName: fileName => host.getCanonicalFileName(fileName),
|
2015-02-05 01:53:14 +01:00
|
|
|
getCommonSourceDirectory: program.getCommonSourceDirectory,
|
|
|
|
getCompilerOptions: program.getCompilerOptions,
|
2015-03-24 18:05:24 +01:00
|
|
|
getCurrentDirectory: () => host.getCurrentDirectory(),
|
|
|
|
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 || (
|
|
|
|
(fileName, data, writeByteOrderMark, onError) => host.writeFile(fileName, data, writeByteOrderMark, onError)),
|
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-06-18 21:04:26 +02:00
|
|
|
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken): EmitResult {
|
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-06-18 19:52:19 +02:00
|
|
|
if (options.noEmitOnError && getPreEmitDiagnostics(program, /*sourceFile:*/ undefined, cancellationToken).length > 0) {
|
2015-02-06 00:50:18 +01:00
|
|
|
return { diagnostics: [], sourceMaps: undefined, emitSkipped: true };
|
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-08-21 02:37:56 +02:00
|
|
|
let emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out)? undefined : sourceFile);
|
2015-02-26 01:45:45 +01:00
|
|
|
|
2015-03-13 23:03:17 +01:00
|
|
|
let start = new Date().getTime();
|
2015-02-05 03:42:44 +01:00
|
|
|
|
2015-03-13 23:03:17 +01:00
|
|
|
let 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-02-04 01:08:46 +01:00
|
|
|
function getSourceFile(fileName: string) {
|
2015-06-03 22:48:34 +02:00
|
|
|
return filesByName.get(fileName);
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-06-18 19:52:19 +02:00
|
|
|
function getDiagnosticsHelper(
|
|
|
|
sourceFile: SourceFile,
|
2015-06-18 21:04:26 +02:00
|
|
|
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-03-13 23:03:17 +01:00
|
|
|
let 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[] {
|
2015-06-18 19:52:19 +02:00
|
|
|
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
|
|
|
//
|
|
|
|
// Note: we are overly agressive here. We do not actually *have* to throw away
|
|
|
|
// 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(() => {
|
|
|
|
let typeChecker = getDiagnosticsProducingTypeChecker();
|
2015-02-05 10:47:29 +01:00
|
|
|
|
2015-06-18 19:52:19 +02:00
|
|
|
Debug.assert(!!sourceFile.bindDiagnostics);
|
|
|
|
let bindDiagnostics = sourceFile.bindDiagnostics;
|
|
|
|
let checkDiagnostics = typeChecker.getDiagnostics(sourceFile, cancellationToken);
|
|
|
|
let programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
|
|
|
|
|
|
|
|
return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics);
|
|
|
|
});
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-06-18 21:04:26 +02:00
|
|
|
function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] {
|
2015-06-18 19:52:19 +02:00
|
|
|
return runWithCancellationToken(() => {
|
|
|
|
if (!isDeclarationFile(sourceFile)) {
|
|
|
|
let resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile, cancellationToken);
|
|
|
|
// Don't actually write any files since we're just getting diagnostics.
|
2015-07-09 02:42:26 +02:00
|
|
|
let writeFile: WriteFileCallback = () => { };
|
2015-06-18 19:52:19 +02:00
|
|
|
return ts.getDeclarationDiagnostics(getEmitHost(writeFile), resolver, sourceFile);
|
|
|
|
}
|
|
|
|
});
|
2015-03-20 00:55:07 +01:00
|
|
|
}
|
|
|
|
|
2015-06-18 18:32:52 +02:00
|
|
|
function getOptionsDiagnostics(): Diagnostic[] {
|
2015-05-27 05:18:13 +02:00
|
|
|
let allDiagnostics: Diagnostic[] = [];
|
|
|
|
addRange(allDiagnostics, diagnostics.getGlobalDiagnostics());
|
|
|
|
return sortAndDeduplicateDiagnostics(allDiagnostics);
|
|
|
|
}
|
|
|
|
|
2014-12-16 22:14:14 +01:00
|
|
|
function getGlobalDiagnostics(): Diagnostic[] {
|
2015-03-13 23:03:17 +01:00
|
|
|
let 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) {
|
|
|
|
processSourceFile(normalizePath(fileName), isDefaultLib);
|
2015-06-23 02:48:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
|
|
|
|
return a.fileName === b.fileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
function moduleNameIsEqualTo(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
|
|
|
}
|
|
|
|
|
|
|
|
function collectExternalModuleReferences(file: SourceFile): void {
|
|
|
|
if (file.imports) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let imports: LiteralExpression[];
|
|
|
|
for (let node of file.statements) {
|
|
|
|
switch (node.kind) {
|
|
|
|
case SyntaxKind.ImportDeclaration:
|
|
|
|
case SyntaxKind.ImportEqualsDeclaration:
|
|
|
|
case SyntaxKind.ExportDeclaration:
|
|
|
|
let moduleNameExpr = getExternalModuleName(node);
|
|
|
|
if (!moduleNameExpr || moduleNameExpr.kind !== SyntaxKind.StringLiteral) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!(<LiteralExpression>moduleNameExpr).text) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
(imports || (imports = [])).push(<LiteralExpression>moduleNameExpr);
|
|
|
|
break;
|
|
|
|
case SyntaxKind.ModuleDeclaration:
|
|
|
|
if ((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral && (node.flags & NodeFlags.Ambient || isDeclarationFile(file))) {
|
|
|
|
// TypeScript 1.0 spec (April 2014): 12.1.6
|
|
|
|
// An AmbientExternalModuleDeclaration declares an external module.
|
|
|
|
// 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
|
|
|
|
forEachChild((<ModuleDeclaration>node).body, node => {
|
|
|
|
if (isExternalModuleImportEqualsDeclaration(node) &&
|
|
|
|
getExternalModuleImportEqualsDeclarationExpression(node).kind === SyntaxKind.StringLiteral) {
|
|
|
|
let moduleName = <LiteralExpression>getExternalModuleImportEqualsDeclarationExpression(node);
|
|
|
|
// TypeScript 1.0 spec (April 2014): 12.1.6
|
|
|
|
// An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules
|
|
|
|
// only through top - level external module names. Relative external module names are not permitted.
|
|
|
|
if (moduleName) {
|
|
|
|
(imports || (imports = [])).push(moduleName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file.imports = imports || emptyArray;
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-02-04 01:08:46 +01:00
|
|
|
function processSourceFile(fileName: string, isDefaultLib: 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
|
|
|
}
|
2015-02-04 01:08:46 +01:00
|
|
|
else if (!findSourceFile(fileName, isDefaultLib, 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 {
|
2015-06-26 02:36:19 +02:00
|
|
|
let nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, isDefaultLib, refFile, refPos, refEnd);
|
2015-06-11 23:30:58 +02:00
|
|
|
if (!nonTsFile) {
|
|
|
|
if (options.allowNonTsExtensions) {
|
|
|
|
diagnostic = Diagnostics.File_0_not_found;
|
|
|
|
diagnosticArgument = [fileName];
|
|
|
|
}
|
|
|
|
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, isDefaultLib, refFile, refPos, refEnd))) {
|
|
|
|
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-08-13 21:45:26 +02:00
|
|
|
diagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...diagnosticArgument));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
else {
|
2015-05-05 08:30:43 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(diagnostic, ...diagnosticArgument));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-04 01:08:46 +01:00
|
|
|
// Get source file from normalized fileName
|
2015-08-12 22:04:10 +02:00
|
|
|
function findSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
|
2015-05-11 23:01:46 +02:00
|
|
|
let canonicalName = host.getCanonicalFileName(normalizeSlashes(fileName));
|
2015-06-03 22:48:34 +02:00
|
|
|
if (filesByName.contains(canonicalName)) {
|
2014-12-16 22:14:14 +01:00
|
|
|
// We've already looked for this file, use cached result
|
2015-02-04 01:08:46 +01:00
|
|
|
return getSourceFileFromCache(fileName, canonicalName, /*useAbsolutePath*/ false);
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
else {
|
2015-03-13 23:03:17 +01:00
|
|
|
let normalizedAbsolutePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
|
|
|
|
let canonicalAbsolutePath = host.getCanonicalFileName(normalizedAbsolutePath);
|
2015-06-03 22:48:34 +02:00
|
|
|
if (filesByName.contains(canonicalAbsolutePath)) {
|
2014-12-16 22:14:14 +01:00
|
|
|
return getSourceFileFromCache(normalizedAbsolutePath, canonicalAbsolutePath, /*useAbsolutePath*/ true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We haven't looked for this file, do so now and cache result
|
2015-06-03 22:48:34 +02:00
|
|
|
let file = host.getSourceFile(fileName, options.target, hostErrorMessage => {
|
2015-08-12 22:04:10 +02:00
|
|
|
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
|
|
|
|
diagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
|
2015-02-04 01:08:46 +01:00
|
|
|
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
|
2014-12-18 09:39:56 +01:00
|
|
|
}
|
|
|
|
else {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
|
2014-12-18 09:39:56 +01:00
|
|
|
}
|
2014-12-16 22:14:14 +01:00
|
|
|
});
|
2015-06-03 22:48:34 +02:00
|
|
|
filesByName.set(canonicalName, file);
|
2014-12-16 22:14:14 +01:00
|
|
|
if (file) {
|
2015-06-04 21:47:12 +02:00
|
|
|
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
|
2014-12-16 22:14:14 +01:00
|
|
|
|
|
|
|
// Set the source file for normalized absolute path
|
2015-06-03 22:48:34 +02:00
|
|
|
filesByName.set(canonicalAbsolutePath, file);
|
2015-08-19 20:58:02 +02:00
|
|
|
|
|
|
|
let basePath = getDirectoryPath(fileName);
|
2014-12-16 22:14:14 +01:00
|
|
|
if (!options.noResolve) {
|
|
|
|
processReferencedFiles(file, basePath);
|
|
|
|
}
|
2015-08-19 20:58:02 +02:00
|
|
|
|
|
|
|
// always process imported modules to record module name resolutions
|
|
|
|
processImportedModules(file, basePath);
|
|
|
|
|
2014-12-16 22:14:14 +01:00
|
|
|
if (isDefaultLib) {
|
2015-06-04 10:03:02 +02:00
|
|
|
file.isDefaultLib = true;
|
2014-12-16 22:14:14 +01:00
|
|
|
files.unshift(file);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
files.push(file);
|
|
|
|
}
|
|
|
|
}
|
2015-03-13 23:03:17 +01:00
|
|
|
|
|
|
|
return file;
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-02-04 01:08:46 +01:00
|
|
|
function getSourceFileFromCache(fileName: string, canonicalName: string, useAbsolutePath: boolean): SourceFile {
|
2015-06-03 22:48:34 +02:00
|
|
|
let file = filesByName.get(canonicalName);
|
2014-12-16 22:14:14 +01:00
|
|
|
if (file && host.useCaseSensitiveFileNames()) {
|
2015-03-13 23:03:17 +01:00
|
|
|
let sourceFileName = useAbsolutePath ? getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()) : file.fileName;
|
2014-12-16 22:14:14 +01:00
|
|
|
if (canonicalName !== sourceFileName) {
|
2015-08-12 22:04:10 +02:00
|
|
|
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
|
|
|
|
diagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
|
|
|
|
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, sourceFileName));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, sourceFileName));
|
|
|
|
}
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function processReferencedFiles(file: SourceFile, basePath: string) {
|
|
|
|
forEach(file.referencedFiles, ref => {
|
2015-07-14 02:44:50 +02:00
|
|
|
let referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
|
|
|
|
processSourceFile(referencedFileName, /* isDefaultLib */ false, file, ref.pos, ref.end);
|
2014-12-16 22:14:14 +01:00
|
|
|
});
|
|
|
|
}
|
2015-07-30 02:16:58 +02:00
|
|
|
|
2015-08-20 00:37:37 +02:00
|
|
|
function processImportedModules(file: SourceFile, basePath: string) {
|
|
|
|
collectExternalModuleReferences(file);
|
|
|
|
if (file.imports.length) {
|
2015-06-25 03:12:02 +02:00
|
|
|
file.resolvedModules = {};
|
2015-08-04 02:42:29 +02:00
|
|
|
let moduleNames = map(file.imports, name => name.text);
|
|
|
|
let resolutions = resolveModuleNamesWorker(moduleNames, file.fileName);
|
|
|
|
for (let i = 0; i < file.imports.length; ++i) {
|
|
|
|
let resolution = resolutions[i];
|
|
|
|
setResolvedModuleName(file, moduleNames[i], resolution);
|
2015-08-19 20:58:02 +02:00
|
|
|
if (resolution && !options.noResolve) {
|
2015-08-04 02:42:29 +02:00
|
|
|
findModuleSourceFile(resolution, file.imports[i]);
|
|
|
|
}
|
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
|
|
|
|
2015-02-09 02:33:45 +01:00
|
|
|
function findModuleSourceFile(fileName: string, nameLiteral: Expression) {
|
2015-08-12 22:04:10 +02:00
|
|
|
return findSourceFile(fileName, /* isDefaultLib */ false, file, nameLiteral.pos, nameLiteral.end);
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-17 01:35:48 +02:00
|
|
|
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string {
|
2015-04-15 00:05:08 +02:00
|
|
|
let commonPathComponents: string[];
|
2015-04-15 07:11:25 +02:00
|
|
|
let currentDirectory = host.getCurrentDirectory();
|
2015-04-15 00:05:08 +02:00
|
|
|
forEach(files, sourceFile => {
|
|
|
|
// Each file contributes into common source file path
|
2015-04-15 07:11:25 +02:00
|
|
|
if (isDeclarationFile(sourceFile)) {
|
|
|
|
return;
|
|
|
|
}
|
2015-04-15 00:05:08 +02:00
|
|
|
|
2015-04-15 07:11:25 +02:00
|
|
|
let sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, currentDirectory);
|
2015-04-20 23:23:24 +02:00
|
|
|
sourcePathComponents.pop(); // The base file name is not part of the common directory path
|
|
|
|
|
|
|
|
if (!commonPathComponents) {
|
|
|
|
// first file
|
|
|
|
commonPathComponents = sourcePathComponents;
|
|
|
|
return;
|
|
|
|
}
|
2015-04-15 00:05:08 +02:00
|
|
|
|
2015-04-20 23:23:24 +02:00
|
|
|
for (let i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) {
|
|
|
|
if (commonPathComponents[i] !== sourcePathComponents[i]) {
|
|
|
|
if (i === 0) {
|
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
|
|
|
|
return;
|
2015-04-15 00:05:08 +02:00
|
|
|
}
|
2015-04-15 07:11:25 +02:00
|
|
|
|
2015-04-20 23:23:24 +02:00
|
|
|
// New common path found that is 0 -> i-1
|
|
|
|
commonPathComponents.length = i;
|
|
|
|
break;
|
2015-04-15 00:05:08 +02:00
|
|
|
}
|
|
|
|
}
|
2015-04-20 23:23:24 +02:00
|
|
|
|
|
|
|
// If the sourcePathComponents was shorter than the commonPathComponents, truncate to the sourcePathComponents
|
|
|
|
if (sourcePathComponents.length < commonPathComponents.length) {
|
|
|
|
commonPathComponents.length = sourcePathComponents.length;
|
2015-04-15 07:11:25 +02:00
|
|
|
}
|
2015-04-15 00:05:08 +02:00
|
|
|
});
|
|
|
|
|
2015-04-15 07:11:25 +02:00
|
|
|
return getNormalizedPathFromPathComponents(commonPathComponents);
|
|
|
|
}
|
|
|
|
|
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-04-15 07:11:25 +02:00
|
|
|
let currentDirectory = host.getCurrentDirectory();
|
|
|
|
let absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
|
|
|
|
|
2015-04-19 22:24:39 +02:00
|
|
|
for (var sourceFile of sourceFiles) {
|
2015-04-15 07:11:25 +02:00
|
|
|
if (!isDeclarationFile(sourceFile)) {
|
|
|
|
let absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
|
|
|
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
2015-04-17 01:35:48 +02:00
|
|
|
diagnostics.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-08-21 00:58:57 +02:00
|
|
|
diagnostics.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-08-21 00:58:57 +02:00
|
|
|
diagnostics.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-08-21 00:58:57 +02:00
|
|
|
diagnostics.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) {
|
|
|
|
diagnostics.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-08-21 00:58:57 +02:00
|
|
|
diagnostics.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-08-21 00:58:57 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"));
|
2015-04-08 09:14:23 +02:00
|
|
|
}
|
|
|
|
if (options.sourceRoot) {
|
2015-08-21 00:58:57 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceRoot", "inlineSourceMap"));
|
2015-04-08 09:14:23 +02:00
|
|
|
}
|
2015-04-21 05:33:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (options.inlineSources) {
|
|
|
|
if (!options.sourceMap && !options.inlineSourceMap) {
|
|
|
|
diagnostics.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-08-21 02:37:56 +02:00
|
|
|
if (options.out && options.outFile) {
|
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile"));
|
|
|
|
}
|
|
|
|
|
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-08-21 00:58:57 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
if (options.sourceRoot) {
|
2015-08-21 00:58:57 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "sourceRoot", "sourceMap"));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-15 23:48:23 +01:00
|
|
|
let languageVersion = options.target || ScriptTarget.ES3;
|
2015-08-21 02:37:56 +02:00
|
|
|
let outFile = options.outFile || options.out;
|
2015-02-13 02:54:30 +01:00
|
|
|
|
2015-03-13 23:03:17 +01:00
|
|
|
let firstExternalModuleSourceFile = forEach(files, f => isExternalModule(f) ? f : undefined);
|
2015-05-19 06:49:41 +02:00
|
|
|
if (options.isolatedModules) {
|
2015-02-13 02:54:30 +01:00
|
|
|
if (!options.module && languageVersion < ScriptTarget.ES6) {
|
2015-05-19 06:49:41 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES6_or_higher));
|
2015-03-12 06:53:36 +01:00
|
|
|
}
|
2015-03-31 04:33:15 +02:00
|
|
|
|
2015-03-31 07:41:49 +02:00
|
|
|
let firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !isDeclarationFile(f) ? f : undefined);
|
2015-03-31 04:33:15 +02:00
|
|
|
if (firstNonExternalModuleSourceFile) {
|
|
|
|
let span = getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile);
|
2015-05-19 06:49:41 +02:00
|
|
|
diagnostics.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
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (firstExternalModuleSourceFile && languageVersion < ScriptTarget.ES6 && !options.module) {
|
2015-07-09 00:35:49 +02:00
|
|
|
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
|
2015-03-31 04:33:15 +02:00
|
|
|
let span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
|
2015-04-27 03:29:37 +02:00
|
|
|
diagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_modules_unless_the_module_flag_is_provided));
|
2015-03-12 06:53:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cannot specify module gen target when in es6 or above
|
2015-02-13 02:54:30 +01:00
|
|
|
if (options.module && languageVersion >= ScriptTarget.ES6) {
|
2015-04-29 01:49:23 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_compile_modules_into_commonjs_amd_system_or_umd_when_targeting_ES6_or_higher));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-03-31 04:33:15 +02:00
|
|
|
// there has to be common source directory if user specified --outdir || --sourceRoot
|
2014-12-16 22:14:14 +01:00
|
|
|
// 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
|
2015-03-31 04:33:15 +02:00
|
|
|
(options.mapRoot && // there is --mapRoot specified and there would be multiple js files generated
|
2015-08-21 02:37:56 +02:00
|
|
|
(!outFile || firstExternalModuleSourceFile !== undefined))) {
|
2014-12-16 22:14:14 +01:00
|
|
|
|
2015-04-15 07:11:25 +02:00
|
|
|
if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) {
|
|
|
|
// If a rootDir is specified and is valid use it as the commonSourceDirectory
|
|
|
|
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, host.getCurrentDirectory());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Compute the commonSourceDirectory from the input files
|
2015-04-17 01:35:48 +02:00
|
|
|
commonSourceDirectory = computeCommonSourceDirectory(files);
|
2015-04-15 07:11:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) {
|
2015-07-09 00:35:49 +02:00
|
|
|
// Make sure directory path ends with directory separator so this string can directly
|
2015-04-15 07:11:25 +02:00
|
|
|
// 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;
|
|
|
|
}
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
2014-12-18 09:39:56 +01:00
|
|
|
|
|
|
|
if (options.noEmit) {
|
2015-08-21 00:58:57 +02:00
|
|
|
if (options.out) {
|
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "out"));
|
|
|
|
}
|
|
|
|
|
2015-08-21 02:37:56 +02:00
|
|
|
if (options.outFile) {
|
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "outFile"));
|
|
|
|
}
|
|
|
|
|
2015-08-21 00:58:57 +02:00
|
|
|
if (options.outDir) {
|
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "outDir"));
|
2014-12-18 09:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (options.declaration) {
|
2015-08-21 00:58:57 +02:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "declaration"));
|
2014-12-18 09:39:56 +01:00
|
|
|
}
|
|
|
|
}
|
2015-06-26 01:24:41 +02:00
|
|
|
|
2015-06-02 00:01:24 +02:00
|
|
|
if (options.emitDecoratorMetadata &&
|
|
|
|
!options.experimentalDecorators) {
|
2015-08-21 00:58:57 +02:00
|
|
|
diagnostics.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
|
|
|
|
2015-06-20 03:05:43 +02:00
|
|
|
if (options.experimentalAsyncFunctions &&
|
|
|
|
options.target !== ScriptTarget.ES6) {
|
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_experimentalAsyncFunctions_cannot_be_specified_when_targeting_ES5_or_lower));
|
|
|
|
}
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
2015-06-17 20:08:13 +02:00
|
|
|
}
|