fabian-hiller / valibot

The modular and type safe schema library for validating structural data 🤖
https://valibot.dev
MIT License
5.6k stars 169 forks source link

Provide source locations for errors in string data #695

Closed kwangure closed 3 days ago

kwangure commented 4 days ago

It would be helpful if there was a Valibot analogue to parse JSON and YAML. It would reuse the same Valibot API, but instead of taking JavaScript values, it would take JSON/YAML strings. By parsing their AST, you can include the exact source locations of the errors. This would be particularly useful for applications that display the inline errors in a text-editor or CLI output.

I imagine it's a matter of implementing a parseJSON (using something like jsonc-parser) and parseYAML (using something like yaml) API that takes the usual Valibot schema. I have admittedly only had a brief look at the current implementation of Valibot...so it might require a few changes elsewhere.

I've been thinking about this since https://github.com/bluwy/publint/issues/39 ...I just haven't gotten around to it yet. There was interest in a similar feature for AJV in https://github.com/ajv-validator/ajv-cli/issues/34. I figured I'll let it stew here in case someone can get to it before me.

fabian-hiller commented 4 days ago

Do you want to validate if the JSON or YAML format is valid or do you want to validate the content of the string?

kwangure commented 4 days ago

The goal is to validate and transform the JSON/YAML string into a type-safe value like the regular Valibot parse function, but include the source location of the errors based on the AST of the string. For example, this allows adding a red squiggly in VS Code in the right place for a validated config file.

import * as v from 'valibot';

const Schema = v.object({
  email: v.pipe(v.string(), v.email()),
  password: v.pipe(v.string(), v.minLength(8)),
});

const userJsonString = JSON.stringify({
  email: 'jane@examplecom', // error - missing "."
  password: '12345678',
}, null, 4);

const result = v.safeParseJSON(Schema, userJsonString);

console.log(result);

Outputs something like:

{
  typed: true,
  success: false,
  output: {
    email: "jane@examplecom",
    password: "12345678"
  },
  issues: [
    {
      kind: "validation",
      type: "email",
      input: "jane@examplecom",
      expected: null,
      received: "\"jane@examplecom\"",
      message: "Invalid email: Received \"jane@examplecom\"",
      requirement: RegExp,
      path: [
        {
          type: "object",
          origin: "value",
          input: {
            email: "jane@examplecom",
            password: "12345678"
          },
          key: "email",
          value: "jane@examplecom",
          start: {
              column: 14,
              line: 2,
           },
           end: {
              column: 31,
              line: 2,
           },
        },
      ],
      issues: undefined,
      lang: undefined,
      abortEarly: undefined,
      abortPipeEarly: undefined
    }
  ]
}

Note that the invalid string "jane@examplecom" has location markers for 2:14-2:31 as per the AST.

fabian-hiller commented 4 days ago

I am not sure if I want to add this to our core package. Maybe this should be a community project for now, that can be moved to our repository if there is a high demand.

kwangure commented 4 days ago

This was my thinking too. I don't think there ever will be "high demand" per se. I imagine it would be most useful for people building developer tools rather than day to day applications. They could be published separately as @valibot/json and @valibot/yaml packages, for example.

fabian-hiller commented 3 days ago

Yes, I agree. Publishing via @valibot/... is not an option at the moment because I do not have time to check everything due to our upcoming v1 release. But I can imagine it in the long run as the core team around Valibot grows. Feel free to start it as a community project and add it to our ecosystem page. I would also be happy to help you share it on X.

kwangure commented 3 days ago

Best of luck with the V1 release! I'll close this to keep your issues focused on what you're actively working on.