diff --git a/src/index.ts b/src/index.ts index da93e5983..e42f9c9a8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -51,10 +51,8 @@ const parsers = { [antlrParserId]: antlrParser }; -const antlrCanAttachComment = (node: { type: string }): boolean => - typeof node.type === 'string' && - node.type !== 'BlockComment' && - node.type !== 'LineComment'; +const antlrCanAttachComment = ({ type }: { type: string }): boolean => + typeof type === 'string' && type !== 'BlockComment' && type !== 'LineComment'; const canAttachComment = (node: AstNode): boolean => typeof node !== 'string' && typeof node !== 'undefined' && diff --git a/src/slang-comments/handlers/add-collection-node-first-comment.ts b/src/slang-comments/handlers/add-collection-first-comment.ts similarity index 62% rename from src/slang-comments/handlers/add-collection-node-first-comment.ts rename to src/slang-comments/handlers/add-collection-first-comment.ts index fa604808f..03e21449e 100644 --- a/src/slang-comments/handlers/add-collection-node-first-comment.ts +++ b/src/slang-comments/handlers/add-collection-first-comment.ts @@ -1,11 +1,11 @@ import { util } from 'prettier'; -import type { Comment, CollectionNode } from '../../slang-nodes/types.d.ts'; +import type { Comment, Collection } from '../../slang-nodes/types.d.ts'; const { addDanglingComment, addLeadingComment } = util; -export default function addCollectionNodeFirstComment( - node: CollectionNode, +export default function addCollectionFirstComment( + node: Collection, comment: Comment ): void { if (node.items.length === 0) { diff --git a/src/slang-comments/handlers/add-collection-node-last-comment.ts b/src/slang-comments/handlers/add-collection-last-comment.ts similarity index 64% rename from src/slang-comments/handlers/add-collection-node-last-comment.ts rename to src/slang-comments/handlers/add-collection-last-comment.ts index 3924f8c10..b52fc3e72 100644 --- a/src/slang-comments/handlers/add-collection-node-last-comment.ts +++ b/src/slang-comments/handlers/add-collection-last-comment.ts @@ -1,11 +1,11 @@ import { util } from 'prettier'; -import type { Comment, CollectionNode } from '../../slang-nodes/types.d.ts'; +import type { Comment, Collection } from '../../slang-nodes/types.d.ts'; const { addDanglingComment, addTrailingComment } = util; -export default function addCollectionNodeLastComment( - node: CollectionNode, +export default function addCollectionLastComment( + node: Collection, comment: Comment ): void { if (node.items.length === 0) { diff --git a/src/slang-comments/handlers/handle-block-comments.ts b/src/slang-comments/handlers/handle-block-comments.ts index 1f05e3925..5ad4085a5 100644 --- a/src/slang-comments/handlers/handle-block-comments.ts +++ b/src/slang-comments/handlers/handle-block-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -15,12 +15,12 @@ export default function handleBlockComments({ } if (precedingNode?.kind === NonterminalKind.Statements) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } if (followingNode?.kind === NonterminalKind.Statements) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-contract-definition-comments.ts b/src/slang-comments/handlers/handle-contract-definition-comments.ts index e6f76f4a1..a8dc0a21d 100644 --- a/src/slang-comments/handlers/handle-contract-definition-comments.ts +++ b/src/slang-comments/handlers/handle-contract-definition-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -36,7 +36,7 @@ export default function handleContractDefinitionComments({ // The comment is at the end of the body of the ContractDefinition. if (precedingNode?.kind === NonterminalKind.ContractMembers) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } @@ -52,7 +52,7 @@ export default function handleContractDefinitionComments({ // If the last ContractSpecifier's an InheritanceSpecifier, the comment // is appended to the last InheritanceType. if (lastContractSpecifier.kind === NonterminalKind.InheritanceSpecifier) { - addCollectionNodeLastComment(lastContractSpecifier.types, comment); + addCollectionLastComment(lastContractSpecifier.types, comment); return true; } if ( diff --git a/src/slang-comments/handlers/handle-contract-specifiers-comments.ts b/src/slang-comments/handlers/handle-contract-specifiers-comments.ts index 03aa79817..0af5a6df3 100644 --- a/src/slang-comments/handlers/handle-contract-specifiers-comments.ts +++ b/src/slang-comments/handlers/handle-contract-specifiers-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -20,7 +20,7 @@ export default function handleContractSpecifiersComments({ precedingNode.kind === NonterminalKind.ContractSpecifier ) { if (precedingNode.variant.kind === NonterminalKind.InheritanceSpecifier) { - addCollectionNodeLastComment(precedingNode.variant.types, comment); + addCollectionLastComment(precedingNode.variant.types, comment); return true; } if (precedingNode.variant.kind === NonterminalKind.StorageLayoutSpecifier) { diff --git a/src/slang-comments/handlers/handle-else-branch-comments.ts b/src/slang-comments/handlers/handle-else-branch-comments.ts index 0e25060c7..a3ee7b865 100644 --- a/src/slang-comments/handlers/handle-else-branch-comments.ts +++ b/src/slang-comments/handlers/handle-else-branch-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -20,7 +20,7 @@ export default function handleElseBranchComments({ followingNode.variant.kind === NonterminalKind.IfStatement ) { if (followingNode.variant.body.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment( + addCollectionFirstComment( followingNode.variant.body.variant.statements, comment ); diff --git a/src/slang-comments/handlers/handle-if-statement-comments.ts b/src/slang-comments/handlers/handle-if-statement-comments.ts index e03560b57..4a702cc51 100644 --- a/src/slang-comments/handlers/handle-if-statement-comments.ts +++ b/src/slang-comments/handlers/handle-if-statement-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -45,10 +45,7 @@ export default function handleIfStatementComments({ if (followingNode.kind === NonterminalKind.IfStatement) { if (followingNode.body.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment( - followingNode.body.variant.statements, - comment - ); + addCollectionFirstComment(followingNode.body.variant.statements, comment); } else { addLeadingComment(followingNode.body.variant, comment); } @@ -60,7 +57,7 @@ export default function handleIfStatementComments({ // if (a) /* comment */ true if (enclosingNode.body === followingNode) { if (followingNode.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment(followingNode.variant.statements, comment); + addCollectionFirstComment(followingNode.variant.statements, comment); } else { addLeadingComment(followingNode, comment); } diff --git a/src/slang-comments/handlers/handle-interface-definition-comments.ts b/src/slang-comments/handlers/handle-interface-definition-comments.ts index 43dcfde07..356cfc328 100644 --- a/src/slang-comments/handlers/handle-interface-definition-comments.ts +++ b/src/slang-comments/handlers/handle-interface-definition-comments.ts @@ -1,8 +1,8 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -24,7 +24,7 @@ export default function handleInterfaceDefinitionComments({ // The comment is at the end of the body of the InterfaceDefinition. if (precedingNode?.kind === NonterminalKind.InterfaceMembers) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } @@ -33,7 +33,7 @@ export default function handleInterfaceDefinitionComments({ nextCharacter === '{' && followingNode?.kind === NonterminalKind.InterfaceMembers ) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-library-definition-comments.ts b/src/slang-comments/handlers/handle-library-definition-comments.ts index 4421794dc..dfe5bafe1 100644 --- a/src/slang-comments/handlers/handle-library-definition-comments.ts +++ b/src/slang-comments/handlers/handle-library-definition-comments.ts @@ -1,8 +1,8 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -24,7 +24,7 @@ export default function handleLibraryDefinitionComments({ // The comment is at the end of the body of the ContractDefinition. if (precedingNode?.kind === NonterminalKind.LibraryMembers) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } @@ -33,7 +33,7 @@ export default function handleLibraryDefinitionComments({ nextCharacter === '{' && followingNode?.kind === NonterminalKind.LibraryMembers ) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-modifier-invocation-comments.ts b/src/slang-comments/handlers/handle-modifier-invocation-comments.ts index 76869222d..06e8d749a 100644 --- a/src/slang-comments/handlers/handle-modifier-invocation-comments.ts +++ b/src/slang-comments/handlers/handle-modifier-invocation-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -34,7 +34,7 @@ export default function handleModifierInvocationComments({ if (followingNode.variant.arguments.items.length === 0) { addTrailingComment(enclosingNode, comment); } else { - addCollectionNodeFirstComment(followingNode.variant.arguments, comment); + addCollectionFirstComment(followingNode.variant.arguments, comment); } return true; } diff --git a/src/slang-comments/handlers/handle-parameters-declaration-comments.ts b/src/slang-comments/handlers/handle-parameters-declaration-comments.ts index b2cbcd1a9..0100e853e 100644 --- a/src/slang-comments/handlers/handle-parameters-declaration-comments.ts +++ b/src/slang-comments/handlers/handle-parameters-declaration-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -15,12 +15,12 @@ export default function handleBlockComments({ } if (precedingNode?.kind === NonterminalKind.Parameters) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } if (followingNode?.kind === NonterminalKind.Parameters) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts b/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts index 5078a0c40..865b93fb9 100644 --- a/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts +++ b/src/slang-comments/handlers/handle-positional-arguments-declaration-comments.ts @@ -1,6 +1,6 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; -import addCollectionNodeLastComment from './add-collection-node-last-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; +import addCollectionLastComment from './add-collection-last-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -15,12 +15,12 @@ export default function handlePositionalArgumentsDeclarationComments({ } if (precedingNode?.kind === NonterminalKind.PositionalArguments) { - addCollectionNodeLastComment(precedingNode, comment); + addCollectionLastComment(precedingNode, comment); return true; } if (followingNode?.kind === NonterminalKind.PositionalArguments) { - addCollectionNodeFirstComment(followingNode, comment); + addCollectionFirstComment(followingNode, comment); return true; } diff --git a/src/slang-comments/handlers/handle-while-statement-comments.ts b/src/slang-comments/handlers/handle-while-statement-comments.ts index 29898c65f..3f40dc12c 100644 --- a/src/slang-comments/handlers/handle-while-statement-comments.ts +++ b/src/slang-comments/handlers/handle-while-statement-comments.ts @@ -1,7 +1,7 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import { util } from 'prettier'; import { locEnd } from '../../slang-utils/loc.js'; -import addCollectionNodeFirstComment from './add-collection-node-first-comment.js'; +import addCollectionFirstComment from './add-collection-first-comment.js'; import type { HandlerParams } from './types.d.ts'; @@ -37,7 +37,7 @@ export default function handleWhileStatementComments({ if (enclosingNode.body === followingNode) { if (followingNode.variant.kind === NonterminalKind.Block) { - addCollectionNodeFirstComment(followingNode.variant.statements, comment); + addCollectionFirstComment(followingNode.variant.statements, comment); } else { addLeadingComment(followingNode, comment); } diff --git a/src/slang-comments/printer.ts b/src/slang-comments/printer.ts index cb2edf6bd..302f6fe25 100644 --- a/src/slang-comments/printer.ts +++ b/src/slang-comments/printer.ts @@ -3,9 +3,7 @@ import { isComment } from '../slang-utils/is-comment.js'; import type { AstPath, Doc } from 'prettier'; import type { AstNode } from '../slang-nodes/types.d.ts'; -export function printComment(commentPath: AstPath): Doc { - const comment = commentPath.getNode()!; - +export function printComment({ node: comment }: AstPath): Doc { if (isComment(comment)) { return comment.print(); } diff --git a/src/slang-nodes/BitwiseOrExpression.ts b/src/slang-nodes/BitwiseOrExpression.ts index 614e71b4b..3c51cfa64 100644 --- a/src/slang-nodes/BitwiseOrExpression.ts +++ b/src/slang-nodes/BitwiseOrExpression.ts @@ -38,11 +38,11 @@ export class BitwiseOrExpression implements SlangNode { loc; - leftOperand; + leftOperand: Expression; - operator; + operator: string; - rightOperand; + rightOperand: Expression; constructor(ast: ast.BitwiseOrExpression, options: ParserOptions) { let metadata = getNodeMetadata(ast); diff --git a/src/slang-nodes/ConditionalExpression.ts b/src/slang-nodes/ConditionalExpression.ts index 24f7bfc22..3eb098044 100644 --- a/src/slang-nodes/ConditionalExpression.ts +++ b/src/slang-nodes/ConditionalExpression.ts @@ -11,11 +11,11 @@ import type { PrintFunction, SlangNode } from '../types.d.ts'; const { group, hardline, ifBreak, indent, line, softline } = doc.builders; -function fillTab(options: ParserOptions): Doc { - if (options.useTabs) return '\t'; +function fillTab({ useTabs, tabWidth }: ParserOptions): Doc { + if (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) : ' '; + return tabWidth > 2 ? ' '.repeat(tabWidth - 1) : ' '; } function experimentalTernaries( @@ -24,7 +24,7 @@ function experimentalTernaries( print: PrintFunction, options: ParserOptions ): Doc { - const grandparent = path.getNode(2) as StrictAstNode; + const grandparent = path.grandparent as StrictAstNode; const isNested = grandparent.kind === NonterminalKind.ConditionalExpression; const isNestedAsTrueExpression = isNested && grandparent.trueExpression.variant === node; @@ -50,9 +50,10 @@ function experimentalTernaries( path.call(print, 'trueExpression') ]); + const groupId = Symbol('Slang.ConditionalExpression.trueExpression'); const conditionAndTrueExpressionGroup = group( [operandDoc, trueExpressionDoc], - { id: Symbol('Slang.ConditionalExpression.trueExpression') } + { id: groupId } ); const falseExpression = path.call(print, 'falseExpression'); @@ -64,10 +65,9 @@ function experimentalTernaries( : ifBreak( [fillTab(options), indent(falseExpression)], [' ', falseExpression], - { - // We only add `fillTab` if we are sure the trueExpression is indented - groupId: conditionAndTrueExpressionGroup.id - } + // We only add `fillTab` if we are sure the trueExpression is + // indented. + { groupId } ) ]; @@ -87,7 +87,7 @@ function traditionalTernaries( indent([ // Nested trueExpression and falseExpression are always printed in a new // line - (path.getNode(2) as StrictAstNode).kind === + (path.grandparent as StrictAstNode).kind === NonterminalKind.ConditionalExpression ? hardline : line, diff --git a/src/slang-nodes/ContractDefinition.ts b/src/slang-nodes/ContractDefinition.ts index 031d9af55..cfea4cf2c 100644 --- a/src/slang-nodes/ContractDefinition.ts +++ b/src/slang-nodes/ContractDefinition.ts @@ -49,12 +49,12 @@ export class ContractDefinition implements SlangNode { // the same name as the contract. const compiler = coerce(options.compiler); if (compiler && !satisfies(compiler, '>=0.5.0')) { - for (const member of this.members.items) { + for (const { variant: member } of this.members.items) { if ( - member.variant.kind === NonterminalKind.FunctionDefinition && - member.variant.name.variant.value !== this.name.value + member.kind === NonterminalKind.FunctionDefinition && + member.name.variant.value !== this.name.value ) { - member.variant.cleanModifierInvocationArguments(); + member.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/ContractSpecifier.ts b/src/slang-nodes/ContractSpecifier.ts index 3df944fa8..bfa0970fd 100644 --- a/src/slang-nodes/ContractSpecifier.ts +++ b/src/slang-nodes/ContractSpecifier.ts @@ -5,8 +5,8 @@ import { StorageLayoutSpecifier } from './StorageLayoutSpecifier.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { AstNode } from './types.js'; -import type { PrintFunction, SlangNode } from '../types.js'; +import type { AstNode } from './types.d.ts'; +import type { PrintFunction, SlangNode } from '../types.d.ts'; export class ContractSpecifier implements SlangNode { readonly kind = NonterminalKind.ContractSpecifier; diff --git a/src/slang-nodes/ContractSpecifiers.ts b/src/slang-nodes/ContractSpecifiers.ts index 96b52098e..60065bd2d 100644 --- a/src/slang-nodes/ContractSpecifiers.ts +++ b/src/slang-nodes/ContractSpecifiers.ts @@ -7,8 +7,8 @@ import { ContractSpecifier } from './ContractSpecifier.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { AstNode } from './types.js'; -import type { PrintFunction, SlangNode } from '../types.js'; +import type { AstNode } from './types.d.ts'; +import type { PrintFunction, SlangNode } from '../types.d.ts'; const { group, ifBreak, line, softline } = doc.builders; diff --git a/src/slang-nodes/FallbackFunctionDefinition.ts b/src/slang-nodes/FallbackFunctionDefinition.ts index cff114207..8ed12dfb6 100644 --- a/src/slang-nodes/FallbackFunctionDefinition.ts +++ b/src/slang-nodes/FallbackFunctionDefinition.ts @@ -53,12 +53,12 @@ export class FallbackFunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { + for (const { variant: attribute } of this.attributes.items) { if ( - typeof attribute.variant !== 'string' && - attribute.variant.kind === NonterminalKind.ModifierInvocation + typeof attribute !== 'string' && + attribute.kind === NonterminalKind.ModifierInvocation ) { - attribute.variant.cleanModifierInvocationArguments(); + attribute.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/FunctionCallExpression.ts b/src/slang-nodes/FunctionCallExpression.ts index 78a9d1d83..029c6561e 100644 --- a/src/slang-nodes/FunctionCallExpression.ts +++ b/src/slang-nodes/FunctionCallExpression.ts @@ -39,18 +39,19 @@ export class FunctionCallExpression implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - let operandDoc = path.call(print, 'operand'); - let argumentsDoc = path.call(print, 'arguments'); + const operandDoc = path.call(print, 'operand'); + const argumentsDoc = path.call(print, 'arguments'); // If we are at the end of a MemberAccessChain we should indent the // arguments accordingly. if (isLabel(operandDoc) && operandDoc.label === 'MemberAccessChain') { const groupId = Symbol('Slang.FunctionCallExpression.operand'); - operandDoc = group(operandDoc.contents, { id: groupId }); - argumentsDoc = indentIfBreak(argumentsDoc, { groupId }); // We wrap the expression in a label in case there is an IndexAccess or // a FunctionCall following this IndexAccess. - return label('MemberAccessChain', [operandDoc, argumentsDoc]); + return label('MemberAccessChain', [ + group(operandDoc.contents, { id: groupId }), + indentIfBreak(argumentsDoc, { groupId }) + ]); } return [operandDoc, argumentsDoc].flat(); diff --git a/src/slang-nodes/FunctionDefinition.ts b/src/slang-nodes/FunctionDefinition.ts index 437258857..572f995ba 100644 --- a/src/slang-nodes/FunctionDefinition.ts +++ b/src/slang-nodes/FunctionDefinition.ts @@ -61,12 +61,12 @@ export class FunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { + for (const { variant: attribute } of this.attributes.items) { if ( - typeof attribute.variant !== 'string' && - attribute.variant.kind === NonterminalKind.ModifierInvocation + typeof attribute !== 'string' && + attribute.kind === NonterminalKind.ModifierInvocation ) { - attribute.variant.cleanModifierInvocationArguments(); + attribute.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/IfStatement.ts b/src/slang-nodes/IfStatement.ts index 608d45614..be3af109c 100644 --- a/src/slang-nodes/IfStatement.ts +++ b/src/slang-nodes/IfStatement.ts @@ -47,19 +47,20 @@ export class IfStatement implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { + const { kind: bodyKind, comments: bodyComments } = this.body.variant; return [ 'if (', printSeparatedItem(path.call(print, 'condition')), ')', - this.body.variant.kind === NonterminalKind.Block + bodyKind === NonterminalKind.Block ? [' ', path.call(print, 'body')] : group(indent([line, path.call(print, 'body')]), { - shouldBreak: this.body.variant.kind === NonterminalKind.IfStatement // `if` within `if` + shouldBreak: bodyKind === NonterminalKind.IfStatement // `if` within `if` }), this.elseBranch ? [ - this.body.variant.kind !== NonterminalKind.Block || // else on a new line if body is not a block - this.body.variant.comments.some( + bodyKind !== NonterminalKind.Block || // else on a new line if body is not a block + bodyComments.some( (comment) => !isBlockComment(comment) || comment.placement === 'ownLine' ) // or if body has trailing single line comments or a block comment on a new line diff --git a/src/slang-nodes/IndexAccessExpression.ts b/src/slang-nodes/IndexAccessExpression.ts index 722acd46c..73077fe39 100644 --- a/src/slang-nodes/IndexAccessExpression.ts +++ b/src/slang-nodes/IndexAccessExpression.ts @@ -1,5 +1,6 @@ import { doc } from 'prettier'; import { NonterminalKind } from '@nomicfoundation/slang/cst'; +import { printSeparatedItem } from '../slang-printers/print-separated-item.js'; import { isLabel } from '../slang-utils/is-label.js'; import { getNodeMetadata, updateMetadata } from '../slang-utils/metadata.js'; import { Expression } from './Expression.js'; @@ -10,7 +11,7 @@ import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { AstNode } from './types.d.ts'; import type { PrintFunction, SlangNode } from '../types.d.ts'; -const { group, indent, indentIfBreak, label, softline } = doc.builders; +const { group, indentIfBreak, label } = doc.builders; export class IndexAccessExpression implements SlangNode { readonly kind = NonterminalKind.IndexAccessExpression; @@ -43,24 +44,23 @@ export class IndexAccessExpression implements SlangNode { } print(path: AstPath, print: PrintFunction): Doc { - let operandDoc: Doc = path.call(print, 'operand'); - let indexDoc: Doc = group([ + const operandDoc = path.call(print, 'operand'); + const indexDoc = [ '[', - indent([softline, path.call(print, 'start'), path.call(print, 'end')]), - softline, + printSeparatedItem([path.call(print, 'start'), path.call(print, 'end')]), ']' - ]); + ]; // If we are at the end of a MemberAccessChain we should indent the // arguments accordingly. if (isLabel(operandDoc) && operandDoc.label === 'MemberAccessChain') { const groupId = Symbol('Slang.IndexAccessExpression.operand'); - operandDoc = group(operandDoc.contents, { id: groupId }); - - indexDoc = indentIfBreak(indexDoc, { groupId }); // We wrap the expression in a label in case there is an IndexAccess or // a FunctionCall following this IndexAccess. - return label('MemberAccessChain', [operandDoc, indexDoc]); + return label('MemberAccessChain', [ + group(operandDoc.contents, { id: groupId }), + indentIfBreak(indexDoc, { groupId }) + ]); } return [operandDoc, indexDoc].flat(); diff --git a/src/slang-nodes/MemberAccessExpression.ts b/src/slang-nodes/MemberAccessExpression.ts index 705837e6c..734c8a0fa 100644 --- a/src/slang-nodes/MemberAccessExpression.ts +++ b/src/slang-nodes/MemberAccessExpression.ts @@ -24,30 +24,26 @@ function isEndOfChain( path: AstPath ): boolean { for ( - let i = 0, - currentNode: StrictAstNode = node, - grandparentNode = path.getNode(i + 2)!; - isChainableExpression(grandparentNode); - i += 2, - currentNode = grandparentNode, - grandparentNode = path.getNode(i + 2)! + let i = 2, current: StrictAstNode = node, grandparent = path.getNode(i)!; + isChainableExpression(grandparent); + i += 2, current = grandparent, grandparent = path.getNode(i)! ) { - switch (grandparentNode.kind) { + switch (grandparent.kind) { case NonterminalKind.MemberAccessExpression: - // If direct ParentNode is a MemberAccess we are not at the end of the - // chain. + // If `grandparent` is a MemberAccessExpression we are not at the end + // of the chain. return false; case NonterminalKind.IndexAccessExpression: - // If direct ParentNode is an IndexAccess and currentNode is not the - // operand then it must be the start or the end in which case it is the - // end of the chain. - if (currentNode !== grandparentNode.operand.variant) return true; + // If `grandparent` is an IndexAccessExpression and `current` is not + // the operand then it must be the start or the end in which case it is + // the end of the chain. + if (current !== grandparent.operand.variant) return true; break; case NonterminalKind.FunctionCallExpression: - // If direct ParentNode is a FunctionCall and currentNode is not the - // operand then it must be and argument in which case it is the end + // If `grandparent` is a FunctionCallExpression and `current` is not + // the operand then it must be and argument in which case it is the end // of the chain. - if (currentNode !== grandparentNode.operand.variant) return true; + if (current !== grandparent.operand.variant) return true; break; } } diff --git a/src/slang-nodes/PositionalArguments.ts b/src/slang-nodes/PositionalArguments.ts index 7b47b0222..414b51b85 100644 --- a/src/slang-nodes/PositionalArguments.ts +++ b/src/slang-nodes/PositionalArguments.ts @@ -17,9 +17,9 @@ export class PositionalArguments implements SlangNode { loc; - items; + items: Expression[]; - separators; + separators: string[]; constructor(ast: ast.PositionalArguments, options: ParserOptions) { let metadata = getNodeMetadata(ast, true); diff --git a/src/slang-nodes/ReceiveFunctionDefinition.ts b/src/slang-nodes/ReceiveFunctionDefinition.ts index b14bb68b2..bcd158749 100644 --- a/src/slang-nodes/ReceiveFunctionDefinition.ts +++ b/src/slang-nodes/ReceiveFunctionDefinition.ts @@ -46,12 +46,12 @@ export class ReceiveFunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { + for (const { variant: attribute } of this.attributes.items) { if ( - typeof attribute.variant !== 'string' && - attribute.variant.kind === NonterminalKind.ModifierInvocation + typeof attribute !== 'string' && + attribute.kind === NonterminalKind.ModifierInvocation ) { - attribute.variant.cleanModifierInvocationArguments(); + attribute.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/ReturnStatement.ts b/src/slang-nodes/ReturnStatement.ts index 2e0a78f54..4e9a0433a 100644 --- a/src/slang-nodes/ReturnStatement.ts +++ b/src/slang-nodes/ReturnStatement.ts @@ -16,10 +16,11 @@ function printExpression( print: PrintFunction, options: ParserOptions ): Doc { - if (node.expression) { - return node.expression.variant.kind === NonterminalKind.TupleExpression || + const expressionVariant = node.expression?.variant; + if (expressionVariant) { + return expressionVariant.kind === NonterminalKind.TupleExpression || (options.experimentalTernaries && - node.expression.variant.kind === NonterminalKind.ConditionalExpression) + expressionVariant.kind === NonterminalKind.ConditionalExpression) ? [' ', path.call(print, 'expression')] : group(indent([line, path.call(print, 'expression')])); } diff --git a/src/slang-nodes/StateVariableDefinition.ts b/src/slang-nodes/StateVariableDefinition.ts index 0e5a746fc..7db4c2c3c 100644 --- a/src/slang-nodes/StateVariableDefinition.ts +++ b/src/slang-nodes/StateVariableDefinition.ts @@ -53,13 +53,9 @@ export class StateVariableDefinition implements SlangNode { print(path: AstPath, print: PrintFunction): Doc { const groupId = Symbol('Slang.StateVariableDefinition.attributes'); - const attributesDoc = group(indent(path.call(print, 'attributes')), { - id: groupId - }); - return [ path.call(print, 'typeName'), - attributesDoc, + group(indent(path.call(print, 'attributes')), { id: groupId }), ' ', path.call(print, 'name'), this.value ? indentIfBreak(path.call(print, 'value'), { groupId }) : '', diff --git a/src/slang-nodes/StorageLayoutSpecifier.ts b/src/slang-nodes/StorageLayoutSpecifier.ts index f2b5e5ec0..de287758f 100644 --- a/src/slang-nodes/StorageLayoutSpecifier.ts +++ b/src/slang-nodes/StorageLayoutSpecifier.ts @@ -6,8 +6,8 @@ import { Expression } from './Expression.js'; import type * as ast from '@nomicfoundation/slang/ast'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { AstNode } from './types.js'; -import type { PrintFunction, SlangNode } from '../types.js'; +import type { AstNode } from './types.d.ts'; +import type { PrintFunction, SlangNode } from '../types.d.ts'; const { line } = doc.builders; diff --git a/src/slang-nodes/StringLiteral.ts b/src/slang-nodes/StringLiteral.ts index 12fb7514c..c7bf84476 100644 --- a/src/slang-nodes/StringLiteral.ts +++ b/src/slang-nodes/StringLiteral.ts @@ -14,7 +14,7 @@ export class StringLiteral implements SlangNode { loc; - variant; + variant: string; constructor(ast: ast.StringLiteral, options: ParserOptions) { const metadata = getNodeMetadata(ast); diff --git a/src/slang-nodes/TupleDeconstructionStatement.ts b/src/slang-nodes/TupleDeconstructionStatement.ts index df472ca87..5c15ef3f4 100644 --- a/src/slang-nodes/TupleDeconstructionStatement.ts +++ b/src/slang-nodes/TupleDeconstructionStatement.ts @@ -45,13 +45,11 @@ export class TupleDeconstructionStatement implements SlangNode { print: PrintFunction ): Doc { const groupId = Symbol('Slang.VariableDeclarationStatement.variables'); - const declarationDoc = group( - [this.varKeyword ? 'var (' : '(', path.call(print, 'elements'), ')'], - { id: groupId } - ); - return [ - declarationDoc, + group( + [this.varKeyword ? 'var (' : '(', path.call(print, 'elements'), ')'], + { id: groupId } + ), indentIfBreak([' = ', path.call(print, 'expression'), ';'], { groupId }) ]; } diff --git a/src/slang-nodes/UnnamedFunctionDefinition.ts b/src/slang-nodes/UnnamedFunctionDefinition.ts index f4c9df659..89caaadfb 100644 --- a/src/slang-nodes/UnnamedFunctionDefinition.ts +++ b/src/slang-nodes/UnnamedFunctionDefinition.ts @@ -46,9 +46,9 @@ export class UnnamedFunctionDefinition implements SlangNode { } cleanModifierInvocationArguments(): void { - for (const attribute of this.attributes.items) { - if (typeof attribute.variant !== 'string') { - attribute.variant.cleanModifierInvocationArguments(); + for (const { variant: attribute } of this.attributes.items) { + if (typeof attribute !== 'string') { + attribute.cleanModifierInvocationArguments(); } } } diff --git a/src/slang-nodes/VariableDeclarationStatement.ts b/src/slang-nodes/VariableDeclarationStatement.ts index 66f738c4e..842932609 100644 --- a/src/slang-nodes/VariableDeclarationStatement.ts +++ b/src/slang-nodes/VariableDeclarationStatement.ts @@ -58,22 +58,20 @@ export class VariableDeclarationStatement implements SlangNode { print: PrintFunction ): Doc { const groupId = Symbol('Slang.VariableDeclarationStatement.variables'); - const declarationDoc = group( - [ - path.call(print, 'variableType'), - indent([ - this.storageLocation - ? [line, path.call(print, 'storageLocation')] - : '', - ' ', - path.call(print, 'name') - ]) - ], - { id: groupId } - ); - return [ - declarationDoc, + group( + [ + path.call(print, 'variableType'), + indent([ + this.storageLocation + ? [line, path.call(print, 'storageLocation')] + : '', + ' ', + path.call(print, 'name') + ]) + ], + { id: groupId } + ), indentIfBreak(path.call(print, 'value'), { groupId }), ';' ]; diff --git a/src/slang-nodes/types.d.ts b/src/slang-nodes/types.d.ts index 0c64815c9..3227e19e0 100644 --- a/src/slang-nodes/types.d.ts +++ b/src/slang-nodes/types.d.ts @@ -460,7 +460,15 @@ export type StrictAstNode = | YulPaths | YulPath; -export type CollectionNode = Extract; +export type NodeCollection = Extract< + StrictAstNode, + { items: StrictAstNode[] | Identifier[] | YulIdentifier[] } +>; + +export type Collection = Extract< + StrictAstNode, + { items: StrictAstNode[] | Identifier[] | YulIdentifier[] | string[] } +>; export type BinaryOperation = Extract< StrictAstNode, diff --git a/src/slang-printers/create-binary-operation-printer.ts b/src/slang-printers/create-binary-operation-printer.ts index 61a3dc1b0..b33f23c32 100644 --- a/src/slang-printers/create-binary-operation-printer.ts +++ b/src/slang-printers/create-binary-operation-printer.ts @@ -23,15 +23,13 @@ function rightOperandPrint( ? [` ${node.operator}`, line, path.call(print, 'rightOperand')] : [line, `${node.operator} `, path.call(print, 'rightOperand')]; - // If it's a single binary operation, avoid having a small right - // operand like - 1 on its own line + // If there's only a single binary expression, we want to create a group in + // order to avoid having a small right part like -1 be on its own line. const leftOperand = node.leftOperand.variant; - const grandparentNode = path.getNode(2) as StrictAstNode; + const grandparentNode = path.grandparent as StrictAstNode; const shouldGroup = - !( - leftOperand.kind !== TerminalKind.Identifier && - isBinaryOperation(leftOperand) - ) && + (leftOperand.kind === TerminalKind.Identifier || + !isBinaryOperation(leftOperand)) && (!isBinaryOperation(grandparentNode) || grandparentNode.kind === NonterminalKind.AssignmentExpression); diff --git a/src/slang-printers/print-binary-operation.ts b/src/slang-printers/print-binary-operation.ts index cb0504c97..7cc419b7d 100644 --- a/src/slang-printers/print-binary-operation.ts +++ b/src/slang-printers/print-binary-operation.ts @@ -10,7 +10,7 @@ import type { BinaryOperation, StrictAstNode } from '../slang-nodes/types.d.ts'; -import type { PrintFunction } from '../types.js'; +import type { PrintFunction } from '../types.d.ts'; const { group, indent } = doc.builders; @@ -18,7 +18,7 @@ export const binaryGroupRulesBuilder = (shouldGroup: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - const grandparentNode = path.getNode(2) as StrictAstNode; + const grandparentNode = path.grandparent as StrictAstNode; if (!isBinaryOperation(grandparentNode)) return group(document); if (shouldGroup(grandparentNode)) return group(document); return document; @@ -44,8 +44,7 @@ export const binaryIndentRulesBuilder = (shouldIndent: (node: BinaryOperation) => boolean) => (path: AstPath) => (document: Doc): Doc => { - let node = path.getNode() as StrictAstNode; - for (let i = 2; ; i += 2) { + for (let i = 2, node = path.node; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; if (!isBinaryOperation(grandparentNode)) return indent(document); diff --git a/src/slang-printers/print-comments.ts b/src/slang-printers/print-comments.ts index cabfb7b78..ee660df14 100644 --- a/src/slang-printers/print-comments.ts +++ b/src/slang-printers/print-comments.ts @@ -12,7 +12,7 @@ export function printComments(path: AstPath): Doc[] { const document = joinExisting( line, path.map((commentPath) => { - const comment = commentPath.getNode()!; + const comment = commentPath.node; if (comment.trailing || comment.leading || comment.printed) { return ''; } diff --git a/src/slang-printers/print-logical-operation.ts b/src/slang-printers/print-logical-operation.ts index 3934842ce..efdeacd32 100644 --- a/src/slang-printers/print-logical-operation.ts +++ b/src/slang-printers/print-logical-operation.ts @@ -21,8 +21,7 @@ const logicalGroupRulesBuilder = binaryGroupRulesBuilder(() => false); const logicalIndentRulesBuilder = (path: AstPath, options: ParserOptions) => (document: Doc): Doc => { - let node = path.getNode() as StrictAstNode; - for (let i = 2; ; i += 2) { + for (let i = 2, node = path.node; ; i += 2) { const grandparentNode = path.getNode(i) as StrictAstNode; if (shouldNotIndent(grandparentNode, path, i)) break; if ( diff --git a/src/slang-printers/print-preserving-empty-lines.ts b/src/slang-printers/print-preserving-empty-lines.ts index fa0f77d96..ae5d67be7 100644 --- a/src/slang-printers/print-preserving-empty-lines.ts +++ b/src/slang-printers/print-preserving-empty-lines.ts @@ -3,22 +3,18 @@ import { doc, util } from 'prettier'; import { locEnd } from '../slang-utils/loc.js'; import type { AstPath, Doc, ParserOptions } from 'prettier'; -import type { - AstNode, - CollectionNode, - StrictAstNode -} from '../slang-nodes/types.d.ts'; +import type { AstNode, NodeCollection } from '../slang-nodes/types.d.ts'; import type { PrintFunction } from '../types.d.ts'; const { hardline } = doc.builders; export function printPreservingEmptyLines( - path: AstPath, + path: AstPath, print: PrintFunction, options: ParserOptions ): Doc { return path.map((childPath) => { - const node = childPath.getNode() as StrictAstNode; + const node = childPath.node; return [ // Only attempt to prepend an empty line if `node` is not the first item diff --git a/src/slang-utils/create-hug-function.ts b/src/slang-utils/create-hug-function.ts index 866b092d1..45dfa556c 100644 --- a/src/slang-utils/create-hug-function.ts +++ b/src/slang-utils/create-hug-function.ts @@ -10,13 +10,13 @@ export function createHugFunction( ): (node: Expression) => Expression { const operators = new Set(huggableOperators); return (node: Expression): Expression => { + const variant = node.variant; if ( - node.variant.kind !== TerminalKind.Identifier && - isBinaryOperation(node.variant) && - operators.has(node.variant.operator) + variant.kind !== TerminalKind.Identifier && + isBinaryOperation(variant) && + operators.has(variant.operator) ) { - const { loc } = node; - + const loc = node.loc; return Object.assign(Object.create(Expression.prototype) as Expression, { kind: NonterminalKind.Expression, loc: { ...loc }, diff --git a/src/slang-utils/create-parser.ts b/src/slang-utils/create-parser.ts index 8d90b680e..088676e00 100644 --- a/src/slang-utils/create-parser.ts +++ b/src/slang-utils/create-parser.ts @@ -5,7 +5,7 @@ import { minSatisfying } from 'semver'; import type { ParseOutput } from '@nomicfoundation/slang/parser'; import type { ParserOptions } from 'prettier'; -import type { AstNode } from '../slang-nodes/types.js'; +import type { AstNode } from '../slang-nodes/types.d.ts'; const supportedVersions = LanguageFacts.allVersions(); const supportedLength = supportedVersions.length; @@ -22,11 +22,11 @@ function parserAndOutput( } function createError( - { parseOutput }: { parseOutput: ParseOutput }, + result: { parseOutput: ParseOutput }, reason: string ): Error { return new Error( - `We encountered the following syntax error:\n\n\t${parseOutput.errors()[0].message}\n\n${reason}` + `We encountered the following syntax error:\n\n\t${result.parseOutput.errors()[0].message}\n\n${reason}` ); } diff --git a/src/slang-utils/metadata.ts b/src/slang-utils/metadata.ts index f5f7fc248..f99d64f89 100644 --- a/src/slang-utils/metadata.ts +++ b/src/slang-utils/metadata.ts @@ -1,5 +1,6 @@ import { TerminalKind, TerminalNode } from '@nomicfoundation/slang/cst'; import { createKindCheckFunction } from './create-kind-check-function.js'; +import { isComment } from './is-comment.js'; import { MultiLineComment } from '../slang-nodes/MultiLineComment.js'; import { MultiLineNatSpecComment } from '../slang-nodes/MultiLineNatSpecComment.js'; import { SingleLineComment } from '../slang-nodes/SingleLineComment.js'; @@ -8,7 +9,6 @@ import { SingleLineNatSpecComment } from '../slang-nodes/SingleLineNatSpecCommen import type { Node } from '@nomicfoundation/slang/cst'; import type { Comment, StrictAstNode } from '../slang-nodes/types.d.ts'; import type { Metadata, SlangAstNode } from '../types.d.ts'; -import { isComment } from './is-comment.js'; const isCommentOrWhiteSpace = createKindCheckFunction([ TerminalKind.MultiLineComment, @@ -53,37 +53,37 @@ export function getNodeMetadata( } }; } + const { cst: parent } = ast; + const children = parent.children().map(({ node }) => node); - const children = ast.cst.children().map((child) => { - return child.node; - }); - - const initialOffset = offsets.get(ast.cst.id) || 0; + const initialOffset = offsets.get(parent.id) || 0; let offset = initialOffset; + const comments: Comment[] = []; - const comments = children.reduce((commentsArray: Comment[], child) => { + for (const child of children) { + const { id, kind, textLength } = child; if (child.isNonterminalNode()) { - offsets.set(child.id, offset); + offsets.set(id, offset); } else { if (isComment(child)) { - offsets.set(child.id, offset); + offsets.set(id, offset); } - switch (child.kind) { + switch (kind) { // Since the fetching the comments and calculating offsets are both done // as we iterate over the children and the comment also depends on the // offset, it's hard to separate these responsibilities into different // functions without doing the iteration twice. case TerminalKind.MultiLineComment: - commentsArray.push(new MultiLineComment(child)); + comments.push(new MultiLineComment(child)); break; case TerminalKind.MultiLineNatSpecComment: - commentsArray.push(new MultiLineNatSpecComment(child)); + comments.push(new MultiLineNatSpecComment(child)); break; case TerminalKind.SingleLineComment: - commentsArray.push(new SingleLineComment(child)); + comments.push(new SingleLineComment(child)); break; case TerminalKind.SingleLineNatSpecComment: - commentsArray.push(new SingleLineNatSpecComment(child)); + comments.push(new SingleLineNatSpecComment(child)); break; case TerminalKind.Identifier: case TerminalKind.YulIdentifier: @@ -91,24 +91,21 @@ export function getNodeMetadata( // functions, etc... // Since a user can add comments to this section of the code as well, // we need to track the offsets. - offsets.set(child.id, offset); + offsets.set(id, offset); break; } } - offset += child.textLength.utf16; - return commentsArray; - }, []); - - const leadingOffset = enclosePeripheralComments - ? 0 - : getLeadingOffset(children); - const trailingOffset = enclosePeripheralComments - ? 0 - : getLeadingOffset(children.reverse()); + offset += textLength.utf16; + } + + const [leadingOffset, trailingOffset] = enclosePeripheralComments + ? [0, 0] + : [getLeadingOffset(children), getLeadingOffset(children.reverse())]; + const loc = { start: initialOffset + leadingOffset, - end: initialOffset + ast.cst.textLength.utf16 - trailingOffset, + end: offset - trailingOffset, leadingOffset, trailingOffset }; @@ -132,23 +129,22 @@ function collectComments( } export function updateMetadata( - metadata: Metadata, + { comments, loc }: Metadata, childNodes: (StrictAstNode | StrictAstNode[] | undefined)[] ): Metadata { // Collect comments - const comments = childNodes.reduce(collectComments, metadata.comments); + comments = childNodes.reduce(collectComments, comments); // calculate correct loc object - const { loc } = metadata; if (loc.leadingOffset === 0) { for (const childNode of childNodes) { if (typeof childNode === 'undefined' || Array.isArray(childNode)) continue; - const childLoc = childNode.loc; + const { leadingOffset, start } = childNode.loc; - if (childLoc.start - childLoc.leadingOffset === loc.start) { - loc.leadingOffset = childLoc.leadingOffset; - loc.start += childLoc.leadingOffset; + if (start - leadingOffset === loc.start) { + loc.leadingOffset = leadingOffset; + loc.start += leadingOffset; break; } } @@ -158,11 +154,11 @@ export function updateMetadata( for (const childNode of childNodes.reverse()) { if (typeof childNode === 'undefined' || Array.isArray(childNode)) continue; - const childLoc = childNode.loc; + const { trailingOffset, end } = childNode.loc; - if (childLoc.end + childLoc.trailingOffset === loc.end) { - loc.trailingOffset = childLoc.trailingOffset; - loc.end -= childLoc.trailingOffset; + if (end + trailingOffset === loc.end) { + loc.trailingOffset = trailingOffset; + loc.end -= trailingOffset; break; } } diff --git a/src/slang-utils/sort-contract-specifiers.ts b/src/slang-utils/sort-contract-specifiers.ts index ca66d7fff..7f0614b65 100644 --- a/src/slang-utils/sort-contract-specifiers.ts +++ b/src/slang-utils/sort-contract-specifiers.ts @@ -3,21 +3,18 @@ import { NonterminalKind } from '@nomicfoundation/slang/cst'; import type { ContractSpecifier } from '../slang-nodes/ContractSpecifier.js'; export function sortContractSpecifiers( - a: ContractSpecifier, - b: ContractSpecifier + { variant: { kind: aKind } }: ContractSpecifier, + { variant: { kind: bKind } }: ContractSpecifier ): number { - const aVariant = a.variant; - const bVariant = b.variant; - // OverrideSpecifiers before ModifierInvocation if ( - aVariant.kind === NonterminalKind.InheritanceSpecifier && - bVariant.kind === NonterminalKind.StorageLayoutSpecifier + aKind === NonterminalKind.InheritanceSpecifier && + bKind === NonterminalKind.StorageLayoutSpecifier ) return -1; if ( - bVariant.kind === NonterminalKind.InheritanceSpecifier && - aVariant.kind === NonterminalKind.StorageLayoutSpecifier + bKind === NonterminalKind.InheritanceSpecifier && + aKind === NonterminalKind.StorageLayoutSpecifier ) return 1; diff --git a/src/slang-utils/sort-function-attributes.ts b/src/slang-utils/sort-function-attributes.ts index 48d1a1da7..3b39415d4 100644 --- a/src/slang-utils/sort-function-attributes.ts +++ b/src/slang-utils/sort-function-attributes.ts @@ -12,12 +12,9 @@ const visibilityKeyWords = new Set([ const mutabilityKeyWords = new Set(['pure', 'constant', 'payable', 'view']); export function sortFunctionAttributes( - a: SortableAttribute, - b: SortableAttribute + { variant: aVariant }: SortableAttribute, + { variant: bVariant }: SortableAttribute ): number { - const aVariant = a.variant; - const bVariant = b.variant; - const aIsString = typeof aVariant === 'string'; const bIsString = typeof bVariant === 'string'; diff --git a/src/slangPrinter.ts b/src/slangPrinter.ts index 77de7f400..524f20c5e 100644 --- a/src/slangPrinter.ts +++ b/src/slangPrinter.ts @@ -5,27 +5,24 @@ import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { AstNode, StrictAstNode } from './slang-nodes/types.d.ts'; import type { PrintFunction } from './types.d.ts'; -function hasNodeIgnoreComment(node: StrictAstNode): boolean { +function hasNodeIgnoreComment({ comments }: StrictAstNode): boolean { // Prettier sets SourceUnit's comments to undefined after assigning comments // to each node. - return ( - node.comments && - node.comments.some( - (comment) => - comment.value - .slice(2, isBlockComment(comment) ? -2 : undefined) - .trim() === 'prettier-ignore' - ) + return comments?.some( + (comment) => + comment.value + .slice(2, isBlockComment(comment) ? -2 : undefined) + .trim() === 'prettier-ignore' ); } function ignoreComments(path: AstPath): void { - const node = path.getNode(); + const node = path.node; // We ignore anything that is not an object if (node === null || typeof node !== 'object') return; - const keys = Object.keys(node) as (keyof StrictAstNode)[]; - for (const key of keys) { + let key: keyof StrictAstNode; + for (key in node) { switch (key) { // We ignore `kind`, `loc`, and comments since these are added by the // parser @@ -35,10 +32,7 @@ function ignoreComments(path: AstPath): void { break; // The key `comments` will contain every comment for this node case 'comments': - path.each((commentPath) => { - const comment = commentPath.getNode()!; - comment.printed = true; - }, 'comments'); + path.each((commentPath) => (commentPath.node.printed = true), key); break; default: // If the value for that key is an Array or an Object we go deeper. @@ -61,11 +55,7 @@ function genericPrint( options: ParserOptions, print: PrintFunction ): Doc { - const node = path.getNode(); - - if (node === null) { - return ''; - } + const node = path.node; if (hasNodeIgnoreComment(node)) { ignoreComments(path); diff --git a/tests/unit/comments/printer.test.js b/tests/unit/comments/printer.test.js index c00c2dcde..bc01efd6c 100644 --- a/tests/unit/comments/printer.test.js +++ b/tests/unit/comments/printer.test.js @@ -1,9 +1,7 @@ import { printComment } from '../../../src/slang-comments/printer.ts'; test('given an unknown comment type then printComment function should throw', () => { - const mockCommentPath = { - getNode: () => ({ type: 'UnknownComment', range: [0, 1] }) - }; + const mockCommentPath = { node: { type: 'UnknownComment', range: [0, 1] } }; expect(() => { printComment(mockCommentPath);