Skip to content

Commit

Permalink
feat(template-compiler): warning for slot attribute not at the top level
Browse files Browse the repository at this point in the history
  • Loading branch information
cardoso committed Oct 26, 2024
1 parent cd41384 commit 2796e28
Show file tree
Hide file tree
Showing 8 changed files with 267 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/@lwc/engine-server/src/__tests__/fixtures.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ async function compileFixture({ input, dirname }: { input: string; dirname: stri
message.includes('LWC1187') ||
// TODO [#4497]: stop warning on duplicate slots or disallow them entirely (LWC1137 is duplicate slots)
message.includes('LWC1137') ||
message.includes('LWC1201') ||
message.includes('-h-t-m-l') ||
code === 'CIRCULAR_DEPENDENCY';
if (!shouldIgnoreWarning) {
Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/errors/src/compiler/error-info/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
/**
* Next error code: 1201
* Next error code: 1202
*/

export * from './compiler';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -939,4 +939,11 @@ export const ParserDiagnostics = {
level: DiagnosticLevel.Error,
url: '',
},

IGNORED_SLOT_ATTRIBUTE_IN_CHILD: {
code: 1201,
message: 'The slot attribute in {0} will likely be ignored by its parent {1}.',
level: DiagnosticLevel.Warning,
url: '',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<template>
<x-inner>
<div>
<span slot="foo">I am the foo slot</span>
</div>
</x-inner>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
{
"root": {
"type": "Root",
"location": {
"startLine": 1,
"startColumn": 1,
"endLine": 7,
"endColumn": 12,
"start": 0,
"end": 134,
"startTag": {
"startLine": 1,
"startColumn": 1,
"endLine": 1,
"endColumn": 11,
"start": 0,
"end": 10
},
"endTag": {
"startLine": 7,
"startColumn": 1,
"endLine": 7,
"endColumn": 12,
"start": 123,
"end": 134
}
},
"directives": [],
"children": [
{
"type": "Component",
"name": "x-inner",
"namespace": "http://www.w3.org/1999/xhtml",
"location": {
"startLine": 2,
"startColumn": 5,
"endLine": 6,
"endColumn": 15,
"start": 15,
"end": 122,
"startTag": {
"startLine": 2,
"startColumn": 5,
"endLine": 2,
"endColumn": 14,
"start": 15,
"end": 24
},
"endTag": {
"startLine": 6,
"startColumn": 5,
"endLine": 6,
"endColumn": 15,
"start": 112,
"end": 122
}
},
"attributes": [],
"properties": [],
"directives": [],
"listeners": [],
"children": [
{
"type": "Element",
"name": "div",
"namespace": "http://www.w3.org/1999/xhtml",
"location": {
"startLine": 3,
"startColumn": 9,
"endLine": 5,
"endColumn": 15,
"start": 33,
"end": 107,
"startTag": {
"startLine": 3,
"startColumn": 9,
"endLine": 3,
"endColumn": 14,
"start": 33,
"end": 38
},
"endTag": {
"startLine": 5,
"startColumn": 9,
"endLine": 5,
"endColumn": 15,
"start": 101,
"end": 107
}
},
"attributes": [],
"properties": [],
"directives": [],
"listeners": [],
"children": [
{
"type": "Element",
"name": "span",
"namespace": "http://www.w3.org/1999/xhtml",
"location": {
"startLine": 4,
"startColumn": 13,
"endLine": 4,
"endColumn": 54,
"start": 51,
"end": 92,
"startTag": {
"startLine": 4,
"startColumn": 13,
"endLine": 4,
"endColumn": 30,
"start": 51,
"end": 68
},
"endTag": {
"startLine": 4,
"startColumn": 47,
"endLine": 4,
"endColumn": 54,
"start": 85,
"end": 92
}
},
"attributes": [
{
"type": "Attribute",
"name": "slot",
"value": {
"type": "Literal",
"value": "foo"
},
"location": {
"startLine": 4,
"startColumn": 19,
"endLine": 4,
"endColumn": 29,
"start": 57,
"end": 67
}
}
],
"properties": [],
"directives": [],
"listeners": [],
"children": [
{
"type": "Text",
"raw": "I am the foo slot",
"value": {
"type": "Literal",
"value": "I am the foo slot"
},
"location": {
"startLine": 4,
"startColumn": 30,
"endLine": 4,
"endColumn": 47,
"start": 68,
"end": 85
}
}
]
}
]
}
]
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import _implicitStylesheets from "./top-level-warning.css";
import _implicitScopedStylesheets from "./top-level-warning.scoped.css?scoped=true";
import _xInner from "x/inner";
import { freezeTemplate, registerTemplate } from "lwc";
const stc0 = {
key: 0,
};
const stc1 = {
key: 1,
};
const stc2 = {
slotAssignment: "foo",
key: 2,
};
function tmpl($api, $cmp, $slotset, $ctx) {
const { t: api_text, h: api_element, c: api_custom_element } = $api;
return [
api_custom_element("x-inner", _xInner, stc0, [
api_element("div", stc1, [
api_element("span", stc2, [api_text("I am the foo slot")]),
]),
]),
];
/*LWC compiler vX.X.X*/
}
export default registerTemplate(tmpl);
tmpl.stylesheets = [];
tmpl.stylesheetToken = "lwc-2vrd1nfb7kv";
tmpl.legacyStylesheetToken = "x-top-level-warning_top-level-warning";
if (_implicitStylesheets) {
tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets);
}
if (_implicitScopedStylesheets) {
tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets);
}
freezeTemplate(tmpl);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"warnings": [
{
"code": 1201,
"message": "LWC1201: The slot attribute in <span> will likely be ignored by its parent <div>.",
"level": 2,
"location": {
"line": 4,
"column": 19,
"start": 57,
"length": 10
}
}
]
}
30 changes: 30 additions & 0 deletions packages/@lwc/template-compiler/src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ function parseElement(
applyLwcDirectives(ctx, parsedAttr, element);
applyAttributes(ctx, parsedAttr, element);

validateSlotAttribute(ctx, parsedAttr, parentNode, element);
validateElement(ctx, element, parse5Elm);
validateAttributes(ctx, parsedAttr, element);
validateProperties(ctx, element);
Expand Down Expand Up @@ -1725,6 +1726,35 @@ function validateAttributes(
}
}

function validateSlotAttribute(
ctx: ParserCtx,
parsedAttr: ParsedAttribute,
parentNode: ParentNode,
element: BaseElement
): void {
const slotAttr = parsedAttr.get('slot');

if (!slotAttr) {
return;
}

if (
ast.isElement(parentNode) ||
ast.isForEach(parentNode) ||
ast.isForOf(parentNode) ||
ast.isSlot(parentNode)
) {
const parentName =
ast.isElement(parentNode) || ast.isSlot(parentNode)
? `<${parentNode.name}>`
: 'iteration block';
ctx.warnOnNode(ParserDiagnostics.IGNORED_SLOT_ATTRIBUTE_IN_CHILD, slotAttr, [
`<${element.name}>`,
parentName,
]);
}
}

function validateProperties(ctx: ParserCtx, element: BaseElement): void {
for (const prop of element.properties) {
const { attributeName: attrName, value } = prop;
Expand Down

0 comments on commit 2796e28

Please sign in to comment.