2014-12-16 22:14:14 +01:00
|
|
|
/// <reference path="sys.ts" />
|
|
|
|
/// <reference path="emitter.ts" />
|
|
|
|
|
|
|
|
module ts {
|
2015-02-05 03:42:44 +01:00
|
|
|
/* @internal */ export var emitTime = 0;
|
2015-02-26 23:51:04 +01:00
|
|
|
/* @internal */ export var ioReadTime = 0;
|
2015-02-05 03:42:44 +01:00
|
|
|
|
2014-12-16 22:14:14 +01:00
|
|
|
export function createCompilerHost(options: CompilerOptions): CompilerHost {
|
|
|
|
var currentDirectory: string;
|
|
|
|
var existingDirectories: Map<boolean> = {};
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
// returned by CScript sys environment
|
|
|
|
var unsupportedFileEncodingErrorCode = -2147024809;
|
|
|
|
|
2015-02-04 01:08:46 +01:00
|
|
|
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
|
2014-12-16 22:14:14 +01:00
|
|
|
try {
|
2015-02-26 23:51:04 +01:00
|
|
|
var start = new Date().getTime();
|
2015-02-04 01:08:46 +01:00
|
|
|
var 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-02-04 01:08:46 +01:00
|
|
|
return text !== undefined ? createSourceFile(fileName, text, languageVersion) : undefined;
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
|
|
|
|
function directoryExists(directoryPath: string): boolean {
|
|
|
|
if (hasProperty(existingDirectories, directoryPath)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (sys.directoryExists(directoryPath)) {
|
|
|
|
existingDirectories[directoryPath] = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function ensureDirectoriesExist(directoryPath: string) {
|
|
|
|
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
|
|
|
var parentDirectory = getDirectoryPath(directoryPath);
|
|
|
|
ensureDirectoriesExist(parentDirectory);
|
|
|
|
sys.createDirectory(directoryPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
|
|
|
sys.writeFile(fileName, data, writeByteOrderMark);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
if (onError) {
|
|
|
|
onError(e.message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
getNewLine: () => sys.newLine
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-02-05 10:47:29 +01:00
|
|
|
export function getPreEmitDiagnostics(program: Program): Diagnostic[] {
|
|
|
|
var diagnostics = program.getSyntacticDiagnostics().concat(program.getGlobalDiagnostics()).concat(program.getSemanticDiagnostics());
|
|
|
|
return sortAndDeduplicateDiagnostics(diagnostics);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain, newLine: string): string {
|
|
|
|
if (typeof messageText === "string") {
|
|
|
|
return messageText;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var diagnosticChain = messageText;
|
|
|
|
var result = "";
|
|
|
|
|
|
|
|
var indent = 0;
|
|
|
|
while (diagnosticChain) {
|
|
|
|
if (indent) {
|
|
|
|
result += newLine;
|
|
|
|
|
|
|
|
for (var i = 0; i < indent; i++) {
|
|
|
|
result += " ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result += diagnosticChain.messageText;
|
|
|
|
indent++;
|
|
|
|
diagnosticChain = diagnosticChain.next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-05 02:02:26 +01:00
|
|
|
export function createProgram(rootNames: string[], options: CompilerOptions, host?: CompilerHost): Program {
|
2014-12-16 22:14:14 +01:00
|
|
|
var program: Program;
|
|
|
|
var files: SourceFile[] = [];
|
|
|
|
var filesByName: Map<SourceFile> = {};
|
2015-02-05 03:12:13 +01:00
|
|
|
var diagnostics = createDiagnosticCollection();
|
2014-12-16 22:14:14 +01:00
|
|
|
var seenNoDefaultLib = options.noLib;
|
|
|
|
var commonSourceDirectory: string;
|
2015-02-05 02:02:26 +01:00
|
|
|
host = host || createCompilerHost(options);
|
2014-12-16 22:14:14 +01:00
|
|
|
|
|
|
|
forEach(rootNames, name => processRootFile(name, false));
|
|
|
|
if (!seenNoDefaultLib) {
|
2015-02-04 01:08:46 +01:00
|
|
|
processRootFile(host.getDefaultLibFileName(options), true);
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
verifyCompilerOptions();
|
2014-12-18 09:39:56 +01:00
|
|
|
|
2014-12-16 22:28:38 +01:00
|
|
|
var diagnosticsProducingTypeChecker: TypeChecker;
|
|
|
|
var noDiagnosticsTypeChecker: TypeChecker;
|
2014-12-16 22:14:14 +01:00
|
|
|
|
|
|
|
program = {
|
|
|
|
getSourceFile: getSourceFile,
|
|
|
|
getSourceFiles: () => files,
|
|
|
|
getCompilerOptions: () => options,
|
2015-02-05 10:47:29 +01:00
|
|
|
getSyntacticDiagnostics,
|
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-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,
|
2014-12-16 23:42:58 +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-02-05 10:47:29 +01:00
|
|
|
function getEmitHost(writeFileCallback?: WriteFileCallback): EmitHost {
|
2015-02-05 01:53:14 +01:00
|
|
|
return {
|
2015-02-05 08:20:26 +01:00
|
|
|
getCanonicalFileName: host.getCanonicalFileName,
|
2015-02-05 01:53:14 +01:00
|
|
|
getCommonSourceDirectory: program.getCommonSourceDirectory,
|
|
|
|
getCompilerOptions: program.getCompilerOptions,
|
2015-02-05 08:20:26 +01:00
|
|
|
getCurrentDirectory: host.getCurrentDirectory,
|
|
|
|
getNewLine: host.getNewLine,
|
2015-02-05 01:53:14 +01:00
|
|
|
getSourceFile: program.getSourceFile,
|
|
|
|
getSourceFiles: program.getSourceFiles,
|
2015-02-05 08:20:26 +01:00
|
|
|
writeFile: writeFileCallback || host.writeFile,
|
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-02-06 02:24:46 +01:00
|
|
|
function getDeclarationDiagnostics(targetSourceFile: SourceFile): Diagnostic[] {
|
2015-02-05 23:41:04 +01:00
|
|
|
var resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(targetSourceFile);
|
2014-12-16 23:42:58 +01:00
|
|
|
return ts.getDeclarationDiagnostics(getEmitHost(), resolver, targetSourceFile);
|
2014-12-16 23:12:17 +01:00
|
|
|
}
|
|
|
|
|
2015-02-05 23:41:04 +01:00
|
|
|
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback): EmitResult {
|
|
|
|
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
|
|
|
|
// immediately bail out.
|
|
|
|
if (options.noEmitOnError && getPreEmitDiagnostics(this).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.
|
|
|
|
var emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile);
|
|
|
|
|
2015-02-05 03:42:44 +01:00
|
|
|
var start = new Date().getTime();
|
|
|
|
|
2015-02-06 00:50:18 +01:00
|
|
|
var 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) {
|
|
|
|
fileName = host.getCanonicalFileName(fileName);
|
|
|
|
return hasProperty(filesByName, fileName) ? filesByName[fileName] : undefined;
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-02-05 11:15:38 +01:00
|
|
|
function getDiagnosticsHelper(sourceFile: SourceFile, getDiagnostics: (sourceFile: SourceFile) => Diagnostic[]): Diagnostic[] {
|
2015-02-05 10:47:29 +01:00
|
|
|
if (sourceFile) {
|
2015-02-05 11:15:38 +01:00
|
|
|
return getDiagnostics(sourceFile);
|
2014-12-16 22:52:47 +01:00
|
|
|
}
|
2015-02-05 10:47:29 +01:00
|
|
|
|
|
|
|
var allDiagnostics: Diagnostic[] = [];
|
|
|
|
forEach(program.getSourceFiles(), sourceFile => {
|
2015-02-05 11:15:38 +01:00
|
|
|
addRange(allDiagnostics, getDiagnostics(sourceFile));
|
2015-02-05 10:47:29 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
return sortAndDeduplicateDiagnostics(allDiagnostics);
|
2014-12-16 22:52:47 +01:00
|
|
|
}
|
|
|
|
|
2015-02-06 02:24:46 +01:00
|
|
|
function getSyntacticDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
|
2015-02-05 22:38:11 +01:00
|
|
|
return getDiagnosticsHelper(sourceFile, getSyntacticDiagnosticsForFile);
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-02-06 02:24:46 +01:00
|
|
|
function getSemanticDiagnostics(sourceFile?: SourceFile): Diagnostic[] {
|
2015-02-05 11:15:38 +01:00
|
|
|
return getDiagnosticsHelper(sourceFile, getSemanticDiagnosticsForFile);
|
2015-01-15 22:22:23 +01:00
|
|
|
}
|
2015-02-05 11:15:38 +01:00
|
|
|
|
2015-02-05 22:38:11 +01:00
|
|
|
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
|
|
|
|
return sourceFile.parseDiagnostics;
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
2015-02-05 10:47:29 +01:00
|
|
|
function getSemanticDiagnosticsForFile(sourceFile: SourceFile): Diagnostic[] {
|
|
|
|
var typeChecker = getDiagnosticsProducingTypeChecker();
|
|
|
|
|
|
|
|
Debug.assert(!!sourceFile.bindDiagnostics);
|
|
|
|
var bindDiagnostics = sourceFile.bindDiagnostics;
|
|
|
|
var checkDiagnostics = typeChecker.getDiagnostics(sourceFile);
|
|
|
|
var programDiagnostics = diagnostics.getDiagnostics(sourceFile.fileName);
|
|
|
|
|
|
|
|
return bindDiagnostics.concat(checkDiagnostics).concat(programDiagnostics);
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function getGlobalDiagnostics(): Diagnostic[] {
|
2015-02-05 10:47:29 +01:00
|
|
|
var typeChecker = getDiagnosticsProducingTypeChecker();
|
|
|
|
|
|
|
|
var allDiagnostics: Diagnostic[] = [];
|
|
|
|
addRange(allDiagnostics, typeChecker.getGlobalDiagnostics());
|
|
|
|
addRange(allDiagnostics, diagnostics.getGlobalDiagnostics());
|
|
|
|
|
|
|
|
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);
|
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) {
|
2014-12-16 22:14:14 +01:00
|
|
|
if (refEnd !== undefined && refPos !== undefined) {
|
|
|
|
var start = refPos;
|
|
|
|
var length = refEnd - refPos;
|
|
|
|
}
|
|
|
|
var diagnostic: DiagnosticMessage;
|
2015-02-04 01:08:46 +01:00
|
|
|
if (hasExtension(fileName)) {
|
|
|
|
if (!options.allowNonTsExtensions && !fileExtensionIs(host.getCanonicalFileName(fileName), ".ts")) {
|
2014-12-16 22:14:14 +01:00
|
|
|
diagnostic = Diagnostics.File_0_must_have_extension_ts_or_d_ts;
|
|
|
|
}
|
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-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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-02-04 01:08:46 +01:00
|
|
|
if (options.allowNonTsExtensions && !findSourceFile(fileName, isDefaultLib, refFile, refPos, refEnd)) {
|
2015-01-13 18:30:54 +01:00
|
|
|
diagnostic = Diagnostics.File_0_not_found;
|
|
|
|
}
|
2015-02-04 01:08:46 +01:00
|
|
|
else if (!findSourceFile(fileName + ".ts", isDefaultLib, refFile, refPos, refEnd) && !findSourceFile(fileName + ".d.ts", isDefaultLib, refFile, refPos, refEnd)) {
|
2014-12-16 22:14:14 +01:00
|
|
|
diagnostic = Diagnostics.File_0_not_found;
|
2015-02-04 01:08:46 +01:00
|
|
|
fileName += ".ts";
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diagnostic) {
|
|
|
|
if (refFile) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createFileDiagnostic(refFile, start, length, diagnostic, fileName));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
else {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createCompilerDiagnostic(diagnostic, fileName));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-04 01:08:46 +01:00
|
|
|
// Get source file from normalized fileName
|
|
|
|
function findSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refStart?: number, refLength?: number): SourceFile {
|
|
|
|
var canonicalName = host.getCanonicalFileName(fileName);
|
2014-12-16 22:14:14 +01:00
|
|
|
if (hasProperty(filesByName, canonicalName)) {
|
|
|
|
// 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-02-04 01:08:46 +01:00
|
|
|
var normalizedAbsolutePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
|
2014-12-16 22:14:14 +01:00
|
|
|
var canonicalAbsolutePath = host.getCanonicalFileName(normalizedAbsolutePath);
|
|
|
|
if (hasProperty(filesByName, canonicalAbsolutePath)) {
|
|
|
|
return getSourceFileFromCache(normalizedAbsolutePath, canonicalAbsolutePath, /*useAbsolutePath*/ true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// We haven't looked for this file, do so now and cache result
|
2015-02-04 01:08:46 +01:00
|
|
|
var file = filesByName[canonicalName] = host.getSourceFile(fileName, options.target, hostErrorMessage => {
|
2014-12-18 09:39:56 +01:00
|
|
|
if (refFile) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createFileDiagnostic(refFile, refStart, refLength,
|
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
|
|
|
});
|
|
|
|
if (file) {
|
|
|
|
seenNoDefaultLib = seenNoDefaultLib || file.hasNoDefaultLib;
|
|
|
|
|
|
|
|
// Set the source file for normalized absolute path
|
|
|
|
filesByName[canonicalAbsolutePath] = file;
|
|
|
|
|
|
|
|
if (!options.noResolve) {
|
2015-02-04 01:08:46 +01:00
|
|
|
var basePath = getDirectoryPath(fileName);
|
2014-12-16 22:14:14 +01:00
|
|
|
processReferencedFiles(file, basePath);
|
|
|
|
processImportedModules(file, basePath);
|
|
|
|
}
|
|
|
|
if (isDefaultLib) {
|
|
|
|
files.unshift(file);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
files.push(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return file;
|
|
|
|
|
2015-02-04 01:08:46 +01:00
|
|
|
function getSourceFileFromCache(fileName: string, canonicalName: string, useAbsolutePath: boolean): SourceFile {
|
2014-12-16 22:14:14 +01:00
|
|
|
var file = filesByName[canonicalName];
|
|
|
|
if (file && host.useCaseSensitiveFileNames()) {
|
2015-02-04 01:08:46 +01:00
|
|
|
var sourceFileName = useAbsolutePath ? getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()) : file.fileName;
|
2014-12-16 22:14:14 +01:00
|
|
|
if (canonicalName !== sourceFileName) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createFileDiagnostic(refFile, refStart, refLength,
|
2015-02-04 01:08:46 +01:00
|
|
|
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-02-04 01:08:46 +01:00
|
|
|
var referencedFileName = isRootedDiskPath(ref.fileName) ? ref.fileName : combinePaths(basePath, ref.fileName);
|
|
|
|
processSourceFile(normalizePath(referencedFileName), /* isDefaultLib */ false, file, ref.pos, ref.end);
|
2014-12-16 22:14:14 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function processImportedModules(file: SourceFile, basePath: string) {
|
|
|
|
forEach(file.statements, node => {
|
2015-02-13 03:05:02 +01:00
|
|
|
if (node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration || node.kind === SyntaxKind.ExportDeclaration) {
|
|
|
|
var moduleNameExpr = getExternalModuleName(node);
|
2015-02-09 02:33:45 +01:00
|
|
|
if (moduleNameExpr && moduleNameExpr.kind === SyntaxKind.StringLiteral) {
|
|
|
|
var moduleNameText = (<LiteralExpression>moduleNameExpr).text;
|
|
|
|
if (moduleNameText) {
|
|
|
|
var searchPath = basePath;
|
|
|
|
while (true) {
|
|
|
|
var searchName = normalizePath(combinePaths(searchPath, moduleNameText));
|
|
|
|
if (findModuleSourceFile(searchName + ".ts", moduleNameExpr) || findModuleSourceFile(searchName + ".d.ts", moduleNameExpr)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
var parentPath = getDirectoryPath(searchPath);
|
|
|
|
if (parentPath === searchPath) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
searchPath = parentPath;
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (node.kind === SyntaxKind.ModuleDeclaration && (<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 => {
|
2015-01-27 23:42:20 +01:00
|
|
|
if (isExternalModuleImportEqualsDeclaration(node) &&
|
|
|
|
getExternalModuleImportEqualsDeclarationExpression(node).kind === SyntaxKind.StringLiteral) {
|
2014-12-16 22:14:14 +01:00
|
|
|
|
2015-01-27 23:42:20 +01:00
|
|
|
var nameLiteral = <LiteralExpression>getExternalModuleImportEqualsDeclarationExpression(node);
|
2014-12-16 22:14:14 +01:00
|
|
|
var moduleName = nameLiteral.text;
|
|
|
|
if (moduleName) {
|
|
|
|
// 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.
|
|
|
|
var searchName = normalizePath(combinePaths(basePath, moduleName));
|
|
|
|
var tsFile = findModuleSourceFile(searchName + ".ts", nameLiteral);
|
|
|
|
if (!tsFile) {
|
|
|
|
findModuleSourceFile(searchName + ".d.ts", nameLiteral);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-02-09 02:33:45 +01:00
|
|
|
function findModuleSourceFile(fileName: string, nameLiteral: Expression) {
|
2015-02-04 01:08:46 +01:00
|
|
|
return findSourceFile(fileName, /* isDefaultLib */ false, file, nameLiteral.pos, nameLiteral.end - nameLiteral.pos);
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function verifyCompilerOptions() {
|
|
|
|
if (!options.sourceMap && (options.mapRoot || options.sourceRoot)) {
|
|
|
|
// Error to specify --mapRoot or --sourceRoot without mapSourceFiles
|
|
|
|
if (options.mapRoot) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
if (options.sourceRoot) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-05 03:15:55 +01:00
|
|
|
var firstExternalModuleSourceFile = forEach(files, f => isExternalModule(f) ? f : undefined);
|
|
|
|
if (firstExternalModuleSourceFile && !options.module) {
|
|
|
|
// We cannot use createDiagnosticFromNode because nodes do not have parents yet
|
|
|
|
var span = getErrorSpanForNode(firstExternalModuleSourceFile, firstExternalModuleSourceFile.externalModuleIndicator);
|
|
|
|
diagnostics.add(createFileDiagnostic(firstExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided));
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// there has to be common source directory if user specified --outdir || --sourcRoot
|
|
|
|
// 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 and there would be multiple js files generated
|
2015-03-05 03:15:55 +01:00
|
|
|
(!options.out || firstExternalModuleSourceFile !== undefined))) {
|
2014-12-16 22:14:14 +01:00
|
|
|
|
|
|
|
var commonPathComponents: string[];
|
|
|
|
forEach(files, sourceFile => {
|
|
|
|
// Each file contributes into common source file path
|
|
|
|
if (!(sourceFile.flags & NodeFlags.DeclarationFile)
|
2015-02-04 01:08:46 +01:00
|
|
|
&& !fileExtensionIs(sourceFile.fileName, ".js")) {
|
|
|
|
var sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, host.getCurrentDirectory());
|
2014-12-16 22:14:14 +01:00
|
|
|
sourcePathComponents.pop(); // FileName is not part of directory
|
|
|
|
if (commonPathComponents) {
|
|
|
|
for (var i = 0; i < Math.min(commonPathComponents.length, sourcePathComponents.length); i++) {
|
|
|
|
if (commonPathComponents[i] !== sourcePathComponents[i]) {
|
|
|
|
if (i === 0) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
|
2014-12-16 22:14:14 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// New common path found that is 0 -> i-1
|
|
|
|
commonPathComponents.length = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the fileComponent path completely matched and less than already found update the length
|
|
|
|
if (sourcePathComponents.length < commonPathComponents.length) {
|
|
|
|
commonPathComponents.length = sourcePathComponents.length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// first file
|
|
|
|
commonPathComponents = sourcePathComponents;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
commonSourceDirectory = getNormalizedPathFromPathComponents(commonPathComponents);
|
|
|
|
if (commonSourceDirectory) {
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2014-12-18 09:39:56 +01:00
|
|
|
|
|
|
|
if (options.noEmit) {
|
|
|
|
if (options.out || options.outDir) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_noEmit_cannot_be_specified_with_option_out_or_outDir));
|
2014-12-18 09:39:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (options.declaration) {
|
2015-02-05 03:12:13 +01:00
|
|
|
diagnostics.add(createCompilerDiagnostic(Diagnostics.Option_noEmit_cannot_be_specified_with_option_declaration));
|
2014-12-18 09:39:56 +01:00
|
|
|
}
|
|
|
|
}
|
2014-12-16 22:14:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|