diff --git a/dist/core/rules/doctype-first.js b/dist/core/rules/doctype-first.js
index f7767d371..235ea1cea 100644
--- a/dist/core/rules/doctype-first.js
+++ b/dist/core/rules/doctype-first.js
@@ -2,20 +2,35 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = {
id: 'doctype-first',
- description: 'Doctype must be declared first.',
+ description: 'Doctype must be declared first (comments and whitespace allowed before DOCTYPE).',
init(parser, reporter) {
+ let doctypeFound = false;
+ let nonCommentContentBeforeDoctype = false;
const allEvent = (event) => {
if (event.type === 'start' ||
(event.type === 'text' && /^\s*$/.test(event.raw))) {
return;
}
- if ((event.type !== 'comment' && event.long === false) ||
- /^DOCTYPE\s+/i.test(event.content) === false) {
- reporter.error('Doctype must be declared first.', event.line, event.col, this, event.raw);
+ if (doctypeFound) {
+ return;
+ }
+ if (event.type === 'comment' &&
+ event.long === false &&
+ /^DOCTYPE\s+/i.test(event.content)) {
+ doctypeFound = true;
+ if (nonCommentContentBeforeDoctype) {
+ reporter.error('Doctype must be declared before any non-comment content.', event.line, event.col, this, event.raw);
+ }
+ return;
+ }
+ if (event.type === 'comment') {
+ return;
}
+ nonCommentContentBeforeDoctype = true;
+ reporter.error('Doctype must be declared before any non-comment content.', event.line, event.col, this, event.raw);
parser.removeListener('all', allEvent);
};
parser.addListener('all', allEvent);
},
};
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9jdHlwZS1maXJzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL3J1bGVzL2RvY3R5cGUtZmlyc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFHQSxrQkFBZTtJQUNiLEVBQUUsRUFBRSxlQUFlO0lBQ25CLFdBQVcsRUFBRSxpQ0FBaUM7SUFDOUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRO1FBQ25CLE1BQU0sUUFBUSxHQUFhLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDbkMsSUFDRSxLQUFLLENBQUMsSUFBSSxLQUFLLE9BQU87Z0JBQ3RCLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxNQUFNLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsRUFDbEQ7Z0JBQ0EsT0FBTTthQUNQO1lBRUQsSUFDRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDO2dCQUNsRCxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxLQUFLLEVBQzVDO2dCQUNBLFFBQVEsQ0FBQyxLQUFLLENBQ1osaUNBQWlDLEVBQ2pDLEtBQUssQ0FBQyxJQUFJLEVBQ1YsS0FBSyxDQUFDLEdBQUcsRUFDVCxJQUFJLEVBQ0osS0FBSyxDQUFDLEdBQUcsQ0FDVixDQUFBO2FBQ0Y7WUFFRCxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQTtRQUN4QyxDQUFDLENBQUE7UUFFRCxNQUFNLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQTtJQUNyQyxDQUFDO0NBQ00sQ0FBQSJ9
\ No newline at end of file
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9jdHlwZS1maXJzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL3J1bGVzL2RvY3R5cGUtZmlyc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFHQSxrQkFBZTtJQUNiLEVBQUUsRUFBRSxlQUFlO0lBQ25CLFdBQVcsRUFDVCxrRkFBa0Y7SUFDcEYsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRO1FBQ25CLElBQUksWUFBWSxHQUFHLEtBQUssQ0FBQTtRQUN4QixJQUFJLDhCQUE4QixHQUFHLEtBQUssQ0FBQTtRQUUxQyxNQUFNLFFBQVEsR0FBYSxDQUFDLEtBQUssRUFBRSxFQUFFO1lBRW5DLElBQ0UsS0FBSyxDQUFDLElBQUksS0FBSyxPQUFPO2dCQUN0QixDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQ2xEO2dCQUNBLE9BQU07YUFDUDtZQUdELElBQUksWUFBWSxFQUFFO2dCQUNoQixPQUFNO2FBQ1A7WUFHRCxJQUNFLEtBQUssQ0FBQyxJQUFJLEtBQUssU0FBUztnQkFDeEIsS0FBSyxDQUFDLElBQUksS0FBSyxLQUFLO2dCQUNwQixjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFDbEM7Z0JBQ0EsWUFBWSxHQUFHLElBQUksQ0FBQTtnQkFDbkIsSUFBSSw4QkFBOEIsRUFBRTtvQkFFbEMsUUFBUSxDQUFDLEtBQUssQ0FDWiwwREFBMEQsRUFDMUQsS0FBSyxDQUFDLElBQUksRUFDVixLQUFLLENBQUMsR0FBRyxFQUNULElBQUksRUFDSixLQUFLLENBQUMsR0FBRyxDQUNWLENBQUE7aUJBQ0Y7Z0JBQ0QsT0FBTTthQUNQO1lBR0QsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFLLFNBQVMsRUFBRTtnQkFDNUIsT0FBTTthQUNQO1lBR0QsOEJBQThCLEdBQUcsSUFBSSxDQUFBO1lBR3JDLFFBQVEsQ0FBQyxLQUFLLENBQ1osMERBQTBELEVBQzFELEtBQUssQ0FBQyxJQUFJLEVBQ1YsS0FBSyxDQUFDLEdBQUcsRUFDVCxJQUFJLEVBQ0osS0FBSyxDQUFDLEdBQUcsQ0FDVixDQUFBO1lBR0QsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUE7UUFDeEMsQ0FBQyxDQUFBO1FBRUQsTUFBTSxDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUE7SUFDckMsQ0FBQztDQUNNLENBQUEifQ==
\ No newline at end of file
diff --git a/dist/htmlhint.js b/dist/htmlhint.js
deleted file mode 100644
index 46cdeb58b..000000000
--- a/dist/htmlhint.js
+++ /dev/null
@@ -1,2065 +0,0 @@
-/*!
- * HTMLHint v1.2.0
- * https://htmlhint.com
- * Built on: 2025-05-31
- * Copyright (c) 2025 HTMLHint
- * Licensed under MIT License
- */
-(function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.HTMLHint = factory());
-})(this, (function () { 'use strict';
-
- function getDefaultExportFromCjs (x) {
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
- }
-
- var core$1 = {};
-
- var htmlparser = {};
-
- var hasRequiredHtmlparser;
-
- function requireHtmlparser () {
- if (hasRequiredHtmlparser) return htmlparser;
- hasRequiredHtmlparser = 1;
- Object.defineProperty(htmlparser, "__esModule", { value: true });
- class HTMLParser {
- constructor() {
- this._listeners = {};
- this._mapCdataTags = this.makeMap('script,style');
- this._arrBlocks = [];
- this.lastEvent = null;
- }
- makeMap(str) {
- const obj = {};
- const items = str.split(',');
- for (let i = 0; i < items.length; i++) {
- obj[items[i]] = true;
- }
- return obj;
- }
- parse(html) {
- const mapCdataTags = this._mapCdataTags;
- const regTag = /<(?:\/([^\s>]+)\s*|!--([\s\S]*?)--|!([^>]*?)|([\w\-:]+)((?:\s+[^\s"'>\/=\x00-\x0F\x7F\x80-\x9F]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'>]*))?)*?)\s*(\/?))>/g;
- const regAttr = /\s*([^\s"'>\/=\x00-\x0F\x7F\x80-\x9F]+)(?:\s*=\s*(?:(")([^"]*)"|(')([^']*)'|([^\s"'>]*)))?/g;
- const regLine = /\r?\n/g;
- let match;
- let matchIndex;
- let lastIndex = 0;
- let tagName;
- let arrAttrs;
- let tagCDATA = null;
- let attrsCDATA;
- let arrCDATA = [];
- let lastCDATAIndex = 0;
- let text;
- let lastLineIndex = 0;
- let line = 1;
- const arrBlocks = this._arrBlocks;
- this.fire('start', {
- pos: 0,
- line: 1,
- col: 1,
- });
- const isMapCdataTagsRequired = () => {
- const attrType = arrAttrs.find((attr) => attr.name === 'type') || {
- value: '',
- };
- return (mapCdataTags[tagName] &&
- attrType.value.indexOf('text/ng-template') === -1);
- };
- const saveBlock = (type, raw, pos, data) => {
- const col = pos - lastLineIndex + 1;
- if (data === undefined) {
- data = {};
- }
- data.raw = raw;
- data.pos = pos;
- data.line = line;
- data.col = col;
- arrBlocks.push(data);
- this.fire(type, data);
- while (regLine.exec(raw)) {
- line++;
- lastLineIndex = pos + regLine.lastIndex;
- }
- };
- while ((match = regTag.exec(html))) {
- matchIndex = match.index;
- if (matchIndex > lastIndex) {
- text = html.substring(lastIndex, matchIndex);
- if (tagCDATA) {
- arrCDATA.push(text);
- }
- else {
- saveBlock('text', text, lastIndex);
- }
- }
- lastIndex = regTag.lastIndex;
- if ((tagName = match[1])) {
- if (tagCDATA && tagName === tagCDATA) {
- text = arrCDATA.join('');
- saveBlock('cdata', text, lastCDATAIndex, {
- tagName: tagCDATA,
- attrs: attrsCDATA,
- });
- tagCDATA = null;
- attrsCDATA = undefined;
- arrCDATA = [];
- }
- if (!tagCDATA) {
- saveBlock('tagend', match[0], matchIndex, {
- tagName: tagName,
- });
- continue;
- }
- }
- if (tagCDATA) {
- arrCDATA.push(match[0]);
- }
- else {
- if ((tagName = match[4])) {
- arrAttrs = [];
- const attrs = match[5];
- let attrMatch;
- let attrMatchCount = 0;
- while ((attrMatch = regAttr.exec(attrs))) {
- const name = attrMatch[1];
- const quote = attrMatch[2]
- ? attrMatch[2]
- : attrMatch[4]
- ? attrMatch[4]
- : '';
- const value = attrMatch[3]
- ? attrMatch[3]
- : attrMatch[5]
- ? attrMatch[5]
- : attrMatch[6]
- ? attrMatch[6]
- : '';
- arrAttrs.push({
- name: name,
- value: value,
- quote: quote,
- index: attrMatch.index,
- raw: attrMatch[0],
- });
- attrMatchCount += attrMatch[0].length;
- }
- if (attrMatchCount === attrs.length) {
- saveBlock('tagstart', match[0], matchIndex, {
- tagName: tagName,
- attrs: arrAttrs,
- close: match[6],
- });
- if (isMapCdataTagsRequired()) {
- tagCDATA = tagName;
- attrsCDATA = arrAttrs.concat();
- arrCDATA = [];
- lastCDATAIndex = lastIndex;
- }
- }
- else {
- saveBlock('text', match[0], matchIndex);
- }
- }
- else if (match[2] || match[3]) {
- saveBlock('comment', match[0], matchIndex, {
- content: match[2] || match[3],
- long: match[2] ? true : false,
- });
- }
- }
- }
- if (html.length > lastIndex) {
- text = html.substring(lastIndex, html.length);
- saveBlock('text', text, lastIndex);
- }
- this.fire('end', {
- pos: lastIndex,
- line: line,
- col: html.length - lastLineIndex + 1,
- });
- }
- addListener(types, listener) {
- const _listeners = this._listeners;
- const arrTypes = types.split(/[,\s]/);
- let type;
- for (let i = 0, l = arrTypes.length; i < l; i++) {
- type = arrTypes[i];
- if (_listeners[type] === undefined) {
- _listeners[type] = [];
- }
- _listeners[type].push(listener);
- }
- }
- fire(type, data) {
- if (data === undefined) {
- data = {};
- }
- data.type = type;
- let listeners = [];
- const listenersType = this._listeners[type];
- const listenersAll = this._listeners['all'];
- if (listenersType !== undefined) {
- listeners = listeners.concat(listenersType);
- }
- if (listenersAll !== undefined) {
- listeners = listeners.concat(listenersAll);
- }
- const lastEvent = this.lastEvent;
- if (lastEvent !== null) {
- delete lastEvent['lastEvent'];
- data.lastEvent = lastEvent;
- }
- this.lastEvent = data;
- for (let i = 0, l = listeners.length; i < l; i++) {
- listeners[i].call(this, data);
- }
- }
- removeListener(type, listener) {
- const listenersType = this._listeners[type];
- if (listenersType !== undefined) {
- for (let i = 0, l = listenersType.length; i < l; i++) {
- if (listenersType[i] === listener) {
- listenersType.splice(i, 1);
- break;
- }
- }
- }
- }
- fixPos(event, index) {
- const text = event.raw.substr(0, index);
- const arrLines = text.split(/\r?\n/);
- const lineCount = arrLines.length - 1;
- let line = event.line;
- let col;
- if (lineCount > 0) {
- line += lineCount;
- col = arrLines[lineCount].length + 1;
- }
- else {
- col = event.col + index;
- }
- return {
- line: line,
- col: col,
- };
- }
- getMapAttrs(arrAttrs) {
- const mapAttrs = {};
- let attr;
- for (let i = 0, l = arrAttrs.length; i < l; i++) {
- attr = arrAttrs[i];
- mapAttrs[attr.name] = attr.value;
- }
- return mapAttrs;
- }
- }
- htmlparser.default = HTMLParser;
-
- return htmlparser;
- }
-
- var reporter = {};
-
- var hasRequiredReporter;
-
- function requireReporter () {
- if (hasRequiredReporter) return reporter;
- hasRequiredReporter = 1;
- Object.defineProperty(reporter, "__esModule", { value: true });
- class Reporter {
- constructor(html, ruleset) {
- this.html = html;
- this.lines = html.split(/\r?\n/);
- const match = /\r?\n/.exec(html);
- this.brLen = match !== null ? match[0].length : 0;
- this.ruleset = ruleset;
- this.messages = [];
- }
- info(message, line, col, rule, raw) {
- this.report("info", message, line, col, rule, raw);
- }
- warn(message, line, col, rule, raw) {
- this.report("warning", message, line, col, rule, raw);
- }
- error(message, line, col, rule, raw) {
- this.report("error", message, line, col, rule, raw);
- }
- report(type, message, line, col, rule, raw) {
- const lines = this.lines;
- const brLen = this.brLen;
- let evidence = '';
- let evidenceLen = 0;
- for (let i = line - 1, lineCount = lines.length; i < lineCount; i++) {
- evidence = lines[i];
- evidenceLen = evidence.length;
- if (col > evidenceLen && line < lineCount) {
- line++;
- col -= evidenceLen;
- if (col !== 1) {
- col -= brLen;
- }
- }
- else {
- break;
- }
- }
- this.messages.push({
- type: type,
- message: message,
- raw: raw,
- evidence: evidence,
- line: line,
- col: col,
- rule: {
- id: rule.id,
- description: rule.description,
- link: `https://htmlhint.com/docs/user-guide/rules/${rule.id}`,
- },
- });
- }
- }
- reporter.default = Reporter;
-
- return reporter;
- }
-
- var rules = {};
-
- var altRequire = {};
-
- var hasRequiredAltRequire;
-
- function requireAltRequire () {
- if (hasRequiredAltRequire) return altRequire;
- hasRequiredAltRequire = 1;
- Object.defineProperty(altRequire, "__esModule", { value: true });
- altRequire.default = {
- id: 'alt-require',
- description: 'The alt attribute of an element must be present and alt attribute of area[href] and input[type=image] must have a value.',
- init(parser, reporter) {
- parser.addListener('tagstart', (event) => {
- const tagName = event.tagName.toLowerCase();
- const mapAttrs = parser.getMapAttrs(event.attrs);
- const col = event.col + tagName.length + 1;
- let selector;
- if (tagName === 'img' && !('alt' in mapAttrs)) {
- reporter.warn('An alt attribute must be present on
elements.', event.line, col, this, event.raw);
- }
- else if ((tagName === 'area' && 'href' in mapAttrs) ||
- (tagName === 'input' && mapAttrs['type'] === 'image')) {
- if (!('alt' in mapAttrs) || mapAttrs['alt'] === '') {
- selector = tagName === 'area' ? 'area[href]' : 'input[type=image]';
- reporter.warn(`The alt attribute of ${selector} must have a value.`, event.line, col, this, event.raw);
- }
- }
- });
- },
- };
-
- return altRequire;
- }
-
- var attrLowercase = {};
-
- var hasRequiredAttrLowercase;
-
- function requireAttrLowercase () {
- if (hasRequiredAttrLowercase) return attrLowercase;
- hasRequiredAttrLowercase = 1;
- Object.defineProperty(attrLowercase, "__esModule", { value: true });
- const svgIgnores = [
- 'allowReorder',
- 'attributeName',
- 'attributeType',
- 'autoReverse',
- 'baseFrequency',
- 'baseProfile',
- 'calcMode',
- 'clipPath',
- 'clipPathUnits',
- 'contentScriptType',
- 'contentStyleType',
- 'diffuseConstant',
- 'edgeMode',
- 'externalResourcesRequired',
- 'filterRes',
- 'filterUnits',
- 'glyphRef',
- 'gradientTransform',
- 'gradientUnits',
- 'kernelMatrix',
- 'kernelUnitLength',
- 'keyPoints',
- 'keySplines',
- 'keyTimes',
- 'lengthAdjust',
- 'limitingConeAngle',
- 'markerHeight',
- 'markerUnits',
- 'markerWidth',
- 'maskContentUnits',
- 'maskUnits',
- 'numOctaves',
- 'onBlur',
- 'onChange',
- 'onClick',
- 'onFocus',
- 'onKeyUp',
- 'onLoad',
- 'pathLength',
- 'patternContentUnits',
- 'patternTransform',
- 'patternUnits',
- 'pointsAtX',
- 'pointsAtY',
- 'pointsAtZ',
- 'preserveAlpha',
- 'preserveAspectRatio',
- 'primitiveUnits',
- 'refX',
- 'refY',
- 'repeatCount',
- 'repeatDur',
- 'requiredExtensions',
- 'requiredFeatures',
- 'specularConstant',
- 'specularExponent',
- 'spreadMethod',
- 'startOffset',
- 'stdDeviation',
- 'stitchTiles',
- 'surfaceScale',
- 'systemLanguage',
- 'tableValues',
- 'targetX',
- 'targetY',
- 'textLength',
- 'viewBox',
- 'viewTarget',
- 'xChannelSelector',
- 'yChannelSelector',
- 'zoomAndPan',
- ];
- function testAgainstStringOrRegExp(value, comparison) {
- if (comparison instanceof RegExp) {
- return comparison.test(value)
- ? { match: value, pattern: comparison }
- : false;
- }
- const firstComparisonChar = comparison[0];
- const lastComparisonChar = comparison[comparison.length - 1];
- const secondToLastComparisonChar = comparison[comparison.length - 2];
- const comparisonIsRegex = firstComparisonChar === '/' &&
- (lastComparisonChar === '/' ||
- (secondToLastComparisonChar === '/' && lastComparisonChar === 'i'));
- const hasCaseInsensitiveFlag = comparisonIsRegex && lastComparisonChar === 'i';
- if (comparisonIsRegex) {
- const valueMatches = hasCaseInsensitiveFlag
- ? new RegExp(comparison.slice(1, -2), 'i').test(value)
- : new RegExp(comparison.slice(1, -1)).test(value);
- return valueMatches;
- }
- return value === comparison;
- }
- attrLowercase.default = {
- id: 'attr-lowercase',
- description: 'All attribute names must be in lowercase.',
- init(parser, reporter, options) {
- const exceptions = (Array.isArray(options) ? options : []).concat(svgIgnores);
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- let attr;
- const col = event.col + event.tagName.length + 1;
- for (let i = 0, l = attrs.length; i < l; i++) {
- attr = attrs[i];
- const attrName = attr.name;
- if (!exceptions.find((exp) => testAgainstStringOrRegExp(attrName, exp)) &&
- attrName !== attrName.toLowerCase()) {
- reporter.error(`The attribute name of [ ${attrName} ] must be in lowercase.`, event.line, col + attr.index, this, attr.raw);
- }
- }
- });
- },
- };
-
- return attrLowercase;
- }
-
- var attrNoDuplication = {};
-
- var hasRequiredAttrNoDuplication;
-
- function requireAttrNoDuplication () {
- if (hasRequiredAttrNoDuplication) return attrNoDuplication;
- hasRequiredAttrNoDuplication = 1;
- Object.defineProperty(attrNoDuplication, "__esModule", { value: true });
- attrNoDuplication.default = {
- id: 'attr-no-duplication',
- description: 'Elements cannot have duplicate attributes.',
- init(parser, reporter) {
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- let attr;
- let attrName;
- const col = event.col + event.tagName.length + 1;
- const mapAttrName = {};
- for (let i = 0, l = attrs.length; i < l; i++) {
- attr = attrs[i];
- attrName = attr.name;
- if (mapAttrName[attrName] === true) {
- reporter.error(`Duplicate of attribute name [ ${attr.name} ] was found.`, event.line, col + attr.index, this, attr.raw);
- }
- mapAttrName[attrName] = true;
- }
- });
- },
- };
-
- return attrNoDuplication;
- }
-
- var attrNoUnnecessaryWhitespace = {};
-
- var hasRequiredAttrNoUnnecessaryWhitespace;
-
- function requireAttrNoUnnecessaryWhitespace () {
- if (hasRequiredAttrNoUnnecessaryWhitespace) return attrNoUnnecessaryWhitespace;
- hasRequiredAttrNoUnnecessaryWhitespace = 1;
- Object.defineProperty(attrNoUnnecessaryWhitespace, "__esModule", { value: true });
- attrNoUnnecessaryWhitespace.default = {
- id: 'attr-no-unnecessary-whitespace',
- description: 'No spaces between attribute names and values.',
- init(parser, reporter, options) {
- const exceptions = Array.isArray(options) ? options : [];
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- const col = event.col + event.tagName.length + 1;
- for (let i = 0; i < attrs.length; i++) {
- if (exceptions.indexOf(attrs[i].name) === -1) {
- const match = /(\s*)=(\s*)/.exec(attrs[i].raw.trim());
- if (match && (match[1].length !== 0 || match[2].length !== 0)) {
- reporter.error(`The attribute '${attrs[i].name}' must not have spaces between the name and value.`, event.line, col + attrs[i].index, this, attrs[i].raw);
- }
- }
- }
- });
- },
- };
-
- return attrNoUnnecessaryWhitespace;
- }
-
- var attrSorted = {};
-
- var hasRequiredAttrSorted;
-
- function requireAttrSorted () {
- if (hasRequiredAttrSorted) return attrSorted;
- hasRequiredAttrSorted = 1;
- Object.defineProperty(attrSorted, "__esModule", { value: true });
- attrSorted.default = {
- id: 'attr-sorted',
- description: 'Attribute tags must be in proper order.',
- init(parser, reporter) {
- const orderMap = {};
- const sortOrder = [
- 'class',
- 'id',
- 'name',
- 'src',
- 'for',
- 'type',
- 'rel',
- 'href',
- 'value',
- 'title',
- 'alt',
- 'role',
- ];
- for (let i = 0; i < sortOrder.length; i++) {
- orderMap[sortOrder[i]] = i;
- }
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- const listOfAttributes = [];
- for (let i = 0; i < attrs.length; i++) {
- listOfAttributes.push(attrs[i].name);
- }
- const originalAttrs = JSON.stringify(listOfAttributes);
- listOfAttributes.sort((a, b) => {
- if (orderMap[a] !== undefined) {
- if (orderMap[b] !== undefined) {
- return orderMap[a] - orderMap[b];
- }
- return -1;
- }
- if (a.startsWith('data-')) {
- if (b.startsWith('data-')) {
- return a.localeCompare(b);
- }
- return 1;
- }
- if (orderMap[b] !== undefined) {
- return 1;
- }
- if (b.startsWith('data-')) {
- return -1;
- }
- return a.localeCompare(b);
- });
- if (originalAttrs !== JSON.stringify(listOfAttributes)) {
- reporter.error(`Inaccurate order ${originalAttrs} should be in hierarchy ${JSON.stringify(listOfAttributes)} `, event.line, event.col, this, event.raw);
- }
- });
- },
- };
-
- return attrSorted;
- }
-
- var attrUnsafeChars = {};
-
- var hasRequiredAttrUnsafeChars;
-
- function requireAttrUnsafeChars () {
- if (hasRequiredAttrUnsafeChars) return attrUnsafeChars;
- hasRequiredAttrUnsafeChars = 1;
- Object.defineProperty(attrUnsafeChars, "__esModule", { value: true });
- attrUnsafeChars.default = {
- id: 'attr-unsafe-chars',
- description: 'Attribute values cannot contain unsafe chars.',
- init(parser, reporter) {
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- let attr;
- const col = event.col + event.tagName.length + 1;
- const regUnsafe = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
- let match;
- for (let i = 0, l = attrs.length; i < l; i++) {
- attr = attrs[i];
- match = regUnsafe.exec(attr.value);
- if (match !== null) {
- const unsafeCode = escape(match[0])
- .replace(/%u/, '\\u')
- .replace(/%/, '\\x');
- reporter.warn(`The value of attribute [ ${attr.name} ] cannot contain an unsafe char [ ${unsafeCode} ].`, event.line, col + attr.index, this, attr.raw);
- }
- }
- });
- },
- };
-
- return attrUnsafeChars;
- }
-
- var attrValueDoubleQuotes = {};
-
- var hasRequiredAttrValueDoubleQuotes;
-
- function requireAttrValueDoubleQuotes () {
- if (hasRequiredAttrValueDoubleQuotes) return attrValueDoubleQuotes;
- hasRequiredAttrValueDoubleQuotes = 1;
- Object.defineProperty(attrValueDoubleQuotes, "__esModule", { value: true });
- attrValueDoubleQuotes.default = {
- id: 'attr-value-double-quotes',
- description: 'Attribute values must be in double quotes.',
- init(parser, reporter) {
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- let attr;
- const col = event.col + event.tagName.length + 1;
- for (let i = 0, l = attrs.length; i < l; i++) {
- attr = attrs[i];
- if ((attr.value !== '' && attr.quote !== '"') ||
- (attr.value === '' && attr.quote === "'")) {
- reporter.error(`The value of attribute [ ${attr.name} ] must be in double quotes.`, event.line, col + attr.index, this, attr.raw);
- }
- }
- });
- },
- };
-
- return attrValueDoubleQuotes;
- }
-
- var attrValueNotEmpty = {};
-
- var hasRequiredAttrValueNotEmpty;
-
- function requireAttrValueNotEmpty () {
- if (hasRequiredAttrValueNotEmpty) return attrValueNotEmpty;
- hasRequiredAttrValueNotEmpty = 1;
- Object.defineProperty(attrValueNotEmpty, "__esModule", { value: true });
- attrValueNotEmpty.default = {
- id: 'attr-value-not-empty',
- description: 'All attributes must have values.',
- init(parser, reporter) {
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- let attr;
- const col = event.col + event.tagName.length + 1;
- for (let i = 0, l = attrs.length; i < l; i++) {
- attr = attrs[i];
- if (attr.quote === '' && attr.value === '') {
- reporter.warn(`The attribute [ ${attr.name} ] must have a value.`, event.line, col + attr.index, this, attr.raw);
- }
- }
- });
- },
- };
-
- return attrValueNotEmpty;
- }
-
- var attrValueSingleQuotes = {};
-
- var hasRequiredAttrValueSingleQuotes;
-
- function requireAttrValueSingleQuotes () {
- if (hasRequiredAttrValueSingleQuotes) return attrValueSingleQuotes;
- hasRequiredAttrValueSingleQuotes = 1;
- Object.defineProperty(attrValueSingleQuotes, "__esModule", { value: true });
- attrValueSingleQuotes.default = {
- id: 'attr-value-single-quotes',
- description: 'Attribute values must be in single quotes.',
- init(parser, reporter) {
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- let attr;
- const col = event.col + event.tagName.length + 1;
- for (let i = 0, l = attrs.length; i < l; i++) {
- attr = attrs[i];
- if ((attr.value !== '' && attr.quote !== "'") ||
- (attr.value === '' && attr.quote === '"')) {
- reporter.error(`The value of attribute [ ${attr.name} ] must be in single quotes.`, event.line, col + attr.index, this, attr.raw);
- }
- }
- });
- },
- };
-
- return attrValueSingleQuotes;
- }
-
- var attrWhitespace = {};
-
- var hasRequiredAttrWhitespace;
-
- function requireAttrWhitespace () {
- if (hasRequiredAttrWhitespace) return attrWhitespace;
- hasRequiredAttrWhitespace = 1;
- Object.defineProperty(attrWhitespace, "__esModule", { value: true });
- attrWhitespace.default = {
- id: 'attr-whitespace',
- description: 'All attributes should be separated by only one space and not have leading/trailing whitespace.',
- init(parser, reporter, options) {
- const exceptions = Array.isArray(options)
- ? options
- : [];
- parser.addListener('tagstart', (event) => {
- const attrs = event.attrs;
- let attr;
- const col = event.col + event.tagName.length + 1;
- attrs.forEach((elem) => {
- attr = elem;
- const attrName = elem.name;
- if (exceptions.indexOf(attrName) !== -1) {
- return;
- }
- if (elem.value.trim() !== elem.value) {
- reporter.error(`The attributes of [ ${attrName} ] must not have leading or trailing whitespace.`, event.line, col + attr.index, this, attr.raw);
- }
- if (elem.value.replace(/ +(?= )/g, '') !== elem.value) {
- reporter.error(`The attributes of [ ${attrName} ] must be separated by only one space.`, event.line, col + attr.index, this, attr.raw);
- }
- });
- });
- },
- };
-
- return attrWhitespace;
- }
-
- var doctypeFirst = {};
-
- var hasRequiredDoctypeFirst;
-
- function requireDoctypeFirst () {
- if (hasRequiredDoctypeFirst) return doctypeFirst;
- hasRequiredDoctypeFirst = 1;
- Object.defineProperty(doctypeFirst, "__esModule", { value: true });
- doctypeFirst.default = {
- id: 'doctype-first',
- description: 'Doctype must be declared first.',
- init(parser, reporter) {
- const allEvent = (event) => {
- if (event.type === 'start' ||
- (event.type === 'text' && /^\s*$/.test(event.raw))) {
- return;
- }
- if ((event.type !== 'comment' && event.long === false) ||
- /^DOCTYPE\s+/i.test(event.content) === false) {
- reporter.error('Doctype must be declared first.', event.line, event.col, this, event.raw);
- }
- parser.removeListener('all', allEvent);
- };
- parser.addListener('all', allEvent);
- },
- };
-
- return doctypeFirst;
- }
-
- var doctypeHtml5 = {};
-
- var hasRequiredDoctypeHtml5;
-
- function requireDoctypeHtml5 () {
- if (hasRequiredDoctypeHtml5) return doctypeHtml5;
- hasRequiredDoctypeHtml5 = 1;
- Object.defineProperty(doctypeHtml5, "__esModule", { value: true });
- doctypeHtml5.default = {
- id: 'doctype-html5',
- description: 'Invalid doctype. Use: ""',
- init(parser, reporter) {
- const onComment = (event) => {
- if (event.long === false &&
- event.content.toLowerCase() !== 'doctype html') {
- reporter.warn('Invalid doctype. Use: ""', event.line, event.col, this, event.raw);
- }
- };
- const onTagStart = () => {
- parser.removeListener('comment', onComment);
- parser.removeListener('tagstart', onTagStart);
- };
- parser.addListener('all', onComment);
- parser.addListener('tagstart', onTagStart);
- },
- };
-
- return doctypeHtml5;
- }
-
- var emptyTagNotSelfClosed = {};
-
- var hasRequiredEmptyTagNotSelfClosed;
-
- function requireEmptyTagNotSelfClosed () {
- if (hasRequiredEmptyTagNotSelfClosed) return emptyTagNotSelfClosed;
- hasRequiredEmptyTagNotSelfClosed = 1;
- Object.defineProperty(emptyTagNotSelfClosed, "__esModule", { value: true });
- emptyTagNotSelfClosed.default = {
- id: 'empty-tag-not-self-closed',
- description: 'Empty tags must not use self closed syntax.',
- init(parser, reporter) {
- const mapEmptyTags = parser.makeMap('area,base,basefont,bgsound,br,col,frame,hr,img,input,isindex,link,meta,param,embed,track,command,source,keygen,wbr');
- parser.addListener('tagstart', (event) => {
- const tagName = event.tagName.toLowerCase();
- if (mapEmptyTags[tagName] !== undefined) {
- if (event.close) {
- reporter.error(`The empty tag : [ ${tagName} ] must not use self closed syntax.`, event.line, event.col, this, event.raw);
- }
- }
- });
- },
- };
-
- return emptyTagNotSelfClosed;
- }
-
- var h1Require = {};
-
- var hasRequiredH1Require;
-
- function requireH1Require () {
- if (hasRequiredH1Require) return h1Require;
- hasRequiredH1Require = 1;
- Object.defineProperty(h1Require, "__esModule", { value: true });
- h1Require.default = {
- id: 'h1-require',
- description: '