Merge pull request #12336 from Microsoft/ownJsonParsing

Use parser to parse tsconfig json instead of using Json.parse
This commit is contained in:
Sheetal Nandi
2017-06-15 14:30:42 -07:00
committed by GitHub
83 changed files with 2238 additions and 1041 deletions
+6
View File
@@ -27,6 +27,12 @@ namespace ts {
return symbol.id;
}
export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) {
const moduleState = getModuleInstanceState(node);
return moduleState === ModuleInstanceState.Instantiated ||
(preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly);
}
export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
// Cancellation that controls whether or not we can cancel in the middle of type checking.
// In general cancelling is *not* safe for the type checker. We might be in the middle of
File diff suppressed because it is too large Load Diff
+2
View File
@@ -2139,6 +2139,8 @@ namespace ts {
return ScriptKind.TS;
case Extension.Tsx:
return ScriptKind.TSX;
case ".json":
return ScriptKind.JSON;
default:
return ScriptKind.Unknown;
}
+9 -1
View File
@@ -1,4 +1,4 @@
{
{
"Unterminated string literal.": {
"category": "Error",
"code": 1002
@@ -899,6 +899,14 @@
"category": "Error",
"code": 1326
},
"String literal with double quotes expected.": {
"category": "Error",
"code": 1327
},
"Property value can only be string literal, numeric literal, 'true', 'false', 'null', object literal or array literal.": {
"category": "Error",
"code": 1328
},
"Duplicate identifier '{0}'.": {
"category": "Error",
+64
View File
@@ -8,6 +8,70 @@ namespace ts {
const delimiters = createDelimiterMap();
const brackets = createBracketsMap();
/*@internal*/
/**
* Iterates over the source files that are expected to have an emit output.
*
* @param host An EmitHost.
* @param action The action to execute.
* @param sourceFilesOrTargetSourceFile
* If an array, the full list of source files to emit.
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
*/
export function forEachEmittedFile(
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean) => void,
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
emitOnlyDtsFiles?: boolean) {
const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile);
const options = host.getCompilerOptions();
if (options.outFile || options.out) {
if (sourceFiles.length) {
const jsFilePath = options.outFile || options.out;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + Extension.Dts : "";
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
}
}
else {
for (const sourceFile of sourceFiles) {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFile, emitOnlyDtsFiles);
}
}
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): Extension {
if (options.jsx === JsxEmit.Preserve) {
if (isSourceFileJavaScript(sourceFile)) {
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
return Extension.Jsx;
}
}
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
// TypeScript source file preserving JSX syntax
return Extension.Jsx;
}
}
return Extension.Js;
}
function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) {
if (sourceFileOrBundle.kind === SyntaxKind.Bundle) {
return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile));
}
return getOriginalSourceFile(sourceFileOrBundle);
}
/*@internal*/
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean, transformers?: TransformerFactory<SourceFile>[]): EmitResult {
-191
View File
@@ -2287,14 +2287,6 @@ namespace ts {
return range;
}
/**
* Gets flags that control emit behavior of a node.
*/
export function getEmitFlags(node: Node): EmitFlags | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.flags;
}
/**
* Sets flags that control emit behavior of a node.
*/
@@ -3809,16 +3801,6 @@ namespace ts {
return node;
}
export function skipPartiallyEmittedExpressions(node: Expression): Expression;
export function skipPartiallyEmittedExpressions(node: Node): Node;
export function skipPartiallyEmittedExpressions(node: Node) {
while (node.kind === SyntaxKind.PartiallyEmittedExpression) {
node = (<PartiallyEmittedExpression>node).expression;
}
return node;
}
function updateOuterExpression(outerExpression: OuterExpression, expression: Expression) {
switch (outerExpression.kind) {
case SyntaxKind.ParenthesizedExpression: return updateParen(outerExpression, expression);
@@ -4239,177 +4221,4 @@ namespace ts {
Debug.assertNode(node, isExpression);
return <Expression>node;
}
export interface ExternalModuleInfo {
externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; // imports of other external modules
externalHelpersImportDeclaration: ImportDeclaration | undefined; // import of external helpers
exportSpecifiers: Map<ExportSpecifier[]>; // export specifiers by name
exportedBindings: Identifier[][]; // exported names of local declarations
exportedNames: Identifier[]; // all exported names local to module
exportEquals: ExportAssignment | undefined; // an export= declaration if one was present
hasExportStarsToExportValues: boolean; // whether this module contains export*
}
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
const exportSpecifiers = createMultiMap<ExportSpecifier>();
const exportedBindings: Identifier[][] = [];
const uniqueExports = createMap<boolean>();
let exportedNames: Identifier[];
let hasExportDefault = false;
let exportEquals: ExportAssignment = undefined;
let hasExportStarsToExportValues = false;
for (const node of sourceFile.statements) {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
// import "mod"
// import x from "mod"
// import * as x from "mod"
// import { x, y } from "mod"
externalImports.push(<ImportDeclaration>node);
break;
case SyntaxKind.ImportEqualsDeclaration:
if ((<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference) {
// import x = require("mod")
externalImports.push(<ImportEqualsDeclaration>node);
}
break;
case SyntaxKind.ExportDeclaration:
if ((<ExportDeclaration>node).moduleSpecifier) {
if (!(<ExportDeclaration>node).exportClause) {
// export * from "mod"
externalImports.push(<ExportDeclaration>node);
hasExportStarsToExportValues = true;
}
else {
// export { x, y } from "mod"
externalImports.push(<ExportDeclaration>node);
}
}
else {
// export { x, y }
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
if (!uniqueExports.get(specifier.name.text)) {
const name = specifier.propertyName || specifier.name;
exportSpecifiers.add(name.text, specifier);
const decl = resolver.getReferencedImportDeclaration(name)
|| resolver.getReferencedValueDeclaration(name);
if (decl) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
}
uniqueExports.set(specifier.name.text, true);
exportedNames = append(exportedNames, specifier.name);
}
}
}
break;
case SyntaxKind.ExportAssignment:
if ((<ExportAssignment>node).isExportEquals && !exportEquals) {
// export = x
exportEquals = <ExportAssignment>node;
}
break;
case SyntaxKind.VariableStatement:
if (hasModifier(node, ModifierFlags.Export)) {
for (const decl of (<VariableStatement>node).declarationList.declarations) {
exportedNames = collectExportedVariableInfo(decl, uniqueExports, exportedNames);
}
}
break;
case SyntaxKind.FunctionDeclaration:
if (hasModifier(node, ModifierFlags.Export)) {
if (hasModifier(node, ModifierFlags.Default)) {
// export default function() { }
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<FunctionDeclaration>node));
hasExportDefault = true;
}
}
else {
// export function x() { }
const name = (<FunctionDeclaration>node).name;
if (!uniqueExports.get(name.text)) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(name.text, true);
exportedNames = append(exportedNames, name);
}
}
}
break;
case SyntaxKind.ClassDeclaration:
if (hasModifier(node, ModifierFlags.Export)) {
if (hasModifier(node, ModifierFlags.Default)) {
// export default class { }
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<ClassDeclaration>node));
hasExportDefault = true;
}
}
else {
// export class x { }
const name = (<ClassDeclaration>node).name;
if (!uniqueExports.get(name.text)) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(name.text, true);
exportedNames = append(exportedNames, name);
}
}
}
break;
}
}
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues);
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText));
if (externalHelpersImportDeclaration) {
externalImports.unshift(externalHelpersImportDeclaration);
}
return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration };
}
function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: Map<boolean>, exportedNames: Identifier[]) {
if (isBindingPattern(decl.name)) {
for (const element of decl.name.elements) {
if (!isOmittedExpression(element)) {
exportedNames = collectExportedVariableInfo(element, uniqueExports, exportedNames);
}
}
}
else if (!isGeneratedIdentifier(decl.name)) {
if (!uniqueExports.get(decl.name.text)) {
uniqueExports.set(decl.name.text, true);
exportedNames = append(exportedNames, decl.name);
}
}
return exportedNames;
}
/** Use a sparse array as a multi-map. */
function multiMapSparseArrayAdd<V>(map: V[][], key: number, value: V): V[] {
let values = map[key];
if (values) {
values.push(value);
}
else {
map[key] = values = [value];
}
return values;
}
}
+36 -3
View File
@@ -1,6 +1,5 @@
/// <reference path="utilities.ts"/>
/// <reference path="scanner.ts"/>
/// <reference path="factory.ts"/>
namespace ts {
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
@@ -466,6 +465,15 @@ namespace ts {
return Parser.parseIsolatedEntityName(text, languageVersion);
}
/**
* Parse json text into SyntaxTree and return node and parse errors if any
* @param fileName
* @param sourceText
*/
export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {
return Parser.parseJsonText(fileName, sourceText);
}
// See also `isExternalOrCommonJsModule` in utilities.ts
export function isExternalModule(file: SourceFile): boolean {
return file.externalModuleIndicator !== undefined;
@@ -632,9 +640,34 @@ namespace ts {
return isInvalid ? entityName : undefined;
}
export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {
initializeState(sourceText, ScriptTarget.ES2015, /*syntaxCursor*/ undefined, ScriptKind.JSON);
// Set source file so that errors will be reported with this file name
sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON);
const result = <JsonSourceFile>sourceFile;
// Prime the scanner.
nextToken();
if (token() === SyntaxKind.EndOfFileToken) {
sourceFile.endOfFileToken = <EndOfFileToken>parseTokenNode();
}
else if (token() === SyntaxKind.OpenBraceToken ||
lookAhead(() => token() === SyntaxKind.StringLiteral)) {
result.jsonObject = parseObjectLiteralExpression();
sourceFile.endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, /*reportAtCurrentPosition*/ false, Diagnostics.Unexpected_token);
}
else {
parseExpected(SyntaxKind.OpenBraceToken);
}
sourceFile.parseDiagnostics = parseDiagnostics;
clearState();
return result;
}
function getLanguageVariant(scriptKind: ScriptKind) {
// .tsx and .jsx files are treated as jsx language variant.
return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS ? LanguageVariant.JSX : LanguageVariant.Standard;
return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard;
}
function initializeState(_sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, scriptKind: ScriptKind) {
@@ -652,7 +685,7 @@ namespace ts {
identifierCount = 0;
nodeCount = 0;
contextFlags = scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX ? NodeFlags.JavaScriptFile : NodeFlags.None;
contextFlags = scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JSON ? NodeFlags.JavaScriptFile : NodeFlags.None;
parseErrorBeforeNextFinishedNode = false;
// Initialize and prime the scanner before parsing the source elements.
+123 -31
View File
@@ -442,6 +442,7 @@ namespace ts {
// Map storing if there is emit blocking diagnostics for given input
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName);
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression;
let moduleResolutionCache: ModuleResolutionCache;
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[];
@@ -1328,7 +1329,11 @@ namespace ts {
function getOptionsDiagnostics(): Diagnostic[] {
return sortAndDeduplicateDiagnostics(concatenate(
fileProcessingDiagnostics.getGlobalDiagnostics(),
programDiagnostics.getGlobalDiagnostics()));
concatenate(
programDiagnostics.getGlobalDiagnostics(),
options.configFile ? programDiagnostics.getDiagnostics(options.configFile.fileName) : []
)
));
}
function getGlobalDiagnostics(): Diagnostic[] {
@@ -1773,33 +1778,33 @@ namespace ts {
function verifyCompilerOptions() {
if (options.isolatedModules) {
if (options.declaration) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declaration", "isolatedModules"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declaration", "isolatedModules");
}
if (options.noEmitOnError) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmitOnError", "isolatedModules"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmitOnError", "isolatedModules");
}
if (options.out) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "isolatedModules");
}
if (options.outFile) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", "isolatedModules"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "outFile", "isolatedModules");
}
}
if (options.inlineSourceMap) {
if (options.sourceMap) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "sourceMap", "inlineSourceMap");
}
if (options.mapRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap");
}
}
if (options.paths && options.baseUrl === undefined) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_paths_cannot_be_used_without_specifying_baseUrl_option));
createDiagnosticForOptionName(Diagnostics.Option_paths_cannot_be_used_without_specifying_baseUrl_option, "paths");
}
if (options.paths) {
@@ -1808,63 +1813,65 @@ namespace ts {
continue;
}
if (!hasZeroOrOneAsteriskCharacter(key)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key));
createDiagnosticForOptionPaths(/*onKey*/ true, key, Diagnostics.Pattern_0_can_have_at_most_one_Asterisk_character, key);
}
if (isArray(options.paths[key])) {
if (options.paths[key].length === 0) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key));
const len = options.paths[key].length;
if (len === 0) {
createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_shouldn_t_be_an_empty_array, key);
}
for (const subst of options.paths[key]) {
for (let i = 0; i < len; i++) {
const subst = options.paths[key][i];
const typeOfSubst = typeof subst;
if (typeOfSubst === "string") {
if (!hasZeroOrOneAsteriskCharacter(subst)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key));
createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_in_pattern_1_in_can_have_at_most_one_Asterisk_character, subst, key);
}
}
else {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst));
createDiagnosticForOptionPathKeyValue(key, i, Diagnostics.Substitution_0_for_pattern_1_has_incorrect_type_expected_string_got_2, subst, key, typeOfSubst);
}
}
}
else {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key));
createDiagnosticForOptionPaths(/*onKey*/ false, key, Diagnostics.Substitutions_for_pattern_0_should_be_an_array, key);
}
}
}
if (!options.sourceMap && !options.inlineSourceMap) {
if (options.inlineSources) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources"));
createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "inlineSources");
}
if (options.sourceRoot) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot"));
createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided, "sourceRoot");
}
}
if (options.out && options.outFile) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile");
}
if (options.mapRoot && !options.sourceMap) {
// Error to specify --mapRoot without --sourcemap
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "mapRoot", "sourceMap");
}
if (options.declarationDir) {
if (!options.declaration) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationDir", "declaration"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationDir", "declaration");
}
if (options.out || options.outFile) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile");
}
}
if (options.lib && options.noLib) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "lib", "noLib");
}
if (options.noImplicitUseStrict && (options.alwaysStrict === undefined ? options.strict : options.alwaysStrict)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict");
}
const languageVersion = options.target || ScriptTarget.ES3;
@@ -1873,7 +1880,7 @@ namespace ts {
const firstNonAmbientExternalModuleSourceFile = forEach(files, f => isExternalModule(f) && !f.isDeclarationFile ? f : undefined);
if (options.isolatedModules) {
if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher));
createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target");
}
const firstNonExternalModuleSourceFile = forEach(files, f => !isExternalModule(f) && !f.isDeclarationFile ? f : undefined);
@@ -1891,7 +1898,7 @@ namespace ts {
// Cannot specify module gen that isn't amd or system with --out
if (outFile) {
if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile"));
createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module");
}
else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) {
const span = getErrorSpanForNode(firstNonAmbientExternalModuleSourceFile, firstNonAmbientExternalModuleSourceFile.externalModuleIndicator);
@@ -1910,12 +1917,12 @@ namespace ts {
// If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
if (options.outDir && dir === "" && forEach(files, file => getRootLength(file.fileName) > 1)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
createDiagnosticForOptionName(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files, "outDir");
}
}
if (!options.noEmit && options.allowJs && options.declaration) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration");
}
if (options.checkJs && !options.allowJs) {
@@ -1924,19 +1931,19 @@ namespace ts {
if (options.emitDecoratorMetadata &&
!options.experimentalDecorators) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators");
}
if (options.jsxFactory) {
if (options.reactNamespace) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory"));
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory");
}
if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory));
createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory);
}
}
else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace));
createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace);
}
// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
@@ -1976,6 +1983,91 @@ namespace ts {
}
}
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0: string | number, arg1: string | number, arg2?: string | number) {
let needCompilerDiagnostic = true;
const pathsSyntax = getOptionPathsSyntax();
for (const pathProp of pathsSyntax) {
if (isObjectLiteralExpression(pathProp.initializer)) {
for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) {
if (isArrayLiteralExpression(keyProps.initializer) &&
keyProps.initializer.elements.length > valueIndex) {
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile, keyProps.initializer.elements[valueIndex], message, arg0, arg1, arg2));
needCompilerDiagnostic = false;
}
}
}
}
if (needCompilerDiagnostic) {
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
}
}
function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, arg0: string | number) {
let needCompilerDiagnostic = true;
const pathsSyntax = getOptionPathsSyntax();
for (const pathProp of pathsSyntax) {
if (isObjectLiteralExpression(pathProp.initializer) &&
createOptionDiagnosticInObjectLiteralSyntax(
pathProp.initializer, onKey, key, /*key2*/ undefined,
message, arg0)) {
needCompilerDiagnostic = false;
}
}
if (needCompilerDiagnostic) {
programDiagnostics.add(createCompilerDiagnostic(message, arg0));
}
}
function getOptionPathsSyntax() {
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
if (compilerOptionsObjectLiteralSyntax) {
return getPropertyAssignment(compilerOptionsObjectLiteralSyntax, "paths");
}
return emptyArray;
}
function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string) {
createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2);
}
function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, arg0: string) {
createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0);
}
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string, message: DiagnosticMessage, arg0: string | number, arg1?: string | number) {
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax ||
!createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1);
if (needCompilerDiagnostic) {
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
}
}
function getCompilerOptionsObjectLiteralSyntax() {
if (_compilerOptionsObjectLiteralSyntax === undefined) {
_compilerOptionsObjectLiteralSyntax = null; // tslint:disable-line:no-null-keyword
if (options.configFile && options.configFile.jsonObject) {
for (const prop of getPropertyAssignment(options.configFile.jsonObject, "compilerOptions")) {
if (isObjectLiteralExpression(prop.initializer)) {
_compilerOptionsObjectLiteralSyntax = prop.initializer;
break;
}
}
}
}
return _compilerOptionsObjectLiteralSyntax;
}
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string, message: DiagnosticMessage, arg0: string | number, arg1?: string | number): boolean {
const props = getPropertyAssignment(objectLiteral, key1, key2);
for (const prop of props) {
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile, onKey ? prop.name : prop.initializer, message, arg0, arg1));
}
return !!props.length;
}
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
hasEmitBlockingDiagnostics.set(toPath(emitFileName, currentDirectory, getCanonicalFileName), true);
programDiagnostics.add(diag);
+1
View File
@@ -1,4 +1,5 @@
/// <reference path="visitor.ts" />
/// <reference path="transformers/utilities.ts" />
/// <reference path="transformers/ts.ts" />
/// <reference path="transformers/jsx.ts" />
/// <reference path="transformers/esnext.ts" />
+180
View File
@@ -0,0 +1,180 @@
/* @internal */
namespace ts {
export function getOriginalNodeId(node: Node) {
node = getOriginalNode(node);
return node ? getNodeId(node) : 0;
}
export interface ExternalModuleInfo {
externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; // imports of other external modules
externalHelpersImportDeclaration: ImportDeclaration | undefined; // import of external helpers
exportSpecifiers: Map<ExportSpecifier[]>; // export specifiers by name
exportedBindings: Identifier[][]; // exported names of local declarations
exportedNames: Identifier[]; // all exported names local to module
exportEquals: ExportAssignment | undefined; // an export= declaration if one was present
hasExportStarsToExportValues: boolean; // whether this module contains export*
}
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
const exportSpecifiers = createMultiMap<ExportSpecifier>();
const exportedBindings: Identifier[][] = [];
const uniqueExports = createMap<boolean>();
let exportedNames: Identifier[];
let hasExportDefault = false;
let exportEquals: ExportAssignment = undefined;
let hasExportStarsToExportValues = false;
for (const node of sourceFile.statements) {
switch (node.kind) {
case SyntaxKind.ImportDeclaration:
// import "mod"
// import x from "mod"
// import * as x from "mod"
// import { x, y } from "mod"
externalImports.push(<ImportDeclaration>node);
break;
case SyntaxKind.ImportEqualsDeclaration:
if ((<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference) {
// import x = require("mod")
externalImports.push(<ImportEqualsDeclaration>node);
}
break;
case SyntaxKind.ExportDeclaration:
if ((<ExportDeclaration>node).moduleSpecifier) {
if (!(<ExportDeclaration>node).exportClause) {
// export * from "mod"
externalImports.push(<ExportDeclaration>node);
hasExportStarsToExportValues = true;
}
else {
// export { x, y } from "mod"
externalImports.push(<ExportDeclaration>node);
}
}
else {
// export { x, y }
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
if (!uniqueExports.get(specifier.name.text)) {
const name = specifier.propertyName || specifier.name;
exportSpecifiers.add(name.text, specifier);
const decl = resolver.getReferencedImportDeclaration(name)
|| resolver.getReferencedValueDeclaration(name);
if (decl) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
}
uniqueExports.set(specifier.name.text, true);
exportedNames = append(exportedNames, specifier.name);
}
}
}
break;
case SyntaxKind.ExportAssignment:
if ((<ExportAssignment>node).isExportEquals && !exportEquals) {
// export = x
exportEquals = <ExportAssignment>node;
}
break;
case SyntaxKind.VariableStatement:
if (hasModifier(node, ModifierFlags.Export)) {
for (const decl of (<VariableStatement>node).declarationList.declarations) {
exportedNames = collectExportedVariableInfo(decl, uniqueExports, exportedNames);
}
}
break;
case SyntaxKind.FunctionDeclaration:
if (hasModifier(node, ModifierFlags.Export)) {
if (hasModifier(node, ModifierFlags.Default)) {
// export default function() { }
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<FunctionDeclaration>node));
hasExportDefault = true;
}
}
else {
// export function x() { }
const name = (<FunctionDeclaration>node).name;
if (!uniqueExports.get(name.text)) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(name.text, true);
exportedNames = append(exportedNames, name);
}
}
}
break;
case SyntaxKind.ClassDeclaration:
if (hasModifier(node, ModifierFlags.Export)) {
if (hasModifier(node, ModifierFlags.Default)) {
// export default class { }
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<ClassDeclaration>node));
hasExportDefault = true;
}
}
else {
// export class x { }
const name = (<ClassDeclaration>node).name;
if (!uniqueExports.get(name.text)) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(name.text, true);
exportedNames = append(exportedNames, name);
}
}
}
break;
}
}
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues);
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
createLiteral(externalHelpersModuleNameText));
if (externalHelpersImportDeclaration) {
externalImports.unshift(externalHelpersImportDeclaration);
}
return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration };
}
function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: Map<boolean>, exportedNames: Identifier[]) {
if (isBindingPattern(decl.name)) {
for (const element of decl.name.elements) {
if (!isOmittedExpression(element)) {
exportedNames = collectExportedVariableInfo(element, uniqueExports, exportedNames);
}
}
}
else if (!isGeneratedIdentifier(decl.name)) {
if (!uniqueExports.get(decl.name.text)) {
uniqueExports.set(decl.name.text, true);
exportedNames = append(exportedNames, decl.name);
}
}
return exportedNames;
}
/** Use a sparse array as a multi-map. */
function multiMapSparseArrayAdd<V>(map: V[][], key: number, value: V): V[] {
let values = map[key];
if (values) {
values.push(value);
}
else {
map[key] = values = [value];
}
return values;
}
}
+6 -13
View File
@@ -223,20 +223,13 @@ namespace ts {
return;
}
const result = parseConfigFileTextToJson(configFileName, cachedConfigFileText);
const configObject = result.config;
if (!configObject) {
reportDiagnostics([result.error], /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
const result = parseJsonText(configFileName, cachedConfigFileText);
reportDiagnostics(result.parseDiagnostics, /* compilerHost */ undefined);
const cwd = sys.getCurrentDirectory();
const configParseResult = parseJsonConfigFileContent(configObject, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd));
if (configParseResult.errors.length > 0) {
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
const configParseResult = parseJsonSourceFileConfigFileContent(result, sys, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), commandLine.options, getNormalizedAbsolutePath(configFileName, cwd));
reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined);
if (isWatchSet(configParseResult.options)) {
if (!sys.watchFile) {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* host */ undefined);
+1
View File
@@ -17,6 +17,7 @@
"checker.ts",
"factory.ts",
"visitor.ts",
"transformers/utilities.ts",
"transformers/ts.ts",
"transformers/jsx.ts",
"transformers/esnext.ts",
+11 -2
View File
@@ -2375,6 +2375,11 @@ namespace ts {
sourceFiles: SourceFile[];
}
export interface JsonSourceFile extends SourceFile {
jsonObject?: ObjectLiteralExpression;
extendedSourceFiles?: string[];
}
export interface ScriptReferenceHost {
getCompilerOptions(): CompilerOptions;
getSourceFile(fileName: string): SourceFile;
@@ -3488,6 +3493,7 @@ namespace ts {
charset?: string;
checkJs?: boolean;
/* @internal */ configFilePath?: string;
/* @internal */ readonly configFile?: JsonSourceFile;
declaration?: boolean;
declarationDir?: string;
/* @internal */ diagnostics?: boolean;
@@ -3560,7 +3566,7 @@ namespace ts {
/*@internal*/ version?: boolean;
/*@internal*/ watch?: boolean;
[option: string]: CompilerOptionsValue | undefined;
[option: string]: CompilerOptionsValue | JsonSourceFile | undefined;
}
export interface TypeAcquisition {
@@ -3620,7 +3626,8 @@ namespace ts {
JSX = 2,
TS = 3,
TSX = 4,
External = 5
External = 5,
JSON = 6
}
export const enum ScriptTarget {
@@ -3692,6 +3699,8 @@ namespace ts {
/* @internal */
export interface TsConfigOnlyOption extends CommandLineOptionBase {
type: "object";
elementOptions?: Map<CommandLineOption>;
extraKeyDiagnosticMessage?: DiagnosticMessage;
}
/* @internal */
+28 -75
View File
@@ -309,6 +309,14 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node, includeTrivia);
}
/**
* Gets flags that control emit behavior of a node.
*/
export function getEmitFlags(node: Node): EmitFlags | undefined {
const emitNode = node.emitNode;
return emitNode && emitNode.flags;
}
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile) {
// If we don't need to downlevel and we can reach the original source text using
// the node's parent reference, then simply get the text as it was originally written.
@@ -882,6 +890,15 @@ namespace ts {
return predicate && predicate.kind === TypePredicateKind.This;
}
export function getPropertyAssignment(objectLiteral: ObjectLiteralExpression, key: string, key2?: string) {
return <PropertyAssignment[]>filter(objectLiteral.properties, property => {
if (property.kind === SyntaxKind.PropertyAssignment) {
const propName = getTextOfPropertyName(property.name);
return key === propName || (key2 && key2 === propName);
}
});
}
export function getContainingFunction(node: Node): FunctionLikeDeclaration {
while (true) {
node = node.parent;
@@ -1242,12 +1259,6 @@ namespace ts {
return false;
}
export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) {
const moduleState = getModuleInstanceState(node);
return moduleState === ModuleInstanceState.Instantiated ||
(preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly);
}
export function isExternalModuleImportEqualsDeclaration(node: Node) {
return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
}
@@ -2013,14 +2024,7 @@ namespace ts {
|| positionIsSynthesized(node.end);
}
export function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) {
if (sourceFileOrBundle.kind === SyntaxKind.Bundle) {
return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile));
}
return getOriginalSourceFile(sourceFileOrBundle);
}
function getOriginalSourceFile(sourceFile: SourceFile) {
export function getOriginalSourceFile(sourceFile: SourceFile) {
return getParseTreeNode(sourceFile, isSourceFile) || sourceFile;
}
@@ -2028,11 +2032,6 @@ namespace ts {
return sameMap(sourceFiles, getOriginalSourceFile);
}
export function getOriginalNodeId(node: Node) {
node = getOriginalNode(node);
return node ? getNodeId(node) : 0;
}
export const enum Associativity {
Left,
Right
@@ -2540,62 +2539,6 @@ namespace ts {
return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !sourceFile.isDeclarationFile && !isSourceFileFromExternalLibrary(sourceFile);
}
/**
* Iterates over the source files that are expected to have an emit output.
*
* @param host An EmitHost.
* @param action The action to execute.
* @param sourceFilesOrTargetSourceFile
* If an array, the full list of source files to emit.
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
*/
export function forEachEmittedFile(
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean) => void,
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
emitOnlyDtsFiles?: boolean) {
const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile);
const options = host.getCompilerOptions();
if (options.outFile || options.out) {
if (sourceFiles.length) {
const jsFilePath = options.outFile || options.out;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + Extension.Dts : "";
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
}
}
else {
for (const sourceFile of sourceFiles) {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFile, emitOnlyDtsFiles);
}
}
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): Extension {
if (options.jsx === JsxEmit.Preserve) {
if (isSourceFileJavaScript(sourceFile)) {
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
return Extension.Jsx;
}
}
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
// TypeScript source file preserving JSX syntax
return Extension.Jsx;
}
}
return Extension.Js;
}
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory());
const commonSourceDirectory = host.getCommonSourceDirectory();
@@ -4284,6 +4227,16 @@ namespace ts {
return node.kind === SyntaxKind.ParenthesizedExpression;
}
export function skipPartiallyEmittedExpressions(node: Expression): Expression;
export function skipPartiallyEmittedExpressions(node: Node): Node;
export function skipPartiallyEmittedExpressions(node: Node) {
while (node.kind === SyntaxKind.PartiallyEmittedExpression) {
node = (<PartiallyEmittedExpression>node).expression;
}
return node;
}
export function isFunctionExpression(node: Node): node is FunctionExpression {
return node.kind === SyntaxKind.FunctionExpression;
}
+15 -6
View File
@@ -64,6 +64,7 @@ class CompilerBaselineRunner extends RunnerBase {
let result: Harness.Compiler.CompilerResult;
let options: ts.CompilerOptions;
let tsConfigFiles: Harness.Compiler.TestFile[];
// equivalent to the files that will be passed on the command line
let toBeCompiled: Harness.Compiler.TestFile[];
// equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files)
@@ -77,10 +78,12 @@ class CompilerBaselineRunner extends RunnerBase {
const units = testCaseContent.testUnitData;
harnessSettings = testCaseContent.settings;
let tsConfigOptions: ts.CompilerOptions;
tsConfigFiles = [];
if (testCaseContent.tsConfig) {
assert.equal(testCaseContent.tsConfig.fileNames.length, 0, `list of files in tsconfig is not currently supported`);
tsConfigOptions = ts.clone(testCaseContent.tsConfig.options);
tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options);
tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath)));
}
else {
const baseUrl = harnessSettings["baseUrl"];
@@ -98,21 +101,22 @@ class CompilerBaselineRunner extends RunnerBase {
otherFiles = [];
if (testCaseContent.settings["noImplicitReferences"] || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions });
toBeCompiled.push(this.createHarnessTestFile(lastUnit, rootDir));
units.forEach(unit => {
if (unit.name !== lastUnit.name) {
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions });
otherFiles.push(this.createHarnessTestFile(unit, rootDir));
}
});
}
else {
toBeCompiled = units.map(unit => {
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions };
return this.createHarnessTestFile(unit, rootDir);
});
}
if (tsConfigOptions && tsConfigOptions.configFilePath !== undefined) {
tsConfigOptions.configFilePath = ts.combinePaths(rootDir, tsConfigOptions.configFilePath);
tsConfigOptions.configFile.fileName = tsConfigOptions.configFilePath;
}
const output = Harness.Compiler.compileFiles(
@@ -132,11 +136,12 @@ class CompilerBaselineRunner extends RunnerBase {
options = undefined;
toBeCompiled = undefined;
otherFiles = undefined;
tsConfigFiles = undefined;
});
// check errors
it("Correct errors for " + fileName, () => {
Harness.Compiler.doErrorBaseline(justName, toBeCompiled.concat(otherFiles), result.errors);
Harness.Compiler.doErrorBaseline(justName, tsConfigFiles.concat(toBeCompiled, otherFiles), result.errors);
});
it (`Correct module resolution tracing for ${fileName}`, () => {
@@ -165,7 +170,7 @@ class CompilerBaselineRunner extends RunnerBase {
it("Correct JS output for " + fileName, () => {
if (hasNonDtsFiles && this.emit) {
Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, toBeCompiled, otherFiles, harnessSettings);
Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, tsConfigFiles, toBeCompiled, otherFiles, harnessSettings);
}
});
@@ -183,6 +188,10 @@ class CompilerBaselineRunner extends RunnerBase {
});
}
private createHarnessTestFile(lastUnit: Harness.TestCaseParser.TestUnitData, rootDir: string, unitName?: string): Harness.Compiler.TestFile {
return { unitName: unitName || this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions };
}
public initializeTests() {
describe(this.testSuiteName + " tests", () => {
describe("Setup compiler for compiler baselines", () => {
+15 -8
View File
@@ -1125,7 +1125,7 @@ namespace Harness {
compilerOptions: ts.CompilerOptions,
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
currentDirectory: string): CompilationOutput {
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false };
const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false };
options.target = options.target || ts.ScriptTarget.ES3;
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
options.noErrorTruncation = true;
@@ -1557,7 +1557,7 @@ namespace Harness {
}
}
export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, tsConfigFiles: Harness.Compiler.TestFile[], toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) {
throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
}
@@ -1593,7 +1593,7 @@ namespace Harness {
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
jsCode += "\r\n\r\n";
jsCode += Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
jsCode += Harness.Compiler.getErrorBaseline(tsConfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}
if (jsCode.length > 0) {
@@ -1744,7 +1744,12 @@ namespace Harness {
}
/** Given a test file containing // @FileName directives, return an array of named units of code to be added to an existing compiler instance */
export function makeUnitsFromTest(code: string, fileName: string, rootDir?: string): { settings: CompilerSettings; testUnitData: TestUnitData[]; tsConfig: ts.ParsedCommandLine } {
export function makeUnitsFromTest(code: string, fileName: string, rootDir?: string): {
settings: CompilerSettings;
testUnitData: TestUnitData[];
tsConfig: ts.ParsedCommandLine;
tsConfigFileUnitData: TestUnitData;
} {
const settings = extractCompilerSettings(code);
// List of all the subfiles we've parsed out
@@ -1830,17 +1835,19 @@ namespace Harness {
// check if project has tsconfig.json in the list of files
let tsConfig: ts.ParsedCommandLine;
let tsConfigFileUnitData: TestUnitData;
for (let i = 0; i < testUnitData.length; i++) {
const data = testUnitData[i];
if (ts.getBaseFileName(data.name).toLowerCase() === "tsconfig.json") {
const configJson = ts.parseConfigFileTextToJson(data.name, data.content);
assert.isTrue(configJson.config !== undefined);
const configJson = ts.parseJsonText(data.name, data.content);
assert.isTrue(configJson.endOfFileToken !== undefined);
let baseDir = ts.normalizePath(ts.getDirectoryPath(data.name));
if (rootDir) {
baseDir = ts.getNormalizedAbsolutePath(baseDir, rootDir);
}
tsConfig = ts.parseJsonConfigFileContent(configJson.config, parseConfigHost, baseDir);
tsConfig = ts.parseJsonSourceFileConfigFileContent(configJson, parseConfigHost, baseDir);
tsConfig.options.configFilePath = data.name;
tsConfigFileUnitData = data;
// delete entry from the list
ts.orderedRemoveItemAt(testUnitData, i);
@@ -1848,7 +1855,7 @@ namespace Harness {
break;
}
}
return { settings, testUnitData, tsConfig };
return { settings, testUnitData, tsConfig, tsConfigFileUnitData };
}
}
+24 -30
View File
@@ -24,6 +24,7 @@ interface BatchCompileProjectTestCaseEmittedFile extends Harness.Compiler.Genera
}
interface CompileProjectFilesResult {
configFileSourceFiles: ts.SourceFile[];
moduleKind: ts.ModuleKind;
program?: ts.Program;
compilerOptions?: ts.CompilerOptions;
@@ -124,7 +125,8 @@ class ProjectRunner extends RunnerBase {
return Harness.IO.resolvePath(testCase.projectRoot);
}
function compileProjectFiles(moduleKind: ts.ModuleKind, getInputFiles: () => string[],
function compileProjectFiles(moduleKind: ts.ModuleKind, configFileSourceFiles: ts.SourceFile[],
getInputFiles: () => string[],
getSourceFileTextImpl: (fileName: string) => string,
writeFile: (fileName: string, data: string, writeByteOrderMark: boolean) => void,
compilerOptions: ts.CompilerOptions): CompileProjectFilesResult {
@@ -148,6 +150,7 @@ class ProjectRunner extends RunnerBase {
}
return {
configFileSourceFiles,
moduleKind,
program,
errors,
@@ -196,6 +199,7 @@ class ProjectRunner extends RunnerBase {
const outputFiles: BatchCompileProjectTestCaseEmittedFile[] = [];
let inputFiles = testCase.inputFiles;
let compilerOptions = createCompilerOptions();
const configFileSourceFiles: ts.SourceFile[] = [];
let configFileName: string;
if (compilerOptions.project) {
@@ -207,41 +211,31 @@ class ProjectRunner extends RunnerBase {
configFileName = ts.findConfigFile("", fileExists);
}
let errors: ts.Diagnostic[];
if (configFileName) {
const result = ts.readConfigFile(configFileName, getSourceFileText);
if (result.error) {
return {
moduleKind,
errors: [result.error]
};
}
const configObject = result.config;
const result = ts.readJsonConfigFile(configFileName, getSourceFileText);
configFileSourceFiles.push(result);
const configParseHost: ts.ParseConfigHost = {
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
fileExists,
readDirectory,
readFile
};
const configParseResult = ts.parseJsonConfigFileContent(configObject, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
if (configParseResult.errors.length > 0) {
return {
moduleKind,
errors: configParseResult.errors
};
}
const configParseResult = ts.parseJsonSourceFileConfigFileContent(result, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
inputFiles = configParseResult.fileNames;
compilerOptions = configParseResult.options;
errors = result.parseDiagnostics.concat(configParseResult.errors);
}
const projectCompilerResult = compileProjectFiles(moduleKind, () => inputFiles, getSourceFileText, writeFile, compilerOptions);
const projectCompilerResult = compileProjectFiles(moduleKind, configFileSourceFiles, () => inputFiles, getSourceFileText, writeFile, compilerOptions);
return {
configFileSourceFiles,
moduleKind,
program: projectCompilerResult.program,
compilerOptions,
sourceMapData: projectCompilerResult.sourceMapData,
outputFiles,
errors: projectCompilerResult.errors,
errors: errors ? errors.concat(projectCompilerResult.errors) : projectCompilerResult.errors,
};
function createCompilerOptions() {
@@ -402,7 +396,7 @@ class ProjectRunner extends RunnerBase {
});
// Dont allow config files since we are compiling existing source options
return compileProjectFiles(compilerResult.moduleKind, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
return compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
function findOutputDtsFile(fileName: string) {
return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.emittedFileName === fileName ? outputFile : undefined);
@@ -428,16 +422,16 @@ class ProjectRunner extends RunnerBase {
}
function getErrorsBaseline(compilerResult: CompileProjectFilesResult) {
const inputFiles = compilerResult.program ? ts.map(ts.filter(compilerResult.program.getSourceFiles(),
sourceFile => !Harness.isDefaultLibraryFile(sourceFile.fileName)),
sourceFile => {
return {
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
RunnerBase.removeFullPaths(sourceFile.fileName) :
sourceFile.fileName,
content: sourceFile.text
};
}) : [];
const inputFiles = ts.map(compilerResult.configFileSourceFiles.concat(
compilerResult.program ?
ts.filter(compilerResult.program.getSourceFiles(), sourceFile => !Harness.isDefaultLibraryFile(sourceFile.fileName)) :
[]),
sourceFile => <Harness.Compiler.TestFile>{
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
RunnerBase.removeFullPaths(sourceFile.fileName) :
sourceFile.fileName,
content: sourceFile.text
});
return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors);
}
+10 -6
View File
@@ -30,6 +30,7 @@ namespace RWC {
describe("Testing a RWC project: " + jsonPath, () => {
let inputFiles: Harness.Compiler.TestFile[] = [];
let otherFiles: Harness.Compiler.TestFile[] = [];
let tsconfigFiles: Harness.Compiler.TestFile[] = [];
let compilerResult: Harness.Compiler.CompilerResult;
let compilerOptions: ts.CompilerOptions;
const baselineOpts: Harness.Baseline.BaselineOptions = {
@@ -44,6 +45,7 @@ namespace RWC {
// Therefore we have to clean out large objects after the test is done.
inputFiles = [];
otherFiles = [];
tsconfigFiles = [];
compilerResult = undefined;
compilerOptions = undefined;
currentDirectory = undefined;
@@ -74,16 +76,18 @@ namespace RWC {
const tsconfigFile = ts.forEach(ioLog.filesRead, f => isTsConfigFile(f) ? f : undefined);
if (tsconfigFile) {
const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path);
const parsedTsconfigFileContents = ts.parseConfigFileTextToJson(tsconfigFile.path, tsconfigFileContents.content);
tsconfigFiles.push({ unitName: tsconfigFile.path, content: tsconfigFileContents.content });
const parsedTsconfigFileContents = ts.parseJsonText(tsconfigFile.path, tsconfigFileContents.content);
const configParseHost: ts.ParseConfigHost = {
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
fileExists: Harness.IO.fileExists,
readDirectory: Harness.IO.readDirectory,
readFile: Harness.IO.readFile
};
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
const configParseResult = ts.parseJsonSourceFileConfigFileContent(parsedTsconfigFileContents, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
fileNames = configParseResult.fileNames;
opts.options = ts.extend(opts.options, configParseResult.options);
ts.setConfigFileInOptions(opts.options, configParseResult.options.configFile);
}
// Load the files
@@ -198,8 +202,8 @@ namespace RWC {
return null;
}
// Do not include the library in the baselines to avoid noise
const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
const errors = compilerResult.errors.filter(e => e.file && !Harness.isDefaultLibraryFile(e.file.fileName));
const baselineFiles = tsconfigFiles.concat(inputFiles, otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
const errors = compilerResult.errors.filter(e => !e.file || !Harness.isDefaultLibraryFile(e.file.fileName));
return Harness.Compiler.getErrorBaseline(baselineFiles, errors);
}, baselineOpts);
});
@@ -218,7 +222,7 @@ namespace RWC {
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
Harness.IO.newLine() + Harness.IO.newLine() +
Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
Harness.Compiler.getErrorBaseline(tsconfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}, baselineOpts);
}
});
@@ -259,4 +263,4 @@ class RWCRunner extends RunnerBase {
private runTest(jsonFileName: string) {
RWC.runRWCTest(jsonFileName);
}
}
}
+1
View File
@@ -24,6 +24,7 @@
"../compiler/checker.ts",
"../compiler/factory.ts",
"../compiler/visitor.ts",
"../compiler/transformers/utilities.ts",
"../compiler/transformers/ts.ts",
"../compiler/transformers/jsx.ts",
"../compiler/transformers/esnext.ts",
@@ -158,7 +158,7 @@ namespace ts {
// setting compiler options discards module resolution cache
fileExistsCalled = false;
const compilerOptions = ts.clone(project.getCompilerOptions());
const compilerOptions = ts.cloneCompilerOptions(project.getCompilerOptions());
compilerOptions.target = ts.ScriptTarget.ES5;
project.setCompilerOptions(compilerOptions);
@@ -111,23 +111,47 @@ namespace ts {
["under a case insensitive host", caseInsensitiveBasePath, caseInsensitiveHost],
["under a case sensitive host", caseSensitiveBasePath, caseSensitiveHost]
], ([testName, basePath, host]) => {
function getParseCommandLine(entry: string) {
const {config, error} = ts.readConfigFile(entry, name => host.readFile(name));
assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n"));
return ts.parseJsonConfigFileContent(config, host, basePath, {}, entry);
}
function getParseCommandLineJsonSourceFile(entry: string) {
const jsonSourceFile = ts.readJsonConfigFile(entry, name => host.readFile(name));
assert(jsonSourceFile.endOfFileToken && !jsonSourceFile.parseDiagnostics.length, flattenDiagnosticMessageText(jsonSourceFile.parseDiagnostics[0] && jsonSourceFile.parseDiagnostics[0].messageText, "\n"));
return {
jsonSourceFile,
parsed: ts.parseJsonSourceFileConfigFileContent(jsonSourceFile, host, basePath, {}, entry)
};
}
function testSuccess(name: string, entry: string, expected: CompilerOptions, expectedFiles: string[]) {
expected.configFilePath = entry;
it(name, () => {
const {config, error} = ts.readConfigFile(entry, name => host.readFile(name));
assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n"));
const parsed = ts.parseJsonConfigFileContent(config, host, basePath, {}, entry);
const parsed = getParseCommandLine(entry);
assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n"));
expected.configFilePath = entry;
assert.deepEqual(parsed.options, expected);
assert.deepEqual(parsed.fileNames, expectedFiles);
});
it(name + " with jsonSourceFile", () => {
const { parsed, jsonSourceFile } = getParseCommandLineJsonSourceFile(entry);
assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n"));
assert.deepEqual(parsed.options, expected);
assert.equal(parsed.options.configFile, jsonSourceFile);
assert.deepEqual(parsed.fileNames, expectedFiles);
});
}
function testFailure(name: string, entry: string, expectedDiagnostics: {code: number, category: DiagnosticCategory, messageText: string}[]) {
function testFailure(name: string, entry: string, expectedDiagnostics: { code: number, category: DiagnosticCategory, messageText: string }[]) {
it(name, () => {
const {config, error} = ts.readConfigFile(entry, name => host.readFile(name));
assert(config && !error, flattenDiagnosticMessageText(error && error.messageText, "\n"));
const parsed = ts.parseJsonConfigFileContent(config, host, basePath, {}, entry);
const parsed = getParseCommandLine(entry);
verifyDiagnostics(parsed.errors, expectedDiagnostics);
});
it(name + " with jsonSourceFile", () => {
const { parsed } = getParseCommandLineJsonSourceFile(entry);
verifyDiagnostics(parsed.errors, expectedDiagnostics);
});
}
@@ -185,4 +209,4 @@ namespace ts {
});
});
});
}
}
@@ -4,6 +4,11 @@
namespace ts {
describe("convertCompilerOptionsFromJson", () => {
function assertCompilerOptions(json: any, configFileName: string, expectedResult: { compilerOptions: CompilerOptions, errors: Diagnostic[] }) {
assertCompilerOptionsWithJson(json, configFileName, expectedResult);
assertCompilerOptionsWithJsonNode(json, configFileName, expectedResult);
}
function assertCompilerOptionsWithJson(json: any, configFileName: string, expectedResult: { compilerOptions: CompilerOptions, errors: Diagnostic[] }) {
const { options: actualCompilerOptions, errors: actualErrors} = convertCompilerOptionsFromJson(json["compilerOptions"], "/apath/", configFileName);
const parsedCompilerOptions = JSON.stringify(actualCompilerOptions);
@@ -21,6 +26,34 @@ namespace ts {
}
}
function assertCompilerOptionsWithJsonNode(json: any, configFileName: string, expectedResult: { compilerOptions: CompilerOptions, errors: Diagnostic[] }) {
const fileText = JSON.stringify(json);
const result = parseJsonText(configFileName, fileText);
assert(!result.parseDiagnostics.length);
assert(!!result.endOfFileToken);
const host: ParseConfigHost = new Utils.MockParseConfigHost("/apath/", true, []);
const { options: actualCompilerOptions, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName);
expectedResult.compilerOptions["configFilePath"] = configFileName;
const parsedCompilerOptions = JSON.stringify(actualCompilerOptions);
const expectedCompilerOptions = JSON.stringify(expectedResult.compilerOptions);
assert.equal(parsedCompilerOptions, expectedCompilerOptions);
assert.equal(actualCompilerOptions.configFile, result);
const actualErrors = filter(actualParseErrors, error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
const expectedErrors = expectedResult.errors;
assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`);
for (let i = 0; i < actualErrors.length; i++) {
const actualError = actualErrors[i];
const expectedError = expectedErrors[i];
assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`);
assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`);
assert(actualError.file);
assert(actualError.start);
assert(actualError.length);
}
}
// tsconfig.json tests
it("Convert correctly format tsconfig.json to compiler-options ", () => {
assertCompilerOptions(
@@ -2,14 +2,20 @@
/// <reference path="..\..\compiler\commandLineParser.ts" />
namespace ts {
type ExpectedResult = { typeAcquisition: TypeAcquisition, errors: Diagnostic[] };
describe("convertTypeAcquisitionFromJson", () => {
function assertTypeAcquisition(json: any, configFileName: string, expectedResult: { typeAcquisition: TypeAcquisition, errors: Diagnostic[] }) {
const jsonOptions = json["typeAcquisition"] || json["typingOptions"];
const { options: actualTypeAcquisition, errors: actualErrors } = convertTypeAcquisitionFromJson(jsonOptions, "/apath/", configFileName);
function assertTypeAcquisition(json: any, configFileName: string, expectedResult: ExpectedResult) {
assertTypeAcquisitionWithJson(json, configFileName, expectedResult);
assertTypeAcquisitionWithJsonNode(json, configFileName, expectedResult);
}
function verifyAcquisition(actualTypeAcquisition: TypeAcquisition, expectedResult: ExpectedResult) {
const parsedTypeAcquisition = JSON.stringify(actualTypeAcquisition);
const expectedTypeAcquisition = JSON.stringify(expectedResult.typeAcquisition);
assert.equal(parsedTypeAcquisition, expectedTypeAcquisition);
}
function verifyErrors(actualErrors: Diagnostic[], expectedResult: ExpectedResult, hasLocation?: boolean) {
const expectedErrors = expectedResult.errors;
assert.isTrue(expectedResult.errors.length === actualErrors.length, `Expected error: ${JSON.stringify(expectedResult.errors)}. Actual error: ${JSON.stringify(actualErrors)}.`);
for (let i = 0; i < actualErrors.length; i++) {
@@ -17,9 +23,34 @@ namespace ts {
const expectedError = expectedErrors[i];
assert.equal(actualError.code, expectedError.code, `Expected error-code: ${JSON.stringify(expectedError.code)}. Actual error-code: ${JSON.stringify(actualError.code)}.`);
assert.equal(actualError.category, expectedError.category, `Expected error-category: ${JSON.stringify(expectedError.category)}. Actual error-category: ${JSON.stringify(actualError.category)}.`);
if (hasLocation) {
assert(actualError.file);
assert(actualError.start);
assert(actualError.length);
}
}
}
function assertTypeAcquisitionWithJson(json: any, configFileName: string, expectedResult: ExpectedResult) {
const jsonOptions = json["typeAcquisition"] || json["typingOptions"];
const { options: actualTypeAcquisition, errors: actualErrors } = convertTypeAcquisitionFromJson(jsonOptions, "/apath/", configFileName);
verifyAcquisition(actualTypeAcquisition, expectedResult);
verifyErrors(actualErrors, expectedResult);
}
function assertTypeAcquisitionWithJsonNode(json: any, configFileName: string, expectedResult: ExpectedResult) {
const fileText = JSON.stringify(json);
const result = parseJsonText(configFileName, fileText);
assert(!result.parseDiagnostics.length);
assert(!!result.endOfFileToken);
const host: ParseConfigHost = new Utils.MockParseConfigHost("/apath/", true, []);
const { typeAcquisition: actualTypeAcquisition, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName);
verifyAcquisition(actualTypeAcquisition, expectedResult);
const actualErrors = filter(actualParseErrors, error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
verifyErrors(actualErrors, expectedResult, /*hasLocation*/ true);
}
// tsconfig.json
it("Convert deprecated typingOptions.enableAutoDiscovery format tsconfig.json to typeAcquisition ", () => {
assertTypeAcquisition(
@@ -177,7 +208,7 @@ namespace ts {
},
errors: [
{
category: Diagnostics.Unknown_compiler_option_0.category,
category: Diagnostics.Unknown_type_acquisition_option_0.category,
code: Diagnostics.Unknown_type_acquisition_option_0.code,
file: undefined,
start: 0,
+101 -119
View File
@@ -95,6 +95,44 @@ namespace ts {
assert.deepEqual(actual.errors, expected.errors);
}
function validateMatches(expected: ts.ParsedCommandLine, json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[]) {
{
const jsonText = JSON.stringify(json);
const result = parseJsonText(caseInsensitiveTsconfigPath, jsonText);
const actual = ts.parseJsonSourceFileConfigFileContent(result, host, basePath, existingOptions, configFileName, resolutionStack);
for (const error of expected.errors) {
if (error.file) {
error.file = result;
}
}
assertParsed(actual, expected);
}
{
const actual = ts.parseJsonConfigFileContent(json, host, basePath, existingOptions, configFileName, resolutionStack);
expected.errors = map(expected.errors, error => {
return <Diagnostic>{
category: error.category,
code: error.code,
file: undefined,
length: undefined,
messageText: error.messageText,
start: undefined,
};
});
assertParsed(actual, expected);
}
}
function createDiagnosticForConfigFile(json: any, start: number, length: number, diagnosticMessage: DiagnosticMessage, arg0: string) {
const text = JSON.stringify(json);
const file = <SourceFile>{
fileName: caseInsensitiveTsconfigPath,
kind: SyntaxKind.SourceFile,
text
};
return ts.createFileDiagnostic(file, start, length, diagnosticMessage, arg0);
}
describe("matchFiles", () => {
it("with defaults", () => {
const json = {};
@@ -109,8 +147,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
describe("with literal file list", () => {
@@ -130,8 +167,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("missing files are still present", () => {
const json = {
@@ -149,8 +185,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("are not removed due to excludes", () => {
const json = {
@@ -171,8 +206,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
@@ -193,8 +227,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with non .ts file extensions are excluded", () => {
const json = {
@@ -212,8 +245,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("with missing files are excluded", () => {
const json = {
@@ -231,8 +263,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("with literal excludes", () => {
const json = {
@@ -252,8 +283,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with wildcard excludes", () => {
const json = {
@@ -280,8 +310,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with recursive excludes", () => {
const json = {
@@ -307,8 +336,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with case sensitive exclude", () => {
const json = {
@@ -327,8 +355,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath);
});
it("with common package folders and no exclusions", () => {
const json = {
@@ -352,8 +379,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and exclusions", () => {
const json = {
@@ -379,8 +405,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and empty exclude", () => {
const json = {
@@ -404,8 +429,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
});
@@ -436,8 +460,7 @@ namespace ts {
"c:/dev/x": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("same named declarations are excluded", () => {
@@ -458,8 +481,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("`*` matches only ts files", () => {
const json = {
@@ -479,8 +501,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("`?` matches only a single character", () => {
const json = {
@@ -499,8 +520,7 @@ namespace ts {
"c:/dev/x": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with recursive directory", () => {
const json = {
@@ -521,8 +541,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with multiple recursive directories", () => {
const json = {
@@ -545,8 +564,7 @@ namespace ts {
"c:/dev/z": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("case sensitive", () => {
const json = {
@@ -564,8 +582,7 @@ namespace ts {
"/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath);
});
it("with missing files are excluded", () => {
const json = {
@@ -584,8 +601,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("always include literal files", () => {
const json = {
@@ -609,8 +625,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("exclude folders", () => {
const json = {
@@ -634,8 +649,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with common package folders and no exclusions", () => {
const json = {
@@ -656,8 +670,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and exclusions", () => {
const json = {
@@ -680,8 +693,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and empty exclude", () => {
const json = {
@@ -703,8 +715,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("exclude .js files when allowJs=false", () => {
const json = {
@@ -728,8 +739,7 @@ namespace ts {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("include .js files when allowJs=true", () => {
const json = {
@@ -753,8 +763,7 @@ namespace ts {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("include explicitly listed .min.js files when allowJs=true", () => {
const json = {
@@ -778,8 +787,7 @@ namespace ts {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("include paths outside of the project", () => {
const json = {
@@ -802,8 +810,7 @@ namespace ts {
"c:/ext": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("include paths outside of the project using relative paths", () => {
const json = {
@@ -825,8 +832,7 @@ namespace ts {
"c:/ext": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("exclude paths outside of the project using relative paths", () => {
const json = {
@@ -846,8 +852,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("include files with .. in their name", () => {
const json = {
@@ -866,8 +871,7 @@ namespace ts {
],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("exclude files with .. in their name", () => {
const json = {
@@ -888,8 +892,7 @@ namespace ts {
"c:/ext": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with jsx=none, allowJs=false", () => {
const json = {
@@ -911,8 +914,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=preserve, allowJs=false", () => {
const json = {
@@ -936,8 +938,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=react-native, allowJs=false", () => {
const json = {
@@ -961,8 +962,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=none, allowJs=true", () => {
const json = {
@@ -986,8 +986,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=preserve, allowJs=true", () => {
const json = {
@@ -1013,8 +1012,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=react-native, allowJs=true", () => {
const json = {
@@ -1040,8 +1038,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("exclude .min.js files using wildcards", () => {
const json = {
@@ -1067,8 +1064,7 @@ namespace ts {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
describe("with trailing recursive directory", () => {
it("in includes", () => {
@@ -1080,15 +1076,14 @@ namespace ts {
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**"),
createDiagnosticForConfigFile(json, 12, 4, ts.Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**"),
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("in excludes", () => {
const json = {
@@ -1108,8 +1103,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
});
describe("with multiple recursive directory patterns", () => {
@@ -1122,15 +1116,14 @@ namespace ts {
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**/*"),
createDiagnosticForConfigFile(json, 12, 11, ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**/*"),
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("in excludes", () => {
const json = {
@@ -1144,7 +1137,7 @@ namespace ts {
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**")
createDiagnosticForConfigFile(json, 34, 9, ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**")
],
fileNames: [
"c:/dev/a.ts",
@@ -1156,8 +1149,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
@@ -1171,15 +1163,14 @@ namespace ts {
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/../*"),
createDiagnosticForConfigFile(json, 12, 9, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/../*"),
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("in includes after a subdirectory", () => {
@@ -1191,15 +1182,14 @@ namespace ts {
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/../*"),
createDiagnosticForConfigFile(json, 12, 11, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/../*"),
ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]")
],
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
it("in excludes immediately after", () => {
@@ -1214,7 +1204,7 @@ namespace ts {
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/..")
createDiagnosticForConfigFile(json, 34, 7, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/..")
],
fileNames: [
"c:/dev/a.ts",
@@ -1226,8 +1216,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("in excludes after a subdirectory", () => {
@@ -1242,7 +1231,7 @@ namespace ts {
const expected: ts.ParsedCommandLine = {
options: {},
errors: [
ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/..")
createDiagnosticForConfigFile(json, 34, 9, ts.Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**/y/..")
],
fileNames: [
"c:/dev/a.ts",
@@ -1254,8 +1243,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
@@ -1272,8 +1260,7 @@ namespace ts {
"c:/dev/z": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
});
@@ -1297,8 +1284,7 @@ namespace ts {
"c:/dev/w": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
});
describe("that are explicitly included", () => {
it("without wildcards", () => {
@@ -1317,8 +1303,7 @@ namespace ts {
],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
});
it("with recursive wildcards that match directories", () => {
const json = {
@@ -1339,8 +1324,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
});
it("with recursive wildcards that match nothing", () => {
const json = {
@@ -1361,8 +1345,7 @@ namespace ts {
"c:/dev/x": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath);
});
it("with wildcard excludes that implicitly exclude dotted files", () => {
const json = {
@@ -1382,8 +1365,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
assertParsed(actual, expected);
validateMatches(expected, json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath);
});
});
});
+21 -12
View File
@@ -6,7 +6,10 @@ namespace ts.projectSystem {
describe("Project errors", () => {
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: string[]) {
assert.isTrue(projectFiles !== undefined, "missing project files");
const errors = projectFiles.projectErrors;
checkProjectErrorsWorker(projectFiles.projectErrors, expectedErrors);
}
function checkProjectErrorsWorker(errors: Diagnostic[], expectedErrors: string[]) {
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
if (expectedErrors.length) {
for (let i = 0; i < errors.length; i++) {
@@ -122,12 +125,13 @@ namespace ts.projectSystem {
projectService.checkNumberOfProjects({ configuredProjects: 1 });
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, [
"')' expected.",
"Declaration or statement expected.",
"Declaration or statement expected.",
"Failed to parse file '/a/b/tsconfig.json'"
checkProjectErrors(configuredProject, []);
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
checkProjectErrorsWorker(projectErrors, [
"'{' expected."
]);
assert.isNotNull(projectErrors[0].file);
assert.equal(projectErrors[0].file.fileName, corruptedConfig.path);
}
// fix config and trigger watcher
host.reloadFS([file1, file2, correctConfig]);
@@ -137,6 +141,8 @@ namespace ts.projectSystem {
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, []);
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
checkProjectErrorsWorker(projectErrors, []);
}
});
@@ -166,6 +172,8 @@ namespace ts.projectSystem {
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, []);
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
checkProjectErrorsWorker(projectErrors, []);
}
// break config and trigger watcher
host.reloadFS([file1, file2, corruptedConfig]);
@@ -174,13 +182,14 @@ namespace ts.projectSystem {
projectService.checkNumberOfProjects({ configuredProjects: 1 });
const configuredProject = forEach(projectService.synchronizeProjectList([]), f => f.info.projectName === corruptedConfig.path && f);
assert.isTrue(configuredProject !== undefined, "should find configured project");
checkProjectErrors(configuredProject, [
"')' expected.",
"Declaration or statement expected.",
"Declaration or statement expected.",
"Failed to parse file '/a/b/tsconfig.json'"
checkProjectErrors(configuredProject, []);
const projectErrors = projectService.configuredProjects[0].getAllProjectErrors();
checkProjectErrorsWorker(projectErrors, [
"'{' expected."
]);
assert.isNotNull(projectErrors[0].file);
assert.equal(projectErrors[0].file.fileName, corruptedConfig.path);
}
});
});
}
}
+1 -3
View File
@@ -45,7 +45,7 @@ namespace ts.projectSystem {
it("works with external project", () => {
const file1 = makeFile("/a.ts");
const et = new EventTracker([file1]);
const compilerOptions: ts.CompilerOptions = { strict: true };
const compilerOptions: ts.server.protocol.CompilerOptions = { strict: true };
const projectFileName = "/hunter2/foo.csproj";
@@ -138,8 +138,6 @@ namespace ts.projectSystem {
declaration: true,
lib: ["es6", "dom"],
checkJs: "" as any as boolean,
};
(compilerOptions as any).unknownCompilerOption = "hunter2"; // These are always ignored.
const tsconfig = makeFile("/tsconfig.json", { compilerOptions, files: ["/a.ts"] });
+59 -21
View File
@@ -3,37 +3,69 @@
namespace ts {
describe("parseConfigFileTextToJson", () => {
function assertParseResult(jsonText: string, expectedConfigObject: { config?: any; error?: Diagnostic }) {
function assertParseResult(jsonText: string, expectedConfigObject: { config?: any; error?: Diagnostic[] }) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.equal(JSON.stringify(parsed), JSON.stringify(expectedConfigObject));
}
function assertParseError(jsonText: string) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.isTrue(undefined === parsed.config);
assert.deepEqual(parsed.config, {});
assert.isTrue(undefined !== parsed.error);
}
function assertParseErrorWithExcludesKeyword(jsonText: string) {
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
const parsedCommand = ts.parseJsonConfigFileContent(parsed.config, ts.sys, "tests/cases/unittests");
assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 &&
parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code);
{
const parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
const parsedCommand = ts.parseJsonConfigFileContent(parsed.config, ts.sys, "tests/cases/unittests");
assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 &&
parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code);
}
{
const parsed = ts.parseJsonText("/apath/tsconfig.json", jsonText);
const parsedCommand = ts.parseJsonSourceFileConfigFileContent(parsed, ts.sys, "tests/cases/unittests");
assert.isTrue(parsedCommand.errors && parsedCommand.errors.length === 1 &&
parsedCommand.errors[0].code === ts.Diagnostics.Unknown_option_excludes_Did_you_mean_exclude.code);
}
}
function getParsedCommandJson(jsonText: string, configFileName: string, basePath: string, allFileList: string[]) {
const parsed = ts.parseConfigFileTextToJson(configFileName, jsonText);
const host: ParseConfigHost = new Utils.MockParseConfigHost(basePath, true, allFileList);
return ts.parseJsonConfigFileContent(parsed.config, host, basePath, /*existingOptions*/ undefined, configFileName);
}
function getParsedCommandJsonNode(jsonText: string, configFileName: string, basePath: string, allFileList: string[]) {
const parsed = ts.parseJsonText(configFileName, jsonText);
const host: ParseConfigHost = new Utils.MockParseConfigHost(basePath, true, allFileList);
return ts.parseJsonSourceFileConfigFileContent(parsed, host, basePath, /*existingOptions*/ undefined, configFileName);
}
function assertParseFileList(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedFileList: string[]) {
const json = JSON.parse(jsonText);
const host: ParseConfigHost = new Utils.MockParseConfigHost(basePath, true, allFileList);
const parsed = ts.parseJsonConfigFileContent(json, host, basePath, /*existingOptions*/ undefined, configFileName);
assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort()));
{
const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList);
assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort()));
}
{
const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList);
assert.isTrue(arrayIsEqualTo(parsed.fileNames.sort(), expectedFileList.sort()));
}
}
function assertParseFileDiagnostics(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedDiagnosticCode: number) {
const json = JSON.parse(jsonText);
const host: ParseConfigHost = new Utils.MockParseConfigHost(basePath, true, allFileList);
const parsed = ts.parseJsonConfigFileContent(json, host, basePath, /*existingOptions*/ undefined, configFileName);
assert.isTrue(parsed.errors.length >= 0);
assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`);
function assertParseFileDiagnostics(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedDiagnosticCode: number, noLocation?: boolean) {
{
const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList);
assert.isTrue(parsed.errors.length >= 0);
assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`);
}
{
const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList);
assert.isTrue(parsed.errors.length >= 0);
assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)}`);
if (!noLocation) {
assert.isTrue(parsed.errors.filter(e => e.code === expectedDiagnosticCode && e.file && e.start && e.length).length > 0, `Expected error code ${expectedDiagnosticCode} to be in ${JSON.stringify(parsed.errors)} with location information`);
}
}
}
it("returns empty config for file with only whitespaces", () => {
@@ -199,7 +231,9 @@ namespace ts {
}
"files": ["file1.ts"]
}`;
const { configJsonObject, diagnostics } = sanitizeConfigFile("config.json", content);
const result = parseJsonText("config.json", content);
const diagnostics = result.parseDiagnostics;
const configJsonObject = convertToObject(result, diagnostics);
const expectedResult = {
compilerOptions: {
allowJs: true,
@@ -229,7 +263,8 @@ namespace ts {
"/apath/tsconfig.json",
"tests/cases/unittests",
["/apath/a.js"],
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code,
/*noLocation*/ true);
});
it("generates errors for empty directory", () => {
@@ -242,7 +277,8 @@ namespace ts {
"/apath/tsconfig.json",
"tests/cases/unittests",
[],
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code,
/*noLocation*/ true);
});
it("generates errors for empty include", () => {
@@ -253,7 +289,8 @@ namespace ts {
"/apath/tsconfig.json",
"tests/cases/unittests",
["/apath/a.ts"],
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code,
/*noLocation*/ true);
});
it("generates errors for includes with outDir", () => {
@@ -267,7 +304,8 @@ namespace ts {
"/apath/tsconfig.json",
"tests/cases/unittests",
["/apath/a.ts"],
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code);
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code,
/*noLocation*/ true);
});
});
}
+93 -28
View File
@@ -735,7 +735,7 @@ namespace ts.projectSystem {
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkProjectActualFiles(project, [file1.path, libFile.path, file2.path]);
checkProjectActualFiles(project, [file1.path, libFile.path, file2.path, configFile.path]);
checkProjectRootFiles(project, [file1.path, file2.path]);
// watching all files except one that was open
checkWatchedFiles(host, [configFile.path, file2.path, libFile.path]);
@@ -992,7 +992,7 @@ namespace ts.projectSystem {
checkNumberOfConfiguredProjects(projectService, 1);
const project = projectService.configuredProjects[0];
checkProjectActualFiles(project, [file1.path, nodeModuleFile.path]);
checkProjectActualFiles(project, [file1.path, nodeModuleFile.path, configFile.path]);
checkNumberOfInferredProjects(projectService, 1);
configFile.content = `{
@@ -1003,7 +1003,7 @@ namespace ts.projectSystem {
}`;
host.reloadFS(files);
host.triggerFileWatcherCallback(configFile.path);
checkProjectActualFiles(project, [file1.path, classicModuleFile.path]);
checkProjectActualFiles(project, [file1.path, classicModuleFile.path, configFile.path]);
checkNumberOfInferredProjects(projectService, 1);
});
@@ -1566,7 +1566,7 @@ namespace ts.projectSystem {
host.reloadFS([file1, file2, file3, configFile]);
host.triggerDirectoryWatcherCallback(getDirectoryPath(configFile.path), configFile.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path, file3.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path, file3.path, configFile.path]);
});
it("correctly migrate files between projects", () => {
@@ -1624,7 +1624,7 @@ namespace ts.projectSystem {
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, configFile.path]);
host.reloadFS([file1, file2, configFile]);
@@ -1655,7 +1655,7 @@ namespace ts.projectSystem {
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, configFile.path]);
const modifiedConfigFile = {
path: configFile.path,
@@ -1688,7 +1688,7 @@ namespace ts.projectSystem {
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path, configFile.path]);
const modifiedConfigFile = {
path: configFile.path,
@@ -1769,11 +1769,11 @@ namespace ts.projectSystem {
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path, config.path]);
projectService.openClientFile(file2.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path, config.path]);
host.reloadFS([file1, file2]);
host.triggerFileWatcherCallback(config.path, /*removed*/ true);
@@ -1808,13 +1808,13 @@ namespace ts.projectSystem {
});
projectService.openClientFile(f1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, config.path]);
projectService.closeClientFile(f1.path);
projectService.openClientFile(f2.path);
projectService.checkNumberOfProjects({ configuredProjects: 1, inferredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, config.path]);
checkProjectActualFiles(projectService.inferredProjects[0], [f2.path]);
});
@@ -1838,7 +1838,7 @@ namespace ts.projectSystem {
// HTML file will not be included in any projects yet
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, config.path]);
// Specify .html extension as mixed content
const extraFileExtensions = [{ extension: ".html", scriptKind: ScriptKind.JS, isMixedContent: true }];
@@ -1847,7 +1847,7 @@ namespace ts.projectSystem {
// HTML file still not included in the project as it is closed
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, config.path]);
// Open HTML file
projectService.applyChangesInOpenFiles(
@@ -1857,7 +1857,7 @@ namespace ts.projectSystem {
// Now HTML file is included in the project
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path, config.path]);
// Check identifiers defined in HTML content are available in .ts file
const project = projectService.configuredProjects[0];
@@ -1872,7 +1872,7 @@ namespace ts.projectSystem {
// HTML file is still included in project
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path, file2.path, config.path]);
// Check identifiers defined in HTML content are not available in .ts file
completions = project.getLanguageService().getCompletionsAtPosition(file1.path, 5);
@@ -2488,7 +2488,7 @@ namespace ts.projectSystem {
options: {}
});
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, tsconfig.path]);
// rename tsconfig.json back to lib.ts
host.reloadFS([f1, f2]);
@@ -2546,8 +2546,8 @@ namespace ts.projectSystem {
options: {}
});
projectService.checkNumberOfProjects({ configuredProjects: 2 });
checkProjectActualFiles(projectService.configuredProjects[0], [cLib.path]);
checkProjectActualFiles(projectService.configuredProjects[1], [dLib.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [cLib.path, cTsconfig.path]);
checkProjectActualFiles(projectService.configuredProjects[1], [dLib.path, dTsconfig.path]);
// remove one config file
projectService.openExternalProject({
@@ -2557,7 +2557,7 @@ namespace ts.projectSystem {
});
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [dLib.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [dLib.path, dTsconfig.path]);
// remove second config file
projectService.openExternalProject({
@@ -2577,8 +2577,8 @@ namespace ts.projectSystem {
options: {}
});
projectService.checkNumberOfProjects({ configuredProjects: 2 });
checkProjectActualFiles(projectService.configuredProjects[0], [cLib.path]);
checkProjectActualFiles(projectService.configuredProjects[1], [dLib.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [cLib.path, cTsconfig.path]);
checkProjectActualFiles(projectService.configuredProjects[1], [dLib.path, dTsconfig.path]);
// close all projects - no projects should be opened
projectService.closeExternalProject(projectName);
@@ -2634,13 +2634,13 @@ namespace ts.projectSystem {
projectService.openClientFile(app.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [libES5.path, app.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [libES5.path, app.path, config1.path]);
host.reloadFS([libES5, libES2015Promise, app, config2]);
host.triggerFileWatcherCallback(config1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [libES5.path, libES2015Promise.path, app.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [libES5.path, libES2015Promise.path, app.path, config2.path]);
});
it("should handle non-existing directories in config file", () => {
@@ -2695,7 +2695,7 @@ namespace ts.projectSystem {
projectService.openClientFile(f1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, barTypings.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, barTypings.path, config.path]);
});
});
@@ -2766,7 +2766,7 @@ namespace ts.projectSystem {
projectService.openClientFile(f1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, t1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, t1.path, tsconfig.path]);
// delete t1
host.reloadFS([f1, tsconfig]);
@@ -2775,7 +2775,7 @@ namespace ts.projectSystem {
host.runQueuedTimeoutCallbacks();
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, tsconfig.path]);
// create t2
host.reloadFS([f1, tsconfig, t2]);
@@ -2784,7 +2784,7 @@ namespace ts.projectSystem {
host.runQueuedTimeoutCallbacks();
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, t2.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, t2.path, tsconfig.path]);
});
});
@@ -2969,7 +2969,7 @@ namespace ts.projectSystem {
const projectService = createProjectService(host);
projectService.openClientFile(f1.path);
projectService.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, node.path]);
checkProjectActualFiles(projectService.configuredProjects[0], [f1.path, node.path, config.path]);
});
});
@@ -3980,4 +3980,69 @@ namespace ts.projectSystem {
assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth);
});
});
describe("Options Diagnostic locations reported correctly with changes in configFile contents", () => {
it("when options change", () => {
const file = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const configFileContentBeforeComment = `{`;
const configFileContentComment = `
// comment`;
const configFileContentAfterComment = `
"compilerOptions": {
"allowJs": true,
"declaration": true
}
}`;
const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment;
const configFileContentWithoutCommentLine = configFileContentBeforeComment + configFileContentAfterComment;
const configFile = {
path: "/a/b/tsconfig.json",
content: configFileContentWithComment
};
const host = createServerHost([file, libFile, configFile]);
const session = createSession(host);
openFilesForSession([file], session);
const projectService = session.getProjectService();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const projectName = projectService.configuredProjects[0].getProjectName();
const diags = session.executeCommand(<server.protocol.SemanticDiagnosticsSyncRequest>{
type: "request",
command: server.CommandNames.SemanticDiagnosticsSync,
seq: 2,
arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }
}).response;
assert.isTrue(diags.length === 2);
configFile.content = configFileContentWithoutCommentLine;
host.reloadFS([file, configFile]);
host.triggerFileWatcherCallback(configFile.path);
const diagsAfterEdit = session.executeCommand(<server.protocol.SemanticDiagnosticsSyncRequest>{
type: "request",
command: server.CommandNames.SemanticDiagnosticsSync,
seq: 2,
arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }
}).response;
assert.isTrue(diagsAfterEdit.length === 2);
verifyDiagnostic(diags[0], diagsAfterEdit[0]);
verifyDiagnostic(diags[1], diagsAfterEdit[1]);
function verifyDiagnostic(beforeEditDiag: server.protocol.DiagnosticWithLinePosition, afterEditDiag: server.protocol.DiagnosticWithLinePosition) {
assert.equal(beforeEditDiag.message, afterEditDiag.message);
assert.equal(beforeEditDiag.code, afterEditDiag.code);
assert.equal(beforeEditDiag.category, afterEditDiag.category);
assert.equal(beforeEditDiag.startLocation.line, afterEditDiag.startLocation.line + 1);
assert.equal(beforeEditDiag.startLocation.offset, afterEditDiag.startLocation.offset);
assert.equal(beforeEditDiag.endLocation.line, afterEditDiag.endLocation.line + 1);
assert.equal(beforeEditDiag.endLocation.offset, afterEditDiag.endLocation.offset);
}
});
});
}
+10 -10
View File
@@ -80,7 +80,7 @@ namespace ts.projectSystem {
const service = createProjectService(host, { typingsInstaller: installer });
service.openClientFile(f1.path);
service.checkNumberOfProjects({ configuredProjects: 1 });
checkProjectActualFiles(service.configuredProjects[0], [f1.path, f2.path]);
checkProjectActualFiles(service.configuredProjects[0], [f1.path, f2.path, config.path]);
installer.installAll(0);
});
});
@@ -133,12 +133,12 @@ namespace ts.projectSystem {
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const p = projectService.configuredProjects[0];
checkProjectActualFiles(p, [file1.path]);
checkProjectActualFiles(p, [file1.path, tsconfig.path]);
installer.installAll(/*expectedCount*/ 1);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(p, [file1.path, jquery.path]);
checkProjectActualFiles(p, [file1.path, jquery.path, tsconfig.path]);
});
it("inferred project (typings installed)", () => {
@@ -684,12 +684,12 @@ namespace ts.projectSystem {
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const p = projectService.configuredProjects[0];
checkProjectActualFiles(p, [app.path]);
checkProjectActualFiles(p, [app.path, jsconfig.path]);
installer.installAll(/*expectedCount*/ 1);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(p, [app.path, jqueryDTS.path]);
checkProjectActualFiles(p, [app.path, jqueryDTS.path, jsconfig.path]);
});
it("configured projects discover from bower_components", () => {
@@ -730,13 +730,13 @@ namespace ts.projectSystem {
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const p = projectService.configuredProjects[0];
checkProjectActualFiles(p, [app.path]);
checkProjectActualFiles(p, [app.path, jsconfig.path]);
checkWatchedFiles(host, [jsconfig.path, "/bower_components", "/node_modules"]);
installer.installAll(/*expectedCount*/ 1);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(p, [app.path, jqueryDTS.path]);
checkProjectActualFiles(p, [app.path, jqueryDTS.path, jsconfig.path]);
});
it("configured projects discover from bower.json", () => {
@@ -777,12 +777,12 @@ namespace ts.projectSystem {
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const p = projectService.configuredProjects[0];
checkProjectActualFiles(p, [app.path]);
checkProjectActualFiles(p, [app.path, jsconfig.path]);
installer.installAll(/*expectedCount*/ 1);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
checkProjectActualFiles(p, [app.path, jqueryDTS.path]);
checkProjectActualFiles(p, [app.path, jqueryDTS.path, jsconfig.path]);
});
it("Malformed package.json should be watched", () => {
@@ -1206,4 +1206,4 @@ namespace ts.projectSystem {
checkProjectActualFiles(projectService.inferredProjects[0], [f1.path]);
});
});
}
}
+13 -19
View File
@@ -976,20 +976,14 @@ namespace ts.server {
configFilename = normalizePath(configFilename);
const configFileContent = this.host.readFile(configFilename);
let errors: Diagnostic[];
const result = parseConfigFileTextToJson(configFilename, configFileContent);
let config = result.config;
if (result.error) {
// try to reparse config file
const { configJsonObject: sanitizedConfig, diagnostics } = sanitizeConfigFile(configFilename, configFileContent);
config = sanitizedConfig;
errors = diagnostics.length ? diagnostics : [result.error];
const result = parseJsonText(configFilename, configFileContent);
if (!result.endOfFileToken) {
result.endOfFileToken = <EndOfFileToken>{ kind: SyntaxKind.EndOfFileToken };
}
const parsedCommandLine = parseJsonConfigFileContent(
config,
const errors = result.parseDiagnostics;
const parsedCommandLine = parseJsonSourceFileConfigFileContent(
result,
this.host,
getDirectoryPath(configFilename),
/*existingOptions*/ {},
@@ -998,23 +992,23 @@ namespace ts.server {
this.hostConfiguration.extraFileExtensions);
if (parsedCommandLine.errors.length) {
errors = concatenate(errors, parsedCommandLine.errors);
errors.push(...parsedCommandLine.errors);
}
Debug.assert(!!parsedCommandLine.fileNames);
if (parsedCommandLine.fileNames.length === 0) {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename));
errors.push(createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename));
return { success: false, configFileErrors: errors };
}
const projectOptions: ProjectOptions = {
files: parsedCommandLine.fileNames,
compilerOptions: parsedCommandLine.options,
configHasExtendsProperty: config.extends !== undefined,
configHasFilesProperty: config.files !== undefined,
configHasIncludeProperty: config.include !== undefined,
configHasExcludeProperty: config.exclude !== undefined,
configHasExtendsProperty: parsedCommandLine.raw["extends"] !== undefined,
configHasFilesProperty: parsedCommandLine.raw["files"] !== undefined,
configHasIncludeProperty: parsedCommandLine.raw["include"] !== undefined,
configHasExcludeProperty: parsedCommandLine.raw["exclude"] !== undefined,
wildcardDirectories: createMapFromTemplate(parsedCommandLine.wildcardDirectories),
typeAcquisition: parsedCommandLine.typeAcquisition,
compileOnSave: parsedCommandLine.compileOnSave
@@ -1183,7 +1177,7 @@ namespace ts.server {
return {
success: conversionResult.success,
project,
errors: project.getProjectErrors()
errors: project.getGlobalProjectErrors()
};
}
+43 -6
View File
@@ -216,7 +216,14 @@ namespace ts.server {
}
}
getProjectErrors() {
/**
* Get the errors that dont have any file name associated
*/
getGlobalProjectErrors() {
return filter(this.projectErrors, diagnostic => !diagnostic.file);
}
getAllProjectErrors() {
return this.projectErrors;
}
@@ -363,7 +370,7 @@ namespace ts.server {
return this.getLanguageService().getEmitOutput(info.fileName, emitOnlyDtsFiles);
}
getFileNames(excludeFilesFromExternalLibraries?: boolean) {
getFileNames(excludeFilesFromExternalLibraries?: boolean, excludeConfigFiles?: boolean) {
if (!this.program) {
return [];
}
@@ -386,9 +393,39 @@ namespace ts.server {
}
result.push(asNormalizedPath(f.fileName));
}
if (!excludeConfigFiles) {
const configFile = this.program.getCompilerOptions().configFile;
if (configFile) {
result.push(asNormalizedPath(configFile.fileName));
if (configFile.extendedSourceFiles) {
for (const f of configFile.extendedSourceFiles) {
result.push(asNormalizedPath(f));
}
}
}
}
return result;
}
hasConfigFile(configFilePath: NormalizedPath) {
if (this.program && this.languageServiceEnabled) {
const configFile = this.program.getCompilerOptions().configFile;
if (configFile) {
if (configFilePath === asNormalizedPath(configFile.fileName)) {
return true;
}
if (configFile.extendedSourceFiles) {
for (const f of configFile.extendedSourceFiles) {
if (configFilePath === asNormalizedPath(f)) {
return true;
}
}
}
}
}
return false;
}
getAllEmittableFiles() {
if (!this.languageServiceEnabled) {
return [];
@@ -663,7 +700,7 @@ namespace ts.server {
if (this.lastReportedFileNames && lastKnownVersion === this.lastReportedVersion) {
// if current structure version is the same - return info without any changes
if (this.projectStructureVersion === this.lastReportedVersion && !updatedFileNames) {
return { info, projectErrors: this.projectErrors };
return { info, projectErrors: this.getGlobalProjectErrors() };
}
// compute and return the difference
const lastReportedFileNames = this.lastReportedFileNames;
@@ -685,14 +722,14 @@ namespace ts.server {
});
this.lastReportedFileNames = currentFiles;
this.lastReportedVersion = this.projectStructureVersion;
return { info, changes: { added, removed, updated }, projectErrors: this.projectErrors };
return { info, changes: { added, removed, updated }, projectErrors: this.getGlobalProjectErrors() };
}
else {
// unknown version - return everything
const projectFileNames = this.getFileNames();
this.lastReportedFileNames = arrayToMap(projectFileNames, x => x);
this.lastReportedVersion = this.projectStructureVersion;
return { info, files: projectFileNames, projectErrors: this.projectErrors };
return { info, files: projectFileNames, projectErrors: this.getGlobalProjectErrors() };
}
}
@@ -782,7 +819,7 @@ namespace ts.server {
setCompilerOptions(options?: CompilerOptions) {
// Avoid manipulating the given options directly
const newOptions = options ? clone(options) : this.getCompilerOptions();
const newOptions = options ? cloneCompilerOptions(options) : this.getCompilerOptions();
if (!newOptions) {
return;
}
+8 -1
View File
@@ -1943,6 +1943,13 @@ namespace ts.server.protocol {
source?: string;
}
export interface DiagnosticWithFileName extends Diagnostic {
/**
* Name of the file the diagnostic is in
*/
fileName: string;
}
export interface DiagnosticEventBody {
/**
* The file for which diagnostic information is reported.
@@ -1977,7 +1984,7 @@ namespace ts.server.protocol {
/**
* An arry of diagnostic information items for the found config file.
*/
diagnostics: Diagnostic[];
diagnostics: DiagnosticWithFileName[];
}
/**
+76 -14
View File
@@ -84,14 +84,20 @@ namespace ts.server {
};
}
function formatConfigFileDiag(diag: ts.Diagnostic): protocol.Diagnostic {
return {
start: undefined,
end: undefined,
text: ts.flattenDiagnosticMessageText(diag.messageText, "\n"),
category: DiagnosticCategory[diag.category].toLowerCase(),
source: diag.source
};
function convertToILineInfo(lineAndCharacter: LineAndCharacter): ILineInfo {
return { line: lineAndCharacter.line + 1, offset: lineAndCharacter.character + 1 };
}
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: true): protocol.DiagnosticWithFileName;
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: false): protocol.Diagnostic;
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName {
const start = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start));
const end = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const text = ts.flattenDiagnosticMessageText(diag.messageText, "\n");
const { code, source } = diag;
const category = DiagnosticCategory[diag.category].toLowerCase();
return includeFileName ? { start, end, text, code, category, source, fileName: diag.file && diag.file.fileName } :
{ start, end, text, code, category, source };
}
export interface PendingErrorCheck {
@@ -384,7 +390,7 @@ namespace ts.server {
}
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: ts.Diagnostic[]) {
const bakedDiags = ts.map(diagnostics, formatConfigFileDiag);
const bakedDiags = ts.map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
const ev: protocol.ConfigFileDiagnosticEvent = {
seq: 0,
type: "event",
@@ -517,9 +523,55 @@ namespace ts.server {
return projectFileName && this.projectService.findProject(projectFileName);
}
private getConfigFileAndProject(args: protocol.FileRequestArgs) {
const project = this.getProject(args.projectFileName);
const file = toNormalizedPath(args.file);
return {
configFile: project && project.hasConfigFile(file) && file,
project
};
}
private getConfigFileDiagnostics(configFile: NormalizedPath, project: Project, includeLinePosition: boolean) {
const projectErrors = project.getAllProjectErrors();
const optionsErrors = project.getLanguageService().getCompilerOptionsDiagnostics();
const diagnosticsForConfigFile = filter(
concatenate(projectErrors, optionsErrors),
diagnostic => diagnostic.file && diagnostic.file.fileName === configFile
);
return includeLinePosition ?
this.convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnosticsForConfigFile) :
map(
diagnosticsForConfigFile,
diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ false)
);
}
private convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics: Diagnostic[]) {
return diagnostics.map(d => <protocol.DiagnosticWithLinePosition>{
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
start: d.start,
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
code: d.code,
startLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start + d.length))
});
}
private getCompilerOptionsDiagnostics(args: protocol.CompilerOptionsDiagnosticsRequestArgs) {
const project = this.getProject(args.projectFileName);
return this.convertToDiagnosticsWithLinePosition(project.getLanguageService().getCompilerOptionsDiagnostics(), /*scriptInfo*/ undefined);
// Get diagnostics that dont have associated file with them
// The diagnostics which have file would be in config file and
// would be reported as part of configFileDiagnostics
return this.convertToDiagnosticsWithLinePosition(
filter(
project.getLanguageService().getCompilerOptionsDiagnostics(),
diagnostic => !diagnostic.file
),
/*scriptInfo*/ undefined
);
}
private convertToDiagnosticsWithLinePosition(diagnostics: Diagnostic[], scriptInfo: ScriptInfo) {
@@ -645,10 +697,20 @@ namespace ts.server {
}
private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs): protocol.Diagnostic[] | protocol.DiagnosticWithLinePosition[] {
const { configFile } = this.getConfigFileAndProject(args);
if (configFile) {
// all the config file errors are reported as part of semantic check so nothing to report here
return [];
}
return this.getDiagnosticsWorker(args, /*isSemantic*/ false, (project, file) => project.getLanguageService().getSyntacticDiagnostics(file), args.includeLinePosition);
}
private getSemanticDiagnosticsSync(args: protocol.SemanticDiagnosticsSyncRequestArgs): protocol.Diagnostic[] | protocol.DiagnosticWithLinePosition[] {
const { configFile, project } = this.getConfigFileAndProject(args);
if (configFile) {
return this.getConfigFileDiagnostics(configFile, project, args.includeLinePosition);
}
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file), args.includeLinePosition);
}
@@ -692,15 +754,15 @@ namespace ts.server {
}
private getProjectInfo(args: protocol.ProjectInfoRequestArgs): protocol.ProjectInfo {
return this.getProjectInfoWorker(args.file, args.projectFileName, args.needFileNameList);
return this.getProjectInfoWorker(args.file, args.projectFileName, args.needFileNameList, /*excludeConfigFiles*/ false);
}
private getProjectInfoWorker(uncheckedFileName: string, projectFileName: string, needFileNameList: boolean) {
private getProjectInfoWorker(uncheckedFileName: string, projectFileName: string, needFileNameList: boolean, excludeConfigFiles: boolean) {
const { project } = this.getFileAndProjectWorker(uncheckedFileName, projectFileName, /*refreshInferredProjects*/ true, /*errorOnMissingProject*/ true);
const projectInfo = {
configFileName: project.getProjectName(),
languageServiceDisabled: !project.languageServiceEnabled,
fileNames: needFileNameList ? project.getFileNames() : undefined
fileNames: needFileNameList ? project.getFileNames(/*excludeFilesFromExternalLibraries*/ false, excludeConfigFiles) : undefined
};
return projectInfo;
}
@@ -1553,7 +1615,7 @@ namespace ts.server {
}
private getDiagnosticsForProject(next: NextStep, delay: number, fileName: string): void {
const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true);
const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true, /*excludeConfigFiles*/ true);
if (languageServiceDisabled) {
return;
}
+1 -1
View File
@@ -49,7 +49,7 @@ namespace ts.server {
export function createInstallTypingsRequest(project: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>, cachePath?: string): DiscoverTypings {
return {
projectName: project.getProjectName(),
fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true),
fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true, /*excludeConfigFiles*/ true),
compilerOptions: project.getCompilerOptions(),
typeAcquisition,
unresolvedImports,
+13 -18
View File
@@ -76,7 +76,7 @@ namespace ts.JsTyping {
if (!safeList) {
const result = readConfigFile(safeListPath, (path: string) => host.readFile(path));
safeList = result.config ? createMapFromTemplate<string>(result.config) : EmptySafeList;
safeList = createMapFromTemplate<string>(result.config);
}
const filesToWatch: string[] = [];
@@ -163,20 +163,18 @@ namespace ts.JsTyping {
filesToWatch.push(jsonPath);
}
const result = readConfigFile(jsonPath, (path: string) => host.readFile(path));
if (result.config) {
const jsonConfig: PackageJson = result.config;
if (jsonConfig.dependencies) {
mergeTypings(getOwnKeys(jsonConfig.dependencies));
}
if (jsonConfig.devDependencies) {
mergeTypings(getOwnKeys(jsonConfig.devDependencies));
}
if (jsonConfig.optionalDependencies) {
mergeTypings(getOwnKeys(jsonConfig.optionalDependencies));
}
if (jsonConfig.peerDependencies) {
mergeTypings(getOwnKeys(jsonConfig.peerDependencies));
}
const jsonConfig: PackageJson = result.config;
if (jsonConfig.dependencies) {
mergeTypings(getOwnKeys(jsonConfig.dependencies));
}
if (jsonConfig.devDependencies) {
mergeTypings(getOwnKeys(jsonConfig.devDependencies));
}
if (jsonConfig.optionalDependencies) {
mergeTypings(getOwnKeys(jsonConfig.optionalDependencies));
}
if (jsonConfig.peerDependencies) {
mergeTypings(getOwnKeys(jsonConfig.peerDependencies));
}
}
@@ -222,9 +220,6 @@ namespace ts.JsTyping {
continue;
}
const result = readConfigFile(normalizedFileName, (path: string) => host.readFile(path));
if (!result.config) {
continue;
}
const packageJson: PackageJson = result.config;
// npm 3's package.json contains a "_requiredBy" field
+13 -1
View File
@@ -1299,8 +1299,20 @@ namespace ts {
}
}
const currentOptions = program.getCompilerOptions();
const newOptions = hostCache.compilationSettings();
// If the compilation settings do no match, then the program is not up-to-date
return compareDataObjects(program.getCompilerOptions(), hostCache.compilationSettings());
if (!compareDataObjects(currentOptions, newOptions)) {
return false;
}
// If everything matches but the text of config file is changed,
// error locations can change for program options, so update the program
if (currentOptions.configFile && newOptions.configFile) {
return currentOptions.configFile.text === newOptions.configFile.text;
}
return true;
}
}
+4 -15
View File
@@ -1109,27 +1109,16 @@ namespace ts {
() => {
const text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength());
const result = parseConfigFileTextToJson(fileName, text);
if (result.error) {
return {
options: {},
typeAcquisition: {},
files: [],
raw: {},
errors: [realizeDiagnostic(result.error, "\r\n")]
};
}
const result = parseJsonText(fileName, text);
const normalizedFileName = normalizeSlashes(fileName);
const configFile = parseJsonConfigFileContent(result.config, this.host, getDirectoryPath(normalizedFileName), /*existingOptions*/ {}, normalizedFileName);
const configFile = parseJsonSourceFileConfigFileContent(result, this.host, getDirectoryPath(normalizedFileName), /*existingOptions*/ {}, normalizedFileName);
return {
options: configFile.options,
typeAcquisition: configFile.typeAcquisition,
files: configFile.fileNames,
raw: configFile.raw,
errors: realizeDiagnostics(configFile.errors, "\r\n")
errors: realizeDiagnostics(result.parseDiagnostics.concat(configFile.errors), "\r\n")
};
});
}
@@ -1248,4 +1237,4 @@ namespace TypeScript.Services {
// TODO: it should be moved into a namespace though.
/* @internal */
const toolsVersion = "2.5";
const toolsVersion = "2.5";
+1 -1
View File
@@ -130,7 +130,7 @@ namespace ts {
commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
typeof o.type === "object" && !forEachEntry(o.type, v => typeof v !== "number"));
options = clone(options);
options = cloneCompilerOptions(options);
for (const opt of commandLineOptionsStringToEnum) {
if (!hasProperty(options, opt.name)) {
+1
View File
@@ -17,6 +17,7 @@
"../compiler/checker.ts",
"../compiler/factory.ts",
"../compiler/visitor.ts",
"../compiler/transformers/utilities.ts",
"../compiler/transformers/ts.ts",
"../compiler/transformers/jsx.ts",
"../compiler/transformers/esnext.ts",
+6 -24
View File
@@ -982,6 +982,12 @@ namespace ts {
return false;
}
export function cloneCompilerOptions(options: CompilerOptions): CompilerOptions {
const result = clone(options);
setConfigFileInOptions(result, options && options.configFile);
return result;
}
export function compareDataObjects(dst: any, src: any): boolean {
if (!dst || !src || Object.keys(dst).length !== Object.keys(src).length) {
return false;
@@ -1306,30 +1312,6 @@ namespace ts {
return ensureScriptKind(fileName, scriptKind);
}
export function sanitizeConfigFile(configFileName: string, content: string) {
const options: TranspileOptions = {
fileName: "config.js",
compilerOptions: {
target: ScriptTarget.ES2015,
removeComments: true
},
reportDiagnostics: true
};
const { outputText, diagnostics } = ts.transpileModule("(" + content + ")", options);
// Becasue the content was wrapped in "()", the start position of diagnostics needs to be subtract by 1
// also, the emitted result will have "(" in the beginning and ");" in the end. We need to strip these
// as well
const trimmedOutput = outputText.trim();
for (const diagnostic of diagnostics) {
diagnostic.start = diagnostic.start - 1;
}
const {config, error} = parseConfigFileTextToJson(configFileName, trimmedOutput.substring(1, trimmedOutput.length - 2), /*stripComments*/ false);
return {
configJsonObject: config || {},
diagnostics: error ? concatenate(diagnostics, [error]) : diagnostics
};
}
export function getFirstNonSpaceCharacterPosition(text: string, position: number) {
while (isWhiteSpaceLike(text.charCodeAt(position))) {
position += 1;
@@ -1,6 +1,16 @@
/index.ts(4,5): error TS2339: Property 'y' does not exist on type 'typeof "shortid"'.
==== /tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"outDir": "bin"
},
"exclude": [ "node_modules" ]
}
==== /index.ts (1 errors) ====
/// <reference path="/typings/index.d.ts" />
import * as foo from "shortid";
@@ -1,7 +1,22 @@
error TS5060: Option 'paths' cannot be used without specifying '--baseUrl' option.
c:/root/tsconfig.json(5,9): error TS5060: Option 'paths' cannot be used without specifying '--baseUrl' option.
==== c:/root/tsconfig.json (1 errors) ====
// paths should error in the absence of baseurl
{
"compilerOptions": {
"paths": {
~~~~~~~
!!! error TS5060: Option 'paths' cannot be used without specifying '--baseUrl' option.
"*": [
"*",
"generated/*"
]
}
}
}
==== c:/root/f1.ts (0 errors) ====
export var x = 1;
@@ -1,7 +1,21 @@
error TS5060: Option 'paths' cannot be used without specifying '--baseUrl' option.
c:/root/tsconfig.json(4,9): error TS5060: Option 'paths' cannot be used without specifying '--baseUrl' option.
==== c:/root/tsconfig.json (1 errors) ====
// paths should error in the absence of baseurl
{
"compilerOptions": {
"paths": {
~~~~~~~
!!! error TS5060: Option 'paths' cannot be used without specifying '--baseUrl' option.
"*": [
"*",
"generated/*"
]
}
}
}
==== c:/root/f1.ts (0 errors) ====
export var x = 1;
@@ -1,8 +1,23 @@
error TS5061: Pattern '*1*' can have at most one '*' character.
error TS5062: Substitution '*2*' in pattern '*1*' in can have at most one '*' character.
tests/cases/compiler/root/tsconfig.json(8,13): error TS5061: Pattern '*1*' can have at most one '*' character.
tests/cases/compiler/root/tsconfig.json(8,22): error TS5062: Substitution '*2*' in pattern '*1*' in can have at most one '*' character.
==== tests/cases/compiler/root/tsconfig.json (2 errors) ====
// baseurl is defined in tsconfig.json
// paths has errors
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"*1*": [ "*2*" ]
~~~~~
!!! error TS5061: Pattern '*1*' can have at most one '*' character.
~~~~~
!!! error TS5062: Substitution '*2*' in pattern '*1*' in can have at most one '*' character.
}
}
}
==== tests/cases/compiler/root/src/folder1/file1.ts (0 errors) ====
export var x = 1;
@@ -1,8 +1,23 @@
error TS5061: Pattern '*1*' can have at most one '*' character.
error TS5062: Substitution '*2*' in pattern '*1*' in can have at most one '*' character.
tests/cases/compiler/root/tsconfig.json(8,13): error TS5061: Pattern '*1*' can have at most one '*' character.
tests/cases/compiler/root/tsconfig.json(8,22): error TS5062: Substitution '*2*' in pattern '*1*' in can have at most one '*' character.
==== tests/cases/compiler/root/tsconfig.json (2 errors) ====
// baseurl is defined in tsconfig.json
// paths has errors
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"*1*": [ "*2*" ]
~~~~~
!!! error TS5061: Pattern '*1*' can have at most one '*' character.
~~~~~
!!! error TS5062: Substitution '*2*' in pattern '*1*' in can have at most one '*' character.
}
}
}
==== tests/cases/compiler/root/src/folder1/file1.ts (0 errors) ====
export var x = 1;
@@ -1,6 +1,16 @@
/a.ts(1,21): error TS2307: Cannot find module 'foo'.
==== /tsconfig.json (0 errors) ====
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"foo": ["foo/foo.ts"]
}
}
}
==== /a.ts (1 errors) ====
import { foo } from "foo";
~~~~~
@@ -1,6 +1,16 @@
error TS5063: Substitutions for pattern '*' should be an array.
tests/cases/compiler/tsconfig.json(5,18): error TS5063: Substitutions for pattern '*' should be an array.
==== tests/cases/compiler/tsconfig.json (1 errors) ====
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": "*"
~~~
!!! error TS5063: Substitutions for pattern '*' should be an array.
}
}
}
==== tests/cases/compiler/a.ts (0 errors) ====
let x = 1;
@@ -1,6 +1,16 @@
error TS5064: Substitution '1' for pattern '*' has incorrect type, expected 'string', got 'number'.
tests/cases/compiler/tsconfig.json(5,19): error TS5064: Substitution '1' for pattern '*' has incorrect type, expected 'string', got 'number'.
==== tests/cases/compiler/tsconfig.json (1 errors) ====
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": [1]
~
!!! error TS5064: Substitution '1' for pattern '*' has incorrect type, expected 'string', got 'number'.
}
}
}
==== tests/cases/compiler/a.ts (0 errors) ====
let x = 1;
@@ -1,6 +1,17 @@
error TS5066: Substitutions for pattern 'foo' shouldn't be an empty array.
tests/cases/compiler/tsconfig.json(5,20): error TS5066: Substitutions for pattern 'foo' shouldn't be an empty array.
==== tests/cases/compiler/tsconfig.json (1 errors) ====
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"foo": []
~~
!!! error TS5066: Substitutions for pattern 'foo' shouldn't be an empty array.
}
}
}
==== tests/cases/compiler/a.ts (0 errors) ====
let x = 1;
@@ -1,6 +1,20 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,20 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,21 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true,
"noResolve": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,21 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true,
"noResolve": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,19 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "system",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,19 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "system",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,21 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,21 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,22 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true,
"noResolve": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,22 @@
main.ts(1,21): error TS2307: Cannot find module 'angular2/core'.
==== tsconfig.json (0 errors) ====
{
"compileOnSave": true,
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"isolatedModules": true,
"noResolve": true
},
"files": [
"main.ts"
]
}
==== main.ts (1 errors) ====
import * as ng from "angular2/core";
~~~~~~~~~~~~~~~
@@ -1,6 +1,11 @@
error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
DifferentNamesNotSpecified/tsconfig.json(2,24): error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
==== DifferentNamesNotSpecified/tsconfig.json (1 errors) ====
{
"compilerOptions": { "out": "test.js" }
~~~~~
!!! error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
}
==== DifferentNamesNotSpecified/a.ts (0 errors) ====
var test = 10;
@@ -1,7 +1,15 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
DifferentNamesNotSpecifiedWithAllowJs/tsconfig.json(4,5): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== DifferentNamesNotSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{
"compilerOptions": {
"out": "test.js",
"allowJs": true
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
}
}
==== DifferentNamesNotSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
==== DifferentNamesNotSpecifiedWithAllowJs/b.js (0 errors) ====
@@ -1,9 +1,18 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
DifferentNamesNotSpecifiedWithAllowJs/tsconfig.json(3,5): error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
DifferentNamesNotSpecifiedWithAllowJs/tsconfig.json(4,5): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== DifferentNamesNotSpecifiedWithAllowJs/tsconfig.json (2 errors) ====
{
"compilerOptions": {
"out": "test.js",
~~~~~
!!! error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
"allowJs": true
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
}
}
==== DifferentNamesNotSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
==== DifferentNamesNotSpecifiedWithAllowJs/b.js (0 errors) ====
@@ -2,5 +2,10 @@ error TS6054: File 'DifferentNamesSpecified/b.js' has unsupported extension. The
!!! error TS6054: File 'DifferentNamesSpecified/b.js' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.
==== DifferentNamesSpecified/tsconfig.json (0 errors) ====
{
"compilerOptions": { "out": "test.js" },
"files": [ "a.ts", "b.js" ]
}
==== DifferentNamesSpecified/a.ts (0 errors) ====
var test = 10;
@@ -1,8 +1,14 @@
error TS6054: File 'DifferentNamesSpecified/b.js' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.
error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
DifferentNamesSpecified/tsconfig.json(2,24): error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
!!! error TS6054: File 'DifferentNamesSpecified/b.js' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts'.
==== DifferentNamesSpecified/tsconfig.json (1 errors) ====
{
"compilerOptions": { "out": "test.js" },
~~~~~
!!! error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
"files": [ "a.ts", "b.js" ]
}
==== DifferentNamesSpecified/a.ts (0 errors) ====
var test = 10;
@@ -1,7 +1,16 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
DifferentNamesSpecifiedWithAllowJs/tsconfig.json(4,5): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== DifferentNamesSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{
"compilerOptions": {
"out": "test.js",
"allowJs": true
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
},
"files": [ "a.ts", "b.js" ]
}
==== DifferentNamesSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
==== DifferentNamesSpecifiedWithAllowJs/b.js (0 errors) ====
@@ -1,9 +1,19 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
DifferentNamesSpecifiedWithAllowJs/tsconfig.json(3,5): error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
DifferentNamesSpecifiedWithAllowJs/tsconfig.json(4,5): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== DifferentNamesSpecifiedWithAllowJs/tsconfig.json (2 errors) ====
{
"compilerOptions": {
"out": "test.js",
~~~~~
!!! error TS6082: Only 'amd' and 'system' modules are supported alongside --out.
"allowJs": true
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
},
"files": [ "a.ts", "b.js" ]
}
==== DifferentNamesSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
==== DifferentNamesSpecifiedWithAllowJs/b.js (0 errors) ====
@@ -1,6 +1,12 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
SameNameDTsSpecifiedWithAllowJs/tsconfig.json(2,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameDTsSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{
"compilerOptions": { "allowJs": true },
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
"files": [ "a.d.ts" ]
}
==== SameNameDTsSpecifiedWithAllowJs/a.d.ts (0 errors) ====
declare var test: number;
@@ -1,6 +1,12 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
SameNameDTsSpecifiedWithAllowJs/tsconfig.json(2,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameDTsSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{
"compilerOptions": { "allowJs": true },
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
"files": [ "a.d.ts" ]
}
==== SameNameDTsSpecifiedWithAllowJs/a.d.ts (0 errors) ====
declare var test: number;
@@ -1,11 +1,14 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
error TS5055: Cannot write file 'SameNameDTsNotSpecifiedWithAllowJs/a.js' because it would overwrite input file.
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
SameNameDTsNotSpecifiedWithAllowJs/tsconfig.json(1,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
!!! error TS5055: Cannot write file 'SameNameDTsNotSpecifiedWithAllowJs/a.js' because it would overwrite input file.
!!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
==== SameNameDTsNotSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{ "compilerOptions": { "allowJs": true } }
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameDTsNotSpecifiedWithAllowJs/a.d.ts (0 errors) ====
declare var a: number;
==== SameNameDTsNotSpecifiedWithAllowJs/a.js (0 errors) ====
@@ -1,11 +1,14 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
error TS5055: Cannot write file 'SameNameDTsNotSpecifiedWithAllowJs/a.js' because it would overwrite input file.
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
SameNameDTsNotSpecifiedWithAllowJs/tsconfig.json(1,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
!!! error TS5055: Cannot write file 'SameNameDTsNotSpecifiedWithAllowJs/a.js' because it would overwrite input file.
!!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
==== SameNameDTsNotSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{ "compilerOptions": { "allowJs": true } }
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameDTsNotSpecifiedWithAllowJs/a.d.ts (0 errors) ====
declare var a: number;
==== SameNameDTsNotSpecifiedWithAllowJs/a.js (0 errors) ====
@@ -1,6 +1,9 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
SameNameFilesNotSpecifiedWithAllowJs/tsconfig.json(1,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameFilesNotSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{ "compilerOptions": { "allowJs": true } }
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameFilesNotSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
@@ -1,6 +1,9 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
SameNameFilesNotSpecifiedWithAllowJs/tsconfig.json(1,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameFilesNotSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{ "compilerOptions": { "allowJs": true } }
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameFilesNotSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
@@ -1,6 +1,12 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
SameNameTsSpecifiedWithAllowJs/tsconfig.json(2,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameTsSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{
"compilerOptions": { "allowJs": true },
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
"files": [ "a.ts" ]
}
==== SameNameTsSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
@@ -1,6 +1,12 @@
error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
SameNameTsSpecifiedWithAllowJs/tsconfig.json(2,24): error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
==== SameNameTsSpecifiedWithAllowJs/tsconfig.json (1 errors) ====
{
"compilerOptions": { "allowJs": true },
~~~~~~~~~
!!! error TS5053: Option 'allowJs' cannot be specified with option 'declaration'.
"files": [ "a.ts" ]
}
==== SameNameTsSpecifiedWithAllowJs/a.ts (0 errors) ====
var test = 10;
@@ -1,6 +1,16 @@
importHigher/root.ts(6,1): error TS2322: Type '"10"' is not assignable to type 'number'.
==== importHigher/tsconfig.json (0 errors) ====
{
"compilerOptions": {
"allowJs": true,
"declaration": false,
"moduleResolution": "node",
"maxNodeModuleJsDepth": 2
}
}
==== entry.js (0 errors) ====
var m3 = require("m3");
@@ -1,6 +1,16 @@
importHigher/root.ts(6,1): error TS2322: Type '"10"' is not assignable to type 'number'.
==== importHigher/tsconfig.json (0 errors) ====
{
"compilerOptions": {
"allowJs": true,
"declaration": false,
"moduleResolution": "node",
"maxNodeModuleJsDepth": 2
}
}
==== entry.js (0 errors) ====
var m3 = require("m3");
@@ -2,6 +2,17 @@ maxDepthExceeded/root.ts(3,1): error TS2322: Type '"10"' is not assignable to ty
maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it is a constant or a read-only property.
==== maxDepthExceeded/tsconfig.json (0 errors) ====
{
"compilerOptions": {
"allowJs": true,
"maxNodeModuleJsDepth": 1, // Note: Module m1 is already included as a root file
"outDir": "built"
},
"include": ["**/*"],
"exclude": ["node_modules/m2/**/*"]
}
==== relative.js (0 errors) ====
exports.relativeProp = true;
@@ -2,6 +2,17 @@ maxDepthExceeded/root.ts(3,1): error TS2322: Type '"10"' is not assignable to ty
maxDepthExceeded/root.ts(4,4): error TS2540: Cannot assign to 'rel' because it is a constant or a read-only property.
==== maxDepthExceeded/tsconfig.json (0 errors) ====
{
"compilerOptions": {
"allowJs": true,
"maxNodeModuleJsDepth": 1, // Note: Module m1 is already included as a root file
"outDir": "built"
},
"include": ["**/*"],
"exclude": ["node_modules/m2/**/*"]
}
==== relative.js (0 errors) ====
exports.relativeProp = true;
@@ -1,6 +1,14 @@
maxDepthIncreased/root.ts(7,1): error TS2322: Type '"10"' is not assignable to type 'number'.
==== maxDepthIncreased/tsconfig.json (0 errors) ====
{
"compilerOptions": {
"allowJs": true,
"maxNodeModuleJsDepth": 3
}
}
==== index.js (0 errors) ====
exports.person = {
"name": "John Doe",
@@ -1,6 +1,14 @@
maxDepthIncreased/root.ts(7,1): error TS2322: Type '"10"' is not assignable to type 'number'.
==== maxDepthIncreased/tsconfig.json (0 errors) ====
{
"compilerOptions": {
"allowJs": true,
"maxNodeModuleJsDepth": 3
}
}
==== index.js (0 errors) ====
exports.person = {
"name": "John Doe",
@@ -10,4 +10,4 @@
////{ "files": ["a.ts", "b.ts"] }
goTo.file("a.ts")
verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts"])
verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts", "tsconfig.json"])
@@ -10,4 +10,4 @@
////{ "files": ["a.ts", "c.ts", "b.ts"] }
goTo.file("a.ts");
verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts"])
verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts", "tsconfig.json"])
+78 -176
View File
@@ -76,6 +76,40 @@ namespace ts {
"c:/dev/jspm_packages/a.ts"
]);
function assertParsed(actual: ts.ParsedCommandLine, expected: ts.ParsedCommandLine): void {
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
}
function validateMatches(expected: ts.ParsedCommandLine, json: any, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[]) {
{
const jsonText = JSON.stringify(json);
const result = parseJsonText("c:/dev/tsconfig.json", jsonText);
const actual = ts.parseJsonSourceFileConfigFileContent(result, host, basePath, existingOptions, configFileName, resolutionStack);
for (const error of expected.errors) {
if (error.file) {
error.file = result;
}
}
assertParsed(actual, expected);
}
{
const actual = ts.parseJsonConfigFileContent(json, host, basePath, existingOptions, configFileName, resolutionStack);
expected.errors = map(expected.errors, error => {
return <Diagnostic>{
category: error.category,
code: error.code,
file: undefined,
length: undefined,
messageText: error.messageText,
start: undefined,
};
});
assertParsed(actual, expected);
}
}
describe("matchFiles", () => {
describe("with literal file list", () => {
it("without exclusions", () => {
@@ -94,10 +128,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("missing files are still present", () => {
const json = {
@@ -115,10 +146,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("are not removed due to excludes", () => {
const json = {
@@ -139,10 +167,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
@@ -163,10 +188,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with non .ts file extensions are excluded", () => {
const json = {
@@ -181,10 +203,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with missing files are excluded", () => {
const json = {
@@ -199,10 +218,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with literal excludes", () => {
const json = {
@@ -222,10 +238,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with wildcard excludes", () => {
const json = {
@@ -252,10 +265,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with recursive excludes", () => {
const json = {
@@ -281,10 +291,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with case sensitive exclude", () => {
const json = {
@@ -303,10 +310,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath);
});
it("with common package folders and no exclusions", () => {
const json = {
@@ -327,10 +331,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and exclusions", () => {
const json = {
@@ -356,10 +357,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and empty exclude", () => {
const json = {
@@ -384,10 +382,7 @@ namespace ts {
],
wildcardDirectories: {},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
});
@@ -410,10 +405,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("`*` matches only ts files", () => {
const json = {
@@ -433,10 +425,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("`?` matches only a single character", () => {
const json = {
@@ -455,10 +444,7 @@ namespace ts {
"c:/dev/x": ts.WatchDirectoryFlags.None
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with recursive directory", () => {
const json = {
@@ -479,10 +465,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with multiple recursive directories", () => {
const json = {
@@ -505,10 +488,7 @@ namespace ts {
"c:/dev/z": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("case sensitive", () => {
const json = {
@@ -526,10 +506,7 @@ namespace ts {
"/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath);
});
it("with missing files are excluded", () => {
const json = {
@@ -545,10 +522,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("always include literal files", () => {
const json = {
@@ -572,10 +546,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("exclude folders", () => {
const json = {
@@ -599,10 +570,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with common package folders and no exclusions", () => {
const json = {
@@ -620,10 +588,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and exclusions", () => {
const json = {
@@ -646,10 +611,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("with common package folders and empty exclude", () => {
const json = {
@@ -671,10 +633,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
},
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath);
});
it("exclude .js files when allowJs=false", () => {
const json = {
@@ -695,10 +654,7 @@ namespace ts {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("include .js files when allowJs=true", () => {
const json = {
@@ -722,10 +678,7 @@ namespace ts {
"c:/dev/js": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("include paths outside of the project", () => {
const json = {
@@ -748,10 +701,7 @@ namespace ts {
"c:/ext": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("include paths outside of the project using relative paths", () => {
@@ -774,10 +724,7 @@ namespace ts {
"c:/ext": ts.WatchDirectoryFlags.None
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("exclude paths outside of the project using relative paths", () => {
const json = {
@@ -794,10 +741,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("include files with .. in their name", () => {
const json = {
@@ -816,10 +760,7 @@ namespace ts {
],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("exclude files with .. in their name", () => {
const json = {
@@ -840,10 +781,7 @@ namespace ts {
"c:/ext": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("with jsx=none, allowJs=false", () => {
@@ -866,10 +804,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=preserve, allowJs=false", () => {
const json = {
@@ -893,10 +828,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=react-native, allowJs=false", () => {
const json = {
@@ -947,10 +879,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=preserve, allowJs=true", () => {
const json = {
@@ -976,10 +905,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
});
it("with jsx=react-native, allowJs=true", () => {
const json = {
@@ -1025,10 +951,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("in excludes", () => {
const json = {
@@ -1045,10 +968,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
describe("with multiple recursive directory patterns", () => {
@@ -1066,10 +986,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("in excludes", () => {
const json = {
@@ -1095,10 +1012,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
@@ -1117,10 +1031,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("in includes after a subdirectory", () => {
@@ -1137,10 +1048,7 @@ namespace ts {
fileNames: [],
wildcardDirectories: {}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("in excludes immediately after", () => {
@@ -1167,10 +1075,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
it("in excludes after a subdirectory", () => {
@@ -1197,10 +1102,7 @@ namespace ts {
"c:/dev": ts.WatchDirectoryFlags.Recursive
}
};
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath);
assert.deepEqual(actual.fileNames, expected.fileNames);
assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories);
assert.deepEqual(actual.errors, expected.errors);
validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath);
});
});
});