mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-23 19:07:27 -06:00
Merge branch 'master' into watchAPIAndProjectReferences
This commit is contained in:
commit
40d33c809a
@ -2666,7 +2666,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (!isBindingPattern(node.name)) {
|
||||
const isEnum = !!getJSDocEnumTag(node);
|
||||
const isEnum = isInJSFile(node) && !!getJSDocEnumTag(node);
|
||||
const enumFlags = (isEnum ? SymbolFlags.RegularEnum : SymbolFlags.None);
|
||||
const enumExcludes = (isEnum ? SymbolFlags.RegularEnumExcludes : SymbolFlags.None);
|
||||
if (isBlockOrCatchScoped(node)) {
|
||||
|
||||
@ -2219,7 +2219,7 @@ namespace ts {
|
||||
const sourceFile = resolvedModule && !resolutionDiagnostic && host.getSourceFile(resolvedModule.resolvedFileName);
|
||||
if (sourceFile) {
|
||||
if (sourceFile.symbol) {
|
||||
if (resolvedModule.isExternalLibraryImport && !extensionIsTypeScript(resolvedModule.extension)) {
|
||||
if (resolvedModule.isExternalLibraryImport && !extensionIsTS(resolvedModule.extension)) {
|
||||
errorOnImplicitAnyModule(/*isError*/ false, errorNode, resolvedModule, moduleReference);
|
||||
}
|
||||
// merged symbol is module declaration symbol combined with all augmentations
|
||||
@ -2240,7 +2240,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// May be an untyped module. If so, ignore resolutionDiagnostic.
|
||||
if (resolvedModule && !resolutionExtensionIsTypeScriptOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) {
|
||||
if (resolvedModule && !resolutionExtensionIsTSOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) {
|
||||
if (isForAugmentation) {
|
||||
const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented;
|
||||
error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName);
|
||||
@ -2273,7 +2273,7 @@ namespace ts {
|
||||
error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName);
|
||||
}
|
||||
else {
|
||||
const tsExtension = tryExtractTypeScriptExtension(moduleReference);
|
||||
const tsExtension = tryExtractTSExtension(moduleReference);
|
||||
if (tsExtension) {
|
||||
const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead;
|
||||
error(errorNode, diag, tsExtension, removeExtension(moduleReference, tsExtension));
|
||||
@ -3351,7 +3351,7 @@ namespace ts {
|
||||
if (symbol) {
|
||||
const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class;
|
||||
id = (isConstructorObject ? "+" : "") + getSymbolId(symbol);
|
||||
if (isJavascriptConstructor(symbol.valueDeclaration)) {
|
||||
if (isJSConstructor(symbol.valueDeclaration)) {
|
||||
// Instance and static types share the same symbol; only add 'typeof' for the static side.
|
||||
const isInstanceType = type === getInferredClassType(symbol) ? SymbolFlags.Type : SymbolFlags.Value;
|
||||
return symbolToTypeNode(symbol, context, isInstanceType);
|
||||
@ -5563,7 +5563,7 @@ namespace ts {
|
||||
const constraint = getBaseConstraintOfType(type);
|
||||
return !!constraint && isValidBaseType(constraint) && isMixinConstructorType(constraint);
|
||||
}
|
||||
return isJavascriptConstructorType(type);
|
||||
return isJSConstructorType(type);
|
||||
}
|
||||
|
||||
function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments | undefined {
|
||||
@ -5573,7 +5573,7 @@ namespace ts {
|
||||
function getConstructorsForTypeArguments(type: Type, typeArgumentNodes: ReadonlyArray<TypeNode> | undefined, location: Node): ReadonlyArray<Signature> {
|
||||
const typeArgCount = length(typeArgumentNodes);
|
||||
const isJavascript = isInJSFile(location);
|
||||
if (isJavascriptConstructorType(type) && !typeArgCount) {
|
||||
if (isJSConstructorType(type) && !typeArgCount) {
|
||||
return getSignaturesOfType(type, SignatureKind.Call);
|
||||
}
|
||||
return filter(getSignaturesOfType(type, SignatureKind.Construct),
|
||||
@ -5668,8 +5668,8 @@ namespace ts {
|
||||
else if (baseConstructorType.flags & TypeFlags.Any) {
|
||||
baseType = baseConstructorType;
|
||||
}
|
||||
else if (isJavascriptConstructorType(baseConstructorType) && !baseTypeNode.typeArguments) {
|
||||
baseType = getJavascriptClassType(baseConstructorType.symbol) || anyType;
|
||||
else if (isJSConstructorType(baseConstructorType) && !baseTypeNode.typeArguments) {
|
||||
baseType = getJSClassType(baseConstructorType.symbol) || anyType;
|
||||
}
|
||||
else {
|
||||
// The class derives from a "class-like" constructor function, check that we have at least one construct signature
|
||||
@ -10176,7 +10176,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
let outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true);
|
||||
if (isJavascriptConstructor(declaration)) {
|
||||
if (isJSConstructor(declaration)) {
|
||||
const templateTagParameters = getTypeParametersFromDeclaration(declaration as DeclarationWithTypeParameters);
|
||||
outerTypeParameters = addRange(outerTypeParameters, templateTagParameters);
|
||||
}
|
||||
@ -10862,13 +10862,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (!ignoreReturnTypes) {
|
||||
const targetReturnType = (target.declaration && isJavascriptConstructor(target.declaration)) ?
|
||||
getJavascriptClassType(target.declaration.symbol)! : getReturnTypeOfSignature(target);
|
||||
const targetReturnType = (target.declaration && isJSConstructor(target.declaration)) ?
|
||||
getJSClassType(target.declaration.symbol)! : getReturnTypeOfSignature(target);
|
||||
if (targetReturnType === voidType) {
|
||||
return result;
|
||||
}
|
||||
const sourceReturnType = (source.declaration && isJavascriptConstructor(source.declaration)) ?
|
||||
getJavascriptClassType(source.declaration.symbol)! : getReturnTypeOfSignature(source);
|
||||
const sourceReturnType = (source.declaration && isJSConstructor(source.declaration)) ?
|
||||
getJSClassType(source.declaration.symbol)! : getReturnTypeOfSignature(source);
|
||||
|
||||
// The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
|
||||
const targetTypePredicate = getTypePredicateOfSignature(target);
|
||||
@ -12132,8 +12132,8 @@ namespace ts {
|
||||
return Ternary.True;
|
||||
}
|
||||
|
||||
const sourceIsJSConstructor = source.symbol && isJavascriptConstructor(source.symbol.valueDeclaration);
|
||||
const targetIsJSConstructor = target.symbol && isJavascriptConstructor(target.symbol.valueDeclaration);
|
||||
const sourceIsJSConstructor = source.symbol && isJSConstructor(source.symbol.valueDeclaration);
|
||||
const targetIsJSConstructor = target.symbol && isJSConstructor(target.symbol.valueDeclaration);
|
||||
|
||||
const sourceSignatures = getSignaturesOfType(source, (sourceIsJSConstructor && kind === SignatureKind.Construct) ?
|
||||
SignatureKind.Call : kind);
|
||||
@ -15821,7 +15821,7 @@ namespace ts {
|
||||
if (isInJS && className) {
|
||||
const classSymbol = checkExpression(className).symbol;
|
||||
if (classSymbol && classSymbol.members && (classSymbol.flags & SymbolFlags.Function)) {
|
||||
const classType = getJavascriptClassType(classSymbol);
|
||||
const classType = getJSClassType(classSymbol);
|
||||
if (classType) {
|
||||
return getFlowTypeOfReference(node, classType);
|
||||
}
|
||||
@ -15834,7 +15834,7 @@ namespace ts {
|
||||
else if (isInJS &&
|
||||
(container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.FunctionDeclaration) &&
|
||||
getJSDocClassTag(container)) {
|
||||
const classType = getJavascriptClassType(container.symbol);
|
||||
const classType = getJSClassType(container.symbol);
|
||||
if (classType) {
|
||||
return getFlowTypeOfReference(node, classType);
|
||||
}
|
||||
@ -19851,7 +19851,7 @@ namespace ts {
|
||||
if (callSignatures.length) {
|
||||
const signature = resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
|
||||
if (!noImplicitAny) {
|
||||
if (signature.declaration && !isJavascriptConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
|
||||
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
|
||||
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
|
||||
}
|
||||
if (getThisTypeOfSignature(signature) === voidType) {
|
||||
@ -20134,7 +20134,7 @@ namespace ts {
|
||||
* Indicates whether a declaration can be treated as a constructor in a JavaScript
|
||||
* file.
|
||||
*/
|
||||
function isJavascriptConstructor(node: Declaration | undefined): boolean {
|
||||
function isJSConstructor(node: Declaration | undefined): boolean {
|
||||
if (node && isInJSFile(node)) {
|
||||
// If the node has a @class tag, treat it like a constructor.
|
||||
if (getJSDocClassTag(node)) return true;
|
||||
@ -20150,22 +20150,22 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isJavascriptConstructorType(type: Type) {
|
||||
function isJSConstructorType(type: Type) {
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
|
||||
return resolved.callSignatures.length === 1 && isJavascriptConstructor(resolved.callSignatures[0].declaration);
|
||||
return resolved.callSignatures.length === 1 && isJSConstructor(resolved.callSignatures[0].declaration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getJavascriptClassType(symbol: Symbol): Type | undefined {
|
||||
function getJSClassType(symbol: Symbol): Type | undefined {
|
||||
let inferred: Type | undefined;
|
||||
if (isJavascriptConstructor(symbol.valueDeclaration)) {
|
||||
if (isJSConstructor(symbol.valueDeclaration)) {
|
||||
inferred = getInferredClassType(symbol);
|
||||
}
|
||||
const assigned = getAssignedClassType(symbol);
|
||||
const valueType = getTypeOfSymbol(symbol);
|
||||
if (valueType.symbol && !isInferredClassType(valueType) && isJavascriptConstructor(valueType.symbol.valueDeclaration)) {
|
||||
if (valueType.symbol && !isInferredClassType(valueType) && isJSConstructor(valueType.symbol.valueDeclaration)) {
|
||||
inferred = getInferredClassType(valueType.symbol);
|
||||
}
|
||||
return assigned && inferred ?
|
||||
@ -20180,14 +20180,14 @@ namespace ts {
|
||||
isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
|
||||
isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent));
|
||||
if (assignmentSymbol) {
|
||||
const prototype = forEach(assignmentSymbol.declarations, getAssignedJavascriptPrototype);
|
||||
const prototype = forEach(assignmentSymbol.declarations, getAssignedJSPrototype);
|
||||
if (prototype) {
|
||||
return checkExpression(prototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAssignedJavascriptPrototype(node: Node) {
|
||||
function getAssignedJSPrototype(node: Node) {
|
||||
if (!node.parent) {
|
||||
return false;
|
||||
}
|
||||
@ -20248,7 +20248,7 @@ namespace ts {
|
||||
if (!funcSymbol && node.expression.kind === SyntaxKind.Identifier) {
|
||||
funcSymbol = getResolvedSymbol(node.expression as Identifier);
|
||||
}
|
||||
const type = funcSymbol && getJavascriptClassType(funcSymbol);
|
||||
const type = funcSymbol && getJSClassType(funcSymbol);
|
||||
if (type) {
|
||||
return signature.target ? instantiateType(type, signature.mapper) : type;
|
||||
}
|
||||
@ -20897,7 +20897,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
if (strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression &&
|
||||
!(isJavascriptConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol))) {
|
||||
!(isJSConstructor(func) && aggregatedTypes.some(t => t.symbol === func.symbol))) {
|
||||
// Javascript "callable constructors", containing eg `if (!(this instanceof A)) return new A()` should not add undefined
|
||||
pushIfUnique(aggregatedTypes, undefinedType);
|
||||
}
|
||||
@ -25811,7 +25811,7 @@ namespace ts {
|
||||
// that the base type is a class or interface type (and not, for example, an anonymous object type).
|
||||
// (Javascript constructor functions have this property trivially true since their return type is ignored.)
|
||||
const constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments, baseTypeNode);
|
||||
if (forEach(constructors, sig => !isJavascriptConstructor(sig.declaration) && getReturnTypeOfSignature(sig) !== baseType)) {
|
||||
if (forEach(constructors, sig => !isJSConstructor(sig.declaration) && getReturnTypeOfSignature(sig) !== baseType)) {
|
||||
error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type);
|
||||
}
|
||||
}
|
||||
@ -29938,10 +29938,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
|
||||
const jsdocTypeParameters = isInJSFile(node) && getJSDocTypeParameterDeclarations(node);
|
||||
if (node.typeParameters || jsdocTypeParameters && jsdocTypeParameters.length) {
|
||||
const { pos, end } = node.typeParameters || jsdocTypeParameters && jsdocTypeParameters[0] || node;
|
||||
return grammarErrorAtPos(node, pos, end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
|
||||
const jsdocTypeParameters = isInJSFile(node) ? getJSDocTypeParameterDeclarations(node) : undefined;
|
||||
const range = node.typeParameters || jsdocTypeParameters && firstOrUndefined(jsdocTypeParameters);
|
||||
if (range) {
|
||||
const pos = range.pos === range.end ? range.pos : skipTrivia(getSourceFileOfNode(node).text, range.pos);
|
||||
return grammarErrorAtPos(node, pos, range.end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
export const libMap = createMapFromEntries(libEntries);
|
||||
|
||||
const commonOptionsWithBuild: CommandLineOption[] = [
|
||||
/* @internal */
|
||||
export const commonOptionsWithBuild: CommandLineOption[] = [
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
@ -83,6 +84,18 @@ namespace ts {
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
{
|
||||
name: "listFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "listEmittedFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
shortName: "w",
|
||||
@ -561,18 +574,6 @@ namespace ts {
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Include_modules_imported_with_json_extension
|
||||
},
|
||||
{
|
||||
name: "listFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "listEmittedFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
|
||||
},
|
||||
|
||||
{
|
||||
name: "out",
|
||||
@ -903,17 +904,27 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
|
||||
const options: CompilerOptions = {};
|
||||
/* @internal */
|
||||
export interface OptionsBase {
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
|
||||
/** Tuple with error messages for 'unknown compiler option', 'option requires type' */
|
||||
type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage];
|
||||
|
||||
function parseCommandLineWorker(
|
||||
getOptionNameMap: () => OptionNameMap,
|
||||
[unknownOptionDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics,
|
||||
commandLine: ReadonlyArray<string>,
|
||||
readFile?: (path: string) => string | undefined) {
|
||||
const options = {} as OptionsBase;
|
||||
const fileNames: string[] = [];
|
||||
const projectReferences: ProjectReference[] | undefined = undefined;
|
||||
const errors: Diagnostic[] = [];
|
||||
|
||||
parseStrings(commandLine);
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
projectReferences,
|
||||
errors
|
||||
};
|
||||
|
||||
@ -926,7 +937,7 @@ namespace ts {
|
||||
parseResponseFile(s.slice(1));
|
||||
}
|
||||
else if (s.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionFromName(s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
const opt = getOptionDeclarationFromName(getOptionNameMap, s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
if (opt.isTSConfigOnly) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name));
|
||||
@ -934,7 +945,7 @@ namespace ts {
|
||||
else {
|
||||
// Check to see if no argument was provided (e.g. "--locale" is the last command-line argument).
|
||||
if (!args[i] && opt.type !== "boolean") {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name));
|
||||
errors.push(createCompilerDiagnostic(optionTypeMismatchDiagnostic, opt.name));
|
||||
}
|
||||
|
||||
switch (opt.type) {
|
||||
@ -971,7 +982,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, s));
|
||||
errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1014,13 +1025,19 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
|
||||
return parseCommandLineWorker(getOptionNameMap, [
|
||||
Diagnostics.Unknown_compiler_option_0,
|
||||
Diagnostics.Compiler_option_0_expects_an_argument
|
||||
], commandLine, readFile);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
|
||||
return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
optionName = optionName.toLowerCase();
|
||||
const { optionNameMap, shortOptionNames } = getOptionNameMap();
|
||||
// Try to translate short option names to their full equivalents.
|
||||
@ -1044,25 +1061,11 @@ namespace ts {
|
||||
export function parseBuildCommand(args: string[]): ParsedBuildCommand {
|
||||
let buildOptionNameMap: OptionNameMap | undefined;
|
||||
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
|
||||
|
||||
const buildOptions: BuildOptions = {};
|
||||
const projects: string[] = [];
|
||||
let errors: Diagnostic[] | undefined;
|
||||
for (const arg of args) {
|
||||
if (arg.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
buildOptions[opt.name as keyof BuildOptions] = true;
|
||||
}
|
||||
else {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Not a flag, parse as filename
|
||||
projects.push(arg);
|
||||
}
|
||||
}
|
||||
const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [
|
||||
Diagnostics.Unknown_build_option_0,
|
||||
Diagnostics.Build_option_0_requires_a_value_of_type_1
|
||||
], args);
|
||||
const buildOptions = options as BuildOptions;
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
@ -1071,19 +1074,19 @@ namespace ts {
|
||||
|
||||
// Nonsensical combinations
|
||||
if (buildOptions.clean && buildOptions.force) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.verbose) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
|
||||
}
|
||||
if (buildOptions.clean && buildOptions.watch) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
|
||||
}
|
||||
if (buildOptions.watch && buildOptions.dry) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
}
|
||||
|
||||
return { buildOptions, projects, errors: errors || emptyArray };
|
||||
return { buildOptions, projects, errors };
|
||||
}
|
||||
|
||||
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
|
||||
@ -1825,7 +1828,8 @@ namespace ts {
|
||||
const options = extend(existingOptions, parsedConfig.options || {});
|
||||
options.configFilePath = configFileName && normalizeSlashes(configFileName);
|
||||
setConfigFileInOptions(options, sourceFile);
|
||||
const { fileNames, wildcardDirectories, spec, projectReferences } = getFileNames();
|
||||
let projectReferences: ProjectReference[] | undefined;
|
||||
const { fileNames, wildcardDirectories, spec } = getFileNames();
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
@ -1904,13 +1908,12 @@ namespace ts {
|
||||
|
||||
if (hasProperty(raw, "references") && !isNullOrUndefined(raw.references)) {
|
||||
if (isArray(raw.references)) {
|
||||
const references: ProjectReference[] = [];
|
||||
for (const ref of raw.references) {
|
||||
if (typeof ref.path !== "string") {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string");
|
||||
}
|
||||
else {
|
||||
references.push({
|
||||
(projectReferences || (projectReferences = [])).push({
|
||||
path: getNormalizedAbsolutePath(ref.path, basePath),
|
||||
originalPath: ref.path,
|
||||
prepend: ref.prepend,
|
||||
@ -1918,7 +1921,6 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
}
|
||||
result.projectReferences = references;
|
||||
}
|
||||
else {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "references", "Array");
|
||||
@ -2407,7 +2409,7 @@ namespace ts {
|
||||
// new entries in these paths.
|
||||
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);
|
||||
|
||||
const spec: ConfigFileSpecs = { filesSpecs, referencesSpecs: undefined, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
|
||||
const spec: ConfigFileSpecs = { filesSpecs, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
|
||||
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
|
||||
}
|
||||
|
||||
@ -2478,16 +2480,9 @@ namespace ts {
|
||||
|
||||
const literalFiles = arrayFrom(literalFileMap.values());
|
||||
const wildcardFiles = arrayFrom(wildcardFileMap.values());
|
||||
const projectReferences = spec.referencesSpecs && spec.referencesSpecs.map((r): ProjectReference => {
|
||||
return {
|
||||
...r,
|
||||
path: getNormalizedAbsolutePath(r.path, basePath)
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
fileNames: literalFiles.concat(wildcardFiles),
|
||||
projectReferences,
|
||||
wildcardDirectories,
|
||||
spec
|
||||
};
|
||||
|
||||
@ -2948,7 +2948,10 @@
|
||||
"category": "Error",
|
||||
"code": 5072
|
||||
},
|
||||
|
||||
"Build option '{0}' requires a value of type {1}.": {
|
||||
"category": "Error",
|
||||
"code": 5073
|
||||
},
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
@ -3874,10 +3877,6 @@
|
||||
"category": "Error",
|
||||
"code": 6370
|
||||
},
|
||||
"Skipping clean because not all projects could be located": {
|
||||
"category": "Error",
|
||||
"code": 6371
|
||||
},
|
||||
|
||||
"The expected type comes from property '{0}' which is declared here on type '{1}'": {
|
||||
"category": "Message",
|
||||
@ -4644,7 +4643,7 @@
|
||||
"category": "Message",
|
||||
"code": 95062
|
||||
},
|
||||
|
||||
|
||||
"Add missing enum member '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95063
|
||||
@ -4653,12 +4652,12 @@
|
||||
"category": "Message",
|
||||
"code": 95064
|
||||
},
|
||||
"Convert to async function":{
|
||||
"Convert to async function": {
|
||||
"category": "Message",
|
||||
"code": 95065
|
||||
"code": 95065
|
||||
},
|
||||
"Convert all to async functions": {
|
||||
"category": "Message",
|
||||
"code": 95066
|
||||
"category": "Message",
|
||||
"code": 95066
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ namespace ts {
|
||||
}
|
||||
const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles;
|
||||
// Setup and perform the transformation to retrieve declarations from the input files
|
||||
const nonJsFiles = filter(sourceFiles, isSourceFileNotJavascript);
|
||||
const nonJsFiles = filter(sourceFiles, isSourceFileNotJS);
|
||||
const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(nonJsFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : nonJsFiles;
|
||||
if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
|
||||
// Checker wont collect the linked aliases since thats only done when declaration is enabled.
|
||||
|
||||
@ -74,7 +74,7 @@ namespace ts {
|
||||
if (!resolved) {
|
||||
return undefined;
|
||||
}
|
||||
Debug.assert(extensionIsTypeScript(resolved.extension));
|
||||
Debug.assert(extensionIsTS(resolved.extension));
|
||||
return { fileName: resolved.path, packageId: resolved.packageId };
|
||||
}
|
||||
|
||||
@ -778,7 +778,7 @@ namespace ts {
|
||||
* Throws an error if the module can't be resolved.
|
||||
*/
|
||||
/* @internal */
|
||||
export function resolveJavascriptModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
|
||||
export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
|
||||
const { resolvedModule, failedLookupLocations } =
|
||||
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
|
||||
if (!resolvedModule) {
|
||||
@ -958,7 +958,7 @@ namespace ts {
|
||||
|
||||
// If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one;
|
||||
// e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
|
||||
if (hasJavascriptFileExtension(candidate)) {
|
||||
if (hasJSFileExtension(candidate)) {
|
||||
const extensionless = removeFileExtension(candidate);
|
||||
if (state.traceEnabled) {
|
||||
const extension = candidate.substring(extensionless.length);
|
||||
@ -1052,7 +1052,7 @@ namespace ts {
|
||||
const jsPath = readPackageJsonMainField(packageJsonContent, packageDirectory, state);
|
||||
if (typeof jsPath === "string" && jsPath.length > packageDirectory.length) {
|
||||
const potentialSubModule = jsPath.substring(packageDirectory.length + 1);
|
||||
subModuleName = (forEach(supportedJavascriptExtensions, extension =>
|
||||
subModuleName = (forEach(supportedJSExtensions, extension =>
|
||||
tryRemoveExtension(potentialSubModule, extension)) || potentialSubModule) + Extension.Dts;
|
||||
}
|
||||
else {
|
||||
|
||||
@ -30,7 +30,7 @@ namespace ts.moduleSpecifiers {
|
||||
function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string): Preferences {
|
||||
return {
|
||||
relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative,
|
||||
ending: hasJavascriptOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
|
||||
ending: hasJSOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal,
|
||||
};
|
||||
}
|
||||
@ -148,7 +148,7 @@ namespace ts.moduleSpecifiers {
|
||||
}
|
||||
|
||||
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJavascriptOrJsonFileExtension(text) : undefined) || false;
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJSOrJsonFileExtension(text) : undefined) || false;
|
||||
}
|
||||
|
||||
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
|
||||
@ -415,13 +415,13 @@ namespace ts.moduleSpecifiers {
|
||||
case Ending.Index:
|
||||
return noExtension;
|
||||
case Ending.JsExtension:
|
||||
return noExtension + getJavascriptExtensionForFile(fileName, options);
|
||||
return noExtension + getJSExtensionForFile(fileName, options);
|
||||
default:
|
||||
return Debug.assertNever(ending);
|
||||
}
|
||||
}
|
||||
|
||||
function getJavascriptExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
const ext = extensionFromPath(fileName);
|
||||
switch (ext) {
|
||||
case Extension.Ts:
|
||||
|
||||
@ -6517,7 +6517,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function skipWhitespaceOrAsterisk(): void {
|
||||
function skipWhitespaceOrAsterisk(next: () => void): void {
|
||||
if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
|
||||
if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
|
||||
return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
|
||||
@ -6532,7 +6532,7 @@ namespace ts {
|
||||
else if (token() === SyntaxKind.AsteriskToken) {
|
||||
precedingLineBreak = false;
|
||||
}
|
||||
nextJSDocToken();
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
@ -6542,8 +6542,9 @@ namespace ts {
|
||||
atToken.end = scanner.getTextPos();
|
||||
nextJSDocToken();
|
||||
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
skipWhitespaceOrAsterisk();
|
||||
// Use 'nextToken' instead of 'nextJsDocToken' so we can parse a type like 'number' in `@enum number`
|
||||
const tagName = parseJSDocIdentifierName(/*message*/ undefined, nextToken);
|
||||
skipWhitespaceOrAsterisk(nextToken);
|
||||
|
||||
let tag: JSDocTag | undefined;
|
||||
switch (tagName.escapedText) {
|
||||
@ -6687,7 +6688,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function tryParseTypeExpression(): JSDocTypeExpression | undefined {
|
||||
skipWhitespaceOrAsterisk();
|
||||
skipWhitespaceOrAsterisk(nextJSDocToken);
|
||||
return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
|
||||
}
|
||||
|
||||
@ -6727,7 +6728,7 @@ namespace ts {
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
|
||||
let typeExpression = tryParseTypeExpression();
|
||||
let isNameFirst = !typeExpression;
|
||||
skipWhitespaceOrAsterisk();
|
||||
skipWhitespaceOrAsterisk(nextJSDocToken);
|
||||
|
||||
const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
|
||||
skipWhitespace();
|
||||
@ -6861,7 +6862,7 @@ namespace ts {
|
||||
|
||||
function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespaceOrAsterisk();
|
||||
skipWhitespaceOrAsterisk(nextJSDocToken);
|
||||
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
|
||||
typedefTag.atToken = atToken;
|
||||
@ -7114,7 +7115,7 @@ namespace ts {
|
||||
return entity;
|
||||
}
|
||||
|
||||
function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {
|
||||
function parseJSDocIdentifierName(message?: DiagnosticMessage, next: () => void = nextJSDocToken): Identifier {
|
||||
if (!tokenIsIdentifierOrKeyword(token())) {
|
||||
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
|
||||
}
|
||||
@ -7125,7 +7126,7 @@ namespace ts {
|
||||
result.escapedText = escapeLeadingUnderscores(scanner.getTokenText());
|
||||
finishNode(result, end);
|
||||
|
||||
nextJSDocToken();
|
||||
next();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1455,7 +1455,7 @@ namespace ts {
|
||||
// constructs from within a JavaScript file as syntactic errors.
|
||||
if (isSourceFileJS(sourceFile)) {
|
||||
if (!sourceFile.additionalSyntacticDiagnostics) {
|
||||
sourceFile.additionalSyntacticDiagnostics = getJavascriptSyntacticDiagnosticsForFile(sourceFile);
|
||||
sourceFile.additionalSyntacticDiagnostics = getJSSyntacticDiagnosticsForFile(sourceFile);
|
||||
}
|
||||
return concatenate(sourceFile.additionalSyntacticDiagnostics, sourceFile.parseDiagnostics);
|
||||
}
|
||||
@ -1553,7 +1553,7 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getJavascriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
|
||||
function getJSSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
|
||||
return runWithCancellationToken(() => {
|
||||
const diagnostics: DiagnosticWithLocation[] = [];
|
||||
let parent: Node = sourceFile;
|
||||
@ -2288,7 +2288,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
|
||||
const isJsFile = !resolutionExtensionIsTypeScriptOrJson(resolution.extension);
|
||||
const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension);
|
||||
const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile;
|
||||
const resolvedFileName = resolution.resolvedFileName;
|
||||
|
||||
@ -2356,7 +2356,7 @@ namespace ts {
|
||||
|
||||
function parseProjectReferenceConfigFile(ref: ProjectReference): { commandLine: ParsedCommandLine, sourceFile: SourceFile } | undefined {
|
||||
// The actual filename (i.e. add "/tsconfig.json" if necessary)
|
||||
const refPath = resolveProjectReferencePath(host, ref);
|
||||
const refPath = resolveProjectReferencePath(ref);
|
||||
// An absolute path pointing to the containing directory of the config file
|
||||
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
|
||||
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
|
||||
@ -2809,7 +2809,7 @@ namespace ts {
|
||||
return containsPath(options.outDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames());
|
||||
}
|
||||
|
||||
if (fileExtensionIsOneOf(filePath, supportedJavascriptExtensions) || fileExtensionIs(filePath, Extension.Dts)) {
|
||||
if (fileExtensionIsOneOf(filePath, supportedJSExtensions) || fileExtensionIs(filePath, Extension.Dts)) {
|
||||
// Otherwise just check if sourceFile with the name exists
|
||||
const filePathWithoutExtension = removeFileExtension(filePath);
|
||||
return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) ||
|
||||
@ -2835,18 +2835,13 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export interface ResolveProjectReferencePathHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
}
|
||||
/**
|
||||
* Returns the target config filename of a project reference.
|
||||
* Note: The file might not exist.
|
||||
*/
|
||||
export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName {
|
||||
if (!host.fileExists(ref.path)) {
|
||||
return combinePaths(ref.path, "tsconfig.json") as ResolvedConfigFileName;
|
||||
}
|
||||
return ref.path as ResolvedConfigFileName;
|
||||
// TODO: Does this need to be exposed
|
||||
export function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName {
|
||||
return resolveConfigFileProjectName(ref.path);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@ -226,7 +226,7 @@ namespace ts {
|
||||
|
||||
// otherwise try to load typings from @types
|
||||
const globalCache = resolutionHost.getGlobalCache();
|
||||
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension))) {
|
||||
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) {
|
||||
// create different collection of failed lookup locations for second pass
|
||||
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
|
||||
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(moduleName, resolutionHost.projectName, compilerOptions, host, globalCache);
|
||||
|
||||
@ -317,18 +317,22 @@ namespace ts {
|
||||
const newTime = modifiedTime.getTime();
|
||||
if (oldTime !== newTime) {
|
||||
watchedFile.mtime = modifiedTime;
|
||||
const eventKind = oldTime === 0
|
||||
? FileWatcherEventKind.Created
|
||||
: newTime === 0
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
watchedFile.callback(watchedFile.fileName, eventKind);
|
||||
watchedFile.callback(watchedFile.fileName, getFileWatcherEventKind(oldTime, newTime));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getFileWatcherEventKind(oldTime: number, newTime: number) {
|
||||
return oldTime === 0
|
||||
? FileWatcherEventKind.Created
|
||||
: newTime === 0
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface RecursiveDirectoryWatcherHost {
|
||||
watchDirectory: HostWatchDirectory;
|
||||
|
||||
@ -5,7 +5,7 @@ namespace ts {
|
||||
return []; // No declaration diagnostics for js for now
|
||||
}
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJavascript), [transformDeclarations], /*allowDtsFiles*/ false);
|
||||
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJS), [transformDeclarations], /*allowDtsFiles*/ false);
|
||||
return result.diagnostics;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4517,7 +4517,6 @@ namespace ts {
|
||||
/* @internal */
|
||||
export interface ConfigFileSpecs {
|
||||
filesSpecs: ReadonlyArray<string> | undefined;
|
||||
referencesSpecs: ReadonlyArray<ProjectReference> | undefined;
|
||||
/**
|
||||
* Present to report errors (user specified specs), validatedIncludeSpecs are used for file name matching
|
||||
*/
|
||||
@ -4533,7 +4532,6 @@ namespace ts {
|
||||
|
||||
export interface ExpandResult {
|
||||
fileNames: string[];
|
||||
projectReferences: ReadonlyArray<ProjectReference> | undefined;
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
/* @internal */ spec: ConfigFileSpecs;
|
||||
}
|
||||
|
||||
@ -1688,7 +1688,7 @@ namespace ts {
|
||||
return isInJSFile(file);
|
||||
}
|
||||
|
||||
export function isSourceFileNotJavascript(file: SourceFile): boolean {
|
||||
export function isSourceFileNotJS(file: SourceFile): boolean {
|
||||
return !isInJSFile(file);
|
||||
}
|
||||
|
||||
@ -3824,8 +3824,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */
|
||||
export function tryExtractTypeScriptExtension(fileName: string): string | undefined {
|
||||
return find(supportedTypescriptExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension));
|
||||
export function tryExtractTSExtension(fileName: string): string | undefined {
|
||||
return find(supportedTSExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
/**
|
||||
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
|
||||
@ -4335,7 +4335,7 @@ namespace ts {
|
||||
/**
|
||||
* clears already present map by calling onDeleteExistingValue callback before deleting that key/value
|
||||
*/
|
||||
export function clearMap<T>(map: Map<T>, onDeleteValue: (valueInMap: T, key: string) => void) {
|
||||
export function clearMap<T>(map: { forEach: Map<T>["forEach"]; clear: Map<T>["clear"]; }, onDeleteValue: (valueInMap: T, key: string) => void) {
|
||||
// Remove all
|
||||
map.forEach(onDeleteValue);
|
||||
map.clear();
|
||||
@ -8016,42 +8016,42 @@ namespace ts {
|
||||
/**
|
||||
* List of supported extensions in order of file resolution precedence.
|
||||
*/
|
||||
export const supportedTypescriptExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
|
||||
export const supportedTSExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
|
||||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
export const supportedJavascriptAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypescriptExtensions, ...supportedJavascriptExtensions];
|
||||
export const supportedTSExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJSExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
export const supportedJSAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTSExtensions, ...supportedJSExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
|
||||
const needJsExtensions = options && options.allowJs;
|
||||
|
||||
if (!extraFileExtensions || extraFileExtensions.length === 0) {
|
||||
return needJsExtensions ? allSupportedExtensions : supportedTypescriptExtensions;
|
||||
return needJsExtensions ? allSupportedExtensions : supportedTSExtensions;
|
||||
}
|
||||
|
||||
const extensions = [
|
||||
...needJsExtensions ? allSupportedExtensions : supportedTypescriptExtensions,
|
||||
...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJavascriptLike(x.scriptKind) ? x.extension : undefined)
|
||||
...needJsExtensions ? allSupportedExtensions : supportedTSExtensions,
|
||||
...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJSLike(x.scriptKind) ? x.extension : undefined)
|
||||
];
|
||||
|
||||
return deduplicate<string>(extensions, equateStringsCaseSensitive, compareStringsCaseSensitive);
|
||||
}
|
||||
|
||||
function isJavascriptLike(scriptKind: ScriptKind | undefined): boolean {
|
||||
function isJSLike(scriptKind: ScriptKind | undefined): boolean {
|
||||
return scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX;
|
||||
}
|
||||
|
||||
export function hasJavascriptFileExtension(fileName: string): boolean {
|
||||
return some(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
export function hasJSFileExtension(fileName: string): boolean {
|
||||
return some(supportedJSExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function hasJavascriptOrJsonFileExtension(fileName: string): boolean {
|
||||
return supportedJavascriptAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
|
||||
export function hasJSOrJsonFileExtension(fileName: string): boolean {
|
||||
return supportedJSAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
|
||||
}
|
||||
|
||||
export function hasTypescriptFileExtension(fileName: string): boolean {
|
||||
return some(supportedTypescriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
export function hasTSFileExtension(fileName: string): boolean {
|
||||
return some(supportedTSExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>) {
|
||||
@ -8187,12 +8187,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** True if an extension is one of the supported TypeScript extensions. */
|
||||
export function extensionIsTypeScript(ext: Extension): boolean {
|
||||
export function extensionIsTS(ext: Extension): boolean {
|
||||
return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts;
|
||||
}
|
||||
|
||||
export function resolutionExtensionIsTypeScriptOrJson(ext: Extension) {
|
||||
return extensionIsTypeScript(ext) || ext === Extension.Json;
|
||||
export function resolutionExtensionIsTSOrJson(ext: Extension) {
|
||||
return extensionIsTS(ext) || ext === Extension.Json;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -101,7 +101,7 @@ namespace ts {
|
||||
getGlobalDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
emit(): EmitResult;
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
|
||||
}
|
||||
|
||||
export type ReportEmitErrorSummary = (errorCount: number) => void;
|
||||
@ -109,7 +109,7 @@ namespace ts {
|
||||
/**
|
||||
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
|
||||
*/
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary) {
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary, writeFile?: WriteFileCallback) {
|
||||
// First get and report any syntactic errors.
|
||||
const diagnostics = program.getConfigFileParsingDiagnostics().slice();
|
||||
const configFileParsingDiagnosticsLength = diagnostics.length;
|
||||
@ -128,7 +128,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(/*targetSourceFile*/ undefined, writeFile);
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
|
||||
if (reportSemanticDiagnostics) {
|
||||
|
||||
@ -593,7 +593,7 @@ namespace FourSlash {
|
||||
public verifyNoErrors() {
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
if (!ts.isAnySupportedFileExtension(fileName)
|
||||
|| !this.getProgram().getCompilerOptions().allowJs && !ts.extensionIsTypeScript(ts.extensionFromPath(fileName))) return;
|
||||
|| !this.getProgram().getCompilerOptions().allowJs && !ts.extensionIsTS(ts.extensionFromPath(fileName))) return;
|
||||
const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion);
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
|
||||
@ -268,7 +268,7 @@ namespace Harness.LanguageService {
|
||||
getHost(): LanguageServiceAdapterHost { return this.host; }
|
||||
getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); }
|
||||
getClassifier(): ts.Classifier { return ts.createClassifier(); }
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavascriptFileExtension(fileName)); }
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJSFileExtension(fileName)); }
|
||||
}
|
||||
|
||||
/// Shim adapter
|
||||
|
||||
@ -21,8 +21,8 @@ namespace vpath {
|
||||
export import relative = ts.getRelativePathFromDirectory;
|
||||
export import beneath = ts.containsPath;
|
||||
export import changeExtension = ts.changeAnyExtension;
|
||||
export import isTypeScript = ts.hasTypescriptFileExtension;
|
||||
export import isJavaScript = ts.hasJavascriptFileExtension;
|
||||
export import isTypeScript = ts.hasTSFileExtension;
|
||||
export import isJavaScript = ts.hasJSFileExtension;
|
||||
|
||||
const invalidRootComponentRegExp = /^(?!(\/|\/\/\w+\/|[a-zA-Z]:\/?|)$)/;
|
||||
const invalidNavigableComponentRegExp = /[:*?"<>|]/;
|
||||
|
||||
@ -122,7 +122,7 @@ namespace ts.JsTyping {
|
||||
// Only infer typings for .js and .jsx files
|
||||
fileNames = mapDefined(fileNames, fileName => {
|
||||
const path = normalizePath(fileName);
|
||||
if (hasJavascriptFileExtension(path)) {
|
||||
if (hasJSFileExtension(path)) {
|
||||
return path;
|
||||
}
|
||||
});
|
||||
@ -218,7 +218,7 @@ namespace ts.JsTyping {
|
||||
*/
|
||||
function getTypingNamesFromSourceFileNames(fileNames: string[]) {
|
||||
const fromFileNames = mapDefined(fileNames, j => {
|
||||
if (!hasJavascriptFileExtension(j)) return undefined;
|
||||
if (!hasJSFileExtension(j)) return undefined;
|
||||
|
||||
const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase()));
|
||||
const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName);
|
||||
|
||||
4
src/lib/es2015.promise.d.ts
vendored
4
src/lib/es2015.promise.d.ts
vendored
@ -7,7 +7,7 @@ interface PromiseConstructor {
|
||||
/**
|
||||
* Creates a new Promise.
|
||||
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
|
||||
* a resolve callback used resolve the promise with a value or the result of another promise,
|
||||
* a resolve callback used to resolve the promise with a value or the result of another promise,
|
||||
* and a reject callback used to reject the promise with a provided reason or error.
|
||||
*/
|
||||
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
|
||||
@ -193,4 +193,4 @@ interface PromiseConstructor {
|
||||
resolve(): Promise<void>;
|
||||
}
|
||||
|
||||
declare var Promise: PromiseConstructor;
|
||||
declare var Promise: PromiseConstructor;
|
||||
|
||||
@ -291,7 +291,8 @@ namespace ts.server {
|
||||
ClosedScriptInfo = "Closed Script info",
|
||||
ConfigFileForInferredRoot = "Config file for the inferred project root",
|
||||
FailedLookupLocation = "Directory of Failed lookup locations in module resolution",
|
||||
TypeRoots = "Type root directory"
|
||||
TypeRoots = "Type root directory",
|
||||
NodeModulesForClosedScriptInfo = "node_modules for closed script infos in them",
|
||||
}
|
||||
|
||||
const enum ConfigFileWatcherStatus {
|
||||
@ -353,10 +354,18 @@ namespace ts.server {
|
||||
return !!(infoOrFileName as ScriptInfo).containingProjects;
|
||||
}
|
||||
|
||||
interface ScriptInfoInNodeModulesWatcher extends FileWatcher {
|
||||
refCount: number;
|
||||
}
|
||||
|
||||
function getDetailWatchInfo(watchType: WatchType, project: Project | undefined) {
|
||||
return `Project: ${project ? project.getProjectName() : ""} WatchType: ${watchType}`;
|
||||
}
|
||||
|
||||
function isScriptInfoWatchedFromNodeModules(info: ScriptInfo) {
|
||||
return !info.isScriptOpen() && info.mTime !== undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function updateProjectIfDirty(project: Project) {
|
||||
return project.dirty && project.updateGraph();
|
||||
@ -380,6 +389,7 @@ namespace ts.server {
|
||||
* Container of all known scripts
|
||||
*/
|
||||
private readonly filenameToScriptInfo = createMap<ScriptInfo>();
|
||||
private readonly scriptInfoInNodeModulesWatchers = createMap <ScriptInfoInNodeModulesWatcher>();
|
||||
/**
|
||||
* Contains all the deleted script info's version information so that
|
||||
* it does not reset when creating script info again
|
||||
@ -1447,14 +1457,14 @@ namespace ts.server {
|
||||
|
||||
for (const f of fileNames) {
|
||||
const fileName = propertyReader.getFileName(f);
|
||||
if (hasTypescriptFileExtension(fileName)) {
|
||||
if (hasTSFileExtension(fileName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
totalNonTsFileSize += this.host.getFileSize(fileName);
|
||||
|
||||
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles || totalNonTsFileSize > availableSpace) {
|
||||
this.logger.info(getExceedLimitMessage({ propertyReader, hasTypescriptFileExtension, host: this.host }, totalNonTsFileSize));
|
||||
this.logger.info(getExceedLimitMessage({ propertyReader, hasTSFileExtension, host: this.host }, totalNonTsFileSize));
|
||||
// Keep the size as zero since it's disabled
|
||||
return fileName;
|
||||
}
|
||||
@ -1464,14 +1474,14 @@ namespace ts.server {
|
||||
|
||||
return;
|
||||
|
||||
function getExceedLimitMessage(context: { propertyReader: FilePropertyReader<any>, hasTypescriptFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) {
|
||||
function getExceedLimitMessage(context: { propertyReader: FilePropertyReader<any>, hasTSFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) {
|
||||
const files = getTop5LargestFiles(context);
|
||||
|
||||
return `Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${files.map(file => `${file.name}:${file.size}`).join(", ")}`;
|
||||
}
|
||||
function getTop5LargestFiles({ propertyReader, hasTypescriptFileExtension, host }: { propertyReader: FilePropertyReader<any>, hasTypescriptFileExtension: (filename: string) => boolean, host: ServerHost }) {
|
||||
function getTop5LargestFiles({ propertyReader, hasTSFileExtension, host }: { propertyReader: FilePropertyReader<any>, hasTSFileExtension: (filename: string) => boolean, host: ServerHost }) {
|
||||
return fileNames.map(f => propertyReader.getFileName(f))
|
||||
.filter(name => hasTypescriptFileExtension(name))
|
||||
.filter(name => hasTSFileExtension(name))
|
||||
.map(name => ({ name, size: host.getFileSize!(name) })) // TODO: GH#18217
|
||||
.sort((a, b) => b.size - a.size)
|
||||
.slice(0, 5);
|
||||
@ -1923,18 +1933,97 @@ namespace ts.server {
|
||||
if (!info.isDynamicOrHasMixedContent() &&
|
||||
(!this.globalCacheLocationDirectoryPath ||
|
||||
!startsWith(info.path, this.globalCacheLocationDirectoryPath))) {
|
||||
const { fileName } = info;
|
||||
info.fileWatcher = this.watchFactory.watchFilePath(
|
||||
this.host,
|
||||
fileName,
|
||||
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
|
||||
PollingInterval.Medium,
|
||||
info.path,
|
||||
WatchType.ClosedScriptInfo
|
||||
);
|
||||
const indexOfNodeModules = info.path.indexOf("/node_modules/");
|
||||
if (!this.host.getModifiedTime || indexOfNodeModules === -1) {
|
||||
info.fileWatcher = this.watchFactory.watchFilePath(
|
||||
this.host,
|
||||
info.fileName,
|
||||
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
|
||||
PollingInterval.Medium,
|
||||
info.path,
|
||||
WatchType.ClosedScriptInfo
|
||||
);
|
||||
}
|
||||
else {
|
||||
info.mTime = this.getModifiedTime(info);
|
||||
info.fileWatcher = this.watchClosedScriptInfoInNodeModules(info.path.substr(0, indexOfNodeModules) as Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private watchClosedScriptInfoInNodeModules(dir: Path): ScriptInfoInNodeModulesWatcher {
|
||||
// Watch only directory
|
||||
const existing = this.scriptInfoInNodeModulesWatchers.get(dir);
|
||||
if (existing) {
|
||||
existing.refCount++;
|
||||
return existing;
|
||||
}
|
||||
|
||||
const watchDir = dir + "/node_modules" as Path;
|
||||
const watcher = this.watchFactory.watchDirectory(
|
||||
this.host,
|
||||
watchDir,
|
||||
(fileOrDirectory) => {
|
||||
const fileOrDirectoryPath = this.toPath(fileOrDirectory);
|
||||
// Has extension
|
||||
Debug.assert(result.refCount > 0);
|
||||
if (watchDir === fileOrDirectoryPath) {
|
||||
this.refreshScriptInfosInDirectory(watchDir);
|
||||
}
|
||||
else {
|
||||
const info = this.getScriptInfoForPath(fileOrDirectoryPath);
|
||||
if (info) {
|
||||
if (isScriptInfoWatchedFromNodeModules(info)) {
|
||||
this.refreshScriptInfo(info);
|
||||
}
|
||||
}
|
||||
// Folder
|
||||
else if (!hasExtension(fileOrDirectoryPath)) {
|
||||
this.refreshScriptInfosInDirectory(fileOrDirectoryPath);
|
||||
}
|
||||
}
|
||||
},
|
||||
WatchDirectoryFlags.Recursive,
|
||||
WatchType.NodeModulesForClosedScriptInfo
|
||||
);
|
||||
const result: ScriptInfoInNodeModulesWatcher = {
|
||||
close: () => {
|
||||
if (result.refCount === 1) {
|
||||
watcher.close();
|
||||
this.scriptInfoInNodeModulesWatchers.delete(dir);
|
||||
}
|
||||
else {
|
||||
result.refCount--;
|
||||
}
|
||||
},
|
||||
refCount: 1
|
||||
};
|
||||
this.scriptInfoInNodeModulesWatchers.set(dir, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private getModifiedTime(info: ScriptInfo) {
|
||||
return (this.host.getModifiedTime!(info.path) || missingFileModifiedTime).getTime();
|
||||
}
|
||||
|
||||
private refreshScriptInfo(info: ScriptInfo) {
|
||||
const mTime = this.getModifiedTime(info);
|
||||
if (mTime !== info.mTime) {
|
||||
const eventKind = getFileWatcherEventKind(info.mTime!, mTime);
|
||||
info.mTime = mTime;
|
||||
this.onSourceFileChanged(info.fileName, eventKind, info.path);
|
||||
}
|
||||
}
|
||||
|
||||
private refreshScriptInfosInDirectory(dir: Path) {
|
||||
dir = dir + directorySeparator as Path;
|
||||
this.filenameToScriptInfo.forEach(info => {
|
||||
if (isScriptInfoWatchedFromNodeModules(info) && startsWith(info.path, dir)) {
|
||||
this.refreshScriptInfo(info);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private stopWatchingScriptInfo(info: ScriptInfo) {
|
||||
if (info.fileWatcher) {
|
||||
info.fileWatcher.close();
|
||||
|
||||
@ -167,7 +167,7 @@ namespace ts.server {
|
||||
const fileName = tempFileName || this.fileName;
|
||||
const getText = () => text === undefined ? (text = this.host.readFile(fileName) || "") : text;
|
||||
// Only non typescript files have size limitation
|
||||
if (!hasTypescriptFileExtension(this.fileName)) {
|
||||
if (!hasTSFileExtension(this.fileName)) {
|
||||
const fileSize = this.host.getFileSize ? this.host.getFileSize(fileName) : getText().length;
|
||||
if (fileSize > maxFileSize) {
|
||||
Debug.assert(!!this.info.containingProjects.length);
|
||||
@ -250,6 +250,9 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
cacheSourceFile: DocumentRegistrySourceFileCache;
|
||||
|
||||
/*@internal*/
|
||||
mTime?: number;
|
||||
|
||||
constructor(
|
||||
private readonly host: ServerHost,
|
||||
readonly fileName: NormalizedPath,
|
||||
|
||||
@ -2,11 +2,13 @@
|
||||
namespace ts.codefix {
|
||||
const fixId = "convertToAsyncFunction";
|
||||
const errorCodes = [Diagnostics.This_may_be_converted_to_an_async_function.code];
|
||||
let codeActionSucceeded = true;
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
getCodeActions(context: CodeFixContext) {
|
||||
codeActionSucceeded = true;
|
||||
const changes = textChanges.ChangeTracker.with(context, (t) => convertToAsyncFunction(t, context.sourceFile, context.span.start, context.program.getTypeChecker(), context));
|
||||
return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)];
|
||||
return codeActionSucceeded ? [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)] : [];
|
||||
},
|
||||
fixIds: [fixId],
|
||||
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker(), context)),
|
||||
@ -252,6 +254,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
// dispatch function to recursively build the refactoring
|
||||
// should be kept up to date with isFixablePromiseHandler in suggestionDiagnostics.ts
|
||||
function transformExpression(node: Expression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] {
|
||||
if (!node) {
|
||||
return [];
|
||||
@ -273,6 +276,7 @@ namespace ts.codefix {
|
||||
return transformPromiseCall(node, transformer, prevArgName);
|
||||
}
|
||||
|
||||
codeActionSucceeded = false;
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -381,13 +385,18 @@ namespace ts.codefix {
|
||||
(createVariableDeclarationList([createVariableDeclaration(getSynthesizedDeepClone(prevArgName.identifier), /*type*/ undefined, rightHandSide)], getFlagOfIdentifier(prevArgName.identifier, transformer.constIdentifiers))))]);
|
||||
}
|
||||
|
||||
// should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts
|
||||
function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier, parent: CallExpression, transformer: Transformer): NodeArray<Statement> {
|
||||
|
||||
const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0;
|
||||
const hasArgName = argName && argName.identifier.text.length > 0;
|
||||
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString());
|
||||
switch (func.kind) {
|
||||
case SyntaxKind.NullKeyword:
|
||||
// do not produce a transformed statement for a null argument
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
// identifier includes undefined
|
||||
if (!hasArgName) break;
|
||||
|
||||
const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, [argName.identifier]);
|
||||
@ -443,6 +452,9 @@ namespace ts.codefix {
|
||||
return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody) as Expression)]);
|
||||
}
|
||||
}
|
||||
default:
|
||||
// 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;
|
||||
break;
|
||||
}
|
||||
return createNodeArray([]);
|
||||
@ -492,14 +504,6 @@ namespace ts.codefix {
|
||||
return innerCbBody;
|
||||
}
|
||||
|
||||
function hasPropertyAccessExpressionWithName(node: CallExpression, funcName: string): boolean {
|
||||
if (!isPropertyAccessExpression(node.expression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node.expression.name.text === funcName;
|
||||
}
|
||||
|
||||
function getArgName(funcNode: Node, transformer: Transformer): SynthIdentifier {
|
||||
|
||||
const numberOfAssignmentsOriginal = 0;
|
||||
|
||||
@ -390,11 +390,12 @@ namespace ts.Completions {
|
||||
}
|
||||
type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths, readonly paths: ReadonlyArray<PathCompletions.PathCompletion> } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes;
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost): StringLiteralCompletion | undefined {
|
||||
switch (node.parent.kind) {
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.LiteralType:
|
||||
switch (node.parent.parent.kind) {
|
||||
switch (parent.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent as LiteralTypeNode)), isNewIdentifier: false };
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent as LiteralTypeNode)), isNewIdentifier: false };
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
@ -402,17 +403,21 @@ namespace ts.Completions {
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((node.parent.parent as IndexedAccessTypeNode).objectType));
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((parent.parent as IndexedAccessTypeNode).objectType));
|
||||
case SyntaxKind.ImportType:
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: PathCompletions.getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) };
|
||||
case SyntaxKind.UnionType:
|
||||
return isTypeReferenceNode(node.parent.parent.parent) ? { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent.parent as UnionTypeNode)), isNewIdentifier: false } : undefined;
|
||||
case SyntaxKind.UnionType: {
|
||||
if (!isTypeReferenceNode(parent.parent.parent)) return undefined;
|
||||
const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(parent.parent as UnionTypeNode, parent as LiteralTypeNode);
|
||||
const types = getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent.parent as UnionTypeNode)).filter(t => !contains(alreadyUsedTypes, t.value));
|
||||
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false };
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
if (isObjectLiteralExpression(node.parent.parent) && (<PropertyAssignment>node.parent).name === node) {
|
||||
if (isObjectLiteralExpression(parent.parent) && (<PropertyAssignment>parent).name === node) {
|
||||
// Get quoted name of properties of the object literal expression
|
||||
// i.e. interface ConfigFiles {
|
||||
// 'jspm:dev': string
|
||||
@ -425,12 +430,12 @@ namespace ts.Completions {
|
||||
// foo({
|
||||
// '/*completion position*/'
|
||||
// });
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(node.parent.parent));
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(parent.parent));
|
||||
}
|
||||
return fromContextualType();
|
||||
|
||||
case SyntaxKind.ElementAccessExpression: {
|
||||
const { expression, argumentExpression } = node.parent as ElementAccessExpression;
|
||||
const { expression, argumentExpression } = parent as ElementAccessExpression;
|
||||
if (node === argumentExpression) {
|
||||
// Get all names of properties on the expression
|
||||
// i.e. interface A {
|
||||
@ -445,7 +450,7 @@ namespace ts.Completions {
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
if (!isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(node.parent)) {
|
||||
if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(parent)) {
|
||||
const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(node, position, sourceFile);
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
@ -476,6 +481,11 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current: LiteralTypeNode): ReadonlyArray<string> {
|
||||
return mapDefined(union.types, type =>
|
||||
type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined);
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionsFromSignature(argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes {
|
||||
let isNewIdentifier = false;
|
||||
|
||||
|
||||
@ -196,15 +196,23 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, host: LanguageServiceHost): ToImport | undefined {
|
||||
return resolved && (
|
||||
(resolved.resolvedModule && getIfExists(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, getIfExists));
|
||||
// Search through all locations looking for a moved file, and only then test already existing files.
|
||||
// This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location.
|
||||
return tryEach(tryGetNewFile) || tryEach(tryGetOldFile);
|
||||
|
||||
function getIfExists(oldLocation: string): ToImport | undefined {
|
||||
const newLocation = oldToNew(oldLocation);
|
||||
function tryEach(cb: (oldFileName: string) => ToImport | undefined): ToImport | undefined {
|
||||
return resolved && (
|
||||
(resolved.resolvedModule && cb(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, cb));
|
||||
}
|
||||
|
||||
return host.fileExists!(oldLocation) || newLocation !== undefined && host.fileExists!(newLocation) // TODO: GH#18217
|
||||
? newLocation !== undefined ? { newFileName: newLocation, updated: true } : { newFileName: oldLocation, updated: false }
|
||||
: undefined;
|
||||
function tryGetNewFile(oldFileName: string): ToImport | undefined {
|
||||
const newFileName = oldToNew(oldFileName);
|
||||
return newFileName !== undefined && host.fileExists!(newFileName) ? { newFileName, updated: true } : undefined; // TODO: GH#18217
|
||||
}
|
||||
|
||||
function tryGetOldFile(oldFileName: string): ToImport | undefined {
|
||||
const newFileName = oldToNew(oldFileName);
|
||||
return host.fileExists!(oldFileName) ? newFileName !== undefined ? { newFileName, updated: true } : { newFileName: oldFileName, updated: false } : undefined; // TODO: GH#18217
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -312,7 +312,7 @@ namespace ts.JsDoc {
|
||||
const preamble = "/**" + newLine + indentationStr + " * ";
|
||||
const result =
|
||||
preamble + newLine +
|
||||
parameterDocComments(parameters, hasJavascriptFileExtension(sourceFile.fileName), indentationStr, newLine) +
|
||||
parameterDocComments(parameters, hasJSFileExtension(sourceFile.fileName), indentationStr, newLine) +
|
||||
indentationStr + " */" +
|
||||
(tokenStart === position ? newLine + indentationStr : "");
|
||||
|
||||
|
||||
@ -160,7 +160,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function addHandlers(returnChild: Node) {
|
||||
if (isPromiseHandler(returnChild)) {
|
||||
if (isFixablePromiseHandler(returnChild)) {
|
||||
returnStatements.push(child as ReturnStatement);
|
||||
}
|
||||
}
|
||||
@ -170,8 +170,39 @@ namespace ts {
|
||||
return returnStatements;
|
||||
}
|
||||
|
||||
function isPromiseHandler(node: Node): boolean {
|
||||
return (isCallExpression(node) && isPropertyAccessExpression(node.expression) &&
|
||||
(node.expression.name.text === "then" || node.expression.name.text === "catch"));
|
||||
// Should be kept up to date with transformExpression in convertToAsyncFunction.ts
|
||||
function isFixablePromiseHandler(node: Node): boolean {
|
||||
// ensure outermost call exists and is a promise handler
|
||||
if (!isPromiseHandler(node) || !node.arguments.every(isFixablePromiseArgument)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure all chained calls are valid
|
||||
let currentNode = node.expression;
|
||||
while (isPromiseHandler(currentNode) || isPropertyAccessExpression(currentNode)) {
|
||||
if (isCallExpression(currentNode) && !currentNode.arguments.every(isFixablePromiseArgument)) {
|
||||
return false;
|
||||
}
|
||||
currentNode = currentNode.expression;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isPromiseHandler(node: Node): node is CallExpression {
|
||||
return isCallExpression(node) && (hasPropertyAccessExpressionWithName(node, "then") || hasPropertyAccessExpressionWithName(node, "catch"));
|
||||
}
|
||||
|
||||
// should be kept up to date with getTransformationBody in convertToAsyncFunction.ts
|
||||
function isFixablePromiseArgument(arg: Expression): boolean {
|
||||
switch (arg.kind) {
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.Identifier: // identifier includes undefined
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,8 +23,10 @@ namespace ts {
|
||||
|
||||
export function getMeaningFromDeclaration(node: Node): SemanticMeaning {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return isInJSFile(node) && getJSDocEnumTag(node) ? SemanticMeaning.All : SemanticMeaning.Value;
|
||||
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
@ -224,6 +226,14 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function hasPropertyAccessExpressionWithName(node: CallExpression, funcName: string): boolean {
|
||||
if (!isPropertyAccessExpression(node.expression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node.expression.name.text === funcName;
|
||||
}
|
||||
|
||||
export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } {
|
||||
return node.kind === SyntaxKind.Identifier && isBreakOrContinueStatement(node.parent) && node.parent.label === node;
|
||||
}
|
||||
|
||||
@ -1,68 +1,4 @@
|
||||
namespace ts {
|
||||
interface Range {
|
||||
pos: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
function getTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, pos: text.length, end: undefined! });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop()!;
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
const libFile: TestFSWithWatch.File = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: `/// <reference no-default-lib="true"/>
|
||||
@ -319,19 +255,22 @@ interface String { charAt: any; }
|
||||
interface Array<T> {}`
|
||||
};
|
||||
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, diagnosticDescription: DiagnosticMessage, codeFixDescription: DiagnosticMessage, includeLib?: boolean) {
|
||||
const t = getTest(text);
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, includeLib?: boolean, expectFailure = false) {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection")!;
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
|
||||
[Extension.Ts, Extension.Js].forEach(extension =>
|
||||
const extensions = expectFailure ? [Extension.Ts] : [Extension.Ts, Extension.Js];
|
||||
|
||||
extensions.forEach(extension =>
|
||||
it(`${caption} [${extension}]`, () => runBaseline(extension)));
|
||||
|
||||
function runBaseline(extension: Extension) {
|
||||
const path = "/a" + extension;
|
||||
const program = makeProgram({ path, content: t.source }, includeLib)!;
|
||||
const languageService = makeLanguageService({ path, content: t.source }, includeLib);
|
||||
const program = languageService.getProgram()!;
|
||||
|
||||
if (hasSyntacticDiagnostics(program)) {
|
||||
// Don't bother generating JS baselines for inputs that aren't valid JS.
|
||||
@ -345,10 +284,6 @@ interface Array<T> {}`
|
||||
};
|
||||
|
||||
const sourceFile = program.getSourceFile(path)!;
|
||||
const host = projectSystem.createServerHost([f, libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const languageService = projectService.inferredProjects[0].getLanguageService();
|
||||
const context: CodeFixContext = {
|
||||
errorCode: 80006,
|
||||
span: { start: selectionRange.pos, length: selectionRange.end - selectionRange.pos },
|
||||
@ -361,37 +296,45 @@ interface Array<T> {}`
|
||||
};
|
||||
|
||||
const diagnostics = languageService.getSuggestionDiagnostics(f.path);
|
||||
const diagnostic = find(diagnostics, diagnostic => diagnostic.messageText === diagnosticDescription.message);
|
||||
assert.exists(diagnostic);
|
||||
assert.equal(diagnostic!.start, context.span.start);
|
||||
assert.equal(diagnostic!.length, context.span.length);
|
||||
const diagnostic = find(diagnostics, diagnostic => diagnostic.messageText === Diagnostics.This_may_be_converted_to_an_async_function.message &&
|
||||
diagnostic.start === context.span.start && diagnostic.length === context.span.length);
|
||||
if (expectFailure) {
|
||||
assert.isUndefined(diagnostic);
|
||||
}
|
||||
else {
|
||||
assert.exists(diagnostic);
|
||||
}
|
||||
|
||||
const actions = codefix.getFixes(context);
|
||||
const action = find(actions, action => action.description === codeFixDescription.message)!;
|
||||
assert.exists(action);
|
||||
const action = find(actions, action => action.description === Diagnostics.Convert_to_async_function.message);
|
||||
if (expectFailure) {
|
||||
assert.isNotTrue(action && action.changes.length > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
assert.isTrue(action && action.changes.length > 0);
|
||||
|
||||
const data: string[] = [];
|
||||
data.push(`// ==ORIGINAL==`);
|
||||
data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/"));
|
||||
const changes = action.changes;
|
||||
const changes = action!.changes;
|
||||
assert.lengthOf(changes, 1);
|
||||
|
||||
data.push(`// ==ASYNC FUNCTION::${action.description}==`);
|
||||
data.push(`// ==ASYNC FUNCTION::${action!.description}==`);
|
||||
const newText = textChanges.applyChanges(sourceFile.text, changes[0].textChanges);
|
||||
data.push(newText);
|
||||
|
||||
const diagProgram = makeProgram({ path, content: newText }, includeLib)!;
|
||||
const diagProgram = makeLanguageService({ path, content: newText }, includeLib).getProgram()!;
|
||||
assert.isFalse(hasSyntacticDiagnostics(diagProgram));
|
||||
Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, data.join(newLineCharacter));
|
||||
}
|
||||
|
||||
function makeProgram(f: { path: string, content: string }, includeLib?: boolean) {
|
||||
function makeLanguageService(f: { path: string, content: string }, includeLib?: boolean) {
|
||||
|
||||
const host = projectSystem.createServerHost(includeLib ? [f, libFile] : [f]); // libFile is expensive to parse repeatedly - only test when required
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
return program;
|
||||
return projectService.inferredProjects[0].getLanguageService();
|
||||
}
|
||||
|
||||
function hasSyntacticDiagnostics(program: Program) {
|
||||
@ -400,27 +343,6 @@ interface Array<T> {}`
|
||||
}
|
||||
}
|
||||
|
||||
function testConvertToAsyncFunctionFailed(caption: string, text: string, description: DiagnosticMessage) {
|
||||
it(caption, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f, libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const languageService = projectService.inferredProjects[0].getLanguageService();
|
||||
|
||||
const actions = languageService.getSuggestionDiagnostics(f.path);
|
||||
assert.isUndefined(find(actions, action => action.messageText === description.message));
|
||||
});
|
||||
}
|
||||
|
||||
describe("convertToAsyncFunctions", () => {
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_basic", `
|
||||
function [#|f|](): Promise<void>{
|
||||
@ -545,6 +467,12 @@ function [#|f|]():Promise<void | Response> {
|
||||
function [#|f|]():Promise<void | Response> {
|
||||
return fetch('https://typescriptlang.org').catch(rej => console.log(rej));
|
||||
}
|
||||
`
|
||||
);
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_NoRes4", `
|
||||
function [#|f|]() {
|
||||
return fetch('https://typescriptlang.org').then(undefined, rejection => console.log("rejected:", rejection));
|
||||
}
|
||||
`
|
||||
);
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestion", `
|
||||
@ -1157,7 +1085,7 @@ function [#|f|]() {
|
||||
`
|
||||
);
|
||||
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_NestedFunction", `
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_NestedFunctionWrongLocation", `
|
||||
function [#|f|]() {
|
||||
function fn2(){
|
||||
function fn3(){
|
||||
@ -1167,6 +1095,18 @@ function [#|f|]() {
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_NestedFunctionRightLocation", `
|
||||
function f() {
|
||||
function fn2(){
|
||||
function [#|fn3|](){
|
||||
return fetch("https://typescriptlang.org").then(res => console.log(res));
|
||||
}
|
||||
return fn3();
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_UntypedFunction", `
|
||||
@ -1194,14 +1134,26 @@ const [#|foo|] = function () {
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunction", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve().then(f ? (x => x) : (y => y));
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunctionNotLastInChain", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve().then(f ? (x => x) : (y => y)).then(q => q);
|
||||
}
|
||||
`);
|
||||
|
||||
|
||||
});
|
||||
|
||||
function _testConvertToAsyncFunction(caption: string, text: string) {
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", Diagnostics.This_may_be_converted_to_an_async_function, Diagnostics.Convert_to_async_function, /*includeLib*/ true);
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true);
|
||||
}
|
||||
|
||||
function _testConvertToAsyncFunctionFailed(caption: string, text: string) {
|
||||
testConvertToAsyncFunctionFailed(caption, text, Diagnostics.Convert_to_async_function);
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true);
|
||||
}
|
||||
}
|
||||
@ -83,7 +83,7 @@ namespace ts {
|
||||
describe("Node module resolution - relative paths", () => {
|
||||
|
||||
function testLoadAsFile(containingFileName: string, moduleFileNameNoExt: string, moduleName: string): void {
|
||||
for (const ext of supportedTypescriptExtensions) {
|
||||
for (const ext of supportedTSExtensions) {
|
||||
test(ext, /*hasDirectoryExists*/ false);
|
||||
test(ext, /*hasDirectoryExists*/ true);
|
||||
}
|
||||
@ -96,7 +96,7 @@ namespace ts {
|
||||
|
||||
const failedLookupLocations: string[] = [];
|
||||
const dir = getDirectoryPath(containingFileName);
|
||||
for (const e of supportedTypescriptExtensions) {
|
||||
for (const e of supportedTSExtensions) {
|
||||
if (e === ext) {
|
||||
break;
|
||||
}
|
||||
@ -137,7 +137,7 @@ namespace ts {
|
||||
const resolution = nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile));
|
||||
checkResolvedModule(resolution.resolvedModule, createResolvedModule(moduleFile.name));
|
||||
// expect three failed lookup location - attempt to load module as file with all supported extensions
|
||||
assert.equal(resolution.failedLookupLocations.length, supportedTypescriptExtensions.length);
|
||||
assert.equal(resolution.failedLookupLocations.length, supportedTSExtensions.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -199,7 +199,7 @@ namespace ts {
|
||||
tick();
|
||||
touch(fs, "/src/logic/index.ts");
|
||||
// Because we haven't reset the build context, the builder should assume there's nothing to do right now
|
||||
const status = builder.getUpToDateStatusOfFile(builder.resolveProjectName("/src/logic")!);
|
||||
const status = builder.getUpToDateStatusOfFile(builder.resolveProjectName("/src/logic"));
|
||||
assert.equal(status.type, UpToDateStatusType.UpToDate, "Project should be assumed to be up-to-date");
|
||||
|
||||
// Rebuild this project
|
||||
@ -210,10 +210,26 @@ namespace ts {
|
||||
assert.equal(fs.statSync("/src/logic/index.js").mtimeMs, time(), "JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should *not* have been rebuilt");
|
||||
|
||||
// Does not build tests or core because there is no change in declaration file
|
||||
tick();
|
||||
builder.buildInvalidatedProject();
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/core/index.js").mtimeMs, time(), "Upstream JS file should not have been rebuilt");
|
||||
|
||||
// Rebuild this project
|
||||
tick();
|
||||
fs.writeFileSync("/src/logic/index.ts", `${fs.readFileSync("/src/logic/index.ts")}
|
||||
export class cNew {}`);
|
||||
builder.invalidateProject("/src/logic");
|
||||
builder.buildInvalidatedProject();
|
||||
// The file should be updated
|
||||
assert.equal(fs.statSync("/src/logic/index.js").mtimeMs, time(), "JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should *not* have been rebuilt");
|
||||
|
||||
// Build downstream projects should update 'tests', but not 'core'
|
||||
tick();
|
||||
builder.buildInvalidatedProject();
|
||||
assert.equal(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(fs.statSync("/src/core/index.js").mtimeMs, time(), "Upstream JS file should not have been rebuilt");
|
||||
});
|
||||
});
|
||||
@ -248,6 +264,63 @@ namespace ts {
|
||||
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withIncludeAndFiles.json");
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - lists files", () => {
|
||||
it("listFiles", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { listFiles: true });
|
||||
builder.buildAllProjects();
|
||||
assert.deepEqual(host.traces, [
|
||||
...getLibs(),
|
||||
"/src/core/anotherModule.ts",
|
||||
"/src/core/index.ts",
|
||||
"/src/core/some_decl.d.ts",
|
||||
...getLibs(),
|
||||
...getCoreOutputs(),
|
||||
"/src/logic/index.ts",
|
||||
...getLibs(),
|
||||
...getCoreOutputs(),
|
||||
"/src/logic/index.d.ts",
|
||||
"/src/tests/index.ts"
|
||||
]);
|
||||
|
||||
function getLibs() {
|
||||
return [
|
||||
"/lib/lib.d.ts",
|
||||
"/lib/lib.es5.d.ts",
|
||||
"/lib/lib.dom.d.ts",
|
||||
"/lib/lib.webworker.importscripts.d.ts",
|
||||
"/lib/lib.scripthost.d.ts"
|
||||
];
|
||||
}
|
||||
|
||||
function getCoreOutputs() {
|
||||
return [
|
||||
"/src/core/index.d.ts",
|
||||
"/src/core/anotherModule.d.ts"
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
it("listEmittedFiles", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { listEmittedFiles: true });
|
||||
builder.buildAllProjects();
|
||||
assert.deepEqual(host.traces, [
|
||||
"TSFILE: /src/core/anotherModule.js",
|
||||
"TSFILE: /src/core/anotherModule.d.ts",
|
||||
"TSFILE: /src/core/index.js",
|
||||
"TSFILE: /src/core/index.d.ts",
|
||||
"TSFILE: /src/logic/index.js",
|
||||
"TSFILE: /src/logic/index.js.map",
|
||||
"TSFILE: /src/logic/index.d.ts",
|
||||
"TSFILE: /src/tests/index.js",
|
||||
"TSFILE: /src/tests/index.d.ts",
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export namespace OutFile {
|
||||
@ -377,7 +450,6 @@ namespace ts {
|
||||
|
||||
const projFileNames = rootNames.map(getProjectFileName);
|
||||
const graph = builder.getBuildGraph(projFileNames);
|
||||
if (graph === undefined) throw new Error("Graph shouldn't be undefined");
|
||||
|
||||
assert.sameMembers(graph.buildQueue, expectedBuildSet.map(getProjectFileName));
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ namespace ts.tscWatch {
|
||||
export import libFile = TestFSWithWatch.libFile;
|
||||
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
const host = createSolutionBuilderWithWatchHost(system);
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { dry: false, force: false, verbose: false, watch: true });
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { watch: true });
|
||||
}
|
||||
|
||||
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
@ -26,8 +26,12 @@ namespace ts.tscWatch {
|
||||
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
|
||||
const root = Harness.IO.getWorkspaceRoot();
|
||||
|
||||
function projectPath(subProject: SubProject) {
|
||||
return `${projectsLocation}/${project}/${subProject}`;
|
||||
}
|
||||
|
||||
function projectFilePath(subProject: SubProject, baseFileName: string) {
|
||||
return `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`;
|
||||
return `${projectPath(subProject)}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
@ -58,13 +62,17 @@ namespace ts.tscWatch {
|
||||
return getOutputFileNames(subProject, baseFileNameWithoutExtension).map(f => [f, host.getModifiedTime(f)] as OutputFileStamp);
|
||||
}
|
||||
|
||||
function getOutputFileStamps(host: WatchedSystem): OutputFileStamp[] {
|
||||
return [
|
||||
function getOutputFileStamps(host: WatchedSystem, additionalFiles?: ReadonlyArray<[SubProject, string]>): OutputFileStamp[] {
|
||||
const result = [
|
||||
...getOutputStamps(host, SubProject.core, "anotherModule"),
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
...getOutputStamps(host, SubProject.tests, "index"),
|
||||
];
|
||||
if (additionalFiles) {
|
||||
additionalFiles.forEach(([subProject, baseFileNameWithoutExtension]) => result.push(...getOutputStamps(host, subProject, baseFileNameWithoutExtension)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function verifyChangedFiles(actualStamps: OutputFileStamp[], oldTimeStamps: OutputFileStamp[], changedFiles: string[]) {
|
||||
@ -87,76 +95,306 @@ namespace ts.tscWatch {
|
||||
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
|
||||
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
|
||||
|
||||
function createSolutionInWatchMode() {
|
||||
function createSolutionInWatchMode(allFiles: ReadonlyArray<File>, defaultOptions?: BuildOptions, disableConsoleClears?: boolean) {
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ true); // TODO: #26524
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`], defaultOptions);
|
||||
verifyWatches(host);
|
||||
checkOutputErrorsInitial(host, emptyArray, disableConsoleClears);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
function verifyWatches(host: WatchedSystem) {
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
}
|
||||
|
||||
it("creates solution in watch mode", () => {
|
||||
createSolutionInWatchMode();
|
||||
createSolutionInWatchMode(allFiles);
|
||||
});
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const host = createSolutionInWatchMode();
|
||||
verifyChange(`${core[1].content}
|
||||
describe("validates the changes and watched files", () => {
|
||||
const newFileWithoutExtension = "newFile";
|
||||
const newFile: File = {
|
||||
path: projectFilePath(SubProject.core, `${newFileWithoutExtension}.ts`),
|
||||
content: `export const newFileConst = 30;`
|
||||
};
|
||||
|
||||
function verifyProjectChanges(allFiles: ReadonlyArray<File>) {
|
||||
function createSolutionInWatchModeToVerifyChanges(additionalFiles?: ReadonlyArray<[SubProject, string]>) {
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
return { host, verifyChangeWithFile, verifyChangeAfterTimeout, verifyWatches };
|
||||
|
||||
function verifyChangeWithFile(fileName: string, content: string) {
|
||||
const outputFileStamps = getOutputFileStamps(host, additionalFiles);
|
||||
host.writeFile(fileName, content);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
}
|
||||
|
||||
function verifyChangeAfterTimeout(outputFileStamps: OutputFileStamp[]) {
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host, additionalFiles);
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index"),
|
||||
...(additionalFiles ? getOutputFileNames(SubProject.core, newFileWithoutExtension) : emptyArray)
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host, additionalFiles);
|
||||
verifyChangedFiles(changedLogic, changedCore, [
|
||||
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host, additionalFiles);
|
||||
verifyChangedFiles(changedTests, changedLogic, [
|
||||
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const { host, verifyChangeWithFile, verifyChangeAfterTimeout } = createSolutionInWatchModeToVerifyChanges();
|
||||
verifyChange(`${core[1].content}
|
||||
export class someClass { }`);
|
||||
|
||||
// Another change requeues and builds it
|
||||
verifyChange(core[1].content);
|
||||
// Another change requeues and builds it
|
||||
verifyChange(core[1].content);
|
||||
|
||||
// Two changes together report only single time message: File change detected. Starting incremental compilation...
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
const change1 = `${core[1].content}
|
||||
// Two changes together report only single time message: File change detected. Starting incremental compilation...
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
const change1 = `${core[1].content}
|
||||
export class someClass { }`;
|
||||
host.writeFile(core[1].path, change1);
|
||||
host.writeFile(core[1].path, `${change1}
|
||||
host.writeFile(core[1].path, change1);
|
||||
host.writeFile(core[1].path, `${change1}
|
||||
export class someClass2 { }`);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
|
||||
function verifyChange(coreContent: string) {
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
host.writeFile(core[1].path, coreContent);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
function verifyChange(coreContent: string) {
|
||||
verifyChangeWithFile(core[1].path, coreContent);
|
||||
}
|
||||
});
|
||||
|
||||
it("non local change does not start build of referencing projects", () => {
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
function foo() { }`);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index"),
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches(host);
|
||||
});
|
||||
|
||||
it("builds when new file is added, and its subsequent updates", () => {
|
||||
const additinalFiles: ReadonlyArray<[SubProject, string]> = [[SubProject.core, newFileWithoutExtension]];
|
||||
const { verifyChangeWithFile } = createSolutionInWatchModeToVerifyChanges(additinalFiles);
|
||||
verifyChange(newFile.content);
|
||||
|
||||
// Another change requeues and builds it
|
||||
verifyChange(`${newFile.content}
|
||||
export class someClass2 { }`);
|
||||
|
||||
function verifyChange(newFileContent: string) {
|
||||
verifyChangeWithFile(newFile.path, newFileContent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifyChangeAfterTimeout(outputFileStamps: OutputFileStamp[]) {
|
||||
describe("with simple project reference graph", () => {
|
||||
verifyProjectChanges(allFiles);
|
||||
});
|
||||
|
||||
describe("with circular project reference", () => {
|
||||
const [coreTsconfig, ...otherCoreFiles] = core;
|
||||
const circularCoreConfig: File = {
|
||||
path: coreTsconfig.path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true },
|
||||
references: [{ path: "../tests", circular: true }]
|
||||
})
|
||||
};
|
||||
verifyProjectChanges([libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests]);
|
||||
});
|
||||
});
|
||||
|
||||
it("watches config files that are not present", () => {
|
||||
const allFiles = [libFile, ...core, logic[1], ...tests];
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
checkWatchedFiles(host, [core[0], core[1], core[2], logic[0], ...tests].map(f => f.path));
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core)], /*recursive*/ true);
|
||||
checkOutputErrorsInitial(host, [
|
||||
createCompilerDiagnostic(Diagnostics.File_0_not_found, logic[0].path)
|
||||
]);
|
||||
for (const f of [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"),
|
||||
...getOutputFileNames(SubProject.core, "index")
|
||||
]) {
|
||||
assert.isTrue(host.fileExists(f), `${f} expected to be present`);
|
||||
}
|
||||
for (const f of [
|
||||
...getOutputFileNames(SubProject.logic, "index"),
|
||||
...getOutputFileNames(SubProject.tests, "index")
|
||||
]) {
|
||||
assert.isFalse(host.fileExists(f), `${f} expected to be absent`);
|
||||
}
|
||||
|
||||
// Create tsconfig file for logic and see that build succeeds
|
||||
const initial = getOutputFileStamps(host);
|
||||
host.writeFile(logic[0].path, logic[0].content);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, initial, [
|
||||
...getOutputFileNames(SubProject.logic, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedTests, changedLogic, [
|
||||
...getOutputFileNames(SubProject.tests, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches(host);
|
||||
});
|
||||
|
||||
it("when referenced using prepend, builds referencing project even for non local change", () => {
|
||||
const coreTsConfig: File = {
|
||||
path: core[0].path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, outFile: "index.js" }
|
||||
})
|
||||
};
|
||||
const coreIndex: File = {
|
||||
path: core[1].path,
|
||||
content: `function foo() { return 10; }`
|
||||
};
|
||||
const logicTsConfig: File = {
|
||||
path: logic[0].path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, outFile: "index.js" },
|
||||
references: [{ path: "../core", prepend: true }]
|
||||
})
|
||||
};
|
||||
const logicIndex: File = {
|
||||
path: logic[1].path,
|
||||
content: `function bar() { return foo() + 1 };`
|
||||
};
|
||||
|
||||
const projectFiles = [coreTsConfig, coreIndex, logicTsConfig, logicIndex];
|
||||
const host = createWatchedSystem([libFile, ...projectFiles], { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.logic}`]);
|
||||
verifyWatches();
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
const outputFileStamps = getOutputFileStamps();
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
|
||||
// Make non local change
|
||||
verifyChangeInCore(`${coreIndex.content}
|
||||
function myFunc() { return 10; }`);
|
||||
|
||||
// Make local change to function bar
|
||||
verifyChangeInCore(`${coreIndex.content}
|
||||
function myFunc() { return 100; }`);
|
||||
|
||||
function verifyChangeInCore(content: string) {
|
||||
const outputFileStamps = getOutputFileStamps();
|
||||
host.writeFile(coreIndex.path, content);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
const changedCore = getOutputFileStamps();
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedTests, changedCore, [
|
||||
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, changedTests, [
|
||||
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
|
||||
const changedLogic = getOutputFileStamps();
|
||||
verifyChangedFiles(changedLogic, changedCore, [
|
||||
...getOutputFileNames(SubProject.logic, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches();
|
||||
}
|
||||
|
||||
function getOutputFileStamps(): OutputFileStamp[] {
|
||||
const result = [
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
];
|
||||
return result;
|
||||
}
|
||||
|
||||
function verifyWatches() {
|
||||
checkWatchedFiles(host, projectFiles.map(f => f.path));
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
}
|
||||
});
|
||||
|
||||
describe("reports errors in all projects on incremental compile", () => {
|
||||
function verifyIncrementalErrors(defaultBuildOptions?: BuildOptions, disabledConsoleClear?: boolean) {
|
||||
const host = createSolutionInWatchMode(allFiles, defaultBuildOptions, disabledConsoleClear);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
|
||||
host.writeFile(logic[1].path, `${logic[1].content}
|
||||
let y: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, outputFileStamps, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
], disabledConsoleClear);
|
||||
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
let x: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, changedLogic, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/core/index.ts(5,5): error TS2322: Type '10' is not assignable to type 'string'.\n`,
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
], disabledConsoleClear);
|
||||
}
|
||||
|
||||
it("when preserveWatchOutput is not used", () => {
|
||||
verifyIncrementalErrors();
|
||||
});
|
||||
|
||||
it("when preserveWatchOutput is passed on command line", () => {
|
||||
verifyIncrementalErrors({ preserveWatchOutput: true, watch: true }, /*disabledConsoleClear*/ true);
|
||||
});
|
||||
});
|
||||
|
||||
it("tsc-watch works with project references", () => {
|
||||
// Build the composite project
|
||||
const host = createSolutionInWatchMode();
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
|
||||
createWatchOfConfigFile(tests[0].path, host);
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
});
|
||||
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
});
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ namespace ts.tscWatch {
|
||||
logsBeforeWatchDiagnostic: string[] | undefined,
|
||||
preErrorsWatchDiagnostic: Diagnostic,
|
||||
logsBeforeErrors: string[] | undefined,
|
||||
errors: ReadonlyArray<Diagnostic>,
|
||||
errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>,
|
||||
disableConsoleClears?: boolean | undefined,
|
||||
...postErrorsWatchDiagnostics: Diagnostic[]
|
||||
) {
|
||||
@ -96,8 +96,12 @@ namespace ts.tscWatch {
|
||||
assert.equal(host.screenClears.length, screenClears, "Expected number of screen clears");
|
||||
host.clearOutput();
|
||||
|
||||
function assertDiagnostic(diagnostic: Diagnostic) {
|
||||
const expected = formatDiagnostic(diagnostic, host);
|
||||
function isDiagnostic(diagnostic: Diagnostic | string): diagnostic is Diagnostic {
|
||||
return !!(diagnostic as Diagnostic).messageText;
|
||||
}
|
||||
|
||||
function assertDiagnostic(diagnostic: Diagnostic | string) {
|
||||
const expected = isDiagnostic(diagnostic) ? formatDiagnostic(diagnostic, host) : diagnostic;
|
||||
assert.equal(outputs[index], expected, getOutputAtFailedMessage("Diagnostic", expected));
|
||||
index++;
|
||||
}
|
||||
@ -130,13 +134,13 @@ namespace ts.tscWatch {
|
||||
}
|
||||
}
|
||||
|
||||
function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray<Diagnostic>) {
|
||||
function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>) {
|
||||
return errors.length === 1
|
||||
? createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes)
|
||||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
}
|
||||
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
@ -147,7 +151,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
@ -158,7 +162,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
|
||||
@ -3136,7 +3136,7 @@ namespace ts.projectSystem {
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isDefined(project);
|
||||
checkProjectActualFiles(project, [file1.path, libFile.path, module1.path, module2.path, configFile.path]);
|
||||
checkWatchedFiles(host, [libFile.path, module1.path, module2.path, configFile.path]);
|
||||
checkWatchedFiles(host, [libFile.path, configFile.path]);
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
const watchedRecursiveDirectories = getTypeRootsFromLocation(root + "/a/b/src");
|
||||
watchedRecursiveDirectories.push(`${root}/a/b/src/node_modules`, `${root}/a/b/node_modules`);
|
||||
@ -7435,7 +7435,7 @@ namespace ts.projectSystem {
|
||||
const projectFilePaths = map(projectFiles, f => f.path);
|
||||
checkProjectActualFiles(project, projectFilePaths);
|
||||
|
||||
const filesWatched = filter(projectFilePaths, p => p !== app.path);
|
||||
const filesWatched = filter(projectFilePaths, p => p !== app.path && p.indexOf("/a/b/node_modules") === -1);
|
||||
checkWatchedFiles(host, filesWatched);
|
||||
checkWatchedDirectories(host, typeRootDirectories.concat(recursiveWatchedDirectories), /*recursive*/ true);
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
@ -8658,10 +8658,21 @@ new C();`
|
||||
}
|
||||
|
||||
function verifyWatchesWithConfigFile(host: TestServerHost, files: File[], openFile: File, extraExpectedDirectories?: ReadonlyArray<string>) {
|
||||
checkWatchedFiles(host, mapDefined(files, f => f === openFile ? undefined : f.path));
|
||||
const expectedRecursiveDirectories = arrayToSet([projectLocation, `${projectLocation}/${nodeModulesAtTypes}`, ...(extraExpectedDirectories || emptyArray)]);
|
||||
checkWatchedFiles(host, mapDefined(files, f => {
|
||||
if (f === openFile) {
|
||||
return undefined;
|
||||
}
|
||||
const indexOfNodeModules = f.path.indexOf("/node_modules/");
|
||||
if (indexOfNodeModules === -1) {
|
||||
return f.path;
|
||||
}
|
||||
expectedRecursiveDirectories.set(f.path.substr(0, indexOfNodeModules + "/node_modules".length), true);
|
||||
return undefined;
|
||||
}));
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectLocation, `${projectLocation}/${nodeModulesAtTypes}`, ...(extraExpectedDirectories || emptyArray)], /*recursive*/ true);
|
||||
}
|
||||
checkWatchedDirectories(host, arrayFrom(expectedRecursiveDirectories.keys()), /*recursive*/ true);
|
||||
}
|
||||
|
||||
describe("from files in same folder", () => {
|
||||
function getFiles(fileContent: string) {
|
||||
@ -8862,7 +8873,7 @@ new C();`
|
||||
verifyTrace(resolutionTrace, expectedTrace);
|
||||
|
||||
const currentDirectory = getDirectoryPath(file1.path);
|
||||
const watchedFiles = mapDefined(files, f => f === file1 ? undefined : f.path);
|
||||
const watchedFiles = mapDefined(files, f => f === file1 || f.path.indexOf("/node_modules/") !== -1 ? undefined : f.path);
|
||||
forEachAncestorDirectory(currentDirectory, d => {
|
||||
watchedFiles.push(combinePaths(d, "tsconfig.json"), combinePaths(d, "jsconfig.json"));
|
||||
});
|
||||
|
||||
@ -53,14 +53,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) {
|
||||
const result = performBuild(args.slice(1));
|
||||
// undefined = in watch mode, do not exit
|
||||
if (result !== undefined) {
|
||||
return sys.exit(result);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
if (args.length > 0 && args[0].charCodeAt(0) === CharacterCodes.minus) {
|
||||
const firstOption = args[0].slice(args[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
|
||||
if (firstOption === "build" || firstOption === "b") {
|
||||
return performBuild(args.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,40 +160,30 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function performBuild(args: string[]): number | undefined {
|
||||
const { buildOptions, projects: buildProjects, errors } = parseBuildCommand(args);
|
||||
function performBuild(args: string[]) {
|
||||
const { buildOptions, projects, errors } = parseBuildCommand(args);
|
||||
if (errors.length > 0) {
|
||||
errors.forEach(reportDiagnostic);
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
if (buildOptions.help) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
return sys.exit(ExitStatus.Success);
|
||||
}
|
||||
|
||||
// Update to pretty if host supports it
|
||||
updateReportDiagnostic();
|
||||
const projects = mapDefined(buildProjects, project => {
|
||||
const fileName = resolvePath(sys.getCurrentDirectory(), project);
|
||||
const refPath = resolveProjectReferencePath(sys, { path: fileName });
|
||||
if (!sys.fileExists(refPath)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_does_not_exist, fileName));
|
||||
return undefined;
|
||||
}
|
||||
return refPath;
|
||||
});
|
||||
|
||||
if (projects.length === 0) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
return sys.exit(ExitStatus.Success);
|
||||
}
|
||||
|
||||
if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
|
||||
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
if (buildOptions.watch) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
@ -206,16 +192,15 @@ namespace ts {
|
||||
// TODO: change this to host if watch => watchHost otherwiue without wathc
|
||||
const builder = createSolutionBuilder(createSolutionBuilderWithWatchHost(sys, reportDiagnostic, createBuilderStatusReporter(sys, shouldBePretty()), createWatchStatusReporter()), projects, buildOptions);
|
||||
if (buildOptions.clean) {
|
||||
return builder.cleanAllProjects();
|
||||
return sys.exit(builder.cleanAllProjects());
|
||||
}
|
||||
|
||||
if (buildOptions.watch) {
|
||||
builder.buildAllProjects();
|
||||
builder.startWatching();
|
||||
return undefined;
|
||||
return builder.startWatching();
|
||||
}
|
||||
|
||||
return builder.buildAllProjects();
|
||||
return sys.exit(builder.buildAllProjects());
|
||||
}
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
|
||||
@ -891,7 +891,7 @@ namespace ts.server {
|
||||
|
||||
sys.require = (initialDir: string, moduleName: string): RequireResult => {
|
||||
try {
|
||||
return { module: require(resolveJavascriptModule(moduleName, initialDir, sys)), error: undefined };
|
||||
return { module: require(resolveJSModule(moduleName, initialDir, sys)), error: undefined };
|
||||
}
|
||||
catch (error) {
|
||||
return { module: undefined, error };
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"0": {
|
||||
"kind": "JSDocTag",
|
||||
"pos": 63,
|
||||
"end": 68,
|
||||
"end": 67,
|
||||
"atToken": {
|
||||
"kind": "AtToken",
|
||||
"pos": 63,
|
||||
@ -22,7 +22,7 @@
|
||||
},
|
||||
"length": 1,
|
||||
"pos": 63,
|
||||
"end": 68
|
||||
"end": 67
|
||||
},
|
||||
"comment": "{@link first link}\nInside {@link link text} thing"
|
||||
}
|
||||
@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@ -31,7 +31,7 @@
|
||||
}
|
||||
},
|
||||
"length": 1,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19
|
||||
}
|
||||
},
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 21
|
||||
}
|
||||
},
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 23
|
||||
}
|
||||
},
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 24
|
||||
},
|
||||
"comment": "Description of type parameters."
|
||||
|
||||
@ -2585,7 +2585,6 @@ declare namespace ts {
|
||||
}
|
||||
interface ExpandResult {
|
||||
fileNames: string[];
|
||||
projectReferences: ReadonlyArray<ProjectReference> | undefined;
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
}
|
||||
interface CreateProgramOptions {
|
||||
@ -4184,14 +4183,11 @@ declare namespace ts {
|
||||
* @returns A 'Program' object.
|
||||
*/
|
||||
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
|
||||
interface ResolveProjectReferencePathHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
}
|
||||
/**
|
||||
* Returns the target config filename of a project reference.
|
||||
* Note: The file might not exist.
|
||||
*/
|
||||
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
|
||||
function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
|
||||
}
|
||||
declare namespace ts {
|
||||
interface EmitOutput {
|
||||
@ -8385,6 +8381,7 @@ declare namespace ts.server {
|
||||
* Container of all known scripts
|
||||
*/
|
||||
private readonly filenameToScriptInfo;
|
||||
private readonly scriptInfoInNodeModulesWatchers;
|
||||
/**
|
||||
* Contains all the deleted script info's version information so that
|
||||
* it does not reset when creating script info again
|
||||
@ -8555,6 +8552,10 @@ declare namespace ts.server {
|
||||
private createInferredProject;
|
||||
getScriptInfo(uncheckedFileName: string): ScriptInfo | undefined;
|
||||
private watchClosedScriptInfo;
|
||||
private watchClosedScriptInfoInNodeModules;
|
||||
private getModifiedTime;
|
||||
private refreshScriptInfo;
|
||||
private refreshScriptInfosInDirectory;
|
||||
private stopWatchingScriptInfo;
|
||||
private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath;
|
||||
private getOrCreateScriptInfoOpenedByClientForNormalizedPath;
|
||||
|
||||
@ -2585,7 +2585,6 @@ declare namespace ts {
|
||||
}
|
||||
interface ExpandResult {
|
||||
fileNames: string[];
|
||||
projectReferences: ReadonlyArray<ProjectReference> | undefined;
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
}
|
||||
interface CreateProgramOptions {
|
||||
@ -4184,14 +4183,11 @@ declare namespace ts {
|
||||
* @returns A 'Program' object.
|
||||
*/
|
||||
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
|
||||
interface ResolveProjectReferencePathHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
}
|
||||
/**
|
||||
* Returns the target config filename of a project reference.
|
||||
* Note: The file might not exist.
|
||||
*/
|
||||
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
|
||||
function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
|
||||
}
|
||||
declare namespace ts {
|
||||
interface EmitOutput {
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function f() {
|
||||
function fn2(){
|
||||
function /*[#|*/fn3/*|]*/(){
|
||||
return fetch("https://typescriptlang.org").then(res => console.log(res));
|
||||
}
|
||||
return fn3();
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
function f() {
|
||||
function fn2(){
|
||||
async function fn3(){
|
||||
const res = await fetch("https://typescriptlang.org");
|
||||
return console.log(res);
|
||||
}
|
||||
return fn3();
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function f() {
|
||||
function fn2(){
|
||||
function /*[#|*/fn3/*|]*/(){
|
||||
return fetch("https://typescriptlang.org").then(res => console.log(res));
|
||||
}
|
||||
return fn3();
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
function f() {
|
||||
function fn2(){
|
||||
async function fn3(){
|
||||
const res = await fetch("https://typescriptlang.org");
|
||||
return console.log(res);
|
||||
}
|
||||
return fn3();
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return fetch('https://typescriptlang.org').then(undefined, rejection => console.log("rejected:", rejection));
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function f() {
|
||||
try {
|
||||
await fetch('https://typescriptlang.org');
|
||||
}
|
||||
catch (rejection) {
|
||||
return console.log("rejected:", rejection);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return fetch('https://typescriptlang.org').then(undefined, rejection => console.log("rejected:", rejection));
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function f() {
|
||||
try {
|
||||
await fetch('https://typescriptlang.org');
|
||||
}
|
||||
catch (rejection) {
|
||||
return console.log("rejected:", rejection);
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,7 @@ tests/cases/conformance/jsdoc/a.js(37,16): error TS2339: Property 'UNKNOWN' does
|
||||
/** @type {number} */
|
||||
OK_I_GUESS: 2
|
||||
}
|
||||
/** @enum {number} */
|
||||
/** @enum number */
|
||||
const Second = {
|
||||
MISTAKE: "end",
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
@ -19,7 +19,7 @@ const Target = {
|
||||
OK_I_GUESS: 2
|
||||
>OK_I_GUESS : Symbol(OK_I_GUESS, Decl(a.js, 5, 15))
|
||||
}
|
||||
/** @enum {number} */
|
||||
/** @enum number */
|
||||
const Second = {
|
||||
>Second : Symbol(Second, Decl(a.js, 10, 5))
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ const Target = {
|
||||
>OK_I_GUESS : number
|
||||
>2 : 2
|
||||
}
|
||||
/** @enum {number} */
|
||||
/** @enum number */
|
||||
const Second = {
|
||||
>Second : { MISTAKE: string; OK: number; FINE: number; }
|
||||
>{ MISTAKE: "end", OK: 1, /** @type {number} */ FINE: 2,} : { MISTAKE: string; OK: number; FINE: number; }
|
||||
|
||||
@ -67,4 +67,8 @@ tests/cases/compiler/jsdocInTypeScript.ts(42,12): error TS2503: Cannot find name
|
||||
* @type {{foo: (function(string, string): string)}}
|
||||
*/
|
||||
const obj = { foo: (a, b) => a + b };
|
||||
|
||||
/** @enum {string} */
|
||||
var E = {};
|
||||
E[""];
|
||||
|
||||
@ -47,6 +47,10 @@ import M = N; // Error: @typedef does not create namespaces in TypeScript code.
|
||||
* @type {{foo: (function(string, string): string)}}
|
||||
*/
|
||||
const obj = { foo: (a, b) => a + b };
|
||||
|
||||
/** @enum {string} */
|
||||
var E = {};
|
||||
E[""];
|
||||
|
||||
|
||||
//// [jsdocInTypeScript.js]
|
||||
@ -79,3 +83,6 @@ var M = N; // Error: @typedef does not create namespaces in TypeScript code.
|
||||
* @type {{foo: (function(string, string): string)}}
|
||||
*/
|
||||
var obj = { foo: function (a, b) { return a + b; } };
|
||||
/** @enum {string} */
|
||||
var E = {};
|
||||
E[""];
|
||||
|
||||
@ -83,3 +83,10 @@ const obj = { foo: (a, b) => a + b };
|
||||
>a : Symbol(a, Decl(jsdocInTypeScript.ts, 47, 20))
|
||||
>b : Symbol(b, Decl(jsdocInTypeScript.ts, 47, 22))
|
||||
|
||||
/** @enum {string} */
|
||||
var E = {};
|
||||
>E : Symbol(E, Decl(jsdocInTypeScript.ts, 50, 3))
|
||||
|
||||
E[""];
|
||||
>E : Symbol(E, Decl(jsdocInTypeScript.ts, 50, 3))
|
||||
|
||||
|
||||
@ -93,3 +93,13 @@ const obj = { foo: (a, b) => a + b };
|
||||
>a : any
|
||||
>b : any
|
||||
|
||||
/** @enum {string} */
|
||||
var E = {};
|
||||
>E : {}
|
||||
>{} : {}
|
||||
|
||||
E[""];
|
||||
>E[""] : any
|
||||
>E : {}
|
||||
>"" : ""
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
tests/cases/conformance/jsdoc/bad.js(2,11): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsdoc/bad.js(2,11): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
|
||||
tests/cases/conformance/jsdoc/bad.js(2,10): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsdoc/bad.js(2,10): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
|
||||
tests/cases/conformance/jsdoc/bad.js(5,4): error TS1003: Identifier expected.
|
||||
tests/cases/conformance/jsdoc/bad.js(5,4): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
|
||||
tests/cases/conformance/jsdoc/bad.js(6,19): error TS1003: Identifier expected.
|
||||
@ -27,9 +27,9 @@ tests/cases/conformance/jsdoc/bad.js(9,20): error TS7006: Parameter 'z' implicit
|
||||
==== tests/cases/conformance/jsdoc/bad.js (9 errors) ====
|
||||
/**
|
||||
* @param *
|
||||
|
||||
|
||||
!!! error TS1003: Identifier expected.
|
||||
|
||||
|
||||
!!! error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
|
||||
* {number} x Arg x.
|
||||
* @param {number}
|
||||
|
||||
@ -46,3 +46,7 @@ import M = N; // Error: @typedef does not create namespaces in TypeScript code.
|
||||
* @type {{foo: (function(string, string): string)}}
|
||||
*/
|
||||
const obj = { foo: (a, b) => a + b };
|
||||
|
||||
/** @enum {string} */
|
||||
var E = {};
|
||||
E[""];
|
||||
|
||||
@ -11,7 +11,7 @@ const Target = {
|
||||
/** @type {number} */
|
||||
OK_I_GUESS: 2
|
||||
}
|
||||
/** @enum {number} */
|
||||
/** @enum number */
|
||||
const Second = {
|
||||
MISTAKE: "end",
|
||||
OK: 1,
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// type A = 'fooooo' | 'barrrrr';
|
||||
//// type A = 'foo' | 'bar' | 'baz';
|
||||
//// type B<T extends A> = {};
|
||||
//// type C = B<'fooooo' | '/**/'>
|
||||
//// type C = B<'foo' | '/**/'>
|
||||
|
||||
|
||||
goTo.marker();
|
||||
verify.completionListContains("fooooo");
|
||||
verify.completionListContains("barrrrr");
|
||||
verify.completions({ marker: "", exact: ["bar", "baz"] });
|
||||
edit.insert("b");
|
||||
verify.completionListContains("barrrrr");
|
||||
verify.completions({ exact: ["bar", "baz"] });
|
||||
edit.insert("ar");
|
||||
verify.completions({ exact: ["bar", "baz"] });
|
||||
|
||||
16
tests/cases/fourslash/findAllRefs_jsEnum.ts
Normal file
16
tests/cases/fourslash/findAllRefs_jsEnum.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: /a.js
|
||||
/////** @enum {string} */
|
||||
////const [|{| "isWriteAccess": true, "isDefinition": true |}E|] = { A: "" };
|
||||
////[|E|]["A"];
|
||||
/////** @type {[|E|]} */
|
||||
////const e = [|E|].A;
|
||||
|
||||
verify.singleReferenceGroup(
|
||||
`enum E
|
||||
const E: {
|
||||
A: string;
|
||||
}`);
|
||||
@ -0,0 +1,18 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export const x = 0;
|
||||
|
||||
// @Filename: /a.js
|
||||
////exports.x = 0;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import { x } from "./a";
|
||||
|
||||
verify.getEditsForFileRename({
|
||||
oldPath: "/a.ts",
|
||||
newPath: "/a2.ts",
|
||||
newFileContents: {
|
||||
"/b.ts": 'import { x } from "./a2";',
|
||||
},
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user