Socket
Socket
Sign inDemoInstall

prettier-plugin-solidity

Package Overview
Dependencies
Maintainers
3
Versions
95
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

prettier-plugin-solidity - npm Package Compare versions

Comparing version 1.2.0 to 1.3.1

12

package.json
{
"name": "prettier-plugin-solidity",
"version": "1.2.0",
"version": "1.3.1",
"description": "A Prettier Plugin for automatically formatting your Solidity code.",

@@ -101,3 +101,3 @@ "type": "module",

"jest": "^29.6.3",
"jest-light-runner": "^0.5.0",
"jest-light-runner": "^0.6.0",
"jest-snapshot-serializer-ansi": "^2.1.0",

@@ -107,5 +107,5 @@ "jest-snapshot-serializer-raw": "^2.0.0",

"lines-and-columns": "^2.0.3",
"prettier": "^3.0.2",
"prettier": "^3.1.1",
"proxyquire": "^2.1.3",
"solc": "^0.8.21",
"solc": "^0.8.23-fixed",
"webpack": "^5.88.2",

@@ -115,5 +115,5 @@ "webpack-cli": "^5.1.4"

"dependencies": {
"@solidity-parser/parser": "^0.16.2",
"@solidity-parser/parser": "^0.17.0",
"semver": "^7.5.4",
"solidity-comments-extractor": "^0.0.7"
"solidity-comments-extractor": "^0.0.8"
},

@@ -120,0 +120,0 @@ "peerDependencies": {

@@ -209,2 +209,17 @@ # prettier-plugin-solidity

### Experimental Ternaries
_Added in v1.3.0_
Mimicking prettier's [new ternary formatting](https://prettier.io/blog/2023/11/13/curious-ternaries) for the community to try.
Valid options:
- `true` - Use curious ternaries, with the question mark after the condition.
- `false` - Retain the default behavior of ternaries; keep question marks on the same line as the consequent.
| Default | CLI Override | API Override |
| ------- | -------------------------- | ------------------------------- |
| false | `--experimental-ternaries` | `experimentalTernaries: <bool>` |
## Integrations

@@ -211,0 +226,0 @@

@@ -8,3 +8,3 @@ import { doc } from 'prettier';

const indentIfNecessaryBuilder = (path) => (document) => {
const indentIfNecessaryBuilder = (path, options) => (document) => {
let node = path.getNode();

@@ -16,2 +16,8 @@ for (let i = 0; ; i += 1) {

if (parentNode.type === 'WhileStatement') return document;
if (
options.experimentalTernaries &&
parentNode.type === 'Conditional' &&
parentNode.condition === node
)
return document;
if (parentNode.type !== 'BinaryOperation') return indent(document);

@@ -25,5 +31,5 @@ if (node === parentNode.right) return document;

match: (op) => ['&&', '||'].includes(op),
print: (node, path, print) => {
print: (node, path, print, options) => {
const groupIfNecessary = groupIfNecessaryBuilder(path);
const indentIfNecessary = indentIfNecessaryBuilder(path);
const indentIfNecessary = indentIfNecessaryBuilder(path, options);

@@ -30,0 +36,0 @@ const right = [node.operator, line, path.call(print, 'right')];

@@ -30,9 +30,6 @@ import { util } from 'prettier';

// The comment is behind the start of the Block `{}` or behind a base contract
if (
(followingNode && followingNode.type === 'InheritanceSpecifier') ||
nextCharacter === '{'
) {
if (followingNode?.type === 'InheritanceSpecifier' || nextCharacter === '{') {
// In this scenario the comment belongs to a base contract.
// contract A is B, /* comment for B */ C /* comment for C */ {}
if (precedingNode && precedingNode.type === 'InheritanceSpecifier') {
if (precedingNode?.type === 'InheritanceSpecifier') {
addTrailingComment(precedingNode, comment);

@@ -39,0 +36,0 @@ return true;

@@ -30,6 +30,2 @@ import { util } from 'prettier';

export function isFirst(path, _, index) {
return isPrettier2 ? index === 0 : path.isFirst;
}
export function isLast(path, key, index) {

@@ -40,9 +36,1 @@ return isPrettier2

}
export function previous(path, key, index) {
return isPrettier2 ? path.getParentNode()[key][index - 1] : path.previous;
}
export function next(path, key, index) {
return isPrettier2 ? path.getParentNode()[key][index + 1] : path.next;
}
import { doc } from 'prettier';
import {
isFirst,
isLast,
isNextLineEmpty,
isPrettier2,
next,
previous
isPrettier2
} from './backward-compatibility.js';

@@ -27,3 +24,3 @@

comment.printed = true;
return options.printer.printComment(commentPath);
return options.printer.printComment(commentPath, options);
}, 'comments')

@@ -43,18 +40,2 @@ .filter(Boolean)

const shouldHaveEmptyLine = (node, checkForLeading) =>
Boolean(
// if node is not FunctionDefinition, it should have an empty line
node.type !== 'FunctionDefinition' ||
// if FunctionDefinition is not abstract, it should have an empty line
node.body ||
// if FunctionDefinition has the comment we are looking for (trailing or
// leading), it should have an empty line
node.comments?.some((comment) => checkForLeading && comment.leading)
);
const separatingLine = (firstNode, secondNode) =>
shouldHaveEmptyLine(firstNode, false) || shouldHaveEmptyLine(secondNode, true)
? hardline
: '';
export function printPreservingEmptyLines(path, key, options, print) {

@@ -76,34 +57,12 @@ const parts = [];

// Only attempt to prepend an empty line if `node` is not the first item
// and an empty line hasn't already been appended after the previous `node`
if (
!isFirst(childPath, key, index) &&
parts[parts.length - 2] !== hardline
) {
if (nodeType === 'FunctionDefinition') {
// Prepend FunctionDefinition with an empty line if there should be a
// separation with the previous `node`
parts.push(separatingLine(previous(childPath, key, index), node));
} else if (nodeType === 'ContractDefinition') {
// Prepend ContractDefinition with an empty line
parts.push(hardline);
}
}
parts.push(print(childPath));
// Only attempt to append an empty line if `node` is not the last item
if (!isLast(childPath, key, index)) {
if (isNextLineEmpty(options.originalText, options.locEnd(node) + 1)) {
// Append an empty line if the original text already had an one after
// the current `node`
parts.push(hardline);
} else if (nodeType === 'FunctionDefinition') {
// Append FunctionDefinition with an empty line if there should be a
// separation with the next `node`
parts.push(separatingLine(node, next(childPath, key, index)));
} else if (nodeType === 'ContractDefinition') {
// Append ContractDefinition with an empty line
parts.push(hardline);
}
if (
!isLast(childPath, key, index) &&
isNextLineEmpty(options.originalText, options.locEnd(node) + 1)
) {
// Append an empty line if the original text already had an one after
// the current `node`
parts.push(hardline);
}

@@ -110,0 +69,0 @@ }, key);

@@ -43,7 +43,5 @@ import { util, version } from 'prettier';

return (
node &&
node.comments &&
node.comments.length > 0 &&
node?.comments?.length > 0 &&
node.comments.some((comment) => comment.value.trim() === 'prettier-ignore')
);
}

@@ -7,3 +7,3 @@ // see: https://github.com/prettier/prettier/blob/main/src/language-js/loc.js

}
if (node.expression && node.expression.range) {
if (node.expression?.range) {
return node.expression.range[index];

@@ -10,0 +10,0 @@ }

import { doc } from 'prettier';
import { printSeparatedItem } from '../common/printer-helpers.js';
const { group, indent, line } = doc.builders;
const { group, hardline, ifBreak, indent, line, softline } = doc.builders;
let groupIndex = 0;
const experimentalTernaries = (node, path, print, options) => {
const parent = path.getParentNode();
const isNested = parent.type === 'Conditional';
const isNestedAsTrueExpression = isNested && parent.trueExpression === node;
const falseExpressionIsNested = node.falseExpression.type === 'Conditional';
// If the `condition` breaks into multiple lines, we add parentheses,
// unless it already is a `TupleExpression`.
const condition = path.call(print, 'condition');
const conditionDoc = group([
node.condition.type === 'TupleExpression'
? condition
: ifBreak(['(', printSeparatedItem(condition), ')'], condition),
' ?'
]);
// 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(
[conditionDoc, trueExpressionDoc],
{ id: `Conditional.trueExpressionDoc-${groupIndex}` }
);
groupIndex += 1;
// For the odd case of `tabWidth` of 1 or 0 we initiate `fillTab` as a single
// space.
let fillTab = ' ';
if (
!falseExpressionIsNested && // avoid processing if it's not needed
(options.tabWidth > 2 || options.useTabs)
) {
fillTab = options.useTabs ? '\t' : ' '.repeat(options.tabWidth - 1);
}
// A nested `falseExpression` is always printed in a new line.
const falseExpression = path.call(print, 'falseExpression');
const falseExpressionDoc = [
isNested ? hardline : line,
':',
falseExpressionIsNested
? [' ', falseExpression]
: ifBreak([fillTab, indent(falseExpression)], [' ', falseExpression], {
// We only add `fillTab` if we are sure the trueExpression is indented
groupId: conditionAndTrueExpressionGroup.id
})
];
const document = group([conditionAndTrueExpressionGroup, falseExpressionDoc]);
return parent.type === 'VariableDeclarationStatement'
? indent([softline, document])
: document;
};
const traditionalTernaries = (path, print) =>
group([
path.call(print, 'condition'),
indent([
// Nested trueExpression and falseExpression are always printed in a new
// line
path.getParentNode().type === 'Conditional' ? hardline : line,
'? ',
path.call(print, 'trueExpression'),
line,
': ',
path.call(print, 'falseExpression')
])
]);
export const Conditional = {
print: ({ path, print }) =>
group([
path.call(print, 'condition'),
indent([
line,
'? ',
path.call(print, 'trueExpression'),
line,
': ',
path.call(print, 'falseExpression')
])
])
print: ({ node, path, print, options }) =>
options.experimentalTernaries
? experimentalTernaries(node, path, print, options)
: traditionalTernaries(path, print)
};

@@ -23,3 +23,3 @@ import { doc } from 'prettier';

const comments = printComments(node, path, options);
return node.subNodes.length > 0 || (comments && comments.length)
return node.subNodes.length > 0 || comments?.length
? printSeparatedItem(

@@ -26,0 +26,0 @@ [printPreservingEmptyLines(path, 'subNodes', options, print), comments],

import { printSeparatedList } from '../common/printer-helpers.js';
const parameters = (node, path, print) =>
node.parameters && node.parameters.length > 0
node.parameters?.length > 0
? printSeparatedList(path.map(print, 'parameters'))

@@ -6,0 +6,0 @@ : '';

const stateMutability = (node) =>
node.stateMutability && node.stateMutability.length > 0
? [' ', node.stateMutability]
: '';
node.stateMutability?.length > 0 ? [' ', node.stateMutability] : '';

@@ -6,0 +4,0 @@ export const ElementaryTypeName = {

import { printSeparatedList } from '../common/printer-helpers.js';
const parameters = (node, path, print) =>
node.parameters && node.parameters.length > 0
node.parameters?.length > 0
? printSeparatedList(path.map(print, 'parameters'))

@@ -6,0 +6,0 @@ : '';

@@ -13,5 +13,5 @@ import { doc } from 'prettier';

if (parent.type === 'IfStatement') {
if (node.comments && node.comments.length) {
if (node.comments?.length) {
const comments = printComments(node, path, options);
if (comments && comments.length) {
if (comments?.length) {
parts.push(comments);

@@ -18,0 +18,0 @@ parts.push(hardline);

@@ -33,4 +33,4 @@ import { doc } from 'prettier';

if (node.arguments && node.arguments.length > 0) {
if (node.identifiers && node.identifiers.length > 0) {
if (node.arguments?.length > 0) {
if (node.identifiers?.length > 0) {
argumentsDoc = printObject(path, print, options);

@@ -37,0 +37,0 @@ } else {

@@ -29,3 +29,3 @@ import { doc } from 'prettier';

const parameters = (parametersType, node, path, print, options) => {
if (node[parametersType] && node[parametersType].length > 0) {
if (node[parametersType]?.length > 0) {
return printSeparatedList(path.map(print, parametersType), {

@@ -35,3 +35,3 @@ grouped: false

}
if (node.comments && node.comments.length > 0) {
if (node.comments?.length > 0) {
// we add a check to see if the comment is inside the parentheses

@@ -38,0 +38,0 @@ const parameterComments = printComments(

import { printSeparatedList } from '../common/printer-helpers.js';
const printArguments = (node, path, print) =>
node.arguments && node.arguments.length
node.arguments?.length
? ['(', printSeparatedList(path.map(print, 'arguments')), ')']

@@ -6,0 +6,0 @@ : '';

@@ -9,3 +9,3 @@ // @TODO: add support for assembly language specifier

node.language ? `${printString(node.language, options)} ` : '',
node.flags && node.flags.length > 0
node.flags?.length > 0
? [

@@ -12,0 +12,0 @@ '(',

@@ -7,3 +7,3 @@ import { doc } from 'prettier';

const modifierParameters = (node, path, print) => {
if (node.parameters && node.parameters.length > 0) {
if (node.parameters?.length > 0) {
return [

@@ -10,0 +10,0 @@ '(',

@@ -16,4 +16,3 @@ import {

if (
node.comments &&
node.comments.some(
node.comments?.some(
(comment) => !comment.leading && !comment.trailing && !comment.printed

@@ -20,0 +19,0 @@ )

@@ -5,5 +5,6 @@ import { doc } from 'prettier';

const expression = (node, path, print) => {
const expression = (node, path, print, options) => {
if (node.expression) {
return node.expression.type === 'TupleExpression'
return node.expression.type === 'TupleExpression' ||
(options.experimentalTernaries && node.expression.type === 'Conditional')
? [' ', path.call(print, 'expression')]

@@ -16,7 +17,7 @@ : group(indent([line, path.call(print, 'expression')]));

export const ReturnStatement = {
print: ({ node, path, print }) => [
print: ({ node, path, print, options }) => [
'return',
expression(node, path, print),
expression(node, path, print, options),
';'
]
};

@@ -7,7 +7,5 @@ import { doc } from 'prettier';

const contents = (node, path, print) =>
node.components &&
node.components.length === 1 &&
node.components[0].type === 'BinaryOperation'
node.components?.length === 1 && node.components[0].type === 'BinaryOperation'
? path.map(print, 'components')
: [printSeparatedList(path.map(print, 'components'))];
: printSeparatedList(path.map(print, 'components'));

@@ -18,5 +16,5 @@ export const TupleExpression = {

node.isArray ? '[' : '(',
...contents(node, path, print),
contents(node, path, print),
node.isArray ? ']' : ')'
])
};

@@ -9,3 +9,3 @@ import { doc } from 'prettier';

'using ',
node.functions && node.functions.length
node.functions?.length
? [

@@ -12,0 +12,0 @@ '{',

@@ -16,3 +16,3 @@ import { doc } from 'prettier';

const startsWithVar =
node.variables.filter((x) => x && x.typeName).length === 0;
node.variables.filter((x) => x?.typeName).length === 0;

@@ -19,0 +19,0 @@ const declarationDoc = group(

const CATEGORY_GLOBAL = 'Global';
const CATEGORY_COMMON = 'Common';
const CATEGORY_JAVASCRIPT = 'JavaScript';
const CATEGORY_SOLIDITY = 'Solidity';

@@ -43,2 +44,11 @@

},
experimentalTernaries: {
category: CATEGORY_JAVASCRIPT,
type: 'boolean',
default: false,
description:
'Use curious ternaries, with the question mark after the condition.',
oppositeDescription:
'Default behavior of ternaries; keep question marks on the same line as the consequent.'
},
compiler: {

@@ -45,0 +55,0 @@ category: CATEGORY_SOLIDITY,

@@ -46,3 +46,3 @@ import extractComments from 'solidity-comments-extractor';

ctx.modifiers.forEach((modifier) => {
if (modifier.arguments && modifier.arguments.length === 0) {
if (modifier.arguments?.length === 0) {
// eslint-disable-next-line no-param-reassign

@@ -61,6 +61,21 @@ modifier.arguments = null;

HexLiteral(ctx) {
ctx.value = options.singleQuote
? `hex'${ctx.value.slice(4, -1)}'`
: `hex"${ctx.value.slice(4, -1)}"`;
const value = ctx.value.slice(4, -1);
ctx.value = options.singleQuote ? `hex'${value}'` : `hex"${value}"`;
},
Conditional(ctx) {
// TODO: while the behaviour is not stable, it should be behind the
// experimentalTernaries flag.
if (options.experimentalTernaries) {
// We can remove parentheses only because we are sure that the
// `condition` must be a single `bool` value.
while (
ctx.condition.type === 'TupleExpression' &&
!ctx.condition.isArray &&
ctx.condition.components.length === 1 &&
ctx.condition.components[0].type !== 'Conditional'
) {
[ctx.condition] = ctx.condition.components;
}
}
},
BinaryOperation(ctx) {

@@ -83,30 +98,30 @@ switch (ctx.operator) {

case '**':
// If the compiler has not been given as an option using we leave a**b**c.
// If the compiler has not been given as an option using we leave
// a**b**c.
if (!compiler) break;
if (satisfies(compiler, '<0.8.0')) {
// If the compiler is less than 0.8.0 then a**b**c is formatted as
// (a**b)**c.
ctx.left = tryHug(ctx.left, ['**']);
if (satisfies(compiler, '>=0.8.0')) {
// If the compiler is greater than or equal to 0.8.0 then a**b**c
// is formatted as a**(b**c).
ctx.right = tryHug(ctx.right, ['**']);
break;
}
if (
ctx.left.type === 'BinaryOperation' &&
ctx.left.operator === '**'
ctx.right.type === 'BinaryOperation' &&
ctx.right.operator === '**'
) {
// the parser still organizes the a**b**c as (a**b)**c so we need
// to restructure it.
ctx.right = {
// the parser organizes the a**b**c as a**(b**c) so we need to
// restructure it.
const left = {
type: 'BinaryOperation',
operator: '**',
left: ctx.left,
right: ctx.right.left
};
ctx.left = {
type: 'TupleExpression',
components: [
{
type: 'BinaryOperation',
operator: '**',
left: ctx.left.right,
right: ctx.right
}
],
components: [left],
isArray: false
};
ctx.left = ctx.left.left;
ctx.right = ctx.right.right;
}

@@ -113,0 +128,0 @@ break;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc