Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The unevaluatedItems lesson needs work #61

Open
jdesrosiers opened this issue Aug 14, 2024 · 5 comments
Open

The unevaluatedItems lesson needs work #61

jdesrosiers opened this issue Aug 14, 2024 · 5 comments
Labels
📝 Documentation Improvements or additions to documentation Status: Available No one has claimed responsibility for resolving this issue.

Comments

@jdesrosiers
Copy link
Member

The unevaluatedItems lesson is a lesson for items, not unevaluatedItems. While you can use unevaluatedItems in place of items and get the same result, this lesson does nothing to show an actual use case for the keyword. Notice that this passes the lesson.

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "integer"
    },
    "skills": {
      "type": "array",
      "prefixItems": [
        { "enum": ["HTML", "CSS", "JavaScript"] },
        { "enum": ["HTML", "CSS", "JavaScript"] },
        { "enum": ["HTML", "CSS", "JavaScript"] }
      ],
      "items": { "type": "string" }
    }
  }
}

A lesson on unevaluatedItems should include extending and/or closing a tuple using an applicator of some kind. Here's an example of adding an item to the tuple and closing it to further extension.

{
  "$ref": "#/$defs/tuple",
  "prefixItems": [true, true, { "type": "number" }],
  "unevaluatedItems": false,

  "$defs": {
    "tuple": {
      "type": "array",
      "prefixItems": [
        "type": "string",
        "type": "boolean"
      ]
    }
  }
}
@JeelRajodiya JeelRajodiya added the 📝 Documentation Improvements or additions to documentation label Aug 25, 2024
@JeelRajodiya JeelRajodiya added the Status: Available No one has claimed responsibility for resolving this issue. label Sep 29, 2024
@techmannih
Copy link

techmannih commented Oct 25, 2024

@jdesrosiers @JeelRajodiya May I work on this issue? Please give me your suggestions, as I need your help in resolving it.

const code: any = {
  $defs: {},
  type: "object",
  properties: {
    name: {
      type: "string",
    },
    age: {
      type: "integer",
    },
    skills: {
      type: "array",
    },
  },
};

const solution = structuredClone(code);

// Define the $defs for the tuple
solution.$defs = {
  tuple: {
    type: "array",
    prefixItems: [
      { enum: ["HTML", "CSS", "JavaScript"] },
      { enum: ["HTML", "CSS", "JavaScript"] },
      { enum: ["HTML", "CSS", "JavaScript"] }
    ],
  },
};

// Update the 'skills' property to use the tuple and unevaluatedItems

  solution.properties.skills = {
    type: "array",
    $ref: "#/$defs/tuple",
    prefixItems: [
      true,
      true,
      { type: "string" }
    ],
    unevaluatedItems: true
  };

const testCases = [
  {
    input: {
      name: "John Doe",
      age: 30,
      skills: ["HTML", "CSS", "JavaScript", "TypeScript"],
    },
    expected: true,
  },
  {
    input: {
      name: "John Doe",
      age: 30,
      skills: ["JavaScript", "CSS", "HTML", "TypeScript"],
    },
    expected: true,
  },
  {
    input: {
      name: "John Doe",
      age: 30,
      skills: ["JavaScript", "HTML", "CSS", "TypeScript"],
    },
    expected: true,
  },
  {
    input: {
      name: "John Doe",
      age: 30,
      skills: ["HTML", "CSS", "JavaScript", 123],
    },
    expected: true,
  },
  {
    input: {
      name: "John Doe",
      age: 30,
      skills: ["HTML", "CSS", "JavaScript", "TypeScript", "React"],
    },
    expected: true,
  },
  {
    input: {
      name: "John Doe",
      age: 30,
      skills: ["React", "Java", "Vue.js"],
    },
    expected: false,
  },
  {
    input: {
      name: "John Doe",
      age: 30,
      skills: ["HTML", "JavaScript", "TypeScript", "React", "Vue"],
    },
    expected: false,
  },
];

module.exports = {
  code,
  solution,
  testCases,
};

and this solution passed all test cases

{
  "$defs": {
    "tuple": {
      "type": "array",
      "prefixItems": [
        {
          "enum": [
            "HTML",
            "CSS",
            "JavaScript"
          ]
        },
        {
          "enum": [
            "HTML",
            "CSS",
            "JavaScript"
          ]
        },
        {
          "enum": [
            "HTML",
            "CSS",
            "JavaScript"
          ]
        }
      ]
    }
  },
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "integer"
    },
    "skills": {
      "type": "array",
      "$ref": "#/$defs/tuple",
      "prefixItems": [
        true,
        true,
        {
          "type": "string"
        }
      ],
      "unevaluatedItems": true
    }
  }
}

@jdesrosiers
Copy link
Member Author

I'm not a maintainer of this repo, so I can't give you the go ahead to work on this, but I can provide feedback on the proposal.

This proposed schema doesn't do anything and isn't an example of a use-case for unevaluatedItems.

  • The extending tuple doesn't do anything useful. It's saying the third element needs to be a string, but it's already constrained to be an enum whose values are all strings.
  • "unevaluatedItems": true is a no-op. It doesn't do anything. In order to do something useful, you need to give it a schema object or false.

I wouldn't try to iterate off of the original schema because it doesn't make sense to start with. Using prefixItems for a homogeneous array is a bad idea. There are three uses for unevaluatedItems. They should probably each have their own lesson.

  • Closing a tuple -- Let's say you have a tuple that describes a tuple that takes a string, then a number (["a", 1]). You can ensure that the tuple has no more than those defined items by referencing it and using "unevaluatedItems": false.
  • Constrain additional items in the tuple -- Let's say you have a string-number tuple and you want any additional items to be strings (["foo", 42, "a", "b", "c", ...]). You can do that by referencing the tuple and using "unevaluatedItems": { "type": "string" }.
  • Constrain items that don't match a pattern -- Let's say you have an array that needs to have at least one string. The rest need to be numbers. You can do that with "contains": { "type": "string" }, "unevaluatedItems": { "type": "number" }.

The only one that's going to be easy to come up with a realistic example is going the be the first case. The only realistic case I've ever seen for the second case is modeling variatic functions. For the third case, I'm not sure there is an example of using unevaluatedItems with contains that you couldn't do better in another way.

Good luck coming up with your examples. I'm here to help verify you're on the right track.

JeelRajodiya added a commit that referenced this issue Nov 2, 2024
@JeelRajodiya
Copy link
Member

as per the discussion the slack, we have removed the lesson.

If someone wish to improve the lesson, they can refer here to the previous state of the repo and suggest changes accordingly.

@techmannih
Copy link

Hi @JeelRajodiya yes I am interested

@JeelRajodiya
Copy link
Member

@techmannih I hope you have read the slack discussion I mentioned above and this message. If you are confident in resolving the issue. feel free to open a PR directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📝 Documentation Improvements or additions to documentation Status: Available No one has claimed responsibility for resolving this issue.
Projects
None yet
Development

No branches or pull requests

3 participants