Skip to content

Commit 1aa968d

Browse files
committed
Replace TypeScriptMessageFormatter with SourceFileLocationFormatter and standardize the way source file paths are reported
1 parent c0b484e commit 1aa968d

File tree

5 files changed

+73
-44
lines changed

5 files changed

+73
-44
lines changed

apps/api-extractor/src/analyzer/ExportAnalyzer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { AstSymbol } from './AstSymbol';
99
import { AstImport, IAstImportOptions, AstImportKind } from './AstImport';
1010
import { AstModule, AstModuleExportInfo } from './AstModule';
1111
import { TypeScriptInternals } from './TypeScriptInternals';
12-
import { TypeScriptMessageFormatter } from './TypeScriptMessageFormatter';
12+
import { SourceFileLocationFormatter } from './SourceFileLocationFormatter';
1313
import { IFetchAstSymbolOptions, AstEntity } from './AstSymbolTable';
1414

1515
/**
@@ -134,7 +134,7 @@ export class ExportAnalyzer {
134134

135135
if (!astSymbol) {
136136
throw new Error(`Unsupported export ${JSON.stringify(exportedSymbol.name)} in `
137-
+ TypeScriptMessageFormatter.formatFileAndLineNumber(followedSymbol.declarations[0]));
137+
+ SourceFileLocationFormatter.formatDeclaration(followedSymbol.declarations[0]));
138138
}
139139

140140
astModule.cachedExportedEntities.set(exportedSymbol.name, astSymbol);
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import * as ts from 'typescript';
5+
import * as path from 'path';
6+
import { Path, Text } from '@rushstack/node-core-library';
7+
8+
export interface ISourceFileLocationFormatOptions {
9+
sourceFileLine?: number;
10+
sourceFileColumn?: number;
11+
workingPackageFolderPath?: string
12+
}
13+
14+
export class SourceFileLocationFormatter {
15+
/**
16+
* Returns a string such as this, based on the context information in the provided node:
17+
* "[C:\Folder\File.ts#123]"
18+
*/
19+
public static formatDeclaration(node: ts.Node, workingPackageFolderPath?: string): string {
20+
const sourceFile: ts.SourceFile = node.getSourceFile();
21+
const lineAndCharacter: ts.LineAndCharacter = sourceFile.getLineAndCharacterOfPosition(node.getStart());
22+
23+
return SourceFileLocationFormatter.formatPath(sourceFile.fileName, {
24+
sourceFileLine: lineAndCharacter.line + 1,
25+
sourceFileColumn: lineAndCharacter.character + 1,
26+
workingPackageFolderPath
27+
});
28+
}
29+
30+
public static formatPath(sourceFilePath: string, options?: ISourceFileLocationFormatOptions): string {
31+
if (!options) {
32+
options = { };
33+
}
34+
35+
let result: string = '';
36+
37+
// Make the path relative to the workingPackageFolderPath
38+
let scrubbedPath: string = sourceFilePath;
39+
40+
if (options.workingPackageFolderPath) {
41+
// If it's under the working folder, make it a relative path
42+
if (Path.isUnderOrEqual(sourceFilePath, options.workingPackageFolderPath)) {
43+
scrubbedPath = path.relative(options.workingPackageFolderPath, sourceFilePath);
44+
}
45+
}
46+
47+
// Convert it to a Unix-style path
48+
scrubbedPath = Text.replaceAll(scrubbedPath, '\\', '/');
49+
result += scrubbedPath;
50+
51+
if (options.sourceFileLine) {
52+
result += `:${options.sourceFileLine}`;
53+
54+
if (options.sourceFileColumn) {
55+
result += `:${options.sourceFileColumn}`;
56+
}
57+
}
58+
59+
return result;
60+
}
61+
}

apps/api-extractor/src/analyzer/TypeScriptHelpers.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
/* eslint-disable no-bitwise */
55

66
import * as ts from 'typescript';
7-
import { TypeScriptMessageFormatter } from './TypeScriptMessageFormatter';
7+
import { SourceFileLocationFormatter } from './SourceFileLocationFormatter';
88
import { TypeScriptInternals } from './TypeScriptInternals';
9+
import { InternalError } from '@rushstack/node-core-library';
910

1011
export class TypeScriptHelpers {
1112
// Matches TypeScript's encoded names for well-known ECMAScript symbols like
@@ -107,8 +108,8 @@ export class TypeScriptHelpers {
107108
public static getSymbolForDeclaration(declaration: ts.Declaration, checker: ts.TypeChecker): ts.Symbol {
108109
const symbol: ts.Symbol | undefined = TypeScriptInternals.tryGetSymbolForDeclaration(declaration, checker);
109110
if (!symbol) {
110-
throw new Error(TypeScriptMessageFormatter.formatFileAndLineNumber(declaration) + ': '
111-
+ 'Unable to determine semantic information for this declaration');
111+
throw new InternalError('Unable to determine semantic information for declaration: '
112+
+ SourceFileLocationFormatter.formatDeclaration(declaration));
112113
}
113114
return symbol;
114115
}

apps/api-extractor/src/analyzer/TypeScriptMessageFormatter.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

apps/api-extractor/src/api/ExtractorMessage.ts

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
// See LICENSE in the project root for license information.
33

44
import * as tsdoc from '@microsoft/tsdoc';
5-
import * as path from 'path';
65
import { ExtractorMessageId } from './ExtractorMessageId';
7-
import { Path, Text } from '@rushstack/node-core-library';
86
import { ExtractorLogLevel } from './ExtractorLogLevel';
97
import { ConsoleMessageId } from './ConsoleMessageId';
8+
import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter';
109

1110
/**
1211
* Used by {@link ExtractorMessage.properties}.
@@ -211,27 +210,11 @@ export class ExtractorMessage {
211210
let result: string = '';
212211

213212
if (this.sourceFilePath) {
214-
// Make the path relative to the workingPackageFolderPath
215-
let scrubbedPath: string = this.sourceFilePath;
216-
217-
if (workingPackageFolderPath !== undefined) {
218-
// If it's under the working folder, make it a relative path
219-
if (Path.isUnderOrEqual(this.sourceFilePath, workingPackageFolderPath)) {
220-
scrubbedPath = path.relative(workingPackageFolderPath, this.sourceFilePath);
221-
}
222-
}
223-
224-
// Convert it to a Unix-style path
225-
scrubbedPath = Text.replaceAll(scrubbedPath, '\\', '/');
226-
result += scrubbedPath;
227-
228-
if (this.sourceFileLine) {
229-
result += `:${this.sourceFileLine}`;
230-
231-
if (this.sourceFileColumn) {
232-
result += `:${this.sourceFileColumn}`;
233-
}
234-
}
213+
result += SourceFileLocationFormatter.formatPath(this.sourceFilePath, {
214+
sourceFileLine: this.sourceFileLine,
215+
sourceFileColumn: this.sourceFileColumn,
216+
workingPackageFolderPath
217+
});
235218

236219
if (result.length > 0) {
237220
result += ' - ';

0 commit comments

Comments
 (0)