diff --git a/packages/ast-spec/src/unions/LeftHandSideExpression.ts b/packages/ast-spec/src/unions/LeftHandSideExpression.ts
index 5d6922ed42d..fc3a80b2361 100644
--- a/packages/ast-spec/src/unions/LeftHandSideExpression.ts
+++ b/packages/ast-spec/src/unions/LeftHandSideExpression.ts
@@ -9,6 +9,7 @@ import type { JSXFragment } from '../expression/JSXFragment/spec';
import type { MemberExpression } from '../expression/MemberExpression/spec';
import type { MetaProperty } from '../expression/MetaProperty/spec';
import type { ObjectExpression } from '../expression/ObjectExpression/spec';
+import type { SequenceExpression } from '../expression/spec';
import type { Super } from '../expression/Super/spec';
import type { TaggedTemplateExpression } from '../expression/TaggedTemplateExpression/spec';
import type { ThisExpression } from '../expression/ThisExpression/spec';
@@ -34,6 +35,7 @@ export type LeftHandSideExpression =
| MetaProperty
| ObjectExpression
| ObjectPattern
+ | SequenceExpression
| Super
| TaggedTemplateExpression
| ThisExpression
diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md
index 344764dcb96..77a5ff7b455 100644
--- a/packages/eslint-plugin/README.md
+++ b/packages/eslint-plugin/README.md
@@ -189,43 +189,44 @@ In these cases, we create what we call an extension rule; a rule within our plug
**Key**: :white_check_mark: = recommended, :wrench: = fixable, :thought_balloon: = requires type information
-| Name | Description | :white_check_mark: | :wrench: | :thought_balloon: |
-| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------ | -------- | ----------------- |
-| [`@typescript-eslint/brace-style`](./docs/rules/brace-style.md) | Enforce consistent brace style for blocks | | :wrench: | |
-| [`@typescript-eslint/comma-dangle`](./docs/rules/comma-dangle.md) | Require or disallow trailing comma | | :wrench: | |
-| [`@typescript-eslint/comma-spacing`](./docs/rules/comma-spacing.md) | Enforces consistent spacing before and after commas | | :wrench: | |
-| [`@typescript-eslint/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | |
-| [`@typescript-eslint/dot-notation`](./docs/rules/dot-notation.md) | enforce dot notation whenever possible | | :wrench: | :thought_balloon: |
-| [`@typescript-eslint/func-call-spacing`](./docs/rules/func-call-spacing.md) | Require or disallow spacing between function identifiers and their invocations | | :wrench: | |
-| [`@typescript-eslint/indent`](./docs/rules/indent.md) | Enforce consistent indentation | | :wrench: | |
-| [`@typescript-eslint/init-declarations`](./docs/rules/init-declarations.md) | require or disallow initialization in variable declarations | | | |
-| [`@typescript-eslint/keyword-spacing`](./docs/rules/keyword-spacing.md) | Enforce consistent spacing before and after keywords | | :wrench: | |
-| [`@typescript-eslint/lines-between-class-members`](./docs/rules/lines-between-class-members.md) | Require or disallow an empty line between class members | | :wrench: | |
-| [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :white_check_mark: | :wrench: | |
-| [`@typescript-eslint/no-dupe-class-members`](./docs/rules/no-dupe-class-members.md) | Disallow duplicate class members | | | |
-| [`@typescript-eslint/no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate imports | | | |
-| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :white_check_mark: | | |
-| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | |
-| [`@typescript-eslint/no-extra-semi`](./docs/rules/no-extra-semi.md) | Disallow unnecessary semicolons | :white_check_mark: | :wrench: | |
-| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | :white_check_mark: | | :thought_balloon: |
-| [`@typescript-eslint/no-invalid-this`](./docs/rules/no-invalid-this.md) | Disallow `this` keywords outside of classes or class-like objects | | | |
-| [`@typescript-eslint/no-loop-func`](./docs/rules/no-loop-func.md) | Disallow function declarations that contain unsafe references inside loop statements | | | |
-| [`@typescript-eslint/no-loss-of-precision`](./docs/rules/no-loss-of-precision.md) | Disallow literal numbers that lose precision | | | |
-| [`@typescript-eslint/no-magic-numbers`](./docs/rules/no-magic-numbers.md) | Disallow magic numbers | | | |
-| [`@typescript-eslint/no-redeclare`](./docs/rules/no-redeclare.md) | Disallow variable redeclaration | | | |
-| [`@typescript-eslint/no-shadow`](./docs/rules/no-shadow.md) | Disallow variable declarations from shadowing variables declared in the outer scope | | | |
-| [`@typescript-eslint/no-throw-literal`](./docs/rules/no-throw-literal.md) | Disallow throwing literals as exceptions | | | :thought_balloon: |
-| [`@typescript-eslint/no-unused-expressions`](./docs/rules/no-unused-expressions.md) | Disallow unused expressions | | | |
-| [`@typescript-eslint/no-unused-vars`](./docs/rules/no-unused-vars.md) | Disallow unused variables | :white_check_mark: | | |
-| [`@typescript-eslint/no-use-before-define`](./docs/rules/no-use-before-define.md) | Disallow the use of variables before they are defined | | | |
-| [`@typescript-eslint/no-useless-constructor`](./docs/rules/no-useless-constructor.md) | Disallow unnecessary constructors | | | |
-| [`@typescript-eslint/object-curly-spacing`](./docs/rules/object-curly-spacing.md) | Enforce consistent spacing inside braces | | :wrench: | |
-| [`@typescript-eslint/quotes`](./docs/rules/quotes.md) | Enforce the consistent use of either backticks, double, or single quotes | | :wrench: | |
-| [`@typescript-eslint/require-await`](./docs/rules/require-await.md) | Disallow async functions which have no `await` expression | :white_check_mark: | | :thought_balloon: |
-| [`@typescript-eslint/return-await`](./docs/rules/return-await.md) | Enforces consistent returning of awaited values | | :wrench: | :thought_balloon: |
-| [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | |
-| [`@typescript-eslint/space-before-function-paren`](./docs/rules/space-before-function-paren.md) | Enforces consistent spacing before function parenthesis | | :wrench: | |
-| [`@typescript-eslint/space-infix-ops`](./docs/rules/space-infix-ops.md) | This rule is aimed at ensuring there are spaces around infix operators. | | :wrench: | |
+| Name | Description | :white_check_mark: | :wrench: | :thought_balloon: |
+| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------ | -------- | ----------------- |
+| [`@typescript-eslint/brace-style`](./docs/rules/brace-style.md) | Enforce consistent brace style for blocks | | :wrench: | |
+| [`@typescript-eslint/comma-dangle`](./docs/rules/comma-dangle.md) | Require or disallow trailing comma | | :wrench: | |
+| [`@typescript-eslint/comma-spacing`](./docs/rules/comma-spacing.md) | Enforces consistent spacing before and after commas | | :wrench: | |
+| [`@typescript-eslint/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | |
+| [`@typescript-eslint/dot-notation`](./docs/rules/dot-notation.md) | enforce dot notation whenever possible | | :wrench: | :thought_balloon: |
+| [`@typescript-eslint/func-call-spacing`](./docs/rules/func-call-spacing.md) | Require or disallow spacing between function identifiers and their invocations | | :wrench: | |
+| [`@typescript-eslint/indent`](./docs/rules/indent.md) | Enforce consistent indentation | | :wrench: | |
+| [`@typescript-eslint/init-declarations`](./docs/rules/init-declarations.md) | require or disallow initialization in variable declarations | | | |
+| [`@typescript-eslint/keyword-spacing`](./docs/rules/keyword-spacing.md) | Enforce consistent spacing before and after keywords | | :wrench: | |
+| [`@typescript-eslint/lines-between-class-members`](./docs/rules/lines-between-class-members.md) | Require or disallow an empty line between class members | | :wrench: | |
+| [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :white_check_mark: | :wrench: | |
+| [`@typescript-eslint/no-dupe-class-members`](./docs/rules/no-dupe-class-members.md) | Disallow duplicate class members | | | |
+| [`@typescript-eslint/no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate imports | | | |
+| [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | :white_check_mark: | | |
+| [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | |
+| [`@typescript-eslint/no-extra-semi`](./docs/rules/no-extra-semi.md) | Disallow unnecessary semicolons | :white_check_mark: | :wrench: | |
+| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | :white_check_mark: | | :thought_balloon: |
+| [`@typescript-eslint/no-invalid-this`](./docs/rules/no-invalid-this.md) | Disallow `this` keywords outside of classes or class-like objects | | | |
+| [`@typescript-eslint/no-loop-func`](./docs/rules/no-loop-func.md) | Disallow function declarations that contain unsafe references inside loop statements | | | |
+| [`@typescript-eslint/no-loss-of-precision`](./docs/rules/no-loss-of-precision.md) | Disallow literal numbers that lose precision | | | |
+| [`@typescript-eslint/no-magic-numbers`](./docs/rules/no-magic-numbers.md) | Disallow magic numbers | | | |
+| [`@typescript-eslint/no-redeclare`](./docs/rules/no-redeclare.md) | Disallow variable redeclaration | | | |
+| [`@typescript-eslint/no-shadow`](./docs/rules/no-shadow.md) | Disallow variable declarations from shadowing variables declared in the outer scope | | | |
+| [`@typescript-eslint/no-throw-literal`](./docs/rules/no-throw-literal.md) | Disallow throwing literals as exceptions | | | :thought_balloon: |
+| [`@typescript-eslint/no-unused-expressions`](./docs/rules/no-unused-expressions.md) | Disallow unused expressions | | | |
+| [`@typescript-eslint/no-unused-vars`](./docs/rules/no-unused-vars.md) | Disallow unused variables | :white_check_mark: | | |
+| [`@typescript-eslint/no-use-before-define`](./docs/rules/no-use-before-define.md) | Disallow the use of variables before they are defined | | | |
+| [`@typescript-eslint/no-useless-constructor`](./docs/rules/no-useless-constructor.md) | Disallow unnecessary constructors | | | |
+| [`@typescript-eslint/object-curly-spacing`](./docs/rules/object-curly-spacing.md) | Enforce consistent spacing inside braces | | :wrench: | |
+| [`@typescript-eslint/padding-line-between-statements`](./docs/rules/padding-line-between-statements.md) | require or disallow padding lines between statements | | :wrench: | |
+| [`@typescript-eslint/quotes`](./docs/rules/quotes.md) | Enforce the consistent use of either backticks, double, or single quotes | | :wrench: | |
+| [`@typescript-eslint/require-await`](./docs/rules/require-await.md) | Disallow async functions which have no `await` expression | :white_check_mark: | | :thought_balloon: |
+| [`@typescript-eslint/return-await`](./docs/rules/return-await.md) | Enforces consistent returning of awaited values | | :wrench: | :thought_balloon: |
+| [`@typescript-eslint/semi`](./docs/rules/semi.md) | Require or disallow semicolons instead of ASI | | :wrench: | |
+| [`@typescript-eslint/space-before-function-paren`](./docs/rules/space-before-function-paren.md) | Enforces consistent spacing before function parenthesis | | :wrench: | |
+| [`@typescript-eslint/space-infix-ops`](./docs/rules/space-infix-ops.md) | This rule is aimed at ensuring there are spaces around infix operators. | | :wrench: | |
diff --git a/packages/eslint-plugin/docs/rules/padding-line-between-statements.md b/packages/eslint-plugin/docs/rules/padding-line-between-statements.md
new file mode 100644
index 00000000000..b23ce702b78
--- /dev/null
+++ b/packages/eslint-plugin/docs/rules/padding-line-between-statements.md
@@ -0,0 +1,48 @@
+# require or disallow padding lines between statements (`padding-line-between-statements`)
+
+## Rule Details
+
+This rule extends the base [`eslint/padding-line-between-statements`](https://eslint.org/docs/rules/padding-line-between-statements) rule.
+
+**It adds support for TypeScript constructs such as `interface` and `type`.**
+
+## How to use
+
+```jsonc
+{
+ // note you must disable the base rule as it can report incorrect errors
+ "padding-line-between-statements": "off",
+ "@typescript-eslint/padding-line-between-statements": [
+ "error",
+ {
+ "blankLine": "always",
+ "prev": "var",
+ "next": "return"
+ }
+ ]
+}
+```
+
+```jsonc
+{
+ // Example - Add blank lines before interface and type definitions.
+ // note you must disable the base rule as it can report incorrect errors
+ "padding-line-between-statements": "off",
+ "@typescript-eslint/padding-line-between-statements": [
+ "error",
+ {
+ "blankLine": "always",
+ "prev": "*",
+ "next": ["interface", "type"]
+ }
+ ]
+}
+```
+
+## Options
+
+See [`eslint/padding-line-between-statements` options](https://eslint.org/docs/rules/padding-line-between-statements#options).
+
+**Note** - In addition to options provided by ESLint, we have also added options for `interface` and `type`.
+
+Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/padding-line-between-statements.md)
diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts
index b21d14efc9f..6938d507ad4 100644
--- a/packages/eslint-plugin/src/configs/all.ts
+++ b/packages/eslint-plugin/src/configs/all.ts
@@ -116,6 +116,8 @@ export = {
'@typescript-eslint/non-nullable-type-assertion-style': 'error',
'object-curly-spacing': 'off',
'@typescript-eslint/object-curly-spacing': 'error',
+ 'padding-line-between-statements': 'off',
+ '@typescript-eslint/padding-line-between-statements': 'error',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/prefer-enum-initializers': 'error',
'@typescript-eslint/prefer-for-of': 'error',
diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts
index be78db26f80..c61d2f4eeea 100644
--- a/packages/eslint-plugin/src/rules/index.ts
+++ b/packages/eslint-plugin/src/rules/index.ts
@@ -81,6 +81,7 @@ import noUselessConstructor from './no-useless-constructor';
import noVarRequires from './no-var-requires';
import nonNullableTypeAssertionStyle from './non-nullable-type-assertion-style';
import objectCurlySpacing from './object-curly-spacing';
+import paddingLineBetweenStatements from './padding-line-between-statements';
import preferAsConst from './prefer-as-const';
import preferEnumInitializers from './prefer-enum-initializers';
import preferForOf from './prefer-for-of';
@@ -199,6 +200,7 @@ export default {
'no-var-requires': noVarRequires,
'non-nullable-type-assertion-style': nonNullableTypeAssertionStyle,
'object-curly-spacing': objectCurlySpacing,
+ 'padding-line-between-statements': paddingLineBetweenStatements,
'prefer-as-const': preferAsConst,
'prefer-enum-initializers': preferEnumInitializers,
'prefer-for-of': preferForOf,
diff --git a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts
new file mode 100644
index 00000000000..f686476e5de
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts
@@ -0,0 +1,775 @@
+import {
+ AST_NODE_TYPES,
+ TSESLint,
+ TSESTree,
+} from '@typescript-eslint/experimental-utils';
+import * as util from '../util';
+
+/**
+ * This rule is a replica of padding-line-between-statements.
+ *
+ * Ideally we would want to extend the rule support typescript specific support.
+ * But since not all the state is exposed by the eslint and eslint has frozen stylistic rules,
+ * (see - https://eslint.org/blog/2020/05/changes-to-rules-policies for details.)
+ * we are forced to re-implement the rule here.
+ *
+ * We have tried to keep the implementation as close as possible to the eslint implementation, to make
+ * patching easier for future contributors.
+ *
+ * Reference rule - https://github.com/eslint/eslint/blob/master/lib/rules/padding-line-between-statements.js
+ */
+
+type NodeTest = (
+ node: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+) => boolean;
+
+interface NodeTestObject {
+ test: NodeTest;
+}
+
+interface PaddingOption {
+ blankLine: keyof typeof PaddingTypes;
+ prev: string | string[];
+ next: string | string[];
+}
+
+type MessageIds = 'expectedBlankLine' | 'unexpectedBlankLine';
+type Options = PaddingOption[];
+
+const LT = `[${Array.from(
+ new Set(['\r\n', '\r', '\n', '\u2028', '\u2029']),
+).join('')}]`;
+const PADDING_LINE_SEQUENCE = new RegExp(
+ String.raw`^(\s*?${LT})\s*${LT}(\s*;?)$`,
+ 'u',
+);
+
+/**
+ * Creates tester which check if a node starts with specific keyword.
+ * @param keyword The keyword to test.
+ * @returns the created tester.
+ * @private
+ */
+function newKeywordTester(keyword: string): NodeTestObject {
+ return {
+ test(node, sourceCode): boolean {
+ return sourceCode.getFirstToken(node)?.value === keyword;
+ },
+ };
+}
+
+/**
+ * Creates tester which check if a node starts with specific keyword and spans a single line.
+ * @param keyword The keyword to test.
+ * @returns the created tester.
+ * @private
+ */
+function newSinglelineKeywordTester(keyword: string): NodeTestObject {
+ return {
+ test(node, sourceCode): boolean {
+ return (
+ node.loc.start.line === node.loc.end.line &&
+ sourceCode.getFirstToken(node)!.value === keyword
+ );
+ },
+ };
+}
+
+/**
+ * Creates tester which check if a node starts with specific keyword and spans multiple lines.
+ * @param keyword The keyword to test.
+ * @returns the created tester.
+ * @private
+ */
+function newMultilineKeywordTester(keyword: string): NodeTestObject {
+ return {
+ test(node, sourceCode): boolean {
+ return (
+ node.loc.start.line !== node.loc.end.line &&
+ sourceCode.getFirstToken(node)!.value === keyword
+ );
+ },
+ };
+}
+
+/**
+ * Creates tester which check if a node is specific type.
+ * @param type The node type to test.
+ * @returns the created tester.
+ * @private
+ */
+function newNodeTypeTester(type: AST_NODE_TYPES): NodeTestObject {
+ return {
+ test: (node): boolean => node.type === type,
+ };
+}
+
+/**
+ * Skips a chain expression node
+ * @paramnode The node to test
+ * @returnsA non-chain expression
+ * @private
+ */
+function skipChainExpression(node: TSESTree.Node): TSESTree.Node {
+ return node && node.type === AST_NODE_TYPES.ChainExpression
+ ? node.expression
+ : node;
+}
+
+/**
+ * Checks the given node is an expression statement of IIFE.
+ * @paramnode The node to check.
+ * @returns `true` if the node is an expression statement of IIFE.
+ * @private
+ */
+function isIIFEStatement(node: TSESTree.Node): boolean {
+ if (node.type === AST_NODE_TYPES.ExpressionStatement) {
+ let expression = skipChainExpression(node.expression);
+ if (expression.type === AST_NODE_TYPES.UnaryExpression) {
+ expression = skipChainExpression(expression.argument);
+ }
+ if (expression.type === AST_NODE_TYPES.CallExpression) {
+ let node: TSESTree.Node = expression.callee;
+ while (node.type === AST_NODE_TYPES.SequenceExpression) {
+ node = node.expressions[node.expressions.length - 1];
+ }
+ return util.isFunction(node);
+ }
+ }
+ return false;
+}
+
+/**
+ * Checks the given node is a CommonJS require statement
+ * @paramnode The node to check.
+ * @returns `true` if the node is a CommonJS require statement.
+ * @private
+ */
+function isCJSRequire(node: TSESTree.Node): boolean {
+ if (node.type === AST_NODE_TYPES.VariableDeclaration) {
+ const declaration = node.declarations[0];
+ if (declaration?.init) {
+ let call = declaration?.init;
+ while (call.type === AST_NODE_TYPES.MemberExpression) {
+ call = call.object;
+ }
+ if (
+ call.type === AST_NODE_TYPES.CallExpression &&
+ call.callee.type === AST_NODE_TYPES.Identifier
+ ) {
+ return call.callee.name === 'require';
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Checks whether the given node is a block-like statement.
+ * This checks the last token of the node is the closing brace of a block.
+ * @param sourceCode The source code to get tokens.
+ * @paramnode The node to check.
+ * @returns `true` if the node is a block-like statement.
+ * @private
+ */
+function isBlockLikeStatement(
+ node: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+): boolean {
+ // do-while with a block is a block-like statement.
+ if (
+ node.type === AST_NODE_TYPES.DoWhileStatement &&
+ node.body.type === AST_NODE_TYPES.BlockStatement
+ ) {
+ return true;
+ }
+
+ /**
+ * IIFE is a block-like statement specially from
+ * JSCS#disallowPaddingNewLinesAfterBlocks.
+ */
+ if (isIIFEStatement(node)) {
+ return true;
+ }
+
+ // Checks the last token is a closing brace of blocks.
+ const lastToken = sourceCode.getLastToken(node, util.isNotSemicolonToken);
+ const belongingNode =
+ lastToken && util.isClosingBraceToken(lastToken)
+ ? sourceCode.getNodeByRangeIndex(lastToken.range[0])
+ : null;
+
+ return (
+ !!belongingNode &&
+ (belongingNode.type === AST_NODE_TYPES.BlockStatement ||
+ belongingNode.type === AST_NODE_TYPES.SwitchStatement)
+ );
+}
+
+/**
+ * Check whether the given node is a directive or not.
+ * @paramnode The node to check.
+ * @param sourceCode The source code object to get tokens.
+ * @returns `true` if the node is a directive.
+ */
+function isDirective(
+ node: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+): boolean {
+ return (
+ node.type === AST_NODE_TYPES.ExpressionStatement &&
+ (node.parent?.type === AST_NODE_TYPES.Program ||
+ (node.parent?.type === AST_NODE_TYPES.BlockStatement &&
+ util.isFunction(node.parent.parent))) &&
+ node.expression.type === AST_NODE_TYPES.Literal &&
+ typeof node.expression.value === 'string' &&
+ !util.isParenthesized(node.expression, sourceCode)
+ );
+}
+
+/**
+ * Check whether the given node is a part of directive prologue or not.
+ * @paramnode The node to check.
+ * @param sourceCode The source code object to get tokens.
+ * @returns `true` if the node is a part of directive prologue.
+ */
+function isDirectivePrologue(
+ node: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+): boolean {
+ if (
+ isDirective(node, sourceCode) &&
+ node.parent &&
+ 'body' in node.parent &&
+ Array.isArray(node.parent.body)
+ ) {
+ for (const sibling of node.parent.body) {
+ if (sibling === node) {
+ break;
+ }
+ if (!isDirective(sibling, sourceCode)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Checks the given node is a CommonJS export statement
+ * @paramnode The node to check.
+ * @returns `true` if the node is a CommonJS export statement.
+ * @private
+ */
+function isCJSExport(node: TSESTree.Node): boolean {
+ if (node.type === AST_NODE_TYPES.ExpressionStatement) {
+ const expression = node.expression;
+ if (expression.type === AST_NODE_TYPES.AssignmentExpression) {
+ let left = expression.left;
+ if (left.type === AST_NODE_TYPES.MemberExpression) {
+ while (left.object.type === AST_NODE_TYPES.MemberExpression) {
+ left = left.object;
+ }
+ return (
+ left.object.type === AST_NODE_TYPES.Identifier &&
+ (left.object.name === 'exports' ||
+ (left.object.name === 'module' &&
+ left.property.type === AST_NODE_TYPES.Identifier &&
+ left.property.name === 'exports'))
+ );
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Check whether the given node is an expression
+ * @paramnode The node to check.
+ * @param sourceCode The source code object to get tokens.
+ * @returns `true` if the node is an expression
+ */
+function isExpression(
+ node: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+): boolean {
+ return (
+ node.type === AST_NODE_TYPES.ExpressionStatement &&
+ !isDirectivePrologue(node, sourceCode)
+ );
+}
+
+/**
+ * Gets the actual last token.
+ *
+ * If a semicolon is semicolon-less style's semicolon, this ignores it.
+ * For example:
+ *
+ * foo()
+ * ;[1, 2, 3].forEach(bar)
+ * @param sourceCode The source code to get tokens.
+ * @paramnode The node to get.
+ * @returns The actual last token.
+ * @private
+ */
+function getActualLastToken(
+ node: TSESTree.Node,
+ sourceCode: TSESLint.SourceCode,
+): TSESTree.Token | null {
+ const semiToken = sourceCode.getLastToken(node)!;
+ const prevToken = sourceCode.getTokenBefore(semiToken);
+ const nextToken = sourceCode.getTokenAfter(semiToken);
+ const isSemicolonLessStyle =
+ prevToken &&
+ nextToken &&
+ prevToken.range[0] >= node.range[0] &&
+ util.isSemicolonToken(semiToken) &&
+ semiToken.loc.start.line !== prevToken.loc.end.line &&
+ semiToken.loc.end.line === nextToken.loc.start.line;
+
+ return isSemicolonLessStyle ? prevToken : semiToken;
+}
+
+/**
+ * This returns the concatenation of the first 2 captured strings.
+ * @param _ Unused. Whole matched string.
+ * @param trailingSpaces The trailing spaces of the first line.
+ * @param indentSpaces The indentation spaces of the last line.
+ * @returns The concatenation of trailingSpaces and indentSpaces.
+ * @private
+ */
+function replacerToRemovePaddingLines(
+ _: string,
+ trailingSpaces: string,
+ indentSpaces: string,
+): string {
+ return trailingSpaces + indentSpaces;
+}
+
+/**
+ * Check and report statements for `any` configuration.
+ * It does nothing.
+ *
+ * @private
+ */
+function verifyForAny(): void {
+ // Empty
+}
+
+/**
+ * Check and report statements for `never` configuration.
+ * This autofix removes blank lines between the given 2 statements.
+ * However, if comments exist between 2 blank lines, it does not remove those
+ * blank lines automatically.
+ * @param context The rule context to report.
+ * @param_ Unused. The previous node to check.
+ * @paramnextNode The next node to check.
+ * @param paddingLines The array of token pairs that blank
+ * lines exist between the pair.
+ *
+ * @private
+ */
+function verifyForNever(
+ context: TSESLint.RuleContext,
+ _: TSESTree.Node,
+ nextNode: TSESTree.Node,
+ paddingLines: [TSESTree.Token, TSESTree.Token][],
+): void {
+ if (paddingLines.length === 0) {
+ return;
+ }
+
+ context.report({
+ node: nextNode,
+ messageId: 'unexpectedBlankLine',
+ fix(fixer) {
+ if (paddingLines.length >= 2) {
+ return null;
+ }
+
+ const prevToken = paddingLines[0][0];
+ const nextToken = paddingLines[0][1];
+ const start = prevToken.range[1];
+ const end = nextToken.range[0];
+ const text = context
+ .getSourceCode()
+ .text.slice(start, end)
+ .replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines);
+
+ return fixer.replaceTextRange([start, end], text);
+ },
+ });
+}
+
+/**
+ * Check and report statements for `always` configuration.
+ * This autofix inserts a blank line between the given 2 statements.
+ * If the `prevNode` has trailing comments, it inserts a blank line after the
+ * trailing comments.
+ * @param context The rule context to report.
+ * @paramprevNode The previous node to check.
+ * @paramnextNode The next node to check.
+ * @param paddingLines The array of token pairs that blank
+ * lines exist between the pair.
+ *
+ * @private
+ */
+function verifyForAlways(
+ context: TSESLint.RuleContext,
+ prevNode: TSESTree.Node,
+ nextNode: TSESTree.Node,
+ paddingLines: [TSESTree.Token, TSESTree.Token][],
+): void {
+ if (paddingLines.length > 0) {
+ return;
+ }
+
+ context.report({
+ node: nextNode,
+ messageId: 'expectedBlankLine',
+ fix(fixer) {
+ const sourceCode = context.getSourceCode();
+ let prevToken = getActualLastToken(
+ prevNode,
+ sourceCode,
+ ) as TSESTree.Token;
+ const nextToken =
+ (sourceCode.getFirstTokenBetween(prevToken, nextNode, {
+ includeComments: true,
+
+ /**
+ * Skip the trailing comments of the previous node.
+ * This inserts a blank line after the last trailing comment.
+ *
+ * For example:
+ *
+ * foo(); // trailing comment.
+ * // comment.
+ * bar();
+ *
+ * Get fixed to:
+ *
+ * foo(); // trailing comment.
+ *
+ * // comment.
+ * bar();
+ * @param token The token to check.
+ * @returns `true` if the token is not a trailing comment.
+ * @private
+ */
+ filter(token) {
+ if (util.isTokenOnSameLine(prevToken, token)) {
+ prevToken = token;
+ return false;
+ }
+ return true;
+ },
+ }) as TSESTree.Token) || nextNode;
+ const insertText = util.isTokenOnSameLine(prevToken, nextToken)
+ ? '\n\n'
+ : '\n';
+
+ return fixer.insertTextAfter(prevToken, insertText);
+ },
+ });
+}
+
+/**
+ * Types of blank lines.
+ * `any`, `never`, and `always` are defined.
+ * Those have `verify` method to check and report statements.
+ * @private
+ */
+const PaddingTypes = {
+ any: { verify: verifyForAny },
+ never: { verify: verifyForNever },
+ always: { verify: verifyForAlways },
+};
+
+/**
+ * Types of statements.
+ * Those have `test` method to check it matches to the given statement.
+ * @private
+ */
+const StatementTypes: Record = {
+ '*': { test: (): boolean => true },
+ 'block-like': { test: isBlockLikeStatement },
+ exports: { test: isCJSExport },
+ require: { test: isCJSRequire },
+ directive: { test: isDirectivePrologue },
+ expression: { test: isExpression },
+ iife: { test: isIIFEStatement },
+
+ 'multiline-block-like': {
+ test: (node, sourceCode) =>
+ node.loc.start.line !== node.loc.end.line &&
+ isBlockLikeStatement(node, sourceCode),
+ },
+ 'multiline-expression': {
+ test: (node, sourceCode) =>
+ node.loc.start.line !== node.loc.end.line &&
+ node.type === AST_NODE_TYPES.ExpressionStatement &&
+ !isDirectivePrologue(node, sourceCode),
+ },
+
+ 'multiline-const': newMultilineKeywordTester('const'),
+ 'multiline-let': newMultilineKeywordTester('let'),
+ 'multiline-var': newMultilineKeywordTester('var'),
+ 'singleline-const': newSinglelineKeywordTester('const'),
+ 'singleline-let': newSinglelineKeywordTester('let'),
+ 'singleline-var': newSinglelineKeywordTester('var'),
+
+ block: newNodeTypeTester(AST_NODE_TYPES.BlockStatement),
+ empty: newNodeTypeTester(AST_NODE_TYPES.EmptyStatement),
+ function: newNodeTypeTester(AST_NODE_TYPES.FunctionDeclaration),
+
+ break: newKeywordTester('break'),
+ case: newKeywordTester('case'),
+ class: newKeywordTester('class'),
+ const: newKeywordTester('const'),
+ continue: newKeywordTester('continue'),
+ debugger: newKeywordTester('debugger'),
+ default: newKeywordTester('default'),
+ do: newKeywordTester('do'),
+ export: newKeywordTester('export'),
+ for: newKeywordTester('for'),
+ if: newKeywordTester('if'),
+ import: newKeywordTester('import'),
+ let: newKeywordTester('let'),
+ return: newKeywordTester('return'),
+ switch: newKeywordTester('switch'),
+ throw: newKeywordTester('throw'),
+ try: newKeywordTester('try'),
+ var: newKeywordTester('var'),
+ while: newKeywordTester('while'),
+ with: newKeywordTester('with'),
+
+ // Additional Typescript constructs
+ interface: newKeywordTester('interface'),
+ type: newKeywordTester('type'),
+};
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+export default util.createRule({
+ name: 'padding-line-between-statements',
+ meta: {
+ type: 'layout',
+ docs: {
+ description: 'require or disallow padding lines between statements',
+ category: 'Stylistic Issues',
+ recommended: false,
+ extendsBaseRule: true,
+ },
+ fixable: 'whitespace',
+ schema: {
+ definitions: {
+ paddingType: {
+ enum: Object.keys(PaddingTypes),
+ },
+ statementType: {
+ anyOf: [
+ { enum: Object.keys(StatementTypes) },
+ {
+ type: 'array',
+ items: { enum: Object.keys(StatementTypes) },
+ minItems: 1,
+ uniqueItems: true,
+ additionalItems: false,
+ },
+ ],
+ },
+ },
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ blankLine: { $ref: '#/definitions/paddingType' },
+ prev: { $ref: '#/definitions/statementType' },
+ next: { $ref: '#/definitions/statementType' },
+ },
+ additionalProperties: false,
+ required: ['blankLine', 'prev', 'next'],
+ },
+ additionalItems: false,
+ },
+ messages: {
+ unexpectedBlankLine: 'Unexpected blank line before this statement.',
+ expectedBlankLine: 'Expected blank line before this statement.',
+ },
+ },
+ defaultOptions: [],
+ create(context) {
+ const sourceCode = context.getSourceCode();
+ const configureList = context.options || [];
+
+ type Scope = null | {
+ upper: Scope;
+ prevNode: TSESTree.Node | null;
+ };
+
+ let scopeInfo: Scope = null;
+
+ /**
+ * Processes to enter to new scope.
+ * This manages the current previous statement.
+ *
+ * @private
+ */
+ function enterScope(): void {
+ scopeInfo = {
+ upper: scopeInfo,
+ prevNode: null,
+ };
+ }
+
+ /**
+ * Processes to exit from the current scope.
+ *
+ * @private
+ */
+ function exitScope(): void {
+ if (scopeInfo) {
+ scopeInfo = scopeInfo.upper;
+ }
+ }
+
+ /**
+ * Checks whether the given node matches the given type.
+ * @paramnode The statement node to check.
+ * @param type The statement type to check.
+ * @returns `true` if the statement node matched the type.
+ * @private
+ */
+ function match(node: TSESTree.Node, type: string | string[]): boolean {
+ let innerStatementNode = node;
+
+ while (innerStatementNode.type === AST_NODE_TYPES.LabeledStatement) {
+ innerStatementNode = innerStatementNode.body;
+ }
+
+ if (Array.isArray(type)) {
+ return type.some(match.bind(null, innerStatementNode));
+ }
+
+ return StatementTypes[type].test(innerStatementNode, sourceCode);
+ }
+
+ /**
+ * Finds the last matched configure from configureList.
+ * @paramprevNode The previous statement to match.
+ * @paramnextNode The current statement to match.
+ * @returns The tester of the last matched configure.
+ * @private
+ */
+ function getPaddingType(
+ prevNode: TSESTree.Node,
+ nextNode: TSESTree.Node,
+ ): typeof PaddingTypes[keyof typeof PaddingTypes] {
+ for (let i = configureList.length - 1; i >= 0; --i) {
+ const configure = configureList[i];
+ if (
+ match(prevNode, configure.prev) &&
+ match(nextNode, configure.next)
+ ) {
+ return PaddingTypes[configure.blankLine];
+ }
+ }
+ return PaddingTypes.any;
+ }
+
+ /**
+ * Gets padding line sequences between the given 2 statements.
+ * Comments are separators of the padding line sequences.
+ * @paramprevNode The previous statement to count.
+ * @paramnextNode The current statement to count.
+ * @returns The array of token pairs.
+ * @private
+ */
+ function getPaddingLineSequences(
+ prevNode: TSESTree.Node,
+ nextNode: TSESTree.Node,
+ ): [TSESTree.Token, TSESTree.Token][] {
+ const pairs: [TSESTree.Token, TSESTree.Token][] = [];
+ let prevToken: TSESTree.Token = getActualLastToken(prevNode, sourceCode)!;
+
+ if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
+ do {
+ const token: TSESTree.Token = sourceCode.getTokenAfter(prevToken, {
+ includeComments: true,
+ })!;
+
+ if (token.loc.start.line - prevToken.loc.end.line >= 2) {
+ pairs.push([prevToken, token]);
+ }
+ prevToken = token;
+ } while (prevToken.range[0] < nextNode.range[0]);
+ }
+
+ return pairs;
+ }
+
+ /**
+ * Verify padding lines between the given node and the previous node.
+ * @paramnode The node to verify.
+ *
+ * @private
+ */
+ function verify(node: TSESTree.Node): void {
+ if (
+ !node.parent ||
+ ![
+ AST_NODE_TYPES.SwitchStatement,
+ AST_NODE_TYPES.BlockStatement,
+ AST_NODE_TYPES.Program,
+ AST_NODE_TYPES.SwitchCase,
+ ].includes(node.parent.type)
+ ) {
+ return;
+ }
+
+ // Save this node as the current previous statement.
+ const prevNode = scopeInfo!.prevNode;
+
+ // Verify.
+ if (prevNode) {
+ const type = getPaddingType(prevNode, node);
+ const paddingLines = getPaddingLineSequences(prevNode, node);
+
+ type.verify(context, prevNode, node, paddingLines);
+ }
+
+ scopeInfo!.prevNode = node;
+ }
+
+ /**
+ * Verify padding lines between the given node and the previous node.
+ * Then process to enter to new scope.
+ * @paramnode The node to verify.
+ *
+ * @private
+ */
+ function verifyThenEnterScope(node: TSESTree.Node): void {
+ verify(node);
+ enterScope();
+ }
+
+ return {
+ Program: enterScope,
+ BlockStatement: enterScope,
+ SwitchStatement: enterScope,
+ 'Program:exit': exitScope,
+ 'BlockStatement:exit': exitScope,
+ 'SwitchStatement:exit': exitScope,
+
+ ':statement': verify,
+
+ SwitchCase: verifyThenEnterScope,
+ 'SwitchCase:exit': exitScope,
+ };
+ },
+});
diff --git a/packages/eslint-plugin/tests/rules/padding-line-between-statements.test.ts b/packages/eslint-plugin/tests/rules/padding-line-between-statements.test.ts
new file mode 100644
index 00000000000..d018f189929
--- /dev/null
+++ b/packages/eslint-plugin/tests/rules/padding-line-between-statements.test.ts
@@ -0,0 +1,5060 @@
+/* eslint-disable eslint-comments/no-use */
+// this rule tests new lines which prettier tries to fix, breaking the tests
+/* eslint "@typescript-eslint/internal/plugin-test-formatting": ["error", { formatWithPrettier: false }] */
+/* eslint-enable eslint-comments/no-use */
+
+import rule from '../../src/rules/padding-line-between-statements';
+import { RuleTester } from '../RuleTester';
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+ parser: '@typescript-eslint/parser',
+});
+
+ruleTester.run('padding-line-between-statements', rule, {
+ valid: [
+ // do nothing if no options.
+ "'use strict'; foo(); if (a) { bar(); }",
+
+ // do nothing for single statement.
+ {
+ code: 'foo()',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo()',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ },
+
+ //----------------------------------------------------------------------
+ // wildcard
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo();bar();',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo();\nbar();',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo();\n//comment\nbar();',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo();\n/*comment*/\nbar();',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo();\n\nbar();',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo();\n\n//comment\nbar();',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo();\n//comment\n\nbar();',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ },
+ {
+ code: 'foo();\n//comment\n\n//comment\nbar();',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ },
+ {
+ code: 'if(a){}\n\n;[].map(b)',
+ options: [
+ { blankLine: 'always', prev: 'if', next: '*' },
+ { blankLine: 'never', prev: 'empty', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // block-like
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo();\n\n{ foo() }\n\nfoo();',
+ options: [
+ { blankLine: 'always', prev: '*', next: '*' },
+ { blankLine: 'never', prev: 'block-like', next: 'block-like' },
+ ],
+ },
+ {
+ code: '{ foo() } { foo() }',
+ options: [
+ { blankLine: 'always', prev: '*', next: '*' },
+ { blankLine: 'never', prev: 'block-like', next: 'block-like' },
+ ],
+ },
+ {
+ code: '{ foo() }\n{ foo() }',
+ options: [
+ { blankLine: 'always', prev: '*', next: '*' },
+ { blankLine: 'never', prev: 'block-like', next: 'block-like' },
+ ],
+ },
+ {
+ code: '{ foo() }\n\n{ foo() }',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: 'block-like' },
+ ],
+ },
+ {
+ code: '{ foo() }\n\n//comment\n{ foo() }',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: 'block-like' },
+ ],
+ },
+ {
+ code: 'if(a);\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'do;while(a);\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'do{}while(a);\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'a={}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'let a={}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'foo(function(){})\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+ {
+ code: '(function(){})()\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+ {
+ code: '!function(){}()\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block-like', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // exports
+ //----------------------------------------------------------------------
+
+ {
+ code: 'module.exports=1',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'exports', next: '*' },
+ ],
+ },
+ {
+ code: 'module.exports=1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'exports', next: '*' },
+ ],
+ },
+ {
+ code: 'module.exports.foo=1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'exports', next: '*' },
+ ],
+ },
+ {
+ code: 'exports.foo=1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'exports', next: '*' },
+ ],
+ },
+ {
+ code: 'm.exports=1\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'exports', next: '*' },
+ ],
+ },
+ {
+ code: 'module.foo=1\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'exports', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // require
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo=require("foo")\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'require', next: '*' },
+ ],
+ },
+ {
+ code: 'const foo=a.require("foo")\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'require', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // directive
+ //----------------------------------------------------------------------
+
+ {
+ code: '"use strict"\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: 'function foo(){"use strict"\n\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: '(function foo(){"use strict"\n\nfoo()})',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: '(()=>{"use strict"\n\nfoo()})',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: "'use strict'\n\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: 'foo("use strict")\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: '`use strict`\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: '("use strict")\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: "'use '+'strict'\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: 'foo()\n"use strict"\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+ {
+ code: '{"use strict"\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'directive', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-block-like
+ //----------------------------------------------------------------------
+
+ {
+ code: '{}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'if(a){}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'while(a){}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: '{\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'if(a){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'while(a){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'do{\n}while(a)\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'for(;;){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'for(a in b){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'for(a of b){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'switch(a){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'function foo(a){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'var a=function foo(a){\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // block
+ //----------------------------------------------------------------------
+
+ {
+ code: '{}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block', next: '*' },
+ ],
+ },
+ {
+ code: '{\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block', next: '*' },
+ ],
+ },
+ {
+ code: '{\nfoo()\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block', next: '*' },
+ ],
+ },
+ {
+ code: 'if(a){}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block', next: '*' },
+ ],
+ },
+ {
+ code: 'a={}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'block', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // empty
+ //----------------------------------------------------------------------
+
+ {
+ code: ';\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'empty', next: '*' },
+ ],
+ },
+ {
+ code: '1;\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'empty', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // expression
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo()\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'expression', next: '*' },
+ ],
+ },
+ {
+ code: 'a=b+c\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'expression', next: '*' },
+ ],
+ },
+ {
+ code: 'var a=1\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'expression', next: '*' },
+ ],
+ },
+ {
+ code: "'use strict'\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'expression', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-expression
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo()\n\nfoo(\n\tx,\n\ty\n)',
+ options: [
+ { blankLine: 'always', prev: '*', next: 'multiline-expression' },
+ ],
+ },
+ {
+ code: 'foo()\nfoo()',
+ options: [
+ { blankLine: 'always', prev: '*', next: 'multiline-expression' },
+ ],
+ },
+ {
+ code: '() => {\n\tsomeArray.forEach(x => doSomething(x));\n\treturn theThing;\n}',
+ options: [
+ { blankLine: 'always', prev: 'multiline-expression', next: 'return' },
+ ],
+ },
+ {
+ code: '() => {\n\tsomeArray.forEach(\n\t\tx => doSomething(x)\n\t);\n\n\treturn theThing;\n}',
+ options: [
+ { blankLine: 'always', prev: 'multiline-expression', next: 'return' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // break
+ //----------------------------------------------------------------------
+
+ {
+ code: 'A:{break A\n\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'break', next: '*' },
+ ],
+ },
+ {
+ code: 'while(a){break\n\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'break', next: '*' },
+ ],
+ },
+ {
+ code: 'switch(a){case 0:break\n\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'break', next: '*' },
+ ],
+ },
+ {
+ code: 'switch(a){case 0:break\ncase 1:break}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'break', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // case
+ //----------------------------------------------------------------------
+
+ {
+ code: 'switch(a){case 0:\nfoo()\n\ncase 1:\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'case', next: '*' },
+ ],
+ },
+ {
+ code: 'switch(a){case 0:\nfoo()\n\ndefault:\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'case', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // class
+ //----------------------------------------------------------------------
+
+ {
+ code: 'class A{}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'class', next: '*' },
+ ],
+ },
+ {
+ code: 'var A = class{}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'class', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // const
+ //----------------------------------------------------------------------
+
+ {
+ code: 'const a=1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'const', next: '*' },
+ ],
+ },
+ {
+ code: 'let a=1\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'const', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // type
+ //----------------------------------------------------------------------
+
+ {
+ code: 'type a=number\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'type', next: '*' },
+ ],
+ },
+ {
+ code: 'let a=number\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'type', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // interface
+ //----------------------------------------------------------------------
+
+ {
+ code: 'interface Test{\na:number;\n}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'interface', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // continue
+ //----------------------------------------------------------------------
+
+ {
+ code: 'while(a){continue\n\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'continue', next: '*' },
+ ],
+ },
+ {
+ code: 'while(a){break\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'continue', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // debugger
+ //----------------------------------------------------------------------
+
+ {
+ code: 'debugger\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'debugger', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // default
+ //----------------------------------------------------------------------
+
+ {
+ code: 'switch(a){default:\nfoo()\n\ncase 0:\nfoo()\ncase 1:}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'default', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // do
+ //----------------------------------------------------------------------
+
+ {
+ code: 'do;while(a)\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'do', next: '*' },
+ ],
+ },
+ {
+ code: 'while(a);\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'do', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // export
+ //----------------------------------------------------------------------
+
+ {
+ code: 'export default 1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'export', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'export let a=1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'export', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'var a = 0; export {a}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'export', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'exports.foo=1\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'export', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'module.exports={}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'export', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+
+ //----------------------------------------------------------------------
+ // for
+ //----------------------------------------------------------------------
+
+ {
+ code: 'for(;;);\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'for', next: '*' },
+ ],
+ },
+ {
+ code: 'for(a in b);\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'for', next: '*' },
+ ],
+ },
+ {
+ code: 'for(a of b);\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'for', next: '*' },
+ ],
+ },
+ {
+ code: 'while(a);\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'for', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // function
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function foo(){}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'function', next: '*' },
+ ],
+ },
+ {
+ code: 'var foo=function(){}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'function', next: '*' },
+ ],
+ },
+ {
+ code: 'async function foo(){}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'function', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // if
+ //----------------------------------------------------------------------
+
+ {
+ code: 'if(a);\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'if', next: '*' },
+ ],
+ },
+ {
+ code: 'if(a);else;\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'if', next: '*' },
+ ],
+ },
+ {
+ code: 'if(a);else if(b);else;\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'if', next: '*' },
+ ],
+ },
+ {
+ code: 'for(;;);\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'if', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // iife
+ //----------------------------------------------------------------------
+
+ {
+ code: '(function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ },
+ {
+ code: '+(function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ },
+ {
+ code: '(function(){\n})()\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'iife', next: '*' }],
+ },
+ {
+ code: '+(function(){\n})()\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'iife', next: '*' }],
+ },
+ {
+ code: '(1, 2, 3, function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ },
+
+ //----------------------------------------------------------------------
+ // import
+ //----------------------------------------------------------------------
+
+ {
+ code: "import 'a'\n\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'import', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: "import a from 'a'\n\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'import', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: "import * as a from 'a'\n\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'import', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: "import {a} from 'a'\n\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'import', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: "const a=require('a')\nfoo()",
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'import', next: '*' },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+
+ //----------------------------------------------------------------------
+ // let
+ //----------------------------------------------------------------------
+
+ {
+ code: 'let a=1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'let', next: '*' },
+ ],
+ },
+ {
+ code: 'var a=1\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'let', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // return
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function foo(){return\n\nfoo()}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'return', next: '*' },
+ ],
+ },
+ {
+ code: 'throw a\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'return', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // switch
+ //----------------------------------------------------------------------
+
+ {
+ code: 'switch(a){}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'switch', next: '*' },
+ ],
+ },
+ {
+ code: 'if(a){}\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'switch', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // throw
+ //----------------------------------------------------------------------
+
+ {
+ code: 'throw a\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'throw', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // try
+ //----------------------------------------------------------------------
+
+ {
+ code: 'try{}catch(e){}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'try', next: '*' },
+ ],
+ },
+ {
+ code: 'try{}finally{}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'try', next: '*' },
+ ],
+ },
+ {
+ code: 'try{}catch(e){}finally{}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'try', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // var
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a=1\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'var', next: '*' },
+ ],
+ },
+ {
+ code: 'const a=1\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'var', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // while
+ //----------------------------------------------------------------------
+
+ {
+ code: 'while(a);\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'while', next: '*' },
+ ],
+ },
+ {
+ code: 'do;while(a)\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'while', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // with
+ //----------------------------------------------------------------------
+
+ {
+ code: 'with(a);\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'with', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-const
+ //----------------------------------------------------------------------
+
+ {
+ code: 'const a={\nb:1,\nc:2\n}\n\nconst d=3',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-const', next: '*' },
+ ],
+ },
+ {
+ code: 'const a=1\n\nconst b={\nc:2,\nd:3\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'multiline-const' },
+ ],
+ },
+ {
+ code: 'const a=1\nconst b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-const', next: '*' },
+ ],
+ },
+ {
+ code: 'const a=1\nconst b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'multiline-const' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-let
+ //----------------------------------------------------------------------
+
+ {
+ code: 'let a={\nb:1,\nc:2\n}\n\nlet d=3',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-let', next: '*' },
+ ],
+ },
+ {
+ code: 'let a=1\n\nlet b={\nc:2,\nd:3\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'multiline-let' },
+ ],
+ },
+ {
+ code: 'let a=1\nlet b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-let', next: '*' },
+ ],
+ },
+ {
+ code: 'let a=1\nlet b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'multiline-let' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-var
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a={\nb:1,\nc:2\n}\n\nvar d=3',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-var', next: '*' },
+ ],
+ },
+ {
+ code: 'var a=1\n\nvar b={\nc:2,\nd:3\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'multiline-var' },
+ ],
+ },
+ {
+ code: 'var a=1\nvar b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'multiline-var', next: '*' },
+ ],
+ },
+ {
+ code: 'var a=1\nvar b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'multiline-var' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // single line const
+ //----------------------------------------------------------------------
+
+ {
+ code: 'const a=1\n\nconst b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'singleline-const', next: '*' },
+ ],
+ },
+ {
+ code: 'const a=1\n\nconst b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'singleline-const' },
+ ],
+ },
+ {
+ code: 'const a={\nb:1,\nc:2\n}\nconst d={\ne:3,\nf:4\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'singleline-const', next: '*' },
+ ],
+ },
+ {
+ code: 'const a={\nb:1,\nc:2\n}\nconst d={\ne:3,\nf:4\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'singleline-const' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // single line let
+ //----------------------------------------------------------------------
+
+ {
+ code: 'let a=1\n\nlet b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'singleline-let', next: '*' },
+ ],
+ },
+ {
+ code: 'let a=1\n\nlet b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'singleline-let' },
+ ],
+ },
+ {
+ code: 'let a={\nb:1,\nc:2\n}\nlet d={\ne:3,\nf:4\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'singleline-let', next: '*' },
+ ],
+ },
+ {
+ code: 'let a={\nb:1,\nc:2\n}\nlet d={\ne:3,\nf:4\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'singleline-let' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // single line var
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a=1\n\nvar b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'singleline-var', next: '*' },
+ ],
+ },
+ {
+ code: 'var a=1\n\nvar b=2',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'singleline-var' },
+ ],
+ },
+ {
+ code: 'var a={\nb:1,\nc:2\n}\nvar d={\ne:3,\nf:4\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'singleline-var', next: '*' },
+ ],
+ },
+ {
+ code: 'var a={\nb:1,\nc:2\n}\nvar d={\ne:3,\nf:4\n}',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: '*', next: 'singleline-var' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // Tests from newline-after-var
+ //----------------------------------------------------------------------
+
+ // should skip rule entirely
+ {
+ code: 'console.log(greet);',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'console.log(greet);',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should ignore a `var` with no following token
+ {
+ code: "var greet = 'hello';",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow no line break in "never" mode
+ {
+ code: "var greet = 'hello';console.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow no blank line in "never" mode
+ {
+ code: "var greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow one blank line in "always" mode
+ {
+ code: "var greet = 'hello';\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow two or more blank lines in "always" mode
+ {
+ code: "var greet = 'hello';\n\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n\n\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow trailing whitespace after the `var`
+ {
+ code: "var greet = 'hello'; \n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello'; \nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow inline comments after the `var`
+ {
+ code: "var greet = 'hello'; // inline comment\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello'; // inline comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow a comment on the next line in "never" mode
+ {
+ code: "var greet = 'hello';\n// next-line comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n/* block comment\nblock comment */\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow comments on the next line followed by a blank in "always" mode
+ {
+ code: "var greet = 'hello';\n// next-line comment\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n/* block comment\nblock comment */\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n// next-line comment\n// second-line comment\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow comments on the next line followed by no blank in "never" mode
+ {
+ code: "var greet = 'hello';\n// next-line comment\n// second-line comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n// next-line comment\n/* block comment\nblock comment */\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow another `var` statement to follow without blank line
+ {
+ code: "var greet = 'hello';var name = 'world';console.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\nvar name = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should allow a comment directly between `var` statements
+ {
+ code: "var greet = 'hello';\n// inline comment\nvar name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n/* block comment\nblock comment */\nvar name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n// inline comment\nvar name = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello';\n/* block comment\nblock comment */\nvar name = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle single `var` statement with multiple declarations
+ {
+ code: "var greet = 'hello', name = 'world';console.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello', name = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle single `var` statement with multi-line declaration
+ {
+ code: "var greet = 'hello',\nname = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello',\nname = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello',\nname = 'world';\n// next-line comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var greet = 'hello',\nname = 'world';\n/* block comment\nblock comment */\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle ES6 `let` block binding
+ {
+ code: "let greet = 'hello';\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "let greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle ES6 `const` block binding
+ {
+ code: "const greet = 'hello';\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "const greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle a mix of `var`, `let`, or `const`
+ {
+ code: "let greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "const greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "let greet = 'hello';\nconst name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle a mix of `var` or `let` inside for variations
+ {
+ code: 'for(let a = 1; a < 1; a++){\n break;\n}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'for(var a = 1; a < 1; a++){\n break;\n}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'for(let a = 1; a < 1; a++){\n break;\n}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'for(var a = 1; a < 1; a++){\n break;\n}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'for(let a in obj){\n break;\n}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'for(var a in obj){\n break;\n}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'for(let a in obj){\n break;\n}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'for(var a in obj){\n break;\n}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle export specifiers
+ {
+ code: 'export let a = 1;\nexport let b = 2;',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'export let a = 1;\nexport let b = 2;',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'export var a = 1;\nexport var b = 2;',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'export var a = 1;\nexport var b = 2;',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'export const a = 1;\nexport const b = 2;',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+ {
+ code: 'export const a = 1;\nexport const b = 2;',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ },
+
+ // should allow no blank line at end of block
+ {
+ code: "function example() {\nvar greet = 'hello'\n}",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "function example() {\nvar greet = 'hello'\n}",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "function example() {\nvar greet = 'hello';\nconsole.log(greet);\n}",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var f = function() {\nvar greet = 'hello'\n};",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var f = function() {\nvar greet = 'hello'\n};",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "var f = function() {\nvar greet = 'hello';\nconsole.log(greet);\n};",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "() => {\nvar greet = 'hello';\n}",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "() => {\nvar greet = 'hello';\n}",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: "() => {\nvar greet = 'hello';\nconsole.log(greet);\n}",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: '{\nvar foo;\n}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: '{\nvar foo;\n}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'if(true) {\nvar foo;\n}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'if(true) {\nvar foo;\n}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'switch(a) {\ncase 0:\nvar foo;\n}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'switch(a) {\ncase 0:\nvar foo;\n}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // should handle one/no blank before case.
+ {
+ code: 'switch(a) {\ncase 0:\nvar foo;\n\ncase 1:}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'switch(a) {\ncase 0:\nvar foo;\ncase 1:}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ // https://github.com/eslint/eslint/issues/6834
+ {
+ code: `
+var a = 1
+
+;(b || c).doSomething()
+ `,
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: `
+var a = 1
+;(b || c).doSomething()
+ `,
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: `
+var a = 1
+;
+(b || c).doSomething();
+ `,
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ {
+ code: 'switch(a) {\ncase 0:\nvar foo;\n\ncase 1:}',
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: 'switch(a) {\ncase 0:\nvar foo;\ncase 1:}',
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+ {
+ code: `
+var a = 1
+
+;
+(b || c).doSomething();
+ `,
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // Tests from newline-before-return
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function a() {\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nvar b;\n\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) { return; }\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\nreturn;\n}\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\n\nreturn;\n}\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (!b) {\nreturn;\n} else {\nreturn b;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (!b) {\nreturn;\n} else {\n\nreturn b;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\nreturn b;\n} else if (c) {\nreturn c;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\nreturn b;\n} else if (c) {\nreturn c;\n} else {\nreturn d;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\nreturn b;\n} else if (c) {\nreturn c;\n} else {\nreturn d;\n}\n\nreturn a;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse return d;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\nreturn d;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\n\nreturn d;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nwhile (b) return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n while (b) \nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n while (b) { return; }\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n while (b) {\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n while (b) {\nc();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\ndo return;\nwhile (b);\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\ndo \nreturn;\nwhile (b);\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\ndo { return; } while (b);\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\ndo { return; }\nwhile (b);\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\ndo {\nreturn;\n} while (b);\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\ndo {\nc();\n\nreturn;\n} while (b);\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (var b; b < c; b++) return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (var b; b < c; b++)\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (var b; b < c; b++) {\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (var b; b < c; b++) {\nc();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b in c)\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b in c) { return; }\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b in c) {\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b in c) {\nd();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b of c) return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b of c)\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b of c) {\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nfor (b of c) {\nd();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: "function a() {\nswitch (b) {\ncase 'b': return;\n}\n}",
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: "function a() {\nswitch (b) {\ncase 'b':\nreturn;\n}\n}",
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: "function a() {\nswitch (b) {\ncase 'b': {\nreturn;\n}\n}\n}",
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n//comment\nreturn b;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n{\n//comment\n}\n\nreturn\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nvar b = {\n//comment\n};\n\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {/*multi-line\ncomment*/return b;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n/*comment\ncomment*/\n//comment\nreturn b;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n/*comment\ncomment*/\n//comment\nif (b) return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\n/*comment\ncomment*/\n//comment\nif (b) {\nc();\n\nreturn b;\n} else {\n//comment\nreturn d;\n}\n\n/*multi-line\ncomment*/\nreturn e;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) { //comment\nreturn;\n}\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) { return; } //comment\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'function a() {\nif (b) { return; }\n\n/*multi-line\ncomment*/ return c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ },
+ {
+ code: 'return;',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ parserOptions: { ecmaFeatures: { globalReturn: true } },
+ },
+ {
+ code: 'var a;\n\nreturn;',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ parserOptions: { ecmaFeatures: { globalReturn: true } },
+ },
+ {
+ code: '// comment\nreturn;',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ parserOptions: { ecmaFeatures: { globalReturn: true } },
+ },
+ {
+ code: '/* comment */\nreturn;',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ parserOptions: { ecmaFeatures: { globalReturn: true } },
+ },
+ {
+ code: '/* multi-line\ncomment */\nreturn;',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ parserOptions: { ecmaFeatures: { globalReturn: true } },
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS disallowPaddingNewLinesAfterBlocks
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-after-blocks.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'if(true){}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){}\n',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){}\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){\nif(true) {}\n}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'var a = {\nfoo: function() {\n},\nbar: function() {\n}}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: '(function(){\n})()\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true) {\n}\nelse\n{\n}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true) {\n} else {\n var a = 2; }',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true) {\n}\nelse if(true)\n{\n}\nelse {\n}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'do{\n}\nwhile(true)',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'try{\n}\ncatch(e) {}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'try{\n}\nfinally {}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'try{\n}\ncatch(e) {\n}\nfinally {\n}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: '[].map(function() {})\n.filter(function(){})',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS disallowPaddingNewLinesBeforeExport
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-before-export.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a = 2;\nmodule.exports = a;',
+ options: [{ blankLine: 'never', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'module.exports = 2;',
+ options: [{ blankLine: 'never', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'var a = 2;\n// foo\nmodule.exports = a;',
+ options: [{ blankLine: 'never', prev: '*', next: 'exports' }],
+ },
+
+ /*
+ * TODO: May it need an option to ignore blank lines followed by comments?
+ * {
+ * code: "var a = 2;\n\n// foo\nmodule.exports = a;",
+ * options: [
+ * { blankLine: "never", prev: "*", next: "exports" }
+ * ]
+ * },
+ */
+ {
+ code: 'var a = 2;\n\nfoo.exports = a;',
+ options: [{ blankLine: 'never', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'var a = 2;\n\nmodule.foo = a;',
+ options: [{ blankLine: 'never', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'var a = 2;\n\nfoo = a;',
+ options: [{ blankLine: 'never', prev: '*', next: 'exports' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS requirePaddingNewLinesAfterBlocks
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-after-blocks.js
+ //----------------------------------------------------------------------
+
+ {
+ code: '{}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){}\n',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){}\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){}\n\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true){\nif(true) {}\n}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'var a = {\nfoo: function() {\n},\n\nbar: function() {\n}}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: '(function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true) {\n}\nelse\n{\n}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true) {\n} else {\n var a = 2; }',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'if(true) {\n}\nelse if(true)\n{\n}\nelse {\n}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'do{\n}\nwhile(true)',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'try{\n}\ncatch(e) {}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'try{\n}\nfinally {}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'try{\n}\ncatch(e) {\n}\nfinally {\n}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: '[].map(function() {})\n.filter(function(){})',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'func(\n2,\n3,\nfunction() {\n}\n)',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: '[\n2,\n3,\nfunction() {\n}\n]',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'a(res => {\n})\n.b();',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ },
+ {
+ code: 'var foo = (\n\nfoo\n
\n);',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ parserOptions: { ecmaFeatures: { jsx: true } },
+ },
+ {
+ code: 'var i = 0;\nwhile (i < 100) {\nif(i % 2 === 0) {continue;}\n++i;\n}',
+ options: [
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+ {
+ code: 'var i = 0;\nwhile (i < 100) {\nif(i % 2 === 0) {if(i === 4) {continue;}}\n++i;\n}',
+ options: [
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS requirePaddingNewLinesBeforeExport
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-export.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'module.exports = 2;',
+ options: [{ blankLine: 'always', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'var a = 2;\n\nmodule.exports = a;',
+ options: [{ blankLine: 'always', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'var a = 2;\nfoo.exports = a;',
+ options: [{ blankLine: 'always', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'var a = 2;\nmodule.foo = a;',
+ options: [{ blankLine: 'always', prev: '*', next: 'exports' }],
+ },
+ {
+ code: 'if (true) {\nmodule.exports = a;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'exports' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS requirePaddingNewlinesBeforeKeywords
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-keywords.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function x() { return; }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ },
+ {
+ code: 'if (true) {} else if (false) {}',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ },
+ {
+ code: 'function x() { var a = true; do { a = !a; } while (a); }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ },
+ {
+ code: 'function x() { if (true) return; }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ },
+ {
+ code: 'function test() {};',
+ options: [
+ { blankLine: 'always', prev: 'block-like', next: 'block-like' },
+ ],
+ },
+ ],
+ invalid: [
+ //----------------------------------------------------------------------
+ // wildcard
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo();\n\nfoo();',
+ output: 'foo();\nfoo();',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'foo();\n\n//comment\nfoo();',
+ output: 'foo();\n//comment\nfoo();',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: ' foo();\n \n //comment\n foo();',
+ output: ' foo();\n //comment\n foo();',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'if (a) {}\n\nfor (;;) {}',
+ output: 'if (a) {}\nfor (;;) {}',
+ options: [{ blankLine: 'never', prev: '*', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'foo();\nfoo();',
+ output: 'foo();\n\nfoo();',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: ' function a() {}\n do {} while (a)',
+ output: ' function a() {}\n\n do {} while (a)',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'foo();//trailing-comment\n//comment\n//comment\nfoo();',
+ output: 'foo();//trailing-comment\n\n//comment\n//comment\nfoo();',
+ options: [{ blankLine: 'always', prev: '*', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // block-like
+ //----------------------------------------------------------------------
+
+ {
+ code: '{}\n\nfoo()',
+ output: '{}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '{}\nfoo()',
+ output: '{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){}\nfoo()',
+ output: 'if(a){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){}else{}\nfoo()',
+ output: 'if(a){}else{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){}else if(b){}\nfoo()',
+ output: 'if(a){}else if(b){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){}else if(b){}else{}\nfoo()',
+ output: 'if(a){}else if(b){}else{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){}\nfoo()',
+ output: 'switch(a){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){case 0:}\nfoo()',
+ output: 'switch(a){case 0:}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{}catch(e){}\nfoo()',
+ output: 'try{}catch(e){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{}finally{}\nfoo()',
+ output: 'try{}finally{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{}catch(e){}finally{}\nfoo()',
+ output: 'try{}catch(e){}finally{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'while(a){}\nfoo()',
+ output: 'while(a){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'do{}while(a)\nfoo()',
+ output: 'do{}while(a)\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(;;){}\nfoo()',
+ output: 'for(;;){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(a in b){}\nfoo()',
+ output: 'for(a in b){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(a of b){}\nfoo()',
+ output: 'for(a of b){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'a=function(){}\nfoo()',
+ output: 'a=function(){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'a=()=>{}\nfoo()',
+ output: 'a=()=>{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a(){}\nfoo()',
+ output: 'function a(){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'let a=function(){}\nfoo()',
+ output: 'let a=function(){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // exports
+ //----------------------------------------------------------------------
+
+ {
+ code: 'module.exports=1\n\nfoo()',
+ output: 'module.exports=1\nfoo()',
+ options: [{ blankLine: 'never', prev: 'exports', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'module.exports=1\nfoo()',
+ output: 'module.exports=1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'exports', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'module.exports.foo=1\nfoo()',
+ output: 'module.exports.foo=1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'exports', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'module.exports[foo]=1\nfoo()',
+ output: 'module.exports[foo]=1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'exports', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'exports.foo=1\nfoo()',
+ output: 'exports.foo=1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'exports', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'exports[foo]=1\nfoo()',
+ output: 'exports[foo]=1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'exports', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // require
+ //----------------------------------------------------------------------
+
+ {
+ code: 'const foo=require("foo")\n\nfoo()',
+ output: 'const foo=require("foo")\nfoo()',
+ options: [{ blankLine: 'never', prev: 'require', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'const foo=require("foo")\nfoo()',
+ output: 'const foo=require("foo")\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'require', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'const foo=require("foo").Foo\nfoo()',
+ output: 'const foo=require("foo").Foo\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'require', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'const foo=require("foo")[a]\nfoo()',
+ output: 'const foo=require("foo")[a]\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'require', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // directive
+ //----------------------------------------------------------------------
+
+ {
+ code: '"use strict"\n\nfoo()',
+ output: '"use strict"\nfoo()',
+ options: [{ blankLine: 'never', prev: 'directive', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '"use strict"\nfoo()',
+ output: '"use strict"\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'directive', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "'use strict'\nfoo()",
+ output: "'use strict'\n\nfoo()",
+ options: [{ blankLine: 'always', prev: 'directive', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "'use asm'\nfoo()",
+ output: "'use asm'\n\nfoo()",
+ options: [{ blankLine: 'always', prev: 'directive', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-block-like
+ //----------------------------------------------------------------------
+
+ {
+ code: '{\n}\n\nfoo()',
+ output: '{\n}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '{\n}\nfoo()',
+ output: '{\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){\n}\nfoo()',
+ output: 'if(a){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){\n}else{\n}\nfoo()',
+ output: 'if(a){\n}else{\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){\n}else if(b){\n}\nfoo()',
+ output: 'if(a){\n}else if(b){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a){\n}else if(b){\n}else{\n}\nfoo()',
+ output: 'if(a){\n}else if(b){\n}else{\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){\n}\nfoo()',
+ output: 'switch(a){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{\n}catch(e){\n}\nfoo()',
+ output: 'try{\n}catch(e){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{\n}finally{\n}\nfoo()',
+ output: 'try{\n}finally{\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{\n}catch(e){\n}finally{\n}\nfoo()',
+ output: 'try{\n}catch(e){\n}finally{\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'while(a){\n}\nfoo()',
+ output: 'while(a){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'do{\n}while(a)\nfoo()',
+ output: 'do{\n}while(a)\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(;;){\n}\nfoo()',
+ output: 'for(;;){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(a in b){\n}\nfoo()',
+ output: 'for(a in b){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(a of b){\n}\nfoo()',
+ output: 'for(a of b){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'a=function(){\n}\nfoo()',
+ output: 'a=function(){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'a=()=>{\n}\nfoo()',
+ output: 'a=()=>{\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a(){\n}\nfoo()',
+ output: 'function a(){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'let a=function(){\n}\nfoo()',
+ output: 'let a=function(){\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // block
+ //----------------------------------------------------------------------
+
+ {
+ code: '{}\n\nfoo()',
+ output: '{}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'block', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '{}\nfoo()',
+ output: '{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'block', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // empty
+ //----------------------------------------------------------------------
+
+ {
+ code: ';\n\nfoo()',
+ output: ';\nfoo()',
+ options: [{ blankLine: 'never', prev: 'empty', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: ';\nfoo()',
+ output: ';\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'empty', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // expression
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo()\n\nfoo()',
+ output: 'foo()\nfoo()',
+ options: [{ blankLine: 'never', prev: 'expression', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'foo()\nfoo()',
+ output: 'foo()\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'expression', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-expression
+ //----------------------------------------------------------------------
+
+ {
+ code: 'foo()\n\nfoo(\n\tx,\n\ty\n)',
+ output: 'foo()\nfoo(\n\tx,\n\ty\n)',
+ options: [
+ { blankLine: 'never', prev: '*', next: 'multiline-expression' },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'foo()\nfoo(\n\tx,\n\ty\n)',
+ output: 'foo()\n\nfoo(\n\tx,\n\ty\n)',
+ options: [
+ { blankLine: 'always', prev: '*', next: 'multiline-expression' },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: '() => {\n\tsomeArray.forEach(\n\t\tx => doSomething(x)\n\t);\n\treturn theThing;\n}',
+ output:
+ '() => {\n\tsomeArray.forEach(\n\t\tx => doSomething(x)\n\t);\n\n\treturn theThing;\n}',
+ options: [
+ { blankLine: 'always', prev: 'multiline-expression', next: 'return' },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // break
+ //----------------------------------------------------------------------
+
+ {
+ code: 'while(a){break\n\nfoo()}',
+ output: 'while(a){break\nfoo()}',
+ options: [{ blankLine: 'never', prev: 'break', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){case 0:break\n\nfoo()}',
+ output: 'switch(a){case 0:break\nfoo()}',
+ options: [{ blankLine: 'never', prev: 'break', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'while(a){break\nfoo()}',
+ output: 'while(a){break\n\nfoo()}',
+ options: [{ blankLine: 'always', prev: 'break', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){case 0:break\nfoo()}',
+ output: 'switch(a){case 0:break\n\nfoo()}',
+ options: [{ blankLine: 'always', prev: 'break', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // case
+ //----------------------------------------------------------------------
+
+ {
+ code: 'switch(a){case 0:\nfoo()\n\ndefault:}',
+ output: 'switch(a){case 0:\nfoo()\ndefault:}',
+ options: [{ blankLine: 'never', prev: 'case', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){case 0:\nfoo()\ndefault:}',
+ output: 'switch(a){case 0:\nfoo()\n\ndefault:}',
+ options: [{ blankLine: 'always', prev: 'case', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // class
+ //----------------------------------------------------------------------
+
+ {
+ code: 'class A{}\n\nfoo()',
+ output: 'class A{}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'class', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'class A{}\nfoo()',
+ output: 'class A{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'class', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // const
+ //----------------------------------------------------------------------
+
+ {
+ code: 'const a=1\n\nfoo()',
+ output: 'const a=1\nfoo()',
+ options: [{ blankLine: 'never', prev: 'const', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'const a=1\nfoo()',
+ output: 'const a=1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'const', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // type
+ //----------------------------------------------------------------------
+
+ {
+ code: 'type a=number\n\nfoo()',
+ output: 'type a=number\nfoo()',
+ options: [{ blankLine: 'never', prev: 'type', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'type a=number\nfoo()',
+ output: 'type a=number\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'type', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // interface
+ //----------------------------------------------------------------------
+
+ {
+ code: 'interface Test{\na:number;\n}\nfoo()',
+ output: 'interface Test{\na:number;\n}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'interface', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // continue
+ //----------------------------------------------------------------------
+
+ {
+ code: 'while(a){continue\n\nfoo()}',
+ output: 'while(a){continue\nfoo()}',
+ options: [{ blankLine: 'never', prev: 'continue', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'while(a){continue\nfoo()}',
+ output: 'while(a){continue\n\nfoo()}',
+ options: [{ blankLine: 'always', prev: 'continue', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // debugger
+ //----------------------------------------------------------------------
+
+ {
+ code: 'debugger\n\nfoo()',
+ output: 'debugger\nfoo()',
+ options: [{ blankLine: 'never', prev: 'debugger', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'debugger\nfoo()',
+ output: 'debugger\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'debugger', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // default
+ //----------------------------------------------------------------------
+
+ {
+ code: 'switch(a){default:\nfoo()\n\ncase 0:}',
+ output: 'switch(a){default:\nfoo()\ncase 0:}',
+ options: [{ blankLine: 'never', prev: 'default', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){default:\nfoo()\ncase 0:}',
+ output: 'switch(a){default:\nfoo()\n\ncase 0:}',
+ options: [{ blankLine: 'always', prev: 'default', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // do
+ //----------------------------------------------------------------------
+
+ {
+ code: 'do;while(a)\n\nfoo()',
+ output: 'do;while(a)\nfoo()',
+ options: [{ blankLine: 'never', prev: 'do', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'do;while(a)\nfoo()',
+ output: 'do;while(a)\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'do', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // export
+ //----------------------------------------------------------------------
+
+ {
+ code: 'export default 1\n\nfoo()',
+ output: 'export default 1\nfoo()',
+ options: [{ blankLine: 'never', prev: 'export', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'export let a=1\n\nfoo()',
+ output: 'export let a=1\nfoo()',
+ options: [{ blankLine: 'never', prev: 'export', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'var a = 0;export {a}\n\nfoo()',
+ output: 'var a = 0;export {a}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'export', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'export default 1\nfoo()',
+ output: 'export default 1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'export', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'export let a=1\nfoo()',
+ output: 'export let a=1\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'export', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'var a = 0;export {a}\nfoo()',
+ output: 'var a = 0;export {a}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'export', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // for
+ //----------------------------------------------------------------------
+
+ {
+ code: 'for(;;);\n\nfoo()',
+ output: 'for(;;);\nfoo()',
+ options: [{ blankLine: 'never', prev: 'for', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'for(a in b);\n\nfoo()',
+ output: 'for(a in b);\nfoo()',
+ options: [{ blankLine: 'never', prev: 'for', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'for(a of b);\n\nfoo()',
+ output: 'for(a of b);\nfoo()',
+ options: [{ blankLine: 'never', prev: 'for', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'for(;;);\nfoo()',
+ output: 'for(;;);\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'for', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(a in b);\nfoo()',
+ output: 'for(a in b);\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'for', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'for(a of b);\nfoo()',
+ output: 'for(a of b);\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'for', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // function
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function foo(){}\n\nfoo()',
+ output: 'function foo(){}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'function', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'function foo(){}\nfoo()',
+ output: 'function foo(){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'function', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'async function foo(){}\nfoo()',
+ output: 'async function foo(){}\n\nfoo()',
+ options: [
+ { blankLine: 'never', prev: '*', next: '*' },
+ { blankLine: 'always', prev: 'function', next: '*' },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // if
+ //----------------------------------------------------------------------
+
+ {
+ code: 'if(a);\n\nfoo()',
+ output: 'if(a);\nfoo()',
+ options: [{ blankLine: 'never', prev: 'if', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'if(a);else;\n\nfoo()',
+ output: 'if(a);else;\nfoo()',
+ options: [{ blankLine: 'never', prev: 'if', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'if(a);\nfoo()',
+ output: 'if(a);\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'if', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(a);else;\nfoo()',
+ output: 'if(a);else;\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'if', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // iife
+ //----------------------------------------------------------------------
+
+ {
+ code: '(function(){\n})()\n\nvar a = 2;',
+ output: '(function(){\n})()\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'iife', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '+(function(){\n})()\n\nvar a = 2;',
+ output: '+(function(){\n})()\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'iife', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '(function(){\n})()\nvar a = 2;',
+ output: '(function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: '+(function(){\n})()\nvar a = 2;',
+ output: '+(function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ // Optional chaining
+ {
+ code: '(function(){\n})?.()\nvar a = 2;',
+ output: '(function(){\n})?.()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ parserOptions: { ecmaVersion: 2020 },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'void (function(){\n})?.()\nvar a = 2;',
+ output: 'void (function(){\n})?.()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ parserOptions: { ecmaVersion: 2020 },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ // Sequenced function
+ {
+ code: '(1,2,3,function(){\n})()\nvar a = 2;',
+ output: '(1,2,3,function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'iife', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // import
+ //----------------------------------------------------------------------
+
+ {
+ code: "import a from 'a'\n\nfoo()",
+ output: "import a from 'a'\nfoo()",
+ options: [{ blankLine: 'never', prev: 'import', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "import * as a from 'a'\n\nfoo()",
+ output: "import * as a from 'a'\nfoo()",
+ options: [{ blankLine: 'never', prev: 'import', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "import {a} from 'a'\n\nfoo()",
+ output: "import {a} from 'a'\nfoo()",
+ options: [{ blankLine: 'never', prev: 'import', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "import a from 'a'\nfoo()",
+ output: "import a from 'a'\n\nfoo()",
+ options: [{ blankLine: 'always', prev: 'import', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "import * as a from 'a'\nfoo()",
+ output: "import * as a from 'a'\n\nfoo()",
+ options: [{ blankLine: 'always', prev: 'import', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "import {a} from 'a'\nfoo()",
+ output: "import {a} from 'a'\n\nfoo()",
+ options: [{ blankLine: 'always', prev: 'import', next: '*' }],
+ parserOptions: { ecmaVersion: 6, sourceType: 'module' },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // let
+ //----------------------------------------------------------------------
+
+ {
+ code: 'let a\n\nfoo()',
+ output: 'let a\nfoo()',
+ options: [{ blankLine: 'never', prev: 'let', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'let a\nfoo()',
+ output: 'let a\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'let', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // return
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function foo(){return\n\nfoo()}',
+ output: 'function foo(){return\nfoo()}',
+ options: [{ blankLine: 'never', prev: 'return', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'function foo(){return\nfoo()}',
+ output: 'function foo(){return\n\nfoo()}',
+ options: [{ blankLine: 'always', prev: 'return', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // switch
+ //----------------------------------------------------------------------
+
+ {
+ code: 'switch(a){}\n\nfoo()',
+ output: 'switch(a){}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'switch', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'switch(a){}\nfoo()',
+ output: 'switch(a){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'switch', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // throw
+ //----------------------------------------------------------------------
+
+ {
+ code: 'throw a\n\nfoo()',
+ output: 'throw a\nfoo()',
+ options: [{ blankLine: 'never', prev: 'throw', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'throw a\nfoo()',
+ output: 'throw a\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'throw', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // try
+ //----------------------------------------------------------------------
+
+ {
+ code: 'try{}catch(e){}\n\nfoo()',
+ output: 'try{}catch(e){}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'try', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'try{}finally{}\n\nfoo()',
+ output: 'try{}finally{}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'try', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'try{}catch(e){}finally{}\n\nfoo()',
+ output: 'try{}catch(e){}finally{}\nfoo()',
+ options: [{ blankLine: 'never', prev: 'try', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'try{}catch(e){}\nfoo()',
+ output: 'try{}catch(e){}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'try', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{}finally{}\nfoo()',
+ output: 'try{}finally{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'try', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'try{}catch(e){}finally{}\nfoo()',
+ output: 'try{}catch(e){}finally{}\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'try', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // var
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a\n\nfoo()',
+ output: 'var a\nfoo()',
+ options: [{ blankLine: 'never', prev: 'var', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'var a\nfoo()',
+ output: 'var a\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'var', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // while
+ //----------------------------------------------------------------------
+
+ {
+ code: 'while(a);\n\nfoo()',
+ output: 'while(a);\nfoo()',
+ options: [{ blankLine: 'never', prev: 'while', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'while(a);\nfoo()',
+ output: 'while(a);\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'while', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // with
+ //----------------------------------------------------------------------
+
+ {
+ code: 'with(a);\n\nfoo()',
+ output: 'with(a);\nfoo()',
+ options: [{ blankLine: 'never', prev: 'with', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'with(a);\nfoo()',
+ output: 'with(a);\n\nfoo()',
+ options: [{ blankLine: 'always', prev: 'with', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-const
+ //----------------------------------------------------------------------
+
+ {
+ code: 'const a={\nb:1,\nc:2\n}\n\nconst d=3',
+ output: 'const a={\nb:1,\nc:2\n}\nconst d=3',
+ options: [{ blankLine: 'never', prev: 'multiline-const', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'const a={\nb:1,\nc:2\n}\nconst d=3',
+ output: 'const a={\nb:1,\nc:2\n}\n\nconst d=3',
+ options: [{ blankLine: 'always', prev: 'multiline-const', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'const a=1\n\nconst b={\nc:2,\nd:3\n}',
+ output: 'const a=1\nconst b={\nc:2,\nd:3\n}',
+ options: [{ blankLine: 'never', prev: '*', next: 'multiline-const' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'const a=1\nconst b={\nc:2,\nd:3\n}',
+ output: 'const a=1\n\nconst b={\nc:2,\nd:3\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'multiline-const' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-let
+ //----------------------------------------------------------------------
+
+ {
+ code: 'let a={\nb:1,\nc:2\n}\n\nlet d=3',
+ output: 'let a={\nb:1,\nc:2\n}\nlet d=3',
+ options: [{ blankLine: 'never', prev: 'multiline-let', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'let a={\nb:1,\nc:2\n}\nlet d=3',
+ output: 'let a={\nb:1,\nc:2\n}\n\nlet d=3',
+ options: [{ blankLine: 'always', prev: 'multiline-let', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'let a=1\n\nlet b={\nc:2,\nd:3\n}',
+ output: 'let a=1\nlet b={\nc:2,\nd:3\n}',
+ options: [{ blankLine: 'never', prev: '*', next: 'multiline-let' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'let a=1\nlet b={\nc:2,\nd:3\n}',
+ output: 'let a=1\n\nlet b={\nc:2,\nd:3\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'multiline-let' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // multiline-var
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a={\nb:1,\nc:2\n}\n\nvar d=3',
+ output: 'var a={\nb:1,\nc:2\n}\nvar d=3',
+ options: [{ blankLine: 'never', prev: 'multiline-var', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'var a={\nb:1,\nc:2\n}\nvar d=3',
+ output: 'var a={\nb:1,\nc:2\n}\n\nvar d=3',
+ options: [{ blankLine: 'always', prev: 'multiline-var', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'var a=1\n\nvar b={\nc:2,\nd:3\n}',
+ output: 'var a=1\nvar b={\nc:2,\nd:3\n}',
+ options: [{ blankLine: 'never', prev: '*', next: 'multiline-var' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'var a=1\nvar b={\nc:2,\nd:3\n}',
+ output: 'var a=1\n\nvar b={\nc:2,\nd:3\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'multiline-var' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // single line const
+ //----------------------------------------------------------------------
+
+ {
+ code: 'const a=1\n\nconst b=2',
+ output: 'const a=1\nconst b=2',
+ options: [{ blankLine: 'never', prev: 'singleline-const', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'const a=1\nconst b=2',
+ output: 'const a=1\n\nconst b=2',
+ options: [{ blankLine: 'always', prev: 'singleline-const', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'const a=1\n\nconst b=2',
+ output: 'const a=1\nconst b=2',
+ options: [{ blankLine: 'never', prev: '*', next: 'singleline-const' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'const a=1\nconst b=2',
+ output: 'const a=1\n\nconst b=2',
+ options: [{ blankLine: 'always', prev: '*', next: 'singleline-const' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // single line let
+ //----------------------------------------------------------------------
+
+ {
+ code: 'let a=1\n\nlet b=2',
+ output: 'let a=1\nlet b=2',
+ options: [{ blankLine: 'never', prev: 'singleline-let', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'let a=1\nlet b=2',
+ output: 'let a=1\n\nlet b=2',
+ options: [{ blankLine: 'always', prev: 'singleline-let', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'let a=1\n\nlet b=2',
+ output: 'let a=1\nlet b=2',
+ options: [{ blankLine: 'never', prev: '*', next: 'singleline-let' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'let a=1\nlet b=2',
+ output: 'let a=1\n\nlet b=2',
+ options: [{ blankLine: 'always', prev: '*', next: 'singleline-let' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // single line var
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a=1\n\nvar b=2',
+ output: 'var a=1\nvar b=2',
+ options: [{ blankLine: 'never', prev: 'singleline-var', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'var a=1\nvar b=2',
+ output: 'var a=1\n\nvar b=2',
+ options: [{ blankLine: 'always', prev: 'singleline-var', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'var a=1\n\nvar b=2',
+ output: 'var a=1\nvar b=2',
+ options: [{ blankLine: 'never', prev: '*', next: 'singleline-var' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'var a=1\nvar b=2',
+ output: 'var a=1\n\nvar b=2',
+ options: [{ blankLine: 'always', prev: '*', next: 'singleline-var' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // Tests from newline-after-var
+ //----------------------------------------------------------------------
+
+ // should disallow no line break in "always" mode
+ {
+ code: "var greet = 'hello';console.log(greet);",
+ output: "var greet = 'hello';\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';var name = 'world';console.log(greet, name);",
+ output:
+ "var greet = 'hello';var name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello', name = 'world';console.log(greet, name);",
+ output:
+ "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ // should disallow no blank line in "always" mode
+ {
+ code: "var greet = 'hello';\nconsole.log(greet);",
+ output: "var greet = 'hello';\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello'; \nconsole.log(greet);",
+ output: "var greet = 'hello';\n \nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello'; // inline comment\nconsole.log(greet);",
+ output: "var greet = 'hello'; // inline comment\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';\nvar name = 'world';\nconsole.log(greet, name);",
+ output:
+ "var greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello', name = 'world';\nconsole.log(greet, name);",
+ output:
+ "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello',\nname = 'world';\nconsole.log(greet, name);",
+ output:
+ "var greet = 'hello',\nname = 'world';\n\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "let greet = 'hello';\nconsole.log(greet);",
+ output: "let greet = 'hello';\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "const greet = 'hello';\nconsole.log(greet);",
+ output: "const greet = 'hello';\n\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "function example() {\nvar greet = 'hello';\nconsole.log(greet);\n}",
+ output:
+ "function example() {\nvar greet = 'hello';\n\nconsole.log(greet);\n}",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var f = function() {\nvar greet = 'hello';\nconsole.log(greet);\n};",
+ output:
+ "var f = function() {\nvar greet = 'hello';\n\nconsole.log(greet);\n};",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "() => {\nvar greet = 'hello';\nconsole.log(greet);\n}",
+ output: "() => {\nvar greet = 'hello';\n\nconsole.log(greet);\n}",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ // should disallow blank lines in "never" mode
+ {
+ code: "var greet = 'hello';\n\nconsole.log(greet);",
+ output: "var greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';\n\n\nconsole.log(greet);",
+ output: "var greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';\n\n\n\nconsole.log(greet);",
+ output: "var greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello'; \n\nconsole.log(greet);",
+ output: "var greet = 'hello'; \nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello'; // inline comment\n\nconsole.log(greet);",
+ output: "var greet = 'hello'; // inline comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';\nvar name = 'world';\n\nconsole.log(greet, name);",
+ output:
+ "var greet = 'hello';\nvar name = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello', name = 'world';\n\nconsole.log(greet, name);",
+ output: "var greet = 'hello', name = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello',\nname = 'world';\n\nconsole.log(greet, name);",
+ output:
+ "var greet = 'hello',\nname = 'world';\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\n\nconsole.log(greet, name);",
+ output:
+ "var greet = 'hello', // inline comment\nname = 'world'; // inline comment\nconsole.log(greet, name);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "let greet = 'hello';\n\nconsole.log(greet);",
+ output: "let greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: "const greet = 'hello';\n\nconsole.log(greet);",
+ output: "const greet = 'hello';\nconsole.log(greet);",
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+
+ // should disallow a comment on the next line that's not in turn followed by a blank in "always" mode
+ {
+ code: "var greet = 'hello';\n// next-line comment\nconsole.log(greet);",
+ output:
+ "var greet = 'hello';\n\n// next-line comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';\n/* block comment\nblock comment */\nconsole.log(greet);",
+ output:
+ "var greet = 'hello';\n\n/* block comment\nblock comment */\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello',\nname = 'world';\n// next-line comment\nconsole.log(greet);",
+ output:
+ "var greet = 'hello',\nname = 'world';\n\n// next-line comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello',\nname = 'world';\n/* block comment\nblock comment */\nconsole.log(greet);",
+ output:
+ "var greet = 'hello',\nname = 'world';\n\n/* block comment\nblock comment */\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';\n// next-line comment\n// second-line comment\nconsole.log(greet);",
+ output:
+ "var greet = 'hello';\n\n// next-line comment\n// second-line comment\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: "var greet = 'hello';\n// next-line comment\n/* block comment\nblock comment */\nconsole.log(greet);",
+ output:
+ "var greet = 'hello';\n\n// next-line comment\n/* block comment\nblock comment */\nconsole.log(greet);",
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ // https://github.com/eslint/eslint/issues/6834
+ {
+ code: `
+var a = 1
+;(b || c).doSomething()
+ `,
+ output: `
+var a = 1
+
+;(b || c).doSomething()
+ `,
+ options: [
+ { blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: `
+var a = 1
+
+;(b || c).doSomething()
+ `,
+ output: `
+var a = 1
+;(b || c).doSomething()
+ `,
+ options: [
+ { blankLine: 'never', prev: ['const', 'let', 'var'], next: '*' },
+ {
+ blankLine: 'any',
+ prev: ['const', 'let', 'var'],
+ next: ['const', 'let', 'var'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // Tests from newline-before-return
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function a() {\nvar b; return;\n}',
+ output: 'function a() {\nvar b;\n\n return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b;\nreturn;\n}',
+ output: 'function a() {\nvar b;\n\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\nreturn d;\n}\n}',
+ output:
+ 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\n\nreturn d;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne(); return d;\n}\n}',
+ output:
+ 'function a() {\nif (b) return b;\nelse if (c) return c;\nelse {\ne();\n\n return d;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\n while (b) {\nc();\nreturn;\n}\n}',
+ output: 'function a() {\n while (b) {\nc();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\ndo {\nc();\nreturn;\n} while (b);\n}',
+ output: 'function a() {\ndo {\nc();\n\nreturn;\n} while (b);\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nfor (var b; b < c; b++) {\nc();\nreturn;\n}\n}',
+ output:
+ 'function a() {\nfor (var b; b < c; b++) {\nc();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nfor (b in c) {\nd();\nreturn;\n}\n}',
+ output: 'function a() {\nfor (b in c) {\nd();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nfor (b of c) {\nd();\nreturn;\n}\n}',
+ output: 'function a() {\nfor (b of c) {\nd();\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nif (b) {\nc();\n}\n//comment\nreturn b;\n}',
+ output: 'function a() {\nif (b) {\nc();\n}\n\n//comment\nreturn b;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\n/*comment\ncomment*/\nif (b) {\nc();\nreturn b;\n} else {\n//comment\n\nreturn d;\n}\n/*multi-line\ncomment*/\nreturn e;\n}',
+ output:
+ 'function a() {\n/*comment\ncomment*/\nif (b) {\nc();\n\nreturn b;\n} else {\n//comment\n\nreturn d;\n}\n\n/*multi-line\ncomment*/\nreturn e;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ ],
+ },
+ {
+ code: 'function a() {\nif (b) { return; } //comment\nreturn c;\n}',
+ output: 'function a() {\nif (b) { return; } //comment\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\nreturn c;\n}',
+ output:
+ 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nif (b) { return; }\n/*multi-line\ncomment*/ return c;\n}',
+ output:
+ 'function a() {\nif (b) { return; }\n\n/*multi-line\ncomment*/ return c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nif (b) { return; } /*multi-line\ncomment*/ return c;\n}',
+ output:
+ 'function a() {\nif (b) { return; } /*multi-line\ncomment*/\n\n return c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'var a;\nreturn;',
+ output: 'var a;\n\nreturn;',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ parserOptions: { ecmaFeatures: { globalReturn: true } },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'var a; return;',
+ output: 'var a;\n\n return;',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ parserOptions: { ecmaFeatures: { globalReturn: true } },
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\n{\n//comment\n}\nreturn\n}',
+ output: 'function a() {\n{\n//comment\n}\n\nreturn\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\n{\n//comment\n} return\n}',
+ output: 'function a() {\n{\n//comment\n}\n\n return\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\nreturn c;\n}',
+ output:
+ 'function a() {\nvar c;\nwhile (b) {\n c = d; //comment\n}\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\nreturn;\n}\n}',
+ output:
+ 'function a() {\nfor (var b; b < c; b++) {\nif (d) {\nbreak; //comment\n}\n\nreturn;\n}\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b; /*multi-line\ncomment*/\nreturn c;\n}',
+ output: 'function a() {\nvar b; /*multi-line\ncomment*/\n\nreturn c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b;\n/*multi-line\ncomment*/ return c;\n}',
+ output: 'function a() {\nvar b;\n\n/*multi-line\ncomment*/ return c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b; /*multi-line\ncomment*/ return c;\n}',
+ output: 'function a() {\nvar b; /*multi-line\ncomment*/\n\n return c;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b;\n//comment\nreturn;\n}',
+ output: 'function a() {\nvar b;\n\n//comment\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b; //comment\nreturn;\n}',
+ output: 'function a() {\nvar b; //comment\n\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b;\n/* comment */ return;\n}',
+ output: 'function a() {\nvar b;\n\n/* comment */ return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b;\n//comment\n/* comment */ return;\n}',
+ output: 'function a() {\nvar b;\n\n//comment\n/* comment */ return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b; /* comment */ return;\n}',
+ output: 'function a() {\nvar b; /* comment */\n\n return;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b; /* comment */\nreturn;\n}',
+ output: 'function a() {\nvar b; /* comment */\n\nreturn;\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b;\nreturn; //comment\n}',
+ output: 'function a() {\nvar b;\n\nreturn; //comment\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function a() {\nvar b; return; //comment\n}',
+ output: 'function a() {\nvar b;\n\n return; //comment\n}',
+ options: [{ blankLine: 'always', prev: '*', next: 'return' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS disallowPaddingNewLinesAfterBlocks
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-after-blocks.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'if(true){}\n\nvar a = 2;',
+ output: 'if(true){}\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'if(true){\nif(true) {}\n\nvar a = 2;}',
+ output: 'if(true){\nif(true) {}\nvar a = 2;}',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '(function(){\n})()\n\nvar a = 2;',
+ output: '(function(){\n})()\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: '+(function(){\n})()\n\nvar a = 2;',
+ output: '+(function(){\n})()\nvar a = 2;',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'var a = function() {};\n\nvar b = 2;',
+ output: 'var a = function() {};\nvar b = 2;',
+ options: [{ blankLine: 'never', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS disallowPaddingNewLinesBeforeExport
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-before-export.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a = 2;\n\nmodule.exports = a;',
+ output: 'var a = 2;\nmodule.exports = a;',
+ options: [{ blankLine: 'never', prev: '*', next: 'exports' }],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS disallowPaddingNewLinesBeforeExport
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/disallow-padding-newlines-before-keywords.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function x() { var a;\n\nreturn; }',
+ output: 'function x() { var a;\nreturn; }',
+ options: [
+ {
+ blankLine: 'never',
+ prev: '*',
+ next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'function x() { var a = true;\n\nif (a) { a = !a; }; }',
+ output: 'function x() { var a = true;\nif (a) { a = !a; }; }',
+ options: [
+ {
+ blankLine: 'never',
+ prev: '*',
+ next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'function x() { var a = true;\n\nfor (var i = 0; i < 10; i++) { a = !a; }; }',
+ output:
+ 'function x() { var a = true;\nfor (var i = 0; i < 10; i++) { a = !a; }; }',
+ options: [
+ {
+ blankLine: 'never',
+ prev: '*',
+ next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'],
+ },
+ ],
+ errors: [{ messageId: 'unexpectedBlankLine' }],
+ },
+ {
+ code: 'function x() { var y = true;\n\nswitch ("Oranges") { case "Oranges": y = !y;\n\nbreak;\n\ncase "Apples": y = !y;\n\nbreak; default: y = !y; } }',
+ output:
+ 'function x() { var y = true;\nswitch ("Oranges") { case "Oranges": y = !y;\nbreak;\ncase "Apples": y = !y;\nbreak; default: y = !y; } }',
+ options: [
+ {
+ blankLine: 'never',
+ prev: '*',
+ next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'],
+ },
+ ],
+ errors: [
+ { messageId: 'unexpectedBlankLine' },
+ { messageId: 'unexpectedBlankLine' },
+ { messageId: 'unexpectedBlankLine' },
+ { messageId: 'unexpectedBlankLine' },
+ ],
+ },
+ {
+ code: 'function x() {try { var a;\n\nthrow 0; } catch (e) { var b = 0;\n\nthrow e; } }',
+ output:
+ 'function x() {try { var a;\nthrow 0; } catch (e) { var b = 0;\nthrow e; } }',
+ options: [
+ {
+ blankLine: 'never',
+ prev: '*',
+ next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'],
+ },
+ ],
+ errors: [
+ { messageId: 'unexpectedBlankLine' },
+ { messageId: 'unexpectedBlankLine' },
+ ],
+ },
+ {
+ code: 'function x(a) { var b = 0;\n\nif (!a) { return false; };\n\nfor (var i = 0; i < b; i++) { if (!a[i]) return false; }\n\nreturn true; }',
+ output:
+ 'function x(a) { var b = 0;\nif (!a) { return false; };\nfor (var i = 0; i < b; i++) { if (!a[i]) return false; }\nreturn true; }',
+ options: [
+ {
+ blankLine: 'never',
+ prev: '*',
+ next: ['if', 'for', 'return', 'switch', 'case', 'break', 'throw'],
+ },
+ ],
+ errors: [
+ { messageId: 'unexpectedBlankLine' },
+ { messageId: 'unexpectedBlankLine' },
+ { messageId: 'unexpectedBlankLine' },
+ ],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS requirePaddingNewLinesAfterBlocks
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-after-blocks.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'if(true){}\nvar a = 2;',
+ output: 'if(true){}\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'var a = function() {\n};\nvar b = 2;',
+ output: 'var a = function() {\n};\n\nvar b = 2;',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'if(true){\nif(true) {}\nvar a = 2;}',
+ output: 'if(true){\nif(true) {}\n\nvar a = 2;}',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: '(function(){\n})()\nvar a = 2;',
+ output: '(function(){\n})()\n\nvar a = 2;',
+ options: [{ blankLine: 'always', prev: 'block-like', next: '*' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'var a = function() {\n};\nvar b = 2;',
+ output: 'var a = function() {\n};\n\nvar b = 2;',
+ options: [
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: '(function(){\n})()\nvar a = 2;',
+ output: '(function(){\n})()\n\nvar a = 2;',
+ options: [
+ { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS requirePaddingNewLinesBeforeExport
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-export.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'var a = 2;\nmodule.exports = a;',
+ output: 'var a = 2;\n\nmodule.exports = a;',
+ options: [{ blankLine: 'always', prev: '*', next: 'exports' }],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+
+ //----------------------------------------------------------------------
+ // From JSCS requirePaddingNewlinesBeforeKeywords
+ // https://github.com/jscs-dev/node-jscs/blob/44f9b86eb0757fd4ca05a81a50450c5f1b25c37b/test/specs/rules/require-padding-newlines-before-keywords.js
+ //----------------------------------------------------------------------
+
+ {
+ code: 'function x() { var a; return; }',
+ output: 'function x() { var a;\n\n return; }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function x() { var a = true; for (var i = 0; i < 10; i++) { a = !a; }; }',
+ output:
+ 'function x() { var a = true;\n\n for (var i = 0; i < 10; i++) { a = !a; }; }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function x() { var y = true; switch ("Oranges") { case "Oranges": y = !y; break; case "Apples": y = !y; break; default: y = !y; } }',
+ output:
+ 'function x() { var y = true;\n\n switch ("Oranges") { case "Oranges": y = !y;\n\n break;\n\n case "Apples": y = !y;\n\n break;\n\n default: y = !y; } }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ errors: [
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ ],
+ },
+ {
+ code: 'function x() { var a = true; while (!a) { a = !a; }; }',
+ output: 'function x() { var a = true;\n\n while (!a) { a = !a; }; }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ errors: [{ messageId: 'expectedBlankLine' }],
+ },
+ {
+ code: 'function x() {try { var a; throw 0; } catch (e) { var b = 0; throw e; } }',
+ output:
+ 'function x() {try { var a;\n\n throw 0; } catch (e) { var b = 0;\n\n throw e; } }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ errors: [
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ ],
+ },
+ {
+ code: 'function x(a) { var b = 0; if (!a) { return false; }; for (var i = 0; i < b; i++) { if (!a[i]) return false; } return true; }',
+ output:
+ 'function x(a) { var b = 0;\n\n if (!a) { return false; };\n\n for (var i = 0; i < b; i++) { if (!a[i]) return false; }\n\n return true; }',
+ options: [
+ {
+ blankLine: 'always',
+ prev: '*',
+ next: [
+ 'if',
+ 'for',
+ 'return',
+ 'switch',
+ 'case',
+ 'break',
+ 'throw',
+ 'while',
+ 'default',
+ ],
+ },
+ ],
+ errors: [
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ { messageId: 'expectedBlankLine' },
+ ],
+ },
+ ],
+});