UNPKG

prettier-plugin-solidity

Version:

A Prettier Plugin for automatically formatting your Solidity code.

140 lines 5.45 kB
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'; import { SingleLineNatSpecComment } from '../slang-nodes/SingleLineNatSpecComment.js'; const isCommentOrWhiteSpace = createKindCheckFunction([ TerminalKind.MultiLineComment, TerminalKind.MultiLineNatSpecComment, TerminalKind.SingleLineComment, TerminalKind.SingleLineNatSpecComment, TerminalKind.EndOfLine, TerminalKind.Whitespace ]); const offsets = new Map(); export function clearOffsets() { offsets.clear(); } function getLeadingOffset(children) { let offset = 0; for (const child of children) { if (child.isNonterminalNode() || !isCommentOrWhiteSpace(child)) { // The node's content starts when we find the first non-terminal token, // or if we find a non-comment, non-whitespace token. return offset; } offset += child.textLength.utf16; } return offset; } export function getNodeMetadata(ast, enclosePeripheralComments = false) { if (ast instanceof TerminalNode) { const offset = offsets.get(ast.id) || 0; return { comments: [], loc: { start: offset, end: offset + ast.textLength.utf16, leadingOffset: 0, trailingOffset: 0 } }; } const { cst: parent } = ast; const children = parent.children().map(({ node }) => node); const initialOffset = offsets.get(parent.id) || 0; let offset = initialOffset; const comments = []; for (const child of children) { const { id, kind, textLength } = child; if (child.isNonterminalNode()) { offsets.set(id, offset); } else { if (isComment(child)) { offsets.set(id, offset); } 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: comments.push(new MultiLineComment(child)); break; case TerminalKind.MultiLineNatSpecComment: comments.push(new MultiLineNatSpecComment(child)); break; case TerminalKind.SingleLineComment: comments.push(new SingleLineComment(child)); break; case TerminalKind.SingleLineNatSpecComment: comments.push(new SingleLineNatSpecComment(child)); break; case TerminalKind.Identifier: case TerminalKind.YulIdentifier: // Identifiers usually are user provided names for variables, // functions, etc... // Since a user can add comments to this section of the code as well, // we need to track the offsets. offsets.set(id, offset); break; } } offset += textLength.utf16; } const [leadingOffset, trailingOffset] = enclosePeripheralComments ? [0, 0] : [getLeadingOffset(children), getLeadingOffset(children.reverse())]; const loc = { start: initialOffset + leadingOffset, end: offset - trailingOffset, leadingOffset, trailingOffset }; return { comments, loc }; } function collectComments(comments, node) { if (node) { if (Array.isArray(node)) { return node.reduce(collectComments, comments); } if (node.comments.length > 0) { comments.push(...node.comments.splice(0)); } } return comments; } export function updateMetadata({ comments, loc }, childNodes) { // Collect comments comments = childNodes.reduce(collectComments, comments); // calculate correct loc object if (loc.leadingOffset === 0) { for (const childNode of childNodes) { if (typeof childNode === 'undefined' || Array.isArray(childNode)) continue; const { leadingOffset, start } = childNode.loc; if (start - leadingOffset === loc.start) { loc.leadingOffset = leadingOffset; loc.start += leadingOffset; break; } } } if (loc.trailingOffset === 0) { for (const childNode of childNodes.reverse()) { if (typeof childNode === 'undefined' || Array.isArray(childNode)) continue; const { trailingOffset, end } = childNode.loc; if (end + trailingOffset === loc.end) { loc.trailingOffset = trailingOffset; loc.end -= trailingOffset; break; } } } return { comments, loc }; } //# sourceMappingURL=metadata.js.map