mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-20 19:45:07 -06:00
Added printer
This commit is contained in:
parent
0f2bbb181f
commit
6b381ecdbd
@ -44,6 +44,8 @@ var compilerSources = [
|
||||
"visitor.ts",
|
||||
"transformer.ts",
|
||||
"sourcemap.ts",
|
||||
"comments.ts",
|
||||
"printer.ts",
|
||||
"declarationEmitter.ts",
|
||||
"emitter.ts",
|
||||
"program.ts",
|
||||
@ -67,6 +69,8 @@ var servicesSources = [
|
||||
"visitor.ts",
|
||||
"transformer.ts",
|
||||
"sourcemap.ts",
|
||||
"comments.ts",
|
||||
"printer.ts",
|
||||
"declarationEmitter.ts",
|
||||
"emitter.ts",
|
||||
"program.ts",
|
||||
|
||||
214
src/compiler/comments.ts
Normal file
214
src/compiler/comments.ts
Normal file
@ -0,0 +1,214 @@
|
||||
/// <reference path="sourcemap.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface CommentWriter {
|
||||
reset(): void;
|
||||
setSourceFile(sourceFile: SourceFile): void;
|
||||
getLeadingCommentsToEmit(node: TextRange): CommentRange[];
|
||||
getTrailingCommentsToEmit(node: TextRange): CommentRange[];
|
||||
emitDetachedComments(node: TextRange): void;
|
||||
emitLeadingComments(node: TextRange, comments?: CommentRange[]): void;
|
||||
emitTrailingComments(node: TextRange, comments?: CommentRange[]): void;
|
||||
}
|
||||
|
||||
export function createCommentWriter(host: EmitHost, writer: EmitTextWriter, sourceMap: SourceMapWriter): CommentWriter {
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
const newLine = host.getNewLine();
|
||||
const { emitPos } = sourceMap;
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentText: string;
|
||||
let currentLineMap: number[];
|
||||
let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[];
|
||||
|
||||
// This maps start->end for a comment range. See `hasConsumedCommentRange` and
|
||||
// `consumeCommentRange` for usage.
|
||||
let consumedCommentRanges: number[];
|
||||
let leadingCommentRangeNodeStarts: boolean[];
|
||||
let trailingCommentRangeNodeEnds: boolean[];
|
||||
|
||||
return compilerOptions.removeComments
|
||||
? createCommentRemovingWriter()
|
||||
: createCommentPreservingWriter();
|
||||
|
||||
function createCommentRemovingWriter(): CommentWriter {
|
||||
return {
|
||||
reset,
|
||||
setSourceFile,
|
||||
getLeadingCommentsToEmit(node: TextRange): CommentRange[] { return undefined; },
|
||||
getTrailingCommentsToEmit(node: TextRange): CommentRange[] { return undefined; },
|
||||
emitDetachedComments,
|
||||
emitLeadingComments(node: TextRange, comments?: CommentRange[]): void { },
|
||||
emitTrailingComments(node: TextRange, comments?: CommentRange[]): void { },
|
||||
};
|
||||
|
||||
function emitDetachedComments(node: TextRange): void {
|
||||
emitDetachedCommentsAndUpdateCommentsInfo(node, /*removeComments*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
function createCommentPreservingWriter(): CommentWriter {
|
||||
const noComments: CommentRange[] = [];
|
||||
return {
|
||||
reset,
|
||||
setSourceFile,
|
||||
getLeadingCommentsToEmit,
|
||||
getTrailingCommentsToEmit,
|
||||
emitDetachedComments,
|
||||
emitLeadingComments,
|
||||
emitTrailingComments,
|
||||
};
|
||||
|
||||
function getLeadingCommentsToEmit(node: TextRange) {
|
||||
if (nodeIsSynthesized(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!leadingCommentRangeNodeStarts[node.pos]) {
|
||||
leadingCommentRangeNodeStarts[node.pos] = true;
|
||||
const comments = hasDetachedComments(node.pos)
|
||||
? getLeadingCommentsWithoutDetachedComments()
|
||||
: getLeadingCommentRanges(currentText, node.pos);
|
||||
return consumeCommentRanges(comments);
|
||||
}
|
||||
|
||||
return noComments;
|
||||
}
|
||||
|
||||
function getTrailingCommentsToEmit(node: TextRange) {
|
||||
if (nodeIsSynthesized(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!trailingCommentRangeNodeEnds[node.end]) {
|
||||
trailingCommentRangeNodeEnds[node.end] = true;
|
||||
const comments = getTrailingCommentRanges(currentText, node.end);
|
||||
return consumeCommentRanges(comments);
|
||||
}
|
||||
|
||||
return noComments;
|
||||
}
|
||||
|
||||
function hasConsumedCommentRange(comment: CommentRange) {
|
||||
return comment.end === consumedCommentRanges[comment.pos];
|
||||
}
|
||||
|
||||
function consumeCommentRange(comment: CommentRange) {
|
||||
if (!hasConsumedCommentRange(comment)) {
|
||||
consumedCommentRanges[comment.pos] = comment.end;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function consumeCommentRanges(comments: CommentRange[]) {
|
||||
let consumed: CommentRange[];
|
||||
if (comments) {
|
||||
let commentsSkipped = 0;
|
||||
let commentsConsumed = 0;
|
||||
for (let i = 0; i < comments.length; i++) {
|
||||
const comment = comments[i];
|
||||
if (consumeCommentRange(comment)) {
|
||||
commentsConsumed++;
|
||||
if (commentsSkipped !== 0) {
|
||||
if (consumed === undefined) {
|
||||
consumed = [comment];
|
||||
}
|
||||
else {
|
||||
consumed.push(comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
commentsSkipped++;
|
||||
if (commentsConsumed !== 0 && consumed === undefined) {
|
||||
consumed = comments.slice(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (commentsConsumed) {
|
||||
return consumed || comments;
|
||||
}
|
||||
}
|
||||
|
||||
return noComments;
|
||||
}
|
||||
|
||||
function emitLeadingComments(range: TextRange, leadingComments: CommentRange[] = getLeadingCommentsToEmit(range)) {
|
||||
emitNewLineBeforeLeadingComments(currentLineMap, writer, range, leadingComments);
|
||||
|
||||
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
||||
emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
|
||||
}
|
||||
|
||||
function emitTrailingComments(range: TextRange, trailingComments = getTrailingCommentsToEmit(range)) {
|
||||
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
|
||||
emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment);
|
||||
}
|
||||
|
||||
function emitDetachedComments(range: TextRange) {
|
||||
emitDetachedCommentsAndUpdateCommentsInfo(range, /*removeComments*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
currentSourceFile = undefined;
|
||||
currentText = undefined;
|
||||
currentLineMap = undefined;
|
||||
detachedCommentsInfo = undefined;
|
||||
consumedCommentRanges = undefined;
|
||||
trailingCommentRangeNodeEnds = undefined;
|
||||
leadingCommentRangeNodeStarts = undefined;
|
||||
}
|
||||
|
||||
function setSourceFile(sourceFile: SourceFile) {
|
||||
currentSourceFile = sourceFile;
|
||||
currentText = sourceFile.text;
|
||||
currentLineMap = getLineStarts(sourceFile);
|
||||
detachedCommentsInfo = undefined;
|
||||
consumedCommentRanges = [];
|
||||
leadingCommentRangeNodeStarts = [];
|
||||
trailingCommentRangeNodeEnds = [];
|
||||
}
|
||||
|
||||
function hasDetachedComments(pos: number) {
|
||||
return detachedCommentsInfo !== undefined && lastOrUndefined(detachedCommentsInfo).nodePos === pos;
|
||||
}
|
||||
|
||||
function getLeadingCommentsWithoutDetachedComments() {
|
||||
// get the leading comments from detachedPos
|
||||
const pos = lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos;
|
||||
const leadingComments = getLeadingCommentRanges(currentText, pos);
|
||||
if (detachedCommentsInfo.length - 1) {
|
||||
detachedCommentsInfo.pop();
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = undefined;
|
||||
}
|
||||
|
||||
return leadingComments;
|
||||
}
|
||||
|
||||
function emitDetachedCommentsAndUpdateCommentsInfo(node: TextRange, removeComments: boolean) {
|
||||
const currentDetachedCommentInfo = emitDetachedComments(currentText, currentLineMap, writer, writeComment, node, newLine, removeComments);
|
||||
|
||||
if (currentDetachedCommentInfo) {
|
||||
if (detachedCommentsInfo) {
|
||||
detachedCommentsInfo.push(currentDetachedCommentInfo);
|
||||
}
|
||||
else {
|
||||
detachedCommentsInfo = [currentDetachedCommentInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string) {
|
||||
emitPos(comment.pos);
|
||||
writeCommentRange(text, lineMap, writer, comment, newLine);
|
||||
emitPos(comment.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -895,7 +895,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
|
||||
function emitLiteral(node: LiteralExpression | TemplateLiteralFragment) {
|
||||
const text = getLiteralText(node);
|
||||
const text = getLiteralText(node, currentSourceFile, languageVersion);
|
||||
|
||||
if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
|
||||
writer.writeLiteral(text);
|
||||
@ -909,43 +909,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
}
|
||||
}
|
||||
|
||||
function getLiteralText(node: LiteralExpression | TemplateLiteralFragment) {
|
||||
// Any template literal or string literal with an extended escape
|
||||
// (e.g. "\u{0067}") will need to be downleveled as a escaped string literal.
|
||||
if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) {
|
||||
return getQuotedEscapedLiteralText("\"", node.text, "\"");
|
||||
}
|
||||
|
||||
// If we don't need to downlevel and we can reach the original source text using
|
||||
// the node's parent reference, then simply get the text as it was originally written.
|
||||
if (node.parent) {
|
||||
return getTextOfNodeFromSourceText(currentText, node);
|
||||
}
|
||||
|
||||
// If we can't reach the original source text, use the canonical form if it's a number,
|
||||
// or an escaped quoted form of the original text if it's string-like.
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
return getQuotedEscapedLiteralText("\"", node.text, "\"");
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
return getQuotedEscapedLiteralText("`", node.text, "`");
|
||||
case SyntaxKind.TemplateHead:
|
||||
return getQuotedEscapedLiteralText("`", node.text, "${");
|
||||
case SyntaxKind.TemplateMiddle:
|
||||
return getQuotedEscapedLiteralText("}", node.text, "${");
|
||||
case SyntaxKind.TemplateTail:
|
||||
return getQuotedEscapedLiteralText("}", node.text, "`");
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return node.text;
|
||||
}
|
||||
|
||||
Debug.fail(`Literal kind '${node.kind}' not accounted for.`);
|
||||
}
|
||||
|
||||
function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) {
|
||||
return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote;
|
||||
}
|
||||
|
||||
function emitDownlevelRawTemplateLiteral(node: LiteralExpression) {
|
||||
// Find original source text, since we need to emit the raw strings of the tagged template.
|
||||
// The raw strings contain the (escaped) strings of what the user wrote.
|
||||
@ -6590,7 +6553,8 @@ const _super = (function (geti, seti) {
|
||||
}
|
||||
const moduleName = getExternalModuleName(importNode);
|
||||
if (moduleName.kind === SyntaxKind.StringLiteral) {
|
||||
return tryRenameExternalModule(<LiteralExpression>moduleName) || getLiteralText(<LiteralExpression>moduleName);
|
||||
return tryRenameExternalModule(<LiteralExpression>moduleName)
|
||||
|| getLiteralText(<LiteralExpression>moduleName, currentSourceFile, languageVersion);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@ -144,14 +144,9 @@ namespace ts {
|
||||
|
||||
export function createLiteral(value: string): StringLiteral;
|
||||
export function createLiteral(value: number): LiteralExpression;
|
||||
export function createLiteral(value: string | number | boolean | void): PrimaryExpression;
|
||||
export function createLiteral<T extends PrimaryExpression>(value: string | number | boolean | void): T {
|
||||
if (typeof value === "string") {
|
||||
const node = <T & StringLiteral>createNode(SyntaxKind.StringLiteral);
|
||||
node.text = value;
|
||||
return node;
|
||||
}
|
||||
else if (typeof value === "number") {
|
||||
export function createLiteral(value: string | number | boolean): PrimaryExpression;
|
||||
export function createLiteral<T extends PrimaryExpression>(value: string | number | boolean): T {
|
||||
if (typeof value === "number") {
|
||||
const node = <T & LiteralExpression>createNode(SyntaxKind.NumericLiteral);
|
||||
node.text = value.toString();
|
||||
return node;
|
||||
@ -159,8 +154,10 @@ namespace ts {
|
||||
else if (typeof value === "boolean") {
|
||||
return <T>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword);
|
||||
}
|
||||
else if (value === null) {
|
||||
return <T>createNode(SyntaxKind.NullKeyword);
|
||||
else {
|
||||
const node = <T & StringLiteral>createNode(SyntaxKind.StringLiteral);
|
||||
node.text = String(value);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,9 +251,6 @@ namespace ts {
|
||||
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
||||
return createLiteral(value);
|
||||
}
|
||||
else if (value === null) {
|
||||
return createLiteral(null);
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
|
||||
2421
src/compiler/printer.ts
Normal file
2421
src/compiler/printer.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,12 @@
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function getTransformers(compilerOptions: CompilerOptions) {
|
||||
const transformers: Transformer[] = [];
|
||||
// TODO(rbuckton): Add transformers
|
||||
return transformers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of SourceFiles by passing them through each transformer.
|
||||
*
|
||||
|
||||
@ -20,6 +20,9 @@
|
||||
"factory.ts",
|
||||
"visitor.ts",
|
||||
"transformer.ts",
|
||||
"comments.ts",
|
||||
"printer.ts",
|
||||
"declarationEmitter.ts",
|
||||
"emitter.ts",
|
||||
"program.ts",
|
||||
"commandLineParser.ts",
|
||||
|
||||
@ -2795,6 +2795,7 @@ namespace ts {
|
||||
UMDDefine = 1 << 2, // This node should be replaced with the UMD define helper.
|
||||
NoLexicalEnvironment = 1 << 3, // A new LexicalEnvironment should *not* be introduced when emitting this node.
|
||||
SingleLine = 1 << 4, // The contents of this node should be emit on a single line.
|
||||
MultiLine = 1 << 5, // The contents of this node should be emit on multiple lines.
|
||||
}
|
||||
|
||||
/** Additional context provided to `visitEachChild` */
|
||||
|
||||
@ -102,6 +102,22 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getLanguageVersion(compilerOptions: CompilerOptions) {
|
||||
return compilerOptions.target || ScriptTarget.ES3;
|
||||
}
|
||||
|
||||
export function getModuleKind(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions.module) {
|
||||
return compilerOptions.module;
|
||||
}
|
||||
|
||||
if (getLanguageVersion(compilerOptions) === ScriptTarget.ES6) {
|
||||
return ModuleKind.ES6;
|
||||
}
|
||||
|
||||
return ModuleKind.None;
|
||||
}
|
||||
|
||||
export function hasResolvedModule(sourceFile: SourceFile, moduleNameText: string): boolean {
|
||||
return sourceFile.resolvedModules && hasProperty(sourceFile.resolvedModules, moduleNameText);
|
||||
}
|
||||
@ -242,6 +258,60 @@ namespace ts {
|
||||
return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node, includeTrivia);
|
||||
}
|
||||
|
||||
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, languageVersion: ScriptTarget) {
|
||||
// Any template literal or string literal with an extended escape
|
||||
// (e.g. "\u{0067}") will need to be downleveled as a escaped string literal.
|
||||
if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) {
|
||||
return getQuotedEscapedLiteralText("\"", node.text, "\"");
|
||||
}
|
||||
|
||||
// If we don't need to downlevel and we can reach the original source text using
|
||||
// the node's parent reference, then simply get the text as it was originally written.
|
||||
if (!nodeIsSynthesized(node) && node.parent) {
|
||||
const text = getSourceTextOfNodeFromSourceFile(sourceFile, node);
|
||||
if (languageVersion < ScriptTarget.ES6 && isBinaryOrOctalIntegerLiteral(node, text)) {
|
||||
return node.text;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
// If we can't reach the original source text, use the canonical form if it's a number,
|
||||
// or an escaped quoted form of the original text if it's string-like.
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
return getQuotedEscapedLiteralText("\"", node.text, "\"");
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
return getQuotedEscapedLiteralText("`", node.text, "`");
|
||||
case SyntaxKind.TemplateHead:
|
||||
return getQuotedEscapedLiteralText("`", node.text, "${");
|
||||
case SyntaxKind.TemplateMiddle:
|
||||
return getQuotedEscapedLiteralText("}", node.text, "${");
|
||||
case SyntaxKind.TemplateTail:
|
||||
return getQuotedEscapedLiteralText("}", node.text, "`");
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return node.text;
|
||||
}
|
||||
|
||||
Debug.fail(`Literal kind '${node.kind}' not accounted for.`);
|
||||
}
|
||||
|
||||
export function isBinaryOrOctalIntegerLiteral(node: LiteralLikeNode, text: string) {
|
||||
if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) {
|
||||
switch (text.charCodeAt(1)) {
|
||||
case CharacterCodes.b:
|
||||
case CharacterCodes.B:
|
||||
case CharacterCodes.o:
|
||||
case CharacterCodes.O:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) {
|
||||
return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote;
|
||||
}
|
||||
|
||||
// Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__'
|
||||
export function escapeIdentifier(identifier: string): string {
|
||||
return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier;
|
||||
@ -2765,7 +2835,7 @@ namespace ts {
|
||||
return isUnaryExpressionKind(node.kind);
|
||||
}
|
||||
|
||||
function isExpressionKind(kind: SyntaxKind): boolean {
|
||||
export function isExpressionKind(kind: SyntaxKind): boolean {
|
||||
return kind === SyntaxKind.ConditionalExpression
|
||||
|| kind === SyntaxKind.YieldExpression
|
||||
|| kind === SyntaxKind.ArrowFunction
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user