Comment

Comment by zeveb

> s-expressions have no central specification on precise syntax

There is: https://people.csail.mit.edu/rivest/Sexp.txt

It's imperfect, but it does get the job done. Among its advantages is that it's both pure text and binary: there's a canonical representation which is binary, and an advanced representation which is textual, and they map 1:1 to one another.

Examples:

    (session
     (capabilities
      (urn:ietf:params:jmap:core
       (max-size-upload 50000000)
       (max-concurrent-upload 8)
       (max-size-request 10000000)
       (max-calls-in-request 32)
       (max-objects-in-get 256)
       (max-objects-in-set 128)
       (collation-algorithms ("i;ascii-numeric"
                              "i;ascii-casemap"
                              "i;unicode-casemap")))
      (urn:ietf:params:jmap:mail)
      (urn:ietf:params:jmap:contacts)
      (https://example.com/apis/foobar
       (max-foos-finagled 42)))
     (accounts
      (A13824
       (name "[email protected]")
       (is-personal true)
       (is-read-only false)
       (account-capabilities
        (urn:ietf:params:jmap:mail
         (max-mailboxes-per-email nil)
         (max-mailbox-depth 10))
        (urn:ietf:params:jmap:contacts
         …)))
      (A97813
       (name "[email protected]")
       (is-personal false)
       (is-read-only true)
       (account-capabilities
        (urn:ietf:params:jmap:mail
         (max-mailboxes-per-email 1)
         (max-mailbox-depth 10)))))
     (primary-accounts
      (urn:ietf:params:jmap:mail A13824)
      (urn:ietf:params:jmap:contacts A13824))
     (username "[email protected]")
     (api-url "https://jmap.example.com/download/{accountId}/{blobId}/{name}?accept={type}")
     (upload-url "https://jmap.example.com/upload/{accountId}/")
     (event-source-url "https://jmap.example.com/eventsource/?types={types}&closeafter={closeafter}&ping={ping}")
     (state "75128aab4b1b"))
Or the binary encoding: {KDc6c2Vzc2lvbigxMjpjYXBhYmlsaXRpZXMoMjU6dXJuOmlldGY6cGFyYW1zOmptYXA6Y29y ZSgxNTptYXgtc2l6ZS11cGxvYWQ4OjUwMDAwMDAwKSgyMTptYXgtY29uY3VycmVudC11cGxv YWQxOjgpKDE2Om1heC1zaXplLXJlcXVlc3Q4OjEwMDAwMDAwKSgyMDptYXgtY2FsbHMtaW4t cmVxdWVzdDI6MzIpKDE4Om1heC1vYmplY3RzLWluLWdldDM6MjU2KSgxODptYXgtb2JqZWN0 cy1pbi1zZXQzOjEyOCkoMjA6Y29sbGF0aW9uLWFsZ29yaXRobXMoMTU6aTthc2NpaS1udW1l cmljMTU6aTthc2NpaS1jYXNlbWFwMTc6aTt1bmljb2RlLWNhc2VtYXApKSkoMjU6dXJuOmll dGY6cGFyYW1zOmptYXA6bWFpbCkoMjk6dXJuOmlldGY6cGFyYW1zOmptYXA6Y29udGFjdHMp KSgzMTpodHRwczovL2V4YW1wbGUuY29tL2FwaXMvZm9vYmFyKDE3Om1heC1mb29zLWZpbmFn bGVkMjo0MikpKDg6YWNjb3VudHMoNjpBMTM4MjQoNDpuYW1lMTY6am9obkBleGFtcGxlLmNv bSkoMTE6aXMtcGVyc29uYWw0OnRydWUpKDEyOmlzLXJlYWQtb25seTU6ZmFsc2UpKDIwOmFj Y291bnQtY2FwYWJpbGl0aWVzKDI1OnVybjppZXRmOnBhcmFtczpqbWFwOm1haWwoMjM6bWF4 LW1haWxib3hlcy1wZXItZW1haWwzOm5pbCkoMTc6bWF4LW1haWxib3gtZGVwdGgyOjEwKSko Mjk6dXJuOmlldGY6cGFyYW1zOmptYXA6Y29udGFjdHMzWiYpKSkoNjpBOTc4MTMoNDpuYW1l MTY6amFuZUBleGFtcGxlLmNvbSkoMTE6aXMtcGVyc29uYWw1OmZhbHNlKSgxMjppcy1yZWFk LW9ubHk0OnRydWUpKDIwOmFjY291bnQtY2FwYWJpbGl0aWVzKDI1dXJuOmlldGY6cGFyYW1z OmptYXA6bWFpbCgyMzptYXgtbWFpbGJveGVzLXBlci1lbWFpbDE6MSkoMTc6bWF4LW1haWxi b3gtZGVwdGgyOjEwKSkpKSkoMTY6cHJpbWFyeS1hY2NvdW50cygyNTp1cm46aWV0ZjpwYXJh bXM6am1hcDptYWlsNjpBMTM4MjQpKDI5OnVybjppZXRmOnBhcmFtczpqbWFwOmNvbnRhY3Rz NjpBMTM4MjQpKSg4OnVzZXJuYW1lMTY6am9obgo=}

This is the equivalent of the JSON:

    {
        "capabilities": {
            "urn:ietf:params:jmap:core": {
                "maxSizeUpload": 50000000,
                "maxConcurrentUpload": 8,
                "maxSizeRequest": 10000000,
                "maxConcurrentRequest": 8,
                "maxCallsInRequest": 32,
                "maxObjectsInGet": 256,
                "maxObjectsInSet": 128,
                "collationAlgorithms": [
                    "i;ascii-numeric",
                    "i;ascii-casemap",
                    "i;unicode-casemap"
                ]
            },
            "urn:ietf:params:jmap:mail": {}
            "urn:ietf:params:jmap:contacts": {},
            "https://example.com/apis/foobar": {
                "maxFoosFinangled": 42
            }
        },
        "accounts": {
            "A13824": {
                "name": "[email protected]",
                "isPersonal": true,
                "isReadOnly": false,
                "accountCapabilities": {
                    "urn:ietf:params:jmap:mail": {
                        "maxMailboxesPerEmail": null,
                        "maxMailboxDepth": 10,
                        ...
                    },
                    "urn:ietf:params:jmap:contacts": {
                        ...
                    }
                }
            },
            "A97813": {
                "name": "[email protected]",
                "isPersonal": false,
                "isReadOnly": true,
                "accountCapabilities": {
                    "urn:ietf:params:jmap:mail": {
                        "maxMailboxesPerEmail": 1,
                        "maxMailboxDepth": 10,
                        ...
                    }
                }
            }
        },
        "primaryAccounts": {
            "urn:ietf:params:jmap:mail": "A13824",
            "urn:ietf:params:jmap:contacts": "A13824"
        },
        "username": "[email protected]",
        "apiUrl": "https://jmap.example.com/api/",
        "downloadUrl": "https://jmap.example.com
           /download/{accountId}/{blobId}/{name}?accept={type}",
        "uploadUrl": "https://jmap.example.com/upload/{accountId}/",
        "eventSourceUrl": "https://jmap.example.com
           /eventsource/?types={types}&closeafter={closeafter}&ping={ping}",
        "state": "75128aab4b1b"
    }
I think it's pretty obvious which one is cleaner …
parent zeveb 7 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton