Skip to content

Commit 261adff

Browse files
committed
Add rootDir option
1 parent e7895c5 commit 261adff

6 files changed

Lines changed: 81 additions & 30 deletions

File tree

src/compiler/commandLineParser.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ module ts {
110110
type: "boolean",
111111
description: Diagnostics.Do_not_emit_comments_to_output,
112112
},
113+
{
114+
name: "rootDir",
115+
type: "string",
116+
isFilePath: true,
117+
description: Diagnostics.Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir,
118+
paramType: Diagnostics.LOCATION,
119+
},
113120
{
114121
name: "separateCompilation",
115122
type: "boolean",

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ module ts {
495495
Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures: { code: 6055, category: DiagnosticCategory.Message, key: "Suppress noImplicitAny errors for indexing objects lacking index signatures." },
496496
Do_not_emit_declarations_for_code_that_has_an_internal_annotation: { code: 6056, category: DiagnosticCategory.Message, key: "Do not emit declarations for code that has an '@internal' annotation." },
497497
Preserve_new_lines_when_emitting_code: { code: 6057, category: DiagnosticCategory.Message, key: "Preserve new-lines when emitting code." },
498+
Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir: { code: 6058, category: DiagnosticCategory.Message, key: "Specifies the root directory of input files. Use to control the output directory structure with --outDir." },
499+
File_0_is_not_under_rootDir_1_RootDir_is_expected_to_contain_all_source_files: { code: 6059, category: DiagnosticCategory.Error, key: "File '{0}' is not under rootDir '{1}'. RootDir is expected to contain all source files." },
498500
Variable_0_implicitly_has_an_1_type: { code: 7005, category: DiagnosticCategory.Error, key: "Variable '{0}' implicitly has an '{1}' type." },
499501
Parameter_0_implicitly_has_an_1_type: { code: 7006, category: DiagnosticCategory.Error, key: "Parameter '{0}' implicitly has an '{1}' type." },
500502
Member_0_implicitly_has_an_1_type: { code: 7008, category: DiagnosticCategory.Error, key: "Member '{0}' implicitly has an '{1}' type." },

src/compiler/diagnosticMessages.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,15 @@
19681968
"category": "Message",
19691969
"code": 6057
19701970
},
1971+
"Specifies the root directory of input files. Use to control the output directory structure with --outDir.": {
1972+
"category": "Message",
1973+
"code": 6058
1974+
},
1975+
"File '{0}' is not under rootDir '{1}'. RootDir is expected to contain all source files.": {
1976+
"category": "Error",
1977+
"code": 6059
1978+
},
1979+
19711980

19721981
"Variable '{0}' implicitly has an '{1}' type.": {
19731982
"category": "Error",

src/compiler/program.ts

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -455,47 +455,62 @@ module ts {
455455

456456
function computecommonSourceDirectory(sourceFiles: SourceFile[]): string {
457457
let commonPathComponents: string[];
458+
let currentDirectory = host.getCurrentDirectory();
458459
forEach(files, sourceFile => {
459460
// Each file contributes into common source file path
460-
if (!(sourceFile.flags & NodeFlags.DeclarationFile)
461-
&& !fileExtensionIs(sourceFile.fileName, ".js")) {
462-
let sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, host.getCurrentDirectory());
463-
sourcePathComponents.pop(); // FileName is not part of directory
464-
if (commonPathComponents) {
465-
for (let i = 0; i < Math.min(commonPathComponents.length, sourcePathComponents.length); i++) {
466-
if (commonPathComponents[i] !== sourcePathComponents[i]) {
467-
if (i === 0) {
468-
diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
469-
return;
470-
}
461+
if (isDeclarationFile(sourceFile)) {
462+
return;
463+
}
471464

472-
// New common path found that is 0 -> i-1
473-
commonPathComponents.length = i;
474-
break;
465+
let sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, currentDirectory);
466+
sourcePathComponents.pop(); // FileName is not part of directory
467+
if (commonPathComponents) {
468+
for (let i = 0; i < Math.min(commonPathComponents.length, sourcePathComponents.length); i++) {
469+
if (commonPathComponents[i] !== sourcePathComponents[i]) {
470+
if (i === 0) {
471+
diagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
472+
return;
475473
}
476-
}
477474

478-
// If the fileComponent path completely matched and less than already found update the length
479-
if (sourcePathComponents.length < commonPathComponents.length) {
480-
commonPathComponents.length = sourcePathComponents.length;
475+
// New common path found that is 0 -> i-1
476+
commonPathComponents.length = i;
477+
break;
481478
}
482479
}
483-
else {
484-
// first file
485-
commonPathComponents = sourcePathComponents;
480+
481+
// If the fileComponent path completely matched and less than already found update the length
482+
if (sourcePathComponents.length < commonPathComponents.length) {
483+
commonPathComponents.length = sourcePathComponents.length;
486484
}
487485
}
486+
else {
487+
// first file
488+
commonPathComponents = sourcePathComponents;
489+
}
490+
488491
});
489492

490-
let commonSourceDirectory = getNormalizedPathFromPathComponents(commonPathComponents);
491-
if (commonSourceDirectory) {
492-
// Make sure directory path ends with directory separator so this string can directly
493-
// used to replace with "" to get the relative path of the source file and the relative path doesn't
494-
// start with / making it rooted path
495-
commonSourceDirectory += directorySeparator;
493+
return getNormalizedPathFromPathComponents(commonPathComponents);
494+
}
495+
496+
function checkSourceFilesBelongToPath(soruceFiles: SourceFile[], rootDirectory: string): boolean {
497+
let allFilesBelongToPath = true;
498+
if (files) {
499+
let currentDirectory = host.getCurrentDirectory();
500+
let absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
501+
502+
for (var sourceFile of files) {
503+
if (!isDeclarationFile(sourceFile)) {
504+
let absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
505+
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
506+
diagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_RootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, options.rootDir));
507+
allFilesBelongToPath = false;
508+
}
509+
}
510+
}
496511
}
497512

498-
return commonSourceDirectory;
513+
return allFilesBelongToPath;
499514
}
500515

501516
function verifyCompilerOptions() {
@@ -560,7 +575,21 @@ module ts {
560575
(options.mapRoot && // there is --mapRoot specified and there would be multiple js files generated
561576
(!options.out || firstExternalModuleSourceFile !== undefined))) {
562577

563-
commonSourceDirectory = computecommonSourceDirectory(files);
578+
if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) {
579+
// If a rootDir is specified and is valid use it as the commonSourceDirectory
580+
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, host.getCurrentDirectory());
581+
}
582+
else {
583+
// Compute the commonSourceDirectory from the input files
584+
commonSourceDirectory = computecommonSourceDirectory(files);
585+
}
586+
587+
if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) {
588+
// Make sure directory path ends with directory separator so this string can directly
589+
// used to replace with "" to get the relative path of the source file and the relative path doesn't
590+
// start with / making it rooted path
591+
commonSourceDirectory += directorySeparator;
592+
}
564593
}
565594

566595
if (options.noEmit) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,7 @@ module ts {
16481648
preserveConstEnums?: boolean;
16491649
project?: string;
16501650
removeComments?: boolean;
1651+
rootDir?: string;
16511652
sourceMap?: boolean;
16521653
sourceRoot?: string;
16531654
suppressImplicitAnyIndexErrors?: boolean;

src/harness/projectsRunner.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface ProjectRunnerTestCase {
1818
runTest?: boolean; // Run the resulting test
1919
bug?: string; // If there is any bug associated with this test case
2020
noResolve?: boolean;
21+
rootDir?: string; // --rootDir
2122
}
2223

2324
interface ProjectRunnerTestCaseResolutionInfo extends ProjectRunnerTestCase {
@@ -160,7 +161,8 @@ class ProjectRunner extends RunnerBase {
160161
mapRoot: testCase.resolveMapRoot && testCase.mapRoot ? ts.sys.resolvePath(testCase.mapRoot) : testCase.mapRoot,
161162
sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? ts.sys.resolvePath(testCase.sourceRoot) : testCase.sourceRoot,
162163
module: moduleKind,
163-
noResolve: testCase.noResolve
164+
noResolve: testCase.noResolve,
165+
rootDir: testCase.rootDir
164166
};
165167
}
166168

@@ -344,6 +346,7 @@ class ProjectRunner extends RunnerBase {
344346
baselineCheck: testCase.baselineCheck,
345347
runTest: testCase.runTest,
346348
bug: testCase.bug,
349+
rootDir: testCase.rootDir,
347350
resolvedInputFiles: ts.map(compilerResult.program.getSourceFiles(), inputFile => inputFile.fileName),
348351
emittedFiles: ts.map(compilerResult.outputFiles, outputFile => outputFile.emittedFileName)
349352
};

0 commit comments

Comments
 (0)