Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: 1214
* Next error code: 1215
*/

export * from './compiler';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,16 @@ export const ParserDiagnostics = {
url: '',
},

DOCUMENT_STRUCTURE_TAG_NOT_ALLOWED_IN_TEMPLATE: {
code: 1214,
message:
"The '<0>' tag is not allowed inside an LWC template and will not be rendered. " +
"'<html>', '<head>', '<body>', and doctype declarations are document-level constructs " +
'and have no meaning inside a component template.',
level: DiagnosticLevel.Warning,
url: '',
},

UNKNOWN_HTML_TAG_IN_TEMPLATE: {
code: 1123,
message:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<template>
<!doctype html>
<html></html>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some tags with props? Also, what happens if there's more than one of a kind, since these are usually unique per document? What happens if there's an unmatched opening tag, or an unmatched closing tag?

<head></head>
<body></body>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"root": {
"type": "Root",
"location": {
"startLine": 1,
"startColumn": 1,
"endLine": 6,
"endColumn": 12,
"start": 0,
"end": 96,
"startTag": {
"startLine": 1,
"startColumn": 1,
"endLine": 1,
"endColumn": 11,
"start": 0,
"end": 10
},
"endTag": {
"startLine": 6,
"startColumn": 1,
"endLine": 6,
"endColumn": 12,
"start": 85,
"end": 96
}
},
"directives": [],
"children": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import _implicitStylesheets from "./disallowed-document-structure-tags.css";
import _implicitScopedStylesheets from "./disallowed-document-structure-tags.scoped.css?scoped=true";
import { freezeTemplate, registerTemplate } from "lwc";
const stc0 = [];
function tmpl($api, $cmp, $slotset, $ctx) {
return stc0;
/*LWC compiler vX.X.X*/
}
export default registerTemplate(tmpl);
tmpl.stylesheets = [];
tmpl.stylesheetToken = "lwc-5d17n7c3a3p";
tmpl.legacyStylesheetToken =
"x-disallowed-document-structure-tags_disallowed-document-structure-tags";
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,88 @@
{
"warnings": [
{
"code": 1214,
"message": "LWC1214: The '<0>' tag is not allowed inside an LWC template and will not be rendered. '<html>', '<head>', '<body>', and doctype declarations are document-level constructs and have no meaning inside a component template.",
"level": 2,
"url": "",
"location": {
"line": 1,
"column": 11,
"start": 10,
"length": 75
}
},
{
"code": 1214,
"message": "LWC1214: The '<0>' tag is not allowed inside an LWC template and will not be rendered. '<html>', '<head>', '<body>', and doctype declarations are document-level constructs and have no meaning inside a component template.",
"level": 2,
"url": "",
"location": {
"line": 1,
"column": 11,
"start": 10,
"length": 75
}
},
{
"code": 1214,
"message": "LWC1214: The '<0>' tag is not allowed inside an LWC template and will not be rendered. '<html>', '<head>', '<body>', and doctype declarations are document-level constructs and have no meaning inside a component template.",
"level": 2,
"url": "",
"location": {
"line": 1,
"column": 11,
"start": 10,
"length": 75
}
},
{
"code": 1214,
"message": "LWC1214: The '<0>' tag is not allowed inside an LWC template and will not be rendered. '<html>', '<head>', '<body>', and doctype declarations are document-level constructs and have no meaning inside a component template.",
"level": 2,
"url": "",
"location": {
"line": 1,
"column": 11,
"start": 10,
"length": 75
}
},
{
"code": 1214,
"message": "LWC1214: The '<0>' tag is not allowed inside an LWC template and will not be rendered. '<html>', '<head>', '<body>', and doctype declarations are document-level constructs and have no meaning inside a component template.",
"level": 2,
"url": "",
"location": {
"line": 1,
"column": 11,
"start": 10,
"length": 75
}
},
{
"code": 1214,
"message": "LWC1214: The '<0>' tag is not allowed inside an LWC template and will not be rendered. '<html>', '<head>', '<body>', and doctype declarations are document-level constructs and have no meaning inside a component template.",
"level": 2,
"url": "",
"location": {
"line": 1,
"column": 11,
"start": 10,
"length": 75
}
},
{
"code": 1214,
"message": "LWC1214: The '<0>' tag is not allowed inside an LWC template and will not be rendered. '<html>', '<head>', '<body>', and doctype declarations are document-level constructs and have no meaning inside a component template.",
"level": 2,
"url": "",
"location": {
"line": 1,
"column": 11,
"start": 10,
"length": 75
}
}
]
}
2 changes: 2 additions & 0 deletions packages/@lwc/template-compiler/src/parser/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export const ATTRS_PROPS_TRANFORMS: { [attr: string]: string } = {

export const DISALLOWED_HTML_TAGS = new Set(['base', 'link', 'meta', 'script', 'title']);

export const DOCUMENT_STRUCTURE_TAGS_RE = /<!doctype[^>]*>|<\/?(?:html|head|body)(?:\s[^>]*)?>/gi;

export const KNOWN_HTML_AND_SVG_ELEMENTS = new Set([...HTML_ELEMENTS, ...SVG_ELEMENTS]);

export const HTML_TAG = {
Expand Down
21 changes: 19 additions & 2 deletions packages/@lwc/template-compiler/src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
import {
DISALLOWED_HTML_TAGS,
DISALLOWED_MATHML_TAGS,
DOCUMENT_STRUCTURE_TAGS_RE,
EVENT_HANDLER_NAME_RE,
EVENT_HANDLER_RE,
EXPRESSION_RE,
Expand Down Expand Up @@ -568,8 +569,24 @@ function parseTextNode(ctx: ParserCtx, parse5Text: parse5Tools.TextNode): Text[]
);
}

// Extract the raw source to avoid HTML entity decoding done by parse5
const rawText = cleanTextNode(ctx.getSource(location.startOffset, location.endOffset));
// parse5 collapses <html>/<head>/<body>/doctype into a text node when parsing
// a fragment. We re-read raw source here, so their literal markup leaks through
// as rendered text without this check. Strip and warn instead.
// https://github.com/salesforce/lwc/issues/3681
let rawText = cleanTextNode(ctx.getSource(location.startOffset, location.endOffset));

const documentStructureMatches = rawText.match(DOCUMENT_STRUCTURE_TAGS_RE);
if (documentStructureMatches) {
for (const match of documentStructureMatches) {
const tagName = match.replace(/[<>/]/g, '').split(/\s/)[0];
ctx.warnAtLocation(
ParserDiagnostics.DOCUMENT_STRUCTURE_TAG_NOT_ALLOWED_IN_TEMPLATE,
ast.sourceLocation(location),
[tagName]
);
}
rawText = rawText.replace(DOCUMENT_STRUCTURE_TAGS_RE, '');
}

if (!rawText.trim().length) {
return [];
Expand Down
Loading