prettier-plugin-gherkin
Advanced tools
Comparing version 2.1.1 to 2.2.0
# CHANGELOG | ||
## [2.2.0] - 2023-12-28 | ||
- Add `forceNewlineBetweenStepBlocks` option [#16](https://github.com/mapado/prettier-plugin-gherkin/pull/16) by [@jdeniau](https://github.com/jdeniau) | ||
## [2.1.1] - 2023-11-21 | ||
@@ -20,2 +24,3 @@ | ||
> package.json | ||
```diff | ||
@@ -29,2 +34,3 @@ - "prettier": "^2.0.0", | ||
> .prettierrc | ||
```diff | ||
@@ -36,3 +42,2 @@ { | ||
### (maybe) remove support for Node 14 | ||
@@ -39,0 +44,0 @@ |
@@ -45,2 +45,5 @@ export function isWithLocation(node) { | ||
} | ||
get lastLine() { | ||
return this.location.line; | ||
} | ||
} | ||
@@ -200,2 +203,9 @@ /** | ||
} | ||
get lastLine() { | ||
const dataTableLength = this.dataTable?.rows.length ?? 0; | ||
const docStringLength = this.docString | ||
? this.docString.content.split('\n').length + 2 | ||
: 0; | ||
return this.location.line + dataTableLength + docStringLength; | ||
} | ||
} | ||
@@ -202,0 +212,0 @@ export class TypedScenario extends TypedGherkinNodeWithLocation { |
@@ -36,2 +36,10 @@ import { Parser as GherkinParser, AstBuilder, GherkinClassicTokenMatcher, } from '@cucumber/gherkin'; | ||
} | ||
function findPreviousNode(path, reversePosition) { | ||
const nodePosition = path.stack[path.stack.length - reversePosition]; | ||
// @ts-expect-error -- in a TypedStep, we have an array of TypedStep at position reversePosition -1 | ||
const siblings = path.stack[path.stack.length - (reversePosition + 1)]; | ||
return typeof nodePosition === 'number' && nodePosition > 0 | ||
? siblings[nodePosition - 1] | ||
: null; | ||
} | ||
let textColumnWidth = []; | ||
@@ -171,5 +179,16 @@ function generateColumnSizes(text) { | ||
} | ||
function stepNeedsHardline(node, isFirstStep) { | ||
return (!isFirstStep && | ||
node.keywordType && | ||
function stepNeedsHardline(options, node, commentNode, previousNode) { | ||
if (!previousNode) { | ||
// do not force hardline for the first step | ||
return false; | ||
} | ||
const currentNode = commentNode ?? node; | ||
if (options.forceNewlineBetweenStepBlocks !== true) { | ||
const hadHardlineBefore = previousNode && currentNode.location.line - previousNode.lastLine >= 2; | ||
if (hadHardlineBefore) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
return (node.keywordType && | ||
[StepKeywordType.CONTEXT, StepKeywordType.ACTION].includes(node.keywordType)); | ||
@@ -184,8 +203,8 @@ } | ||
} | ||
const parentNode = path.getParentNode(); | ||
const parentNodeIsFirstStep = path.stack[path.stack.length - 6] === 0; | ||
const stepNode = path.getParentNode(); | ||
const previousNode = findPreviousNode(path, 6); | ||
// if the comment follows a `Given` step, then the comment should have a leading blank line | ||
// but no blank line between the comment and the step | ||
if (parentNode instanceof TypedStep && | ||
stepNeedsHardline(parentNode, parentNodeIsFirstStep)) { | ||
if (stepNode instanceof TypedStep && | ||
stepNeedsHardline(options, stepNode, node, previousNode)) { | ||
return [printHardline(), node.text.trim()]; | ||
@@ -196,3 +215,3 @@ } | ||
canAttachComment(node) { | ||
// comments are all in the TypedGherkinDocument.comments array. | ||
// comments are all in the TypedGherkinDocument.comments array. | ||
// Do not handle comments in the subtree of the AST. | ||
@@ -335,6 +354,6 @@ return node instanceof TypedGherkinDocument; | ||
else if (node instanceof TypedStep) { | ||
// console.log(node); | ||
const previousNode = findPreviousNode(path, 2); | ||
return [ | ||
// if the step has comment, the hardline will be handled by the comment printer | ||
stepNeedsHardline(node, path.stack[path.stack.length - 2] === 0) && | ||
stepNeedsHardline(options, node, null, previousNode) && | ||
// @ts-expect-error comments are injected by prettier directly | ||
@@ -470,4 +489,11 @@ !node.comments | ||
}, | ||
forceNewlineBetweenStepBlocks: { | ||
type: 'boolean', | ||
default: false, | ||
description: 'Force new line between Context and Action blocks', | ||
oppositeDescription: 'Do not force hardline between Context and Action blocks', | ||
category: 'Format', | ||
}, | ||
}, | ||
}; | ||
export default plugin; |
{ | ||
"name": "prettier-plugin-gherkin", | ||
"version": "2.1.1", | ||
"version": "2.2.0", | ||
"type": "module", | ||
@@ -5,0 +5,0 @@ "description": "This prettier plugin format your gherkin (`.feature` files) documents.", |
@@ -84,4 +84,4 @@ # prettier-plugin-gherkin | ||
> .prettierrc | ||
> .prettierrc | ||
```diff | ||
@@ -101,4 +101,32 @@ { | ||
This plugin has a single options: | ||
This plugin has the following options: | ||
### `forceNewlineBetweenStepBlocks` (default: `false`) | ||
Do force a blank linesbetween steps block: | ||
Given the following block: | ||
```gherkin | ||
Given some context | ||
And some other context | ||
When I do something | ||
Then I should have a result | ||
``` | ||
The default output will be the same as the input (no blank lines). | ||
If you set this option to `true`, it will force a blank line between the context block and the action block: | ||
```gherkin | ||
Given some context | ||
And some other context | ||
When I do something | ||
Then I should have a result | ||
``` | ||
If you already have a blank line in your input, it will be kept as-is (event with this option set to `false`). | ||
If you have more than one blank line, it will be reduced to a single blank line. | ||
### `escapeBackslashes` | ||
@@ -105,0 +133,0 @@ |
@@ -101,3 +101,3 @@ import { | ||
export abstract class TypedGherkinNodeWithLocation< | ||
N extends GherkinNodeWithLocation | ||
N extends GherkinNodeWithLocation, | ||
> extends TypedGherkinNode<N> { | ||
@@ -110,2 +110,6 @@ location: Location; | ||
} | ||
get lastLine(): number { | ||
return this.location.line; | ||
} | ||
} | ||
@@ -330,2 +334,11 @@ | ||
} | ||
get lastLine(): number { | ||
const dataTableLength = this.dataTable?.rows.length ?? 0; | ||
const docStringLength = this.docString | ||
? this.docString.content.split('\n').length + 2 | ||
: 0; | ||
return this.location.line + dataTableLength + docStringLength; | ||
} | ||
} | ||
@@ -332,0 +345,0 @@ |
@@ -94,2 +94,17 @@ import { | ||
function findPreviousNode( | ||
path: AstPath<TypedGherkinNode<GherkinNode>>, | ||
reversePosition: number | ||
) { | ||
const nodePosition = path.stack[path.stack.length - reversePosition]; | ||
// @ts-expect-error -- in a TypedStep, we have an array of TypedStep at position reversePosition -1 | ||
const siblings: Array<TypedStep> = | ||
path.stack[path.stack.length - (reversePosition + 1)]; | ||
return typeof nodePosition === 'number' && nodePosition > 0 | ||
? siblings[nodePosition - 1] | ||
: null; | ||
} | ||
let textColumnWidth: Array<number> = []; | ||
@@ -115,2 +130,3 @@ | ||
escapeBackslashes?: boolean; | ||
forceNewlineBetweenStepBlocks?: boolean; | ||
} | ||
@@ -299,5 +315,27 @@ | ||
function stepNeedsHardline(node: TypedStep, isFirstStep: boolean) { | ||
function stepNeedsHardline( | ||
options: GherkinParseOptions, | ||
node: TypedStep, | ||
commentNode: null | TypedComment, | ||
previousNode: null | TypedStep | ||
) { | ||
if (!previousNode) { | ||
// do not force hardline for the first step | ||
return false; | ||
} | ||
const currentNode = commentNode ?? node; | ||
if (options.forceNewlineBetweenStepBlocks !== true) { | ||
const hadHardlineBefore = | ||
previousNode && currentNode.location.line - previousNode.lastLine >= 2; | ||
if (hadHardlineBefore) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
return ( | ||
!isFirstStep && | ||
node.keywordType && | ||
@@ -317,4 +355,4 @@ [StepKeywordType.CONTEXT, StepKeywordType.ACTION].includes(node.keywordType) | ||
const parentNode = path.getParentNode(); | ||
const parentNodeIsFirstStep = path.stack[path.stack.length - 6] === 0; | ||
const stepNode = path.getParentNode(); | ||
const previousNode = findPreviousNode(path, 6); | ||
@@ -324,4 +362,4 @@ // if the comment follows a `Given` step, then the comment should have a leading blank line | ||
if ( | ||
parentNode instanceof TypedStep && | ||
stepNeedsHardline(parentNode, parentNodeIsFirstStep) | ||
stepNode instanceof TypedStep && | ||
stepNeedsHardline(options, stepNode, node, previousNode) | ||
) { | ||
@@ -335,3 +373,3 @@ return [printHardline(), node.text.trim()]; | ||
canAttachComment(node): boolean { | ||
// comments are all in the TypedGherkinDocument.comments array. | ||
// comments are all in the TypedGherkinDocument.comments array. | ||
// Do not handle comments in the subtree of the AST. | ||
@@ -346,4 +384,2 @@ return node instanceof TypedGherkinDocument; | ||
// getCommentChildNodes: (node) => { | ||
@@ -516,6 +552,7 @@ // console.log('getCommentChildNodes', node) | ||
} else if (node instanceof TypedStep) { | ||
// console.log(node); | ||
const previousNode = findPreviousNode(path, 2); | ||
return [ | ||
// if the step has comment, the hardline will be handled by the comment printer | ||
stepNeedsHardline(node, path.stack[path.stack.length - 2] === 0) && | ||
stepNeedsHardline(options, node, null, previousNode) && | ||
// @ts-expect-error comments are injected by prettier directly | ||
@@ -661,2 +698,10 @@ !node.comments | ||
}, | ||
forceNewlineBetweenStepBlocks: { | ||
type: 'boolean', | ||
default: false, | ||
description: 'Force new line between Context and Action blocks', | ||
oppositeDescription: | ||
'Do not force hardline between Context and Action blocks', | ||
category: 'Format', | ||
}, | ||
}, | ||
@@ -663,0 +708,0 @@ }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
18905206
149372
181