Code Monkey home page Code Monkey logo

valkyrie's Introduction

The Valkyrie Package

Version 0.2.0

This package implements type validation, and is targeted mainly at package and template developers. The desired outcome is that it becomes easier for the programmer to quickly put a package together without spending a long time on type safety, but also to make the usage of those packages by end-users less painful by generating useful error messages.

Example Usage

#import "@preview/valkyrie:0.2.0" as z

#let my-schema = z.dictionary((
    should-be-string: z.string(),
    complicated-tuple: z.tuple(
      z.email(),
      z.ip(),
      z.either(
        z.string(),
        z.number(),
      ),
    ),
  )
)

#z.parse(
  (
    should-be-string: "This doesn't error",
    complicated-tuple: (
      "neither@does-this.com",
      // Error: Schema validation failed on argument.complicated-tuple.1: 
      //        String must be a valid IP address
      "NOT AN IP",
      1,
    ),
  ),
  my-schema,
)

Community-lead

As of version 0.2.0, valkyrie now resides in the typst-community organisation. Typst users are encouraged to submit additional types, assertions, coercions, and schemas that they believe are already used widely, or should be widely adopted for the health of the ecosystem.

valkyrie's People

Contributors

jamesxx avatar tingerrr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

ericvdtoorn

valkyrie's Issues

Add schemas for argument sinks

Many package provide argument sinks, which are frequently used to allow passing variadic positional arguments and then fail if the sink contained any named arguments.

Some of these (to be discussed which) should be provided as built in schemas with some default transformers like unwrapping only the positional arguments after the assertions ensured there are no named arguments.

Allow default values to use other values

I would like to be able to set the default value of one value to be the same as the value of another argument, or use that value somehow.

For example, if I wanted to create a create-theme function that creates a color theme with a primary, secondary and tertiary color:

#{
 let theme-schema = t.dictionary((
    primary: t.color(),
    secondary: t.color(optional: true),
    tertiary: t.color(optional: true),
  ))

  let create-theme(primary, ..args) = {
    let theme = t.parse(
      (
        primary: primary,
        ..args.named(),
      ),
      theme-schema,
    )
    if theme.secondary == none {
      theme.secondary = theme.primary.rotate(120deg)
    }
    if theme.tertiary == none {
      theme.tertiary = theme.primary.rotate(240deg)
    }
    return theme
  }

  create-theme(rgb("#ff2f93"))
}

I need to check each optional value and set it to a color that is based on the mandatory primary color if none was given. It would be nice to define this kind of default value in the schema itself.

Maybe some kind of "pos-post-transform" could be introduced that runs after all values have been parsed and receives the result of the parsing. Something like this:

#{
  let theme-schema = t.dictionary((
    primary: t.color(),
    secondary: t.color(
      optional: true,
      post-post-transform: (self, it, result) => {
        if it == none {
          result.primary.rotate(120deg)
        } else {
          it
        }
      },
    ),
    tertiary: t.color(
      optional: true,
      post-post-transform: (self, it, result) => {
        if it == none {
          result.primary.rotate(240deg)
        } else {
          it
        }
      },
    ),
  ))
}

Make tuple fail gracefully for wrong number of values

The tuple type currently throws a somewhat confusing error message when the input has to few values, while it passes for inputs with more values than expected.

See this example:

#{
  let schema = t.tuple(t.integer(), t.integer())
  t.parse((0, 1, 2), schema) // passes
  t.parse((0, 1), schema)    // passes
  t.parse((0,), schema)      // fails with error
}

The first call to parse throws this error:

error: array index out of bounds (index: 1, len: 1) and no default value was specified
   ┌─ @preview/valkyrie:0.2.0/src/types/tuple.typ:25:10
   │
25 │           it.at(key),

It would be nice to get a more helpful error message like with the other types.

In addition, I would expect the validation to fail, if the supplied value has more values as expected. In the example, the first call to parse should have failed.

Add named schemas for missing built-in types

Some types, such as gradient, stroke, or even simpler ones like label or selector do not yet have schemas.

Some others which are more complex deserve getting dedicated schemas like validation for queryable element functions, countable element functions etc. (what is internally tracked using traits on elements) should likely be included as choice schemas.

Enhance `content` schema or add a more permissive schema

Currently, with something like z.content I would've assumed to be able to pass sym.dagger, but It turns out this is of type symbol. This makes sense of course, but a user my expect z.content to allow this too.

I think symbol should be added to z.content, as it is trivially converted to content. I wonder if there are any other types we may have missed that ought to be included here.

Add types and coercions for "variable" types like stroke and fill

#18 added a schema for the Typst builtin type "stroke". But most of the time stroke arguments accept either one of stroke, length, color or dict. Similarly fill usually accepts color, gradient or pattern.

There should be types to support this, since those are very common use-cases in Typst.

I suggest these compound types:

  • strokes: z.either(z.stroke(), z.length(), z.color(), z.dictionary( (thickness: z.length(optional:true), ...) ))
  • fill: z.either(z.color(), z.gradient(), z.pattern()) (pattern is still missing as a base-type, I think)
  • inset: z.either(z.length(), z.dictionary( (x: z.length(optional:true), ...) ))

I probably missed some.

Syntax error when using with Typst 0.11

First of all, thanks for this great library!

With the recent Typst 0.11 a new context keyword was introduced and I think the #import "context.typ": context line conflicts with it.

This is probably fixable by simply renaming the import type to ctx or something similar.

Should coercions respect `optional: true`?

Not sure if this is intended, but currently coercions will panic if a value is none, which can happen with optional: true set.

I think it would be more intuitive, if a coercion respected the optional setting and returned none, if the key was not present.

For example, the array coercion would look like this:

#let array(self, it) = {
  if self.optional and it == none {
    return none
  }
  if (type(it) != type(())) {
    return (it,)
  }
  it
}

Feature Request: A means of visualizing a schema and its requirements

This may not end up being possible but I'm creating this issue to track the addition of a means to visualize valkyrie schema for the purposes of inclusion in package documentation.

Current thoughts: Schema define a new method for the purposes of generating content that adequately represents the schema and its requirements. This might only work for the simplest schema without coercions or assertions. Alternatively, this task is left to individual documentation-generator packages as its implementation will depend heavily on the end use-case.

Mutually exclusive choices in `either`

Is it possible to set either to have mutually exclusive choices, e.g. where only one of

let schema = val.either(
        val.dictionary((
            dynamic: val.boolean()
        )),
        val.dictionary((
            seed: val.integer()
        ))
)

can be the case but not both?

I might be doing something wrong but this schema seems to pass even when there's a dictionary with both fields present.

Handle `default` in case of `auto`, not `none`

Currently, the default in base-type is used if it == none or == type(none), ideally this should happen when it is auto, as none means an explicit opt, out in most cases.

I'm unsure whether this is always a good idea, this likely interferes with optional: true too in some way.

Add built-in `version` schema and coercion

Add a schema and coercion for the verison type, the coercion should attempt parsing a string into a version before it is validated.

Currently, coercions seem to be infallible pre- or post-transformers, at least in semantics, perhaps a relaxation of this could allow parsing conversions like these to simply be pre-transformers.

Reflect change in repository ownership

There'll be some references throughout the codebase that need to be updated to reflect the transfer of the repository to the typst-community org. I'll self assign but others are welcome to participate too.

Fix failing CI on building docs

CI automatically builds the docs, which depend on a locally installed unreleased version of mantis. This issue could be resolved by either not requiring that CI successfully compiles the docs, or by some means installing this package during CI.

Add back `min` and `max` schema parameters

Previously the number, integer, float, string, and array schemas had the parameters min and max.

I propose adding these back, those range checks are fairly convenient, especially combined with z.<schema>.with(min: ...) for schema adaption. The main downside of not having them now is that nested schema validation cannot perform easy length checks.

Inconsistency between parsing and coercions for datetimes

Firstly, thank you for the package; it seems to be a great help to package authors.

However, I encountered an issue when using coercions with datetime objects. The date schema function accepts any datetime object (even time only), while the coercion only works for actual dates, without a time component. I think it would be best to split this into three different types, according to the amount of precision: dates, times, and datetimes. Then each of those could have separate schema and coercion functions.

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.