mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into promisesAndUnderscores
This commit is contained in:
@@ -2465,7 +2465,7 @@ namespace ts {
|
||||
node.left.parent = node;
|
||||
node.right.parent = node;
|
||||
const lhs = node.left as PropertyAccessEntityNameExpression;
|
||||
bindPropertyAssignment(lhs, lhs, /*isPrototypeProperty*/ false);
|
||||
bindPropertyAssignment(lhs.expression, lhs, /*isPrototypeProperty*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2522,7 +2522,7 @@ namespace ts {
|
||||
const isToplevel = isBinaryExpression(propertyAccess.parent)
|
||||
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile
|
||||
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
|
||||
if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevel) {
|
||||
if (isToplevel && !isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace))) {
|
||||
// make symbols or add declarations for intermediate containers
|
||||
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
|
||||
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment;
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace ts.BuilderState {
|
||||
function getReferencedFileFromImportedModuleSymbol(symbol: Symbol) {
|
||||
if (symbol.declarations && symbol.declarations[0]) {
|
||||
const declarationSourceFile = getSourceFileOfNode(symbol.declarations[0]);
|
||||
return declarationSourceFile && declarationSourceFile.path;
|
||||
return declarationSourceFile && (declarationSourceFile.resolvedPath || declarationSourceFile.path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,13 @@ namespace ts.BuilderState {
|
||||
return symbol && getReferencedFileFromImportedModuleSymbol(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to reference file from file name, it could be resolvedPath if present otherwise path
|
||||
*/
|
||||
function getReferencedFileFromFileName(program: Program, fileName: string, sourceFileDirectory: Path, getCanonicalFileName: GetCanonicalFileName): Path {
|
||||
return toPath(program.getProjectReferenceRedirect(fileName) || fileName, sourceFileDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true
|
||||
*/
|
||||
@@ -123,7 +130,7 @@ namespace ts.BuilderState {
|
||||
// Handle triple slash references
|
||||
if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
|
||||
for (const referencedFile of sourceFile.referencedFiles) {
|
||||
const referencedPath = toPath(referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
|
||||
const referencedPath = getReferencedFileFromFileName(program, referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
|
||||
addReferencedFile(referencedPath);
|
||||
}
|
||||
}
|
||||
@@ -136,7 +143,7 @@ namespace ts.BuilderState {
|
||||
}
|
||||
|
||||
const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217
|
||||
const typeFilePath = toPath(fileName, sourceFileDirectory, getCanonicalFileName);
|
||||
const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName);
|
||||
addReferencedFile(typeFilePath);
|
||||
});
|
||||
}
|
||||
|
||||
+49
-19
@@ -640,7 +640,7 @@ namespace ts {
|
||||
const identityRelation = createMap<RelationComparisonResult>();
|
||||
const enumRelation = createMap<RelationComparisonResult>();
|
||||
|
||||
type TypeSystemEntity = Symbol | Type | Signature;
|
||||
type TypeSystemEntity = Node | Symbol | Type | Signature;
|
||||
|
||||
const enum TypeSystemPropertyName {
|
||||
Type,
|
||||
@@ -648,6 +648,7 @@ namespace ts {
|
||||
DeclaredType,
|
||||
ResolvedReturnType,
|
||||
ImmediateBaseConstraint,
|
||||
EnumTagType,
|
||||
}
|
||||
|
||||
const enum CheckMode {
|
||||
@@ -3470,8 +3471,8 @@ namespace ts {
|
||||
const arity = getTypeReferenceArity(type);
|
||||
const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context);
|
||||
const hasRestElement = (<TupleType>type.target).hasRestElement;
|
||||
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
|
||||
for (let i = (<TupleType>type.target).minLength; i < arity; i++) {
|
||||
if (tupleConstituentNodes) {
|
||||
for (let i = (<TupleType>type.target).minLength; i < Math.min(arity, tupleConstituentNodes.length); i++) {
|
||||
tupleConstituentNodes[i] = hasRestElement && i === arity - 1 ?
|
||||
createRestTypeNode(createArrayTypeNode(tupleConstituentNodes[i])) :
|
||||
createOptionalTypeNode(tupleConstituentNodes[i]);
|
||||
@@ -4475,6 +4476,8 @@ namespace ts {
|
||||
switch (propertyName) {
|
||||
case TypeSystemPropertyName.Type:
|
||||
return !!getSymbolLinks(<Symbol>target).type;
|
||||
case TypeSystemPropertyName.EnumTagType:
|
||||
return !!(getNodeLinks(target as JSDocEnumTag).resolvedEnumType);
|
||||
case TypeSystemPropertyName.DeclaredType:
|
||||
return !!getSymbolLinks(<Symbol>target).declaredType;
|
||||
case TypeSystemPropertyName.ResolvedBaseConstructorType:
|
||||
@@ -8252,9 +8255,18 @@ namespace ts {
|
||||
}
|
||||
|
||||
// JS are 'string' or 'number', not an enum type.
|
||||
const enumTag = symbol.valueDeclaration && getJSDocEnumTag(symbol.valueDeclaration);
|
||||
const enumTag = isInJSFile(node) && symbol.valueDeclaration && getJSDocEnumTag(symbol.valueDeclaration);
|
||||
if (enumTag) {
|
||||
return enumTag.typeExpression ? getTypeFromTypeNode(enumTag.typeExpression) : errorType;
|
||||
const links = getNodeLinks(enumTag);
|
||||
if (!pushTypeResolution(enumTag, TypeSystemPropertyName.EnumTagType)) {
|
||||
return errorType;
|
||||
}
|
||||
let type = enumTag.typeExpression ? getTypeFromTypeNode(enumTag.typeExpression) : errorType;
|
||||
if (!popTypeResolution()) {
|
||||
type = errorType;
|
||||
error(node, Diagnostics.Enum_type_0_circularly_references_itself, symbolToString(symbol));
|
||||
}
|
||||
return (links.resolvedEnumType = type);
|
||||
}
|
||||
|
||||
// Get type from reference to named type that cannot be generic (enum or type parameter)
|
||||
@@ -13373,7 +13385,7 @@ namespace ts {
|
||||
let propagationType: Type;
|
||||
inferFromTypes(originalSource, originalTarget);
|
||||
|
||||
function inferFromTypes(source: Type, target: Type) {
|
||||
function inferFromTypes(source: Type, target: Type): void {
|
||||
if (!couldContainTypeVariables(target)) {
|
||||
return;
|
||||
}
|
||||
@@ -13508,6 +13520,9 @@ namespace ts {
|
||||
inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
|
||||
inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
|
||||
}
|
||||
else if (target.flags & TypeFlags.Conditional) {
|
||||
inferFromTypes(source, getUnionType([getTrueTypeFromConditionalType(<ConditionalType>target), getFalseTypeFromConditionalType(<ConditionalType>target)]));
|
||||
}
|
||||
else if (target.flags & TypeFlags.UnionOrIntersection) {
|
||||
const targetTypes = (<UnionOrIntersectionType>target).types;
|
||||
let typeVariableCount = 0;
|
||||
@@ -13541,7 +13556,14 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) {
|
||||
source = getApparentType(source);
|
||||
const apparentSource = getApparentType(source);
|
||||
// getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type.
|
||||
// If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes`
|
||||
// with the simplified source.
|
||||
if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
|
||||
return inferFromTypes(apparentSource, target);
|
||||
}
|
||||
source = apparentSource;
|
||||
}
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
||||
const key = source.id + "," + target.id;
|
||||
@@ -13747,7 +13769,7 @@ namespace ts {
|
||||
|
||||
function hasPrimitiveConstraint(type: TypeParameter): boolean {
|
||||
const constraint = getConstraintOfTypeParameter(type);
|
||||
return !!constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index);
|
||||
return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index);
|
||||
}
|
||||
|
||||
function isObjectLiteralType(type: Type) {
|
||||
@@ -14734,6 +14756,14 @@ namespace ts {
|
||||
// reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case,
|
||||
// return the declared type.
|
||||
if (containsMatchingReference(reference, node)) {
|
||||
// A matching dotted name might also be an expando property on a function *expression*,
|
||||
// in which case we continue control flow analysis back to the function's declaration
|
||||
if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConst(node))) {
|
||||
const init = getDeclaredExpandoInitializer(node);
|
||||
if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) {
|
||||
return getTypeAtFlowNode(flow.antecedent);
|
||||
}
|
||||
}
|
||||
return declaredType;
|
||||
}
|
||||
// Assignment doesn't affect reference
|
||||
@@ -18208,7 +18238,7 @@ namespace ts {
|
||||
// Referencing abstract properties within their own constructors is not allowed
|
||||
if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) {
|
||||
const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!);
|
||||
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node, declaringClassDeclaration)) {
|
||||
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node)) {
|
||||
error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); // TODO: GH#18217
|
||||
return false;
|
||||
}
|
||||
@@ -18395,6 +18425,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strictNullChecks && prop && prop.valueDeclaration && isPropertyAccessExpression(prop.valueDeclaration) && getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration)) {
|
||||
assumeUninitialized = true;
|
||||
}
|
||||
const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType);
|
||||
if (assumeUninitialized && !(getFalsyFlags(propType) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
|
||||
error(right, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217
|
||||
@@ -20192,18 +20225,15 @@ namespace ts {
|
||||
assigned || inferred;
|
||||
}
|
||||
|
||||
function getAssignedClassType(symbol: Symbol) {
|
||||
function getAssignedClassType(symbol: Symbol): Type | undefined {
|
||||
const decl = symbol.valueDeclaration;
|
||||
const assignmentSymbol = decl && decl.parent &&
|
||||
(isFunctionDeclaration(decl) && getSymbolOfNode(decl) ||
|
||||
isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
|
||||
isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent));
|
||||
if (assignmentSymbol) {
|
||||
const prototype = forEach(assignmentSymbol.declarations, getAssignedJSPrototype);
|
||||
if (prototype) {
|
||||
return checkExpression(prototype);
|
||||
}
|
||||
}
|
||||
const prototype = assignmentSymbol && assignmentSymbol.exports && assignmentSymbol.exports.get("prototype" as __String);
|
||||
const init = prototype && getAssignedJSPrototype(prototype.valueDeclaration);
|
||||
return init ? checkExpression(init) : undefined;
|
||||
}
|
||||
|
||||
function getAssignedJSPrototype(node: Node) {
|
||||
@@ -27419,12 +27449,12 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function isNodeUsedDuringClassInitialization(node: Node, classDeclaration: ClassLikeDeclaration) {
|
||||
function isNodeUsedDuringClassInitialization(node: Node) {
|
||||
return !!findAncestor(node, element => {
|
||||
if ((isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) && element.parent === classDeclaration) {
|
||||
if (isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) {
|
||||
return true;
|
||||
}
|
||||
else if (element === classDeclaration || isFunctionLikeDeclaration(element)) {
|
||||
else if (isClassLike(element) || isFunctionLikeDeclaration(element)) {
|
||||
return "quit";
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,8 @@ namespace ts {
|
||||
es2018: ScriptTarget.ES2018,
|
||||
esnext: ScriptTarget.ESNext,
|
||||
}),
|
||||
affectsSourceFile: true,
|
||||
affectsModuleResolution: true,
|
||||
paramType: Diagnostics.VERSION,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
@@ -190,6 +192,7 @@ namespace ts {
|
||||
es2015: ModuleKind.ES2015,
|
||||
esnext: ModuleKind.ESNext
|
||||
}),
|
||||
affectsModuleResolution: true,
|
||||
paramType: Diagnostics.KIND,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
@@ -202,6 +205,7 @@ namespace ts {
|
||||
name: "lib",
|
||||
type: libMap
|
||||
},
|
||||
affectsModuleResolution: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation
|
||||
@@ -209,6 +213,7 @@ namespace ts {
|
||||
{
|
||||
name: "allowJs",
|
||||
type: "boolean",
|
||||
affectsModuleResolution: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
description: Diagnostics.Allow_javascript_files_to_be_compiled
|
||||
@@ -226,6 +231,7 @@ namespace ts {
|
||||
"react-native": JsxEmit.ReactNative,
|
||||
"react": JsxEmit.React
|
||||
}),
|
||||
affectsSourceFile: true,
|
||||
paramType: Diagnostics.KIND,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
@@ -336,6 +342,7 @@ namespace ts {
|
||||
{
|
||||
name: "noImplicitAny",
|
||||
type: "boolean",
|
||||
affectsSemanticDiagnostics: true,
|
||||
strictFlag: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
@@ -344,6 +351,7 @@ namespace ts {
|
||||
{
|
||||
name: "strictNullChecks",
|
||||
type: "boolean",
|
||||
affectsSemanticDiagnostics: true,
|
||||
strictFlag: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
@@ -352,6 +360,7 @@ namespace ts {
|
||||
{
|
||||
name: "strictFunctionTypes",
|
||||
type: "boolean",
|
||||
affectsSemanticDiagnostics: true,
|
||||
strictFlag: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
@@ -360,6 +369,7 @@ namespace ts {
|
||||
{
|
||||
name: "strictPropertyInitialization",
|
||||
type: "boolean",
|
||||
affectsSemanticDiagnostics: true,
|
||||
strictFlag: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
@@ -368,6 +378,7 @@ namespace ts {
|
||||
{
|
||||
name: "noImplicitThis",
|
||||
type: "boolean",
|
||||
affectsSemanticDiagnostics: true,
|
||||
strictFlag: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
@@ -376,6 +387,7 @@ namespace ts {
|
||||
{
|
||||
name: "alwaysStrict",
|
||||
type: "boolean",
|
||||
affectsSourceFile: true,
|
||||
strictFlag: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Strict_Type_Checking_Options,
|
||||
@@ -410,6 +422,7 @@ namespace ts {
|
||||
{
|
||||
name: "noFallthroughCasesInSwitch",
|
||||
type: "boolean",
|
||||
affectsBindDiagnostics: true,
|
||||
affectsSemanticDiagnostics: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Additional_Checks,
|
||||
@@ -423,6 +436,7 @@ namespace ts {
|
||||
node: ModuleResolutionKind.NodeJs,
|
||||
classic: ModuleResolutionKind.Classic,
|
||||
}),
|
||||
affectsModuleResolution: true,
|
||||
paramType: Diagnostics.STRATEGY,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Specify_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
|
||||
@@ -430,6 +444,7 @@ namespace ts {
|
||||
{
|
||||
name: "baseUrl",
|
||||
type: "string",
|
||||
affectsModuleResolution: true,
|
||||
isFilePath: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Base_directory_to_resolve_non_absolute_module_names
|
||||
@@ -439,6 +454,7 @@ namespace ts {
|
||||
// use type = object to copy the value as-is
|
||||
name: "paths",
|
||||
type: "object",
|
||||
affectsModuleResolution: true,
|
||||
isTSConfigOnly: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl
|
||||
@@ -454,6 +470,7 @@ namespace ts {
|
||||
type: "string",
|
||||
isFilePath: true
|
||||
},
|
||||
affectsModuleResolution: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.List_of_root_folders_whose_combined_content_represents_the_structure_of_the_project_at_runtime
|
||||
},
|
||||
@@ -465,6 +482,7 @@ namespace ts {
|
||||
type: "string",
|
||||
isFilePath: true
|
||||
},
|
||||
affectsModuleResolution: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.List_of_folders_to_include_type_definitions_from
|
||||
},
|
||||
@@ -475,6 +493,7 @@ namespace ts {
|
||||
name: "types",
|
||||
type: "string"
|
||||
},
|
||||
affectsModuleResolution: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Type_declaration_files_to_be_included_in_compilation
|
||||
@@ -633,12 +652,14 @@ namespace ts {
|
||||
{
|
||||
name: "noLib",
|
||||
type: "boolean",
|
||||
affectsModuleResolution: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Do_not_include_the_default_library_file_lib_d_ts
|
||||
},
|
||||
{
|
||||
name: "noResolve",
|
||||
type: "boolean",
|
||||
affectsModuleResolution: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Do_not_add_triple_slash_references_or_imported_modules_to_the_list_of_compiled_files
|
||||
},
|
||||
@@ -651,6 +672,7 @@ namespace ts {
|
||||
{
|
||||
name: "disableSizeLimit",
|
||||
type: "boolean",
|
||||
affectsSourceFile: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Disable_size_limitations_on_JavaScript_projects
|
||||
},
|
||||
@@ -696,6 +718,7 @@ namespace ts {
|
||||
{
|
||||
name: "allowUnusedLabels",
|
||||
type: "boolean",
|
||||
affectsBindDiagnostics: true,
|
||||
affectsSemanticDiagnostics: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Do_not_report_errors_on_unused_labels
|
||||
@@ -703,6 +726,7 @@ namespace ts {
|
||||
{
|
||||
name: "allowUnreachableCode",
|
||||
type: "boolean",
|
||||
affectsBindDiagnostics: true,
|
||||
affectsSemanticDiagnostics: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Do_not_report_errors_on_unreachable_code
|
||||
@@ -730,6 +754,7 @@ namespace ts {
|
||||
{
|
||||
name: "maxNodeModuleJsDepth",
|
||||
type: "number",
|
||||
// TODO: GH#27108 affectsModuleResolution: true,
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.The_maximum_dependency_depth_to_search_under_node_modules_and_load_JavaScript_files
|
||||
},
|
||||
@@ -759,6 +784,18 @@ namespace ts {
|
||||
}
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
export const semanticDiagnosticsOptionDeclarations: ReadonlyArray<CommandLineOption> =
|
||||
optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics);
|
||||
|
||||
/* @internal */
|
||||
export const moduleResolutionOptionDeclarations: ReadonlyArray<CommandLineOption> =
|
||||
optionDeclarations.filter(option => !!option.affectsModuleResolution);
|
||||
|
||||
/* @internal */
|
||||
export const sourceFileAffectingCompilerOptions: ReadonlyArray<CommandLineOption> = optionDeclarations.filter(option =>
|
||||
!!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics);
|
||||
|
||||
/* @internal */
|
||||
export const buildOpts: CommandLineOption[] = [
|
||||
...commonOptionsWithBuild,
|
||||
@@ -1993,7 +2030,7 @@ namespace ts {
|
||||
if (ownConfig.extendedConfigPath) {
|
||||
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
|
||||
resolutionStack = resolutionStack.concat([resolvedPath]);
|
||||
const extendedConfig = getExtendedConfig(sourceFile!, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
|
||||
const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
|
||||
if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) {
|
||||
const baseRaw = extendedConfig.raw;
|
||||
const raw = ownConfig.raw;
|
||||
@@ -2134,7 +2171,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getExtendedConfig(
|
||||
sourceFile: TsConfigSourceFile,
|
||||
sourceFile: TsConfigSourceFile | undefined,
|
||||
extendedConfigPath: string,
|
||||
host: ParseConfigHost,
|
||||
basePath: string,
|
||||
@@ -2143,7 +2180,7 @@ namespace ts {
|
||||
): ParsedTsconfig | undefined {
|
||||
const extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
|
||||
if (sourceFile) {
|
||||
(sourceFile.extendedSourceFiles || (sourceFile.extendedSourceFiles = [])).push(extendedResult.fileName);
|
||||
sourceFile.extendedSourceFiles = [extendedResult.fileName];
|
||||
}
|
||||
if (extendedResult.parseDiagnostics.length) {
|
||||
errors.push(...extendedResult.parseDiagnostics);
|
||||
@@ -2153,8 +2190,8 @@ namespace ts {
|
||||
const extendedDirname = getDirectoryPath(extendedConfigPath);
|
||||
const extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
|
||||
getBaseFileName(extendedConfigPath), resolutionStack, errors);
|
||||
if (sourceFile) {
|
||||
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles!);
|
||||
if (sourceFile && extendedResult.extendedSourceFiles) {
|
||||
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles);
|
||||
}
|
||||
|
||||
if (isSuccessfulParsedTsconfig(extendedConfig)) {
|
||||
|
||||
@@ -842,7 +842,7 @@ namespace ts {
|
||||
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
|
||||
}
|
||||
|
||||
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T) => boolean = equateValues): boolean {
|
||||
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
|
||||
if (!array1 || !array2) {
|
||||
return array1 === array2;
|
||||
}
|
||||
@@ -852,7 +852,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
for (let i = 0; i < array1.length; i++) {
|
||||
if (!equalityComparer(array1[i], array2[i])) {
|
||||
if (!equalityComparer(array1[i], array2[i], i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2112,6 +2112,10 @@
|
||||
"category": "Error",
|
||||
"code": 2585
|
||||
},
|
||||
"Enum type '{0}' circularly references itself.": {
|
||||
"category": "Error",
|
||||
"code": 2586
|
||||
},
|
||||
"JSX element attributes type '{0}' may not be a union type.": {
|
||||
"category": "Error",
|
||||
"code": 2600
|
||||
@@ -4145,6 +4149,10 @@
|
||||
"category": "Error",
|
||||
"code": 8030
|
||||
},
|
||||
"You cannot rename a module via a global import.": {
|
||||
"category": "Error",
|
||||
"code": 8031
|
||||
},
|
||||
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
|
||||
"category": "Error",
|
||||
"code": 9002
|
||||
|
||||
@@ -1041,7 +1041,7 @@ namespace ts {
|
||||
// SyntaxKind.TemplateMiddle
|
||||
// SyntaxKind.TemplateTail
|
||||
function emitLiteral(node: LiteralLikeNode) {
|
||||
const text = getLiteralTextOfNode(node);
|
||||
const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape);
|
||||
if ((printerOptions.sourceMap || printerOptions.inlineSourceMap)
|
||||
&& (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
|
||||
writeLiteral(text);
|
||||
@@ -1532,7 +1532,7 @@ namespace ts {
|
||||
expression = skipPartiallyEmittedExpressions(expression);
|
||||
if (isNumericLiteral(expression)) {
|
||||
// check if numeric literal is a decimal literal that was originally written with a dot
|
||||
const text = getLiteralTextOfNode(<LiteralExpression>expression);
|
||||
const text = getLiteralTextOfNode(<LiteralExpression>expression, /*neverAsciiEscape*/ true);
|
||||
return !expression.numericLiteralFlags
|
||||
&& !stringContains(text, tokenToString(SyntaxKind.DotToken)!);
|
||||
}
|
||||
@@ -3306,20 +3306,20 @@ namespace ts {
|
||||
return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia);
|
||||
}
|
||||
|
||||
function getLiteralTextOfNode(node: LiteralLikeNode): string {
|
||||
function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined): string {
|
||||
if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
|
||||
const textSourceNode = (<StringLiteral>node).textSourceNode!;
|
||||
if (isIdentifier(textSourceNode)) {
|
||||
return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ?
|
||||
return neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ?
|
||||
`"${escapeString(getTextOfNode(textSourceNode))}"` :
|
||||
`"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`;
|
||||
}
|
||||
else {
|
||||
return getLiteralTextOfNode(textSourceNode);
|
||||
return getLiteralTextOfNode(textSourceNode, neverAsciiEscape);
|
||||
}
|
||||
}
|
||||
|
||||
return getLiteralText(node, currentSourceFile);
|
||||
return getLiteralText(node, currentSourceFile, neverAsciiEscape);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+55
-31
@@ -455,7 +455,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// If project references dont match
|
||||
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences)) {
|
||||
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences, projectReferenceUptoDate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -483,9 +483,27 @@ namespace ts {
|
||||
|
||||
return true;
|
||||
|
||||
function sourceFileNotUptoDate(sourceFile: SourceFile): boolean {
|
||||
return sourceFile.version !== getSourceVersion(sourceFile.path) ||
|
||||
hasInvalidatedResolution(sourceFile.path);
|
||||
function sourceFileNotUptoDate(sourceFile: SourceFile) {
|
||||
return !sourceFileVersionUptoDate(sourceFile) ||
|
||||
hasInvalidatedResolution(sourceFile.resolvedPath || sourceFile.path);
|
||||
}
|
||||
|
||||
function sourceFileVersionUptoDate(sourceFile: SourceFile) {
|
||||
return sourceFile.version === getSourceVersion(sourceFile.resolvedPath || sourceFile.path);
|
||||
}
|
||||
|
||||
function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) {
|
||||
if (!projectReferenceIsEqualTo(oldRef, newRef)) {
|
||||
return false;
|
||||
}
|
||||
const oldResolvedRef = program!.getResolvedProjectReferences()![index];
|
||||
if (oldResolvedRef) {
|
||||
// If sourceFile for the oldResolvedRef existed, check the version for uptodate
|
||||
return sourceFileVersionUptoDate(oldResolvedRef.sourceFile);
|
||||
}
|
||||
// In old program, not able to resolve project reference path,
|
||||
// so if config file doesnt exist, it is uptodate.
|
||||
return !fileExists(resolveProjectReferencePath(oldRef));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,23 +514,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determined if source file needs to be re-created even if its text hasn't changed
|
||||
* Determine if source file needs to be re-created even if its text hasn't changed
|
||||
*/
|
||||
function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions) {
|
||||
// If any of these options change, we can't reuse old source file even if version match
|
||||
// The change in options like these could result in change in syntax tree change
|
||||
const oldOptions = program && program.getCompilerOptions();
|
||||
return oldOptions && (
|
||||
oldOptions.target !== newOptions.target ||
|
||||
oldOptions.module !== newOptions.module ||
|
||||
oldOptions.moduleResolution !== newOptions.moduleResolution ||
|
||||
oldOptions.noResolve !== newOptions.noResolve ||
|
||||
oldOptions.jsx !== newOptions.jsx ||
|
||||
oldOptions.allowJs !== newOptions.allowJs ||
|
||||
oldOptions.disableSizeLimit !== newOptions.disableSizeLimit ||
|
||||
oldOptions.baseUrl !== newOptions.baseUrl ||
|
||||
!equalOwnProperties(oldOptions.paths, newOptions.paths)
|
||||
);
|
||||
function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions): boolean {
|
||||
if (!program) return false;
|
||||
// If any compiler options change, we can't reuse old source file even if version match
|
||||
// The change in options like these could result in change in syntax tree or `sourceFile.bindDiagnostics`.
|
||||
const oldOptions = program.getCompilerOptions();
|
||||
return !!sourceFileAffectingCompilerOptions.some(option =>
|
||||
!isJsonEqual(getCompilerOptionValue(oldOptions, option), getCompilerOptionValue(newOptions, option)));
|
||||
}
|
||||
|
||||
function createCreateProgramOptions(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): CreateProgramOptions {
|
||||
@@ -666,8 +676,9 @@ namespace ts {
|
||||
const parsedRef = parseProjectReferenceConfigFile(ref);
|
||||
resolvedProjectReferences!.push(parsedRef);
|
||||
if (parsedRef) {
|
||||
if (parsedRef.commandLine.options.outFile) {
|
||||
const dtsOutfile = changeExtension(parsedRef.commandLine.options.outFile, ".d.ts");
|
||||
const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out;
|
||||
if (out) {
|
||||
const dtsOutfile = changeExtension(out, ".d.ts");
|
||||
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
|
||||
}
|
||||
addProjectReferenceRedirects(parsedRef.commandLine, projectReferenceRedirects);
|
||||
@@ -766,7 +777,8 @@ namespace ts {
|
||||
getConfigFileParsingDiagnostics,
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache,
|
||||
getProjectReferences,
|
||||
getResolvedProjectReferences
|
||||
getResolvedProjectReferences,
|
||||
getProjectReferenceRedirect
|
||||
};
|
||||
|
||||
verifyCompilerOptions();
|
||||
@@ -1233,6 +1245,13 @@ namespace ts {
|
||||
}
|
||||
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
|
||||
resolvedProjectReferences = oldProgram.getResolvedProjectReferences();
|
||||
if (resolvedProjectReferences) {
|
||||
resolvedProjectReferences.forEach(ref => {
|
||||
if (ref) {
|
||||
addProjectReferenceRedirects(ref.commandLine, projectReferenceRedirects);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
|
||||
redirectTargetsMap = oldProgram.redirectTargetsMap;
|
||||
@@ -1288,12 +1307,13 @@ namespace ts {
|
||||
const ref = projectReferences[i];
|
||||
const resolvedRefOpts = resolvedProjectReferences![i]!.commandLine;
|
||||
if (ref.prepend && resolvedRefOpts && resolvedRefOpts.options) {
|
||||
const out = resolvedRefOpts.options.outFile || resolvedRefOpts.options.out;
|
||||
// Upstream project didn't have outFile set -- skip (error will have been issued earlier)
|
||||
if (!resolvedRefOpts.options.outFile) continue;
|
||||
if (!out) continue;
|
||||
|
||||
const dtsFilename = changeExtension(resolvedRefOpts.options.outFile, ".d.ts");
|
||||
const js = host.readFile(resolvedRefOpts.options.outFile) || `/* Input file ${resolvedRefOpts.options.outFile} was missing */\r\n`;
|
||||
const jsMapPath = resolvedRefOpts.options.outFile + ".map"; // TODO: try to read sourceMappingUrl comment from the file
|
||||
const dtsFilename = changeExtension(out, ".d.ts");
|
||||
const js = host.readFile(out) || `/* Input file ${out} was missing */\r\n`;
|
||||
const jsMapPath = out + ".map"; // TODO: try to read sourceMappingUrl comment from the file
|
||||
const jsMap = host.readFile(jsMapPath);
|
||||
const dts = host.readFile(dtsFilename) || `/* Input file ${dtsFilename} was missing */\r\n`;
|
||||
const dtsMapPath = dtsFilename + ".map";
|
||||
@@ -2435,9 +2455,10 @@ namespace ts {
|
||||
createDiagnosticForReference(i, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
|
||||
}
|
||||
if (ref.prepend) {
|
||||
if (resolvedRefOpts.outFile) {
|
||||
if (!host.fileExists(resolvedRefOpts.outFile)) {
|
||||
createDiagnosticForReference(i, Diagnostics.Output_file_0_from_project_1_does_not_exist, resolvedRefOpts.outFile, ref.path);
|
||||
const out = resolvedRefOpts.outFile || resolvedRefOpts.out;
|
||||
if (out) {
|
||||
if (!host.fileExists(out)) {
|
||||
createDiagnosticForReference(i, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2829,7 +2850,10 @@ namespace ts {
|
||||
export function parseConfigHostFromCompilerHost(host: CompilerHost): ParseConfigFileHost {
|
||||
return {
|
||||
fileExists: f => host.fileExists(f),
|
||||
readDirectory: (root, extensions, includes, depth?) => host.readDirectory ? host.readDirectory(root, extensions, includes, depth) : [],
|
||||
readDirectory(root, extensions, excludes, includes, depth) {
|
||||
Debug.assertDefined(host.readDirectory, "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'");
|
||||
return host.readDirectory!(root, extensions, excludes, includes, depth);
|
||||
},
|
||||
readFile: f => host.readFile(f),
|
||||
useCaseSensitiveFileNames: host.useCaseSensitiveFileNames(),
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
|
||||
@@ -285,16 +285,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getOutFileOutputs(project: ParsedCommandLine): ReadonlyArray<string> {
|
||||
if (!project.options.outFile) {
|
||||
const out = project.options.outFile || project.options.out;
|
||||
if (!out) {
|
||||
return Debug.fail("outFile must be set");
|
||||
}
|
||||
const outputs: string[] = [];
|
||||
outputs.push(project.options.outFile);
|
||||
outputs.push(out);
|
||||
if (project.options.sourceMap) {
|
||||
outputs.push(`${project.options.outFile}.map`);
|
||||
outputs.push(`${out}.map`);
|
||||
}
|
||||
if (getEmitDeclarations(project.options)) {
|
||||
const dts = changeExtension(project.options.outFile, Extension.Dts);
|
||||
const dts = changeExtension(out, Extension.Dts);
|
||||
outputs.push(dts);
|
||||
if (project.options.declarationMap) {
|
||||
outputs.push(`${dts}.map`);
|
||||
@@ -862,7 +863,7 @@ namespace ts {
|
||||
if (buildProject) {
|
||||
buildSingleInvalidatedProject(buildProject.project, buildProject.reloadLevel);
|
||||
if (hasPendingInvalidatedProjects()) {
|
||||
if (!timerToBuildInvalidatedProject) {
|
||||
if (options.watch && !timerToBuildInvalidatedProject) {
|
||||
scheduleBuildInvalidatedProject();
|
||||
}
|
||||
}
|
||||
@@ -1248,7 +1249,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getAllProjectOutputs(project: ParsedCommandLine): ReadonlyArray<string> {
|
||||
if (project.options.outFile) {
|
||||
if (project.options.outFile || project.options.out) {
|
||||
return getOutFileOutputs(project);
|
||||
}
|
||||
else {
|
||||
|
||||
+12
-1
@@ -2551,6 +2551,11 @@ namespace ts {
|
||||
fileName: string;
|
||||
/* @internal */ path: Path;
|
||||
text: string;
|
||||
/** Resolved path can be different from path property,
|
||||
* when file is included through project reference is mapped to its output instead of source
|
||||
* in that case resolvedPath = path to output file
|
||||
* path = input file's path
|
||||
*/
|
||||
/* @internal */ resolvedPath: Path;
|
||||
|
||||
/**
|
||||
@@ -2819,6 +2824,7 @@ namespace ts {
|
||||
|
||||
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
|
||||
getResolvedProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
|
||||
/*@internal*/ getProjectReferenceRedirect(fileName: string): string | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3670,6 +3676,7 @@ namespace ts {
|
||||
export interface NodeLinks {
|
||||
flags: NodeCheckFlags; // Set of flags specific to Node
|
||||
resolvedType?: Type; // Cached type of type node
|
||||
resolvedEnumType?: Type; // Cached constraint type from enum jsdoc tag
|
||||
resolvedSignature?: Signature; // Cached signature of signature node or call expression
|
||||
resolvedSignatures?: Map<Signature[]>; // Cached signatures of jsx node
|
||||
resolvedSymbol?: Symbol; // Cached name resolution result
|
||||
@@ -4569,6 +4576,9 @@ namespace ts {
|
||||
showInSimplifiedHelpView?: boolean;
|
||||
category?: DiagnosticMessage;
|
||||
strictFlag?: true; // true if the option is one of the flag under strict
|
||||
affectsSourceFile?: true; // true if we should recreate SourceFiles after this option changes
|
||||
affectsModuleResolution?: true; // currently same effect as `affectsSourceFile`
|
||||
affectsBindDiagnostics?: true; // true if this affects binding (currently same effect as `affectsSourceFile`)
|
||||
affectsSemanticDiagnostics?: true; // true if option affects semantic diagnostics
|
||||
}
|
||||
|
||||
@@ -4964,7 +4974,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
export interface EmitNode {
|
||||
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
|
||||
flags: EmitFlags; // Flags that customize emit
|
||||
flags: EmitFlags; // Flags that customize emit
|
||||
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
|
||||
trailingComments?: SynthesizedComment[]; // Synthesized trailing comments
|
||||
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
|
||||
@@ -5324,6 +5334,7 @@ namespace ts {
|
||||
/*@internal*/ inlineSourceMap?: boolean;
|
||||
/*@internal*/ extendedDiagnostics?: boolean;
|
||||
/*@internal*/ onlyPrintJsDocStyle?: boolean;
|
||||
/*@internal*/ neverAsciiEscape?: boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
+16
-27
@@ -101,22 +101,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOptions: CompilerOptions): boolean {
|
||||
return !oldOptions ||
|
||||
(oldOptions.module !== newOptions.module) ||
|
||||
(oldOptions.moduleResolution !== newOptions.moduleResolution) ||
|
||||
(oldOptions.noResolve !== newOptions.noResolve) ||
|
||||
(oldOptions.target !== newOptions.target) ||
|
||||
(oldOptions.noLib !== newOptions.noLib) ||
|
||||
(oldOptions.jsx !== newOptions.jsx) ||
|
||||
(oldOptions.allowJs !== newOptions.allowJs) ||
|
||||
(oldOptions.rootDir !== newOptions.rootDir) ||
|
||||
(oldOptions.configFilePath !== newOptions.configFilePath) ||
|
||||
(oldOptions.baseUrl !== newOptions.baseUrl) ||
|
||||
(oldOptions.maxNodeModuleJsDepth !== newOptions.maxNodeModuleJsDepth) ||
|
||||
!arrayIsEqualTo(oldOptions.lib, newOptions.lib) ||
|
||||
!arrayIsEqualTo(oldOptions.typeRoots, newOptions.typeRoots) ||
|
||||
!arrayIsEqualTo(oldOptions.rootDirs, newOptions.rootDirs) ||
|
||||
!equalOwnProperties(oldOptions.paths, newOptions.paths);
|
||||
return oldOptions.configFilePath !== newOptions.configFilePath || moduleResolutionOptionDeclarations.some(o =>
|
||||
!isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,14 +524,14 @@ namespace ts {
|
||||
return emitNode && emitNode.flags || 0;
|
||||
}
|
||||
|
||||
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile) {
|
||||
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, neverAsciiEscape: boolean | undefined) {
|
||||
// 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.
|
||||
if (!nodeIsSynthesized(node) && node.parent && !(isNumericLiteral(node) && node.numericLiteralFlags & TokenFlags.ContainsSeparator)) {
|
||||
return getSourceTextOfNodeFromSourceFile(sourceFile, node);
|
||||
}
|
||||
|
||||
const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? escapeString : escapeNonAsciiString;
|
||||
const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : escapeNonAsciiString;
|
||||
|
||||
// If we can't reach the original source text, use the canonical form if it's a number,
|
||||
// or a (possibly escaped) quoted form of the original text if it's string-like.
|
||||
@@ -7091,9 +7077,8 @@ namespace ts {
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
return compilerOptions.allowSyntheticDefaultImports !== undefined
|
||||
? compilerOptions.allowSyntheticDefaultImports
|
||||
: compilerOptions.esModuleInterop
|
||||
? moduleKind !== ModuleKind.None && moduleKind < ModuleKind.ES2015
|
||||
: moduleKind === ModuleKind.System;
|
||||
: compilerOptions.esModuleInterop ||
|
||||
moduleKind === ModuleKind.System;
|
||||
}
|
||||
|
||||
export function getEmitDeclarations(compilerOptions: CompilerOptions): boolean {
|
||||
@@ -7106,13 +7091,13 @@ namespace ts {
|
||||
return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag];
|
||||
}
|
||||
|
||||
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions) {
|
||||
if (oldOptions === newOptions) {
|
||||
return false;
|
||||
}
|
||||
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean {
|
||||
return oldOptions !== newOptions &&
|
||||
semanticDiagnosticsOptionDeclarations.some(option => !isJsonEqual(getCompilerOptionValue(oldOptions, option), getCompilerOptionValue(newOptions, option)));
|
||||
}
|
||||
|
||||
return optionDeclarations.some(option => (!!option.strictFlag && getStrictOptionValue(newOptions, option.name as StrictOptionName) !== getStrictOptionValue(oldOptions, option.name as StrictOptionName)) ||
|
||||
(!!option.affectsSemanticDiagnostics && !newOptions[option.name] !== !oldOptions[option.name]));
|
||||
export function getCompilerOptionValue(options: CompilerOptions, option: CommandLineOption): unknown {
|
||||
return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) : options[option.name];
|
||||
}
|
||||
|
||||
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
|
||||
@@ -8380,4 +8365,8 @@ namespace ts {
|
||||
// '/// <reference no-default-lib="true"/>' directive.
|
||||
return options.skipLibCheck && sourceFile.isDeclarationFile || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib;
|
||||
}
|
||||
|
||||
export function isJsonEqual(a: unknown, b: unknown): boolean {
|
||||
return a === b || typeof a === "object" && a !== null && typeof b === "object" && b !== null && equalOwnProperties(a as MapLike<unknown>, b as MapLike<unknown>, isJsonEqual);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,9 +187,10 @@ interface Array<T> {}`
|
||||
}
|
||||
|
||||
export function checkArray(caption: string, actual: ReadonlyArray<string>, expected: ReadonlyArray<string>) {
|
||||
checkMapKeys(caption, arrayToMap(actual, identity), expected);
|
||||
assert.equal(actual.length, expected.length, `${caption}: incorrect actual number of files, expected:\r\n${expected.join("\r\n")}\r\ngot: ${actual.join("\r\n")}`);
|
||||
for (const f of expected) {
|
||||
assert.equal(true, contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
|
||||
assert.isTrue(contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -654,7 +655,7 @@ interface Array<T> {}`
|
||||
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath));
|
||||
}
|
||||
|
||||
invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
|
||||
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
|
||||
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath))!, ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind));
|
||||
}
|
||||
|
||||
@@ -934,7 +935,12 @@ interface Array<T> {}`
|
||||
const folder = this.fs.get(base) as FsFolder;
|
||||
Debug.assert(isFsFolder(folder));
|
||||
|
||||
this.addFileOrFolderInFolder(folder, file);
|
||||
if (!this.fs.has(file.path)) {
|
||||
this.addFileOrFolderInFolder(folder, file);
|
||||
}
|
||||
else {
|
||||
this.modifyFile(path, content);
|
||||
}
|
||||
}
|
||||
|
||||
write(message: string) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1123,6 +1123,9 @@ namespace ts.server.protocol {
|
||||
* Optional modifiers for the kind (such as 'public').
|
||||
*/
|
||||
kindModifiers: string;
|
||||
|
||||
/** Span of text to rename. */
|
||||
triggerSpan: TextSpan;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+23
-12
@@ -336,16 +336,23 @@ namespace ts.server {
|
||||
function combineProjectOutputForReferences(projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService): ReadonlyArray<ReferencedSymbol> {
|
||||
const outputs: ReferencedSymbol[] = [];
|
||||
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, tryAddToTodo) => {
|
||||
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, getMappedLocation) => {
|
||||
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
|
||||
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, outputReferencedSymbol.definition));
|
||||
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
|
||||
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
|
||||
...outputReferencedSymbol.definition,
|
||||
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
|
||||
fileName: mappedDefinitionFile.fileName,
|
||||
};
|
||||
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
|
||||
if (!symbolToAddTo) {
|
||||
symbolToAddTo = { definition: outputReferencedSymbol.definition, references: [] };
|
||||
symbolToAddTo = { definition, references: [] };
|
||||
outputs.push(symbolToAddTo);
|
||||
}
|
||||
|
||||
for (const ref of outputReferencedSymbol.references) {
|
||||
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(ref))) {
|
||||
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
|
||||
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
|
||||
symbolToAddTo.references.push(ref);
|
||||
}
|
||||
}
|
||||
@@ -373,12 +380,17 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
type CombineProjectOutputCallback<TLocation extends sourcemaps.SourceMappableLocation | undefined> = (
|
||||
where: ProjectAndLocation<TLocation>,
|
||||
getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => sourcemaps.SourceMappableLocation | undefined,
|
||||
) => void;
|
||||
|
||||
function combineProjectOutputWorker<TLocation extends sourcemaps.SourceMappableLocation | undefined>(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: TLocation,
|
||||
projectService: ProjectService,
|
||||
cb: (where: ProjectAndLocation<TLocation>, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
|
||||
cb: CombineProjectOutputCallback<TLocation>,
|
||||
getDefinition: (() => sourcemaps.SourceMappableLocation | undefined) | undefined,
|
||||
): void {
|
||||
let toDo: ProjectAndLocation<TLocation>[] | undefined;
|
||||
@@ -417,13 +429,13 @@ namespace ts.server {
|
||||
projectService: ProjectService,
|
||||
toDo: ProjectAndLocation<TLocation>[] | undefined,
|
||||
seenProjects: Map<true>,
|
||||
cb: (where: ProjectAndLocation<TLocation>, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
|
||||
cb: CombineProjectOutputCallback<TLocation>,
|
||||
): ProjectAndLocation<TLocation>[] | undefined {
|
||||
if (projectAndLocation.project.getCancellationToken().isCancellationRequested()) return undefined; // Skip rest of toDo if cancelled
|
||||
cb(projectAndLocation, (project, location) => {
|
||||
seenProjects.set(projectAndLocation.project.projectName, true);
|
||||
const originalLocation = projectService.getOriginalLocationEnsuringConfiguredProject(project, location);
|
||||
if (!originalLocation) return false;
|
||||
if (!originalLocation) return undefined;
|
||||
|
||||
const originalScriptInfo = projectService.getScriptInfo(originalLocation.fileName)!;
|
||||
toDo = toDo || [];
|
||||
@@ -437,7 +449,7 @@ namespace ts.server {
|
||||
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects);
|
||||
});
|
||||
}
|
||||
return true;
|
||||
return originalLocation;
|
||||
});
|
||||
return toDo;
|
||||
}
|
||||
@@ -1149,13 +1161,12 @@ namespace ts.server {
|
||||
if (!simplifiedResult) return locations;
|
||||
|
||||
const defaultProject = this.getDefaultProject(args);
|
||||
const renameInfo = Session.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position));
|
||||
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position), Debug.assertDefined(this.projectService.getScriptInfo(file)));
|
||||
return { info: renameInfo, locs: this.toSpanGroups(locations) };
|
||||
}
|
||||
|
||||
// strips 'triggerSpan'
|
||||
private static mapRenameInfo({ canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers }: RenameInfo): protocol.RenameInfo {
|
||||
return { canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers };
|
||||
private mapRenameInfo({ canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers, triggerSpan }: RenameInfo, scriptInfo: ScriptInfo): protocol.RenameInfo {
|
||||
return { canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: this.toLocationTextSpan(triggerSpan, scriptInfo) };
|
||||
}
|
||||
|
||||
private toSpanGroups(locations: ReadonlyArray<RenameLocation>): ReadonlyArray<protocol.SpanGroup> {
|
||||
|
||||
@@ -397,7 +397,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
// should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts
|
||||
function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier | undefined, parent: CallExpression, transformer: Transformer): NodeArray<Statement> {
|
||||
function getTransformationBody(func: Expression, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier | undefined, parent: CallExpression, transformer: Transformer): NodeArray<Statement> {
|
||||
|
||||
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString());
|
||||
switch (func.kind) {
|
||||
@@ -427,13 +427,14 @@ namespace ts.codefix {
|
||||
return varDeclOrAssignment;
|
||||
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.ArrowFunction: {
|
||||
const funcBody = (func as FunctionExpression | ArrowFunction).body;
|
||||
// Arrow functions with block bodies { } will enter this control flow
|
||||
if (isFunctionLikeDeclaration(func) && func.body && isBlock(func.body) && func.body.statements) {
|
||||
if (isBlock(funcBody)) {
|
||||
let refactoredStmts: Statement[] = [];
|
||||
let seenReturnStatement = false;
|
||||
|
||||
for (const statement of func.body.statements) {
|
||||
for (const statement of funcBody.statements) {
|
||||
if (isReturnStatement(statement)) {
|
||||
seenReturnStatement = true;
|
||||
}
|
||||
@@ -450,7 +451,6 @@ namespace ts.codefix {
|
||||
removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer, seenReturnStatement);
|
||||
}
|
||||
else {
|
||||
const funcBody = cast((<ArrowFunction>func).body, isExpression);
|
||||
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody));
|
||||
const innerCbBody = getInnerTransformationBody(transformer, innerRetStmts, prevArgName);
|
||||
|
||||
@@ -473,6 +473,7 @@ namespace ts.codefix {
|
||||
return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody))]);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
// If no cases apply, we've found a transformation body we don't know how to handle, so the refactoring should no-op to avoid deleting code.
|
||||
codeActionSucceeded = false;
|
||||
|
||||
@@ -121,10 +121,6 @@ namespace ts {
|
||||
const buckets = createMap<Map<DocumentRegistryEntry>>();
|
||||
const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
|
||||
|
||||
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
|
||||
return <DocumentRegistryBucketKey>`_${settings.target}|${settings.module}|${settings.noResolve}|${settings.jsx}|${settings.allowJs}|${settings.baseUrl}|${JSON.stringify(settings.typeRoots)}|${JSON.stringify(settings.rootDirs)}|${JSON.stringify(settings.paths)}`;
|
||||
}
|
||||
|
||||
function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): Map<DocumentRegistryEntry> {
|
||||
let bucket = buckets.get(key);
|
||||
if (!bucket && createIfMissing) {
|
||||
@@ -273,4 +269,8 @@ namespace ts {
|
||||
getKeyForCompilationSettings
|
||||
};
|
||||
}
|
||||
|
||||
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
|
||||
return sourceFileAffectingCompilerOptions.map(option => getCompilerOptionValue(settings, option)).join("|") as DocumentRegistryBucketKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,18 @@ namespace ts.Rename {
|
||||
}
|
||||
|
||||
function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, moduleSymbol: Symbol): RenameInfo | undefined {
|
||||
if (!isExternalModuleNameRelative(node.text)) {
|
||||
return getRenameInfoError(Diagnostics.You_cannot_rename_a_module_via_a_global_import);
|
||||
}
|
||||
|
||||
const moduleSourceFile = find(moduleSymbol.declarations, isSourceFile);
|
||||
if (!moduleSourceFile) return undefined;
|
||||
const withoutIndex = node.text.endsWith("/index") || node.text.endsWith("/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index");
|
||||
const name = withoutIndex === undefined ? moduleSourceFile.fileName : withoutIndex;
|
||||
const kind = withoutIndex === undefined ? ScriptElementKind.moduleElement : ScriptElementKind.directory;
|
||||
const indexAfterLastSlash = node.text.lastIndexOf("/") + 1;
|
||||
// Span should only be the last component of the path. + 1 to account for the quote character.
|
||||
const triggerSpan = createTextSpan(node.getStart(sourceFile) + 1 + indexAfterLastSlash, node.text.length - indexAfterLastSlash);
|
||||
return {
|
||||
canRename: true,
|
||||
fileToRename: name,
|
||||
@@ -52,7 +59,7 @@ namespace ts.Rename {
|
||||
localizedErrorMessage: undefined,
|
||||
fullDisplayName: name,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
triggerSpan: createTriggerSpanForNode(node, sourceFile),
|
||||
triggerSpan,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1218,6 +1218,10 @@ namespace ts {
|
||||
getDirectories: path => {
|
||||
return host.getDirectories ? host.getDirectories(path) : [];
|
||||
},
|
||||
readDirectory(path, extensions, exclude, include, depth) {
|
||||
Debug.assertDefined(host.readDirectory, "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'");
|
||||
return host.readDirectory!(path, extensions, exclude, include, depth);
|
||||
},
|
||||
onReleaseOldSourceFile,
|
||||
hasInvalidatedResolution,
|
||||
hasChangedAutomaticTypeDirectiveNames: host.hasChangedAutomaticTypeDirectiveNames
|
||||
|
||||
@@ -781,7 +781,7 @@ namespace ts.textChanges {
|
||||
function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } {
|
||||
const writer = new Writer(newLineCharacter);
|
||||
const newLine = newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed;
|
||||
createPrinter({ newLine }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer);
|
||||
createPrinter({ newLine, neverAsciiEscape: true }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer);
|
||||
return { text: writer.getText(), node: assignPositionsToNode(node) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +244,20 @@ namespace ts {
|
||||
}, [
|
||||
combinePaths(basePath, "main.ts")
|
||||
]);
|
||||
|
||||
it("adds extendedSourceFiles only once", () => {
|
||||
const sourceFile = readJsonConfigFile("configs/fourth.json", (path) => host.readFile(path));
|
||||
const dir = combinePaths(basePath, "configs");
|
||||
const expected = [
|
||||
combinePaths(dir, "third.json"),
|
||||
combinePaths(dir, "second.json"),
|
||||
combinePaths(dir, "base.json"),
|
||||
];
|
||||
parseJsonSourceFileConfigFileContent(sourceFile, host, dir, {}, "fourth.json");
|
||||
assert.deepEqual(sourceFile.extendedSourceFiles, expected);
|
||||
parseJsonSourceFileConfigFileContent(sourceFile, host, dir, {}, "fourth.json");
|
||||
assert.deepEqual(sourceFile.extendedSourceFiles, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -305,10 +305,10 @@ namespace ts {
|
||||
assert.equal(program1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("fails if rootdir changes", () => {
|
||||
it("succeeds if rootdir changes", () => {
|
||||
const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" });
|
||||
updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop);
|
||||
assert.equal(program1.structureIsReused, StructureIsReused.Not);
|
||||
assert.equal(program1.structureIsReused, StructureIsReused.Completely);
|
||||
});
|
||||
|
||||
it("fails if config path changes", () => {
|
||||
|
||||
@@ -34,6 +34,10 @@ namespace ts.tscWatch {
|
||||
return `${projectPath(subProject)}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFileName(subProject: SubProject, baseFileName: string) {
|
||||
return `${projectPath(subProject)}/${baseFileName}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
return {
|
||||
path: projectFilePath(subProject, baseFileName),
|
||||
@@ -94,6 +98,7 @@ namespace ts.tscWatch {
|
||||
const ui = subProjectFiles(SubProject.ui);
|
||||
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
|
||||
const testProjectExpectedWatchedDirectoriesRecursive = [projectPath(SubProject.core), projectPath(SubProject.logic)];
|
||||
|
||||
function createSolutionInWatchMode(allFiles: ReadonlyArray<File>, defaultOptions?: BuildOptions, disableConsoleClears?: boolean) {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
@@ -110,7 +115,7 @@ namespace ts.tscWatch {
|
||||
function verifyWatches(host: WatchedSystem) {
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
checkWatchedDirectories(host, testProjectExpectedWatchedDirectoriesRecursive, /*recursive*/ true);
|
||||
}
|
||||
|
||||
it("creates solution in watch mode", () => {
|
||||
@@ -161,7 +166,7 @@ namespace ts.tscWatch {
|
||||
function verifyWatches() {
|
||||
checkWatchedFiles(host, additionalFiles ? testProjectExpectedWatchedFiles.concat(newFile.path) : testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
checkWatchedDirectories(host, testProjectExpectedWatchedDirectoriesRecursive, /*recursive*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +352,7 @@ function myFunc() { return 100; }`);
|
||||
function verifyWatches() {
|
||||
checkWatchedFiles(host, projectFiles.map(f => f.path));
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
checkWatchedDirectories(host, testProjectExpectedWatchedDirectoriesRecursive, /*recursive*/ true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -389,12 +394,106 @@ let x: string = 10;`);
|
||||
});
|
||||
});
|
||||
|
||||
it("tsc-watch works with project references", () => {
|
||||
// Build the composite project
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
describe("tsc-watch works with project references", () => {
|
||||
const coreIndexDts = projectFileName(SubProject.core, "index.d.ts");
|
||||
const coreAnotherModuleDts = projectFileName(SubProject.core, "anotherModule.d.ts");
|
||||
const logicIndexDts = projectFileName(SubProject.logic, "index.d.ts");
|
||||
const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase()));
|
||||
const expectedWatchedDirectoriesRecursive = projectSystem.getTypeRootsFromLocation(projectPath(SubProject.tests));
|
||||
|
||||
createWatchOfConfigFile(tests[0].path, host);
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
function createSolution() {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
const solutionBuilder = createSolutionBuilder(host, [`${project}/${SubProject.tests}`], {});
|
||||
return { host, solutionBuilder };
|
||||
}
|
||||
|
||||
function createBuiltSolution() {
|
||||
const result = createSolution();
|
||||
const { host, solutionBuilder } = result;
|
||||
solutionBuilder.buildAllProjects();
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function verifyWatches(host: WatchedSystem) {
|
||||
checkWatchedFilesDetailed(host, expectedWatchedFiles, 1);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectoriesRecursive, 1, /*recursive*/ true);
|
||||
}
|
||||
|
||||
function createSolutionAndWatchMode() {
|
||||
// Build the composite project
|
||||
const { host, solutionBuilder } = createBuiltSolution();
|
||||
|
||||
// Build in watch mode
|
||||
const watch = createWatchOfConfigFileReturningBuilder(tests[0].path, host);
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
|
||||
return { host, solutionBuilder, watch };
|
||||
}
|
||||
|
||||
function verifyDependencies(watch: () => BuilderProgram, filePath: string, expected: ReadonlyArray<string>) {
|
||||
checkArray(`${filePath} dependencies`, watch().getAllDependencies(watch().getSourceFile(filePath)!), expected);
|
||||
}
|
||||
|
||||
describe("invoking when references are already built", () => {
|
||||
it("verifies dependencies and watches", () => {
|
||||
const { host, watch } = createSolutionAndWatchMode();
|
||||
|
||||
verifyWatches(host);
|
||||
verifyDependencies(watch, coreIndexDts, [coreIndexDts]);
|
||||
verifyDependencies(watch, coreAnotherModuleDts, [coreAnotherModuleDts]);
|
||||
verifyDependencies(watch, logicIndexDts, [logicIndexDts, coreAnotherModuleDts]);
|
||||
verifyDependencies(watch, tests[1].path, [tests[1].path, coreAnotherModuleDts, logicIndexDts, coreAnotherModuleDts]);
|
||||
});
|
||||
|
||||
it("local edit in ts file, result in watch compilation because logic.d.ts is written", () => {
|
||||
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
|
||||
host.writeFile(logic[1].path, `${logic[1].content}
|
||||
function foo() {
|
||||
}`);
|
||||
solutionBuilder.invalidateProject(`${project}/${SubProject.logic}`);
|
||||
solutionBuilder.buildInvalidatedProject();
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // not ideal, but currently because of d.ts but no new file is written
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
|
||||
});
|
||||
|
||||
it("non local edit in ts file, rebuilds in watch compilation", () => {
|
||||
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
|
||||
host.writeFile(logic[1].path, `${logic[1].content}
|
||||
export function gfoo() {
|
||||
}`);
|
||||
solutionBuilder.invalidateProject(logic[0].path);
|
||||
solutionBuilder.buildInvalidatedProject();
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
|
||||
});
|
||||
|
||||
it("change in project reference config file builds correctly", () => {
|
||||
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
|
||||
host.writeFile(logic[0].path, JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, declarationDir: "decls" },
|
||||
references: [{ path: "../core" }]
|
||||
}));
|
||||
solutionBuilder.invalidateProject(logic[0].path, ConfigFileProgramReloadLevel.Full);
|
||||
solutionBuilder.buildInvalidatedProject();
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
// TODO: #26036
|
||||
// The error is reported in d.ts file because it isnt resolved from ts file path, but is resolved from .d.ts file
|
||||
"sample1/logic/decls/index.d.ts(2,22): error TS2307: Cannot find module '../core/anotherModule'.\n"
|
||||
]);
|
||||
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@ namespace ts.tscWatch {
|
||||
checkArray(`Program rootFileNames`, program.getRootFileNames(), expectedFiles);
|
||||
}
|
||||
|
||||
export function createWatchOfConfigFileReturningBuilder(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
|
||||
const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, {}, host);
|
||||
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
|
||||
const watch = createWatchProgram(compilerHost);
|
||||
return () => watch.getCurrentProgram();
|
||||
}
|
||||
|
||||
export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
|
||||
const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, {}, host);
|
||||
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
|
||||
@@ -443,6 +450,33 @@ namespace ts.tscWatch {
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
it("Updates diagnostics when '--noUnusedLabels' changes", () => {
|
||||
const aTs: File = { path: "/a.ts", content: "label: while (1) {}" };
|
||||
const files = [libFile, aTs];
|
||||
const paths = files.map(f => f.path);
|
||||
const options = (allowUnusedLabels: boolean) => `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`;
|
||||
const tsconfig: File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) };
|
||||
|
||||
const host = createWatchedSystem([...files, tsconfig]);
|
||||
const watch = createWatchOfConfigFile(tsconfig.path, host);
|
||||
|
||||
checkProgramActualFiles(watch(), paths);
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
|
||||
host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ false));
|
||||
host.checkTimeoutQueueLengthAndRun(1); // reload the configured project
|
||||
|
||||
checkProgramActualFiles(watch(), paths);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
getDiagnosticOfFileFromProgram(watch(), aTs.path, 0, "label".length, Diagnostics.Unused_label),
|
||||
]);
|
||||
|
||||
host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ true));
|
||||
host.checkTimeoutQueueLengthAndRun(1); // reload the configured project
|
||||
checkProgramActualFiles(watch(), paths);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
it("files explicitly excluded in config file", () => {
|
||||
const configFile: File = {
|
||||
path: "/a/b/tsconfig.json",
|
||||
@@ -1190,7 +1224,7 @@ namespace ts.tscWatch {
|
||||
host.reloadFS(files);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
checkProgramActualFiles(watch(), files.map(file => file.path));
|
||||
checkOutputErrorsIncremental(host, []);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
});
|
||||
|
||||
it("watched files when file is deleted and new file is added as part of change", () => {
|
||||
@@ -1322,12 +1356,10 @@ export class B
|
||||
path: `${currentDirectory}/a.ts`,
|
||||
content: `declare function foo(): null | { hello: any };
|
||||
foo().hello`
|
||||
};
|
||||
const compilerOptions: CompilerOptions = {
|
||||
};
|
||||
const config: File = {
|
||||
path: `${currentDirectory}/tsconfig.json`,
|
||||
content: JSON.stringify({ compilerOptions })
|
||||
content: JSON.stringify({ compilerOptions: {} })
|
||||
};
|
||||
const files = [aFile, config, libFile];
|
||||
const host = createWatchedSystem(files, { currentDirectory });
|
||||
@@ -1335,8 +1367,7 @@ foo().hello`
|
||||
checkProgramActualFiles(watch(), [aFile.path, libFile.path]);
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
const modifiedTimeOfAJs = host.getModifiedTime(`${currentDirectory}/a.js`);
|
||||
compilerOptions.strictNullChecks = true;
|
||||
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
|
||||
host.writeFile(config.path, JSON.stringify({ compilerOptions: { strictNullChecks: true } }));
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
const expectedStrictNullErrors = [
|
||||
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.lastIndexOf("foo()"), 5, Diagnostics.Object_is_possibly_null)
|
||||
@@ -1344,15 +1375,12 @@ foo().hello`
|
||||
checkOutputErrorsIncremental(host, expectedStrictNullErrors);
|
||||
// File a need not be rewritten
|
||||
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
|
||||
compilerOptions.strict = true;
|
||||
delete (compilerOptions.strictNullChecks);
|
||||
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
|
||||
host.writeFile(config.path, JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } })); // Avoid changing 'alwaysStrict' or must re-bind
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
checkOutputErrorsIncremental(host, expectedStrictNullErrors);
|
||||
// File a need not be rewritten
|
||||
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
|
||||
delete (compilerOptions.strict);
|
||||
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
|
||||
host.writeFile(config.path, JSON.stringify({ compilerOptions: {} }));
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
// File a need not be rewritten
|
||||
|
||||
@@ -456,7 +456,7 @@ namespace ts.projectSystem {
|
||||
function protocolFileLocationFromSubstring(file: File, substring: string): protocol.FileLocationRequestArgs {
|
||||
return { file: file.path, ...protocolLocationFromSubstring(file.content, substring) };
|
||||
}
|
||||
function protocolFileSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions) {
|
||||
function protocolFileSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): protocol.FileSpan {
|
||||
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, substring, options) };
|
||||
}
|
||||
function documentSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): DocumentSpan {
|
||||
@@ -3491,7 +3491,7 @@ namespace ts.projectSystem {
|
||||
host.checkTimeoutQueueLength(2); // Update configured project and projects for open file
|
||||
checkProjectActualFiles(services.configuredProjects.get(config.path)!, filesWithFileA.map(f => f.path));
|
||||
|
||||
// host.fileExists = originalFileExists;
|
||||
// host.fileExists = originalFileExists;
|
||||
openFile(fileSubA);
|
||||
// This should create inferred project since fileSubA not on the disk
|
||||
checkProjectActualFiles(services.configuredProjects.get(config.path)!, mapDefined(filesWithFileA, f => f === fileA ? undefined : f.path));
|
||||
@@ -3672,7 +3672,7 @@ namespace ts.projectSystem {
|
||||
path: `${projectRoot}/app1/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
files: ["app.ts", "../core/core.ts"],
|
||||
compilerOptions: { outFile : "build/output.js" },
|
||||
compilerOptions: { outFile: "build/output.js" },
|
||||
compileOnSave: true
|
||||
})
|
||||
};
|
||||
@@ -6778,9 +6778,9 @@ namespace ts.projectSystem {
|
||||
fileName: "/a.1.ts",
|
||||
textChanges: [
|
||||
{
|
||||
start: { line: 0, offset: 0 },
|
||||
end: { line: 0, offset: 0 },
|
||||
newText: "export const a = 0;",
|
||||
start: { line: 0, offset: 0 },
|
||||
end: { line: 0, offset: 0 },
|
||||
newText: "export const a = 0;",
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -8287,7 +8287,8 @@ namespace ts.projectSystem {
|
||||
protocolTextSpanFromSubstring(aFile.content, "C"),
|
||||
protocolTextSpanFromSubstring(aFile.content, "C", { index: 1 }),
|
||||
];
|
||||
const cLocs: protocol.TextSpan[] = [protocolTextSpanFromSubstring(cFile.content, "C")];
|
||||
const span = protocolTextSpanFromSubstring(cFile.content, "C");
|
||||
const cLocs: protocol.TextSpan[] = [span];
|
||||
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
|
||||
info: {
|
||||
canRename: true,
|
||||
@@ -8296,6 +8297,7 @@ namespace ts.projectSystem {
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
localizedErrorMessage: undefined,
|
||||
triggerSpan: span,
|
||||
},
|
||||
locs: [
|
||||
{ file: aFc, locs: cLocs },
|
||||
@@ -8672,7 +8674,7 @@ new C();`
|
||||
}));
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
checkWatchedDirectories(host, arrayFrom(expectedRecursiveDirectories.keys()), /*recursive*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
describe("from files in same folder", () => {
|
||||
function getFiles(fileContent: string) {
|
||||
@@ -9750,7 +9752,7 @@ declare class TestLib {
|
||||
function verifyATsConfigOriginalProject(session: TestSession) {
|
||||
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
|
||||
verifyInferredProjectUnchanged(session);
|
||||
verifyATsConfigProject(session);
|
||||
verifyATsConfigProject(session);
|
||||
// Close user file should close all the projects
|
||||
closeFilesForSession([userTs], session);
|
||||
verifyOnlyOrphanInferredProject(session);
|
||||
@@ -9900,11 +9902,12 @@ declare class TestLib {
|
||||
verifyATsConfigWhenOpened(session);
|
||||
});
|
||||
|
||||
interface ReferencesFullRequest extends protocol.FileLocationRequest { readonly command: protocol.CommandTypes.ReferencesFull; }
|
||||
interface ReferencesFullResponse extends protocol.Response { readonly body: ReadonlyArray<ReferencedSymbol>; }
|
||||
|
||||
it("findAllReferencesFull", () => {
|
||||
const session = makeSampleProjects();
|
||||
|
||||
interface ReferencesFullRequest extends protocol.FileLocationRequest { command: protocol.CommandTypes.ReferencesFull; }
|
||||
interface ReferencesFullResponse extends protocol.Response { body: ReadonlyArray<ReferencedSymbol>; }
|
||||
const responseFull = executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
|
||||
|
||||
function fnAVoid(kind: SymbolDisplayPartKind): SymbolDisplayPart[] {
|
||||
@@ -9961,6 +9964,67 @@ declare class TestLib {
|
||||
verifyATsConfigOriginalProject(session);
|
||||
});
|
||||
|
||||
it("findAllReferencesFull definition is in mapped file", () => {
|
||||
const aTs: File = { path: "/a/a.ts", content: `function f() {}` };
|
||||
const aTsconfig: File = {
|
||||
path: "/a/tsconfig.json",
|
||||
content: JSON.stringify({ compilerOptions: { declaration: true, declarationMap: true, outFile: "../bin/a.js" } }),
|
||||
};
|
||||
const bTs: File = { path: "/b/b.ts", content: `f();` };
|
||||
const bTsconfig: File = { path: "/b/tsconfig.json", content: JSON.stringify({ references: [{ path: "../a" }] }) };
|
||||
const aDts: File = { path: "/bin/a.d.ts", content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map` };
|
||||
const aDtsMap: File = {
|
||||
path: "/bin/a.d.ts.map",
|
||||
content: JSON.stringify({ version: 3, file: "a.d.ts", sourceRoot: "", sources: ["../a/a.ts"], names: [], mappings: "AAAA,iBAAS,CAAC,SAAK" }),
|
||||
};
|
||||
|
||||
const session = createSession(createServerHost([aTs, aTsconfig, bTs, bTsconfig, aDts, aDtsMap]));
|
||||
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
|
||||
openFilesForSession([bTs], session);
|
||||
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
|
||||
|
||||
const responseFull = executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(bTs, "f()"));
|
||||
|
||||
assert.deepEqual<ReadonlyArray<ReferencedSymbol>>(responseFull, [
|
||||
{
|
||||
definition: {
|
||||
containerKind: ScriptElementKind.unknown,
|
||||
containerName: "",
|
||||
displayParts: [
|
||||
keywordPart(SyntaxKind.FunctionKeyword),
|
||||
spacePart(),
|
||||
displayPart("f", SymbolDisplayPartKind.functionName),
|
||||
punctuationPart(SyntaxKind.OpenParenToken),
|
||||
punctuationPart(SyntaxKind.CloseParenToken),
|
||||
punctuationPart(SyntaxKind.ColonToken),
|
||||
spacePart(),
|
||||
keywordPart(SyntaxKind.VoidKeyword),
|
||||
],
|
||||
fileName: aTs.path,
|
||||
kind: ScriptElementKind.functionElement,
|
||||
name: "function f(): void",
|
||||
textSpan: { start: 9, length: 1 },
|
||||
},
|
||||
references: [
|
||||
{
|
||||
fileName: bTs.path,
|
||||
isDefinition: false,
|
||||
isInString: undefined,
|
||||
isWriteAccess: false,
|
||||
textSpan: { start: 0, length: 1 },
|
||||
},
|
||||
{
|
||||
fileName: aTs.path,
|
||||
isDefinition: true,
|
||||
isInString: undefined,
|
||||
isWriteAccess: true,
|
||||
textSpan: { start: 9, length: 1 },
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("findAllReferences -- target does not exist", () => {
|
||||
const session = makeSampleProjects();
|
||||
|
||||
@@ -10001,6 +10065,7 @@ declare class TestLib {
|
||||
kind: ScriptElementKind.alias,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
localizedErrorMessage: undefined,
|
||||
triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
|
||||
},
|
||||
locs: [renameUserTs(userTs), renameATs(aTs)],
|
||||
});
|
||||
@@ -10019,6 +10084,7 @@ declare class TestLib {
|
||||
kind: ScriptElementKind.functionElement,
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
localizedErrorMessage: undefined,
|
||||
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "fnA"),
|
||||
},
|
||||
locs: [renameATs(aTs), renameUserTs(userTs)],
|
||||
});
|
||||
@@ -10047,6 +10113,7 @@ declare class TestLib {
|
||||
kind: ScriptElementKind.alias,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
localizedErrorMessage: undefined,
|
||||
triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnB", { index: 1 }),
|
||||
},
|
||||
locs: [
|
||||
{
|
||||
@@ -10180,6 +10247,35 @@ declare class TestLib {
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsserverProjectSystem config file change", () => {
|
||||
it("Updates diagnostics when '--noUnusedLabels' changes", () => {
|
||||
const aTs: File = { path: "/a.ts", content: "label: while (1) {}" };
|
||||
const options = (allowUnusedLabels: boolean) => `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`;
|
||||
const tsconfig: File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) };
|
||||
|
||||
const host = createServerHost([aTs, tsconfig]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ false));
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
const response = executeSessionRequest<protocol.SemanticDiagnosticsSyncRequest, protocol.SemanticDiagnosticsSyncResponse>(session, protocol.CommandTypes.SemanticDiagnosticsSync, { file: aTs.path }) as protocol.Diagnostic[] | undefined;
|
||||
assert.deepEqual<protocol.Diagnostic[] | undefined>(response, [
|
||||
{
|
||||
start: { line: 1, offset: 1 },
|
||||
end: { line: 1, offset: 1 + "label".length },
|
||||
text: "Unused label.",
|
||||
category: "error",
|
||||
code: Diagnostics.Unused_label.code,
|
||||
relatedInformation: undefined,
|
||||
reportsUnnecessary: true,
|
||||
source: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
function makeReferenceItem(file: File, isDefinition: boolean, text: string, lineText: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
|
||||
return {
|
||||
...protocolFileSpanFromSubstring(file, text, options),
|
||||
|
||||
Reference in New Issue
Block a user