Skip to content

Commit 55a7bfc

Browse files
committed
implement
1 parent d86c507 commit 55a7bfc

File tree

4 files changed

+79
-23
lines changed

4 files changed

+79
-23
lines changed

packages/eslint-plugin/lib/rules/use-standard-html/check-content-model.js

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* @property {AnyHTMLNode[]} children
1616
*/
1717

18+
const { getElementSpec } = require("html-standard");
19+
const { isTag } = require("../utils/node");
1820
const { shouldIgnoreChild, getNodeName } = require("./helpers");
1921

2022
const EXIT = false;
@@ -47,10 +49,23 @@ function getContentModel(state) {
4749
/**
4850
* @param {Context} context
4951
* @param {ElementSpec} spec
50-
* @param {AnyHTMLNode} node
52+
* @param {Tag} node
5153
* @param {AnyHTMLNode[]} children
54+
* @param {boolean} allowUnknownChildren
5255
*/
53-
function checkContentModel(context, spec, node, children) {
56+
function checkContentModel(
57+
context,
58+
spec,
59+
node,
60+
children,
61+
allowUnknownChildren
62+
) {
63+
if (
64+
allowUnknownChildren &&
65+
children.some((child) => isTag(child) && !getElementSpec(child.name))
66+
) {
67+
return;
68+
}
5469
/**
5570
* @type {State}
5671
*/
@@ -66,6 +81,7 @@ function checkContentModel(context, spec, node, children) {
6681
if (!contentModel) {
6782
return;
6883
}
84+
6985
switch (contentModel.type) {
7086
case "required": {
7187
result = required(contentModel, context, state, node);
@@ -91,7 +107,12 @@ function checkContentModel(context, spec, node, children) {
91107
}
92108
}
93109
}
94-
const remain = getChild(state);
110+
let remain = getChild(state);
111+
while (remain && shouldIgnoreChild(remain)) {
112+
state.childIndex++;
113+
remain = getChild(state);
114+
}
115+
95116
const contentModel = getContentModel(state);
96117
if (remain && !contentModel) {
97118
context.report({
@@ -105,29 +126,32 @@ function checkContentModel(context, spec, node, children) {
105126
* @param {ContentModel & {type: "required"}} model
106127
* @param {Context} context
107128
* @param {State} state
108-
* @param {AnyHTMLNode} node
129+
* @param {Tag} node
109130
* @returns {boolean}
110131
*/
132+
111133
function required(model, context, state, node) {
112134
let child = getChild(state);
135+
while (child && shouldIgnoreChild(child)) {
136+
state.childIndex++;
137+
child = getChild(state);
138+
}
113139
if (!child) {
114140
context.report({
115-
node,
141+
node: node.openStart,
116142
messageId: MESSAGE_IDS.REQUIRED,
117143
});
118144
return EXIT;
119145
}
120-
if (shouldIgnoreChild(child)) {
121-
state.childIndex++;
122-
}
146+
123147
const name = getNodeName(child);
124148
if (model.contents.has(name)) {
125149
state.childIndex++;
126150
state.contentModelIndex++;
127151
return CONTINUE;
128152
}
129153
context.report({
130-
node,
154+
node: node.openStart,
131155
messageId: MESSAGE_IDS.NOT_ALLOWED,
132156
});
133157
return EXIT;
@@ -166,7 +190,7 @@ function zeroOrMore(model, state) {
166190
* @param {ContentModel & {type: "oneOrMore"}} model
167191
* @param {Context} context
168192
* @param {State} state
169-
* @param {AnyHTMLNode} node
193+
* @param {Tag} node
170194
* @returns {boolean}
171195
*/
172196
function oneOrMore(model, context, state, node) {
@@ -193,7 +217,7 @@ function oneOrMore(model, context, state, node) {
193217

194218
if (count <= 0 && !model.contents.has("#text")) {
195219
context.report({
196-
node,
220+
node: node.openStart,
197221
messageId: MESSAGE_IDS.REQUIRED,
198222
});
199223
return EXIT;

packages/eslint-plugin/lib/rules/use-standard-html/use-standard-html.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @typedef {import("../../types").Context<[Option]> } Context
88
*
99
* @typedef {Object} Option
10-
* @property {string[]} [Option.priority]
10+
* @property {boolean} [Option.allowUnknownChildren]
1111
* @typedef { import("../../types").RuleModule<[Option]> } RuleModule
1212
*/
1313

@@ -33,22 +33,28 @@ module.exports = {
3333
{
3434
type: "object",
3535
properties: {
36-
priority: {
37-
type: "array",
38-
items: {
39-
type: "string",
40-
uniqueItems: true,
41-
},
36+
allowUnknownChildren: {
37+
type: "boolean",
4238
},
4339
},
4440
},
4541
],
4642
messages: {
47-
[MESSAGE_IDS.REQUIRED]: "TBD",
48-
[MESSAGE_IDS.NOT_ALLOWED]: "TBD",
43+
[MESSAGE_IDS.REQUIRED]: "required",
44+
[MESSAGE_IDS.NOT_ALLOWED]: "not allowed",
4945
},
5046
},
5147
create(context) {
48+
/**
49+
* @type {Option}
50+
*/
51+
const options =
52+
context.options && context.options[0]
53+
? context.options[0]
54+
: {
55+
allowUnknownChildren: true,
56+
};
57+
const allowUnknownChildren = options.allowUnknownChildren;
5258
return {
5359
Tag(node) {
5460
const name = node.name.toLowerCase();
@@ -67,7 +73,13 @@ module.exports = {
6773
return;
6874
}
6975

70-
checkContentModel(context, spec, node, node.children);
76+
checkContentModel(
77+
context,
78+
spec,
79+
node,
80+
node.children,
81+
allowUnknownChildren === true
82+
);
7183
},
7284
};
7385
},

packages/eslint-plugin/tests/rules/use-standard-html.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ const ruleTester = createRuleTester();
55

66
ruleTester.run("use-standard-html", rule, {
77
valid: [
8+
{
9+
code: `<html>
10+
<head><title>TITLE</title></head>
11+
<body></body>
12+
</html>`,
13+
},
14+
{
15+
code: "<title>TITLE</title>",
16+
},
17+
{
18+
code: "<span>TITLE</span>",
19+
},
820
{
921
code: `<slot></slot>`,
1022
},
@@ -143,6 +155,14 @@ ruleTester.run("use-standard-html", rule, {
143155
},
144156
],
145157
},
158+
{
159+
code: `<div><style> .foo { } </style></div>`,
160+
errors: [
161+
{
162+
messageId: "notAllowed",
163+
},
164+
],
165+
},
146166
{
147167
code: `<fieldset><base></base></fieldset>`,
148168
errors: [

packages/website/src/components/header/header.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@
4141
class="menuInput peer sr-only hidden"
4242
aria-hidden="true"
4343
>
44-
<label
44+
<span
4545
for="menu"
4646
aria-label="menu button"
4747
class="burger flex flex-col justify-between ml-auto h-[21px] w-[21px] px-[1px] py-[3px] [&>div]:h-[2px] [&>div]:w-[18px] [&>div]:bg-black-900 md:hidden hover:cursor-pointer"
4848
>
4949
<div></div>
5050
<div></div>
5151
<div></div>
52-
</label>
52+
</span>
5353
<module href="/components/header/nav.html"></module>
5454
</header>
5555

0 commit comments

Comments
 (0)