From ecb0bdc9b0188eec3c2d3aa2bc5e8042ee3d1826 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sun, 12 Apr 2026 22:21:20 -0400 Subject: [PATCH] removing `undefined` from `AstPath` since it's not required --- src/index.ts | 17 ++++++------ src/slang-comments/printer.ts | 4 +-- src/slang-printers/print-comments.ts | 36 +++++++++++++------------- src/slang-utils/get-visitor-keys.ts | 21 +++++++++++++++ src/slang-utils/has-prettier-ignore.ts | 6 ++--- src/slang-utils/is-comment.ts | 6 ++--- src/slangSolidityParser.ts | 8 +++--- src/types.d.ts | 6 +---- 8 files changed, 58 insertions(+), 46 deletions(-) create mode 100644 src/slang-utils/get-visitor-keys.ts diff --git a/src/index.ts b/src/index.ts index b591d7b7e..c5d3b4395 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,6 +10,7 @@ import slangPrint from './slangPrinter.js'; import { isBlockComment, isComment } from './slang-utils/is-comment.js'; import { locEnd, locStart } from './slang-utils/loc.js'; import { hasPrettierIgnore } from './slang-utils/has-prettier-ignore.js'; +import { getVisitorKeys } from './slang-utils/get-visitor-keys.js'; import type { AstPath, @@ -57,10 +58,9 @@ const parsers = { const antlrCanAttachComment = ({ type }: { type: string }): boolean => typeof type === 'string' && type !== 'BlockComment' && type !== 'LineComment'; -const canAttachComment = (node: PrintableNode | undefined): boolean => - node !== undefined && - node.kind && // Make sure it's not Location - !isComment(node); +const canAttachComment = (node: PrintableNode): boolean => + // Make sure it's not Location + node.kind && !isComment(node); // https://prettier.io/docs/en/plugins.html#printers const antlrPrinter = { @@ -75,18 +75,19 @@ const antlrPrinter = { print: antlrPrint, printComment: comments.printComment }; -const slangPrinter: Printer = { +const slangPrinter: Printer = { canAttachComment, handleComments, isBlockComment, massageAstNode, print: slangPrint as ( - path: AstPath, - options: ParserOptions, - print: (path: AstPath) => Doc, + path: AstPath, + options: ParserOptions, + print: (path: AstPath) => Doc, args?: unknown ) => Doc, hasPrettierIgnore, + getVisitorKeys, printComment }; diff --git a/src/slang-comments/printer.ts b/src/slang-comments/printer.ts index 08e3dd1f1..39fb0d3b0 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 { PrintableNode } from '../slang-nodes/types.d.ts'; -export function printComment({ - node: comment -}: AstPath): Doc { +export function printComment({ node: comment }: AstPath): Doc { if (isComment(comment)) { return comment.print(); } diff --git a/src/slang-printers/print-comments.ts b/src/slang-printers/print-comments.ts index ce8e5a887..57c8e67ae 100644 --- a/src/slang-printers/print-comments.ts +++ b/src/slang-printers/print-comments.ts @@ -1,12 +1,11 @@ import { doc, util } from 'prettier'; import { printComment } from '../slang-comments/printer.js'; -import { joinExisting } from '../slang-utils/join-existing.js'; import { locEnd } from '../slang-utils/loc.js'; import type { AstPath, Doc, ParserOptions } from 'prettier'; import type { Comment, PrintableNode } from '../slang-nodes/types.d.ts'; -const { hardline, line } = doc.builders; +const { hardline } = doc.builders; function isPrintable(comment: Comment): boolean { return !comment.trailing && !comment.leading && !comment.printed; @@ -21,20 +20,21 @@ export function printComments( if (lastPrintableIndex === -1) { return []; } - return joinExisting( - line, - path.map(({ node: comment }, index) => { - if (!isPrintable(comment)) { - return ''; - } - comment.printed = true; - return [ - printComment(path), - index !== lastPrintableIndex && - util.isNextLineEmpty(options.originalText, locEnd(comment)) - ? hardline - : '' - ]; - }, 'comments') - ); + return path.map(({ node: comment }, index) => { + if (!isPrintable(comment)) { + return ''; + } + comment.printed = true; + return [ + printComment(path), + index !== lastPrintableIndex + ? [ + hardline, + util.isNextLineEmpty(options.originalText, locEnd(comment)) + ? hardline + : '' + ] + : '' + ]; + }, 'comments'); } diff --git a/src/slang-utils/get-visitor-keys.ts b/src/slang-utils/get-visitor-keys.ts new file mode 100644 index 000000000..75f8b9fda --- /dev/null +++ b/src/slang-utils/get-visitor-keys.ts @@ -0,0 +1,21 @@ +import type { PrintableNode } from '../slang-nodes/types.js'; + +const ignoredKeys = new Set([ + 'kind', + 'loc', + 'comments', + 'print', + 'isEmpty', + 'updateMetadata', + 'cleanModifierInvocationArguments', + 'getSingleExpression' +]); + +export function getVisitorKeys( + node: PrintableNode, + nonTraversableKeys: Set +): string[] { + return Object.keys(node).filter( + (key) => !nonTraversableKeys.has(key) && !ignoredKeys.has(key) + ); +} diff --git a/src/slang-utils/has-prettier-ignore.ts b/src/slang-utils/has-prettier-ignore.ts index 3033c4130..1661db7ff 100644 --- a/src/slang-utils/has-prettier-ignore.ts +++ b/src/slang-utils/has-prettier-ignore.ts @@ -3,10 +3,8 @@ import { isBlockComment, isComment } from './is-comment.js'; import type { AstPath } from 'prettier'; import type { PrintableNode } from '../slang-nodes/types.js'; -export function hasPrettierIgnore({ - node -}: AstPath): boolean { - if (node === undefined || isComment(node)) return false; +export function hasPrettierIgnore({ node }: AstPath): boolean { + if (isComment(node)) return false; // Prettier sets SourceUnit's comments to undefined after assigning comments // to each node. diff --git a/src/slang-utils/is-comment.ts b/src/slang-utils/is-comment.ts index d7eb3073f..5240060eb 100644 --- a/src/slang-utils/is-comment.ts +++ b/src/slang-utils/is-comment.ts @@ -11,13 +11,11 @@ import type { export const isBlockComment = createKindCheckFunction([ TerminalKind.MultiLineComment, TerminalKind.MultiLineNatSpecComment -]) as ( - node: PrintableNode | Comment | Node | undefined -) => node is BlockComment; +]) as (node: PrintableNode | Comment | Node) => node is BlockComment; export const isComment = createKindCheckFunction([ TerminalKind.MultiLineComment, TerminalKind.MultiLineNatSpecComment, TerminalKind.SingleLineComment, TerminalKind.SingleLineNatSpecComment -]) as (node: PrintableNode | Comment | Node | undefined) => node is Comment; +]) as (node: PrintableNode | Comment | Node) => node is Comment; diff --git a/src/slangSolidityParser.ts b/src/slangSolidityParser.ts index 47f5bd043..35990094a 100644 --- a/src/slangSolidityParser.ts +++ b/src/slangSolidityParser.ts @@ -1,6 +1,7 @@ // https://prettier.io/docs/en/plugins.html#parsers import { SourceUnit as SlangSourceUnit } from '@nomicfoundation/slang/ast'; import { createParser } from './slang-utils/create-parser.js'; +import { locStart } from './slang-utils/loc.js'; import { SourceUnit } from './slang-nodes/SourceUnit.js'; import type { ParserOptions } from 'prettier'; @@ -12,7 +13,7 @@ export default function parse( ): PrintableNode { const { parser, parseOutput } = createParser(text, options); - // We update the compiler version by the inferred one. + // We update the compiler version with the inferred one. options.compiler = parser.languageVersion; const comments: Comment[] = []; const parsed = new SourceUnit( @@ -21,8 +22,7 @@ export default function parse( options ); - // Because of comments being extracted like a Russian doll, the order needs - // to be fixed at the end. - parsed.comments = comments.sort((a, b) => a.loc.start - b.loc.start); + // Comments are extracted in nested order; sort them by location. + parsed.comments = comments.sort((a, b) => locStart(a) - locStart(b)); return parsed; } diff --git a/src/types.d.ts b/src/types.d.ts index c57ae0502..ccf458eef 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -25,11 +25,7 @@ interface AstLocation extends Location { } type PrintFunction = ( - selector?: - | string - | number - | (string | number)[] - | AstPath + selector?: string | number | (string | number)[] | AstPath ) => Doc; // This the union of all the types in the namespace `ast`.