1/* @internal */ 2namespace ts.formatting { 3 export const enum FormattingRequestKind { 4 FormatDocument, 5 FormatSelection, 6 FormatOnEnter, 7 FormatOnSemicolon, 8 FormatOnOpeningCurlyBrace, 9 FormatOnClosingCurlyBrace 10 } 11 12 export class FormattingContext { 13 public currentTokenSpan!: TextRangeWithKind; 14 public nextTokenSpan!: TextRangeWithKind; 15 public contextNode!: Node; 16 public currentTokenParent!: Node; 17 public nextTokenParent!: Node; 18 19 private contextNodeAllOnSameLine: boolean | undefined; 20 private nextNodeAllOnSameLine: boolean | undefined; 21 private tokensAreOnSameLine: boolean | undefined; 22 private contextNodeBlockIsOnOneLine: boolean | undefined; 23 private nextNodeBlockIsOnOneLine: boolean | undefined; 24 25 constructor(public readonly sourceFile: SourceFileLike, public formattingRequestKind: FormattingRequestKind, public options: FormatCodeSettings) { 26 } 27 28 public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) { 29 this.currentTokenSpan = Debug.checkDefined(currentRange); 30 this.currentTokenParent = Debug.checkDefined(currentTokenParent); 31 this.nextTokenSpan = Debug.checkDefined(nextRange); 32 this.nextTokenParent = Debug.checkDefined(nextTokenParent); 33 this.contextNode = Debug.checkDefined(commonParent); 34 35 // drop cached results 36 this.contextNodeAllOnSameLine = undefined; 37 this.nextNodeAllOnSameLine = undefined; 38 this.tokensAreOnSameLine = undefined; 39 this.contextNodeBlockIsOnOneLine = undefined; 40 this.nextNodeBlockIsOnOneLine = undefined; 41 } 42 43 public ContextNodeAllOnSameLine(): boolean { 44 if (this.contextNodeAllOnSameLine === undefined) { 45 this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode); 46 } 47 48 return this.contextNodeAllOnSameLine; 49 } 50 51 public NextNodeAllOnSameLine(): boolean { 52 if (this.nextNodeAllOnSameLine === undefined) { 53 this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent); 54 } 55 56 return this.nextNodeAllOnSameLine; 57 } 58 59 public TokensAreOnSameLine(): boolean { 60 if (this.tokensAreOnSameLine === undefined) { 61 const startLine = this.sourceFile.getLineAndCharacterOfPosition(this.currentTokenSpan.pos).line; 62 const endLine = this.sourceFile.getLineAndCharacterOfPosition(this.nextTokenSpan.pos).line; 63 this.tokensAreOnSameLine = (startLine === endLine); 64 } 65 66 return this.tokensAreOnSameLine; 67 } 68 69 public ContextNodeBlockIsOnOneLine() { 70 if (this.contextNodeBlockIsOnOneLine === undefined) { 71 this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode); 72 } 73 74 return this.contextNodeBlockIsOnOneLine; 75 } 76 77 public NextNodeBlockIsOnOneLine() { 78 if (this.nextNodeBlockIsOnOneLine === undefined) { 79 this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent); 80 } 81 82 return this.nextNodeBlockIsOnOneLine; 83 } 84 85 private NodeIsOnOneLine(node: Node): boolean { 86 const startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart(this.sourceFile)).line; 87 const endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line; 88 return startLine === endLine; 89 } 90 91 private BlockIsOnOneLine(node: Node): boolean { 92 const openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile); 93 const closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile); 94 if (openBrace && closeBrace) { 95 const startLine = this.sourceFile.getLineAndCharacterOfPosition(openBrace.getEnd()).line; 96 const endLine = this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line; 97 return startLine === endLine; 98 } 99 return false; 100 } 101 } 102} 103