diff --git a/docs/rules/max-lines-per-block.md b/docs/rules/max-lines-per-block.md new file mode 100644 index 000000000..02fd2be41 --- /dev/null +++ b/docs/rules/max-lines-per-block.md @@ -0,0 +1,54 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/max-lines-per-block +description: enforce maximum number of lines in Vue SFC blocks +--- +# vue/max-lines-per-block + +> enforce maximum number of lines in Vue SFC blocks + +- :exclamation: ***This rule has not been released yet.*** + +## :book: Rule Details + +This rule enforces a maximum number of lines per block, in order to aid in maintainability and reduce complexity. + +## :wrench: Options + +This rule takes an object, where you can specify the maximum number of lines in each type of SFC block and customize the line counting behavior. +The following properties can be specified for the object. + +- `script` ... Specify the maximum number of lines in ` +``` + + diff --git a/lib/rules/max-lines-per-block.js b/lib/rules/max-lines-per-block.js new file mode 100644 index 000000000..bcb82d563 --- /dev/null +++ b/lib/rules/max-lines-per-block.js @@ -0,0 +1,110 @@ +/** + * @author lsdsjy + * @fileoverview Rule for checking the maximum number of lines in Vue SFC blocks. + */ +'use strict' + +const { SourceCode } = require('eslint') +const utils = require('../utils') + +/** + * @param {string} text + */ +function isEmptyLine(text) { + return !text.trim() +} + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'enforce maximum number of lines in Vue SFC blocks', + categories: undefined, + url: 'https://eslint.vuejs.org/rules/max-lines-per-block.html' + }, + fixable: null, + schema: [ + { + type: 'object', + properties: { + style: { + type: 'integer', + minimum: 1 + }, + template: { + type: 'integer', + minimum: 1 + }, + script: { + type: 'integer', + minimum: 1 + }, + skipBlankLines: { + type: 'boolean', + minimum: 0 + } + }, + additionalProperties: false + } + ], + messages: { + tooManyLines: + 'Block has too many lines ({{lineCount}}). Maximum allowed is {{limit}}.' + } + }, + /** @param {RuleContext} context */ + create(context) { + const option = context.options[0] || {} + /** + * @type {Record} + */ + const limits = { + template: option.template, + script: option.script, + style: option.style + } + + const code = context.getSourceCode() + const documentFragment = + context.parserServices.getDocumentFragment && + context.parserServices.getDocumentFragment() + + function getTopLevelHTMLElements() { + if (documentFragment) { + return documentFragment.children.filter(utils.isVElement) + } + return [] + } + + return { + /** @param {Program} node */ + Program(node) { + if (utils.hasInvalidEOF(node)) { + return + } + for (const block of getTopLevelHTMLElements()) { + if (limits[block.name]) { + // We suppose the start tag and end tag occupy one single line respectively + let lineCount = block.loc.end.line - block.loc.start.line - 1 + + if (option.skipBlankLines) { + const lines = SourceCode.splitLines(code.getText(block)) + lineCount -= lines.filter(isEmptyLine).length + } + + if (lineCount > limits[block.name]) { + context.report({ + node: block, + messageId: 'tooManyLines', + data: { + limit: limits[block.name], + lineCount + } + }) + } + } + } + } + } + } +} diff --git a/tests/lib/rules/max-lines-per-block.js b/tests/lib/rules/max-lines-per-block.js new file mode 100644 index 000000000..01d868e62 --- /dev/null +++ b/tests/lib/rules/max-lines-per-block.js @@ -0,0 +1,84 @@ +/** + * @author lsdsjy + */ +'use strict' + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/max-lines-per-block') + +const tester = new RuleTester({ + parser: require.resolve('vue-eslint-parser'), + parserOptions: { + ecmaVersion: 2020, + sourceType: 'module' + } +}) + +tester.run('max-lines-per-block', rule, { + valid: [ + { + code: ` + + + `, + options: [{ template: 1 }] + }, + { + code: ` + + `, + options: [{ template: 1, skipBlankLines: true }] + }, + { + code: ` + + `, + options: [{ script: 1, style: 1 }] + } + ], + invalid: [ + { + code: ` + + `, + options: [{ template: 1 }], + errors: [ + { + message: 'Block has too many lines (2). Maximum allowed is 1.', + line: 2, + column: 7 + } + ] + }, + { + code: ` + + `, + options: [{ script: 1, skipBlankLines: true }], + errors: [ + { + message: 'Block has too many lines (2). Maximum allowed is 1.', + line: 2, + column: 7 + } + ] + } + ] +})