A human-friendly DSL for ATProto Lexicons mlf.lol

Nested object don't always validate #4

Open stavola.xyz
Open opened by and assigned to stavola.xyz

Nested objects are not necessarily supported by Lexicon validators. Currently e.g. atcute does not, which is used on https://pdsls.dev/. Also see https://github.com/bluesky-social/atproto-website/issues/470 for more details.

A Node.js script to validate Lexicons with atcute can be found at https://gist.github.com/vmx/4aaeaec4c61fb3b05d423eed0b4dcea4

Here's an example:

/// A social media post post
record post {
    // The text of the post
    text: string,
    /// The number of reactions to that post
    numReactions: {
        /// Number of likes
        likes: integer,
        /// Number of reposts
        reposts: integer,
    },
}

Currently converts to:

{
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1,
  "id": "com.example.post",
  "defs": {
    "main": {
      "type": "record",
      "description": "A social media post post",
      "key": "tid",
      "record": {
        "type": "object",
        "required": [],
        "properties": {
          "text": {
            "type": "string"
          },
          "numReactions": {
            "type": "object",
            "required": [],
            "properties": {
              "likes": {
                "type": "integer",
                "description": "Number of likes"
              },
              "reposts": {
                "type": "integer",
                "description": "Number of reposts"
              }
            },
            "description": "The number of reactions to that post"
          }
        }
      }
    }
  }
}

To make it validate with atcute, it needs to be something like:

{
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1,
  "id": "com.example.post",
  "defs": {
    "main": {
      "type": "record",
      "description": "A social media post post",
      "key": "tid",
      "record": {
        "type": "object",
        "required": [],
        "properties": {
          "text": {
            "type": "string"
          },
          "numReactions": {
            "type": "ref",
            "ref": "#numReactions",
            "description": "The number of reactions to that post"
          }
        }
      }
    },
    "numReactions": {
      "type": "object",
      "required": [],
      "properties": {
        "likes": {
          "type": "integer",
          "description": "Number of likes"
        },
        "reposts": {
          "type": "integer",
          "description": "Number of reposts"
        }
      }
    }
  }
}

Which corresponds to this MLF version:

/// A social media post post
record post {
    // The text of the post
    text: string,
    /// The number of reactions to that post
    numReactions: numReactions,
}

def type numReactions = {
    /// Number of likes
    likes: integer,
    /// Number of reposts
    reposts: integer,
};

The Lexicon version could potentially be auto-generated. But I'm not sure if that's desired. You can fix it by doing it manually as the MLF version above shows.

I've mostly opened this issue for people running into errors on https://pdsls.dev/ that their schema doesn't validate. You will get an error like:

Invalid lexicon: defs.main.record.properties.numReactions.type: invalid_literal (expected: ["boolean","integer","string","bytes","cid-link","blob","ref","union","unknown","array"])

One option could be to output a warning when nested objects are used until it's officially decided whether it's valid or not. Though I'm not sure if that's even needed.

Feel free to close this issue if you think no action is needed.

Very good point, though after reading the linked issue it seems most involved are okay with it and the original Typescript SDK supported it. With that in mind I'm inclined to keep the behavior and just keep an eye out for that issue to see if a decision is made one way or the other.

I'll keep this issue open as a reminder to check back in.

Sign up or Sign in to add to the discussion.