html-validate 6.0.2 → 6.1.3
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/CHANGELOG.md +29 -0
- package/README.md +10 -2
- package/dist/cjs/browser.d.ts +1 -2
- package/dist/cjs/cli.js +3 -0
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/core.d.ts +220 -7
- package/dist/cjs/core.js +241 -45
- package/dist/cjs/core.js.map +1 -1
- package/dist/cjs/html-validate.js +1 -1
- package/dist/cjs/html-validate.js.map +1 -1
- package/dist/cjs/index.d.ts +5 -4
- package/dist/cjs/jest-lib.d.ts +1 -1
- package/dist/es/browser.d.ts +1 -2
- package/dist/es/cli.js +3 -0
- package/dist/es/cli.js.map +1 -1
- package/dist/es/core.d.ts +220 -7
- package/dist/es/core.js +241 -45
- package/dist/es/core.js.map +1 -1
- package/dist/es/html-validate.js +1 -1
- package/dist/es/html-validate.js.map +1 -1
- package/dist/es/index.d.ts +5 -4
- package/dist/es/jest-lib.d.ts +1 -1
- package/elements/html5.json +0 -1
- package/package.json +39 -37
package/dist/es/core.js
CHANGED
|
@@ -252,6 +252,9 @@ class NestedError extends Error {
|
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
+
/**
|
|
256
|
+
* @public
|
|
257
|
+
*/
|
|
255
258
|
class UserError extends NestedError {
|
|
256
259
|
}
|
|
257
260
|
|
|
@@ -262,6 +265,9 @@ function getSummary(schema, obj, errors) {
|
|
|
262
265
|
// istanbul ignore next: for safety only
|
|
263
266
|
return output.length > 0 ? output[0].error : "unknown validation error";
|
|
264
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* @public
|
|
270
|
+
*/
|
|
265
271
|
class SchemaValidationError extends UserError {
|
|
266
272
|
constructor(filename, message, obj, schema, errors) {
|
|
267
273
|
const summary = getSummary(schema, obj, errors);
|
|
@@ -695,6 +701,8 @@ var TextContent$1;
|
|
|
695
701
|
/**
|
|
696
702
|
* Properties listed here can be copied (loaded) onto another element using
|
|
697
703
|
* [[HtmlElement.loadMeta]].
|
|
704
|
+
*
|
|
705
|
+
* @public
|
|
698
706
|
*/
|
|
699
707
|
const MetaCopyableProperty = [
|
|
700
708
|
"metadata",
|
|
@@ -835,16 +843,27 @@ const ajvRegexpKeyword = {
|
|
|
835
843
|
errors: true,
|
|
836
844
|
validate: ajvRegexpValidate,
|
|
837
845
|
};
|
|
846
|
+
/**
|
|
847
|
+
* @public
|
|
848
|
+
*/
|
|
838
849
|
class MetaTable {
|
|
850
|
+
/**
|
|
851
|
+
* @internal
|
|
852
|
+
*/
|
|
839
853
|
constructor() {
|
|
840
854
|
this.elements = {};
|
|
841
855
|
this.schema = clone(schema);
|
|
842
856
|
}
|
|
857
|
+
/**
|
|
858
|
+
* @internal
|
|
859
|
+
*/
|
|
843
860
|
init() {
|
|
844
861
|
this.resolveGlobal();
|
|
845
862
|
}
|
|
846
863
|
/**
|
|
847
864
|
* Extend validation schema.
|
|
865
|
+
*
|
|
866
|
+
* @internal
|
|
848
867
|
*/
|
|
849
868
|
extendValidationSchema(patch) {
|
|
850
869
|
if (patch.properties) {
|
|
@@ -865,6 +884,7 @@ class MetaTable {
|
|
|
865
884
|
/**
|
|
866
885
|
* Load metadata table from object.
|
|
867
886
|
*
|
|
887
|
+
* @internal
|
|
868
888
|
* @param obj - Object with metadata to load
|
|
869
889
|
* @param filename - Optional filename used when presenting validation error
|
|
870
890
|
*/
|
|
@@ -885,6 +905,7 @@ class MetaTable {
|
|
|
885
905
|
/**
|
|
886
906
|
* Load metadata table from filename
|
|
887
907
|
*
|
|
908
|
+
* @internal
|
|
888
909
|
* @param filename - Filename to load
|
|
889
910
|
*/
|
|
890
911
|
loadFromFile(filename) {
|
|
@@ -903,6 +924,7 @@ class MetaTable {
|
|
|
903
924
|
/**
|
|
904
925
|
* Get [[MetaElement]] for the given tag or null if the element doesn't exist.
|
|
905
926
|
*
|
|
927
|
+
* @public
|
|
906
928
|
* @returns A shallow copy of metadata.
|
|
907
929
|
*/
|
|
908
930
|
getMetaFor(tagName) {
|
|
@@ -911,6 +933,8 @@ class MetaTable {
|
|
|
911
933
|
}
|
|
912
934
|
/**
|
|
913
935
|
* Find all tags which has enabled given property.
|
|
936
|
+
*
|
|
937
|
+
* @public
|
|
914
938
|
*/
|
|
915
939
|
getTagsWithProperty(propName) {
|
|
916
940
|
return Object.entries(this.elements)
|
|
@@ -919,6 +943,8 @@ class MetaTable {
|
|
|
919
943
|
}
|
|
920
944
|
/**
|
|
921
945
|
* Find tag matching tagName or inheriting from it.
|
|
946
|
+
*
|
|
947
|
+
* @public
|
|
922
948
|
*/
|
|
923
949
|
getTagsDerivedFrom(tagName) {
|
|
924
950
|
return Object.entries(this.elements)
|
|
@@ -950,6 +976,9 @@ class MetaTable {
|
|
|
950
976
|
ajv.addKeyword({ keyword: "copyable" });
|
|
951
977
|
return ajv.compile(this.schema);
|
|
952
978
|
}
|
|
979
|
+
/**
|
|
980
|
+
* @public
|
|
981
|
+
*/
|
|
953
982
|
getJSONSchema() {
|
|
954
983
|
return this.schema;
|
|
955
984
|
}
|
|
@@ -985,6 +1014,9 @@ class MetaTable {
|
|
|
985
1014
|
merged.attributes = Object.fromEntries(filteredAttrs);
|
|
986
1015
|
return merged;
|
|
987
1016
|
}
|
|
1017
|
+
/**
|
|
1018
|
+
* @internal
|
|
1019
|
+
*/
|
|
988
1020
|
resolve(node) {
|
|
989
1021
|
if (node.meta) {
|
|
990
1022
|
expandProperties(node, node.meta);
|
|
@@ -1079,6 +1111,9 @@ function matchAttribute(node, match) {
|
|
|
1079
1111
|
}
|
|
1080
1112
|
}
|
|
1081
1113
|
|
|
1114
|
+
/**
|
|
1115
|
+
* @public
|
|
1116
|
+
*/
|
|
1082
1117
|
class DynamicValue {
|
|
1083
1118
|
constructor(expr) {
|
|
1084
1119
|
this.expr = expr;
|
|
@@ -1195,12 +1230,14 @@ var State;
|
|
|
1195
1230
|
State[State["ATTR"] = 5] = "ATTR";
|
|
1196
1231
|
State[State["CDATA"] = 6] = "CDATA";
|
|
1197
1232
|
State[State["SCRIPT"] = 7] = "SCRIPT";
|
|
1233
|
+
State[State["STYLE"] = 8] = "STYLE";
|
|
1198
1234
|
})(State || (State = {}));
|
|
1199
1235
|
|
|
1200
1236
|
var ContentModel;
|
|
1201
1237
|
(function (ContentModel) {
|
|
1202
1238
|
ContentModel[ContentModel["TEXT"] = 1] = "TEXT";
|
|
1203
1239
|
ContentModel[ContentModel["SCRIPT"] = 2] = "SCRIPT";
|
|
1240
|
+
ContentModel[ContentModel["STYLE"] = 3] = "STYLE";
|
|
1204
1241
|
})(ContentModel || (ContentModel = {}));
|
|
1205
1242
|
class Context {
|
|
1206
1243
|
constructor(source) {
|
|
@@ -1729,6 +1766,8 @@ const TEXT_NODE_NAME = "#text";
|
|
|
1729
1766
|
*
|
|
1730
1767
|
* Text nodes are appended as children of `HtmlElement` and cannot have childen
|
|
1731
1768
|
* of its own.
|
|
1769
|
+
*
|
|
1770
|
+
* @public
|
|
1732
1771
|
*/
|
|
1733
1772
|
class TextNode extends DOMNode {
|
|
1734
1773
|
/**
|
|
@@ -1760,6 +1799,9 @@ class TextNode extends DOMNode {
|
|
|
1760
1799
|
}
|
|
1761
1800
|
}
|
|
1762
1801
|
|
|
1802
|
+
/**
|
|
1803
|
+
* @public
|
|
1804
|
+
*/
|
|
1763
1805
|
var NodeClosed;
|
|
1764
1806
|
(function (NodeClosed) {
|
|
1765
1807
|
NodeClosed[NodeClosed["Open"] = 0] = "Open";
|
|
@@ -1774,6 +1816,9 @@ function isElement(node) {
|
|
|
1774
1816
|
function isValidTagName(tagName) {
|
|
1775
1817
|
return Boolean(tagName !== "" && tagName !== "*");
|
|
1776
1818
|
}
|
|
1819
|
+
/**
|
|
1820
|
+
* @public
|
|
1821
|
+
*/
|
|
1777
1822
|
class HtmlElement extends DOMNode {
|
|
1778
1823
|
constructor(tagName, parent, closed, meta, location) {
|
|
1779
1824
|
const nodeType = tagName ? NodeType.ELEMENT_NODE : NodeType.DOCUMENT_NODE;
|
|
@@ -1799,9 +1844,15 @@ class HtmlElement extends DOMNode {
|
|
|
1799
1844
|
}
|
|
1800
1845
|
}
|
|
1801
1846
|
}
|
|
1847
|
+
/**
|
|
1848
|
+
* @internal
|
|
1849
|
+
*/
|
|
1802
1850
|
static rootNode(location) {
|
|
1803
1851
|
return new HtmlElement(undefined, null, NodeClosed.EndTag, null, location);
|
|
1804
1852
|
}
|
|
1853
|
+
/**
|
|
1854
|
+
* @internal
|
|
1855
|
+
*/
|
|
1805
1856
|
static fromTokens(startToken, endToken, parent, metaTable) {
|
|
1806
1857
|
const tagName = startToken.data[2];
|
|
1807
1858
|
if (!tagName) {
|
|
@@ -2111,6 +2162,8 @@ class HtmlElement extends DOMNode {
|
|
|
2111
2162
|
}
|
|
2112
2163
|
/**
|
|
2113
2164
|
* Visit all nodes from this node and down. Depth first.
|
|
2165
|
+
*
|
|
2166
|
+
* @internal
|
|
2114
2167
|
*/
|
|
2115
2168
|
visitDepthFirst(callback) {
|
|
2116
2169
|
function visit(node) {
|
|
@@ -2123,6 +2176,8 @@ class HtmlElement extends DOMNode {
|
|
|
2123
2176
|
}
|
|
2124
2177
|
/**
|
|
2125
2178
|
* Evaluates callbackk on all descendants, returning true if any are true.
|
|
2179
|
+
*
|
|
2180
|
+
* @internal
|
|
2126
2181
|
*/
|
|
2127
2182
|
someChildren(callback) {
|
|
2128
2183
|
return this.childElements.some(visit);
|
|
@@ -2137,6 +2192,8 @@ class HtmlElement extends DOMNode {
|
|
|
2137
2192
|
}
|
|
2138
2193
|
/**
|
|
2139
2194
|
* Evaluates callbackk on all descendants, returning true if all are true.
|
|
2195
|
+
*
|
|
2196
|
+
* @internal
|
|
2140
2197
|
*/
|
|
2141
2198
|
everyChildren(callback) {
|
|
2142
2199
|
return this.childElements.every(visit);
|
|
@@ -2151,6 +2208,8 @@ class HtmlElement extends DOMNode {
|
|
|
2151
2208
|
* Visit all nodes from this node and down. Breadth first.
|
|
2152
2209
|
*
|
|
2153
2210
|
* The first node for which the callback evaluates to true is returned.
|
|
2211
|
+
*
|
|
2212
|
+
* @internal
|
|
2154
2213
|
*/
|
|
2155
2214
|
find(callback) {
|
|
2156
2215
|
function visit(node) {
|
|
@@ -2758,6 +2817,9 @@ function compareKey(node, key, filename) {
|
|
|
2758
2817
|
}
|
|
2759
2818
|
}
|
|
2760
2819
|
}
|
|
2820
|
+
/**
|
|
2821
|
+
* @public
|
|
2822
|
+
*/
|
|
2761
2823
|
class TemplateExtractor {
|
|
2762
2824
|
constructor(ast, filename, data) {
|
|
2763
2825
|
this.ast = ast;
|
|
@@ -2851,19 +2913,28 @@ var TRANSFORMER_API;
|
|
|
2851
2913
|
TRANSFORMER_API[TRANSFORMER_API["VERSION"] = 1] = "VERSION";
|
|
2852
2914
|
})(TRANSFORMER_API || (TRANSFORMER_API = {}));
|
|
2853
2915
|
|
|
2916
|
+
/* generated file, changes will be overwritten */
|
|
2917
|
+
/** @public */
|
|
2854
2918
|
const name = "html-validate";
|
|
2855
|
-
|
|
2919
|
+
/** @public */
|
|
2920
|
+
const version = "6.1.3";
|
|
2921
|
+
/** @public */
|
|
2856
2922
|
const homepage = "https://html-validate.org";
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
};
|
|
2923
|
+
/** @public */
|
|
2924
|
+
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
2860
2925
|
|
|
2926
|
+
/**
|
|
2927
|
+
* @public
|
|
2928
|
+
*/
|
|
2861
2929
|
var Severity;
|
|
2862
2930
|
(function (Severity) {
|
|
2863
2931
|
Severity[Severity["DISABLED"] = 0] = "DISABLED";
|
|
2864
2932
|
Severity[Severity["WARN"] = 1] = "WARN";
|
|
2865
2933
|
Severity[Severity["ERROR"] = 2] = "ERROR";
|
|
2866
2934
|
})(Severity || (Severity = {}));
|
|
2935
|
+
/**
|
|
2936
|
+
* @internal
|
|
2937
|
+
*/
|
|
2867
2938
|
function parseSeverity(value) {
|
|
2868
2939
|
switch (value) {
|
|
2869
2940
|
case 0:
|
|
@@ -2911,6 +2982,9 @@ function getSchemaValidator(ruleId, properties) {
|
|
|
2911
2982
|
};
|
|
2912
2983
|
return ajv$1.compile(schema);
|
|
2913
2984
|
}
|
|
2985
|
+
/**
|
|
2986
|
+
* @public
|
|
2987
|
+
*/
|
|
2914
2988
|
class Rule {
|
|
2915
2989
|
constructor(options) {
|
|
2916
2990
|
/* faux initialization, properly initialized by init(). This is to keep TS happy without adding null-checks everywhere */
|
|
@@ -3112,6 +3186,9 @@ class Rule {
|
|
|
3112
3186
|
return null;
|
|
3113
3187
|
}
|
|
3114
3188
|
}
|
|
3189
|
+
/**
|
|
3190
|
+
* @internal
|
|
3191
|
+
*/
|
|
3115
3192
|
function ruleDocumentationUrl(filename) {
|
|
3116
3193
|
/* during bundling all "@/rule.ts"'s are converted to paths relative to the src
|
|
3117
3194
|
* folder and with the @/ prefix, by replacing the @ with the dist folder we
|
|
@@ -3142,24 +3219,60 @@ const description = {
|
|
|
3142
3219
|
["absolute" /* ABSOLUTE */]: "Absolute links are not allowed by current configuration.",
|
|
3143
3220
|
["anchor" /* ANCHOR */]: null,
|
|
3144
3221
|
};
|
|
3222
|
+
function parseAllow(value) {
|
|
3223
|
+
if (typeof value === "boolean") {
|
|
3224
|
+
return value;
|
|
3225
|
+
}
|
|
3226
|
+
return {
|
|
3227
|
+
/* eslint-disable security/detect-non-literal-regexp */
|
|
3228
|
+
include: value.include ? value.include.map((it) => new RegExp(it)) : null,
|
|
3229
|
+
exclude: value.exclude ? value.exclude.map((it) => new RegExp(it)) : null,
|
|
3230
|
+
/* eslint-enable security/detect-non-literal-regexp */
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
/**
|
|
3234
|
+
* @internal
|
|
3235
|
+
*/
|
|
3236
|
+
function matchList(value, list) {
|
|
3237
|
+
if (list.include && !list.include.some((it) => it.test(value))) {
|
|
3238
|
+
return false;
|
|
3239
|
+
}
|
|
3240
|
+
if (list.exclude && list.exclude.some((it) => it.test(value))) {
|
|
3241
|
+
return false;
|
|
3242
|
+
}
|
|
3243
|
+
return true;
|
|
3244
|
+
}
|
|
3145
3245
|
class AllowedLinks extends Rule {
|
|
3146
3246
|
constructor(options) {
|
|
3147
3247
|
super({ ...defaults$p, ...options });
|
|
3248
|
+
this.allowExternal = parseAllow(this.options.allowExternal);
|
|
3249
|
+
this.allowRelative = parseAllow(this.options.allowRelative);
|
|
3250
|
+
this.allowAbsolute = parseAllow(this.options.allowAbsolute);
|
|
3148
3251
|
}
|
|
3149
3252
|
static schema() {
|
|
3253
|
+
const booleanOrObject = {
|
|
3254
|
+
anyOf: [
|
|
3255
|
+
{ type: "boolean" },
|
|
3256
|
+
{
|
|
3257
|
+
type: "object",
|
|
3258
|
+
properties: {
|
|
3259
|
+
include: {
|
|
3260
|
+
type: "array",
|
|
3261
|
+
items: { type: "string" },
|
|
3262
|
+
},
|
|
3263
|
+
exclude: {
|
|
3264
|
+
type: "array",
|
|
3265
|
+
items: { type: "string" },
|
|
3266
|
+
},
|
|
3267
|
+
},
|
|
3268
|
+
},
|
|
3269
|
+
],
|
|
3270
|
+
};
|
|
3150
3271
|
return {
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
},
|
|
3154
|
-
allowBase: {
|
|
3155
|
-
type: "boolean",
|
|
3156
|
-
},
|
|
3157
|
-
allowExternal: {
|
|
3158
|
-
type: "boolean",
|
|
3159
|
-
},
|
|
3160
|
-
allowRelative: {
|
|
3161
|
-
type: "boolean",
|
|
3162
|
-
},
|
|
3272
|
+
allowExternal: { ...booleanOrObject },
|
|
3273
|
+
allowRelative: { ...booleanOrObject },
|
|
3274
|
+
allowAbsolute: { ...booleanOrObject },
|
|
3275
|
+
allowBase: { type: "boolean" },
|
|
3163
3276
|
};
|
|
3164
3277
|
}
|
|
3165
3278
|
documentation(context) {
|
|
@@ -3181,16 +3294,16 @@ class AllowedLinks extends Rule {
|
|
|
3181
3294
|
/* anchor links are always allowed by this rule */
|
|
3182
3295
|
break;
|
|
3183
3296
|
case "absolute" /* ABSOLUTE */:
|
|
3184
|
-
this.handleAbsolute(event, style);
|
|
3297
|
+
this.handleAbsolute(link, event, style);
|
|
3185
3298
|
break;
|
|
3186
3299
|
case "external" /* EXTERNAL */:
|
|
3187
|
-
this.handleExternal(event, style);
|
|
3300
|
+
this.handleExternal(link, event, style);
|
|
3188
3301
|
break;
|
|
3189
3302
|
case "relative-base" /* RELATIVE_BASE */:
|
|
3190
|
-
this.handleRelativeBase(event, style);
|
|
3303
|
+
this.handleRelativeBase(link, event, style);
|
|
3191
3304
|
break;
|
|
3192
3305
|
case "relative-path" /* RELATIVE_PATH */:
|
|
3193
|
-
this.handleRelativePath(event, style);
|
|
3306
|
+
this.handleRelativePath(link, event, style);
|
|
3194
3307
|
break;
|
|
3195
3308
|
}
|
|
3196
3309
|
});
|
|
@@ -3224,28 +3337,49 @@ class AllowedLinks extends Rule {
|
|
|
3224
3337
|
return "relative-base" /* RELATIVE_BASE */;
|
|
3225
3338
|
}
|
|
3226
3339
|
}
|
|
3227
|
-
handleAbsolute(event, style) {
|
|
3228
|
-
const { allowAbsolute } = this
|
|
3229
|
-
if (
|
|
3340
|
+
handleAbsolute(target, event, style) {
|
|
3341
|
+
const { allowAbsolute } = this;
|
|
3342
|
+
if (allowAbsolute === true) {
|
|
3343
|
+
return;
|
|
3344
|
+
}
|
|
3345
|
+
else if (allowAbsolute === false) {
|
|
3230
3346
|
this.report(event.target, "Link destination must not be absolute url", event.valueLocation, style);
|
|
3231
3347
|
}
|
|
3348
|
+
else if (!matchList(target, allowAbsolute)) {
|
|
3349
|
+
this.report(event.target, "Absolute link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3350
|
+
}
|
|
3232
3351
|
}
|
|
3233
|
-
handleExternal(event, style) {
|
|
3234
|
-
const { allowExternal } = this
|
|
3235
|
-
if (
|
|
3352
|
+
handleExternal(target, event, style) {
|
|
3353
|
+
const { allowExternal } = this;
|
|
3354
|
+
if (allowExternal === true) {
|
|
3355
|
+
return;
|
|
3356
|
+
}
|
|
3357
|
+
else if (allowExternal === false) {
|
|
3236
3358
|
this.report(event.target, "Link destination must not be external url", event.valueLocation, style);
|
|
3237
3359
|
}
|
|
3360
|
+
else if (!matchList(target, allowExternal)) {
|
|
3361
|
+
this.report(event.target, "External link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3362
|
+
}
|
|
3238
3363
|
}
|
|
3239
|
-
handleRelativePath(event, style) {
|
|
3240
|
-
const { allowRelative } = this
|
|
3241
|
-
if (
|
|
3364
|
+
handleRelativePath(target, event, style) {
|
|
3365
|
+
const { allowRelative } = this;
|
|
3366
|
+
if (allowRelative === true) {
|
|
3367
|
+
return false;
|
|
3368
|
+
}
|
|
3369
|
+
else if (allowRelative === false) {
|
|
3242
3370
|
this.report(event.target, "Link destination must not be relative url", event.valueLocation, style);
|
|
3371
|
+
return true;
|
|
3243
3372
|
}
|
|
3373
|
+
else if (!matchList(target, allowRelative)) {
|
|
3374
|
+
this.report(event.target, "Relative link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3375
|
+
return true;
|
|
3376
|
+
}
|
|
3377
|
+
return false;
|
|
3244
3378
|
}
|
|
3245
|
-
handleRelativeBase(event, style) {
|
|
3246
|
-
const {
|
|
3247
|
-
if (
|
|
3248
|
-
|
|
3379
|
+
handleRelativeBase(target, event, style) {
|
|
3380
|
+
const { allowBase } = this.options;
|
|
3381
|
+
if (this.handleRelativePath(target, event, style)) {
|
|
3382
|
+
return;
|
|
3249
3383
|
}
|
|
3250
3384
|
else if (!allowBase) {
|
|
3251
3385
|
this.report(event.target, "Relative links must be relative to current folder", event.valueLocation, style);
|
|
@@ -3329,6 +3463,9 @@ class AriaLabelMisuse extends Rule {
|
|
|
3329
3463
|
}
|
|
3330
3464
|
}
|
|
3331
3465
|
|
|
3466
|
+
/**
|
|
3467
|
+
* @public
|
|
3468
|
+
*/
|
|
3332
3469
|
class ConfigError extends UserError {
|
|
3333
3470
|
}
|
|
3334
3471
|
|
|
@@ -3466,10 +3603,11 @@ var TokenType;
|
|
|
3466
3603
|
TokenType[TokenType["TEXT"] = 11] = "TEXT";
|
|
3467
3604
|
TokenType[TokenType["TEMPLATING"] = 12] = "TEMPLATING";
|
|
3468
3605
|
TokenType[TokenType["SCRIPT"] = 13] = "SCRIPT";
|
|
3469
|
-
TokenType[TokenType["
|
|
3470
|
-
TokenType[TokenType["
|
|
3471
|
-
TokenType[TokenType["
|
|
3472
|
-
TokenType[TokenType["
|
|
3606
|
+
TokenType[TokenType["STYLE"] = 14] = "STYLE";
|
|
3607
|
+
TokenType[TokenType["COMMENT"] = 15] = "COMMENT";
|
|
3608
|
+
TokenType[TokenType["CONDITIONAL"] = 16] = "CONDITIONAL";
|
|
3609
|
+
TokenType[TokenType["DIRECTIVE"] = 17] = "DIRECTIVE";
|
|
3610
|
+
TokenType[TokenType["EOF"] = 18] = "EOF";
|
|
3473
3611
|
})(TokenType || (TokenType = {}));
|
|
3474
3612
|
|
|
3475
3613
|
/* eslint-disable no-useless-escape */
|
|
@@ -3482,7 +3620,7 @@ const MATCH_XML_TAG = /^<\?xml.*?\?>\s+/;
|
|
|
3482
3620
|
const MATCH_TAG_OPEN = /^<(\/?)([a-zA-Z0-9\-:]+)/; // https://www.w3.org/TR/html/syntax.html#start-tags
|
|
3483
3621
|
const MATCH_TAG_CLOSE = /^\/?>/;
|
|
3484
3622
|
const MATCH_TEXT = /^[^]*?(?=(?:[ \t]*(?:\r\n|\r|\n)|<[^ ]|$))/;
|
|
3485
|
-
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)
|
|
3623
|
+
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)/s;
|
|
3486
3624
|
const MATCH_TAG_LOOKAHEAD = /^[^]*?(?=<|$)/;
|
|
3487
3625
|
const MATCH_ATTR_START = /^([^\t\r\n\f \/><"'=]+)/; // https://www.w3.org/TR/html/syntax.html#elements-attributes
|
|
3488
3626
|
const MATCH_ATTR_SINGLE = /^(\s*=\s*)'([^']*?)(')/;
|
|
@@ -3492,6 +3630,8 @@ const MATCH_CDATA_BEGIN = /^<!\[CDATA\[/;
|
|
|
3492
3630
|
const MATCH_CDATA_END = /^[^]*?]]>/;
|
|
3493
3631
|
const MATCH_SCRIPT_DATA = /^[^]*?(?=<\/script)/;
|
|
3494
3632
|
const MATCH_SCRIPT_END = /^<(\/)(script)/;
|
|
3633
|
+
const MATCH_STYLE_DATA = /^[^]*?(?=<\/style)/;
|
|
3634
|
+
const MATCH_STYLE_END = /^<(\/)(style)/;
|
|
3495
3635
|
const MATCH_DIRECTIVE = /^<!--\s*\[html-validate-(.*?)]\s*-->/;
|
|
3496
3636
|
const MATCH_COMMENT = /^<!--([^]*?)-->/;
|
|
3497
3637
|
const MATCH_CONDITIONAL = /^<!\[([^\]]*?)\]>/;
|
|
@@ -3531,6 +3671,9 @@ class Lexer {
|
|
|
3531
3671
|
case State.SCRIPT:
|
|
3532
3672
|
yield* this.tokenizeScript(context);
|
|
3533
3673
|
break;
|
|
3674
|
+
case State.STYLE:
|
|
3675
|
+
yield* this.tokenizeStyle(context);
|
|
3676
|
+
break;
|
|
3534
3677
|
/* istanbul ignore next: sanity check: should not happen unless adding new states */
|
|
3535
3678
|
default:
|
|
3536
3679
|
this.unhandled(context);
|
|
@@ -3599,11 +3742,14 @@ class Lexer {
|
|
|
3599
3742
|
* Called when entering a new state.
|
|
3600
3743
|
*/
|
|
3601
3744
|
enter(context, state, data) {
|
|
3602
|
-
/* script tags require a different content model */
|
|
3745
|
+
/* script/style tags require a different content model */
|
|
3603
3746
|
if (state === State.TAG && data && data[0][0] === "<") {
|
|
3604
3747
|
if (data[0] === "<script") {
|
|
3605
3748
|
context.contentModel = ContentModel.SCRIPT;
|
|
3606
3749
|
}
|
|
3750
|
+
else if (data[0] === "<style") {
|
|
3751
|
+
context.contentModel = ContentModel.STYLE;
|
|
3752
|
+
}
|
|
3607
3753
|
else {
|
|
3608
3754
|
context.contentModel = ContentModel.TEXT;
|
|
3609
3755
|
}
|
|
@@ -3629,6 +3775,7 @@ class Lexer {
|
|
|
3629
3775
|
], "expected doctype name");
|
|
3630
3776
|
}
|
|
3631
3777
|
*tokenizeTag(context) {
|
|
3778
|
+
/* eslint-disable-next-line consistent-return -- exhaustive switch handled by typescript */
|
|
3632
3779
|
function nextState(token) {
|
|
3633
3780
|
switch (context.contentModel) {
|
|
3634
3781
|
case ContentModel.TEXT:
|
|
@@ -3640,11 +3787,14 @@ class Lexer {
|
|
|
3640
3787
|
else {
|
|
3641
3788
|
return State.TEXT; /* <script/> (not legal but handle it anyway so the lexer doesn't choke on it) */
|
|
3642
3789
|
}
|
|
3790
|
+
case ContentModel.STYLE:
|
|
3791
|
+
if (token && token.data[0][0] !== "/") {
|
|
3792
|
+
return State.STYLE;
|
|
3793
|
+
}
|
|
3794
|
+
else {
|
|
3795
|
+
return State.TEXT; /* <style/> */
|
|
3796
|
+
}
|
|
3643
3797
|
}
|
|
3644
|
-
/* istanbul ignore next: not covered by a test as there is currently no
|
|
3645
|
-
* way to trigger this unless new content models are added but this will
|
|
3646
|
-
* add a saner default if anyone ever does */
|
|
3647
|
-
return context.contentModel !== ContentModel.SCRIPT ? State.TEXT : State.SCRIPT;
|
|
3648
3798
|
}
|
|
3649
3799
|
yield* this.match(context, [
|
|
3650
3800
|
[MATCH_TAG_CLOSE, nextState, TokenType.TAG_CLOSE],
|
|
@@ -3682,6 +3832,12 @@ class Lexer {
|
|
|
3682
3832
|
[MATCH_SCRIPT_DATA, State.SCRIPT, TokenType.SCRIPT],
|
|
3683
3833
|
], "expected </script>");
|
|
3684
3834
|
}
|
|
3835
|
+
*tokenizeStyle(context) {
|
|
3836
|
+
yield* this.match(context, [
|
|
3837
|
+
[MATCH_STYLE_END, State.TAG, TokenType.TAG_OPEN],
|
|
3838
|
+
[MATCH_STYLE_DATA, State.STYLE, TokenType.STYLE],
|
|
3839
|
+
], "expected </style>");
|
|
3840
|
+
}
|
|
3685
3841
|
}
|
|
3686
3842
|
|
|
3687
3843
|
const whitespace = /(\s+)/;
|
|
@@ -5932,7 +6088,7 @@ function getCSSDeclarations(value) {
|
|
|
5932
6088
|
.filter(Boolean)
|
|
5933
6089
|
.map((it) => {
|
|
5934
6090
|
const [property, value] = it.split(":", 2);
|
|
5935
|
-
return { property: property.trim(), value: value.trim() };
|
|
6091
|
+
return { property: property.trim(), value: value ? value.trim() : undefined };
|
|
5936
6092
|
});
|
|
5937
6093
|
}
|
|
5938
6094
|
class NoInlineStyle extends Rule {
|
|
@@ -6147,7 +6303,7 @@ const defaults$9 = {
|
|
|
6147
6303
|
};
|
|
6148
6304
|
const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6149
6305
|
const unquotedAttrRegexp = /([<>"'=`]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6150
|
-
const matchTemplate = /^(<%.*?%>|<\?.*?\?>|<\$.*?\$>)
|
|
6306
|
+
const matchTemplate = /^(<%.*?%>|<\?.*?\?>|<\$.*?\$>)$/s;
|
|
6151
6307
|
const replacementTable = new Map([
|
|
6152
6308
|
['"', """],
|
|
6153
6309
|
["&", "&"],
|
|
@@ -9447,6 +9603,9 @@ const config = {
|
|
|
9447
9603
|
},
|
|
9448
9604
|
};
|
|
9449
9605
|
|
|
9606
|
+
/**
|
|
9607
|
+
* @internal
|
|
9608
|
+
*/
|
|
9450
9609
|
const presets = {
|
|
9451
9610
|
"html-validate:a17y": config$3,
|
|
9452
9611
|
"html-validate:document": config$2,
|
|
@@ -9594,8 +9753,13 @@ function loadFromFile(filename) {
|
|
|
9594
9753
|
* Configuration holder.
|
|
9595
9754
|
*
|
|
9596
9755
|
* Each file being validated will have a unique instance of this class.
|
|
9756
|
+
*
|
|
9757
|
+
* @public
|
|
9597
9758
|
*/
|
|
9598
9759
|
class Config {
|
|
9760
|
+
/**
|
|
9761
|
+
* @internal
|
|
9762
|
+
*/
|
|
9599
9763
|
constructor(options) {
|
|
9600
9764
|
var _a;
|
|
9601
9765
|
this.transformers = [];
|
|
@@ -9658,6 +9822,8 @@ class Config {
|
|
|
9658
9822
|
* Validate configuration data.
|
|
9659
9823
|
*
|
|
9660
9824
|
* Throws SchemaValidationError if invalid.
|
|
9825
|
+
*
|
|
9826
|
+
* @internal
|
|
9661
9827
|
*/
|
|
9662
9828
|
static validate(configData, filename = null) {
|
|
9663
9829
|
var _a;
|
|
@@ -9685,6 +9851,8 @@ class Config {
|
|
|
9685
9851
|
*
|
|
9686
9852
|
* Must be called before trying to use config. Can safely be called multiple
|
|
9687
9853
|
* times.
|
|
9854
|
+
*
|
|
9855
|
+
* @internal
|
|
9688
9856
|
*/
|
|
9689
9857
|
init() {
|
|
9690
9858
|
if (this.initialized) {
|
|
@@ -9704,6 +9872,7 @@ class Config {
|
|
|
9704
9872
|
* Returns a new configuration as a merge of the two. Entries from the passed
|
|
9705
9873
|
* object takes priority over this object.
|
|
9706
9874
|
*
|
|
9875
|
+
* @internal
|
|
9707
9876
|
* @param rhs - Configuration to merge with this one.
|
|
9708
9877
|
*/
|
|
9709
9878
|
merge(rhs) {
|
|
@@ -9796,6 +9965,8 @@ class Config {
|
|
|
9796
9965
|
}
|
|
9797
9966
|
/**
|
|
9798
9967
|
* Get all configured rules, their severity and options.
|
|
9968
|
+
*
|
|
9969
|
+
* @internal
|
|
9799
9970
|
*/
|
|
9800
9971
|
getRules() {
|
|
9801
9972
|
var _a;
|
|
@@ -9818,6 +9989,8 @@ class Config {
|
|
|
9818
9989
|
}
|
|
9819
9990
|
/**
|
|
9820
9991
|
* Get all configured plugins.
|
|
9992
|
+
*
|
|
9993
|
+
* @internal
|
|
9821
9994
|
*/
|
|
9822
9995
|
getPlugins() {
|
|
9823
9996
|
return this.plugins;
|
|
@@ -9883,6 +10056,8 @@ class Config {
|
|
|
9883
10056
|
*
|
|
9884
10057
|
* A resolved configuration will merge all extended configs and load all
|
|
9885
10058
|
* plugins and transformers, and normalize the rest of the configuration.
|
|
10059
|
+
*
|
|
10060
|
+
* @internal
|
|
9886
10061
|
*/
|
|
9887
10062
|
resolve() {
|
|
9888
10063
|
return new ResolvedConfig(this.resolveData());
|
|
@@ -10067,6 +10242,9 @@ class ConfigLoader {
|
|
|
10067
10242
|
}
|
|
10068
10243
|
}
|
|
10069
10244
|
|
|
10245
|
+
/**
|
|
10246
|
+
* @internal
|
|
10247
|
+
*/
|
|
10070
10248
|
class EventHandler {
|
|
10071
10249
|
constructor() {
|
|
10072
10250
|
this.listeners = {};
|
|
@@ -10147,6 +10325,8 @@ class ParserError extends Error {
|
|
|
10147
10325
|
|
|
10148
10326
|
/**
|
|
10149
10327
|
* Parse HTML document into a DOM tree.
|
|
10328
|
+
*
|
|
10329
|
+
* @internal
|
|
10150
10330
|
*/
|
|
10151
10331
|
class Parser {
|
|
10152
10332
|
/**
|
|
@@ -10623,6 +10803,9 @@ class Parser {
|
|
|
10623
10803
|
}
|
|
10624
10804
|
}
|
|
10625
10805
|
|
|
10806
|
+
/**
|
|
10807
|
+
* @internal
|
|
10808
|
+
*/
|
|
10626
10809
|
class Reporter {
|
|
10627
10810
|
constructor() {
|
|
10628
10811
|
this.result = {};
|
|
@@ -10741,6 +10924,9 @@ function messageSort(a, b) {
|
|
|
10741
10924
|
return 0;
|
|
10742
10925
|
}
|
|
10743
10926
|
|
|
10927
|
+
/**
|
|
10928
|
+
* @internal
|
|
10929
|
+
*/
|
|
10744
10930
|
class Engine {
|
|
10745
10931
|
constructor(config, ParserClass) {
|
|
10746
10932
|
this.report = new Reporter();
|
|
@@ -11094,6 +11280,8 @@ class Engine {
|
|
|
11094
11280
|
*
|
|
11095
11281
|
* In practice this means no configuration is fetch by traversing the
|
|
11096
11282
|
* filesystem.
|
|
11283
|
+
*
|
|
11284
|
+
* @public
|
|
11097
11285
|
*/
|
|
11098
11286
|
class StaticConfigLoader extends ConfigLoader {
|
|
11099
11287
|
getConfigFor(handle, configOverride) {
|
|
@@ -11133,6 +11321,8 @@ function isConfigData(value) {
|
|
|
11133
11321
|
* Primary API for using HTML-validate.
|
|
11134
11322
|
*
|
|
11135
11323
|
* Provides high-level abstractions for common operations.
|
|
11324
|
+
*
|
|
11325
|
+
* @public
|
|
11136
11326
|
*/
|
|
11137
11327
|
class HtmlValidate {
|
|
11138
11328
|
constructor(arg) {
|
|
@@ -11337,6 +11527,7 @@ class HtmlValidate {
|
|
|
11337
11527
|
/**
|
|
11338
11528
|
* Create a parser configured for given filename.
|
|
11339
11529
|
*
|
|
11530
|
+
* @internal
|
|
11340
11531
|
* @param source - Source to use.
|
|
11341
11532
|
*/
|
|
11342
11533
|
getParserFor(source) {
|
|
@@ -11380,6 +11571,7 @@ const defaults$1 = {
|
|
|
11380
11571
|
* Tests if plugin is compatible with html-validate library. Unless the `silent`
|
|
11381
11572
|
* option is used a warning is displayed on the console.
|
|
11382
11573
|
*
|
|
11574
|
+
* @public
|
|
11383
11575
|
* @param name - Name of plugin
|
|
11384
11576
|
* @param declared - What library versions the plugin support (e.g. declared peerDependencies)
|
|
11385
11577
|
* @returns - `true` if version is compatible
|
|
@@ -11408,6 +11600,7 @@ const ruleIds = new Set(Object.keys(bundledRules));
|
|
|
11408
11600
|
* Can be used to create forward/backward compatibility by checking if a rule
|
|
11409
11601
|
* exists to enable/disable it.
|
|
11410
11602
|
*
|
|
11603
|
+
* @public
|
|
11411
11604
|
* @param ruleId - Rule id to check
|
|
11412
11605
|
* @returns `true` if rule exists
|
|
11413
11606
|
*/
|
|
@@ -11447,6 +11640,8 @@ function findConfigurationFiles(directory) {
|
|
|
11447
11640
|
* 2. If set in the global config the override is merged into global and
|
|
11448
11641
|
* returned. No configuration files are searched.
|
|
11449
11642
|
* 3. Setting `root` in configuration file only stops directory traversal.
|
|
11643
|
+
*
|
|
11644
|
+
* @public
|
|
11450
11645
|
*/
|
|
11451
11646
|
class FileSystemConfigLoader extends ConfigLoader {
|
|
11452
11647
|
/**
|
|
@@ -11784,6 +11979,7 @@ const availableFormatters = {
|
|
|
11784
11979
|
/**
|
|
11785
11980
|
* Get formatter function by name.
|
|
11786
11981
|
*
|
|
11982
|
+
* @internal
|
|
11787
11983
|
* @param name - Name of formatter.
|
|
11788
11984
|
* @returns Formatter function or null if it doesn't exist.
|
|
11789
11985
|
*/
|