Skip to content
GitLab
About GitLab
GitLab: the DevOps platform
Explore GitLab
Install GitLab
How GitLab compares
Get started
GitLab docs
GitLab Learn
Pricing
Talk to an expert
/
Help
What's new
2
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Projects
Groups
Snippets
Sign up now
Login
Sign in / Register
Toggle navigation
Menu
Open sidebar
html-validate
html-validate
Commits
d8762060
Commit
d8762060
authored
Apr 11, 2020
by
David Sveningsson
Browse files
feat(rules): new rule allowed-links
parent
f251a361
Pipeline
#182395040
passed with stages
in 9 minutes and 31 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
docs/rules/__tests__/__snapshots__/allowed-links.md.spec.ts.snap
0 → 100644
View file @
d8762060
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs/rules/allowed-links.md inline validation: absolute-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "absolute",
"line": 1,
"message": "Link destination must not be absolute url",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 4,
},
],
"source": "<a href=\\"/foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: absolute-valid 1`] = `Array []`;
exports[`docs/rules/allowed-links.md inline validation: base-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "relative-base",
"line": 1,
"message": "Relative links must be relative to current folder",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 3,
},
],
"source": "<a href=\\"foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: base-valid 1`] = `Array []`;
exports[`docs/rules/allowed-links.md inline validation: external-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "external",
"line": 1,
"message": "Link destination must not be external url",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 22,
},
],
"source": "<a href=\\"http://example.net/foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: external-valid 1`] = `Array []`;
exports[`docs/rules/allowed-links.md inline validation: relative-invalid 1`] = `
Array [
Object {
"errorCount": 1,
"filePath": "inline",
"messages": Array [
Object {
"column": 10,
"context": "relative-path",
"line": 1,
"message": "Link destination must not be relative url",
"offset": 9,
"ruleId": "allowed-links",
"selector": "a",
"severity": 2,
"size": 6,
},
],
"source": "<a href=\\"../foo\\">",
"warningCount": 0,
},
]
`;
exports[`docs/rules/allowed-links.md inline validation: relative-valid 1`] = `Array []`;
docs/rules/__tests__/allowed-links.md.spec.ts
0 → 100644
View file @
d8762060
import
HtmlValidate
from
"
../../../src/htmlvalidate
"
;
const
markup
:
{
[
key
:
string
]:
string
}
=
{};
markup
[
"
external-invalid
"
]
=
`<a href="http://example.net/foo">`
;
markup
[
"
external-valid
"
]
=
`<a href="./foo">`
;
markup
[
"
relative-invalid
"
]
=
`<a href="../foo">`
;
markup
[
"
relative-valid
"
]
=
`<a href="/foo">`
;
markup
[
"
absolute-invalid
"
]
=
`<a href="/foo">`
;
markup
[
"
absolute-valid
"
]
=
`<a href="../foo">`
;
markup
[
"
base-invalid
"
]
=
`<a href="foo">`
;
markup
[
"
base-valid
"
]
=
`<a href="./foo">`
;
describe
(
"
docs/rules/allowed-links.md
"
,
()
=>
{
it
(
"
inline validation: external-invalid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowExternal
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
external-invalid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: external-valid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowExternal
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
external-valid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: relative-invalid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowRelative
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
relative-invalid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: relative-valid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowRelative
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
relative-valid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: absolute-invalid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowAbsolute
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
absolute-invalid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: absolute-valid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowAbsolute
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
absolute-valid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: base-invalid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowBase
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
base-invalid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
it
(
"
inline validation: base-valid
"
,
()
=>
{
expect
.
assertions
(
1
);
const
htmlvalidate
=
new
HtmlValidate
({
"
rules
"
:{
"
allowed-links
"
:[
"
error
"
,{
"
allowBase
"
:
false
}]}});
const
report
=
htmlvalidate
.
validateString
(
markup
[
"
base-valid
"
]);
expect
(
report
.
results
).
toMatchSnapshot
();
});
});
docs/rules/allowed-links.md
0 → 100644
View file @
d8762060
---
docType
:
rule
name
:
allowed-links
category
:
document
summary
:
Disallow link types
---
# Disallows link types (`allowed-links`)
This rules checks the link destination and disallows certain categories of links:
-
External links
-
Relative paths
-
Relative to document base url
The rule checks links from:
-
`<a href=""></a>`
-
`<img src="..">`
-
`<link src="..">`
-
`<script src=".."></script>`
Anchor links are ignored by this rule.
## Rule details
This rules requires additional configuration to yield errors.
By default all links are allowed even when this rule is enabled.
## Options
This rule takes an optional object:
```
json
{
"allowExternal"
:
true
,
"allowRelative"
:
true
,
"allowAbsolute"
:
true
,
"allowBase"
:
true
}
```
### `allowExternal`
By setting
`allowExternal`
to
`false`
any link to a external resource will be disallowed.
<validate
name=
"external-invalid"
rules=
"allowed-links"
allowed-links=
'{"allowExternal": false}'
>
<a
href=
"http://example.net/foo"
>
</validate>
<validate
name=
"external-valid"
rules=
"allowed-links"
allowed-links=
'{"allowExternal": false}'
>
<a
href=
"./foo"
>
</validate>
### `allowRelative`
By setting
`allowRelative`
to
`false`
any link with a relative url will be disallowed.
<validate
name=
"relative-invalid"
rules=
"allowed-links"
allowed-links=
'{"allowRelative": false}'
>
<a
href=
"../foo"
>
</validate>
<validate
name=
"relative-valid"
rules=
"allowed-links"
allowed-links=
'{"allowRelative": false}'
>
<a
href=
"/foo"
>
</validate>
### `allowAbsolute`
By setting
`allowAbsolute`
to
`false`
any link with a absolute url will be disallowed.
<validate
name=
"absolute-invalid"
rules=
"allowed-links"
allowed-links=
'{"allowAbsolute": false}'
>
<a
href=
"/foo"
>
</validate>
<validate
name=
"absolute-valid"
rules=
"allowed-links"
allowed-links=
'{"allowAbsolute": false}'
>
<a
href=
"../foo"
>
</validate>
### `allowBase`
By setting
`allowBase`
to
`false`
relative urls can be used only if using an explicit path but not when relative to document base url.
This is useful when wanting to use relative urls but not rely on
`<base href="..">`
being set correctly.
Effectively this also means that links to files in the same folder must use
`./target`
even if
`target`
is valid.
<validate
name=
"base-invalid"
rules=
"allowed-links"
allowed-links=
'{"allowBase": false}'
>
<a
href=
"foo"
>
</validate>
<validate
name=
"base-valid"
rules=
"allowed-links"
allowed-links=
'{"allowBase": false}'
>
<a
href=
"./foo"
>
</validate>
src/rules/__snapshots__/allowed-links.spec.ts.snap
0 → 100644
View file @
d8762060
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rule allowed-links should contain contextual documentation absolute 1`] = `
Object {
"description": "Absolute links are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain contextual documentation external 1`] = `
Object {
"description": "External links are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain contextual documentation relative to base 1`] = `
Object {
"description": "Links relative to <base> are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain contextual documentation relative to path 1`] = `
Object {
"description": "Relative links are not allowed by current configuration.",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
exports[`rule allowed-links should contain documentation 1`] = `
Object {
"description": "This link type is not allowed by current configuration",
"url": "https://html-validate.org/rules/allowed-links.html",
}
`;
src/rules/allowed-links.spec.ts
0 → 100644
View file @
d8762060
import
HtmlValidate
from
"
../htmlvalidate
"
;
import
"
../matchers
"
;
import
{
processAttribute
}
from
"
../transform/mocks/attribute
"
;
import
{
Style
}
from
"
./allowed-links
"
;
describe
(
"
rule allowed-links
"
,
()
=>
{
let
htmlvalidate
:
HtmlValidate
;
describe
(
"
should report error for
"
,
()
=>
{
it
.
each
`
description | markup
${
"
<a href>
"
}
|
${
'
<a href="/foo"></a>
'
}
${
"
<img src>
"
}
|
${
'
<img src="/foo">
'
}
${
"
<link href>
"
}
|
${
'
<link href="/foo">
'
}
${
"
<script src>
"
}
|
${
'
<script src="/foo"></script>
'
}
`
(
"
$description
"
,
({
markup
})
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
[
"
error
"
,
{
allowAbsolute
:
false
}]
},
});
const
report
=
htmlvalidate
.
validateString
(
markup
);
expect
(
report
).
toBeInvalid
();
});
});
it
(
"
should not report error for anchor links
"
,
()
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
[
"
error
"
,
{
allowAbsolute
:
false
}]
},
});
const
report
=
htmlvalidate
.
validateString
(
'
<a href="#foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error for link is dynamic
"
,
()
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
[
"
error
"
,
{
allowRelative
:
false
}],
},
});
const
report
=
htmlvalidate
.
validateString
(
'
<a dynamic-src="{{ expr }}"></a>
'
,
null
,
{
processAttribute
,
}
);
expect
(
report
).
toBeValid
();
});
describe
(
"
allowExternal: false
"
,
()
=>
{
beforeAll
(()
=>
{
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
[
"
error
"
,
{
allowExternal
:
false
}]
},
});
});
it
(
"
should report error when link is external using //
"
,
()
=>
{
expect
.
assertions
(
2
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="//example.net/foo"></a>
'
);
expect
(
report
).
toBeInvalid
();
expect
(
report
).
toHaveError
(
"
allowed-links
"
,
"
Link destination must not be external url
"
);
});
it
(
"
should report error when link is external using protocol://
"
,
()
=>
{
expect
.
assertions
(
2
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="http://example.net/foo"></a>
'
);
expect
(
report
).
toBeInvalid
();
expect
(
report
).
toHaveError
(
"
allowed-links
"
,
"
Link destination must not be external url
"
);
});
it
(
"
should not report error link is absolute
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error link is relative to path
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="./foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error link is relative to base
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
});
describe
(
"
allowRelative: false
"
,
()
=>
{
beforeAll
(()
=>
{
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
[
"
error
"
,
{
allowRelative
:
false
}]
},
});
});
it
(
"
should not report error when link is external using //
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="//example.net/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error when link is external using protocol://
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="http://example.net/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error link is absolute
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should report error link is relative to path
"
,
()
=>
{
expect
.
assertions
(
2
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="./foo"></a>
'
);
expect
(
report
).
toBeInvalid
();
expect
(
report
).
toHaveError
(
"
allowed-links
"
,
"
Link destination must not be relative url
"
);
});
it
(
"
should report error link is relative to base
"
,
()
=>
{
expect
.
assertions
(
2
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="foo"></a>
'
);
expect
(
report
).
toBeInvalid
();
expect
(
report
).
toHaveError
(
"
allowed-links
"
,
"
Link destination must not be relative url
"
);
});
});
describe
(
"
allowBase: false
"
,
()
=>
{
beforeAll
(()
=>
{
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
[
"
error
"
,
{
allowBase
:
false
}]
},
});
});
it
(
"
should not report error when link is external using //
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="//example.net/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error when link is external using protocol://
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="http://example.net/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error link is absolute
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error link is relative to path
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="./foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should report error link is relative to base
"
,
()
=>
{
expect
.
assertions
(
2
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="foo"></a>
'
);
expect
(
report
).
toBeInvalid
();
expect
(
report
).
toHaveError
(
"
allowed-links
"
,
"
Relative links must be relative to current folder
"
);
});
});
describe
(
"
allowAbsolute: false
"
,
()
=>
{
beforeAll
(()
=>
{
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
[
"
error
"
,
{
allowAbsolute
:
false
}]
},
});
});
it
(
"
should not report error when link is external using //
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="//example.net/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should not report error when link is external using protocol://
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="http://example.net/foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should report error link is absolute
"
,
()
=>
{
expect
.
assertions
(
2
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="/foo"></a>
'
);
expect
(
report
).
toBeInvalid
();
expect
(
report
).
toHaveError
(
"
allowed-links
"
,
"
Link destination must not be absolute url
"
);
});
it
(
"
should not report error link is relative to path
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="./foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
it
(
"
should report error link is relative to base
"
,
()
=>
{
expect
.
assertions
(
1
);
const
report
=
htmlvalidate
.
validateString
(
'
<a href="foo"></a>
'
);
expect
(
report
).
toBeValid
();
});
});
it
(
"
should contain documentation
"
,
()
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
"
error
"
},
});
expect
(
htmlvalidate
.
getRuleDocumentation
(
"
allowed-links
"
)
).
toMatchSnapshot
();
});
describe
(
"
should contain contextual documentation
"
,
()
=>
{
it
.
each
`
style | value
${
"
external
"
}
|
${
Style
.
EXTERNAL
}
${
"
relative to base
"
}
|
${
Style
.
RELATIVE_BASE
}
${
"
relative to path
"
}
|
${
Style
.
RELATIVE_PATH
}
${
"
absolute
"
}
|
${
Style
.
ABSOLUTE
}
`
(
"
$style
"
,
({
value
})
=>
{
expect
.
assertions
(
1
);
htmlvalidate
=
new
HtmlValidate
({
rules
:
{
"
allowed-links
"
:
"
error
"
},
});
expect
(
htmlvalidate
.
getRuleDocumentation
(
"
allowed-links
"
,
null
,
value
)
).
toMatchSnapshot
();
});
});
});
src/rules/allowed-links.ts
0 → 100644
View file @
d8762060
import
{
DynamicValue
}
from
"
../dom
"
;
import
{
AttributeEvent
}
from
"
../event
"
;
import
{
Rule
,
RuleDocumentation
,
ruleDocumentationUrl
}
from
"
../rule
"
;
export
const
enum
Style
{
EXTERNAL
=
"
external
"
,
RELATIVE_BASE
=
"
relative-base
"
,
RELATIVE_PATH
=
"
relative-path
"
,
ABSOLUTE
=
"
absolute
"
,
ANCHOR
=
"
anchor
"
,
}
interface
RuleOptions
{
allowExternal
:
boolean
;
allowRelative
:
boolean
;
allowAbsolute
:
boolean
;
allowBase
:
boolean
;
}
const
defaults
:
RuleOptions
=
{
allowExternal
:
true
,
allowRelative
:
true
,
allowAbsolute
:
true
,
allowBase
:
true
,