typst-community / valkyrie Goto Github PK
View Code? Open in Web Editor NEWType safe type safety for Typst
License: Other
Type safe type safety for Typst
License: Other
I'm in the process of implementing a basic visualization of valkyrie schemas for my documentation template (like suggested in #17). It won't cover every possible case, but can be used as a means to define custom datatypes.
Some of the provided types don't expose all necessary information for this, though. For example #choice(list)
"hides" the list of possible choices in an assertion closure.
It would be nice if types made all important information available (like in the example above in a choices
key).
Some types do that (eg #either
has an extra options
key), but not all.
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.
It seems that c52ae78 introduced a regression where, given an either
schema containing an auto
schema, passing auto actually fails with an incorrect message saying it got none
.
#import "@preview/valkyrie:0.2.0" as z
#{
_ = z.parse(auto, z.either(
z.content(),
z.base-type(name: "auto", types: (type(auto),)),
))
}
I haven't actually tested this specific snippet, it's a minified version, I've done the bisection on the actual snippet.
Is there a way to specify that a field in a schema may be absent? TIA.
Suppose I want an optional date as an argument. The code
#import "@preview/valkyrie:0.2.1" as z
#let schema = z.dictionary((
date: z.date(optional: true, pre-transform: z.coerce.date)
))
#z.parse((date: none), schema)
results in the error Unknown date of type 'none' accepts: datetime, str, int, and object
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
}
},
),
))
}
It would be useful to have an assertion that acts opposite to eq
, e.g.,
#let schema = z.string(assertions: (z.assert.not-eq(""),))
It's possible that it is already doable with the current functionality but I haven't found an obvious way for doing so.
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?
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.
I'm trying to parse a schema with an optional trailing content using tuple
. However, when I use a schema like
tuple(string(), string(), content(optional: true))
valkyrie panics when trying to access the third element of the tuple if the trailing content is not specified.
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.
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.
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.
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 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.
#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.
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.
I want to write configurations that accept inset
and outset
. I am certain there is some docs on what these are, but I cannot seem to find them.
I eventually dived into the source to see that what I effectively want is something like
#let inset = z.dictionary((
left: z.optional(...),
right: z.optional(...),
top: z.optional(...),
bottom: z.optional(...),
x: z.optional(...),
y: z.optional(...),
rest: z.optional(...),
))
It would be very helpful for template and package developers to have access to basic known dictionaries, where "dictionary" effectively has its own schema known to Typst.
Edit: The main difficulty is that the actual values (the ...
) are generic in the source, and vary in each use case. You could set it to z.Any()
, but that would not be a great idea.
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.
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
}
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.
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.
I'm not currently working on this but there have been improvements since the last version. @tingerrr, could you help me do the once-over before submitting it to Typst Universe?
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.