antonmedv/fx

expression such as ".1" gives SyntaxError: Unexpected number

darinkelkhoff opened this issue · 6 comments

A simple file with string-numbers as keys, such as:

❯ cat sample.json
{
   "1": "one",
   "z": "zed"
}

Can be used as expected with an argument of ".z":

❯ cat sample.json | fx .z
zed

But fails with a syntax error with an argument of ".1":

❯ cat sample.json | fx .1

   .1
   ^^

SyntaxError: Unexpected number
    at transform (/private/var/folders/tp/nkzj1d3931d66pv0tstwc9y80000gn/T/fx-30.2.0.js:107:20)
    at runTransforms (/private/var/folders/tp/nkzj1d3931d66pv0tstwc9y80000gn/T/fx-30.2.0.js:53:20)
    at async main (/private/var/folders/tp/nkzj1d3931d66pv0tstwc9y80000gn/T/fx-30.2.0.js:42:7)

From documentation: https://fx.wtf/getting-started

Fx also introduces syntactical sugar to enhance simplicity:

  • Reference input data using x or this.
  • Start expressions with . to avoid repeating the x => x.

So .1 is replaced by a function x => x.1, and this is not valid JS. In your case proper solution will be:

.["1"]

As the .1 is syntactical sugar, is there an interest in "sweetening" it further, and internally changing the .1 to .["1"]?

Yeap, I think it will be nice to have such a feature.

cben commented

Note that in most languages .1 is valid float syntax, shorthand for 0.1.
I agree it's not very interesting alone but consider it as part of larger expression:

> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | jq '.x + .1'
1.1
> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | fx '.x + .1'
1.1
> fx --version
30.2.0

Is it worth breaking compatibility with existing fx behavior^?
Would it violate "least surprise" for people familiar with .123 float syntax?
(Subtler question: would it be subconsciously weird that .10 vs. .1 refers to distinct indexes "10" vs. "1" in the proposed syntax while they're equivalent where parsed as floats?)

Surprisingly, same syntax in opposite order is rejected by fx! While other combinations work??

> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | jq '.1 + .x'
1.1
> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | jq '.x + .y'
2.5
> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | jq '.1 + .2'
0.30000000000000004

> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | fx '.1 + .x'

   .1 + .x 
   ^^^^^^^

SyntaxError: Unexpected number
    at transform (/tmp/fx-30.2.0.js:107:20)
    at runTransforms (/tmp/fx-30.2.0.js:53:20)
    at async main (/tmp/fx-30.2.0.js:42:7)
> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | fx '.x + .y'

   .x + .y 
   ^^^^^^^

SyntaxError: Unexpected token '.'
    at transform (/tmp/fx-30.2.0.js:107:20)
    at runTransforms (/tmp/fx-30.2.0.js:53:20)
    at async main (/tmp/fx-30.2.0.js:42:7)
> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | fx '.1 + .2'

   .1 + .2 
   ^^^^^^^

SyntaxError: Unexpected number
    at transform (/tmp/fx-30.2.0.js:107:20)
    at runTransforms (/tmp/fx-30.2.0.js:53:20)
    at async main (/tmp/fx-30.2.0.js:42:7)

I'd call this a parsing bug. IMHO (as a user) either all 3 combinations .1 + .2 , .1 + .x, .x + .1 should work or all should be SyntaxError.

EDIT: my bad, I'd mixed up jq / fx in those experiments, corrected now ^


A half-way shorthand is indexing with number getting implicitly coerced to string — already works in fx and JS but not in jq:

> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | jq '.[1]'
jq: error (at <stdin>:1): Cannot index object with number
> echo '{"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}' | fx '.[1]'
x
> node
Welcome to Node.js v18.17.1.
Type ".help" for more information.
> {"1": "x", "x": 1.0, "y": 1.5, "z": 2.0}[1]
'x'

(I have mixed feelings about such implicit coercion because there are many strings that parse as same number e.g. "001", "1" and "1.00" so choosing one on conversion from number back to string is somewhat arbitrary. But in JSON all object keys must be strings, and it's already supported by fx, and I'm not suggesting to remove it.)

cben commented

[bias disclaimer: I know jq well and use it daily, so I approach fx as kinda "interactive jq + jless". I respect your freedom to make different choices in your own language 😄.
Perhaps jq<->fx differences of "one supports something / one considers it an error" are easier than "both accept it with different behavior" but your call.]

Fx main feature is "it is just JavaScript". If expression starts with dot ., next expression will be added: x => x.

For for

  • .1 + .x
  • Fx adds x => x
  • x => x.1 + .x which is not valid.

On other hand x => x.x + .1 is valid.