Skip to content

Commit

Permalink
feat(template-compiler): remove "is" support and add lwc-deprecated:is (
Browse files Browse the repository at this point in the history
#834)

* feat(template-compiler): remove "is" support. add lwc-deprecated:is

* wip: review comments
  • Loading branch information
apapko authored Nov 14, 2018
1 parent fc6dc9c commit f15ad9f
Show file tree
Hide file tree
Showing 14 changed files with 107 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,16 @@ export const ParserDiagnostics = {
url: ""
},

IS_ATTRIBUTE_CANNOT_BE_EXPRESSION: {
DEPRECATED_IS_ATTRIBUTE_CANNOT_BE_EXPRESSION: {
code: 1001,
message: "Is attribute value can't be an expression",
message: "\"is\" attribute value can't be an expression",
level: DiagnosticLevel.Error,
url: ""
},

IS_ATTRIBUTE_NOT_SUPPORTED: {
code: 1001,
message: "\"is\" attribute is not supported",
level: DiagnosticLevel.Error,
url: ""
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<button lwc-deprecated:is={dynamicCmp}></button>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"warnings": [
{
"code": 1001,
"message": "LWC1001: \"is\" attribute value can't be an expression",
"level": 1,
"location": {
"line": 2,
"column": 13
}
}
],
"metadata": {
"definedSlots": [],
"templateUsedIds": ["dynamicCmp"],
"templateDependencies": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<section>
<x-foo is="x-button"></x-foo>
</section>
</template>
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"warnings": [
{
"code": 1001,
"message": "LWC1001: \"is\" attribute is not supported",
"level": 1,
"location": {
"line": 3,
"column": 16
}
}
],
"metadata": {
"definedSlots": [],
"templateUsedIds": [],
"templateDependencies": [
{
"moduleName": "x/foo",
"properties": {
"is": {
"type": "literal", "value": "x-button"
}
},
"tagName": "x-foo"
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
<svg class="cubano" focusable="true">
<use xlink:href="xx"></use>
</svg>
<div is="ns-buzz" bgcolor="x" aria-hidden="hidden" ></div>
<div lwc-deprecated:is="ns-buzz" bgcolor="x" aria-hidden="hidden" ></div>
<table bgcolor="x"></table>
<table bgcolor="x" is="ns-table" tabindex="0" bar="test" min="3"></table>
<input minlength="3" maxlength="10" is="ns-input" />
<table bgcolor="x" lwc-deprecated:is="ns-table" tabindex="0" bar="test" min="3"></table>
<input minlength="3" maxlength="10" lwc-deprecated:is="ns-input" />
<div class={foo} aria-hidden="hidden"></div>
</template>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<table>
<tbody>
<tr key={row.id} is="ns-row" for:each={rows} for:item="row" if:true={row.visible}>
<tr key={row.id} lwc-deprecated:is="ns-row" for:each={rows} for:item="row" if:true={row.visible}>
</tr>
</tbody>
</table>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<table>
<tbody>
<tr is="ns-row"></tr>
<tr lwc-deprecated:is="ns-row"></tr>
</tbody>
</table>
</template>
35 changes: 17 additions & 18 deletions packages/lwc-template-compiler/src/__tests__/parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,22 +292,6 @@ describe('custom component', () => {
location: EXPECTED_LOCATION
});
});

it('custom component via is attribute', () => {
const { root } = parseTemplate(`<template><button is="x-button"></button></template>`);
expect(root.children[0].tag).toBe('button');
expect(root.children[0].component).toBe('x-button');
});

it('is dynamic attribute error', () => {
const { warnings } = parseTemplate(`<template><button is={dynamicCmp}></button></template>`);
expect(warnings).toContainEqual({
code: expect.any(Number),
level: DiagnosticLevel.Error,
message: `LWC1001: Is attribute value can't be an expression`,
location: EXPECTED_LOCATION
});
});
});

describe('root errors', () => {
Expand Down Expand Up @@ -350,6 +334,21 @@ describe('root errors', () => {
location: EXPECTED_LOCATION
});
});

it('disallows is attribute in non-custom component', () => {
const { warnings } = parseTemplate(`<template>
<x-menu></x-menu>
<button is="x-button"></button>
</template>`);

expect(warnings).toContainEqual({
code: expect.any(Number),
filename: undefined,
level: DiagnosticLevel.Error,
message: `LWC1001: is is not valid attribute for button. For more information refer to https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button`,
location: EXPECTED_LOCATION
});
});
});

describe('expression', () => {
Expand Down Expand Up @@ -488,7 +487,7 @@ describe('props and attributes', () => {

it('custom element using is with attribute / prop mix', () => {
const { root } = parseTemplate(`<template>
<table bgcolor="x" is="x-table" tabindex="2" bar="test" min="3"></table>
<table bgcolor="x" lwc-deprecated:is="x-table" tabindex="2" bar="test" min="3"></table>
</template>`);
expect(root.children[0].props).toMatchObject({
bar: { value: 'test' },
Expand Down Expand Up @@ -522,7 +521,7 @@ describe('metadata', () => {
it('dependent component', () => {
const { state } = parseTemplate(`<template>
<x-menu></x-menu>
<button is="x-button"></button>
<button lwc-deprecated:is="x-button"></button>
</template>`);

expect(Array.from(state.dependencies)).toEqual(['x-menu', 'x-button']);
Expand Down
16 changes: 12 additions & 4 deletions packages/lwc-template-compiler/src/parser/attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ function isAriaAttribute(attrName: string): boolean {
return attrName === 'role' || ARIA_RE.test(attrName);
}

export function isDeprecatedIsAttribute(attrName: string): boolean {
return attrName === 'lwc-deprecated:is';
}

export function isProhibitedIsAttribute(attrName: string): boolean {
return attrName === 'is';
}

export function isTabIndexAttribute(attrName: string): boolean {
return attrName === 'tabindex';
}
Expand All @@ -181,15 +189,15 @@ function isDataAttribute(attrName: string): boolean {

function isFmkAttribute(attrName: string): boolean {
return (
attrName === 'is' ||
attrName === 'lwc-deprecated:is' ||
attrName === 'key' ||
attrName === 'slot'
);
}

function isCustomElementAttribute(attrName: string): boolean {
return (
attrName === 'is' ||
attrName === 'lwc-deprecated:is' ||
attrName === 'key' ||
attrName === 'slot' ||
!!attrName.match(DATA_RE)
Expand Down Expand Up @@ -223,8 +231,8 @@ export function isAttribute(element: IRElement, attrName: string): boolean {

// Handle attributes applied to a subclassed element via the is="" attribute.
// Returns true only attributes that are valid attribute for the base element.
const hasIsAttr = !!getAttribute(element, 'is');
if (hasIsAttr) {
const hasDeprecatedIsAttr = !!getAttribute(element, 'lwc-deprecated:is');
if (hasDeprecatedIsAttr) {
return isValidHTMLAttribute(element.tag, attrName);
}

Expand Down
1 change: 0 additions & 1 deletion packages/lwc-template-compiler/src/parser/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ export const ATTRS_PROPS_TRANFORMS: { [name: string]: string } = {
'novalidate': 'noValidate',
'usemap': 'useMap',
'for': 'htmlFor',

// According to the following list, there are 48 aria attributes (of which 2 are deprecated):
// https://www.w3.org/TR/wai-aria-1.1/#x6-6-definitions-of-states-and-properties-all-aria-attributes
// This list of 46 non-deprecated aria attributes is consistent with the following proposal:
Expand Down
13 changes: 10 additions & 3 deletions packages/lwc-template-compiler/src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
normalizeAttributeValue,
isValidHTMLAttribute,
attributeToPropertyName,
isDeprecatedIsAttribute,
isProhibitedIsAttribute,
isTabIndexAttribute,
isValidTabIndexAttributeValue,
} from './attribute';
Expand Down Expand Up @@ -564,10 +566,10 @@ export default function parse(source: string, state: State): {
component = tag;
}

const isAttr = getTemplateAttribute(element, 'is');
const isAttr = getTemplateAttribute(element, 'lwc-deprecated:is');
if (isAttr) {
if (isAttr.type !== IRAttributeType.String) {
return warnAt(ParserDiagnostics.IS_ATTRIBUTE_CANNOT_BE_EXPRESSION, [], isAttr.location);
return warnAt(ParserDiagnostics.DEPRECATED_IS_ATTRIBUTE_CANNOT_BE_EXPRESSION, [], isAttr.location);
}

// Don't remove the is, because passed as attribute
Expand Down Expand Up @@ -645,6 +647,8 @@ export default function parse(source: string, state: State): {
const { name, location } = attr;
if (!isCustomElement(element) && !isValidHTMLAttribute(element.tag, name)) {
warnAt(ParserDiagnostics.INVALID_HTML_ATTRIBUTE, [name, tag], location);
} else if (isCustomElement(element) && isProhibitedIsAttribute(name)) {
warnAt(ParserDiagnostics.IS_ATTRIBUTE_NOT_SUPPORTED, [name, tag], location);
}

if (attr.type === IRAttributeType.String) {
Expand All @@ -665,7 +669,10 @@ export default function parse(source: string, state: State): {

if (isAttribute(element, name)) {
const attrs = element.attrs || (element.attrs = {});
attrs[name] = attr;

// authored code for 'lwc-deprecated:is' attr maps to 'is'
const attrKey = isDeprecatedIsAttribute(name) ? 'is' : name;
attrs[attrKey] = attr;
} else {
const props = element.props || (element.props = {});
props[attributeToPropertyName(element, name)] = attr;
Expand Down

0 comments on commit f15ad9f

Please sign in to comment.