@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.
Files changed (43) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +63 -61
  3. package/lib/css-syntax.js +16 -11
  4. package/lib/defs.d.ts +1 -0
  5. package/lib/defs.js +172 -52
  6. package/lib/enum.js +1 -1
  7. package/lib/get-candidate.js +2 -2
  8. package/lib/keyword-type.js +3 -3
  9. package/lib/number.d.ts +2 -2
  10. package/lib/number.js +2 -2
  11. package/lib/primitive/is-float.js +1 -1
  12. package/lib/primitive/is-int.js +1 -1
  13. package/lib/primitive/is-non-zero-uint.js +1 -1
  14. package/lib/primitive/is-uint.js +3 -3
  15. package/lib/primitive/range.js +2 -2
  16. package/lib/primitive/split-unit.js +1 -1
  17. package/lib/token/token-collection.d.ts +4 -5
  18. package/lib/token/token-collection.js +23 -18
  19. package/lib/token/token.d.ts +1 -1
  20. package/lib/token/token.js +9 -8
  21. package/lib/types.d.ts +1 -0
  22. package/lib/types.schema.d.ts +1 -1
  23. package/lib/w3c/check-serialized-permissions-policy.js +5 -5
  24. package/lib/whatwg/check-autocomplete.js +10 -13
  25. package/lib/whatwg/check-datetime/date-string.js +3 -3
  26. package/lib/whatwg/check-datetime/datetime-tokens.js +18 -18
  27. package/lib/whatwg/check-datetime/duration-string.js +30 -29
  28. package/lib/whatwg/check-datetime/global-date-and-time-string.js +8 -8
  29. package/lib/whatwg/check-datetime/local-date-and-time-string.js +17 -16
  30. package/lib/whatwg/check-datetime/month-string.js +1 -1
  31. package/lib/whatwg/check-datetime/time-string.js +4 -4
  32. package/lib/whatwg/check-datetime/time-zone-offset-string.js +6 -6
  33. package/lib/whatwg/check-datetime/week-string.js +2 -2
  34. package/lib/whatwg/check-datetime/yearless-date-string.js +2 -2
  35. package/lib/whatwg/is-abs-url.js +7 -7
  36. package/lib/whatwg/is-browser-context-name.d.ts +2 -0
  37. package/lib/whatwg/is-browser-context-name.js +2 -0
  38. package/lib/whatwg/is-custom-element-name.d.ts +9 -4
  39. package/lib/whatwg/is-custom-element-name.js +21 -33
  40. package/lib/whatwg/is-navigable-target-name.d.ts +11 -0
  41. package/lib/whatwg/is-navigable-target-name.js +20 -0
  42. package/package.json +12 -9
  43. package/types.schema.json +3 -0
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2019 Yusuke Hirao
3
+ Copyright (c) 2017-2024 Yusuke Hirao
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -33,67 +33,69 @@ check('2020-02-30', 'DateTime');
33
33
 
34
34
  ## Type Identifiers
35
35
 
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` | `iframe[name]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/browsers.html#browsing-context-names) | ✅ |
57
- | `BrowsingContextNameOrKeyword` | `a[target]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/browsers.html#valid-browsing-context-name-or-keyword) | ✅ |
58
- | `HTTPSchemaURL` | `a[ping]` (as list) and more | [WHATWG](https://html.spec.whatwg.org/multipage/links.html#ping) | ✅ |
59
- | `MIMEType` | `embed[type]` and more | [WHATWG](https://mimesniff.spec.whatwg.org/#valid-mime-type) | ✅ |
60
- | `ItemProp` | The `itemprop` attribute (as list) | [WHATWG](https://html.spec.whatwg.org/multipage/microdata.html#names:-the-itemprop-attribute) | ✅ |
61
- | `Srcset` | `img[srcset]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/images.html#srcset-attributes) | ✅ |
62
- | `SourceSizeList` | `img[sizes]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/images.html#sizes-attributes) | ✅ |
63
- | `IconSize` | `link[sizes]` (as list) | [WHATWG](https://html.spec.whatwg.org/multipage/semantics.html#attr-link-sizes) | ✅ |
64
- | `AutoComplete` | `input[autocomplete]` and more | [WHATWG](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete) | ✅ |
65
- | `Accept` | `input[accept]` | [WHATWG](https://html.spec.whatwg.org/multipage/input.html#attr-input-accept) | ✅ |
66
- | `SerializedPermissionsPolicy` | `iframe[allow]` | [W3C](https://w3c.github.io/webappsec-permissions-policy/#serialized-permissions-policy) | ✅ |
67
- | `<css-declaration-list>` | The `style` attribute | [CSS](https://drafts.csswg.org/css-style-attr/#syntax) | ✅ |
68
- | `<class-list>` | The `class` attribute | [SVG](https://www.w3.org/TR/SVG/styling.html#ClassAttribute) | ✅ |
69
- | `<svg-font-size>` | Some attributes for SVG | [CSS](https://drafts.csswg.org/css-fonts-5/#descdef-font-face-font-size) | 🚧 |
70
- | `<svg-font-size-adjust>` | Some attributes for SVG | [CSS](https://drafts.csswg.org/css-fonts-5/#propdef-font-size-adjust) | 🚧 |
71
- | `<'color-profile'>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/color.html#ColorProfileProperty) | 🚧 |
72
- | `<'color-rendering'>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/painting.html#ColorRenderingProperty) | 🚧 |
73
- | `<'enable-background'>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/filters.html#EnableBackgroundProperty) | 🚧 |
74
- | `<list-of-svg-feature-string>` | Some attributes for SVG | [SVG](https://www.w3.org/TR/SVG11/feature.html) | 🚧 |
75
- | `<animatable-value>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#FromAttribute) | 🚧 |
76
- | `<begin-value-list>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#BeginValueListSyntax) | 🚧 |
77
- | `<end-value-list>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#EndValueListSyntax) | 🚧 |
78
- | `<list-of-value>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#ValuesAttribute) | 🚧 |
79
- | `<clock-value>` | Some attributes for SVG | [SMIL](https://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-ClockValueSyntax) | 🚧 |
80
- | `<color-matrix>` | Some attributes for SVG | [W3C](https://drafts.fxtf.org/filter-effects/#element-attrdef-fecolormatrix-values) | |
81
- | `<dasharray>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/painting.html#StrokeDasharrayProperty) | |
82
- | `<key-points>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#KeyPointsAttribute) | ✅ |
83
- | `<key-splines>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#KeyTimesAttribute) | ✅ |
84
- | `<key-times>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#KeyTimesAttribute) | ✅ |
85
- | `<system-language>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/struct.html#SystemLanguageAttribute) | ✅ |
86
- | `<origin>` | Some attributes for SVG | [SMIL](https://www.w3.org/TR/2001/REC-smil-animation-20010904/#MotionOriginAttribute) | ✅ |
87
- | `<svg-path>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/paths.html#PathDataBNF) | 🚧 |
88
- | `<points>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/shapes.html#DataTypePoints) | ✅ |
89
- | `<preserve-aspect-ratio>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/coords.html#PreserveAspectRatioAttribute) | |
90
- | `<view-box>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/coords.html#ViewBoxAttribute) | ✅ |
91
- | `<rotate>` | Some attributes for SVG | [SVG](https://svgwg.org/specs/animations/#RotateAttribute) | ✅ |
92
- | `<text-coordinate>` | Some attributes for SVG | [SVG](https://svgwg.org/svg2-draft/text.html#TSpanAttributes) | ✅ |
93
- | `<list-of-lengths>` | Some attributes for SVG | | ✅ |
94
- | `<list-of-numbers>` | Some attributes for SVG | | ✅ |
95
- | `<list-of-percentages>` | Some attributes for SVG | | ✅ |
96
- | `<number-optional-number>` | Some attributes for SVG | | ✅ |
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).forEach(key => {
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
- Object.keys(typesExtended).forEach(key => eachMimicCases(key, typesExtended));
46
- Object.keys(propsExtended).forEach(key => eachMimicCases(key, propsExtended));
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: typesExtended,
55
+ types: {
56
+ ...overrides,
57
+ ...typesExtended,
58
+ },
54
59
  properties: propsExtended,
55
60
  }).lexer;
56
- Object.keys(typesCheckers).forEach(key => {
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.replace(/^<'?|'?>$/g, '');
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.replace(/[A-Z]/g, $0 => `${MIMIC_TAG_L}${$0}${MIMIC_TAG_R}`);
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.replace(new RegExp(`${MIMIC_TAG_L}([A-Z])${MIMIC_TAG_R}`, 'g'), (_, $1) => $1);
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
@@ -1,3 +1,4 @@
1
1
  import type { Defs, CssSyntaxTokenizer } from './types.js';
2
2
  export declare const types: Defs;
3
+ export declare const overrides: Record<string, string>;
3
4
  export declare const tokenizers: Record<string, CssSyntaxTokenizer>;
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 => (0 < value.length ? matched() : unmatched(value, 'empty-token')),
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
- // 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]
91
- const nameStartChar = /[: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}]/u;
92
- // NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
93
- const nameCharTail = /-|[.0-9\u00B7]|[\u0300-\u036F\u203F-\u2040]/;
94
- // Name ::= NameStartChar (NameChar)*
95
- const name = RegExp(`(?:${nameStartChar.source})(?:${nameCharTail})*`, 'u');
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
- syntax: {
340
- apply: '<srcset>',
341
- def: {
342
- srcset: '<image-candidate-strings> [, <image-candidate-strings>]*',
343
- 'image-candidate-strings': '<valid-non-empty-url> [ <width-descriptor> | <pixel-density-descriptor> ]?',
344
- 'valid-non-empty-url'(token, getNextToken) {
345
- if (!token) {
346
- return 0;
347
- }
348
- let willAdoptTokenLength = 0;
349
- do {
350
- if (token.type === 13) {
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
- willAdoptTokenLength++;
354
- } while ((token = getNextToken(willAdoptTokenLength)));
355
- return willAdoptTokenLength;
356
- },
357
- 'width-descriptor'(token) {
358
- if (!token) {
359
- return 0;
360
- }
361
- const { num, unit } = splitUnit(token.value);
362
- if (unit !== 'w') {
363
- return 0;
364
- }
365
- if (!isUint(num)) {
366
- return 0;
367
- }
368
- return 1;
369
- },
370
- 'pixel-density-descriptor'(token) {
371
- if (!token) {
372
- return 0;
373
- }
374
- const { num, unit } = splitUnit(token.value);
375
- if (unit !== 'x') {
376
- return 0;
377
- }
378
- if (!isFloat(num)) {
379
- return 0;
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
- return 1;
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.slice();
8
+ let values = [...type.enum];
9
9
  if (caseInsensitive) {
10
10
  value = value.toLowerCase();
11
11
  values = type.enum.map(v => v.toLowerCase());
@@ -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
- list.forEach(word => {
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
  }
@@ -35,12 +35,12 @@ function _checkKeywordType(value, type) {
35
35
  try {
36
36
  return cssSyntaxMatch(value, type);
37
37
  }
38
- catch (e) {
39
- if (e instanceof Error && e.message === 'MARKUPLINT_TYPE_NO_EXIST') {
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 e;
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<Number>, ref?: string): Result;
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;