Merge branch 'master' into saferIndexedAccessTypes

This commit is contained in:
Anders Hejlsberg
2019-04-05 16:23:48 -10:00
272 changed files with 3313 additions and 1079 deletions
+1 -2
View File
@@ -2710,8 +2710,7 @@ namespace ts {
}
else {
const s = forEachIdentifierInEntityName(e.expression, parent, action);
if (!s || !s.exports) return Debug.fail();
return action(e.name, s.exports.get(e.name.escapedText), s);
return action(e.name, s && s.exports && s.exports.get(e.name.escapedText), s);
}
}
+3 -3
View File
@@ -792,7 +792,7 @@ namespace ts {
state,
// When whole program is affected, do emit only once (eg when --out or --outFile is specified)
// Otherwise just affected file
affected.emitBuildInfo(writeFile || host.writeFile, cancellationToken),
affected.emitBuildInfo(writeFile || maybeBind(host, host.writeFile), cancellationToken),
affected,
/*isPendingEmitFile*/ false,
/*isBuildInfoEmit*/ true
@@ -820,7 +820,7 @@ namespace ts {
state,
// When whole program is affected, do emit only once (eg when --out or --outFile is specified)
// Otherwise just affected file
Debug.assertDefined(state.program).emit(affected === state.program ? undefined : affected as SourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers),
Debug.assertDefined(state.program).emit(affected === state.program ? undefined : affected as SourceFile, writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers),
affected,
isPendingEmitFile
);
@@ -862,7 +862,7 @@ namespace ts {
};
}
}
return Debug.assertDefined(state.program).emit(targetSourceFile, writeFile || host.writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
return Debug.assertDefined(state.program).emit(targetSourceFile, writeFile || maybeBind(host, host.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers);
}
/**
+79 -25
View File
@@ -392,6 +392,7 @@ namespace ts {
const literalTypes = createMap<LiteralType>();
const indexedAccessTypes = createMap<IndexedAccessType>();
const conditionalTypes = createMap<Type>();
const substitutionTypes = createMap<SubstitutionType>();
const evolvingArrayTypes: EvolvingArrayType[] = [];
const undefinedProperties = createMap<Symbol>() as UnderscoreEscapedMap<Symbol>;
@@ -1137,6 +1138,10 @@ namespace ts {
// still might be illegal if the usage is within a computed property name in the class (eg class A { static p = "a"; [A.p]() {} })
return !findAncestor(usage, n => isComputedPropertyName(n) && n.parent.parent === declaration);
}
else if (isPropertyDeclaration(declaration)) {
// still might be illegal if a self-referencing property initializer (eg private x = this.x)
return !isPropertyImmediatelyReferencedWithinDeclaration(declaration, usage);
}
return true;
}
@@ -1211,6 +1216,40 @@ namespace ts {
return false;
});
}
function isPropertyImmediatelyReferencedWithinDeclaration(declaration: PropertyDeclaration, usage: Node) {
// always legal if usage is after declaration
if (usage.end > declaration.end) {
return false;
}
// still might be legal if usage is deferred (e.g. x: any = () => this.x)
// otherwise illegal if immediately referenced within the declaration (e.g. x: any = this.x)
const ancestorChangingReferenceScope = findAncestor(usage, (node: Node) => {
if (node === declaration) {
return "quit";
}
switch (node.kind) {
case SyntaxKind.ArrowFunction:
case SyntaxKind.PropertyDeclaration:
return true;
case SyntaxKind.Block:
switch (node.parent.kind) {
case SyntaxKind.GetAccessor:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.SetAccessor:
return true;
default:
return false;
}
default:
return false;
}
});
return ancestorChangingReferenceScope === undefined;
}
}
/**
@@ -7339,7 +7378,7 @@ namespace ts {
const declaredType = <MappedType>getTypeFromMappedTypeNode(type.declaration);
const constraint = getConstraintTypeFromMappedType(declaredType);
const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>constraint) : constraint;
type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((<IndexType>extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType;
type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((<IndexType>extendedConstraint).type, type.mapper || identityMapper) : unknownType;
}
}
return type.modifiersType;
@@ -7785,7 +7824,7 @@ namespace ts {
* type itself. Note that the apparent type of a union type is the union type itself.
*/
function getApparentType(type: Type): Type {
const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || emptyObjectType : type;
const t = type.flags & TypeFlags.Instantiable ? getBaseConstraintOfType(type) || unknownType : type;
return getObjectFlags(t) & ObjectFlags.Mapped ? getApparentTypeOfMappedType(<MappedType>t) :
t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
t.flags & TypeFlags.StringLike ? globalStringType :
@@ -7795,6 +7834,7 @@ namespace ts {
t.flags & TypeFlags.ESSymbolLike ? getGlobalESSymbolType(/*reportErrors*/ languageVersion >= ScriptTarget.ES2015) :
t.flags & TypeFlags.NonPrimitive ? emptyObjectType :
t.flags & TypeFlags.Index ? keyofConstraintType :
t.flags & TypeFlags.Unknown && !strictNullChecks ? emptyObjectType :
t;
}
@@ -8118,7 +8158,7 @@ namespace ts {
const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
for (let i = numTypeArguments; i < numTypeParameters; i++) {
let defaultType = getDefaultFromTypeParameter(typeParameters![i]);
if (isJavaScriptImplicitAny && defaultType && isTypeIdenticalTo(defaultType, emptyObjectType)) {
if (isJavaScriptImplicitAny && defaultType && (isTypeIdenticalTo(defaultType, unknownType) || isTypeIdenticalTo(defaultType, emptyObjectType))) {
defaultType = anyType;
}
result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) : baseDefaultType;
@@ -8497,7 +8537,7 @@ namespace ts {
const typeParameters = signature.typeParameters;
if (typeParameters) {
const typeEraser = createTypeEraser(typeParameters);
const baseConstraints = map(typeParameters, tp => instantiateType(getBaseConstraintOfType(tp), typeEraser) || emptyObjectType);
const baseConstraints = map(typeParameters, tp => instantiateType(getBaseConstraintOfType(tp), typeEraser) || unknownType);
return instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true);
}
return signature;
@@ -8887,9 +8927,15 @@ namespace ts {
if (substitute.flags & TypeFlags.AnyOrUnknown) {
return typeVariable;
}
const id = `${getTypeId(typeVariable)}>${getTypeId(substitute)}`;
const cached = substitutionTypes.get(id);
if (cached) {
return cached;
}
const result = <SubstitutionType>createType(TypeFlags.Substitution);
result.typeVariable = typeVariable;
result.substitute = substitute;
substitutionTypes.set(id, result);
return result;
}
@@ -10839,7 +10885,7 @@ namespace ts {
* This is used during inference when instantiating type parameter defaults.
*/
function createBackreferenceMapper(context: InferenceContext, index: number): TypeMapper {
return t => findIndex(context.inferences, info => info.typeParameter === t) >= index ? emptyObjectType : t;
return t => findIndex(context.inferences, info => info.typeParameter === t) >= index ? unknownType : t;
}
function combineTypeMappers(mapper1: TypeMapper | undefined, mapper2: TypeMapper): TypeMapper;
@@ -11386,7 +11432,7 @@ namespace ts {
function isTypeDerivedFrom(source: Type, target: Type): boolean {
return source.flags & TypeFlags.Union ? every((<UnionType>source).types, t => isTypeDerivedFrom(t, target)) :
target.flags & TypeFlags.Union ? some((<UnionType>target).types, t => isTypeDerivedFrom(source, t)) :
source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || emptyObjectType, target) :
source.flags & TypeFlags.InstantiableNonPrimitive ? isTypeDerivedFrom(getBaseConstraintOfType(source) || unknownType, target) :
target === globalObjectType ? !!(source.flags & (TypeFlags.Object | TypeFlags.NonPrimitive)) :
target === globalFunctionType ? !!(source.flags & TypeFlags.Object) && isFunctionObjectType(source as ObjectType) :
hasBaseType(source, getTargetType(target));
@@ -13404,7 +13450,7 @@ namespace ts {
return indexTypesIdenticalTo(source, target, kind);
}
const targetInfo = getIndexInfoOfType(target, kind);
if (!targetInfo || targetInfo.type.flags & TypeFlags.AnyOrUnknown && !sourceIsPrimitive) {
if (!targetInfo || targetInfo.type.flags & TypeFlags.Any && !sourceIsPrimitive) {
// Index signature of type any permits assignment from everything but primitives
return Ternary.True;
}
@@ -14555,7 +14601,7 @@ namespace ts {
const templateType = getTemplateTypeFromMappedType(target);
const inference = createInferenceInfo(typeParameter);
inferTypes([inference], sourceType, templateType);
return getTypeFromInference(inference) || emptyObjectType;
return getTypeFromInference(inference) || unknownType;
}
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean) {
@@ -15154,7 +15200,7 @@ namespace ts {
}
function getDefaultTypeArgumentType(isInJavaScriptFile: boolean): Type {
return isInJavaScriptFile ? anyType : emptyObjectType;
return isInJavaScriptFile ? anyType : unknownType;
}
function getInferredTypes(context: InferenceContext): Type[] {
@@ -15498,7 +15544,7 @@ namespace ts {
return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
}
if (flags & TypeFlags.Instantiable) {
return getTypeFacts(getBaseConstraintOfType(type) || emptyObjectType);
return getTypeFacts(getBaseConstraintOfType(type) || unknownType);
}
if (flags & TypeFlags.UnionOrIntersection) {
return getTypeFactsOfTypes((<UnionOrIntersectionType>type).types);
@@ -16804,7 +16850,7 @@ namespace ts {
}
function typeHasNullableConstraint(type: Type) {
return type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable);
return type.flags & TypeFlags.InstantiableNonPrimitive && maybeTypeOfKind(getBaseConstraintOfType(type) || unknownType, TypeFlags.Nullable);
}
function getConstraintForLocation(type: Type, node: Node): Type;
@@ -18254,7 +18300,7 @@ namespace ts {
}
function getJsxPropsTypeFromCallSignature(sig: Signature, context: JsxOpeningLikeElement) {
let propsType = getTypeOfFirstParameterOfSignatureWithFallback(sig, emptyObjectType);
let propsType = getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType);
propsType = getJsxManagedAttributesFromLocatedAttributes(context, getJsxNamespaceAt(context), propsType);
const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context);
if (intrinsicAttribs !== errorType) {
@@ -18328,7 +18374,7 @@ namespace ts {
const forcedLookupLocation = getJsxElementPropertiesName(ns);
let attributesType = forcedLookupLocation === undefined
// If there is no type ElementAttributesProperty, return the type of the first parameter of the signature, which should be the props type
? getTypeOfFirstParameterOfSignatureWithFallback(sig, emptyObjectType)
? getTypeOfFirstParameterOfSignatureWithFallback(sig, unknownType)
: forcedLookupLocation === ""
// If there is no e.g. 'props' member in ElementAttributesProperty, use the element class type instead
? getReturnTypeOfSignature(sig)
@@ -18340,7 +18386,7 @@ namespace ts {
if (!!forcedLookupLocation && !!length(context.attributes.properties)) {
error(context, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(forcedLookupLocation));
}
return emptyObjectType;
return unknownType;
}
attributesType = getJsxManagedAttributesFromLocatedAttributes(context, ns, attributesType);
@@ -19551,7 +19597,7 @@ namespace ts {
undefinedDiagnostic?: DiagnosticMessage,
nullOrUndefinedDiagnostic?: DiagnosticMessage
): Type {
if (type.flags & TypeFlags.Unknown) {
if (strictNullChecks && type.flags & TypeFlags.Unknown) {
error(node, Diagnostics.Object_is_of_type_unknown);
return errorType;
}
@@ -19568,6 +19614,14 @@ namespace ts {
return type;
}
function checkNonNullNonVoidType(type: Type, node: Node): Type {
const nonNullType = checkNonNullType(type, node);
if (nonNullType !== errorType && nonNullType.flags & TypeFlags.Void) {
error(node, Diagnostics.Object_is_possibly_undefined);
}
return nonNullType;
}
function checkPropertyAccessExpression(node: PropertyAccessExpression) {
return checkPropertyAccessExpressionOrQualifiedName(node, node.expression, node.name);
}
@@ -22047,7 +22101,7 @@ namespace ts {
const decl = parameter.valueDeclaration as ParameterDeclaration;
if (decl.name.kind !== SyntaxKind.Identifier) {
// if inference didn't come up with anything but {}, fall back to the binding pattern if present.
if (links.type === emptyObjectType) {
if (links.type === unknownType) {
links.type = getTypeFromBindingPattern(decl.name);
}
assignBindingElementTypes(decl.name);
@@ -22060,11 +22114,11 @@ namespace ts {
const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true);
if (globalPromiseType !== emptyGenericType) {
// if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type
promisedType = getAwaitedType(promisedType) || emptyObjectType;
promisedType = getAwaitedType(promisedType) || unknownType;
return createTypeReference(globalPromiseType, [promisedType]);
}
return emptyObjectType;
return unknownType;
}
function createPromiseLikeType(promisedType: Type): Type {
@@ -22072,16 +22126,16 @@ namespace ts {
const globalPromiseLikeType = getGlobalPromiseLikeType(/*reportErrors*/ true);
if (globalPromiseLikeType !== emptyGenericType) {
// if the promised type is itself a promise, get the underlying type; otherwise, fallback to the promised type
promisedType = getAwaitedType(promisedType) || emptyObjectType;
promisedType = getAwaitedType(promisedType) || unknownType;
return createTypeReference(globalPromiseLikeType, [promisedType]);
}
return emptyObjectType;
return unknownType;
}
function createPromiseReturnType(func: FunctionLikeDeclaration | ImportCall, promisedType: Type) {
const promiseType = createPromiseType(promisedType);
if (promiseType === emptyObjectType) {
if (promiseType === unknownType) {
error(func, isImportCall(func) ?
Diagnostics.A_dynamic_import_call_returns_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option :
Diagnostics.An_async_function_or_method_must_return_a_Promise_Make_sure_you_have_a_declaration_for_Promise_or_include_ES2015_in_your_lib_option);
@@ -23514,7 +23568,7 @@ namespace ts {
// If the contextual type is a type variable constrained to a primitive type, consider
// this a literal context for literals of that primitive type. For example, given a
// type parameter 'T extends string', infer string literal types for T.
const constraint = getBaseConstraintOfType(contextualType) || emptyObjectType;
const constraint = getBaseConstraintOfType(contextualType) || unknownType;
return maybeTypeOfKind(constraint, TypeFlags.String) && maybeTypeOfKind(candidateType, TypeFlags.StringLiteral) ||
maybeTypeOfKind(constraint, TypeFlags.Number) && maybeTypeOfKind(candidateType, TypeFlags.NumberLiteral) ||
maybeTypeOfKind(constraint, TypeFlags.BigInt) && maybeTypeOfKind(candidateType, TypeFlags.BigIntLiteral) ||
@@ -26313,7 +26367,7 @@ namespace ts {
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
const initializerType = checkExpressionCached(node.initializer);
if (strictNullChecks && node.name.elements.length === 0) {
checkNonNullType(initializerType, node);
checkNonNullNonVoidType(initializerType, node);
}
else {
checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer);
@@ -30354,7 +30408,7 @@ namespace ts {
autoArrayType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
}
globalReadonlyArrayType = <GenericType>getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1);
globalReadonlyArrayType = <GenericType>getGlobalTypeOrUndefined("ReadonlyArray" as __String, /*arity*/ 1) || globalArrayType;
anyReadonlyArrayType = globalReadonlyArrayType ? createTypeFromGenericGlobalType(globalReadonlyArrayType, [anyType]) : anyArrayType;
globalThisType = <GenericType>getGlobalTypeOrUndefined("ThisType" as __String, /*arity*/ 1);
@@ -31509,7 +31563,7 @@ namespace ts {
}
if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || node.flags & NodeFlags.Ambient)) {
return grammarErrorOnNode(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context);
return grammarErrorOnNode(node.exclamationToken, Diagnostics.Definite_assignment_assertions_can_only_be_used_along_with_a_type_annotation);
}
if (compilerOptions.module !== ModuleKind.ES2015 && compilerOptions.module !== ModuleKind.ESNext && compilerOptions.module !== ModuleKind.System && !compilerOptions.noEmit &&
+7 -8
View File
@@ -136,6 +136,13 @@ namespace ts {
category: Diagnostics.Advanced_Options,
description: Diagnostics.Show_verbose_diagnostic_information
},
{
name: "incremental",
shortName: "i",
type: "boolean",
category: Diagnostics.Basic_Options,
description: Diagnostics.Enable_incremental_compilation,
},
];
/* @internal */
@@ -331,19 +338,11 @@ namespace ts {
category: Diagnostics.Basic_Options,
description: Diagnostics.Enable_project_compilation,
},
{
name: "incremental",
type: "boolean",
isTSConfigOnly: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Enable_incremental_compilation,
},
{
name: "tsBuildInfoFile",
type: "string",
isFilePath: true,
paramType: Diagnostics.FILE,
isTSConfigOnly: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Specify_file_to_store_incremental_compilation_information,
},
+1 -1
View File
@@ -1,7 +1,7 @@
namespace ts {
// WARNING: The script `configureNightly.ts` uses a regexp to parse out these values.
// If changing the text in this section, be sure to test `configureNightly` too.
export const versionMajorMinor = "3.4";
export const versionMajorMinor = "3.5";
/** The version of the TypeScript compiler release */
export const version = `${versionMajorMinor}.0-dev`;
}
+8
View File
@@ -847,6 +847,10 @@
"category": "Error",
"code": 1257
},
"Definite assignment assertions can only be used along with a type annotation.": {
"category": "Error",
"code": 1258
},
"'with' statements are not allowed in an async function block.": {
"category": "Error",
"code": 1300
@@ -3072,6 +3076,10 @@
"category": "Error",
"code": 5073
},
"Option '--incremental' can only be specified using tsconfig, emitting to single file or when option `--tsBuildInfoFile` is specified.": {
"category": "Error",
"code": 5074
},
"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
+2 -1
View File
@@ -54,7 +54,7 @@ namespace ts {
/*@internal*/
export function getOutputPathForBuildInfo(options: CompilerOptions) {
const configFile = options.configFilePath;
if (!configFile || !isIncrementalCompilation(options)) return undefined;
if (!isIncrementalCompilation(options)) return undefined;
if (options.tsBuildInfoFile) return options.tsBuildInfoFile;
const outPath = options.outFile || options.out;
let buildInfoExtensionLess: string;
@@ -62,6 +62,7 @@ namespace ts {
buildInfoExtensionLess = removeFileExtension(outPath);
}
else {
if (!configFile) return undefined;
const configFileExtensionLess = removeFileExtension(configFile);
buildInfoExtensionLess = options.outDir ?
options.rootDir ?
+18 -17
View File
@@ -3693,9 +3693,11 @@ namespace ts {
// - "(x = 10)" is an assignment expression parsed as a signature with a default parameter value.
// - "(x,y)" is a comma expression parsed as a signature with two parameters.
// - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
// - "a ? (b): function() {}" will too, since function() is a valid JSDoc function type.
//
// So we need just a bit of lookahead to ensure that it can only be a signature.
if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) {
const hasJSDocFunctionType = node.type && isJSDocFunctionType(node.type);
if (!allowAmbiguity && token() !== SyntaxKind.EqualsGreaterThanToken && (hasJSDocFunctionType || token() !== SyntaxKind.OpenBraceToken)) {
// Returning undefined here will cause our caller to rewind to where we started from.
return undefined;
}
@@ -7749,17 +7751,17 @@ namespace ts {
context.pragmas = createMap() as PragmaMap;
for (const pragma of pragmas) {
if (context.pragmas.has(pragma!.name)) { // TODO: GH#18217
const currentValue = context.pragmas.get(pragma!.name);
if (context.pragmas.has(pragma.name)) {
const currentValue = context.pragmas.get(pragma.name);
if (currentValue instanceof Array) {
currentValue.push(pragma!.args);
currentValue.push(pragma.args);
}
else {
context.pragmas.set(pragma!.name, [currentValue, pragma!.args]);
context.pragmas.set(pragma.name, [currentValue, pragma.args]);
}
continue;
}
context.pragmas.set(pragma!.name, pragma!.args);
context.pragmas.set(pragma.name, pragma.args);
}
}
@@ -7783,9 +7785,8 @@ namespace ts {
const typeReferenceDirectives = context.typeReferenceDirectives;
const libReferenceDirectives = context.libReferenceDirectives;
forEach(toArray(entryOrList), (arg: PragmaPseudoMap["reference"]) => {
// TODO: GH#18217
const { types, lib, path } = arg!.arguments;
if (arg!.arguments["no-default-lib"]) {
const { types, lib, path } = arg.arguments;
if (arg.arguments["no-default-lib"]) {
context.hasNoDefaultLib = true;
}
else if (types) {
@@ -7798,7 +7799,7 @@ namespace ts {
referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value });
}
else {
reportDiagnostic(arg!.range.pos, arg!.range.end - arg!.range.pos, Diagnostics.Invalid_reference_directive_syntax);
reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax);
}
});
break;
@@ -7806,7 +7807,7 @@ namespace ts {
case "amd-dependency": {
context.amdDependencies = map(
toArray(entryOrList),
(x: PragmaPseudoMap["amd-dependency"]) => ({ name: x!.arguments.name!, path: x!.arguments.path })); // TODO: GH#18217
(x: PragmaPseudoMap["amd-dependency"]) => ({ name: x.arguments.name, path: x.arguments.path }));
break;
}
case "amd-module": {
@@ -7814,13 +7815,13 @@ namespace ts {
for (const entry of entryOrList) {
if (context.moduleName) {
// TODO: It's probably fine to issue this diagnostic on all instances of the pragma
reportDiagnostic(entry!.range.pos, entry!.range.end - entry!.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
}
context.moduleName = (entry as PragmaPseudoMap["amd-module"])!.arguments.name;
context.moduleName = (entry as PragmaPseudoMap["amd-module"]).arguments.name;
}
}
else {
context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"])!.arguments.name;
context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"]).arguments.name;
}
break;
}
@@ -7828,11 +7829,11 @@ namespace ts {
case "ts-check": {
// _last_ of either nocheck or check in a file is the "winner"
forEach(toArray(entryOrList), entry => {
if (!context.checkJsDirective || entry!.range.pos > context.checkJsDirective.pos) { // TODO: GH#18217
if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) {
context.checkJsDirective = {
enabled: key === "ts-check",
end: entry!.range.end,
pos: entry!.range.pos
end: entry.range.end,
pos: entry.range.pos
};
}
});
+28 -9
View File
@@ -193,7 +193,8 @@ namespace ts {
getDirectories: (path: string) => system.getDirectories(path),
realpath,
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth),
createDirectory: d => system.createDirectory(d)
createDirectory: d => system.createDirectory(d),
createHash: maybeBind(system, system.createHash)
};
return compilerHost;
}
@@ -315,7 +316,10 @@ namespace ts {
};
}
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
// tslint:disable unified-signatures
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
/*@internal*/ export function getPreEmitDiagnostics(program: BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
export function getPreEmitDiagnostics(program: Program | BuilderProgram, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
const diagnostics = [
...program.getConfigFileParsingDiagnostics(),
...program.getOptionsDiagnostics(cancellationToken),
@@ -330,6 +334,7 @@ namespace ts {
return sortAndDeduplicateDiagnostics(diagnostics);
}
// tslint:enable unified-signatures
export interface FormatDiagnosticsHost {
getCurrentDirectory(): string;
@@ -1129,7 +1134,7 @@ namespace ts {
function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: string): boolean {
const resolutionToFile = getResolvedModule(oldSourceFile!, moduleName);
const resolvedFile = resolutionToFile && oldProgram!.getSourceFile(resolutionToFile.resolvedFileName);
if (resolutionToFile && resolvedFile && !resolvedFile.externalModuleIndicator) {
if (resolutionToFile && resolvedFile) {
// In the old program, we resolved to an ambient module that was in the same
// place as we expected to find an actual module file.
// We actually need to return 'false' here even though this seems like a 'true' case
@@ -2261,8 +2266,13 @@ namespace ts {
let redirectedPath: Path | undefined;
if (refFile) {
const redirect = getProjectReferenceRedirect(fileName);
if (redirect) {
const redirectProject = getProjectReferenceRedirectProject(fileName);
if (redirectProject) {
if (redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out) {
// Shouldnt create many to 1 mapping file in --out scenario
return undefined;
}
const redirect = getProjectReferenceOutputName(redirectProject, fileName);
fileName = redirect;
// Once we start redirecting to a file, we can potentially come back to it
// via a back-reference from another file in the .d.ts folder. If that happens we'll
@@ -2359,6 +2369,11 @@ namespace ts {
}
function getProjectReferenceRedirect(fileName: string): string | undefined {
const referencedProject = getProjectReferenceRedirectProject(fileName);
return referencedProject && getProjectReferenceOutputName(referencedProject, fileName);
}
function getProjectReferenceRedirectProject(fileName: string) {
// Ignore dts or any of the non ts files
if (!resolvedProjectReferences || !resolvedProjectReferences.length || fileExtensionIs(fileName, Extension.Dts) || !fileExtensionIsOneOf(fileName, supportedTSExtensions)) {
return undefined;
@@ -2366,10 +2381,11 @@ namespace ts {
// If this file is produced by a referenced project, we need to rewrite it to
// look in the output folder of the referenced project rather than the input
const referencedProject = getResolvedProjectReferenceToRedirect(fileName);
if (!referencedProject) {
return undefined;
}
return getResolvedProjectReferenceToRedirect(fileName);
}
function getProjectReferenceOutputName(referencedProject: ResolvedProjectReference, fileName: string) {
const out = referencedProject.commandLine.options.outFile || referencedProject.commandLine.options.out;
return out ?
changeExtension(out, Extension.Dts) :
@@ -2730,6 +2746,9 @@ namespace ts {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "tsBuildInfoFile", "incremental", "composite");
}
}
else if (options.incremental && !options.outFile && !options.out && !options.configFilePath) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_incremental_can_only_be_specified_using_tsconfig_emitting_to_single_file_or_when_option_tsBuildInfoFile_is_specified));
}
verifyProjectReferences();
+2
View File
@@ -327,6 +327,8 @@ namespace ts {
createVariableDeclarationList(lexicalEnvironmentVariableDeclarations)
);
setEmitFlags(statement, EmitFlags.CustomPrologue);
if (!statements) {
statements = [statement];
}
+27 -11
View File
@@ -30,6 +30,7 @@ namespace ts {
listEmittedFiles?: boolean;
listFiles?: boolean;
pretty?: boolean;
incremental?: boolean;
traceResolution?: boolean;
/* @internal */ diagnostics?: boolean;
@@ -363,7 +364,7 @@ namespace ts {
function getCompilerOptionsOfBuildOptions(buildOptions: BuildOptions): CompilerOptions {
const result = {} as CompilerOptions;
commonOptionsWithBuild.forEach(option => {
result[option.name] = buildOptions[option.name];
if (hasProperty(buildOptions, option.name)) result[option.name] = buildOptions[option.name];
});
return result;
}
@@ -393,7 +394,7 @@ namespace ts {
const projectStatus = createFileMap<UpToDateStatus>(toPath);
const missingRoots = createMap<true>();
let globalDependencyGraph: DependencyGraph | undefined;
const writeFileName = (s: string) => host.trace && host.trace(s);
const writeFileName = host.trace ? (s: string) => host.trace!(s) : undefined;
let readFileWithCache = (f: string) => host.readFile(f);
let projectCompilerOptions = baseCompilerOptions;
const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions);
@@ -1128,7 +1129,7 @@ namespace ts {
let declDiagnostics: Diagnostic[] | undefined;
const reportDeclarationDiagnostics = (d: Diagnostic) => (declDiagnostics || (declDiagnostics = [])).push(d);
const outputFiles: OutputFile[] = [];
emitFilesAndReportErrors(program, reportDeclarationDiagnostics, writeFileName, /*reportSummary*/ undefined, (name, text, writeByteOrderMark) => outputFiles.push({ name, text, writeByteOrderMark }));
emitFilesAndReportErrors(program, reportDeclarationDiagnostics, /*writeFileName*/ undefined, /*reportSummary*/ undefined, (name, text, writeByteOrderMark) => outputFiles.push({ name, text, writeByteOrderMark }));
// Don't emit .d.ts if there are decl file errors
if (declDiagnostics) {
program.restoreState();
@@ -1137,7 +1138,7 @@ namespace ts {
// Actual Emit
const emitterDiagnostics = createDiagnosticCollection();
const emittedOutputs = createFileMap<true>(toPath as ToPath);
const emittedOutputs = createFileMap<string>(toPath as ToPath);
outputFiles.forEach(({ name, text, writeByteOrderMark }) => {
let priorChangeTime: Date | undefined;
if (!anyDtsChanged && isDeclarationFile(name)) {
@@ -1151,7 +1152,7 @@ namespace ts {
}
}
emittedOutputs.setValue(name, true);
emittedOutputs.setValue(name, name);
writeFile(compilerHost, emitterDiagnostics, name, text, writeByteOrderMark);
if (priorChangeTime !== undefined) {
newestDeclarationFileContentChangedTime = newer(priorChangeTime, newestDeclarationFileContentChangedTime);
@@ -1164,6 +1165,11 @@ namespace ts {
return buildErrors(emitDiagnostics, BuildResultFlags.EmitErrors, "Emit");
}
if (writeFileName) {
emittedOutputs.forEach(name => listEmittedFile(configFile, name));
listFiles(program, writeFileName);
}
// Update time stamps for rest of the outputs
newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker(configFile, newestDeclarationFileContentChangedTime, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs);
@@ -1181,6 +1187,8 @@ namespace ts {
function buildErrors(diagnostics: ReadonlyArray<Diagnostic>, errorFlags: BuildResultFlags, errorType: string) {
resultFlags |= errorFlags;
reportAndStoreErrors(proj, diagnostics);
// List files if any other build error using program (emit errors already report files)
if (writeFileName) listFiles(program, writeFileName);
projectStatus.setValue(proj, { type: UpToDateStatusType.Unbuildable, reason: `${errorType} errors` });
afterProgramCreate(proj, program);
projectCompilerOptions = baseCompilerOptions;
@@ -1188,6 +1196,12 @@ namespace ts {
}
}
function listEmittedFile(proj: ParsedCommandLine, file: string) {
if (writeFileName && proj.options.listEmittedFiles) {
writeFileName(`TSFILE: ${file}`);
}
}
function afterProgramCreate(proj: ResolvedConfigFileName, program: T) {
if (host.afterProgramEmitAndDiagnostics) {
host.afterProgramEmitAndDiagnostics(program);
@@ -1228,9 +1242,9 @@ namespace ts {
// Actual Emit
Debug.assert(!!outputFiles.length);
const emitterDiagnostics = createDiagnosticCollection();
const emittedOutputs = createFileMap<true>(toPath as ToPath);
const emittedOutputs = createFileMap<string>(toPath as ToPath);
outputFiles.forEach(({ name, text, writeByteOrderMark }) => {
emittedOutputs.setValue(name, true);
emittedOutputs.setValue(name, name);
writeFile(compilerHost, emitterDiagnostics, name, text, writeByteOrderMark);
});
const emitDiagnostics = emitterDiagnostics.getDiagnostics();
@@ -1241,6 +1255,10 @@ namespace ts {
return BuildResultFlags.DeclarationOutputUnchanged | BuildResultFlags.EmitErrors;
}
if (writeFileName) {
emittedOutputs.forEach(name => listEmittedFile(config, name));
}
// Update timestamps for dts
const newestDeclarationFileContentChangedTime = updateOutputTimestampsWorker(config, minimumDate, Diagnostics.Updating_unchanged_output_timestamps_of_project_0, emittedOutputs);
@@ -1269,7 +1287,7 @@ namespace ts {
projectStatus.setValue(proj.options.configFilePath as ResolvedConfigFilePath, status);
}
function updateOutputTimestampsWorker(proj: ParsedCommandLine, priorNewestUpdateTime: Date, verboseMessage: DiagnosticMessage, skipOutputs?: FileMap<true>) {
function updateOutputTimestampsWorker(proj: ParsedCommandLine, priorNewestUpdateTime: Date, verboseMessage: DiagnosticMessage, skipOutputs?: FileMap<string>) {
const outputs = getAllProjectOutputs(proj, !host.useCaseSensitiveFileNames());
if (!skipOutputs || outputs.length !== skipOutputs.getSize()) {
if (options.verbose) {
@@ -1286,9 +1304,7 @@ namespace ts {
}
host.setModifiedTime(file, now);
if (proj.options.listEmittedFiles) {
writeFileName(`TSFILE: ${file}`);
}
listEmittedFile(proj, file);
}
}
+20 -28
View File
@@ -5951,26 +5951,18 @@ namespace ts {
/* @internal */
export interface PragmaDefinition<T1 extends string = string, T2 extends string = string, T3 extends string = string, T4 extends string = string> {
args?:
| [PragmaArgumentSpecification<T1>]
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>]
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>]
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>, PragmaArgumentSpecification<T4>];
| readonly [PragmaArgumentSpecification<T1>]
| readonly [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>]
| readonly [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>]
| readonly [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>, PragmaArgumentSpecification<T4>];
// If not present, defaults to PragmaKindFlags.Default
kind?: PragmaKindFlags;
}
/**
* This function only exists to cause exact types to be inferred for all the literals within `commentPragmas`
*/
/* @internal */
function _contextuallyTypePragmas<T extends {[name: string]: PragmaDefinition<K1, K2, K3, K4>}, K1 extends string, K2 extends string, K3 extends string, K4 extends string>(args: T): T {
return args;
}
// While not strictly a type, this is here because `PragmaMap` needs to be here to be used with `SourceFile`, and we don't
// fancy effectively defining it twice, once in value-space and once in type-space
/* @internal */
export const commentPragmas = _contextuallyTypePragmas({
export const commentPragmas = {
"reference": {
args: [
{ name: "types", optional: true, captureSpan: true },
@@ -5998,7 +5990,7 @@ namespace ts {
args: [{ name: "factory" }],
kind: PragmaKindFlags.MultiLine
},
});
} as const;
/* @internal */
type PragmaArgTypeMaybeCapture<TDesc> = TDesc extends {captureSpan: true} ? {value: string, pos: number, end: number} : string;
@@ -6009,29 +6001,29 @@ namespace ts {
? {[K in TName]?: PragmaArgTypeMaybeCapture<TDesc>}
: {[K in TName]: PragmaArgTypeMaybeCapture<TDesc>};
/* @internal */
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
/* @internal */
type ArgumentDefinitionToFieldUnion<T extends readonly PragmaArgumentSpecification<any>[]> = {
[K in keyof T]: PragmaArgTypeOptional<T[K], T[K] extends {name: infer TName} ? TName extends string ? TName : never : never>
}[Extract<keyof T, number>]; // The mapped type maps over only the tuple members, but this reindex gets _all_ members - by extracting only `number` keys, we get only the tuple members
/**
* Maps a pragma definition into the desired shape for its arguments object
* Maybe the below is a good argument for types being iterable on struture in some way.
*/
/* @internal */
type PragmaArgumentType<T extends PragmaDefinition> =
T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>, PragmaArgumentSpecification<infer TName4>] }
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3> & PragmaArgTypeOptional<T["args"][2], TName4>
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>] }
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3>
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>] }
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2>
: T extends { args: [PragmaArgumentSpecification<infer TName>] }
? PragmaArgTypeOptional<T["args"][0], TName>
: object;
// The above fallback to `object` when there's no args to allow `{}` (as intended), but not the number 2, for example
// TODO: Swap to `undefined` for a cleaner API once strictNullChecks is enabled
type PragmaArgumentType<KPrag extends keyof ConcretePragmaSpecs> =
ConcretePragmaSpecs[KPrag] extends { args: readonly PragmaArgumentSpecification<any>[] }
? UnionToIntersection<ArgumentDefinitionToFieldUnion<ConcretePragmaSpecs[KPrag]["args"]>>
: never;
/* @internal */
type ConcretePragmaSpecs = typeof commentPragmas;
/* @internal */
export type PragmaPseudoMap = {[K in keyof ConcretePragmaSpecs]?: {arguments: PragmaArgumentType<ConcretePragmaSpecs[K]>, range: CommentRange}};
export type PragmaPseudoMap = {[K in keyof ConcretePragmaSpecs]: {arguments: PragmaArgumentType<K>, range: CommentRange}};
/* @internal */
export type PragmaPseudoMapEntry = {[K in keyof PragmaPseudoMap]: {name: K, args: PragmaPseudoMap[K]}}[keyof PragmaPseudoMap];
+9 -6
View File
@@ -121,6 +121,14 @@ namespace ts {
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
}
export function listFiles(program: ProgramToEmitFilesAndReportErrors, writeFileName: (s: string) => void) {
if (program.getCompilerOptions().listFiles) {
forEach(program.getSourceFiles(), file => {
writeFileName(file.fileName);
});
}
}
/**
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
*/
@@ -152,12 +160,7 @@ namespace ts {
const filepath = getNormalizedAbsolutePath(file, currentDir);
writeFileName(`TSFILE: ${filepath}`);
});
if (program.getCompilerOptions().listFiles) {
forEach(program.getSourceFiles(), file => {
writeFileName(file.fileName);
});
}
listFiles(program, writeFileName);
}
if (reportSummary) {
+5 -3
View File
@@ -90,7 +90,7 @@ namespace ts.server {
return <T>request;
}
private processResponse<T extends protocol.Response>(request: protocol.Request): T {
private processResponse<T extends protocol.Response>(request: protocol.Request, expectEmptyBody = false): T {
let foundResponseMessage = false;
let response!: T;
while (!foundResponseMessage) {
@@ -118,7 +118,8 @@ namespace ts.server {
throw new Error("Error " + response.message);
}
Debug.assert(!!response.body, "Malformed response: Unexpected empty response body.");
Debug.assert(expectEmptyBody || !!response.body, "Malformed response: Unexpected empty response body.");
Debug.assert(!expectEmptyBody || !response.body, "Malformed response: Unexpected non-empty response body.");
return response;
}
@@ -696,7 +697,8 @@ namespace ts.server {
}
configurePlugin(pluginName: string, configuration: any): void {
this.processRequest<protocol.ConfigurePluginRequest>("configurePlugin", { pluginName, configuration });
const request = this.processRequest<protocol.ConfigurePluginRequest>("configurePlugin", { pluginName, configuration });
this.processResponse<protocol.ConfigurePluginResponse>(request, /*expectEmptyBody*/ true);
}
getIndentationAtPosition(_fileName: string, _position: number, _options: EditorOptions): number {
+1
View File
@@ -4507,6 +4507,7 @@ namespace FourSlashInterface {
typeEntry("Record"),
typeEntry("Exclude"),
typeEntry("Extract"),
typeEntry("Omit"),
typeEntry("NonNullable"),
typeEntry("Parameters"),
typeEntry("ConstructorParameters"),
+5
View File
@@ -1443,6 +1443,11 @@ type Exclude<T, U> = T extends U ? never : T;
*/
type Extract<T, U> = T extends U ? T : never;
/**
* Construct a type with the properties of T except for those in type K.
*/
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
/**
* Exclude null and undefined from T
*/
+2 -1
View File
@@ -1607,7 +1607,8 @@ namespace ts.server {
this.documentRegistry,
compilerOptions,
/*lastFileExceededProgramSize*/ this.getFilenameForExceededTotalSizeLimitForNonTsFiles(projectFileName, compilerOptions, files, externalFilePropertyReader),
options.compileOnSave === undefined ? true : options.compileOnSave);
options.compileOnSave === undefined ? true : options.compileOnSave,
/*projectFilePath*/ undefined, this.currentPluginConfigOverrides);
project.excludedFiles = excludedFiles;
this.addFilesToNonInferredProject(project, files, externalFilePropertyReader, typeAcquisition);
+6 -1
View File
@@ -958,6 +958,9 @@ namespace ts.server {
);
const elapsed = timestamp() - start;
this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} Version: ${this.getProjectVersion()} structureChanged: ${hasNewProgram} Elapsed: ${elapsed}ms`);
if (this.program !== oldProgram) {
this.print();
}
return hasNewProgram;
}
@@ -1610,7 +1613,8 @@ namespace ts.server {
compilerOptions: CompilerOptions,
lastFileExceededProgramSize: string | undefined,
public compileOnSaveEnabled: boolean,
projectFilePath?: string) {
projectFilePath?: string,
pluginConfigOverrides?: Map<any>) {
super(externalProjectName,
ProjectKind.External,
projectService,
@@ -1621,6 +1625,7 @@ namespace ts.server {
compileOnSaveEnabled,
projectService.host,
getDirectoryPath(projectFilePath || normalizeSlashes(externalProjectName)));
this.enableGlobalPlugins(this.getCompilerOptions(), pluginConfigOverrides);
}
updateGraph() {
+3
View File
@@ -1392,6 +1392,9 @@ namespace ts.server.protocol {
arguments: ConfigurePluginRequestArguments;
}
export interface ConfigurePluginResponse extends Response {
}
/**
* Information found in an "open" request.
*/
+1
View File
@@ -2412,6 +2412,7 @@ namespace ts.server {
},
[CommandNames.ConfigurePlugin]: (request: protocol.ConfigurePluginRequest) => {
this.configurePlugin(request.arguments);
this.doOutput(/*info*/ undefined, CommandNames.ConfigurePlugin, request.seq, /*success*/ true);
return this.notRequired();
}
});
+2 -1
View File
@@ -10,6 +10,7 @@ interface ExecResult {
interface UserConfig {
types: string[];
path?: string;
}
abstract class ExternalCompileRunnerBase extends RunnerBase {
@@ -57,7 +58,7 @@ abstract class ExternalCompileRunnerBase extends RunnerBase {
ts.Debug.assert(!!config.types, "Bad format from test.json: Types field must be present.");
types = config.types;
cwd = submoduleDir;
cwd = config.path ? path.join(cwd, config.path) : submoduleDir;
}
if (fs.existsSync(path.join(cwd, "package.json"))) {
if (fs.existsSync(path.join(cwd, "package-lock.json"))) {
@@ -365,6 +365,26 @@ namespace ts {
}
});
});
it("parse --incremental", () => {
// --lib es6 0.ts
assertParseResult(["--incremental", "0.ts"],
{
errors: [],
fileNames: ["0.ts"],
options: { incremental: true }
});
});
it("parse --tsBuildInfoFile", () => {
// --lib es6 0.ts
assertParseResult(["--tsBuildInfoFile", "build.tsbuildinfo", "0.ts"],
{
errors: [],
fileNames: ["0.ts"],
options: { tsBuildInfoFile: "build.tsbuildinfo" }
});
});
});
describe("unittests:: config:: commandLineParsing:: parseBuildOptions", () => {
@@ -456,6 +476,33 @@ namespace ts {
});
});
it("parse build with --incremental", () => {
// --lib es6 0.ts
assertParseResult(["--incremental", "tests"],
{
errors: [],
projects: ["tests"],
buildOptions: { incremental: true }
});
});
it("parse build with --tsBuildInfoFile", () => {
// --lib es6 0.ts
assertParseResult(["--tsBuildInfoFile", "build.tsbuildinfo", "tests"],
{
errors: [{
messageText: "Unknown build option '--tsBuildInfoFile'.",
category: Diagnostics.Unknown_build_option_0.category,
code: Diagnostics.Unknown_build_option_0.code,
file: undefined,
start: undefined,
length: undefined
}],
projects: ["build.tsbuildinfo", "tests"],
buildOptions: { }
});
});
describe("Combining options that make no sense together", () => {
function verifyInvalidCombination(flag1: keyof BuildOptions, flag2: keyof BuildOptions) {
it(`--${flag1} and --${flag2} together is invalid`, () => {
@@ -445,5 +445,13 @@ var x = 0;`, {
}
}
});
transpilesCorrectly("Supports readonly keyword for arrays", "let x: readonly string[];", {
options: { compilerOptions: { module: ModuleKind.CommonJS } }
});
transpilesCorrectly("Supports 'as const' arrays", `([] as const).forEach(k => console.log(k));`, {
options: { compilerOptions: { module: ModuleKind.CommonJS } }
});
});
}
@@ -198,6 +198,58 @@ ${internal} export enum internalEnum { a, b, c }`);
modifyAgainFs: fs => replaceText(fs, sources[project.lib][source.ts][1], `export const`, `/*@internal*/ export const`),
});
});
describe("when the module resolution finds original source file", () => {
function modifyFs(fs: vfs.FileSystem) {
// Make lib to output to parent dir
replaceText(fs, sources[project.lib][source.config], `"outFile": "module.js"`, `"outFile": "../module.js", "rootDir": "../"`);
// Change reference to file1 module to resolve to lib/file1
replaceText(fs, sources[project.app][source.ts][0], "file1", "lib/file1");
}
const libOutputFile: OutputFile = [
"/src/lib/module.js",
"/src/lib/module.js.map",
"/src/lib/module.d.ts",
"/src/lib/module.d.ts.map",
"/src/lib/module.tsbuildinfo"
];
verifyTsbuildOutput({
scenario: "when the module resolution finds original source file",
projFs: () => outFileFs,
time,
tick,
proj: "amdModulesWithOut",
rootNames: ["/src/app"],
expectedMapFileNames: [
libOutputFile[ext.jsmap],
libOutputFile[ext.dtsmap],
outputFiles[project.app][ext.jsmap],
outputFiles[project.app][ext.dtsmap],
],
expectedBuildInfoFilesForSectionBaselines: [
[libOutputFile[ext.buildinfo], libOutputFile[ext.js], libOutputFile[ext.dts]],
[outputFiles[project.app][ext.buildinfo], outputFiles[project.app][ext.js], outputFiles[project.app][ext.dts]]
],
lastProjectOutputJs: outputFiles[project.app][ext.js],
initialBuild: {
modifyFs,
expectedDiagnostics: [
getExpectedDiagnosticForProjectsInBuild("src/lib/tsconfig.json", "src/app/tsconfig.json"),
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/lib/tsconfig.json", "src/module.js"],
[Diagnostics.Building_project_0, sources[project.lib][source.config]],
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/app/tsconfig.json", "src/app/module.js"],
[Diagnostics.Building_project_0, sources[project.app][source.config]],
]
},
outputFiles: [
...libOutputFile,
...outputFiles[project.app]
],
baselineOnly: true,
verifyDiagnostics: true
});
});
});
});
}
+3 -2
View File
@@ -234,10 +234,11 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
incrementalDtsUnchangedBuild?: BuildState;
incrementalHeaderChangedBuild?: BuildState;
baselineOnly?: true;
verifyDiagnostics?: true;
}
export function verifyTsbuildOutput({
scenario, projFs, time, tick, proj, rootNames, outputFiles, baselineOnly,
scenario, projFs, time, tick, proj, rootNames, outputFiles, baselineOnly, verifyDiagnostics,
expectedMapFileNames, expectedBuildInfoFilesForSectionBaselines, lastProjectOutputJs,
initialBuild, incrementalDtsChangedBuild, incrementalDtsUnchangedBuild, incrementalHeaderChangedBuild
}: VerifyTsBuildInput) {
@@ -264,7 +265,7 @@ Mismatch Actual(path, actual, expected): ${JSON.stringify(arrayFrom(mapDefinedIt
host = undefined!;
});
describe("initialBuild", () => {
if (!baselineOnly) {
if (!baselineOnly || verifyDiagnostics) {
it(`verify diagnostics`, () => {
host.assertDiagnosticMessages(...(initialBuild.expectedDiagnostics || emptyArray));
});
+45 -2
View File
@@ -197,8 +197,8 @@ namespace ts {
dtsUnchangedExpectedReadFilesDependOrdered = undefined!;
});
function createSolutionBuilder(host: fakes.SolutionBuilderHost) {
return ts.createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: true });
function createSolutionBuilder(host: fakes.SolutionBuilderHost, baseOptions?: BuildOptions) {
return ts.createSolutionBuilder(host, ["/src/third"], { dry: false, force: false, verbose: true, ...(baseOptions || {}) });
}
function getInitialExpectedReadFiles(additionalSourceFiles?: ReadonlyArray<string>) {
@@ -446,6 +446,49 @@ namespace ts {
);
});
it("rebuilds completely when command line incremental flag changes between non dts changes", () => {
const fs = outFileFs.shadow();
// Make non composite third project
replaceText(fs, sources[project.third][source.config], `"composite": true,`, "");
// Build with command line incremental
const host = new fakes.SolutionBuilderHost(fs);
const builder = createSolutionBuilder(host, { incremental: true });
builder.buildAllProjects();
host.assertDiagnosticMessages(...initialExpectedDiagnostics);
host.clearDiagnostics();
tick();
// Make non incremental build with change in file that doesnt affect dts
appendText(fs, relSources[project.first][source.ts][part.one], "console.log(s);");
builder.resetBuildContext({ verbose: true });
builder.buildAllProjects();
host.assertDiagnosticMessages(getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]),
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, relSources[project.first][source.config], relOutputFiles[project.first][ext.js], relSources[project.first][source.ts][part.one]],
[Diagnostics.Building_project_0, sources[project.first][source.config]],
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, relSources[project.second][source.config], relSources[project.second][source.ts][part.one], relOutputFiles[project.second][ext.js]],
[Diagnostics.Project_0_is_out_of_date_because_output_of_its_dependency_1_has_changed, relSources[project.third][source.config], "src/first"],
[Diagnostics.Building_project_0, sources[project.third][source.config]]
);
host.clearDiagnostics();
tick();
// Make incremental build with change in file that doesnt affect dts
appendText(fs, relSources[project.first][source.ts][part.one], "console.log(s);");
builder.resetBuildContext({ verbose: true, incremental: true });
builder.buildAllProjects();
// Builds completely because tsbuildinfo is old.
host.assertDiagnosticMessages(
getExpectedDiagnosticForProjectsInBuild(relSources[project.first][source.config], relSources[project.second][source.config], relSources[project.third][source.config]),
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, relSources[project.first][source.config], relOutputFiles[project.first][ext.js], relSources[project.first][source.ts][part.one]],
[Diagnostics.Building_project_0, sources[project.first][source.config]],
[Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, relSources[project.second][source.config], relSources[project.second][source.ts][part.one], relOutputFiles[project.second][ext.js]],
[Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2, relSources[project.third][source.config], relOutputFiles[project.third][ext.buildinfo], "src/first"],
[Diagnostics.Building_project_0, sources[project.third][source.config]]
);
host.clearDiagnostics();
});
describe("Prepend output with .tsbuildinfo", () => {
// Prologues
describe("Prologues", () => {
+3 -3
View File
@@ -427,14 +427,14 @@ export class cNew {}`);
builder.buildAllProjects();
assert.deepEqual(host.traces, [
"TSFILE: /src/core/anotherModule.js",
"TSFILE: /src/core/anotherModule.d.ts",
"TSFILE: /src/core/anotherModule.d.ts.map",
"TSFILE: /src/core/anotherModule.d.ts",
"TSFILE: /src/core/index.js",
"TSFILE: /src/core/index.d.ts",
"TSFILE: /src/core/index.d.ts.map",
"TSFILE: /src/core/index.d.ts",
"TSFILE: /src/core/tsconfig.tsbuildinfo",
"TSFILE: /src/logic/index.js",
"TSFILE: /src/logic/index.js.map",
"TSFILE: /src/logic/index.js",
"TSFILE: /src/logic/index.d.ts",
"TSFILE: /src/logic/tsconfig.tsbuildinfo",
"TSFILE: /src/tests/index.js",
@@ -65,6 +65,8 @@ export const b = new A();`);
const expectedFileTraces = [
...getLibs(),
"/src/a.ts",
...getLibs(),
"/src/b.ts"
];
verifyBuild(fs => modifyFsBTsToNonRelativeImport(fs, "node"),
allExpectedOutputs,
@@ -50,6 +50,68 @@ namespace ts.projectSystem {
});
});
it("load global plugins", () => {
const f1 = {
path: "/a/file1.ts",
content: "let x = [1, 2];"
};
const p1 = { projectFileName: "/a/proj1.csproj", rootFiles: [toExternalFile(f1.path)], options: {} };
const host = createServerHost([f1]);
host.require = (_initialPath, moduleName) => {
assert.equal(moduleName, "myplugin");
return {
module: () => ({
create(info: server.PluginCreateInfo) {
const proxy = Harness.LanguageService.makeDefaultProxy(info);
proxy.getSemanticDiagnostics = filename => {
const prev = info.languageService.getSemanticDiagnostics(filename);
const sourceFile: SourceFile = info.project.getSourceFile(toPath(filename, /*basePath*/ undefined, createGetCanonicalFileName(info.serverHost.useCaseSensitiveFileNames)))!;
prev.push({
category: DiagnosticCategory.Warning,
file: sourceFile,
code: 9999,
length: 3,
messageText: `Plugin diagnostic`,
start: 0
});
return prev;
};
return proxy;
}
}),
error: undefined
};
};
const session = createSession(host, { globalPlugins: ["myplugin"] });
session.executeCommand(<protocol.OpenExternalProjectsRequest>{
seq: 1,
type: "request",
command: "openExternalProjects",
arguments: { projects: [p1] }
});
const projectService = session.getProjectService();
checkNumberOfProjects(projectService, { externalProjects: 1 });
assert.equal(projectService.externalProjects[0].getProjectName(), p1.projectFileName);
const handlerResponse = session.executeCommand(<protocol.SemanticDiagnosticsSyncRequest>{
seq: 2,
type: "request",
command: "semanticDiagnosticsSync",
arguments: {
file: f1.path,
projectFileName: p1.projectFileName
}
});
assert.isDefined(handlerResponse.response);
const response = handlerResponse.response as protocol.Diagnostic[];
assert.equal(response.length, 1);
assert.equal(response[0].text, "Plugin diagnostic");
});
it("remove not-listed external projects", () => {
const f1 = {
path: "/a/app.ts",
@@ -479,6 +479,90 @@ namespace ts.projectSystem {
session.clearMessages();
}
});
it("Correct errors when resolution resolves to file that has same ambient module and is also module", () => {
const projectRootPath = "/users/username/projects/myproject";
const aFile: File = {
path: `${projectRootPath}/src/a.ts`,
content: `import * as myModule from "@custom/plugin";
function foo() {
// hello
}`
};
const config: File = {
path: `${projectRootPath}/tsconfig.json`,
content: JSON.stringify({ include: ["src"] })
};
const plugin: File = {
path: `${projectRootPath}/node_modules/@custom/plugin/index.d.ts`,
content: `import './proposed';
declare module '@custom/plugin' {
export const version: string;
}`
};
const pluginProposed: File = {
path: `${projectRootPath}/node_modules/@custom/plugin/proposed.d.ts`,
content: `declare module '@custom/plugin' {
export const bar = 10;
}`
};
const files = [libFile, aFile, config, plugin, pluginProposed];
const host = createServerHost(files);
const session = createSession(host, { canUseEvents: true });
const service = session.getProjectService();
openFilesForSession([aFile], session);
checkNumberOfProjects(service, { configuredProjects: 1 });
session.clearMessages();
checkErrors();
session.executeCommandSeq<protocol.ChangeRequest>({
command: protocol.CommandTypes.Change,
arguments: {
file: aFile.path,
line: 3,
offset: 8,
endLine: 3,
endOffset: 8,
insertString: "o"
}
});
checkErrors();
function checkErrors() {
host.checkTimeoutQueueLength(0);
const expectedSequenceId = session.getNextSeq();
session.executeCommandSeq<protocol.GeterrRequest>({
command: server.CommandNames.Geterr,
arguments: {
delay: 0,
files: [aFile.path],
}
});
host.checkTimeoutQueueLengthAndRun(1);
checkErrorMessage(session, "syntaxDiag", { file: aFile.path, diagnostics: [] }, /*isMostRecent*/ true);
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
checkErrorMessage(session, "semanticDiag", { file: aFile.path, diagnostics: [] });
session.clearMessages();
host.runQueuedImmediateCallbacks(1);
checkErrorMessage(session, "suggestionDiag", {
file: aFile.path,
diagnostics: [
createDiagnostic({ line: 1, offset: 1 }, { line: 1, offset: 44 }, Diagnostics._0_is_declared_but_its_value_is_never_read, ["myModule"], "suggestion", /*reportsUnnecessary*/ true),
createDiagnostic({ line: 2, offset: 10 }, { line: 2, offset: 13 }, Diagnostics._0_is_declared_but_its_value_is_never_read, ["foo"], "suggestion", /*reportsUnnecessary*/ true)
],
});
checkCompleteEvent(session, 2, expectedSequenceId);
session.clearMessages();
}
});
});
describe("unittests:: tsserver:: Project Errors for Configure file diagnostics events", () => {
+3
View File
@@ -165,6 +165,9 @@ namespace ts {
reportWatchModeWithoutSysSupport();
createWatchOfFilesAndCompilerOptions(commandLine.fileNames, commandLineOptions);
}
else if (isIncrementalCompilation(commandLineOptions)) {
performIncrementalCompilation(commandLine);
}
else {
performCompilation(commandLine.fileNames, /*references*/ undefined, commandLineOptions);
}