镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content
  •  
  •  
  •  
200 changes: 170 additions & 30 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3207,6 +3207,21 @@ namespace ts {
return node;
}

/**
* Sets a callback to use to expand an ellision node (eg, ...) with a more complete node tree
*/
/*@internal*/
export function setExpansionCallback<T extends Node>(node: T, expansionCb: EmitNode["expansion"]) {
getOrCreateEmitNode(node).expansion = expansionCb;
return node;
}

/*@internal*/
export function getExpansionCallback(node: Node) {
const emitNode = node.emitNode;
return emitNode && emitNode.expansion;
}

/**
* Gets a custom text range to use when emitting comments.
*/
Expand Down
14 changes: 7 additions & 7 deletions src/compiler/moduleNameResolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace ts {
/* @internal */
export function trace(host: ModuleResolutionHost, message: DiagnosticMessage, ...args: any[]): void;
export function trace(host: ModuleResolutionHost, message: DiagnosticMessage, ...args: (string | number)[]): void;
export function trace(host: ModuleResolutionHost): void {
host.trace!(formatMessage.apply(undefined, arguments));
}
Expand Down Expand Up @@ -133,7 +133,7 @@ namespace ts {
if (fileName === undefined) return;
const path = normalizePath(combinePaths(baseDirectory, fileName));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName!, path);
}
return path;
}
Expand Down Expand Up @@ -279,15 +279,15 @@ namespace ts {
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_not_set, typeReferenceDirectiveName);
}
else {
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, typeRoots);
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_not_set_root_directory_1, typeReferenceDirectiveName, String(typeRoots));
}
}
else {
if (typeRoots === undefined) {
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_not_set, typeReferenceDirectiveName, containingFile);
}
else {
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, typeRoots);
trace(host, Diagnostics.Resolving_type_reference_directive_0_containing_file_1_root_directory_2, typeReferenceDirectiveName, containingFile, String(typeRoots));
}
}
if (redirectedReference) {
Expand All @@ -307,7 +307,7 @@ namespace ts {
const { fileName, packageId } = resolved;
const resolvedFileName = options.preserveSymlinks ? fileName : realPath(fileName, host, traceEnabled);
if (traceEnabled) {
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFileName, primary);
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFileName, String(primary));
}
resolvedTypeReferenceDirective = { primary, resolvedFileName, packageId, isExternalLibraryImport: pathContainsNodeModules(fileName) };
}
Expand Down Expand Up @@ -796,7 +796,7 @@ namespace ts {
(matchedNormalizedPrefix === undefined || matchedNormalizedPrefix.length < normalizedRoot.length);

if (state.traceEnabled) {
trace(state.host, Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, normalizedRoot, candidate, isLongestMatchingPrefix);
trace(state.host, Diagnostics.Checking_if_0_is_the_longest_matching_prefix_for_1_2, normalizedRoot, candidate, String(isLongestMatchingPrefix));
}

if (isLongestMatchingPrefix) {
Expand Down Expand Up @@ -1506,7 +1506,7 @@ namespace ts {
export function loadModuleFromGlobalCache(moduleName: string, projectName: string | undefined, compilerOptions: CompilerOptions, host: ModuleResolutionHost, globalCache: string): ResolvedModuleWithFailedLookupLocations {
const traceEnabled = isTraceEnabled(compilerOptions, host);
if (traceEnabled) {
trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache);
trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName === undefined ? "unnamed project" : projectName, moduleName, globalCache);
}
const failedLookupLocations: string[] = [];
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
Expand Down
28 changes: 28 additions & 0 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,34 @@ namespace ts {
return output;
}

/* @internal */
export function flattenDiagnosticAnnotationSpans(spans: AnnotationSpan[] | DiagnosticMessageChain | undefined, newLine: string): AnnotationSpan[] | undefined {
if (!spans || isArray(spans)) {
return spans;
}
let results: AnnotationSpan[] | undefined;
let diagnosticChain: DiagnosticMessageChain | undefined = spans;
let offset = 0;

let indent = 0;
while (diagnosticChain) {
if (indent) {
offset += newLine.length;

for (let i = 0; i < indent; i++) {
offset += " ".length;
}
}
if (diagnosticChain.annotations) {
results = concatenate(results, map(diagnosticChain.annotations, d => ({ ...d, start: d.start + offset })));
}
offset += diagnosticChain.messageText.length;
indent++;
diagnosticChain = diagnosticChain.next;
}
return results;
}

export function flattenDiagnosticMessageText(messageText: string | DiagnosticMessageChain | undefined, newLine: string): string {
if (isString(messageText)) {
return messageText;
Expand Down
53 changes: 52 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3319,6 +3319,51 @@ namespace ts {
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;

/* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): ReadonlyArray<TypeParameter> | undefined;

/* @internal */ getDiagnosticRenderingContext(flags: DiagnosticRendererFlags): DiagnosticRenderContext;

id: number;

getExpandedReveal(id: number): RevealedResult | undefined;
}


/** @internal */
export enum DiagnosticRendererFlags {
None = 0,
UseFullyQualifiedTypes = 1 << 0,
}

export type AnnotationSpan = SymbolSpan | RevealSpan;

export interface AnnotationSpanBase {
kind: AnnotationSpan["kind"];
start: number;
length: number;
}

export interface SymbolSpan extends AnnotationSpanBase {
kind: "symbol";
symbol: Symbol;
}

export interface RevealedResult {
text: string;
annotations?: AnnotationSpan[];
}

export interface RevealSpan extends AnnotationSpanBase {
kind: "reveal";
id: number;
checker: number;
callback: () => RevealedResult;
}

/** @internal */
export interface DiagnosticRenderContext {
typeToString(type: Type, symbolOffset: number): string;
symbolToString(symbol: Symbol, symbolOffset: number): string;
getPendingAnnotationSpans(): AnnotationSpan[] | undefined;
}

/* @internal */
Expand Down Expand Up @@ -4009,6 +4054,8 @@ namespace ts {
restrictiveInstantiation?: Type; // Instantiation with type parameters mapped to unconstrained form
/* @internal */
immediateBaseConstraint?: Type; // Immediate base constraint cache
/* @internal */
escapedName?: undefined; // Never set
}

/* @internal */
Expand Down Expand Up @@ -4043,8 +4090,8 @@ namespace ts {

// Unique symbol types (TypeFlags.UniqueESSymbol)
export interface UniqueESSymbolType extends Type {
__uniqueESSymbolBrand: any;
symbol: Symbol;
escapedName: __String;
}

export interface StringLiteralType extends LiteralType {
Expand Down Expand Up @@ -4547,6 +4594,7 @@ namespace ts {
*/
export interface DiagnosticMessageChain {
messageText: string;
annotations?: AnnotationSpan[];
category: DiagnosticCategory;
code: number;
next?: DiagnosticMessageChain;
Expand All @@ -4565,6 +4613,7 @@ namespace ts {
start: number | undefined;
length: number | undefined;
messageText: string | DiagnosticMessageChain;
annotations?: AnnotationSpan[];
}
export interface DiagnosticWithLocation extends Diagnostic {
file: SourceFile;
Expand Down Expand Up @@ -5260,6 +5309,7 @@ namespace ts {
externalHelpersModuleName?: Identifier; // The local name for an imported helpers module
helpers?: EmitHelper[]; // Emit helpers for the node
startsOnNewLine?: boolean; // If the node should begin on a new line
expansion?: () => Node; // A callback that returns a node tree representing an expansion of this node tree
}

export const enum EmitFlags {
Expand Down Expand Up @@ -5804,6 +5854,7 @@ namespace ts {
getIndent(): number;
isAtStartOfLine(): boolean;
getTextPosWithWriteLine?(): number;
writeExpansionSpan?(start: number, length: number, printCallback: (writer: EmitTextWriter) => string): void;
}

export interface GetEffectiveTypeRootsHost {
Expand Down
78 changes: 72 additions & 6 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,8 @@ namespace ts {
code: messageChain.code,
category: messageChain.category,
messageText: messageChain.next ? messageChain : messageChain.messageText,
relatedInformation
relatedInformation,
...(!messageChain.next && messageChain.annotations ? { annotations: messageChain.annotations } : {})
};
}

Expand Down Expand Up @@ -3194,7 +3195,7 @@ namespace ts {
return indentStrings[1].length;
}

export function createTextWriter(newLine: string): EmitTextWriter {
export function createTextWriter(newLine: string, writeSymbol?: ((t: string, s: Symbol) => string), writeExpansionSpan?: EmitTextWriter["writeExpansionSpan"]): EmitTextWriter {
let output: string;
let indent: number;
let lineStart: boolean;
Expand Down Expand Up @@ -3285,10 +3286,11 @@ namespace ts {
writePunctuation: write,
writeSpace: write,
writeStringLiteral: write,
writeSymbol: (s, _) => write(s),
writeSymbol: (s, _) => write(writeSymbol ? writeSymbol(s, _) : s),
writeTrailingSemicolon: write,
writeComment: write,
getTextPosWithWriteLine
getTextPosWithWriteLine,
writeExpansionSpan
};
}

Expand Down Expand Up @@ -7107,8 +7109,27 @@ namespace ts {
getSourceMapSourceConstructor: () => <any>SourceMapSource,
};

export function formatStringFromArgs(text: string, args: ArrayLike<string | number>, baseIndex = 0): string {
return text.replace(/{(\d+)}/g, (_match, index: string) => "" + Debug.assertDefined(args[+index + baseIndex]));
function renderForOutput(arg: string | number | Type | Symbol, renderContext: DiagnosticRenderContext | undefined, offset: number) {
Debug.assertDefined(arg);
if (typeof arg === "string" || typeof arg === "number") {
return arg;
}
if (!renderContext) {
return Debug.fail("Type or symbol passed into diagnostic rendering pipeline with no renderer provided.");
}
if (arg.escapedName) {
return renderContext.symbolToString(arg, offset);
}
return renderContext.typeToString(arg as Type, offset);
}

export function formatStringFromArgs(text: string, args: ArrayLike<string | number | Type | Symbol>, baseIndex = 0, renderContext?: DiagnosticRenderContext): string {
let offsetAdjustmentFromReplacement = 0;
return text.replace(/{(\d+)}/g, (match: string, index: string, offset: number) => {
const text = "" + renderForOutput(args[+index + baseIndex], renderContext, offset + offsetAdjustmentFromReplacement);
offsetAdjustmentFromReplacement += text.length - match.length;
return text;
});
}

export let localizedDiagnosticMessages: MapLike<string> | undefined;
Expand Down Expand Up @@ -7176,6 +7197,30 @@ namespace ts {
};
}

export function createRenderedCompilerDiagnostic(checker: TypeChecker, flags: DiagnosticRendererFlags, message: DiagnosticMessage, ...args: (string | number | Type | Symbol | undefined)[]): Diagnostic;
export function createRenderedCompilerDiagnostic(checker: TypeChecker, flags: DiagnosticRendererFlags, message: DiagnosticMessage): Diagnostic {
let text = getLocaleSpecificMessage(message);
let spans: AnnotationSpan[] | undefined;

if (arguments.length > 3) {
const ctx = checker.getDiagnosticRenderingContext(flags);
text = formatStringFromArgs(text, arguments, 3, ctx);
spans = ctx.getPendingAnnotationSpans();
}

return {
file: undefined,
start: undefined,
length: undefined,

messageText: text,
category: message.category,
code: message.code,
reportsUnnecessary: message.reportsUnnecessary,
...(typeof spans === "undefined" ? {} : { annotations: spans })
};
}

export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessageChain): Diagnostic {
return {
file: undefined,
Expand Down Expand Up @@ -7205,6 +7250,27 @@ namespace ts {
};
}

export function chainRenderedDiagnosticMessages(checker: TypeChecker, flags: DiagnosticRendererFlags, details: DiagnosticMessageChain | undefined, message: DiagnosticMessage, ...args: (string | number | Type | Symbol | undefined)[]): DiagnosticMessageChain;
export function chainRenderedDiagnosticMessages(checker: TypeChecker, flags: DiagnosticRendererFlags, details: DiagnosticMessageChain | undefined, message: DiagnosticMessage): DiagnosticMessageChain {
let text = getLocaleSpecificMessage(message);
let spans: AnnotationSpan[] | undefined;

if (arguments.length > 4) {
const ctx = checker.getDiagnosticRenderingContext(flags);
text = formatStringFromArgs(text, arguments, 4, ctx);
spans = ctx.getPendingAnnotationSpans();
}

return {
messageText: text,
category: message.category,
code: message.code,

next: details,
...(typeof spans === "undefined" ? {} : { annotations: spans })
};
}

export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): DiagnosticMessageChain {
let lastChain = headChain;
while (lastChain.next) {
Expand Down
Loading