Skip to content

Commit

Permalink
fix(engine): supporting objects with null prototype in iterators (#1152)
Browse files Browse the repository at this point in the history
* fix(engine): supporting objects with null prototype in iterators
* fix(engine): making sure commas are inserted in toString
* test(engine): testing for each fix
* test(engine): removing jest test
  • Loading branch information
davidturissini authored Apr 15, 2019
1 parent b414c3c commit 7c5f264
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 4 deletions.
10 changes: 7 additions & 3 deletions packages/@lwc/engine/src/framework/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,9 @@ export function i(
if (isUndefined(iterable) || iterable === null) {
if (process.env.NODE_ENV !== 'production') {
assert.logWarning(
`Invalid template iteration for value "${iterable}" in ${vmBeingRendered}, it should be an Array or an iterable Object.`,
`Invalid template iteration for value "${toString(
iterable
)}" in ${vmBeingRendered}, it should be an Array or an iterable Object.`,
vmBeingRendered!.elm
);
}
Expand All @@ -453,15 +455,17 @@ export function i(
if (process.env.NODE_ENV !== 'production') {
assert.isFalse(
isUndefined(iterable[SymbolIterator]),
`Invalid template iteration for value \`${iterable}\` in ${vmBeingRendered}, it requires an array-like object, not \`null\` or \`undefined\`.`
`Invalid template iteration for value \`${toString(
iterable
)}\` in ${vmBeingRendered}, it requires an array-like object, not \`null\` or \`undefined\`.`
);
}
const iterator = iterable[SymbolIterator]();

if (process.env.NODE_ENV !== 'production') {
assert.isTrue(
iterator && isFunction(iterator.next),
`Invalid iterator function for "${iterable}" in ${vmBeingRendered}.`
`Invalid iterator function for "${toString(iterable)}" in ${vmBeingRendered}.`
);
}

Expand Down
9 changes: 8 additions & 1 deletion packages/@lwc/engine/src/shared/language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,18 @@ export function isNumber(obj: any): obj is number {
const OtS = {}.toString;
export function toString(obj: any): string {
if (obj && obj.toString) {
// Arrays might hold objects with "null" prototype
// So using Array.prototype.toString directly will cause an error
// Iterate through all the items and handle individually.
if (isArray(obj)) {
return ArrayJoin.call(ArrayMap.call(obj, toString), ',');
}

return obj.toString();
} else if (typeof obj === 'object') {
return OtS.call(obj);
} else {
return obj + '';
return obj + emptyString;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createElement } from 'test-utils';
import XTest from 'x/test';
import ArrayNullPrototype from 'x/arrayNullPrototype';

function testForEach(type, obj) {
it(`should render ${type}`, () => {
Expand Down Expand Up @@ -68,3 +69,10 @@ xit('should log a warning when the passing a non iterable', () => {
/Invalid template iteration for value `\[.*\]` in \[object:vm undefined \(\d*\)\], it requires an array-like object, not `null` or `undefined`/
);
});

it('should render an array of objects with null prototype', () => {
const elm = createElement('x-array-null-prototype', { is: ArrayNullPrototype });
document.body.appendChild(elm);

expect(elm.shadowRoot.querySelector('span').textContent).toBe('text');
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<template for:each={items} for:item="item">
<span key={item.id}>{item.text}</span>
</template>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LightningElement } from 'lwc';

export default class RenderArrayNullPrototype extends LightningElement {
get items() {
const first = Object.create(null);
first.id = 'id';
first.text = 'text';
return [first];
}
}

0 comments on commit 7c5f264

Please sign in to comment.