You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
6.0 KiB
215 lines
6.0 KiB
/** |
|
* @author Yosuke ota |
|
* See LICENSE file in root directory for full license. |
|
*/ |
|
'use strict' |
|
|
|
// ----------------------------------------------------------------------------- |
|
// Requirements |
|
// ----------------------------------------------------------------------------- |
|
|
|
const htmlComments = require('../utils/html-comments') |
|
|
|
/** |
|
* @typedef { import('../utils/html-comments').ParsedHTMLComment } ParsedHTMLComment |
|
*/ |
|
|
|
// ------------------------------------------------------------------------------ |
|
// Helpers |
|
// ------------------------------------------------------------------------------ |
|
|
|
/** |
|
* @param {any} param |
|
*/ |
|
function parseOption(param) { |
|
if (param && typeof param === 'string') { |
|
return { |
|
singleline: param, |
|
multiline: param |
|
} |
|
} |
|
return Object.assign( |
|
{ |
|
singleline: 'never', |
|
multiline: 'always' |
|
}, |
|
param |
|
) |
|
} |
|
|
|
// ------------------------------------------------------------------------------ |
|
// Rule Definition |
|
// ------------------------------------------------------------------------------ |
|
|
|
module.exports = { |
|
meta: { |
|
type: 'layout', |
|
|
|
docs: { |
|
description: 'enforce unified line brake in HTML comments', |
|
categories: undefined, |
|
url: 'https://eslint.vuejs.org/rules/html-comment-content-newline.html' |
|
}, |
|
fixable: 'whitespace', |
|
schema: [ |
|
{ |
|
anyOf: [ |
|
{ |
|
enum: ['always', 'never'] |
|
}, |
|
{ |
|
type: 'object', |
|
properties: { |
|
singleline: { enum: ['always', 'never', 'ignore'] }, |
|
multiline: { enum: ['always', 'never', 'ignore'] } |
|
}, |
|
additionalProperties: false |
|
} |
|
] |
|
}, |
|
{ |
|
type: 'object', |
|
properties: { |
|
exceptions: { |
|
type: 'array', |
|
items: { |
|
type: 'string' |
|
} |
|
} |
|
}, |
|
additionalProperties: false |
|
} |
|
], |
|
messages: { |
|
expectedAfterHTMLCommentOpen: "Expected line break after '<!--'.", |
|
expectedBeforeHTMLCommentOpen: "Expected line break before '-->'.", |
|
expectedAfterExceptionBlock: 'Expected line break after exception block.', |
|
expectedBeforeExceptionBlock: |
|
'Expected line break before exception block.', |
|
unexpectedAfterHTMLCommentOpen: "Unexpected line breaks after '<!--'.", |
|
unexpectedBeforeHTMLCommentOpen: "Unexpected line breaks before '-->'." |
|
} |
|
}, |
|
/** @param {RuleContext} context */ |
|
create(context) { |
|
const option = parseOption(context.options[0]) |
|
return htmlComments.defineVisitor( |
|
context, |
|
context.options[1], |
|
(comment) => { |
|
const { value, openDecoration, closeDecoration } = comment |
|
if (!value) { |
|
return |
|
} |
|
|
|
const startLine = openDecoration |
|
? openDecoration.loc.end.line |
|
: value.loc.start.line |
|
const endLine = closeDecoration |
|
? closeDecoration.loc.start.line |
|
: value.loc.end.line |
|
const newlineType = |
|
startLine === endLine ? option.singleline : option.multiline |
|
if (newlineType === 'ignore') { |
|
return |
|
} |
|
checkCommentOpen(comment, newlineType !== 'never') |
|
checkCommentClose(comment, newlineType !== 'never') |
|
} |
|
) |
|
|
|
/** |
|
* Reports the newline before the contents of a given comment if it's invalid. |
|
* @param {ParsedHTMLComment} comment - comment data. |
|
* @param {boolean} requireNewline - `true` if line breaks are required. |
|
* @returns {void} |
|
*/ |
|
function checkCommentOpen(comment, requireNewline) { |
|
const { value, openDecoration, open } = comment |
|
if (!value) { |
|
return |
|
} |
|
const beforeToken = openDecoration || open |
|
|
|
if (requireNewline) { |
|
if (beforeToken.loc.end.line < value.loc.start.line) { |
|
// Is valid |
|
return |
|
} |
|
context.report({ |
|
loc: { |
|
start: beforeToken.loc.end, |
|
end: value.loc.start |
|
}, |
|
messageId: openDecoration |
|
? 'expectedAfterExceptionBlock' |
|
: 'expectedAfterHTMLCommentOpen', |
|
fix: openDecoration |
|
? undefined |
|
: (fixer) => fixer.insertTextAfter(beforeToken, '\n') |
|
}) |
|
} else { |
|
if (beforeToken.loc.end.line === value.loc.start.line) { |
|
// Is valid |
|
return |
|
} |
|
context.report({ |
|
loc: { |
|
start: beforeToken.loc.end, |
|
end: value.loc.start |
|
}, |
|
messageId: 'unexpectedAfterHTMLCommentOpen', |
|
fix: (fixer) => |
|
fixer.replaceTextRange([beforeToken.range[1], value.range[0]], ' ') |
|
}) |
|
} |
|
} |
|
|
|
/** |
|
* Reports the space after the contents of a given comment if it's invalid. |
|
* @param {ParsedHTMLComment} comment - comment data. |
|
* @param {boolean} requireNewline - `true` if line breaks are required. |
|
* @returns {void} |
|
*/ |
|
function checkCommentClose(comment, requireNewline) { |
|
const { value, closeDecoration, close } = comment |
|
if (!value) { |
|
return |
|
} |
|
const afterToken = closeDecoration || close |
|
|
|
if (requireNewline) { |
|
if (value.loc.end.line < afterToken.loc.start.line) { |
|
// Is valid |
|
return |
|
} |
|
context.report({ |
|
loc: { |
|
start: value.loc.end, |
|
end: afterToken.loc.start |
|
}, |
|
messageId: closeDecoration |
|
? 'expectedBeforeExceptionBlock' |
|
: 'expectedBeforeHTMLCommentOpen', |
|
fix: closeDecoration |
|
? undefined |
|
: (fixer) => fixer.insertTextBefore(afterToken, '\n') |
|
}) |
|
} else { |
|
if (value.loc.end.line === afterToken.loc.start.line) { |
|
// Is valid |
|
return |
|
} |
|
context.report({ |
|
loc: { |
|
start: value.loc.end, |
|
end: afterToken.loc.start |
|
}, |
|
messageId: 'unexpectedBeforeHTMLCommentOpen', |
|
fix: (fixer) => |
|
fixer.replaceTextRange([value.range[1], afterToken.range[0]], ' ') |
|
}) |
|
} |
|
} |
|
} |
|
}
|
|
|