Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
// Raw JS or SCSS file
if (file.endsWith('.js')) {
options.parser = 'babylon';
formatted = prettier.format(source, options);
if (formatted !== source) {
notSoPretty = true;
}
formatted = eslint(formatted);
} else if (file.endsWith('.scss')) {
formatted = lintScss(source);
} else if (file.endsWith('.vue')) {
let block;
// First lint the whole vue component with eslint
formatted = eslint(source);
// Now run htmlhint on the whole vue component
let htmlMessages = HTMLHint.verify(formatted, htmlHintConfig);
if (htmlMessages.length) {
messages.push(...HTMLHint.format(htmlMessages, { colors: true }));
}
let vueComponent = compiler.parseComponent(formatted);
// Prettier strips the 2 space indentation that we enforce within script tags for vue
// components. So here we account for those 2 spaces that will be added.
options.printWidth = options.printWidth - 2;
// Format script block
if (vueComponent.script) {
block = vueComponent.script;
const js = block.content;
options.parser = 'babylon';
let formattedJs = prettier.format(js, options);
var finish = function (target, response, cb) {
var messages = [],
empty = typeof response === 'undefined' || response === '';
// Lint generated html and check if response is empty
if (options.htmlhint !== false) {
messages = HTMLHint.verify(response || '', options.htmlhint);
}
// move on to the next file if everything went right
if (!error && messages.length === 0 && !empty) {
grunt.file.write(target, response);
grunt.log.ok();
grunt.log.debug(target + ' written');
compiled.push(target);
// there was an error, show messages to the user if applicable and move on
} else {
grunt.log.error();
if (empty) {
grunt.log.warn('Resulting HTML is empty');
}
return through2.obj((file, enc, cb) => {
const report = HTMLHint.verify(file.contents.toString(), ruleset);
// Send status down-stream
file.htmlhint = formatOutput(report, file, options);
cb(null, file);
});
};
formatted = eslint(source);
let vueComponent = compiler.parseComponent(formatted);
// Format template block
if (vueComponent.template && vueComponent.template.content) {
formatted = insertContent(
formatted,
vueComponent.template,
vueComponent.template.content
);
vueComponent = compiler.parseComponent(formatted);
}
// Now run htmlhint on the whole vue component
let htmlMessages = HTMLHint.verify(formatted, htmlHintConfig);
if (htmlMessages.length) {
messages.push(...HTMLHint.format(htmlMessages, { colors: true }));
}
// Format script block
if (vueComponent.script) {
block = vueComponent.script;
const js = block.content;
let formattedJs = prettierFormat(js, 'babel', true);
formatted = insertContent(formatted, block, formattedJs);
if (formattedJs.trim() !== js.trim()) {
notSoPretty = true;
}
}
let vueComponent = compiler.parseComponent(formatted);
// Format template block
if (vueComponent.template && vueComponent.template.content) {
formatted = insertContent(
formatted,
vueComponent.template,
vueComponent.template.content
);
vueComponent = compiler.parseComponent(formatted);
}
// Now run htmlhint on the whole vue component
let htmlMessages = HTMLHint.verify(formatted, htmlHintConfig);
if (htmlMessages.length) {
messages.push(...HTMLHint.format(htmlMessages, { colors: true }));
}
// Format script block
if (vueComponent.script) {
block = vueComponent.script;
const js = block.content;
let formattedJs = prettierFormat(js, 'babel', true);
formatted = insertContent(formatted, block, formattedJs);
if (formattedJs.trim() !== js.trim()) {
notSoPretty = true;
}
}
// Format style blocks
for (let i = 0; i < vueComponent.styles.length; i++) {
options.parser = 'babylon';
formatted = prettier.format(source, options);
if (formatted !== source) {
notSoPretty = true;
}
formatted = eslint(formatted);
} else if (file.endsWith('.scss')) {
formatted = lintScss(source);
} else if (file.endsWith('.vue')) {
let block;
// First lint the whole vue component with eslint
formatted = eslint(source);
// Now run htmlhint on the whole vue component
let htmlMessages = HTMLHint.verify(formatted, htmlHintConfig);
if (htmlMessages.length) {
messages.push(...HTMLHint.format(htmlMessages, { colors: true }));
}
let vueComponent = compiler.parseComponent(formatted);
// Prettier strips the 2 space indentation that we enforce within script tags for vue
// components. So here we account for those 2 spaces that will be added.
options.printWidth = options.printWidth - 2;
// Format script block
if (vueComponent.script) {
block = vueComponent.script;
const js = block.content;
options.parser = 'babylon';
let formattedJs = prettier.format(js, options);
formatted = insertContent(formatted, block, formattedJs);
if (formattedJs.trim() !== js.trim()) {
// If necessary check for required param(s), e.g. options hash, etc.
// read config file for htmlhint if available
if (options.htmlhintrc) {
try {
const externalOptions = fs.readFileSync(options.htmlhintrc, 'utf-8');
options = JSON.parse(stripJsonComments(externalOptions));
} catch (error) {
throw new Error('gulp-htmlhint: Cannot parse .htmlhintrc ' + (error.message || error));
}
}
if (Object.keys(options).length > 0) {
// Build a list of all available rules
for (const key in HTMLHint.defaultRuleset) {
if (HTMLHint.defaultRuleset.hasOwnProperty(key)) { // eslint-disable-line no-prototype-builtins
ruleset[key] = 1;
}
}
// Normalize htmlhint options
// htmlhint only checks for rulekey, so remove rule if set to false
for (const rule in options) {
if (options[rule]) {
ruleset[rule] = options[rule];
} else {
delete ruleset[rule];
}
}
}
// Add the defined custom rules
}
// If necessary check for required param(s), e.g. options hash, etc.
// read config file for htmlhint if available
if (options.htmlhintrc) {
try {
const externalOptions = fs.readFileSync(options.htmlhintrc, 'utf-8');
options = JSON.parse(stripJsonComments(externalOptions));
} catch (error) {
throw new Error('gulp-htmlhint: Cannot parse .htmlhintrc ' + (error.message || error));
}
}
if (Object.keys(options).length > 0) {
// Build a list of all available rules
for (const key in HTMLHint.defaultRuleset) {
if (HTMLHint.defaultRuleset.hasOwnProperty(key)) { // eslint-disable-line no-prototype-builtins
ruleset[key] = 1;
}
}
// Normalize htmlhint options
// htmlhint only checks for rulekey, so remove rule if set to false
for (const rule in options) {
if (options[rule]) {
ruleset[rule] = options[rule];
} else {
delete ruleset[rule];
}
}
}
/*
Custom rules for the HTML linter.
Custom rule IDs are prefixed with a double dash ('--')
*/
var HTMLHint = require('htmlhint').HTMLHint;
/* helper to convert alternate-style newlines to unix-style */
function clean(val) {
return val.replace(/\r\n?/g, '\n');
}
/*
Based on the existing `tag-self-close` rule
*/
HTMLHint.addRule({
id: '--no-self-close-common-html5-tags',
description: 'Self-closing HTML5 tags are not valid.',
init: function(parser, reporter) {
var self = this;
var commonTags = parser.makeMap(`a,audio,b,body,button,canvas,caption,center,dir,div,dl,em,font,footer,
form,h1,h2,h3,h4,h5,h6,head,header,html,iframe,label,li,main,map,menu,nav,object,option,output,p,progress,
q,script,section,select,span,strong,style,sub,table,tbody,td,textarea,th,thead,time,title,tr,u,ul,var,video`);
parser.addListener('tagstart', function(event) {
var tagName = event.tagName.toLowerCase();
if (event.close && commonTags[tagName]) {
reporter.error(
'In : [ ' + event.tagName + ' ] self-closing tags are not valid HTML5.',
event.line,
event.col,
self,
event.raw
it('should add a htmlhint rule', () => {
const fakeRule = {
id: 'foo',
description: 'bar',
init() {}
};
htmlhint.addRule(fakeRule);
HTMLHint.rules[fakeRule.id].should.equal(fakeRule);
});
});