Commit 1fa59fbd by kzc Committed by Marijn Haverbeke

fix objects with both computed property and object spread (#144)

parent 4adeb4eb
Pipeline #5380503 passed with stage
in 3 minutes 4 seconds
......@@ -5,12 +5,19 @@ export default class ObjectExpression extends Node {
transpile ( code, transforms ) {
super.transpile( code, transforms );
let firstPropertyStart = this.start + 1;
let regularPropertyCount = 0;
let spreadPropertyCount = 0;
let computedPropertyCount = 0;
for ( let prop of this.properties ) {
if ( prop.type === 'SpreadProperty' ) spreadPropertyCount += 1;
if ( prop.computed ) computedPropertyCount += 1;
if ( prop.type === 'SpreadProperty' ) {
spreadPropertyCount += 1;
} else if ( prop.computed ) {
computedPropertyCount += 1;
} else if ( prop.type === 'Property' ) {
regularPropertyCount += 1;
}
}
if ( spreadPropertyCount ) {
......@@ -19,25 +26,28 @@ export default class ObjectExpression extends Node {
}
// enclose run of non-spread properties in curlies
let i = this.properties.length;
while ( i-- ) {
const prop = this.properties[i];
if ( regularPropertyCount ) {
while ( i-- ) {
const prop = this.properties[i];
if ( prop.type === 'Property' ) {
const lastProp = this.properties[ i - 1 ];
const nextProp = this.properties[ i + 1 ];
if ( prop.type === 'Property' && !prop.computed ) {
const lastProp = this.properties[ i - 1 ];
const nextProp = this.properties[ i + 1 ];
if ( !lastProp || lastProp.type !== 'Property' ) {
code.insertRight( prop.start, '{' );
}
if ( !lastProp || lastProp.type !== 'Property' || lastProp.computed ) {
code.insertRight( prop.start, '{' );
}
if ( !nextProp || nextProp.type !== 'Property' ) {
code.insertLeft( prop.end, '}' );
if ( !nextProp || nextProp.type !== 'Property' || nextProp.computed ) {
code.insertLeft( prop.end, '}' );
}
}
}
}
// wrap the whole thing in Object.assign
code.overwrite( this.start, this.properties[0].start, `${this.program.objectAssign}({}, `);
firstPropertyStart = this.properties[0].start;
code.overwrite( this.start, firstPropertyStart, `${this.program.objectAssign}({}, `);
code.overwrite( this.properties[ this.properties.length - 1 ].end, this.end, ')' );
}
......@@ -47,9 +57,6 @@ export default class ObjectExpression extends Node {
let isSimpleAssignment;
let name;
let start;
let end;
if ( this.parent.type === 'VariableDeclarator' && this.parent.parent.declarations.length === 1 ) {
isSimpleAssignment = true;
name = this.parent.id.alias || this.parent.id.name; // TODO is this right?
......@@ -65,8 +72,8 @@ export default class ObjectExpression extends Node {
const declaration = this.findScope( false ).findDeclaration( name );
if ( declaration ) name = declaration.name;
start = this.start + 1;
end = this.end;
const start = firstPropertyStart;
const end = this.end;
if ( isSimpleAssignment ) {
// ???
......@@ -81,6 +88,7 @@ export default class ObjectExpression extends Node {
const len = this.properties.length;
let lastComputedProp;
let sawNonComputedProperty = false;
for ( let i = 0; i < len; i += 1 ) {
const prop = this.properties[i];
......@@ -105,7 +113,7 @@ export default class ObjectExpression extends Node {
code.insertLeft( c, ' = ' );
code.move( moveStart, prop.end, end );
if ( i === 0 && len > 1 ) {
if ( i < len - 1 && ! sawNonComputedProperty ) {
// remove trailing comma
c = prop.end;
while ( code.original[c] !== ',' ) c += 1;
......@@ -116,6 +124,8 @@ export default class ObjectExpression extends Node {
if ( prop.method && transforms.conciseMethodProperty ) {
code.insertRight( prop.value.start, 'function ' );
}
} else {
sawNonComputedProperty = true;
}
}
......
......@@ -42,6 +42,113 @@ module.exports = [
},
{
description: 'transpiles objects with rest spread with computed property (#144)',
options: {
objectAssign: 'Object.assign'
},
input: `
var a0 = { [ x ] : true , ... y };
var a1 = { [ w ] : 0 , [ x ] : true , ... y };
var a2 = { v, [ w ] : 0, [ x ] : true , ... y };
var a3 = { [ w ] : 0, [ x ] : true };
var a4 = { [ w ] : 0 , [ x ] : true , y };
var a5 = { k : 9 , [ x ] : true, ... y };
var a6 = { ... y, [ x ] : true };
var a7 = { ... y, [ w ] : 0, [ x ] : true };
var a8 = { k : 9, ... y, [ x ] : true };
var a9 = { [ x ] : true , [ y ] : false , [ z ] : 9 };
var a10 = { [ x ] : true, ...y, p, ...q };
var a11 = { x, [c] : 9 , y };
var a12 = { ...b, [c]:3, d:4 };
`,
output: `
var a0 = Object.assign({}, y);
a0[ x ] = true;
var a1 = Object.assign({}, y);
a1[ w ] = 0;
a1[ x ] = true;
var a2 = Object.assign({}, {v: v} , y);
a2[ w ] = 0;
a2[ x ] = true;
var a3 = {};
a3[ w ] = 0;
a3[ x ] = true;
var a4 = { y: y };
a4[ w ] = 0;
a4[ x ] = true;
var a5 = Object.assign({}, {k : 9}, y);
a5[ x ] = true;
var a6 = Object.assign({}, y);
a6[ x ] = true;
var a7 = Object.assign({}, y);
a7[ w ] = 0;
a7[ x ] = true;
var a8 = Object.assign({}, {k : 9}, y);
a8[ x ] = true;
var a9 = {};
a9[ x ] = true;
a9[ y ] = false;
a9[ z ] = 9;
var a10 = Object.assign({}, y, {p: p}, q);
a10[ x ] = true;
var a11 = { x: x , y: y };
a11[c] = 9;
var a12 = Object.assign({}, b, {d:4});
a12[c] = 3;
`
},
{
description: 'transpiles inline objects with rest spread with computed property (#144)',
options: {
objectAssign: 'Object.assign'
},
input: `
f0( { [ x ] : true , ... y } );
f1( { [ w ] : 0 , [ x ] : true , ... y } );
f2( { v, [ w ] : 0, [ x ] : true , ... y } );
f3( { [ w ] : 0, [ x ] : true } );
f4( { [ w ] : 0 , [ x ] : true , y } );
f5( { k : 9 , [ x ] : true, ... y } );
f6( { ... y, [ x ] : true } );
f7( { ... y, [ w ] : 0, [ x ] : true } );
f8( { k : 9, ... y, [ x ] : true } );
f9( { [ x ] : true , [ y ] : false , [ z ] : 9 } );
f10( { [ x ] : true, ...y, p, ...q } );
f11( { x, [c] : 9 , y } );
f12({ ...b, [c]:3, d:4 });
`,
output: `
f0( ( obj = Object.assign({}, y), obj[ x ] = true, obj ) );
var obj;
f1( ( obj$1 = Object.assign({}, y), obj$1[ w ] = 0, obj$1[ x ] = true, obj$1 ) );
var obj$1;
f2( ( obj$2 = Object.assign({}, {v: v} , y), obj$2[ w ] = 0, obj$2[ x ] = true, obj$2 ) );
var obj$2;
f3( ( obj$3 = {}, obj$3[ w ] = 0, obj$3[ x ] = true, obj$3 ) );
var obj$3;
f4( ( obj$4 = { y: y }, obj$4[ w ] = 0, obj$4[ x ] = true, obj$4 ) );
var obj$4;
f5( ( obj$5 = Object.assign({}, {k : 9}, y), obj$5[ x ] = true, obj$5 ) );
var obj$5;
f6( ( obj$6 = Object.assign({}, y), obj$6[ x ] = true, obj$6 ) );
var obj$6;
f7( ( obj$7 = Object.assign({}, y), obj$7[ w ] = 0, obj$7[ x ] = true, obj$7 ) );
var obj$7;
f8( ( obj$8 = Object.assign({}, {k : 9}, y), obj$8[ x ] = true, obj$8 ) );
var obj$8;
f9( ( obj$9 = {}, obj$9[ x ] = true, obj$9[ y ] = false, obj$9[ z ] = 9, obj$9 ) );
var obj$9;
f10( ( obj$10 = Object.assign({}, y, {p: p}, q), obj$10[ x ] = true, obj$10 ) );
var obj$10;
f11( ( obj$11 = { x: x , y: y }, obj$11[c] = 9, obj$11 ) );
var obj$11;
f12(( obj$12 = Object.assign({}, b, {d:4}), obj$12[c] = 3, obj$12 ));
var obj$12;
`
},
{
description: 'transpiles object rest spread nested',
options: {
objectAssign: 'Object.assign'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment