@markuplint/types 4.0.0-alpha.1 → 4.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +63 -61
- package/lib/css-syntax.js +16 -11
- package/lib/defs.d.ts +1 -0
- package/lib/defs.js +172 -52
- package/lib/enum.js +1 -1
- package/lib/get-candidate.js +2 -2
- package/lib/keyword-type.js +3 -3
- package/lib/number.d.ts +2 -2
- package/lib/number.js +2 -2
- package/lib/primitive/is-float.js +1 -1
- package/lib/primitive/is-int.js +1 -1
- package/lib/primitive/is-non-zero-uint.js +1 -1
- package/lib/primitive/is-uint.js +3 -3
- package/lib/primitive/range.js +2 -2
- package/lib/primitive/split-unit.js +1 -1
- package/lib/token/token-collection.d.ts +4 -5
- package/lib/token/token-collection.js +23 -18
- package/lib/token/token.d.ts +1 -1
- package/lib/token/token.js +9 -8
- package/lib/types.d.ts +1 -0
- package/lib/types.schema.d.ts +1 -1
- package/lib/w3c/check-serialized-permissions-policy.js +5 -5
- package/lib/whatwg/check-autocomplete.js +10 -13
- package/lib/whatwg/check-datetime/date-string.js +3 -3
- package/lib/whatwg/check-datetime/datetime-tokens.js +18 -18
- package/lib/whatwg/check-datetime/duration-string.js +30 -29
- package/lib/whatwg/check-datetime/global-date-and-time-string.js +8 -8
- package/lib/whatwg/check-datetime/local-date-and-time-string.js +17 -16
- package/lib/whatwg/check-datetime/month-string.js +1 -1
- package/lib/whatwg/check-datetime/time-string.js +4 -4
- package/lib/whatwg/check-datetime/time-zone-offset-string.js +6 -6
- package/lib/whatwg/check-datetime/week-string.js +2 -2
- package/lib/whatwg/check-datetime/yearless-date-string.js +2 -2
- package/lib/whatwg/is-abs-url.js +7 -7
- package/lib/whatwg/is-browser-context-name.d.ts +2 -0
- package/lib/whatwg/is-browser-context-name.js +2 -0
- package/lib/whatwg/is-custom-element-name.d.ts +9 -4
- package/lib/whatwg/is-custom-element-name.js +21 -33
- package/lib/whatwg/is-navigable-target-name.d.ts +11 -0
- package/lib/whatwg/is-navigable-target-name.js +20 -0
- package/package.json +12 -9
- package/types.schema.json +3 -0
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -33,67 +33,69 @@ check('2020-02-30', 'DateTime');
|
|
|
33
33
|
|
|
34
34
|
## Type Identifiers
|
|
35
35
|
|
|
36
|
-
| Identifier
|
|
37
|
-
|
|
|
38
|
-
| `Any`
|
|
39
|
-
| `NoEmptyAny`
|
|
40
|
-
| `OneLineAny`
|
|
41
|
-
| `Zero`
|
|
42
|
-
| `Number`
|
|
43
|
-
| `Uint`
|
|
44
|
-
| `XMLName`
|
|
45
|
-
| `DOMID`
|
|
46
|
-
| `FunctionBody`
|
|
47
|
-
| `Pattern`
|
|
48
|
-
| `DateTime`
|
|
49
|
-
| `TabIndex`
|
|
50
|
-
| `BCP47`
|
|
51
|
-
| `URL`
|
|
52
|
-
| `AbsoluteURL`
|
|
53
|
-
| `HashName`
|
|
54
|
-
| `OneCodePointChar`
|
|
55
|
-
| `CustomElementName`
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
| `<
|
|
70
|
-
| `<
|
|
71
|
-
| `<
|
|
72
|
-
| `<
|
|
73
|
-
| `<'
|
|
74
|
-
| `<
|
|
75
|
-
| `<
|
|
76
|
-
| `<
|
|
77
|
-
| `<
|
|
78
|
-
| `<
|
|
79
|
-
| `<
|
|
80
|
-
| `<
|
|
81
|
-
| `<
|
|
82
|
-
| `<
|
|
83
|
-
| `<
|
|
84
|
-
| `<key-
|
|
85
|
-
| `<
|
|
86
|
-
| `<
|
|
87
|
-
| `<
|
|
88
|
-
| `<
|
|
89
|
-
| `<
|
|
90
|
-
| `<
|
|
91
|
-
| `<
|
|
92
|
-
| `<
|
|
93
|
-
| `<
|
|
94
|
-
| `<
|
|
95
|
-
| `<list-of-
|
|
96
|
-
| `<
|
|
36
|
+
| Identifier | Use on | Spec | Supported |
|
|
37
|
+
| ---------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | --------- |
|
|
38
|
+
| `Any` | Some attributes | | ✅ |
|
|
39
|
+
| `NoEmptyAny` | Some attributes | | ✅ |
|
|
40
|
+
| `OneLineAny` | Some attributes | | ✅ |
|
|
41
|
+
| `Zero` | Some attributes | | ✅ |
|
|
42
|
+
| `Number` | Some attributes | | ✅ |
|
|
43
|
+
| `Uint` | Some attributes | | ✅ |
|
|
44
|
+
| `XMLName` | `svg\|[attributeName]` and more | [XML](https://www.w3.org/TR/xml/#d0e804) | ✅ |
|
|
45
|
+
| `DOMID` | The `id` attribute and more | [WHATWG](https://html.spec.whatwg.org/multipage/dom.html#global-attributes:concept-id) | ✅ |
|
|
46
|
+
| `FunctionBody` | Event handler attributes | | 🚧 |
|
|
47
|
+
| `Pattern` | `input[pattern]` | [WHATWG](https://html.spec.whatwg.org/multipage/input.html#compiled-pattern-regular-expression) | ✅ |
|
|
48
|
+
| `DateTime` | `time[datetime]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/text-level-semantics.html#datetime-value) | ✅ |
|
|
49
|
+
| `TabIndex` | The `tabindex` attribute | [WHATWG](https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex) | ✅ |
|
|
50
|
+
| `BCP47` | The `lang` attribute and more | [RFC](https://tools.ietf.org/rfc/bcp/bcp47.html) | ✅ |
|
|
51
|
+
| `URL` | Some attributes | [WHATWG](https://html.spec.whatwg.org/multipage/urls-and-fetching.html#valid-url-potentially-surrounded-by-spaces) | ✅ |
|
|
52
|
+
| `AbsoluteURL` | The `itemtype` attribute (as list) | [WHATWG](https://url.spec.whatwg.org/#syntax-url-absolute) | ✅ |
|
|
53
|
+
| `HashName` | `img[usemap]` | [WHATWG](https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-hash-name-reference) | ✅ |
|
|
54
|
+
| `OneCodePointChar` | The `accesskey` attribute (as list) | [WHATWG](https://html.spec.whatwg.org/multipage/interaction.html#the-accesskey-attribute) | ✅ |
|
|
55
|
+
| `CustomElementName` | The `is` attribute | [WHATWG](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) | ✅ |
|
|
56
|
+
| ~~`BrowsingContextName`~~ | Use `NavigableTargetName` instead. | **Obsolated** | ✅ |
|
|
57
|
+
| ~~`BrowsingContextNameOrKeyword`~~ | Use `NavigableTargetNameOrKeyword` instead. | **Obsolated** | ✅ |
|
|
58
|
+
| `NavigableTargetName` | `iframe[name]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/document-sequences.html#valid-navigable-target-name) | ✅ |
|
|
59
|
+
| `NavigableTargetNameOrKeyword` | `a[target]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/document-sequences.html#valid-navigable-target-name-or-keyword) | ✅ |
|
|
60
|
+
| `HTTPSchemaURL` | `a[ping]` (as list) and more | [WHATWG](https://html.spec.whatwg.org/multipage/links.html#ping) | ✅ |
|
|
61
|
+
| `MIMEType` | `embed[type]` and more | [WHATWG](https://mimesniff.spec.whatwg.org/#valid-mime-type) | ✅ |
|
|
62
|
+
| `ItemProp` | The `itemprop` attribute (as list) | [WHATWG](https://html.spec.whatwg.org/multipage/microdata.html#names:-the-itemprop-attribute) | ✅ |
|
|
63
|
+
| `Srcset` | `img[srcset]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/images.html#srcset-attributes) | ✅ |
|
|
64
|
+
| `SourceSizeList` | `img[sizes]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/images.html#sizes-attributes) | ✅ |
|
|
65
|
+
| `IconSize` | `link[sizes]` (as list) | [WHATWG](https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes) | ✅ |
|
|
66
|
+
| `AutoComplete` | `input[autocomplete]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete) | ✅ |
|
|
67
|
+
| `Accept` | `input[accept]` | [WHATWG](https://html.spec.whatwg.org/multipage/input.html#attr-input-accept) | ✅ |
|
|
68
|
+
| `SerializedPermissionsPolicy` | `iframe[allow]` | [W3C](https://w3c.github.io/webappsec-permissions-policy/#serialized-permissions-policy) | ✅ |
|
|
69
|
+
| `<css-declaration-list>` | The `style` attribute | [CSS](https://drafts.csswg.org/css-style-attr/#syntax) | ✅ |
|
|
70
|
+
| `<class-list>` | The `class` attribute | [SVG](https://www.w3.org/TR/SVG/styling.html#ClassAttribute) | ✅ |
|
|
71
|
+
| `<svg-font-size>` | Some attributes for SVG | [CSS](https://drafts.csswg.org/css-fonts-5/#descdef-font-face-font-size) | 🚧 |
|
|
72
|
+
| `<svg-font-size-adjust>` | Some attributes for SVG | [CSS](https://drafts.csswg.org/css-fonts-5/#propdef-font-size-adjust) | 🚧 |
|
|
73
|
+
| `<'color-profile'>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/color.html#ColorProfileProperty) | 🚧 |
|
|
74
|
+
| `<'color-rendering'>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/painting.html#ColorRenderingProperty) | 🚧 |
|
|
75
|
+
| `<'enable-background'>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/filters.html#EnableBackgroundProperty) | 🚧 |
|
|
76
|
+
| `<list-of-svg-feature-string>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/feature.html) | 🚧 |
|
|
77
|
+
| `<animatable-value>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#FromAttribute) | 🚧 |
|
|
78
|
+
| `<begin-value-list>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#BeginValueListSyntax) | 🚧 |
|
|
79
|
+
| `<end-value-list>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#EndValueListSyntax) | 🚧 |
|
|
80
|
+
| `<list-of-value>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#ValuesAttribute) | 🚧 |
|
|
81
|
+
| `<clock-value>` | Some attributes for SVG | [SMIL](https://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-ClockValueSyntax) | 🚧 |
|
|
82
|
+
| `<color-matrix>` | Some attributes for SVG | [W3C](https://drafts.fxtf.org/filter-effects/#element-attrdef-fecolormatrix-values) | ✅ |
|
|
83
|
+
| `<dasharray>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/painting.html#StrokeDasharrayProperty) | ✅ |
|
|
84
|
+
| `<key-points>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#KeyPointsAttribute) | ✅ |
|
|
85
|
+
| `<key-splines>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#KeyTimesAttribute) | ✅ |
|
|
86
|
+
| `<key-times>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#KeyTimesAttribute) | ✅ |
|
|
87
|
+
| `<system-language>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/struct.html#SystemLanguageAttribute) | ✅ |
|
|
88
|
+
| `<origin>` | Some attributes for SVG | [SMIL](https://www.w3.org/TR/2001/REC-smil-animation-20010904/#MotionOriginAttribute) | ✅ |
|
|
89
|
+
| `<svg-path>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/paths.html#PathDataBNF) | 🚧 |
|
|
90
|
+
| `<points>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/shapes.html#DataTypePoints) | ✅ |
|
|
91
|
+
| `<preserve-aspect-ratio>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/coords.html#PreserveAspectRatioAttribute) | ✅ |
|
|
92
|
+
| `<view-box>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/coords.html#ViewBoxAttribute) | ✅ |
|
|
93
|
+
| `<rotate>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#RotateAttribute) | ✅ |
|
|
94
|
+
| `<text-coordinate>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/text.html#TSpanAttributes) | ✅ |
|
|
95
|
+
| `<list-of-lengths>` | Some attributes for SVG | | ✅ |
|
|
96
|
+
| `<list-of-numbers>` | Some attributes for SVG | | ✅ |
|
|
97
|
+
| `<list-of-percentages>` | Some attributes for SVG | | ✅ |
|
|
98
|
+
| `<number-optional-number>` | Some attributes for SVG | | ✅ |
|
|
97
99
|
|
|
98
100
|
In addition, you can use types **[CSSTree](https://github.com/csstree/csstree)** defined.
|
|
99
101
|
|
package/lib/css-syntax.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fork } from 'css-tree';
|
|
2
2
|
import { log } from './debug.js';
|
|
3
|
-
import { tokenizers } from './defs.js';
|
|
3
|
+
import { tokenizers, overrides } from './defs.js';
|
|
4
4
|
import { matched } from './match-result.js';
|
|
5
5
|
const MIMIC_TAG_L = 'mimiccases---';
|
|
6
6
|
const MIMIC_TAG_R = '---mimiccases';
|
|
@@ -30,7 +30,7 @@ export function cssSyntaxMatch(value, type) {
|
|
|
30
30
|
...tokenizers,
|
|
31
31
|
...type.syntax.def,
|
|
32
32
|
};
|
|
33
|
-
Object.keys(types)
|
|
33
|
+
for (const key of Object.keys(types)) {
|
|
34
34
|
const valueOrChecker = types[key];
|
|
35
35
|
if (typeof valueOrChecker === 'string') {
|
|
36
36
|
typesExtended[key] = valueOrChecker;
|
|
@@ -38,26 +38,31 @@ export function cssSyntaxMatch(value, type) {
|
|
|
38
38
|
else if (valueOrChecker) {
|
|
39
39
|
typesCheckers[key] = valueOrChecker;
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|
|
42
42
|
propsExtended = { ...type.syntax.properties };
|
|
43
43
|
if (type.caseSensitive) {
|
|
44
44
|
caseSensitive = true;
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
for (const key of Object.keys(typesExtended))
|
|
46
|
+
eachMimicCases(key, typesExtended);
|
|
47
|
+
for (const key of Object.keys(propsExtended))
|
|
48
|
+
eachMimicCases(key, propsExtended);
|
|
47
49
|
value = mimicCases(value);
|
|
48
50
|
}
|
|
49
51
|
ref = type.ref;
|
|
50
52
|
}
|
|
51
53
|
// @ts-ignore
|
|
52
54
|
const lexer = fork({
|
|
53
|
-
types:
|
|
55
|
+
types: {
|
|
56
|
+
...overrides,
|
|
57
|
+
...typesExtended,
|
|
58
|
+
},
|
|
54
59
|
properties: propsExtended,
|
|
55
60
|
}).lexer;
|
|
56
|
-
Object.keys(typesCheckers)
|
|
61
|
+
for (const key of Object.keys(typesCheckers)) {
|
|
57
62
|
const checker = typesCheckers[key];
|
|
58
63
|
// @ts-ignore
|
|
59
64
|
lexer.addType_(key, (token, getNextToken) => checker?.(token, getNextToken, cssSyntaxMatch));
|
|
60
|
-
}
|
|
65
|
+
}
|
|
61
66
|
const { isProp, name } = detectName(defName);
|
|
62
67
|
// @ts-ignore
|
|
63
68
|
const matcher = isProp ? lexer.properties[name] : lexer.types[name];
|
|
@@ -116,7 +121,7 @@ export function cssSyntaxMatch(value, type) {
|
|
|
116
121
|
}
|
|
117
122
|
function detectName(def) {
|
|
118
123
|
const isProp = def.search("<'") === 0;
|
|
119
|
-
const name = def.
|
|
124
|
+
const name = def.replaceAll(/^<'?|'?>$/g, '');
|
|
120
125
|
return {
|
|
121
126
|
isProp,
|
|
122
127
|
name,
|
|
@@ -140,8 +145,8 @@ obj) {
|
|
|
140
145
|
obj[key] = mimicCases(value);
|
|
141
146
|
}
|
|
142
147
|
function mimicCases(value) {
|
|
143
|
-
return value.
|
|
148
|
+
return value.replaceAll(/[A-Z]/g, $0 => `${MIMIC_TAG_L}${$0}${MIMIC_TAG_R}`);
|
|
144
149
|
}
|
|
145
150
|
function deMimicCases(value) {
|
|
146
|
-
return value.
|
|
151
|
+
return value.replaceAll(new RegExp(`${MIMIC_TAG_L}([A-Z])${MIMIC_TAG_R}`, 'g'), (_, $1) => $1);
|
|
147
152
|
}
|
package/lib/defs.d.ts
CHANGED
package/lib/defs.js
CHANGED
|
@@ -12,6 +12,7 @@ import { isAbsURL } from './whatwg/is-abs-url.js';
|
|
|
12
12
|
import { isBrowserContextName } from './whatwg/is-browser-context-name.js';
|
|
13
13
|
import { isCustomElementName } from './whatwg/is-custom-element-name.js';
|
|
14
14
|
import { isItempropName } from './whatwg/is-itemprop-name.js';
|
|
15
|
+
import { isNavigableTargetName } from './whatwg/is-navigable-target-name.js';
|
|
15
16
|
export const types = {
|
|
16
17
|
Any: {
|
|
17
18
|
ref: '',
|
|
@@ -19,7 +20,7 @@ export const types = {
|
|
|
19
20
|
},
|
|
20
21
|
NoEmptyAny: {
|
|
21
22
|
ref: '',
|
|
22
|
-
is: value => (
|
|
23
|
+
is: value => (value.length > 0 ? matched() : unmatched(value, 'empty-token')),
|
|
23
24
|
},
|
|
24
25
|
OneLineAny: {
|
|
25
26
|
ref: '',
|
|
@@ -87,12 +88,14 @@ export const types = {
|
|
|
87
88
|
},
|
|
88
89
|
],
|
|
89
90
|
is: value => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const name =
|
|
91
|
+
/**
|
|
92
|
+
* NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
|
|
93
|
+
* NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
|
|
94
|
+
* Name ::= NameStartChar (NameChar)*
|
|
95
|
+
*/
|
|
96
|
+
const name =
|
|
97
|
+
// eslint-disable-next-line no-misleading-character-class
|
|
98
|
+
/[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u{10000}-\u{EFFFF}][\d.\u00B7\u0300-\u036F\u203F\u2040-]*/u;
|
|
96
99
|
return name.test(value) ? matched() : unmatched(value, 'unexpected-token');
|
|
97
100
|
},
|
|
98
101
|
},
|
|
@@ -207,6 +210,25 @@ export const types = {
|
|
|
207
210
|
ref: 'https://html.spec.whatwg.org/multipage/urls-and-fetching.html#valid-url-potentially-surrounded-by-spaces',
|
|
208
211
|
is: () => matched(),
|
|
209
212
|
},
|
|
213
|
+
/**
|
|
214
|
+
* Fail if it inclides "data" or "javascript" scheme.
|
|
215
|
+
*
|
|
216
|
+
* > If any of the following are true:
|
|
217
|
+
* > urlRecord is failure;
|
|
218
|
+
* > urlRecord's scheme is "data" or "javascript"; or
|
|
219
|
+
* > running Is base allowed for Document? on urlRecord and document returns "Blocked",
|
|
220
|
+
* > then set element's frozen base URL to document's fallback base URL and return.
|
|
221
|
+
*/
|
|
222
|
+
BaseURL: {
|
|
223
|
+
ref: 'https://html.spec.whatwg.org/multipage/semantics.html#set-the-frozen-base-url',
|
|
224
|
+
is(value) {
|
|
225
|
+
value = value.toLowerCase().trim();
|
|
226
|
+
if (value.startsWith('data:') || value.startsWith('javascript:')) {
|
|
227
|
+
return unmatched(value, 'unexpected-token');
|
|
228
|
+
}
|
|
229
|
+
return matched();
|
|
230
|
+
},
|
|
231
|
+
},
|
|
210
232
|
AbsoluteURL: {
|
|
211
233
|
ref: 'https://url.spec.whatwg.org/#syntax-url-absolute',
|
|
212
234
|
is: matches(isAbsURL()),
|
|
@@ -241,6 +263,20 @@ export const types = {
|
|
|
241
263
|
],
|
|
242
264
|
is: matches(isCustomElementName()),
|
|
243
265
|
},
|
|
266
|
+
NavigableTargetName: {
|
|
267
|
+
ref: 'https://html.spec.whatwg.org/multipage/document-sequences.html#valid-navigable-target-name',
|
|
268
|
+
expects: [
|
|
269
|
+
{
|
|
270
|
+
type: 'common',
|
|
271
|
+
value: 'navigable target name',
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
// <iframe name="[HERE]">
|
|
275
|
+
is: matches(isNavigableTargetName()),
|
|
276
|
+
},
|
|
277
|
+
/**
|
|
278
|
+
* @deprecated Use {@link types.NavigableTargetName} instead.
|
|
279
|
+
*/
|
|
244
280
|
BrowsingContextName: {
|
|
245
281
|
ref: 'https://html.spec.whatwg.org/multipage/browsers.html#browsing-context-names',
|
|
246
282
|
expects: [
|
|
@@ -249,9 +285,43 @@ export const types = {
|
|
|
249
285
|
value: 'browsing context name',
|
|
250
286
|
},
|
|
251
287
|
],
|
|
252
|
-
// <iframe name="[HERE]">
|
|
253
288
|
is: matches(isBrowserContextName()),
|
|
254
289
|
},
|
|
290
|
+
NavigableTargetNameOrKeyword: {
|
|
291
|
+
ref: 'https://html.spec.whatwg.org/multipage/document-sequences.html#valid-navigable-target-name-or-keyword',
|
|
292
|
+
expects: [
|
|
293
|
+
{ type: 'const', value: '_blank' },
|
|
294
|
+
{ type: 'const', value: '_self' },
|
|
295
|
+
{ type: 'const', value: '_parent' },
|
|
296
|
+
{ type: 'const', value: '_top' },
|
|
297
|
+
{
|
|
298
|
+
type: 'common',
|
|
299
|
+
value: 'navigable target name',
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
// <a target="[HERE]">
|
|
303
|
+
is(value) {
|
|
304
|
+
value = value.toLowerCase();
|
|
305
|
+
const keywords = ['_blank', '_self', '_parent', '_top'];
|
|
306
|
+
if (keywords.includes(value)) {
|
|
307
|
+
return matched();
|
|
308
|
+
}
|
|
309
|
+
if (value[0] === '_') {
|
|
310
|
+
const candidate = getCandidate(value, keywords);
|
|
311
|
+
return unmatched(value, 'unexpected-token', { candidate });
|
|
312
|
+
}
|
|
313
|
+
const res = matches(isNavigableTargetName())(value);
|
|
314
|
+
if (!res.matched) {
|
|
315
|
+
// @see https://html.spec.whatwg.org/multipage/semantics.html#get-an-element's-target
|
|
316
|
+
// > If target is not null, and contains an ASCII tab or newline and a U+003C (<), then set target to "_blank".
|
|
317
|
+
return unmatched(value, 'unexpected-token', { fallbackTo: '_blank' });
|
|
318
|
+
}
|
|
319
|
+
return res;
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
/**
|
|
323
|
+
* @deprecated Use {@link types.NavigableTargetNameOrKeyword} instead.
|
|
324
|
+
*/
|
|
255
325
|
BrowsingContextNameOrKeyword: {
|
|
256
326
|
ref: 'https://html.spec.whatwg.org/multipage/browsers.html#valid-browsing-context-name-or-keyword',
|
|
257
327
|
expects: [
|
|
@@ -264,7 +334,6 @@ export const types = {
|
|
|
264
334
|
value: 'browsing context name',
|
|
265
335
|
},
|
|
266
336
|
],
|
|
267
|
-
// <a target="[HERE]">
|
|
268
337
|
is(value) {
|
|
269
338
|
value = value.toLowerCase();
|
|
270
339
|
const keywords = ['_blank', '_self', '_parent', '_top'];
|
|
@@ -336,51 +405,81 @@ export const types = {
|
|
|
336
405
|
},
|
|
337
406
|
Srcset: {
|
|
338
407
|
ref: 'https://html.spec.whatwg.org/multipage/images.html#srcset-attributes',
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
408
|
+
is(value) {
|
|
409
|
+
const images = value.split(',');
|
|
410
|
+
for (const image of images) {
|
|
411
|
+
// image candidate string
|
|
412
|
+
const [url, , descriptor, ...tail] = new TokenCollection(image.trim(), {
|
|
413
|
+
disallowToSurroundBySpaces: true,
|
|
414
|
+
separator: 'space',
|
|
415
|
+
});
|
|
416
|
+
if (!url) {
|
|
417
|
+
return unmatched(value, 'unexpected-token', {
|
|
418
|
+
expects: [
|
|
419
|
+
{
|
|
420
|
+
type: 'format',
|
|
421
|
+
value: 'valid non-empty URL',
|
|
422
|
+
},
|
|
423
|
+
],
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
if (descriptor) {
|
|
427
|
+
const { num, unit } = splitUnit(descriptor.value);
|
|
428
|
+
switch (unit) {
|
|
429
|
+
case 'w': {
|
|
430
|
+
if (!isUint(num)) {
|
|
431
|
+
return unmatched(value, 'unexpected-token', {
|
|
432
|
+
expects: [
|
|
433
|
+
{
|
|
434
|
+
type: 'format',
|
|
435
|
+
value: 'width descriptor',
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
});
|
|
439
|
+
}
|
|
351
440
|
break;
|
|
352
441
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
442
|
+
case 'x': {
|
|
443
|
+
if (!isFloat(num)) {
|
|
444
|
+
return unmatched(value, 'unexpected-token', {
|
|
445
|
+
expects: [
|
|
446
|
+
{
|
|
447
|
+
type: 'format',
|
|
448
|
+
value: 'pixel density descriptor',
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
default: {
|
|
456
|
+
return unmatched(value, 'unexpected-token', {
|
|
457
|
+
expects: [
|
|
458
|
+
{
|
|
459
|
+
type: 'format',
|
|
460
|
+
value: 'width descriptor',
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
type: 'format',
|
|
464
|
+
value: 'pixel density descriptor',
|
|
465
|
+
},
|
|
466
|
+
],
|
|
467
|
+
});
|
|
468
|
+
}
|
|
380
469
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
470
|
+
}
|
|
471
|
+
if (tail[0]) {
|
|
472
|
+
return unmatched(value, 'unexpected-token', {
|
|
473
|
+
expects: [
|
|
474
|
+
{
|
|
475
|
+
type: 'syntax',
|
|
476
|
+
value: 'image candidate string',
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return matched();
|
|
384
483
|
},
|
|
385
484
|
},
|
|
386
485
|
SourceSizeList: {
|
|
@@ -683,7 +782,7 @@ export const types = {
|
|
|
683
782
|
syntax: {
|
|
684
783
|
apply: '<view-box>',
|
|
685
784
|
def: {
|
|
686
|
-
'view-box': '<min-x> [,]? <min-y> [,]? <width> [,]? <height>',
|
|
785
|
+
'view-box': '<min-x> [,]? <min-y> [,]? <width> [,]? <height>', // As '[<min-x>,? <min-y>,? <width>,? <height>]',
|
|
687
786
|
'min-x': '<number>',
|
|
688
787
|
'min-y': '<number>',
|
|
689
788
|
width: '<number>',
|
|
@@ -746,6 +845,27 @@ export const types = {
|
|
|
746
845
|
},
|
|
747
846
|
},
|
|
748
847
|
};
|
|
848
|
+
export const overrides = {
|
|
849
|
+
// Alias
|
|
850
|
+
'legacy-length-percentage': '<length> | <percentage> | <svg-length>',
|
|
851
|
+
'legacy-angle': '<angle> | <zero> | <number>',
|
|
852
|
+
/**
|
|
853
|
+
* @see https://www.w3.org/TR/css-transforms-1/#funcdef-transform-translate
|
|
854
|
+
*/
|
|
855
|
+
'translate()': 'translate( <legacy-length-percentage> , <legacy-length-percentage>? ) | translate( <legacy-length-percentage> <legacy-length-percentage>? )',
|
|
856
|
+
/**
|
|
857
|
+
* @see https://www.w3.org/TR/css-transforms-1/#funcdef-transform-scale
|
|
858
|
+
*/
|
|
859
|
+
'scale()': 'scale( [ <number> | <percentage> ]#{1,2} )',
|
|
860
|
+
/**
|
|
861
|
+
* @see https://www.w3.org/TR/css-transforms-1/#funcdef-transform-rotate
|
|
862
|
+
*/
|
|
863
|
+
'rotate()': 'rotate( <legacy-angle> )',
|
|
864
|
+
/**
|
|
865
|
+
* @see https://www.w3.org/TR/css-transforms-1/#funcdef-transform-skew
|
|
866
|
+
*/
|
|
867
|
+
'skew()': 'skew( <legacy-angle> , <legacy-angle>? ) | skew( <legacy-angle> <legacy-angle>? )',
|
|
868
|
+
};
|
|
749
869
|
export const tokenizers = {
|
|
750
870
|
// RFC
|
|
751
871
|
// https://tools.ietf.org/rfc/bcp/bcp47.html
|
package/lib/enum.js
CHANGED
|
@@ -5,7 +5,7 @@ export function checkEnum(value, type, ref) {
|
|
|
5
5
|
if (!disallowToSurroundBySpaces) {
|
|
6
6
|
value = value.trim();
|
|
7
7
|
}
|
|
8
|
-
let values = type.enum
|
|
8
|
+
let values = [...type.enum];
|
|
9
9
|
if (caseInsensitive) {
|
|
10
10
|
value = value.toLowerCase();
|
|
11
11
|
values = type.enum.map(v => v.toLowerCase());
|
package/lib/get-candidate.js
CHANGED
|
@@ -6,14 +6,14 @@ export function getCandidate(value, ...candidates) {
|
|
|
6
6
|
const list = candidates.flat(2).filter((s) => !!s);
|
|
7
7
|
let candidate;
|
|
8
8
|
let maxRatio = 0;
|
|
9
|
-
|
|
9
|
+
for (const word of list) {
|
|
10
10
|
const dist = leven(value.trim().toLowerCase(), word.trim().toLowerCase());
|
|
11
11
|
const ratio = 1 - dist / word.length;
|
|
12
12
|
if (0.5 <= ratio && maxRatio < ratio) {
|
|
13
13
|
candidate = word;
|
|
14
14
|
}
|
|
15
15
|
maxRatio = Math.max(ratio, maxRatio);
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
17
|
if (value === candidate) {
|
|
18
18
|
return;
|
|
19
19
|
}
|
package/lib/keyword-type.js
CHANGED
|
@@ -35,12 +35,12 @@ function _checkKeywordType(value, type) {
|
|
|
35
35
|
try {
|
|
36
36
|
return cssSyntaxMatch(value, type);
|
|
37
37
|
}
|
|
38
|
-
catch (
|
|
39
|
-
if (
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error instanceof Error && error.message === 'MARKUPLINT_TYPE_NO_EXIST') {
|
|
40
40
|
log("Allow all of any value because the type doesn't exist");
|
|
41
41
|
return matched();
|
|
42
42
|
}
|
|
43
|
-
throw
|
|
43
|
+
throw error;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
const matches = isCSSSyntax(def) ? cssSyntaxMatch(value, def) : def.is(value);
|
package/lib/number.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Result } from './types.js';
|
|
2
|
-
import type { Number } from './types.schema.js';
|
|
3
|
-
export declare function checkNumber(value: string, type: Readonly<
|
|
2
|
+
import type { Number as TypeNumber } from './types.schema.js';
|
|
3
|
+
export declare function checkNumber(value: string, type: Readonly<TypeNumber>, ref?: string): Result;
|
package/lib/number.js
CHANGED
|
@@ -6,8 +6,8 @@ export function checkNumber(value, type, ref) {
|
|
|
6
6
|
}
|
|
7
7
|
const syntaxMatched = type.type === 'float' ? isFloat(value) : isInt(value);
|
|
8
8
|
if (syntaxMatched) {
|
|
9
|
-
const n = parseFloat(value);
|
|
10
|
-
if (!isFinite(n)) {
|
|
9
|
+
const n = Number.parseFloat(value);
|
|
10
|
+
if (!Number.isFinite(n)) {
|
|
11
11
|
return unmatched(value, 'unexpected-token');
|
|
12
12
|
}
|
|
13
13
|
const clampable = type.clampable;
|