...
 
Commits (12)
# html-validate changelog
## [1.5.1](https://gitlab.com/html-validate/html-validate/compare/v1.5.0...v1.5.1) (2019-08-20)
### Bug Fixes
# [1.5.0](https://gitlab.com/html-validate/html-validate/compare/v1.4.0...v1.5.0) (2019-08-17)
- **elements:** mark contextmenu attribute as deprecated ([db4069f](https://gitlab.com/html-validate/html-validate/commit/db4069f))
### Features
### Bug Fixes
- **rules:** new rule no-unknown-elements ([96f5fcf](https://gitlab.com/html-validate/html-validate/commit/96f5fcf))
* **elements:** <img> must have non-empty src ([8916e19](https://gitlab.com/html-validate/html-validate/commit/8916e19))
* **rules:** change output format of wcag/h37 and element-required-attributes to match ([26f5074](https://gitlab.com/html-validate/html-validate/commit/26f5074))
## [1.5.0](https://gitlab.com/html-validate/html-validate/compare/v1.4.0...v1.5.0) (2019-08-17)
### Bug Fixes
- **elements:** `<img>` must have non-empty src ([8916e19](https://gitlab.com/html-validate/html-validate/commit/8916e19))
- **rules:** change output format of wcag/h37 and element-required-attributes to match ([26f5074](https://gitlab.com/html-validate/html-validate/commit/26f5074))
### Features
* **cli:** add --config to specify a custom configuration file ([87b565f](https://gitlab.com/html-validate/html-validate/commit/87b565f))
* **elements:** <fieldset> requires <legend> ([0bce9dd](https://gitlab.com/html-validate/html-validate/commit/0bce9dd))
* **elements:** <head> requires <title> ([8aaa801](https://gitlab.com/html-validate/html-validate/commit/8aaa801))
* **elements:** src, href, etc attributes cannot be empty ([89c7ac6](https://gitlab.com/html-validate/html-validate/commit/89c7ac6))
* **parser:** include valueLocation in doctype event ([803ddae](https://gitlab.com/html-validate/html-validate/commit/803ddae))
* **rules:** new rule doctype-html ([46061a7](https://gitlab.com/html-validate/html-validate/commit/46061a7))
* **rules:** new rule element-required-content ([664dead](https://gitlab.com/html-validate/html-validate/commit/664dead))
* **rules:** new rule no-style-tag ([a1dff5c](https://gitlab.com/html-validate/html-validate/commit/a1dff5c))
- **cli:** add --config to specify a custom configuration file ([87b565f](https://gitlab.com/html-validate/html-validate/commit/87b565f))
- **elements:** `<fieldset>` requires `<legend>` ([0bce9dd](https://gitlab.com/html-validate/html-validate/commit/0bce9dd))
- **elements:** `<head>` requires `<title>` ([8aaa801](https://gitlab.com/html-validate/html-validate/commit/8aaa801))
- **elements:** src, href, etc attributes cannot be empty ([89c7ac6](https://gitlab.com/html-validate/html-validate/commit/89c7ac6))
- **parser:** include valueLocation in doctype event ([803ddae](https://gitlab.com/html-validate/html-validate/commit/803ddae))
- **rules:** new rule doctype-html ([46061a7](https://gitlab.com/html-validate/html-validate/commit/46061a7))
- **rules:** new rule element-required-content ([664dead](https://gitlab.com/html-validate/html-validate/commit/664dead))
- **rules:** new rule no-style-tag ([a1dff5c](https://gitlab.com/html-validate/html-validate/commit/a1dff5c))
# [1.4.0](https://gitlab.com/html-validate/html-validate/compare/v1.3.0...v1.4.0) (2019-08-15)
## [1.4.0](https://gitlab.com/html-validate/html-validate/compare/v1.3.0...v1.4.0) (2019-08-15)
### Bug Fixes
......
......@@ -4,7 +4,7 @@
[![coverage report](https://gitlab.com/html-validate/html-validate/badges/master/coverage.svg)](https://gitlab.com/html-validate/html-validate/commits/master)
Offline HTML5 validator. Validates either a full document or a smaller
(incomplete) template, e.g. from an AngularJS or React component.
(incomplete) template, e.g. from an AngularJS or Vue.js component.
## Features
......@@ -60,8 +60,7 @@ Testing is done using jest.
or call `jest` directly.
Some tests are autogenerated from documentation examples, use `grunt docs` to
build those before running.
Some tests are autogenerated from documentation examples, use `npm run build:docs` to build those before running.
## Lint
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/no-unknown-elements.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/no-unknown-elements.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 1,
"context": "custom-element",
"line": 1,
"message": "Unknown element <custom-element>",
"offset": 0,
"ruleId": "no-unknown-elements",
"severity": 2,
"size": 15,
},
],
"source": "<custom-element></custom-element>",
"warningCount": 0,
},
]
`;
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<custom-element></custom-element>`;
markup["correct"] = `<div></div>`;
describe("docs/rules/no-unknown-elements.md", () => {
it("inline validation: incorrect", () => {
const htmlvalidate = new HtmlValidate({"rules":{"no-unknown-elements":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
const htmlvalidate = new HtmlValidate({"rules":{"no-unknown-elements":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
});
@ngdoc rule
@module rules
@name no-unknown-elements
@summary Disallow usage of unknown elements
@description
# Disallow usage of unknown elements (`no-unknown-elements`)
This rule requires all elements to have a corresponding metadata element
describing its content model.
All HTML5 elements are bundled and can be used with:
"extends": ["html5"]
For custom elements (and framework components) you need supply your [own
metadata](../usage/elements.html).
## Rule details
Examples of **incorrect** code for this rule:
<validate name="incorrect" rules="no-unknown-elements">
<custom-element></custom-element>
</validate>
Examples of **correct** code for this rule:
<validate name="correct" rules="no-unknown-elements">
<div></div>
</validate>
......@@ -5967,7 +5967,7 @@ exports[`HTML elements <xmp> valid markup 1`] = `Array []`;
exports[`HTML elements global attributes invalid markup 1`] = `
Array [
Object {
"errorCount": 8,
"errorCount": 9,
"filePath": "test-files/elements/global-attributes-invalid.html",
"messages": Array [
Object {
......@@ -6112,6 +6112,16 @@ Array [
"severity": 2,
"size": 6,
},
Object {
"column": 4,
"context": undefined,
"line": 9,
"message": "Attribute \\"contextmenu\\" is deprecated on <p> element",
"offset": 190,
"ruleId": "no-deprecated-attr",
"severity": 2,
"size": 11,
},
],
"source": "<p contenteditable=\\"foobar\\"></p>
<p dir=\\"\\"></p>
......@@ -6121,6 +6131,7 @@ Array [
<p hidden=\\"foobar\\"></p>
<p tabindex=\\"\\"></p>
<p tabindex=\\"foobar\\"></p>
<p contextmenu=\\"foobar\\"></p>
",
"warningCount": 0,
},
......
......@@ -6,7 +6,8 @@
"draggable": ["true", "false"],
"hidden": [],
"tabindex": ["/-?\\d+/"]
}
},
"deprecatedAttributes": ["contextmenu"]
},
"a": {
......
{
"name": "html-validate",
"version": "1.5.0",
"version": "1.5.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -2534,9 +2534,9 @@
}
},
"@types/jest": {
"version": "24.0.17",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.17.tgz",
"integrity": "sha512-1cy3xkOAfSYn78dsBWy4M3h/QF/HeWPchNFDjysVtp3GHeTdSmtluNnELfCmfNRRHo0OWEcpf+NsEJQvwQfdqQ==",
"version": "24.0.18",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz",
"integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==",
"dev": true,
"requires": {
"@types/jest-diff": "*"
......@@ -4472,9 +4472,9 @@
"dev": true
},
"readdirp": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.1.tgz",
"integrity": "sha512-XXdSXZrQuvqoETj50+JAitxz1UPdt5dupjT6T5nVB+WvjMv2XKYj+s7hPeAVCXvmJrL36O4YYyWlIC3an2ePiQ==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.2.tgz",
"integrity": "sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw==",
"dev": true,
"requires": {
"picomatch": "^2.0.4"
......@@ -5999,9 +5999,9 @@
},
"dependencies": {
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
......@@ -6565,9 +6565,9 @@
}
},
"eslint-config-prettier": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.0.0.tgz",
"integrity": "sha512-vDrcCFE3+2ixNT5H83g28bO/uYAwibJxerXPj+E7op4qzBCsAV36QfvdAyVOoNxKAH2Os/e01T/2x++V0LPukA==",
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.1.0.tgz",
"integrity": "sha512-k9fny9sPjIBQ2ftFTesJV21Rg4R/7a7t7LCtZVrYQiHEp8Nnuk3EGaDmsKSAnsPj0BYcgB2zxzHa2NTkIxcOLg==",
"dev": true,
"requires": {
"get-stdin": "^6.0.0"
......@@ -9013,9 +9013,9 @@
}
},
"husky": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/husky/-/husky-3.0.3.tgz",
"integrity": "sha512-DBBMPSiBYEMx7EVUTRE/ymXJa/lOL+WplcsV/lZu+/HHGt0gzD+5BIz9EJnCrWyUa7hkMuBh7/9OZ04qDkM+Nw==",
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/husky/-/husky-3.0.4.tgz",
"integrity": "sha512-7Rnt8aJfy+MlV28snmYK7O7vWwtOfeVxV6KhLpUFXlmx5ukQ1nQmNUB7QsAwSgdySB5X+bm7q7JIRgazqBUzKA==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
......@@ -12065,9 +12065,9 @@
"dev": true
},
"lint-staged": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.2.1.tgz",
"integrity": "sha512-3lGgJfBddCy/WndKdNko+uJbwyYjBD1k+V+SA+phBYWzH265S95KQya/Wln/UL+hOjc7NcjtFYVCUWuAcqYHhg==",
"version": "9.2.3",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.2.3.tgz",
"integrity": "sha512-ovDmF0c0VJDTP0VmwLetJQ+lVGyNqOkTniwO9S0MOJxGxIExpSRTL56/ZmvXZ1tHNA53GBbXQbfS8RnNGRXFjg==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
......@@ -12080,6 +12080,7 @@
"listr": "^0.14.3",
"log-symbols": "^3.0.0",
"micromatch": "^4.0.2",
"normalize-path": "^3.0.0",
"please-upgrade-node": "^3.1.1",
"string-argv": "^0.3.0",
"stringify-object": "^3.3.0"
......@@ -12122,9 +12123,9 @@
}
},
"execa": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/execa/-/execa-2.0.3.tgz",
"integrity": "sha512-iM124nlyGSrXmuyZF1EMe83ESY2chIYVyDRZKgmcDynid2Q2v/+GuE7gNMl6Sy9Niwf4MC0DDxagOxeMPjuLsw==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/execa/-/execa-2.0.4.tgz",
"integrity": "sha512-VcQfhuGD51vQUQtKIq2fjGDLDbL6N1DTQVpYzxZ7LPIXw3HqTuIz6uxRmpV1qf8i31LHf2kjiaGI+GdHwRgbnQ==",
"dev": true,
"requires": {
"cross-spawn": "^6.0.5",
......@@ -12168,12 +12169,6 @@
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
"dev": true
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"micromatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
......@@ -12196,6 +12191,12 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
"npm-run-path": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz",
......@@ -17528,9 +17529,9 @@
}
},
"please-upgrade-node": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz",
"integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
"integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
"dev": true,
"requires": {
"semver-compare": "^1.0.0"
......@@ -19547,9 +19548,9 @@
}
},
"sass": {
"version": "1.22.9",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.22.9.tgz",
"integrity": "sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ==",
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.22.10.tgz",
"integrity": "sha512-DUpS1tVMGCH6gr/N9cXCoemrjoNdOLhAHfQ37fJw2A5ZM4gSI9ej/8Xi95Xwus03RqZ2zdSnKZGULL7oS+jfMA==",
"dev": true,
"requires": {
"chokidar": ">=2.0.0 <4.0.0"
......
{
"name": "html-validate",
"version": "1.5.0",
"version": "1.5.1",
"description": "html linter",
"keywords": [
"html",
......@@ -35,7 +35,6 @@
"lint": "npm run eslint && npm run tslint",
"prettier:check": "prettier '**/*.{ts,js,json,md,scss}' --list-different",
"prettier:write": "prettier '**/*.{ts,js,json,md,scss}' --write",
"preversion": "./scripts/validate-version",
"semantic-release": "semantic-release",
"start": "grunt connect",
"test": "jest --ci",
......@@ -75,13 +74,13 @@
[
"@semantic-release/changelog",
{
"changelogTitle": "# html-validate changelog\n\n"
"changelogTitle": "# html-validate changelog"
}
],
[
"@semantic-release/exec",
{
"prepare": "npm run prettier:write"
"prepareCmd": "npm run prettier:write"
}
],
[
......@@ -117,7 +116,7 @@
"@types/babel__code-frame": "7.0.1",
"@types/estree": "0.0.39",
"@types/glob": "7.1.1",
"@types/jest": "24.0.17",
"@types/jest": "24.0.18",
"@types/json-merge-patch": "0.0.4",
"@types/minimist": "1.2.0",
"@types/node": "11.13.19",
......@@ -130,7 +129,7 @@
"cssnano": "4.1.10",
"dgeni": "0.4.12",
"dgeni-packages": "0.28.1",
"eslint-config-prettier": "6.0.0",
"eslint-config-prettier": "6.1.0",
"eslint-config-sidvind": "1.3.2",
"eslint-plugin-array-func": "3.1.3",
"eslint-plugin-import": "2.18.2",
......@@ -148,15 +147,15 @@
"grunt-postcss": "0.9.0",
"grunt-sass": "3.1.0",
"highlight.js": "9.15.9",
"husky": "3.0.3",
"husky": "3.0.4",
"jest": "24.9.0",
"jest-diff": "24.9.0",
"jest-junit": "7.0.0",
"jquery": "3.4.1",
"lint-staged": "9.2.1",
"lint-staged": "9.2.3",
"load-grunt-tasks": "5.1.0",
"prettier": "1.18.2",
"sass": "1.22.9",
"sass": "1.22.10",
"semantic-release": "15.13.21",
"serve-static": "1.14.1",
"strip-ansi": "5.2.0",
......
#!/bin/bash
exec > /dev/stderr
branch=$(git rev-parse --abbrev-ref HEAD)
if [[ "$branch" = "HEAD" ]]; then
echo "Must be on a branch when bumping version"
exit 1
fi
dirty_files=$(git status --porcelain 2>/dev/null | grep -v "^??" | wc -l)
if [[ "${dirty_files}" != "0" ]]; then
echo "Working copy must be clean"
exit 1
fi
# prereleases is ok anywhere
if [[ "${npm_package_version}" =~ -[0-9]+$ ]]; then
exit 0
fi
# prevent branches other than master and release/*
if [[ ! "$branch" =~ master|release/.* ]]; then
echo "Can only bump non-prerelease version on master or release/* branches"
exit 1
fi
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rule no-unknown-elements should contain contextual documentation 1`] = `
Object {
"description": "An unknown element <my-element> was used. If this is a Custom Element you need to supply element metadata for it.",
"url": "https://html-validate.org/rules/no-unknown-elements.html",
}
`;
exports[`rule no-unknown-elements should contain documentation 1`] = `
Object {
"description": "An unknown element was used. If this is a Custom Element you need to supply element metadata for it.",
"url": "https://html-validate.org/rules/no-unknown-elements.html",
}
`;
import HtmlValidate from "../htmlvalidate";
import "../matchers";
describe("rule no-unknown-elements", () => {
let htmlvalidate: HtmlValidate;
beforeAll(() => {
htmlvalidate = new HtmlValidate({
rules: { "no-unknown-elements": "error" },
});
});
it("should not report for known elements", () => {
const report = htmlvalidate.validateString("<div></div>");
expect(report).toBeValid();
});
it("should report error for unknown elements", () => {
const report = htmlvalidate.validateString("<my-element></my-element>");
expect(report).toBeInvalid();
expect(report).toHaveError(
"no-unknown-elements",
"Unknown element <my-element>"
);
});
it("should contain documentation", () => {
expect(
htmlvalidate.getRuleDocumentation("no-unknown-elements")
).toMatchSnapshot();
});
it("should contain contextual documentation", () => {
expect(
htmlvalidate.getRuleDocumentation(
"no-unknown-elements",
null,
"my-element"
)
).toMatchSnapshot();
});
});
import { TagOpenEvent } from "../event";
import { Rule, RuleDocumentation, ruleDocumentationUrl } from "../rule";
class NoUnknownElements extends Rule<string> {
public documentation(context: string): RuleDocumentation {
const element = context ? ` <${context}>` : "";
return {
description: `An unknown element${element} was used. If this is a Custom Element you need to supply element metadata for it.`,
url: ruleDocumentationUrl(__filename),
};
}
public setup(): void {
this.on("tag:open", (event: TagOpenEvent) => {
const node = event.target;
if (!node.meta) {
this.report(
node,
`Unknown element <${node.tagName}>`,
null,
node.tagName
);
}
});
}
}
module.exports = NoUnknownElements;
......@@ -6,3 +6,4 @@
<p hidden="foobar"></p>
<p tabindex=""></p>
<p tabindex="foobar"></p>
<p contextmenu="foobar"></p>