ember-template-lint
Version:
Linter for Ember or Handlebars templates.
134 lines (112 loc) • 3.28 kB
JavaScript
/*
Enforce consistent linebreaks
The following values are valid configuration:
* boolean -- `true` for enabled (same as `unix`) / `false` for disabled
* string -- `unix` for LF linebreaks / `windows` for CRLF linebreaks
*/
const os = require('os');
const createErrorMessage = require('../helpers/create-error-message');
const Rule = require('./base');
const reLineEnds = /(\r\n?|\n)/g;
const reLines = /(.*?(?:\r\n?|\n|$))/gm;
function toUserString(value) {
return value.replace('\r', 'CR').replace('\n', 'LF');
}
const matchMap = {
lf: '\n',
cr: '\r',
crlf: '\r\n',
};
module.exports = class LinebreakStyle extends Rule {
constructor(options) {
super(options);
const configuredIndent = this.editorConfig['end_of_line'];
if (['lf', 'cr', 'crlf'].includes(configuredIndent)) {
this.config = matchMap[configuredIndent];
}
}
parseConfig(config) {
let configType = typeof config;
switch (configType) {
case 'boolean':
return config;
case 'string':
switch (config) {
case 'system':
return os.EOL;
case 'unix':
return '\n';
case 'windows':
return '\r\n';
}
break;
case 'undefined':
return false;
}
let errorMessage = createErrorMessage(
this.ruleName,
[
'* boolean -- `true` for enforcing consistency (all `CRLF` or all `LF` not both in a single file)',
'* string -- `system` for the current platforms default line ending / `unix` for LF linebreaks / `windows` for CRLF linebreaks',
],
config
);
throw new Error(errorMessage);
}
visitor() {
return {
TextNode(node) {
this._checkNodeAndLog(node);
},
MustacheStatement(node) {
this._checkNodeAndLog(node);
},
PartialStatement(node) {
this._checkNodeAndLog(node);
},
MustacheCommentStatement(node) {
this._checkNodeAndLog(node);
},
CommentStatement(node) {
this._checkNodeAndLog(node);
},
};
}
_getWrongLinebreakFromLine(source) {
let linebreaks = source.match(reLineEnds);
if (linebreaks) {
let linebreak = linebreaks[0];
if (!linebreak) {
return null;
}
if (this.config === true) {
this.config = linebreak;
}
if (linebreak !== this.config) {
return linebreak;
}
}
return null;
}
_checkNodeAndLog(node) {
if (!node.loc) {
return;
}
let nodeSource = this.sourceForNode(node);
let lines = nodeSource.match(reLines);
for (const [i, sourceLine] of lines.entries()) {
let wrongLineBreak = this._getWrongLinebreakFromLine(sourceLine);
if (wrongLineBreak) {
let wrongLineBreakForDisplay = toUserString(wrongLineBreak);
let goodLineBreakForDisplay = toUserString(this.config);
this.log({
message: `Wrong linebreak used. Expected ${goodLineBreakForDisplay} but found ${wrongLineBreakForDisplay}`,
line: i + node.loc.start.line,
column: sourceLine.length - wrongLineBreak.length + (i === 0 ? node.loc.start.column : 0),
source: wrongLineBreak,
});
}
}
}
};
;