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/cjs/core.js
CHANGED
|
@@ -264,6 +264,9 @@ class NestedError extends Error {
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
/**
|
|
268
|
+
* @public
|
|
269
|
+
*/
|
|
267
270
|
class UserError extends NestedError {
|
|
268
271
|
}
|
|
269
272
|
|
|
@@ -274,6 +277,9 @@ function getSummary(schema, obj, errors) {
|
|
|
274
277
|
// istanbul ignore next: for safety only
|
|
275
278
|
return output.length > 0 ? output[0].error : "unknown validation error";
|
|
276
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* @public
|
|
282
|
+
*/
|
|
277
283
|
class SchemaValidationError extends UserError {
|
|
278
284
|
constructor(filename, message, obj, schema, errors) {
|
|
279
285
|
const summary = getSummary(schema, obj, errors);
|
|
@@ -707,6 +713,8 @@ var TextContent$1;
|
|
|
707
713
|
/**
|
|
708
714
|
* Properties listed here can be copied (loaded) onto another element using
|
|
709
715
|
* [[HtmlElement.loadMeta]].
|
|
716
|
+
*
|
|
717
|
+
* @public
|
|
710
718
|
*/
|
|
711
719
|
const MetaCopyableProperty = [
|
|
712
720
|
"metadata",
|
|
@@ -847,16 +855,27 @@ const ajvRegexpKeyword = {
|
|
|
847
855
|
errors: true,
|
|
848
856
|
validate: ajvRegexpValidate,
|
|
849
857
|
};
|
|
858
|
+
/**
|
|
859
|
+
* @public
|
|
860
|
+
*/
|
|
850
861
|
class MetaTable {
|
|
862
|
+
/**
|
|
863
|
+
* @internal
|
|
864
|
+
*/
|
|
851
865
|
constructor() {
|
|
852
866
|
this.elements = {};
|
|
853
867
|
this.schema = clone(schema);
|
|
854
868
|
}
|
|
869
|
+
/**
|
|
870
|
+
* @internal
|
|
871
|
+
*/
|
|
855
872
|
init() {
|
|
856
873
|
this.resolveGlobal();
|
|
857
874
|
}
|
|
858
875
|
/**
|
|
859
876
|
* Extend validation schema.
|
|
877
|
+
*
|
|
878
|
+
* @internal
|
|
860
879
|
*/
|
|
861
880
|
extendValidationSchema(patch) {
|
|
862
881
|
if (patch.properties) {
|
|
@@ -877,6 +896,7 @@ class MetaTable {
|
|
|
877
896
|
/**
|
|
878
897
|
* Load metadata table from object.
|
|
879
898
|
*
|
|
899
|
+
* @internal
|
|
880
900
|
* @param obj - Object with metadata to load
|
|
881
901
|
* @param filename - Optional filename used when presenting validation error
|
|
882
902
|
*/
|
|
@@ -897,6 +917,7 @@ class MetaTable {
|
|
|
897
917
|
/**
|
|
898
918
|
* Load metadata table from filename
|
|
899
919
|
*
|
|
920
|
+
* @internal
|
|
900
921
|
* @param filename - Filename to load
|
|
901
922
|
*/
|
|
902
923
|
loadFromFile(filename) {
|
|
@@ -915,6 +936,7 @@ class MetaTable {
|
|
|
915
936
|
/**
|
|
916
937
|
* Get [[MetaElement]] for the given tag or null if the element doesn't exist.
|
|
917
938
|
*
|
|
939
|
+
* @public
|
|
918
940
|
* @returns A shallow copy of metadata.
|
|
919
941
|
*/
|
|
920
942
|
getMetaFor(tagName) {
|
|
@@ -923,6 +945,8 @@ class MetaTable {
|
|
|
923
945
|
}
|
|
924
946
|
/**
|
|
925
947
|
* Find all tags which has enabled given property.
|
|
948
|
+
*
|
|
949
|
+
* @public
|
|
926
950
|
*/
|
|
927
951
|
getTagsWithProperty(propName) {
|
|
928
952
|
return Object.entries(this.elements)
|
|
@@ -931,6 +955,8 @@ class MetaTable {
|
|
|
931
955
|
}
|
|
932
956
|
/**
|
|
933
957
|
* Find tag matching tagName or inheriting from it.
|
|
958
|
+
*
|
|
959
|
+
* @public
|
|
934
960
|
*/
|
|
935
961
|
getTagsDerivedFrom(tagName) {
|
|
936
962
|
return Object.entries(this.elements)
|
|
@@ -962,6 +988,9 @@ class MetaTable {
|
|
|
962
988
|
ajv.addKeyword({ keyword: "copyable" });
|
|
963
989
|
return ajv.compile(this.schema);
|
|
964
990
|
}
|
|
991
|
+
/**
|
|
992
|
+
* @public
|
|
993
|
+
*/
|
|
965
994
|
getJSONSchema() {
|
|
966
995
|
return this.schema;
|
|
967
996
|
}
|
|
@@ -997,6 +1026,9 @@ class MetaTable {
|
|
|
997
1026
|
merged.attributes = Object.fromEntries(filteredAttrs);
|
|
998
1027
|
return merged;
|
|
999
1028
|
}
|
|
1029
|
+
/**
|
|
1030
|
+
* @internal
|
|
1031
|
+
*/
|
|
1000
1032
|
resolve(node) {
|
|
1001
1033
|
if (node.meta) {
|
|
1002
1034
|
expandProperties(node, node.meta);
|
|
@@ -1091,6 +1123,9 @@ function matchAttribute(node, match) {
|
|
|
1091
1123
|
}
|
|
1092
1124
|
}
|
|
1093
1125
|
|
|
1126
|
+
/**
|
|
1127
|
+
* @public
|
|
1128
|
+
*/
|
|
1094
1129
|
class DynamicValue {
|
|
1095
1130
|
constructor(expr) {
|
|
1096
1131
|
this.expr = expr;
|
|
@@ -1207,12 +1242,14 @@ var State;
|
|
|
1207
1242
|
State[State["ATTR"] = 5] = "ATTR";
|
|
1208
1243
|
State[State["CDATA"] = 6] = "CDATA";
|
|
1209
1244
|
State[State["SCRIPT"] = 7] = "SCRIPT";
|
|
1245
|
+
State[State["STYLE"] = 8] = "STYLE";
|
|
1210
1246
|
})(State || (State = {}));
|
|
1211
1247
|
|
|
1212
1248
|
var ContentModel;
|
|
1213
1249
|
(function (ContentModel) {
|
|
1214
1250
|
ContentModel[ContentModel["TEXT"] = 1] = "TEXT";
|
|
1215
1251
|
ContentModel[ContentModel["SCRIPT"] = 2] = "SCRIPT";
|
|
1252
|
+
ContentModel[ContentModel["STYLE"] = 3] = "STYLE";
|
|
1216
1253
|
})(ContentModel || (ContentModel = {}));
|
|
1217
1254
|
class Context {
|
|
1218
1255
|
constructor(source) {
|
|
@@ -1741,6 +1778,8 @@ const TEXT_NODE_NAME = "#text";
|
|
|
1741
1778
|
*
|
|
1742
1779
|
* Text nodes are appended as children of `HtmlElement` and cannot have childen
|
|
1743
1780
|
* of its own.
|
|
1781
|
+
*
|
|
1782
|
+
* @public
|
|
1744
1783
|
*/
|
|
1745
1784
|
class TextNode extends DOMNode {
|
|
1746
1785
|
/**
|
|
@@ -1772,6 +1811,9 @@ class TextNode extends DOMNode {
|
|
|
1772
1811
|
}
|
|
1773
1812
|
}
|
|
1774
1813
|
|
|
1814
|
+
/**
|
|
1815
|
+
* @public
|
|
1816
|
+
*/
|
|
1775
1817
|
exports.NodeClosed = void 0;
|
|
1776
1818
|
(function (NodeClosed) {
|
|
1777
1819
|
NodeClosed[NodeClosed["Open"] = 0] = "Open";
|
|
@@ -1786,6 +1828,9 @@ function isElement(node) {
|
|
|
1786
1828
|
function isValidTagName(tagName) {
|
|
1787
1829
|
return Boolean(tagName !== "" && tagName !== "*");
|
|
1788
1830
|
}
|
|
1831
|
+
/**
|
|
1832
|
+
* @public
|
|
1833
|
+
*/
|
|
1789
1834
|
class HtmlElement extends DOMNode {
|
|
1790
1835
|
constructor(tagName, parent, closed, meta, location) {
|
|
1791
1836
|
const nodeType = tagName ? NodeType.ELEMENT_NODE : NodeType.DOCUMENT_NODE;
|
|
@@ -1811,9 +1856,15 @@ class HtmlElement extends DOMNode {
|
|
|
1811
1856
|
}
|
|
1812
1857
|
}
|
|
1813
1858
|
}
|
|
1859
|
+
/**
|
|
1860
|
+
* @internal
|
|
1861
|
+
*/
|
|
1814
1862
|
static rootNode(location) {
|
|
1815
1863
|
return new HtmlElement(undefined, null, exports.NodeClosed.EndTag, null, location);
|
|
1816
1864
|
}
|
|
1865
|
+
/**
|
|
1866
|
+
* @internal
|
|
1867
|
+
*/
|
|
1817
1868
|
static fromTokens(startToken, endToken, parent, metaTable) {
|
|
1818
1869
|
const tagName = startToken.data[2];
|
|
1819
1870
|
if (!tagName) {
|
|
@@ -2123,6 +2174,8 @@ class HtmlElement extends DOMNode {
|
|
|
2123
2174
|
}
|
|
2124
2175
|
/**
|
|
2125
2176
|
* Visit all nodes from this node and down. Depth first.
|
|
2177
|
+
*
|
|
2178
|
+
* @internal
|
|
2126
2179
|
*/
|
|
2127
2180
|
visitDepthFirst(callback) {
|
|
2128
2181
|
function visit(node) {
|
|
@@ -2135,6 +2188,8 @@ class HtmlElement extends DOMNode {
|
|
|
2135
2188
|
}
|
|
2136
2189
|
/**
|
|
2137
2190
|
* Evaluates callbackk on all descendants, returning true if any are true.
|
|
2191
|
+
*
|
|
2192
|
+
* @internal
|
|
2138
2193
|
*/
|
|
2139
2194
|
someChildren(callback) {
|
|
2140
2195
|
return this.childElements.some(visit);
|
|
@@ -2149,6 +2204,8 @@ class HtmlElement extends DOMNode {
|
|
|
2149
2204
|
}
|
|
2150
2205
|
/**
|
|
2151
2206
|
* Evaluates callbackk on all descendants, returning true if all are true.
|
|
2207
|
+
*
|
|
2208
|
+
* @internal
|
|
2152
2209
|
*/
|
|
2153
2210
|
everyChildren(callback) {
|
|
2154
2211
|
return this.childElements.every(visit);
|
|
@@ -2163,6 +2220,8 @@ class HtmlElement extends DOMNode {
|
|
|
2163
2220
|
* Visit all nodes from this node and down. Breadth first.
|
|
2164
2221
|
*
|
|
2165
2222
|
* The first node for which the callback evaluates to true is returned.
|
|
2223
|
+
*
|
|
2224
|
+
* @internal
|
|
2166
2225
|
*/
|
|
2167
2226
|
find(callback) {
|
|
2168
2227
|
function visit(node) {
|
|
@@ -2770,6 +2829,9 @@ function compareKey(node, key, filename) {
|
|
|
2770
2829
|
}
|
|
2771
2830
|
}
|
|
2772
2831
|
}
|
|
2832
|
+
/**
|
|
2833
|
+
* @public
|
|
2834
|
+
*/
|
|
2773
2835
|
class TemplateExtractor {
|
|
2774
2836
|
constructor(ast, filename, data) {
|
|
2775
2837
|
this.ast = ast;
|
|
@@ -2863,19 +2925,28 @@ var TRANSFORMER_API;
|
|
|
2863
2925
|
TRANSFORMER_API[TRANSFORMER_API["VERSION"] = 1] = "VERSION";
|
|
2864
2926
|
})(TRANSFORMER_API || (TRANSFORMER_API = {}));
|
|
2865
2927
|
|
|
2928
|
+
/* generated file, changes will be overwritten */
|
|
2929
|
+
/** @public */
|
|
2866
2930
|
const name = "html-validate";
|
|
2867
|
-
|
|
2931
|
+
/** @public */
|
|
2932
|
+
const version = "6.1.3";
|
|
2933
|
+
/** @public */
|
|
2868
2934
|
const homepage = "https://html-validate.org";
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
};
|
|
2935
|
+
/** @public */
|
|
2936
|
+
const bugs = "https://gitlab.com/html-validate/html-validate/issues/new";
|
|
2872
2937
|
|
|
2938
|
+
/**
|
|
2939
|
+
* @public
|
|
2940
|
+
*/
|
|
2873
2941
|
exports.Severity = void 0;
|
|
2874
2942
|
(function (Severity) {
|
|
2875
2943
|
Severity[Severity["DISABLED"] = 0] = "DISABLED";
|
|
2876
2944
|
Severity[Severity["WARN"] = 1] = "WARN";
|
|
2877
2945
|
Severity[Severity["ERROR"] = 2] = "ERROR";
|
|
2878
2946
|
})(exports.Severity || (exports.Severity = {}));
|
|
2947
|
+
/**
|
|
2948
|
+
* @internal
|
|
2949
|
+
*/
|
|
2879
2950
|
function parseSeverity(value) {
|
|
2880
2951
|
switch (value) {
|
|
2881
2952
|
case 0:
|
|
@@ -2923,6 +2994,9 @@ function getSchemaValidator(ruleId, properties) {
|
|
|
2923
2994
|
};
|
|
2924
2995
|
return ajv$1.compile(schema);
|
|
2925
2996
|
}
|
|
2997
|
+
/**
|
|
2998
|
+
* @public
|
|
2999
|
+
*/
|
|
2926
3000
|
class Rule {
|
|
2927
3001
|
constructor(options) {
|
|
2928
3002
|
/* faux initialization, properly initialized by init(). This is to keep TS happy without adding null-checks everywhere */
|
|
@@ -3124,6 +3198,9 @@ class Rule {
|
|
|
3124
3198
|
return null;
|
|
3125
3199
|
}
|
|
3126
3200
|
}
|
|
3201
|
+
/**
|
|
3202
|
+
* @internal
|
|
3203
|
+
*/
|
|
3127
3204
|
function ruleDocumentationUrl(filename) {
|
|
3128
3205
|
/* during bundling all "@/rule.ts"'s are converted to paths relative to the src
|
|
3129
3206
|
* folder and with the @/ prefix, by replacing the @ with the dist folder we
|
|
@@ -3154,24 +3231,60 @@ const description = {
|
|
|
3154
3231
|
["absolute" /* ABSOLUTE */]: "Absolute links are not allowed by current configuration.",
|
|
3155
3232
|
["anchor" /* ANCHOR */]: null,
|
|
3156
3233
|
};
|
|
3234
|
+
function parseAllow(value) {
|
|
3235
|
+
if (typeof value === "boolean") {
|
|
3236
|
+
return value;
|
|
3237
|
+
}
|
|
3238
|
+
return {
|
|
3239
|
+
/* eslint-disable security/detect-non-literal-regexp */
|
|
3240
|
+
include: value.include ? value.include.map((it) => new RegExp(it)) : null,
|
|
3241
|
+
exclude: value.exclude ? value.exclude.map((it) => new RegExp(it)) : null,
|
|
3242
|
+
/* eslint-enable security/detect-non-literal-regexp */
|
|
3243
|
+
};
|
|
3244
|
+
}
|
|
3245
|
+
/**
|
|
3246
|
+
* @internal
|
|
3247
|
+
*/
|
|
3248
|
+
function matchList(value, list) {
|
|
3249
|
+
if (list.include && !list.include.some((it) => it.test(value))) {
|
|
3250
|
+
return false;
|
|
3251
|
+
}
|
|
3252
|
+
if (list.exclude && list.exclude.some((it) => it.test(value))) {
|
|
3253
|
+
return false;
|
|
3254
|
+
}
|
|
3255
|
+
return true;
|
|
3256
|
+
}
|
|
3157
3257
|
class AllowedLinks extends Rule {
|
|
3158
3258
|
constructor(options) {
|
|
3159
3259
|
super({ ...defaults$p, ...options });
|
|
3260
|
+
this.allowExternal = parseAllow(this.options.allowExternal);
|
|
3261
|
+
this.allowRelative = parseAllow(this.options.allowRelative);
|
|
3262
|
+
this.allowAbsolute = parseAllow(this.options.allowAbsolute);
|
|
3160
3263
|
}
|
|
3161
3264
|
static schema() {
|
|
3265
|
+
const booleanOrObject = {
|
|
3266
|
+
anyOf: [
|
|
3267
|
+
{ type: "boolean" },
|
|
3268
|
+
{
|
|
3269
|
+
type: "object",
|
|
3270
|
+
properties: {
|
|
3271
|
+
include: {
|
|
3272
|
+
type: "array",
|
|
3273
|
+
items: { type: "string" },
|
|
3274
|
+
},
|
|
3275
|
+
exclude: {
|
|
3276
|
+
type: "array",
|
|
3277
|
+
items: { type: "string" },
|
|
3278
|
+
},
|
|
3279
|
+
},
|
|
3280
|
+
},
|
|
3281
|
+
],
|
|
3282
|
+
};
|
|
3162
3283
|
return {
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
},
|
|
3166
|
-
allowBase: {
|
|
3167
|
-
type: "boolean",
|
|
3168
|
-
},
|
|
3169
|
-
allowExternal: {
|
|
3170
|
-
type: "boolean",
|
|
3171
|
-
},
|
|
3172
|
-
allowRelative: {
|
|
3173
|
-
type: "boolean",
|
|
3174
|
-
},
|
|
3284
|
+
allowExternal: { ...booleanOrObject },
|
|
3285
|
+
allowRelative: { ...booleanOrObject },
|
|
3286
|
+
allowAbsolute: { ...booleanOrObject },
|
|
3287
|
+
allowBase: { type: "boolean" },
|
|
3175
3288
|
};
|
|
3176
3289
|
}
|
|
3177
3290
|
documentation(context) {
|
|
@@ -3193,16 +3306,16 @@ class AllowedLinks extends Rule {
|
|
|
3193
3306
|
/* anchor links are always allowed by this rule */
|
|
3194
3307
|
break;
|
|
3195
3308
|
case "absolute" /* ABSOLUTE */:
|
|
3196
|
-
this.handleAbsolute(event, style);
|
|
3309
|
+
this.handleAbsolute(link, event, style);
|
|
3197
3310
|
break;
|
|
3198
3311
|
case "external" /* EXTERNAL */:
|
|
3199
|
-
this.handleExternal(event, style);
|
|
3312
|
+
this.handleExternal(link, event, style);
|
|
3200
3313
|
break;
|
|
3201
3314
|
case "relative-base" /* RELATIVE_BASE */:
|
|
3202
|
-
this.handleRelativeBase(event, style);
|
|
3315
|
+
this.handleRelativeBase(link, event, style);
|
|
3203
3316
|
break;
|
|
3204
3317
|
case "relative-path" /* RELATIVE_PATH */:
|
|
3205
|
-
this.handleRelativePath(event, style);
|
|
3318
|
+
this.handleRelativePath(link, event, style);
|
|
3206
3319
|
break;
|
|
3207
3320
|
}
|
|
3208
3321
|
});
|
|
@@ -3236,28 +3349,49 @@ class AllowedLinks extends Rule {
|
|
|
3236
3349
|
return "relative-base" /* RELATIVE_BASE */;
|
|
3237
3350
|
}
|
|
3238
3351
|
}
|
|
3239
|
-
handleAbsolute(event, style) {
|
|
3240
|
-
const { allowAbsolute } = this
|
|
3241
|
-
if (
|
|
3352
|
+
handleAbsolute(target, event, style) {
|
|
3353
|
+
const { allowAbsolute } = this;
|
|
3354
|
+
if (allowAbsolute === true) {
|
|
3355
|
+
return;
|
|
3356
|
+
}
|
|
3357
|
+
else if (allowAbsolute === false) {
|
|
3242
3358
|
this.report(event.target, "Link destination must not be absolute url", event.valueLocation, style);
|
|
3243
3359
|
}
|
|
3360
|
+
else if (!matchList(target, allowAbsolute)) {
|
|
3361
|
+
this.report(event.target, "Absolute link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3362
|
+
}
|
|
3244
3363
|
}
|
|
3245
|
-
handleExternal(event, style) {
|
|
3246
|
-
const { allowExternal } = this
|
|
3247
|
-
if (
|
|
3364
|
+
handleExternal(target, event, style) {
|
|
3365
|
+
const { allowExternal } = this;
|
|
3366
|
+
if (allowExternal === true) {
|
|
3367
|
+
return;
|
|
3368
|
+
}
|
|
3369
|
+
else if (allowExternal === false) {
|
|
3248
3370
|
this.report(event.target, "Link destination must not be external url", event.valueLocation, style);
|
|
3249
3371
|
}
|
|
3372
|
+
else if (!matchList(target, allowExternal)) {
|
|
3373
|
+
this.report(event.target, "External link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3374
|
+
}
|
|
3250
3375
|
}
|
|
3251
|
-
handleRelativePath(event, style) {
|
|
3252
|
-
const { allowRelative } = this
|
|
3253
|
-
if (
|
|
3376
|
+
handleRelativePath(target, event, style) {
|
|
3377
|
+
const { allowRelative } = this;
|
|
3378
|
+
if (allowRelative === true) {
|
|
3379
|
+
return false;
|
|
3380
|
+
}
|
|
3381
|
+
else if (allowRelative === false) {
|
|
3254
3382
|
this.report(event.target, "Link destination must not be relative url", event.valueLocation, style);
|
|
3383
|
+
return true;
|
|
3255
3384
|
}
|
|
3385
|
+
else if (!matchList(target, allowRelative)) {
|
|
3386
|
+
this.report(event.target, "Relative link to this destination is not allowed by current configuration", event.valueLocation, style);
|
|
3387
|
+
return true;
|
|
3388
|
+
}
|
|
3389
|
+
return false;
|
|
3256
3390
|
}
|
|
3257
|
-
handleRelativeBase(event, style) {
|
|
3258
|
-
const {
|
|
3259
|
-
if (
|
|
3260
|
-
|
|
3391
|
+
handleRelativeBase(target, event, style) {
|
|
3392
|
+
const { allowBase } = this.options;
|
|
3393
|
+
if (this.handleRelativePath(target, event, style)) {
|
|
3394
|
+
return;
|
|
3261
3395
|
}
|
|
3262
3396
|
else if (!allowBase) {
|
|
3263
3397
|
this.report(event.target, "Relative links must be relative to current folder", event.valueLocation, style);
|
|
@@ -3341,6 +3475,9 @@ class AriaLabelMisuse extends Rule {
|
|
|
3341
3475
|
}
|
|
3342
3476
|
}
|
|
3343
3477
|
|
|
3478
|
+
/**
|
|
3479
|
+
* @public
|
|
3480
|
+
*/
|
|
3344
3481
|
class ConfigError extends UserError {
|
|
3345
3482
|
}
|
|
3346
3483
|
|
|
@@ -3478,10 +3615,11 @@ exports.TokenType = void 0;
|
|
|
3478
3615
|
TokenType[TokenType["TEXT"] = 11] = "TEXT";
|
|
3479
3616
|
TokenType[TokenType["TEMPLATING"] = 12] = "TEMPLATING";
|
|
3480
3617
|
TokenType[TokenType["SCRIPT"] = 13] = "SCRIPT";
|
|
3481
|
-
TokenType[TokenType["
|
|
3482
|
-
TokenType[TokenType["
|
|
3483
|
-
TokenType[TokenType["
|
|
3484
|
-
TokenType[TokenType["
|
|
3618
|
+
TokenType[TokenType["STYLE"] = 14] = "STYLE";
|
|
3619
|
+
TokenType[TokenType["COMMENT"] = 15] = "COMMENT";
|
|
3620
|
+
TokenType[TokenType["CONDITIONAL"] = 16] = "CONDITIONAL";
|
|
3621
|
+
TokenType[TokenType["DIRECTIVE"] = 17] = "DIRECTIVE";
|
|
3622
|
+
TokenType[TokenType["EOF"] = 18] = "EOF";
|
|
3485
3623
|
})(exports.TokenType || (exports.TokenType = {}));
|
|
3486
3624
|
|
|
3487
3625
|
/* eslint-disable no-useless-escape */
|
|
@@ -3494,7 +3632,7 @@ const MATCH_XML_TAG = /^<\?xml.*?\?>\s+/;
|
|
|
3494
3632
|
const MATCH_TAG_OPEN = /^<(\/?)([a-zA-Z0-9\-:]+)/; // https://www.w3.org/TR/html/syntax.html#start-tags
|
|
3495
3633
|
const MATCH_TAG_CLOSE = /^\/?>/;
|
|
3496
3634
|
const MATCH_TEXT = /^[^]*?(?=(?:[ \t]*(?:\r\n|\r|\n)|<[^ ]|$))/;
|
|
3497
|
-
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)
|
|
3635
|
+
const MATCH_TEMPLATING = /^(?:<%.*?%>|<\?.*?\?>|<\$.*?\$>)/s;
|
|
3498
3636
|
const MATCH_TAG_LOOKAHEAD = /^[^]*?(?=<|$)/;
|
|
3499
3637
|
const MATCH_ATTR_START = /^([^\t\r\n\f \/><"'=]+)/; // https://www.w3.org/TR/html/syntax.html#elements-attributes
|
|
3500
3638
|
const MATCH_ATTR_SINGLE = /^(\s*=\s*)'([^']*?)(')/;
|
|
@@ -3504,6 +3642,8 @@ const MATCH_CDATA_BEGIN = /^<!\[CDATA\[/;
|
|
|
3504
3642
|
const MATCH_CDATA_END = /^[^]*?]]>/;
|
|
3505
3643
|
const MATCH_SCRIPT_DATA = /^[^]*?(?=<\/script)/;
|
|
3506
3644
|
const MATCH_SCRIPT_END = /^<(\/)(script)/;
|
|
3645
|
+
const MATCH_STYLE_DATA = /^[^]*?(?=<\/style)/;
|
|
3646
|
+
const MATCH_STYLE_END = /^<(\/)(style)/;
|
|
3507
3647
|
const MATCH_DIRECTIVE = /^<!--\s*\[html-validate-(.*?)]\s*-->/;
|
|
3508
3648
|
const MATCH_COMMENT = /^<!--([^]*?)-->/;
|
|
3509
3649
|
const MATCH_CONDITIONAL = /^<!\[([^\]]*?)\]>/;
|
|
@@ -3543,6 +3683,9 @@ class Lexer {
|
|
|
3543
3683
|
case State.SCRIPT:
|
|
3544
3684
|
yield* this.tokenizeScript(context);
|
|
3545
3685
|
break;
|
|
3686
|
+
case State.STYLE:
|
|
3687
|
+
yield* this.tokenizeStyle(context);
|
|
3688
|
+
break;
|
|
3546
3689
|
/* istanbul ignore next: sanity check: should not happen unless adding new states */
|
|
3547
3690
|
default:
|
|
3548
3691
|
this.unhandled(context);
|
|
@@ -3611,11 +3754,14 @@ class Lexer {
|
|
|
3611
3754
|
* Called when entering a new state.
|
|
3612
3755
|
*/
|
|
3613
3756
|
enter(context, state, data) {
|
|
3614
|
-
/* script tags require a different content model */
|
|
3757
|
+
/* script/style tags require a different content model */
|
|
3615
3758
|
if (state === State.TAG && data && data[0][0] === "<") {
|
|
3616
3759
|
if (data[0] === "<script") {
|
|
3617
3760
|
context.contentModel = ContentModel.SCRIPT;
|
|
3618
3761
|
}
|
|
3762
|
+
else if (data[0] === "<style") {
|
|
3763
|
+
context.contentModel = ContentModel.STYLE;
|
|
3764
|
+
}
|
|
3619
3765
|
else {
|
|
3620
3766
|
context.contentModel = ContentModel.TEXT;
|
|
3621
3767
|
}
|
|
@@ -3641,6 +3787,7 @@ class Lexer {
|
|
|
3641
3787
|
], "expected doctype name");
|
|
3642
3788
|
}
|
|
3643
3789
|
*tokenizeTag(context) {
|
|
3790
|
+
/* eslint-disable-next-line consistent-return -- exhaustive switch handled by typescript */
|
|
3644
3791
|
function nextState(token) {
|
|
3645
3792
|
switch (context.contentModel) {
|
|
3646
3793
|
case ContentModel.TEXT:
|
|
@@ -3652,11 +3799,14 @@ class Lexer {
|
|
|
3652
3799
|
else {
|
|
3653
3800
|
return State.TEXT; /* <script/> (not legal but handle it anyway so the lexer doesn't choke on it) */
|
|
3654
3801
|
}
|
|
3802
|
+
case ContentModel.STYLE:
|
|
3803
|
+
if (token && token.data[0][0] !== "/") {
|
|
3804
|
+
return State.STYLE;
|
|
3805
|
+
}
|
|
3806
|
+
else {
|
|
3807
|
+
return State.TEXT; /* <style/> */
|
|
3808
|
+
}
|
|
3655
3809
|
}
|
|
3656
|
-
/* istanbul ignore next: not covered by a test as there is currently no
|
|
3657
|
-
* way to trigger this unless new content models are added but this will
|
|
3658
|
-
* add a saner default if anyone ever does */
|
|
3659
|
-
return context.contentModel !== ContentModel.SCRIPT ? State.TEXT : State.SCRIPT;
|
|
3660
3810
|
}
|
|
3661
3811
|
yield* this.match(context, [
|
|
3662
3812
|
[MATCH_TAG_CLOSE, nextState, exports.TokenType.TAG_CLOSE],
|
|
@@ -3694,6 +3844,12 @@ class Lexer {
|
|
|
3694
3844
|
[MATCH_SCRIPT_DATA, State.SCRIPT, exports.TokenType.SCRIPT],
|
|
3695
3845
|
], "expected </script>");
|
|
3696
3846
|
}
|
|
3847
|
+
*tokenizeStyle(context) {
|
|
3848
|
+
yield* this.match(context, [
|
|
3849
|
+
[MATCH_STYLE_END, State.TAG, exports.TokenType.TAG_OPEN],
|
|
3850
|
+
[MATCH_STYLE_DATA, State.STYLE, exports.TokenType.STYLE],
|
|
3851
|
+
], "expected </style>");
|
|
3852
|
+
}
|
|
3697
3853
|
}
|
|
3698
3854
|
|
|
3699
3855
|
const whitespace = /(\s+)/;
|
|
@@ -5944,7 +6100,7 @@ function getCSSDeclarations(value) {
|
|
|
5944
6100
|
.filter(Boolean)
|
|
5945
6101
|
.map((it) => {
|
|
5946
6102
|
const [property, value] = it.split(":", 2);
|
|
5947
|
-
return { property: property.trim(), value: value.trim() };
|
|
6103
|
+
return { property: property.trim(), value: value ? value.trim() : undefined };
|
|
5948
6104
|
});
|
|
5949
6105
|
}
|
|
5950
6106
|
class NoInlineStyle extends Rule {
|
|
@@ -6159,7 +6315,7 @@ const defaults$9 = {
|
|
|
6159
6315
|
};
|
|
6160
6316
|
const textRegexp = /([<>]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6161
6317
|
const unquotedAttrRegexp = /([<>"'=`]|&(?![a-zA-Z0-9#]+;))/g;
|
|
6162
|
-
const matchTemplate = /^(<%.*?%>|<\?.*?\?>|<\$.*?\$>)
|
|
6318
|
+
const matchTemplate = /^(<%.*?%>|<\?.*?\?>|<\$.*?\$>)$/s;
|
|
6163
6319
|
const replacementTable = new Map([
|
|
6164
6320
|
['"', """],
|
|
6165
6321
|
["&", "&"],
|
|
@@ -9459,6 +9615,9 @@ const config = {
|
|
|
9459
9615
|
},
|
|
9460
9616
|
};
|
|
9461
9617
|
|
|
9618
|
+
/**
|
|
9619
|
+
* @internal
|
|
9620
|
+
*/
|
|
9462
9621
|
const presets = {
|
|
9463
9622
|
"html-validate:a17y": config$3,
|
|
9464
9623
|
"html-validate:document": config$2,
|
|
@@ -9606,8 +9765,13 @@ function loadFromFile(filename) {
|
|
|
9606
9765
|
* Configuration holder.
|
|
9607
9766
|
*
|
|
9608
9767
|
* Each file being validated will have a unique instance of this class.
|
|
9768
|
+
*
|
|
9769
|
+
* @public
|
|
9609
9770
|
*/
|
|
9610
9771
|
class Config {
|
|
9772
|
+
/**
|
|
9773
|
+
* @internal
|
|
9774
|
+
*/
|
|
9611
9775
|
constructor(options) {
|
|
9612
9776
|
var _a;
|
|
9613
9777
|
this.transformers = [];
|
|
@@ -9670,6 +9834,8 @@ class Config {
|
|
|
9670
9834
|
* Validate configuration data.
|
|
9671
9835
|
*
|
|
9672
9836
|
* Throws SchemaValidationError if invalid.
|
|
9837
|
+
*
|
|
9838
|
+
* @internal
|
|
9673
9839
|
*/
|
|
9674
9840
|
static validate(configData, filename = null) {
|
|
9675
9841
|
var _a;
|
|
@@ -9697,6 +9863,8 @@ class Config {
|
|
|
9697
9863
|
*
|
|
9698
9864
|
* Must be called before trying to use config. Can safely be called multiple
|
|
9699
9865
|
* times.
|
|
9866
|
+
*
|
|
9867
|
+
* @internal
|
|
9700
9868
|
*/
|
|
9701
9869
|
init() {
|
|
9702
9870
|
if (this.initialized) {
|
|
@@ -9716,6 +9884,7 @@ class Config {
|
|
|
9716
9884
|
* Returns a new configuration as a merge of the two. Entries from the passed
|
|
9717
9885
|
* object takes priority over this object.
|
|
9718
9886
|
*
|
|
9887
|
+
* @internal
|
|
9719
9888
|
* @param rhs - Configuration to merge with this one.
|
|
9720
9889
|
*/
|
|
9721
9890
|
merge(rhs) {
|
|
@@ -9808,6 +9977,8 @@ class Config {
|
|
|
9808
9977
|
}
|
|
9809
9978
|
/**
|
|
9810
9979
|
* Get all configured rules, their severity and options.
|
|
9980
|
+
*
|
|
9981
|
+
* @internal
|
|
9811
9982
|
*/
|
|
9812
9983
|
getRules() {
|
|
9813
9984
|
var _a;
|
|
@@ -9830,6 +10001,8 @@ class Config {
|
|
|
9830
10001
|
}
|
|
9831
10002
|
/**
|
|
9832
10003
|
* Get all configured plugins.
|
|
10004
|
+
*
|
|
10005
|
+
* @internal
|
|
9833
10006
|
*/
|
|
9834
10007
|
getPlugins() {
|
|
9835
10008
|
return this.plugins;
|
|
@@ -9895,6 +10068,8 @@ class Config {
|
|
|
9895
10068
|
*
|
|
9896
10069
|
* A resolved configuration will merge all extended configs and load all
|
|
9897
10070
|
* plugins and transformers, and normalize the rest of the configuration.
|
|
10071
|
+
*
|
|
10072
|
+
* @internal
|
|
9898
10073
|
*/
|
|
9899
10074
|
resolve() {
|
|
9900
10075
|
return new ResolvedConfig(this.resolveData());
|
|
@@ -10079,6 +10254,9 @@ class ConfigLoader {
|
|
|
10079
10254
|
}
|
|
10080
10255
|
}
|
|
10081
10256
|
|
|
10257
|
+
/**
|
|
10258
|
+
* @internal
|
|
10259
|
+
*/
|
|
10082
10260
|
class EventHandler {
|
|
10083
10261
|
constructor() {
|
|
10084
10262
|
this.listeners = {};
|
|
@@ -10159,6 +10337,8 @@ class ParserError extends Error {
|
|
|
10159
10337
|
|
|
10160
10338
|
/**
|
|
10161
10339
|
* Parse HTML document into a DOM tree.
|
|
10340
|
+
*
|
|
10341
|
+
* @internal
|
|
10162
10342
|
*/
|
|
10163
10343
|
class Parser {
|
|
10164
10344
|
/**
|
|
@@ -10635,6 +10815,9 @@ class Parser {
|
|
|
10635
10815
|
}
|
|
10636
10816
|
}
|
|
10637
10817
|
|
|
10818
|
+
/**
|
|
10819
|
+
* @internal
|
|
10820
|
+
*/
|
|
10638
10821
|
class Reporter {
|
|
10639
10822
|
constructor() {
|
|
10640
10823
|
this.result = {};
|
|
@@ -10753,6 +10936,9 @@ function messageSort(a, b) {
|
|
|
10753
10936
|
return 0;
|
|
10754
10937
|
}
|
|
10755
10938
|
|
|
10939
|
+
/**
|
|
10940
|
+
* @internal
|
|
10941
|
+
*/
|
|
10756
10942
|
class Engine {
|
|
10757
10943
|
constructor(config, ParserClass) {
|
|
10758
10944
|
this.report = new Reporter();
|
|
@@ -11106,6 +11292,8 @@ class Engine {
|
|
|
11106
11292
|
*
|
|
11107
11293
|
* In practice this means no configuration is fetch by traversing the
|
|
11108
11294
|
* filesystem.
|
|
11295
|
+
*
|
|
11296
|
+
* @public
|
|
11109
11297
|
*/
|
|
11110
11298
|
class StaticConfigLoader extends ConfigLoader {
|
|
11111
11299
|
getConfigFor(handle, configOverride) {
|
|
@@ -11145,6 +11333,8 @@ function isConfigData(value) {
|
|
|
11145
11333
|
* Primary API for using HTML-validate.
|
|
11146
11334
|
*
|
|
11147
11335
|
* Provides high-level abstractions for common operations.
|
|
11336
|
+
*
|
|
11337
|
+
* @public
|
|
11148
11338
|
*/
|
|
11149
11339
|
class HtmlValidate {
|
|
11150
11340
|
constructor(arg) {
|
|
@@ -11349,6 +11539,7 @@ class HtmlValidate {
|
|
|
11349
11539
|
/**
|
|
11350
11540
|
* Create a parser configured for given filename.
|
|
11351
11541
|
*
|
|
11542
|
+
* @internal
|
|
11352
11543
|
* @param source - Source to use.
|
|
11353
11544
|
*/
|
|
11354
11545
|
getParserFor(source) {
|
|
@@ -11392,6 +11583,7 @@ const defaults$1 = {
|
|
|
11392
11583
|
* Tests if plugin is compatible with html-validate library. Unless the `silent`
|
|
11393
11584
|
* option is used a warning is displayed on the console.
|
|
11394
11585
|
*
|
|
11586
|
+
* @public
|
|
11395
11587
|
* @param name - Name of plugin
|
|
11396
11588
|
* @param declared - What library versions the plugin support (e.g. declared peerDependencies)
|
|
11397
11589
|
* @returns - `true` if version is compatible
|
|
@@ -11420,6 +11612,7 @@ const ruleIds = new Set(Object.keys(bundledRules));
|
|
|
11420
11612
|
* Can be used to create forward/backward compatibility by checking if a rule
|
|
11421
11613
|
* exists to enable/disable it.
|
|
11422
11614
|
*
|
|
11615
|
+
* @public
|
|
11423
11616
|
* @param ruleId - Rule id to check
|
|
11424
11617
|
* @returns `true` if rule exists
|
|
11425
11618
|
*/
|
|
@@ -11459,6 +11652,8 @@ function findConfigurationFiles(directory) {
|
|
|
11459
11652
|
* 2. If set in the global config the override is merged into global and
|
|
11460
11653
|
* returned. No configuration files are searched.
|
|
11461
11654
|
* 3. Setting `root` in configuration file only stops directory traversal.
|
|
11655
|
+
*
|
|
11656
|
+
* @public
|
|
11462
11657
|
*/
|
|
11463
11658
|
class FileSystemConfigLoader extends ConfigLoader {
|
|
11464
11659
|
/**
|
|
@@ -11796,6 +11991,7 @@ const availableFormatters = {
|
|
|
11796
11991
|
/**
|
|
11797
11992
|
* Get formatter function by name.
|
|
11798
11993
|
*
|
|
11994
|
+
* @internal
|
|
11799
11995
|
* @param name - Name of formatter.
|
|
11800
11996
|
* @returns Formatter function or null if it doesn't exist.
|
|
11801
11997
|
*/
|