Open9
TypeScriptコードリーディングメモ
bigintサポート時の差分など
tsc.tsからのコールスタック [#1]
tsc.ts
namespace ts {} // empty ts module so the module migration script knows this file depends on the `ts` project namespace
// This file actually uses arguments passed on commandline and executes it
ts.Debug.loggingHost = {
log(_level, s) {
ts.sys.write(`${s || ""}${ts.sys.newLine}`);
}
};
if (ts.Debug.isDebugging) {
ts.Debug.enableDebugInfo();
}
if (ts.sys.tryEnableSourceMapsForHost && /^development$/i.test(ts.sys.getEnvironmentVariable("NODE_ENV"))) {
ts.sys.tryEnableSourceMapsForHost();
}
if (ts.sys.setBlocking) {
ts.sys.setBlocking();
}
ts.executeCommandLine(ts.sys, ts.noop, ts.sys.args);
executeCommandLine.ts
@@ L200 @@
function executeCommandLineWorker(
sys: System,
cb: ExecuteCommandLineCallbacks,
commandLine: ParsedCommandLine,
) {
@@ L370 @@
performCompilation(
sys,
cb,
reportDiagnostic,
{ ...commandLine, options: commandLineOptions }
);
@@ L389 @@
export function executeCommandLine(
system: System,
cb: ExecuteCommandLineCallbacks,
commandLineArgs: readonly string[],
) {
@@ L427 @@
return executeCommandLineWorker(system, cb, commandLine);
@@ L516 @@
function performCompilation(
sys: System,
cb: ExecuteCommandLineCallbacks,
reportDiagnostic: DiagnosticReporter,
config: ParsedCommandLine
) {
@@ L523 @@
const host = createCompilerHostWorker(options, /*setParentPos*/ undefined, sys);
@@ L536 @@
const program = createProgram(programOptions);
const exitStatus = emitFilesAndReportErrorsAndGetExitStatus(
program,
reportDiagnostic,
s => sys.write(s + sys.newLine),
createReportErrorSummary(sys, options)
);
tsc.tsからのコールスタック [#2]
- src/compiler/program.ts#createCompilerHostWorker
- src/compiler/program.ts#createProgram
src/compiler/program.ts
@@ L71 @@
/*@internal*/
// TODO(shkamat): update this after reworking ts build API
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
@@ L77 @@
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
@@ L91 @@
return text !== undefined ? createSourceFile(fileName, text, languageVersion, setParentNodes) : undefined;
@@ L172 @@
const compilerHost: CompilerHost = {
getSourceFile,
@@ L192 @@
return compilerHost;
@@ L763 @@
/**
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
* that represent a compilation unit.
*
* Creating a program proceeds from a set of root files, expanding the set of inputs by following imports and
* triple-slash-reference-path directives transitively. '@types' and triple-slash-reference-types are also pulled in.
*
* @param createProgramOptions - The options for creating a program.
* @returns A 'Program' object.
*/
export function createProgram(createProgramOptions: CreateProgramOptions): Program;
/**
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
* that represent a compilation unit.
*
* Creating a program proceeds from a set of root files, expanding the set of inputs by following imports and
* triple-slash-reference-path directives transitively. '@types' and triple-slash-reference-types are also pulled in.
*
* @param rootNames - A set of root files.
* @param options - The compiler options which should be used.
* @param host - The host interacts with the underlying file system.
* @param oldProgram - Reuses an old program structure.
* @param configFileParsingDiagnostics - error during config file parsing
* @returns A 'Program' object.
*/
export function createProgram(rootNames: readonly string[], options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: readonly Diagnostic[]): Program;
export function createProgram(rootNamesOrOptions: readonly string[] | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: readonly Diagnostic[]): Program {
@@ L968 @@
forEach(rootNames, (name, index) => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.RootFile, index }));
@@ L1053 @@
const program: Program = {
@@ L1055 @@
getSourceFile,
@@ L1109 @@
};
@@ L1131 @@
return program;
@@ L1751 @@
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, transformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
tracing?.push(tracing.Phase.Emit, "emit", { path: sourceFile?.path }, /*separateBeginAndEnd*/ true);
const result = runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles, transformers, forceDtsEmit));
tracing?.pop();
return result;
}
@@ L1762 @@
function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
@@ L1780 @@
const emitResult = emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
sourceFile,
getTransformers(options, customTransformers, emitOnlyDtsFiles),
emitOnlyDtsFiles,
/*onlyBuildInfo*/ false,
forceDtsEmit
);
@@ L1795 @@
function getSourceFile(fileName: string): SourceFile | undefined {
return getSourceFileByPath(toPath(fileName));
}
@@ L1799 @@
function getSourceFileByPath(path: Path): SourceFile | undefined {
return filesByName.get(path) || undefined;
}
@@ L2251 @@
function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason) {
processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined, reason);
}
@@ L2410@@
function getSourceFileFromReferenceWorker(
fileName: string,
getSourceFile: (fileName: string) => SourceFile | undefined,
fail?: (diagnostic: DiagnosticMessage, ...argument: string[]) => void,
reason?: FileIncludeReason): SourceFile | undefined {
@@ L2430 @@
const sourceFile = getSourceFile(fileName);
@@ L2462 @@
/** This has side effects through `findSourceFile`. */
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, reason: FileIncludeReason): void {
getSourceFileFromReferenceWorker(
fileName,
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, reason, packageId), // TODO: GH#18217
(diagnostic, ...args) => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, diagnostic, args),
reason
);
}
@@ L2507 @@
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
@@ L2514 @@
const result = findSourceFileWorker(fileName, path, isDefaultLib, ignoreNoDefaultLib, reason, packageId);
@@ L2519 @@
function findSourceFileWorker(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, reason: FileIncludeReason, packageId: PackageId | undefined): SourceFile | undefined {
@@ L2607 @@
// We haven't looked for this file, do so now and cache result
const file = host.getSourceFile(
fileName,
options.target!,
hostErrorMessage => addFilePreprocessingFileExplainingDiagnostic(/*file*/ undefined, reason, Diagnostics.Cannot_read_file_0_Colon_1, [fileName, hostErrorMessage]),
shouldCreateNewSourceFile
);
@@ L2635 @@
addFileToFilesByName(file, path, redirectedPath);
@@ L2685 @@
function addFileToFilesByName(file: SourceFile | undefined, path: Path, redirectedPath: Path | undefined) {
if (redirectedPath) {
filesByName.set(redirectedPath, file);
filesByName.set(path, file || false);
}
else {
filesByName.set(path, file);
}
}
tsc.tsからのコールスタック [#3]
- src/compiler/parser.ts#createSourceFile
src/compiler/parser.ts
@@ L625 @@
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
@@ L635 @@
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
@@ L698 @@
// Implement the parser as a singleton module. We do this for perf reasons because creating
// parser instances can actually be expensive enough to impact us on projects with many source
// files.
namespace Parser {
@@ L834 @@
export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
@@ L850 @@
const result = parseSourceFileWorker(languageVersion, setParentNodes, scriptKind);
@@ L1022 @@
function parseSourceFileWorker(languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile {
@@ L1031 @@
nextToken();
@@ L1033 @@
const statements = parseList(ParsingContext.SourceElements, parseStatement);
@@ L1847 @@
// True if positioned at the start of a list element
function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean {
const node = currentNode(parsingContext);
if (node) {
return true;
}
switch (parsingContext) {
case ParsingContext.SourceElements:
case ParsingContext.BlockStatements:
case ParsingContext.SwitchClauseStatements:
// If we're in error recovery, then we don't want to treat ';' as an empty statement.
// The problem is that ';' can show up in far too many contexts, and if we see one
// and assume it's a statement, then we may bail out inappropriately from whatever
// we're parsing. For example, if we have a semicolon in the middle of a class, then
// we really don't want to assume the class is over and we're on a statement in the
// outer module. We just want to consume and move on.
return !(token() === SyntaxKind.SemicolonToken && inErrorRecovery) && isStartOfStatement();
case ParsingContext.SwitchClauses:
return token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
case ParsingContext.TypeMembers:
return lookAhead(isTypeMemberStart);
case ParsingContext.ClassMembers:
// We allow semicolons as class elements (as specified by ES6) as long as we're
// not in error recovery. If we're in error recovery, we don't want an errant
// semicolon to be treated as a class member (since they're almost always used
// for statements.
return lookAhead(isClassMemberStart) || (token() === SyntaxKind.SemicolonToken && !inErrorRecovery);
case ParsingContext.EnumMembers:
// Include open bracket computed properties. This technically also lets in indexers,
// which would be a candidate for improved error reporting.
return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
case ParsingContext.ObjectLiteralMembers:
switch (token()) {
case SyntaxKind.OpenBracketToken:
case SyntaxKind.AsteriskToken:
case SyntaxKind.DotDotDotToken:
case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`)
return true;
default:
return isLiteralPropertyName();
}
case ParsingContext.RestProperties:
return isLiteralPropertyName();
case ParsingContext.ObjectBindingElements:
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
case ParsingContext.HeritageClauseElement:
// If we see `{ ... }` then only consume it as an expression if it is followed by `,` or `{`
// That way we won't consume the body of a class in its heritage clause.
if (token() === SyntaxKind.OpenBraceToken) {
return lookAhead(isValidHeritageClauseObjectLiteral);
}
if (!inErrorRecovery) {
return isStartOfLeftHandSideExpression() && !isHeritageClauseExtendsOrImplementsKeyword();
}
else {
// If we're in error recovery we tighten up what we're willing to match.
// That way we don't treat something like "this" as a valid heritage clause
// element during recovery.
return isIdentifier() && !isHeritageClauseExtendsOrImplementsKeyword();
}
case ParsingContext.VariableDeclarations:
return isBindingIdentifierOrPrivateIdentifierOrPattern();
case ParsingContext.ArrayBindingElements:
return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern();
case ParsingContext.TypeParameters:
return isIdentifier();
case ParsingContext.ArrayLiteralMembers:
switch (token()) {
case SyntaxKind.CommaToken:
case SyntaxKind.DotToken: // Not an array literal member, but don't want to close the array (see `tests/cases/fourslash/completionsDotInArrayLiteralInObjectLiteral.ts`)
return true;
}
// falls through
case ParsingContext.ArgumentExpressions:
return token() === SyntaxKind.DotDotDotToken || isStartOfExpression();
case ParsingContext.Parameters:
return isStartOfParameter(/*isJSDocParameter*/ false);
case ParsingContext.JSDocParameters:
return isStartOfParameter(/*isJSDocParameter*/ true);
case ParsingContext.TypeArguments:
case ParsingContext.TupleElementTypes:
return token() === SyntaxKind.CommaToken || isStartOfType();
case ParsingContext.HeritageClauses:
return isHeritageClause();
case ParsingContext.ImportOrExportSpecifiers:
return tokenIsIdentifierOrKeyword(token());
case ParsingContext.JsxAttributes:
return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken;
case ParsingContext.JsxChildren:
return true;
}
return Debug.fail("Non-exhaustive case in 'isListElement'.");
}
@@ L1997 @@
// True if positioned at a list terminator
function isListTerminator(kind: ParsingContext): boolean {
if (token() === SyntaxKind.EndOfFileToken) {
// Being at the end of the file ends all lists.
return true;
}
switch (kind) {
case ParsingContext.BlockStatements:
case ParsingContext.SwitchClauses:
case ParsingContext.TypeMembers:
case ParsingContext.ClassMembers:
case ParsingContext.EnumMembers:
case ParsingContext.ObjectLiteralMembers:
case ParsingContext.ObjectBindingElements:
case ParsingContext.ImportOrExportSpecifiers:
return token() === SyntaxKind.CloseBraceToken;
case ParsingContext.SwitchClauseStatements:
return token() === SyntaxKind.CloseBraceToken || token() === SyntaxKind.CaseKeyword || token() === SyntaxKind.DefaultKeyword;
case ParsingContext.HeritageClauseElement:
return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
case ParsingContext.VariableDeclarations:
return isVariableDeclaratorListTerminator();
case ParsingContext.TypeParameters:
// Tokens other than '>' are here for better error recovery
return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
case ParsingContext.ArgumentExpressions:
// Tokens other than ')' are here for better error recovery
return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.SemicolonToken;
case ParsingContext.ArrayLiteralMembers:
case ParsingContext.TupleElementTypes:
case ParsingContext.ArrayBindingElements:
return token() === SyntaxKind.CloseBracketToken;
case ParsingContext.JSDocParameters:
case ParsingContext.Parameters:
case ParsingContext.RestProperties:
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
return token() === SyntaxKind.CloseParenToken || token() === SyntaxKind.CloseBracketToken /*|| token === SyntaxKind.OpenBraceToken*/;
case ParsingContext.TypeArguments:
// All other tokens should cause the type-argument to terminate except comma token
return token() !== SyntaxKind.CommaToken;
case ParsingContext.HeritageClauses:
return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.CloseBraceToken;
case ParsingContext.JsxAttributes:
return token() === SyntaxKind.GreaterThanToken || token() === SyntaxKind.SlashToken;
case ParsingContext.JsxChildren:
return token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsSlash);
default:
return false;
}
}
@@ L2087 @@
// Parses a list of elements
function parseList<T extends Node>(kind: ParsingContext, parseElement: () => T): NodeArray<T> {
@@ L2094 @@
while (!isListTerminator(kind)) {
if (isListElement(kind, /*inErrorRecovery*/ false)) {
list.push(parseListElement(kind, parseElement));
continue;
}
if (abortParsingListOrMoveToNextToken(kind)) {
break;
}
}
tsc.tsからのコールスタック [#4]
src/compiler/watch.ts
@@ L300 @@
/**
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
*/
export function emitFilesAndReportErrors<T extends BuilderProgram>(
program: Program | T,
reportDiagnostic: DiagnosticReporter,
write?: (s: string) => void,
reportSummary?: ReportEmitErrorSummary,
writeFile?: WriteFileCallback,
cancellationToken?: CancellationToken,
emitOnlyDtsFiles?: boolean,
customTransformers?: CustomTransformers
) {
@@ L334 @@
// Emit and report any errors we ran into.
const emitResult = isListFilesOnly
? { emitSkipped: true, diagnostics: emptyArray }
: program.emit(/*targetSourceFile*/ undefined, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
@@ L362 @@
export function emitFilesAndReportErrorsAndGetExitStatus<T extends BuilderProgram>(
program: Program | T,
reportDiagnostic: DiagnosticReporter,
write?: (s: string) => void,
reportSummary?: ReportEmitErrorSummary,
writeFile?: WriteFileCallback,
cancellationToken?: CancellationToken,
emitOnlyDtsFiles?: boolean,
customTransformers?: CustomTransformers
) {
const { emitResult, diagnostics } = emitFilesAndReportErrors(
program,
reportDiagnostic,
write,
reportSummary,
writeFile,
cancellationToken,
emitOnlyDtsFiles,
customTransformers
);
tsc.tsからのコールスタック [#5]
- src/compiler/emitter.ts#emitFiles
emitter.ts
@@ L9 @@
/*@internal*/
/**
* Iterates over the source files that are expected to have an emit output.
*
* @param host An EmitHost.
* @param action The action to execute.
* @param sourceFilesOrTargetSourceFile
* If an array, the full list of source files to emit.
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
*/
export function forEachEmittedFile<T>(
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) => T,
sourceFilesOrTargetSourceFile?: readonly SourceFile[] | SourceFile,
forceDtsEmit = false,
onlyBuildInfo?: boolean,
includeBuildInfo?: boolean) {
@@ L31 @@
const result = action(getOutputPathsFor(bundle, host, forceDtsEmit), bundle);
@@ L298 @@
/*@internal*/
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, { scriptTransformers, declarationTransformers }: EmitTransformers, emitOnlyDtsFiles?: boolean, onlyBuildInfo?: boolean, forceDtsEmit?: boolean): EmitResult {
@@ L314 @@
forEachEmittedFile(
host,
emitSourceFileOrBundle,
getSourceFilesToEmit(host, targetSourceFile, forceDtsEmit),
forceDtsEmit,
onlyBuildInfo,
!targetSourceFile
);
@@ L333 @@
function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) {
@@ L343 @@
emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath, relativeToBuildInfo);
@@ L347 @@
emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, relativeToBuildInfo);
@@ L351 @@
emitBuildInfo(bundleBuildInfo, buildInfoPath);
@@ L391 @@
function emitJsFileOrBundle(
sourceFileOrBundle: SourceFile | Bundle | undefined,
jsFilePath: string | undefined,
sourceMapFilePath: string | undefined,
relativeToBuildInfo: (path: string) => string) {
@@ L405 @@
// Transform the source files
const transform = transformNodes(resolver, host, factory, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false);
@@L422 @@
const printer = createPrinter(printerOptions, {
// resolver hooks
hasGlobalName: resolver.hasGlobalName,
// transform hooks
onEmitNode: transform.emitNodeWithNotification,
isEmitNotificationEnabled: transform.isEmitNotificationEnabled,
substituteNode: transform.substituteNode,
});
@@ L434 @@
printSourceFileOrBundle(jsFilePath, sourceMapFilePath, transform.transformed[0], printer, compilerOptions);
@@ L531 @@
function printSourceFileOrBundle(jsFilePath: string, sourceMapFilePath: string | undefined, sourceFileOrBundle: SourceFile | Bundle, printer: Printer, mapOptions: SourceMapOptions) {
@@ L550 @@
printer.writeFile(sourceFile!, writer, sourceMapGenerator);
@@ L583 @@
// Write the output file
writeFile(host, emitterDiagnostics, jsFilePath, writer.getText(), !!compilerOptions.emitBOM, sourceFiles);
@@ L871 @@
export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer {
@@ L1127 @@
function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) {
@@ L1133 @@
print(EmitHint.SourceFile, sourceFile, sourceFile);
@@ L1148 @@
function print(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined) {
@@ L1153 @@
pipelineEmit(hint, node, /*parenthesizerRule*/ undefined);
@@ L1229 @@
function pipelineEmit(emitHint: EmitHint, node: Node, parenthesizerRule?: (node: Node) => Node) {
currentParenthesizerRule = parenthesizerRule;
const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, emitHint, node);
pipelinePhase(emitHint, node);
currentParenthesizerRule = undefined;
}
@@ L1248 @@
function getPipelinePhase(phase: PipelinePhase, emitHint: EmitHint, node: Node) {
switch (phase) {
@@ L1273 @@
case PipelinePhase.Emit:
return pipelineEmitWithHint;
@@ L1289 @@
function pipelineEmitWithHint(hint: EmitHint, node: Node): void {
@@ L1298 @@
pipelineEmitWithHintWorker(hint, node);
@@ L1305 @@
function pipelineEmitWithHintWorker(hint: EmitHint, node: Node): void {
@@ L1314 @@
if (hint === EmitHint.Unspecified) {
switch (node.kind) {
tsc.tsからのコールスタック [#6]
transformer.ts
@@ L3 @@
function getModuleTransformer(moduleKind: ModuleKind): TransformerFactory<SourceFile | Bundle> {
@@ L15 @@
return transformModule;
@@ L30 @@
export function getTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean): EmitTransformers {
return {
scriptTransformers: getScriptTransformers(compilerOptions, customTransformers, emitOnlyDtsFiles),
declarationTransformers: getDeclarationTransformers(customTransformers),
};
}
@@ L37 @@
function getScriptTransformers(compilerOptions: CompilerOptions, customTransformers?: CustomTransformers, emitOnlyDtsFiles?: boolean) {
@@ L86 @@
transformers.push(getModuleTransformer(moduleKind));
@@ L140 @@
/**
* Transforms an array of SourceFiles by passing them through each transformer.
*
* @param resolver The emit resolver provided by the checker.
* @param host The emit host object used to interact with the file system.
* @param options Compiler options to surface in the `TransformationContext`.
* @param nodes An array of nodes to transform.
* @param transforms An array of `TransformerFactory` callbacks.
* @param allowDtsFiles A value indicating whether to allow the transformation of .d.ts files.
*/
export function transformNodes<T extends Node>(resolver: EmitResolver | undefined, host: EmitHost | undefined, factory: NodeFactory, options: CompilerOptions, nodes: readonly T[], transformers: readonly TransformerFactory<T>[], allowDtsFiles: boolean): TransformationResult<T> {ts.Debug.log("transformer.ts ( L140) start transformNodes");
@@ L221 @@
// Chain together and initialize each transformer.
const transformersWithContext = transformers.map(t => t(context));
const transformation = (node: T): T => {
for (const transform of transformersWithContext) {
node = transform(node);
}
return node;
};
@@ L233 @@
// Transform each node.
const transformed: T[] = [];
for (const node of nodes) {
tracing?.push(tracing.Phase.Emit, "transformNodes", node.kind === SyntaxKind.SourceFile ? { path: (node as any as SourceFile).path } : { kind: node.kind, pos: node.pos, end: node.end });
transformed.push((allowDtsFiles ? transformation : transformRoot)(node));
tracing?.pop();
}
module.ts
@@ L4 @@
export function transformModule(context: TransformationContext) {
@@ L51 @@
return chainBundle(context, transformSourceFile);
@@ L53 @@
/**
* Transforms the module aspects of a SourceFile.
*
* @param node The SourceFile node.
*/
function transformSourceFile(node: SourceFile) {
@@ L70 @@
// Perform the transformation.
const transformModule = getTransformModuleDelegate(moduleKind);
const updated = transformModule(node);
@@ L76 @@
return updated;
utilities.ts
@@ L28 @@
export function chainBundle(context: CoreTransformationContext, transformSourceFile: (x: SourceFile) => SourceFile): (x: SourceFile | Bundle) => SourceFile | Bundle {
return transformSourceFileOrBundle;
function transformSourceFileOrBundle(node: SourceFile | Bundle) {
return node.kind === SyntaxKind.SourceFile ? transformSourceFile(node) : transformBundle(node);
}
function transformBundle(node: Bundle) {
return context.factory.createBundle(map(node.sourceFiles, transformSourceFile), node.prepends);
}
}
tsc.tsからのコールスタック
src/compiler/scanner.ts
@@ L79 @@
const textToKeywordObj: MapLike<KeywordSyntaxKind> = {
abstract: SyntaxKind.AbstractKeyword,
any: SyntaxKind.AnyKeyword,
as: SyntaxKind.AsKeyword,
asserts: SyntaxKind.AssertsKeyword,
bigint: SyntaxKind.BigIntKeyword,
boolean: SyntaxKind.BooleanKeyword,
break: SyntaxKind.BreakKeyword,
case: SyntaxKind.CaseKeyword,
catch: SyntaxKind.CatchKeyword,
class: SyntaxKind.ClassKeyword,
continue: SyntaxKind.ContinueKeyword,
const: SyntaxKind.ConstKeyword,
["" + "constructor"]: SyntaxKind.ConstructorKeyword,
debugger: SyntaxKind.DebuggerKeyword,
declare: SyntaxKind.DeclareKeyword,
default: SyntaxKind.DefaultKeyword,
delete: SyntaxKind.DeleteKeyword,
do: SyntaxKind.DoKeyword,
else: SyntaxKind.ElseKeyword,
enum: SyntaxKind.EnumKeyword,
export: SyntaxKind.ExportKeyword,
extends: SyntaxKind.ExtendsKeyword,
false: SyntaxKind.FalseKeyword,
finally: SyntaxKind.FinallyKeyword,
for: SyntaxKind.ForKeyword,
from: SyntaxKind.FromKeyword,
function: SyntaxKind.FunctionKeyword,
get: SyntaxKind.GetKeyword,
if: SyntaxKind.IfKeyword,
implements: SyntaxKind.ImplementsKeyword,
import: SyntaxKind.ImportKeyword,
in: SyntaxKind.InKeyword,
infer: SyntaxKind.InferKeyword,
instanceof: SyntaxKind.InstanceOfKeyword,
interface: SyntaxKind.InterfaceKeyword,
intrinsic: SyntaxKind.IntrinsicKeyword,
is: SyntaxKind.IsKeyword,
keyof: SyntaxKind.KeyOfKeyword,
let: SyntaxKind.LetKeyword,
module: SyntaxKind.ModuleKeyword,
namespace: SyntaxKind.NamespaceKeyword,
never: SyntaxKind.NeverKeyword,
new: SyntaxKind.NewKeyword,
null: SyntaxKind.NullKeyword,
number: SyntaxKind.NumberKeyword,
object: SyntaxKind.ObjectKeyword,
package: SyntaxKind.PackageKeyword,
private: SyntaxKind.PrivateKeyword,
protected: SyntaxKind.ProtectedKeyword,
public: SyntaxKind.PublicKeyword,
override: SyntaxKind.OverrideKeyword,
readonly: SyntaxKind.ReadonlyKeyword,
require: SyntaxKind.RequireKeyword,
global: SyntaxKind.GlobalKeyword,
return: SyntaxKind.ReturnKeyword,
set: SyntaxKind.SetKeyword,
static: SyntaxKind.StaticKeyword,
string: SyntaxKind.StringKeyword,
super: SyntaxKind.SuperKeyword,
switch: SyntaxKind.SwitchKeyword,
symbol: SyntaxKind.SymbolKeyword,
this: SyntaxKind.ThisKeyword,
throw: SyntaxKind.ThrowKeyword,
true: SyntaxKind.TrueKeyword,
try: SyntaxKind.TryKeyword,
type: SyntaxKind.TypeKeyword,
typeof: SyntaxKind.TypeOfKeyword,
undefined: SyntaxKind.UndefinedKeyword,
unique: SyntaxKind.UniqueKeyword,
unknown: SyntaxKind.UnknownKeyword,
var: SyntaxKind.VarKeyword,
void: SyntaxKind.VoidKeyword,
while: SyntaxKind.WhileKeyword,
with: SyntaxKind.WithKeyword,
yield: SyntaxKind.YieldKeyword,
async: SyntaxKind.AsyncKeyword,
await: SyntaxKind.AwaitKeyword,
of: SyntaxKind.OfKeyword,
};
@@ L162 @@
const textToToken = new Map(getEntries({
...textToKeywordObj,
"{": SyntaxKind.OpenBraceToken,
"}": SyntaxKind.CloseBraceToken,
"(": SyntaxKind.OpenParenToken,
")": SyntaxKind.CloseParenToken,
"[": SyntaxKind.OpenBracketToken,
"]": SyntaxKind.CloseBracketToken,
".": SyntaxKind.DotToken,
"...": SyntaxKind.DotDotDotToken,
";": SyntaxKind.SemicolonToken,
",": SyntaxKind.CommaToken,
"<": SyntaxKind.LessThanToken,
">": SyntaxKind.GreaterThanToken,
"<=": SyntaxKind.LessThanEqualsToken,
">=": SyntaxKind.GreaterThanEqualsToken,
"==": SyntaxKind.EqualsEqualsToken,
"!=": SyntaxKind.ExclamationEqualsToken,
"===": SyntaxKind.EqualsEqualsEqualsToken,
"!==": SyntaxKind.ExclamationEqualsEqualsToken,
"=>": SyntaxKind.EqualsGreaterThanToken,
"+": SyntaxKind.PlusToken,
"-": SyntaxKind.MinusToken,
"**": SyntaxKind.AsteriskAsteriskToken,
"*": SyntaxKind.AsteriskToken,
"/": SyntaxKind.SlashToken,
"%": SyntaxKind.PercentToken,
"++": SyntaxKind.PlusPlusToken,
"--": SyntaxKind.MinusMinusToken,
"<<": SyntaxKind.LessThanLessThanToken,
"</": SyntaxKind.LessThanSlashToken,
">>": SyntaxKind.GreaterThanGreaterThanToken,
">>>": SyntaxKind.GreaterThanGreaterThanGreaterThanToken,
"&": SyntaxKind.AmpersandToken,
"|": SyntaxKind.BarToken,
"^": SyntaxKind.CaretToken,
"!": SyntaxKind.ExclamationToken,
"~": SyntaxKind.TildeToken,
"&&": SyntaxKind.AmpersandAmpersandToken,
"||": SyntaxKind.BarBarToken,
"?": SyntaxKind.QuestionToken,
"??": SyntaxKind.QuestionQuestionToken,
"?.": SyntaxKind.QuestionDotToken,
":": SyntaxKind.ColonToken,
"=": SyntaxKind.EqualsToken,
"+=": SyntaxKind.PlusEqualsToken,
"-=": SyntaxKind.MinusEqualsToken,
"*=": SyntaxKind.AsteriskEqualsToken,
"**=": SyntaxKind.AsteriskAsteriskEqualsToken,
"/=": SyntaxKind.SlashEqualsToken,
"%=": SyntaxKind.PercentEqualsToken,
"<<=": SyntaxKind.LessThanLessThanEqualsToken,
">>=": SyntaxKind.GreaterThanGreaterThanEqualsToken,
">>>=": SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken,
"&=": SyntaxKind.AmpersandEqualsToken,
"|=": SyntaxKind.BarEqualsToken,
"^=": SyntaxKind.CaretEqualsToken,
"||=": SyntaxKind.BarBarEqualsToken,
"&&=": SyntaxKind.AmpersandAmpersandEqualsToken,
"??=": SyntaxKind.QuestionQuestionEqualsToken,
"@": SyntaxKind.AtToken,
"`": SyntaxKind.BacktickToken
}));