Skip to content

Commit

Permalink
feat(versioning): make parse5 warnings into errors
Browse files Browse the repository at this point in the history
  • Loading branch information
nolanlawson committed Feb 17, 2023
1 parent 45e6fc7 commit 068688e
Show file tree
Hide file tree
Showing 11 changed files with 49 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,4 @@
<template if:true={doRender}>
<tr></tr>
</template>
</template>
</template>
6 changes: 6 additions & 0 deletions packages/@lwc/shared/src/api-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,17 @@ export const enum APIFeature {
* This is just used as a placeholder.
*/
DUMMY_FEATURE,
/**
* If enabled, all parse5 errors will result in a compile-time error, rather than some being treated as warnings
* (for backwards compatibility).
*/
TREAT_ALL_PARSE5_ERRORS_AS_ERRORS,
}

export function isAPIFeatureEnabled(apiVersionFeature: APIFeature, apiVersion: APIVersion) {
switch (apiVersionFeature) {
case APIFeature.DUMMY_FEATURE:
case APIFeature.TREAT_ALL_PARSE5_ERRORS_AS_ERRORS:
return apiVersion >= APIVersion.V59_246_WINTER_24;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import parse5Errors from 'parse5/lib/common/error-codes';
import { errorCodesToErrorOn, errorCodesToWarnOn } from '../parser/parse5Errors';
import { errorCodesToErrorOn, errorCodesToWarnOnInOlderAPIVersions } from '../parser/parse5Errors';

describe('error codes', () => {
it('all parse5 error codes are accounted for', () => {
const allKnownCodes = new Set([...errorCodesToErrorOn, ...errorCodesToWarnOn]);
const allKnownCodes = new Set([
...errorCodesToErrorOn,
...errorCodesToWarnOnInOlderAPIVersions,
]);
for (const code of Object.values(parse5Errors)) {
expect(allKnownCodes.has(code as string)).toEqual(true);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<template>
<h1>hello</h1>
</template>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"apiVersion": 59
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"warnings": [
{
"code": 1058,
"message": "LWC1058: Invalid HTML syntax: end-tag-without-matching-open-element. For more information, please visit https://html.spec.whatwg.org/multipage/parsing.html#parse-error-end-tag-without-matching-open-element",
"level": 1,
"location": {
"line": 4,
"column": 1,
"start": 42,
"length": 11
}
}
]
}
17 changes: 11 additions & 6 deletions packages/@lwc/template-compiler/src/parser/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@ import * as parse5 from 'parse5';
import * as he from 'he';

import { ParserDiagnostics } from '@lwc/errors';

import { APIFeature, isAPIFeatureEnabled } from '@lwc/shared';
import { sourceLocation } from '../shared/ast';

import ParserCtx from './parser';
import { errorCodesToErrorOn, errorCodesToWarnOn } from './parse5Errors';
import { errorCodesToErrorOn, errorCodesToWarnOnInOlderAPIVersions } from './parse5Errors';

function getLwcErrorFromParse5Error(code: string) {
function getLwcErrorFromParse5Error(ctx: ParserCtx, code: string) {
/* istanbul ignore else */
if (errorCodesToErrorOn.has(code)) {
return ParserDiagnostics.INVALID_HTML_SYNTAX;
} else if (errorCodesToWarnOn.has(code)) {
return ParserDiagnostics.INVALID_HTML_SYNTAX_WARNING;
} else if (errorCodesToWarnOnInOlderAPIVersions.has(code)) {
// In newer API versions, all parse 5 errors are errors, not warnings
if (isAPIFeatureEnabled(APIFeature.TREAT_ALL_PARSE5_ERRORS_AS_ERRORS, ctx.apiVersion)) {
return ParserDiagnostics.INVALID_HTML_SYNTAX;
} else {
return ParserDiagnostics.INVALID_HTML_SYNTAX_WARNING;
}
} else {
// It should be impossible to reach here; we have a test in parser.spec.ts to ensure
// all error codes are accounted for. But just to be safe, make it a warning.
Expand All @@ -34,7 +39,7 @@ export function parseHTML(ctx: ParserCtx, source: string) {
const onParseError = (err: parse5.ParsingError) => {
const { code, ...location } = err;

const lwcError = getLwcErrorFromParse5Error(code);
const lwcError = getLwcErrorFromParse5Error(ctx, code);
ctx.warnAtLocation(lwcError, sourceLocation(location), [code]);
};

Expand Down
2 changes: 1 addition & 1 deletion packages/@lwc/template-compiler/src/parser/parse5Errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const errorCodesToErrorOn = new Set([
]);

// These were added between parse5-with-errors v4.0.4 and parse5 v6.0.1
export const errorCodesToWarnOn = new Set([
export const errorCodesToWarnOnInOlderAPIVersions = new Set([
'non-conforming-doctype',
'missing-doctype',
'misplaced-doctype',
Expand Down
3 changes: 3 additions & 0 deletions packages/@lwc/template-compiler/src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
LWCErrorInfo,
normalizeToDiagnostic,
} from '@lwc/errors';
import { APIVersion } from '@lwc/shared';
import { NormalizedConfig } from '../config';
import { isPreserveCommentsDirective, isRenderModeDirective } from '../shared/ast';

Expand Down Expand Up @@ -106,12 +107,14 @@ export default class ParserCtx {

renderMode: LWCDirectiveRenderMode;
preserveComments: boolean;
apiVersion: APIVersion;

constructor(source: String, config: NormalizedConfig) {
this.source = source;
this.config = config;
this.renderMode = LWCDirectiveRenderMode.shadow;
this.preserveComments = config.preserveHtmlComments;
this.apiVersion = config.apiVersion;
}

getSource(start: number, end: number): string {
Expand Down

0 comments on commit 068688e

Please sign in to comment.