UNPKG

prettier-plugin-solidity

Version:

A Prettier Plugin for automatically formatting your Solidity code.

104 lines 4.72 kB
import { doc } from 'prettier'; import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { getNodeMetadata, updateMetadata } from '../slang-utils/metadata.js'; import { Expression } from './Expression.js'; const { group, hardline, ifBreak, indent, line, softline } = doc.builders; function fillTab(options) { if (options.useTabs) return '\t'; // For the odd case of `tabWidth` of 1 or 0 we initiate `fillTab` as a single // space. return options.tabWidth > 2 ? ' '.repeat(options.tabWidth - 1) : ' '; } function experimentalTernaries(node, path, print, options) { const grandparent = path.getNode(2); const isNested = grandparent.kind === NonterminalKind.ConditionalExpression; const isNestedAsTrueExpression = isNested && grandparent.trueExpression.variant === node; const falseExpressionInSameLine = node.falseExpression.variant.kind === NonterminalKind.TupleExpression || node.falseExpression.variant.kind === NonterminalKind.ConditionalExpression; // If the `condition` breaks into multiple lines, we add parentheses, // unless it already is a `TupleExpression`. const operand = path.call(print, 'operand'); const operandDoc = group([ node.operand.variant.kind === NonterminalKind.TupleExpression ? operand : ifBreak(['(', printSeparatedItem(operand), ')'], operand), ' ?' ]); // To switch between "case-style" and "curious" ternaries we force a new line // before a nested `trueExpression` if the current `Conditional` is also a // `trueExpression`. const trueExpressionDoc = indent([ isNestedAsTrueExpression ? hardline : line, path.call(print, 'trueExpression') ]); const conditionAndTrueExpressionGroup = group([operandDoc, trueExpressionDoc], { id: Symbol('Slang.ConditionalExpression.trueExpression') }); const falseExpression = path.call(print, 'falseExpression'); const falseExpressionDoc = [ isNested ? hardline : line, ':', falseExpressionInSameLine ? [' ', falseExpression] : ifBreak([fillTab(options), indent(falseExpression)], [' ', falseExpression], { // We only add `fillTab` if we are sure the trueExpression is indented groupId: conditionAndTrueExpressionGroup.id }) ]; const document = group([conditionAndTrueExpressionGroup, falseExpressionDoc]); return grandparent.kind === NonterminalKind.VariableDeclarationValue ? group(indent([softline, document])) : document; } function traditionalTernaries(path, print) { return group([ path.call(print, 'operand'), indent([ // Nested trueExpression and falseExpression are always printed in a new // line path.getNode(2).kind === NonterminalKind.ConditionalExpression ? hardline : line, '? ', path.call(print, 'trueExpression'), line, ': ', path.call(print, 'falseExpression') ]) ]); } export class ConditionalExpression { constructor(ast, options) { this.kind = NonterminalKind.ConditionalExpression; let metadata = getNodeMetadata(ast); this.operand = new Expression(ast.operand, options); this.trueExpression = new Expression(ast.trueExpression, options); this.falseExpression = new Expression(ast.falseExpression, options); metadata = updateMetadata(metadata, [ this.operand, this.trueExpression, this.falseExpression ]); this.comments = metadata.comments; this.loc = metadata.loc; if (options.experimentalTernaries) { // We can remove parentheses only because we are sure that the // `condition` must be a single `bool` value. const operandLoc = this.operand.loc; while (this.operand.variant.kind === NonterminalKind.TupleExpression && this.operand.variant.items.items.length === 1 && this.operand.variant.items.items[0].expression.variant.kind !== NonterminalKind.ConditionalExpression) { this.operand = this.operand.variant.items.items[0].expression; } this.operand.loc = operandLoc; } } print(path, print, options) { return options.experimentalTernaries ? experimentalTernaries(this, path, print, options) : traditionalTernaries(path, print); } } //# sourceMappingURL=ConditionalExpression.js.map