Commits (28)
......@@ -68,7 +68,7 @@ Jest:
reports:
junit: temp/jest.xml
script:
- npm test -- src elements
- npm test -- src elements tests
TSLint:
stage: test
......
# html-validate changelog
# [2.17.0](https://gitlab.com/html-validate/html-validate/compare/v2.16.0...v2.17.0) (2020-02-17)
### Bug Fixes
- **elements:** `<img>` `srcset` attribute cannot be empty ([27699ad](https://gitlab.com/html-validate/html-validate/commit/27699ad08d4f9363b275449df3110f36f1b0ee9d))
- **jest:** typescript compatibility with jest@23 ([4efae54](https://gitlab.com/html-validate/html-validate/commit/4efae544dbe9cd499e352776edbde1ea03d83706))
- **rules:** add `aria-label` helper ([6d5d963](https://gitlab.com/html-validate/html-validate/commit/6d5d9630666bec57e70ea3ce563cbef558e2ab3b))
- **rules:** fix `deprecated-rule` missing location ([1156c1e](https://gitlab.com/html-validate/html-validate/commit/1156c1e8b6153ee8ac5691df8f3fdeddfb896255))
- change config merge order in `toHTMLValidate` ([204a8fa](https://gitlab.com/html-validate/html-validate/commit/204a8faac7cfe34b8e0fe2b834124b2b9502e231))
- **rules:** handle `aria-label` on links for WCAG H30 ([eb01542](https://gitlab.com/html-validate/html-validate/commit/eb01542abb0fbf4104672794e621b6bf5564903c)), closes [#67](https://gitlab.com/html-validate/html-validate/issues/67)
### Features
- **rules:** mark `void` as deprecated ([f6afc0f](https://gitlab.com/html-validate/html-validate/commit/f6afc0fd15877695b735754d0eca6dc013252abc)), closes [#58](https://gitlab.com/html-validate/html-validate/issues/58)
- **rules:** new rule `no-self-closing` ([d9c869b](https://gitlab.com/html-validate/html-validate/commit/d9c869b36e3c5c9c4027809417b535bcd565c5cc)), closes [#58](https://gitlab.com/html-validate/html-validate/issues/58)
- **rules:** new rule `script-element` ([48ad6da](https://gitlab.com/html-validate/html-validate/commit/48ad6da1b965d0299d022dbc27c25ebc0ed3ffc8))
- **rules:** new rule `script-type` ([a680f1d](https://gitlab.com/html-validate/html-validate/commit/a680f1d297100c92f08f5d5de2ac39ee27915c15))
- **rules:** new rule `void-content` ([c93c63b](https://gitlab.com/html-validate/html-validate/commit/c93c63b1a3609d90cc493a6cb448b071905926f0)), closes [#58](https://gitlab.com/html-validate/html-validate/issues/58)
- **rules:** new rule `void-style` ([f30de03](https://gitlab.com/html-validate/html-validate/commit/f30de03ea4f8caaf065047d5e3bd44417d0202ad)), closes [#58](https://gitlab.com/html-validate/html-validate/issues/58)
- allow configuration override when using `validate{String,Source}` ([6e62852](https://gitlab.com/html-validate/html-validate/commit/6e62852c88182defbe9b465ab5652f456310d07e))
# [2.16.0](https://gitlab.com/html-validate/html-validate/compare/v2.15.0...v2.16.0) (2020-02-12)
### Bug Fixes
......
......@@ -122,9 +122,9 @@ module.exports = new Package("html-validate-docs", [
docTypes: ["changelog"],
getPath: function(doc) {
const dirname = path.dirname(doc.fileInfo.relativePath);
return path.join(dirname, doc.fileInfo.baseName);
return path.join(dirname, doc.fileInfo.baseName, "index.html");
},
outputPathTemplate: "${path.toLowerCase()}/index.html",
outputPathTemplate: "${path.toLowerCase()}",
});
computePathsProcessor.pathTemplates.push({
......
......@@ -44,14 +44,14 @@ expect("<p></i>").toHTMLValidate({
```
By default configuration is also read from `.htmlvalidate.json` files where the test-case filename is used to match.
If you need to override this (perhaps because the test-case isn't in the same folder) you can pass in a custom filename as the third argument:
This means you can apply transformations using patterns such as `^.*\\.(spec|test).js$`.
If you need to override the filename (perhaps because the test-case isn't in the same folder) you can pass in a custom filename as the third argument:
```js
expect("<p></i>").toHTMLValidate(null, "path/to/my-file.html");
```
This can also be used to apply transformations to the markup.
Additionally, the `root` configuration property can be used to skip loading from `.htmlvalidate.json` but remember to actually include the rules you need:
```js
......
......@@ -124,8 +124,8 @@ Note the usage of a trailing `?`, this limits the allowed occurrences to 0 or 1
Default is to allow any number of occurrences.
Next it uses `permittedOrder` to declare that `<head>` must come before `<body>`.
`permittedOrder` doesnt have to list all the possible elements from `permittedContent` but for the items listed the order must be adhered to.
Contents groups such as `@flow` is allowed and unlisted elements can be used in any anywhere (even inbetween listed elements).
`permittedOrder` doesn't have to list all the possible elements from `permittedContent` but for the items listed the order must be adhered to.
Contents groups such as `@flow` is allowed and unlisted elements can be used in any anywhere (even between listed elements).
Lastly it uses `requiredContent` to declare that both `<head>` and `<body>` must be present.
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/no-self-closing.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/no-self-closing.md inline validation: foreign 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 5,
"context": "svg",
"line": 1,
"message": "<svg> must not be self-closed",
"offset": 4,
"ruleId": "no-self-closing",
"selector": "svg",
"severity": 2,
"size": 2,
},
],
"source": "<svg/>",
"warningCount": 0,
},
]
`;
exports[`docs/rules/no-self-closing.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 5,
"context": "div",
"line": 1,
"message": "<div> must not be self-closed",
"offset": 4,
"ruleId": "no-self-closing",
"selector": "div",
"severity": 2,
"size": 2,
},
],
"source": "<div/>",
"warningCount": 0,
},
]
`;
exports[`docs/rules/no-self-closing.md inline validation: xml 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 12,
"context": "xi:include",
"line": 1,
"message": "<xi:include> must not be self-closed",
"offset": 11,
"ruleId": "no-self-closing",
"selector": "xi:include",
"severity": 2,
"size": 2,
},
],
"source": "<xi:include/>",
"warningCount": 0,
},
]
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/script-element.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/script-element.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 26,
"context": undefined,
"line": 1,
"message": "End tag for <script> must not be omitted",
"offset": 25,
"ruleId": "script-element",
"selector": "script",
"severity": 2,
"size": 2,
},
],
"source": "<script src=\\"myscript.js\\"/>",
"warningCount": 0,
},
]
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/script-type.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/script-type.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 3,
"filePath": "inline",
"messages": Array [
Object {
"column": 9,
"context": undefined,
"line": 1,
"message": "\\"type\\" attribute is unnecessary for javascript resources",
"offset": 8,
"ruleId": "script-type",
"selector": "script",
"severity": 2,
"size": 4,
},
Object {
"column": 9,
"context": undefined,
"line": 2,
"message": "\\"type\\" attribute is unnecessary for javascript resources",
"offset": 34,
"ruleId": "script-type",
"selector": "script:nth-child(2)",
"severity": 2,
"size": 4,
},
Object {
"column": 9,
"context": undefined,
"line": 3,
"message": "\\"type\\" attribute is unnecessary for javascript resources",
"offset": 75,
"ruleId": "script-type",
"selector": "script:nth-child(3)",
"severity": 2,
"size": 4,
},
],
"source": "<script type=\\"\\"></script>
<script type=\\"text/javascript\\"></script>
<script type=\\"application/javascript\\"></script>",
"warningCount": 0,
},
]
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/void-content.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/void-content.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 7,
"context": "img",
"line": 1,
"message": "End tag for <img> must be omitted",
"offset": 6,
"ruleId": "void-content",
"selector": null,
"severity": 2,
"size": 4,
},
],
"source": "<img></img>",
"warningCount": 0,
},
]
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/void-content.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/void-content.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 7,
"context": "img",
"line": 1,
"message": "End tag for <img> must be omitted",
"offset": 6,
"ruleId": "void-content",
"selector": null,
"severity": 2,
"size": 4,
},
],
"source": "<img></img>
<div/>",
"warningCount": 0,
},
]
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/void-style.md inline validation: correct 1`] = `Array []`;
exports[`docs/rules/void-style.md inline validation: incorrect 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 7,
"context": Object {
"style": 1,
"tagName": "input",
},
"line": 1,
"message": "Expected omitted end tag <input> instead of self-closing element <input/>",
"offset": 6,
"ruleId": "void-style",
"selector": "input",
"severity": 2,
"size": 2,
},
],
"source": "<input/>",
"warningCount": 0,
},
]
`;
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<div/>`;
markup["correct"] = `<div></div>
<!-- foreign elements are ignored -->
<svg/>
<!-- elements with XML namespace are ignored -->
<xi:include/>`;
markup["foreign"] = `<svg/>`;
markup["xml"] = `<xi:include/>`;
describe("docs/rules/no-self-closing.md", () => {
it("inline validation: incorrect", () => {
const htmlvalidate = new HtmlValidate({"rules":{"no-self-closing":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
const htmlvalidate = new HtmlValidate({"rules":{"no-self-closing":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: foreign", () => {
const htmlvalidate = new HtmlValidate({"rules":{"no-self-closing":["error",{"ignoreForeign":false}]}});
const report = htmlvalidate.validateString(markup["foreign"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: xml", () => {
const htmlvalidate = new HtmlValidate({"rules":{"no-self-closing":["error",{"ignoreXML":false}]}});
const report = htmlvalidate.validateString(markup["xml"]);
expect(report.results).toMatchSnapshot();
});
});
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<script src="myscript.js"/>`;
markup["correct"] = `<script src="myscript.js"></script>`;
describe("docs/rules/script-element.md", () => {
it("inline validation: incorrect", () => {
const htmlvalidate = new HtmlValidate({"rules":{"script-element":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
const htmlvalidate = new HtmlValidate({"rules":{"script-element":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
});
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<script type=""></script>
<script type="text/javascript"></script>
<script type="application/javascript"></script>`;
markup["correct"] = `<script></script>
<script type="module"></script>
<script type="text/plain"></script>
<script type="text/x-custom"></script>`;
describe("docs/rules/script-type.md", () => {
it("inline validation: incorrect", () => {
const htmlvalidate = new HtmlValidate({"rules":{"script-type":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
const htmlvalidate = new HtmlValidate({"rules":{"script-type":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
});
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<img></img>`;
markup["correct"] = `<img>
<img/>`;
describe("docs/rules/void-content.md", () => {
it("inline validation: incorrect", () => {
const htmlvalidate = new HtmlValidate({"rules":{"void-content":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
const htmlvalidate = new HtmlValidate({"rules":{"void-content":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
});
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<img></img>
<div/>`;
markup["correct"] = `<img>
<div></div>`;
describe("docs/rules/void-content.md", () => {
it("inline validation: incorrect", () => {
const htmlvalidate = new HtmlValidate({"rules":{"void-content":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
const htmlvalidate = new HtmlValidate({"rules":{"void-content":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
});
import HtmlValidate from "../../../src/htmlvalidate";
const markup: { [key: string]: string } = {};
markup["incorrect"] = `<input/>`;
markup["correct"] = `<input>`;
describe("docs/rules/void-style.md", () => {
it("inline validation: incorrect", () => {
const htmlvalidate = new HtmlValidate({"rules":{"void-style":"error"}});
const report = htmlvalidate.validateString(markup["incorrect"]);
expect(report.results).toMatchSnapshot();
});
it("inline validation: correct", () => {
const htmlvalidate = new HtmlValidate({"rules":{"void-style":"error"}});
const report = htmlvalidate.validateString(markup["correct"]);
expect(report.results).toMatchSnapshot();
});
});
---
docType: rule
name: no-self-closing
category: style
summary: Disallow self-closing elements
---
# Disallow self-closing elements (`no-self-closing`)
Require regular end tags for elements even if the element has no content, e.g. require `<div></div>` instead of `<div/>`.
This rule has no effect on void elements, see the related rule {@link void-style}.
## Rule details
Examples of **incorrect** code for this rule:
<validate name="incorrect" rules="no-self-closing">
<div/>
</validate>
Examples of **correct** code for this rule:
<validate name="correct" rules="no-self-closing">
<div></div>
<!-- foreign elements are ignored -->
<svg/>
<!-- elements with XML namespace are ignored -->
<xi:include/>
</validate>
## Options
This rule takes an optional object:
```json
{
"ignoreForeign": true,
"ignoreXML": true
}
```
### `ignoreForeign`
By default foreign elements are ignored by this rule.
By setting `ignoreForeign` to `false` foreign elements must not be self-closed either.
<validate name="foreign" rules="no-self-closing" no-self-closing='{"ignoreForeign": false}'>
<svg/>
</validate>
### `ignoreXML`
By default elements in XML namespaces are ignored by this rule.
By setting `ignoreXML` to `false` elements in XML namespaces must not be self-closed either.
<validate name="xml" rules="no-self-closing" no-self-closing='{"ignoreXML": false}'>
<xi:include/>
</validate>
---
docType: rule
name: script-element
category: content-model
summary: Require end tag for `<script>`
---
# Require end tag for `<script>` element (`script-element`)
For legacy reasons the `<script>` element must include a `</script>` end tag even when using the `src` attribute.
## Rule details
Examples of **incorrect** code for this rule:
<validate name="incorrect" rules="script-element">
<script src="myscript.js"/>
</validate>
Examples of **correct** code for this rule:
<validate name="correct" rules="script-element">
<script src="myscript.js"></script>
</validate>
---
docType: rule
name: script-type
summary: Require valid type for `<script>`
---
# Require valid type for `<script>` element (`script-type`)
The [HTML5 standard encourages][spec] omitting the `type` attribute when the script is a JavaScript resource and only use it to specify `module` or other non-javascript MIME types.
[spec]: https://html.spec.whatwg.org/multipage/scripting.html#attr-script-type
## Rule details
Examples of **incorrect** code for this rule:
<validate name="incorrect" rules="script-type">
<script type=""></script>
<script type="text/javascript"></script>
<script type="application/javascript"></script>
</validate>
Examples of **correct** code for this rule:
<validate name="correct" rules="script-type">
<script></script>
<script type="module"></script>
<script type="text/plain"></script>
<script type="text/x-custom"></script>
</validate>