KCL: Object literals like {x} as shorthand for {x: x} (#4521)

If the key and value in an object literal use the same identifier, allow abbreviating it.

Basically these two are now equivalent:

```
x = 2
obj = { x: x, y: 3}
```

```diff
x = 2
- obj = { x: x, y: 3}
+ obj = { x, y: 3}
```

This syntax is used in JS, Rust and probably elsewhere too.

Here's a more realistic example. Before:

```
radius = 10

startSketchAt([0, 0])
|> circle({center: [0, 0], radius: radius}, %)
```
After:
```diff
radius = 10

startSketchAt([0, 0])
- |> circle({center: [0, 0], radius: radius}, %)
+ |> circle({center: [0, 0], radius}, %)
```
This commit is contained in:
Adam Chalmers
2024-11-20 10:23:32 -06:00
committed by GitHub
parent 30afa65ccf
commit 6fb493f209
2 changed files with 129 additions and 1 deletions

View File

@ -596,6 +596,21 @@ fn array_end_start(i: TokenSlice) -> PResult<Node<ArrayRangeExpression>> {
))
}
fn object_property_same_key_and_val(i: TokenSlice) -> PResult<Node<ObjectProperty>> {
let key = identifier.context(expected("the property's key (the name or identifier of the property), e.g. in 'height: 4', 'height' is the property key")).parse_next(i)?;
ignore_whitespace(i);
Ok(Node {
start: key.start,
end: key.end,
module_id: key.module_id,
inner: ObjectProperty {
value: Expr::Identifier(Box::new(key.clone())),
key,
digest: None,
},
})
}
fn object_property(i: TokenSlice) -> PResult<Node<ObjectProperty>> {
let key = identifier.context(expected("the property's key (the name or identifier of the property), e.g. in 'height: 4', 'height' is the property key")).parse_next(i)?;
ignore_whitespace(i);
@ -642,7 +657,11 @@ pub(crate) fn object(i: TokenSlice) -> PResult<Node<ObjectExpression>> {
0..,
alt((
terminated(non_code_node.map(NonCodeOr::NonCode), whitespace),
terminated(object_property, property_separator).map(NonCodeOr::Code),
terminated(
alt((object_property, object_property_same_key_and_val)),
property_separator,
)
.map(NonCodeOr::Code),
)),
)
.context(expected(
@ -3888,6 +3907,11 @@ const my14 = 4 ^ 2 - 3 ^ 2 * 2
snapshot_test!(bf, "let x = 3 != 3");
snapshot_test!(bg, r#"x = 4"#);
snapshot_test!(bh, "const obj = {center : [10, 10], radius: 5}");
snapshot_test!(
bi,
r#"x = 3
obj = { x, y: 4}"#
);
}
#[allow(unused)]

View File

@ -0,0 +1,104 @@
---
source: kcl/src/parser/parser_impl.rs
expression: actual
snapshot_kind: text
---
{
"body": [
{
"declarations": [
{
"end": 5,
"id": {
"end": 1,
"name": "x",
"start": 0,
"type": "Identifier"
},
"init": {
"end": 5,
"raw": "3",
"start": 4,
"type": "Literal",
"type": "Literal",
"value": 3
},
"start": 0,
"type": "VariableDeclarator"
}
],
"end": 5,
"kind": "const",
"start": 0,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
},
{
"declarations": [
{
"end": 30,
"id": {
"end": 17,
"name": "obj",
"start": 14,
"type": "Identifier"
},
"init": {
"end": 30,
"properties": [
{
"end": 23,
"key": {
"end": 23,
"name": "x",
"start": 22,
"type": "Identifier"
},
"start": 22,
"type": "ObjectProperty",
"value": {
"end": 23,
"name": "x",
"start": 22,
"type": "Identifier",
"type": "Identifier"
}
},
{
"end": 29,
"key": {
"end": 26,
"name": "y",
"start": 25,
"type": "Identifier"
},
"start": 25,
"type": "ObjectProperty",
"value": {
"end": 29,
"raw": "4",
"start": 28,
"type": "Literal",
"type": "Literal",
"value": 4
}
}
],
"start": 20,
"type": "ObjectExpression",
"type": "ObjectExpression"
},
"start": 14,
"type": "VariableDeclarator"
}
],
"end": 30,
"kind": "const",
"start": 14,
"type": "VariableDeclaration",
"type": "VariableDeclaration"
}
],
"end": 30,
"start": 0
}