GithubHelp home page GithubHelp logo

ianstormtaylor / superstruct Goto Github PK

View Code? Open in Web Editor NEW
6.8K 44.0 218.0 5.89 MB

A simple and composable way to validate data in JavaScript (and TypeScript).

Home Page: https://docs.superstructjs.org

License: MIT License

JavaScript 0.40% TypeScript 99.60%
validation types interface structs schema javascript typescript

superstruct's Issues

Add showcase field in README

Hi Ian, thanks for your work, Superstruct works great!

For the past days I was working with a library called Bumpover that deals data migration, whose data validation API relies on Superstruct. This library is usable for now, so how about adding its link to a "Showcase" or "Related" field in README? The more scenarios using Superstuct, the more popularized it is.

add `interface` struct

Similar to other interface implementations, and unlike the existing struct, where it doesn't validate the entire shape of an object, but just ensures that certain properties are available.

add `partial` struct

To parallel, the default object struct, only verifying existing properties, and not throwing for unknown properties passed in.

I think this needs to be separate from interface, because interface doesn't perform other checks.

Allow custom error messages for user defined types

It seems like now is impossible to declare custom error messages for user types

What if in this example I want to provide 2 different error messages, one for first check The provided {value} is not email and other for length check Email can't be longer than 256 smbs

const struct = superstruct({
  types: {
    email: value => isEmail(value) && value.length < 256,
  }
})

May you allow to provide a message in validate function via throw or as a result? Or I just not found a solution.

How to serialize/persist a struct schema?

Hi Ian, good to see you here, this library hits a pain point!

Previously I've involved in a JS library tracking user behaviour. For each site using it, site admins can configure tracking rules, which results in a dynamic schema to persist in DB. We picked JSON schema for that case, which works but looks verbose. So here comes the point: for dynamic schemas, can we serialize the struct to an exchangeable format, them parsing them at runtime? As a side effect supporting this feature, even importing JSON schema as struct seems possible.

Hope for your thoughts on this idea, thanks.

consider adding value normalizing

This is the opposite of coercion, and instead acts on the value after it has been normalized. This can also be useful in cases where you need data in a canonical representation, but you want to allow a few different ones. Although, this might be solved with coercion already

Cannot convert object to primitive value

This line

const message = `Expected a value of type \`${type}\`${path.length ? ` for \`${path.join('.')}\`` : ''} but received \`${value}\`.`
caused an error Cannot convert object to primitive value.

Modern js frameworks like to implement objects without prototype like:

      const a = Object.create(null);
      a.x = 1;
      // The line below will fail with "Cannot convert object to primitive value"
      const www = `jhjh ${a}`;

So every time I met an error in such object instead of superstruct error I get Cannot convert object to primitive value.

I'll try to provide a fix

rename the implicit `object` struct to `shape`

To get rid of the potential confusion between struct('object') and struct.object. The same way that struct('array') and struct.list are separated. Open to ideas for better names that shape.

Edit: Actually record may be a better name than shape.

How to perform asynchronous validation?

Hello, I want to get your thoughts on potentially supporting async validation?

My use case: validating an object by querying a service that some key actually exists in backend.

const Config = struct.async({
  name: val => val === 'a' || val === 'b',
  key: k => axios.get(`/query-service/${k}`),
  //              ^ assume this Promise resolves 'abc' or rejects 'not found'
});

try {
  const config = await Config({ name : 'a', key: 'some-existing-key' }) // {name: 'a', key: 'abc'}
} catch (err) {
  console.log(err) // 'not found'
}

add schema builder

Hi @ianstormtaylor

I really like your library because I have used ajv and joi as well and I was frustrated from these libraries.
I would like to use your library with abstraction layer because I do not want to write types as string Because I will write typos like 'string' 'String' and others variants :)

I saw very nice abstraction on the top of ajv.
https://github.com/RomAnoX/ajv-schema-builder

What do you think about this idea?
Thank you

$ref another schema

I wasn't able to find in the doc a clear reference example.
Like the jsonschema feature: $ref: '#ext' // references another schema

What's the equivalent in superstruct?

Type Definitions

Hello,

Is there a plan to add typescript/flow type definitions?

Thank you!

Making a struct optional

Hello, if I want to make the author field optional, what do I have to do with this basic piece of code ?

const Article = struct({
  id: 'number',
  title: 'string',
  created_at: 'date',
  published_at: 'date?',
  author: User,
})

What I would like to do is just add the question mark sign.

Thanks.

Error building minified UMD bundle

Following error is encountered when installing superstruct from ground.

Environment: macOS 10.13 / Node V8.3.0

โžœ  superstruct git:(master) npm i
โœ” Installed 29 packages
โœ” Linked 441 latest versions
[fsevents] Success: "/Users/ewind/code/playground/superstruct/node_modules/[email protected]@fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" already installed
Pass --update-binary to reinstall or --build-from-source to recompile
โœ” Run 1 scripts
yarn run v1.0.2
$ yarn run build:es && yarn run build:cjs && yarn run build:max && yarn run build:min

./src/index.js โ†’ ./lib/index.es.js...
created ./lib/index.es.js in 694ms

./src/index.js โ†’ ./lib/index.js...
created ./lib/index.js in 1.2s

./src/index.js โ†’ ./umd/superstruct.js...
created ./umd/superstruct.js in 821ms
/bin/sh: uglifyjs: command not found

./src/index.js โ†’ stdout...
created stdout in 1.1s
Error: write EPIPE
    at _errnoException (util.js:1022:11)
    at WriteWrap.afterWrite (net.js:862:14)
error Command failed with exit code 127.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
โœ– Install fail! Error: Run "sh -c yarn run build" error, exit code 1
Error: Run "sh -c yarn run build" error, exit code 1
    at ChildProcess.proc.on.code (/Users/ewind/.nvm/versions/node/v8.3.0/lib/node_modules/cnpm/node_modules/runscript/index.js:74:21)
    at emitTwo (events.js:125:13)
    at ChildProcess.emit (events.js:213:7)
    at maybeClose (internal/child_process.js:927:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)

This error message can be tracked to the build:min script in package.json:

"build:min": "NODE_ENV=production rollup --config ./config/rollup-umd-min.js | uglifyjs > ./umd/superstruct.min.js",

This also results in error running yarn run build:

โžœ  superstruct git:(fix-build) yarn run build
yarn run v1.0.2
$ yarn run build:es && yarn run build:cjs && yarn run build:max && yarn run build:min

./src/index.js โ†’ ./lib/index.es.js...
created ./lib/index.es.js in 637ms

./src/index.js โ†’ ./lib/index.js...
created ./lib/index.js in 613ms

./src/index.js โ†’ ./umd/superstruct.js...
created ./umd/superstruct.js in 582ms
/bin/sh: uglifyify: command not found

./src/index.js โ†’ stdout...
created stdout in 619ms
Error: write EPIPE
    at _errnoException (util.js:1022:11)
    at WriteWrap.afterWrite (net.js:862:14)
error Command failed with exit code 127.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

The uglifyify dependency is missing bin entry, leading error for npm scripts. I've raised an issue about this, while I suggest a minify config with rollup plugin can work better with less verbose config. I'm going to PR for it ๐Ÿ˜€

Supported node version

Which versions of node are supported? Currently due to dependencies only node 8+ is supported, is that intended?

error [email protected]: The engine "node" is incompatible with this module. Expected version ">=8".

Defaults from function

The examples show passing a function to defaults, however when I try to do so I receive the following:

TypeError: Expected a value of type `date` for `created_at` but received `() => new Date()`.

cross referencing data properties

Is there any way to validate a property by cross-referencing other data values? i.e.

const schema = struct({
  foo: 'string',
  bah: (value, data) => !!(data.foo || value),
});

List of unions getting mismatching error.type and error.path/value?

Hello, I have a following script to showcase something I observed. If I have a list of union in my struct, and if one the of members didn't match a union, the path / value points to the actual mismatching property that caused the union to break, but the type only stops at the union level.

I'm not sure if this is intended behavior. In my real use case I have slightly more complex data structure, and the mismatch made it a little harder for me to figure out where the issue is. Can you advise?

const {struct} = require('superstruct');

const Cat = struct({
  name: 'string',
  meow: 'string',
});

const Dog = struct({
  name: 'string',
  bark: 'string'
});

const Pet = struct.union([Cat, Dog]);

const Home = struct({
  pets: [Pet]
});

const homeData = {
  pets: [
    { name: 'pluto', bark: 'woof' },
    { name: 'hello', meow: 'kitty' },
    { name: 'vlad', flap: 'bat flapping' },
  ]
};

try {
  Home.assert(homeData);
} catch (err) {
  console.error('message =', err.message);
  console.error('type =', err.type);
  console.error('path =', err.path);
  console.error('value =', err.value);
  console.error('errors =', err.errors);
}

This prints out

message = Expected a value of type `{name,meow} | {name,bark}` for `pets.2.flap` but received `bat flapping`.

# points to the union struct
type = {name,meow} | {name,bark}    

# points to the prop that broke the union struct
path = [ 'pets', 2, 'flap' ]

# points to the prop that broke the union struct
value = bat flapping                    
errors = [ { data: { pets: [Array] },
    path: [ 'pets', 2, 'flap' ],
    value: 'bat flapping',
    errors: [Circular],
    type: '{name,meow} | {name,bark}' } ]

Providing Context to Type Functions

Thank you for publishing superstruct - amazing clarity.

I am defining schemas in YAML and using superstruct to validate. If I want to do bounds checking for integers, for example, I have to resort to using struct.function(). I can't use types for this scenario because only the value is passed in (edit) - and not the key of the validated data property. If the key were passed to the type validation function, I could bind to that function to look up the additional schema parameters I need.

Please consider if it would be a good idea or a bad idea to pass along additional parameters to the type validation function.

add `enums` struct

It's pretty common to need a list of enums (eg. categories) and the current syntax is:

struct([struct.enum([...])])
struct.list([struct.enum([...])])

I think it would be nice to have:

struct.enums([...])

add support for tuple structs

Right now list structs are required to have a single element definition:

struct(['string'])

But there is a use case for tuples, where the element count is fixed. You wouldn't use this for single-element arrays, so we can make multi-element arrays the syntax for tuples. For example:

struct(['string', 'number'])

Would then require data that looks like:

['a', 1]
['b', 2]
...

This would make the case of validating arguments pretty simple too, for example:

const s = struct(['string', 'number', 'object'])

function myFunction(prefix, amount, options = {}) {
  s.assert(arguments)
  ...
}

recursive schema?

Hi, I'm wondering if superstruct can support recursive schema? For example

const BinaryTree = struct({
  value: 'any',
  left: struct.optional(BinaryTree),
  right: struct.optional(BinaryTree),
});

Intuitively I feel this should be supported already, but I don't know of a way to implement, can you advise? Thanks!

add `constant` struct

For when you need a value to be an exact constant.

const User = struct({
  id: 'number',
  object: struct.constant('user'),
  name: 'string',
  email: 'string',
})

Build script fails on Windows

ฮป yarn run build
yarn run v1.3.2
$ yarn run build:lib && yarn run build:max && yarn run build:min
$ babel ./src --out-dir ./lib
src\default-types.js -> lib\default-types.js
src\index.js -> lib\index.js
src\struct-error.js -> lib\struct-error.js
src\superstruct.js -> lib\superstruct.js
$ mkdir -p ./dist && browserify ./src/index.js --transform babelify --standalone Superstruct > ./dist/superstruct.js
The syntax of the command is incorrect.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

I'll try to work on this.

Usage for other than types validations

Hey

I checked the docs, but didn't find any info if this library is supposed to be used only to validate types of data or it can be used for other validations.

For example, I can check if value is a number. Is it possible and how to check, if this value is less than 100 or more than 6?

Question: is it possible to create a type that matches a list of structs?

Hey, I have a question. Let's say I have this payload that I want to validate:

[
  { id: '1', name: 'John', age: 43 },
  { id: '2', name: 'Miranda' }
]

Then I would create a struct for each item:

const User = struct({
  id: 'string',
  name: 'string',
  age: 'number?'
})

But since it's a list of users, how would I go about validating that? Is there a way to create a type that is a list of struct?

Validate full structure

Hi,

I need help :(
I any option to validate full structute and return all errors?

My current solution show first found error in structure

Error when bundle with webpack

Unexpected token: name (StructError) [./node_modules/superstruct/lib/index.es.js:7,0][index.ef29450fbb2e4dc5d2e2.js:147554,6]

consider adding value coercion

This can sometimes be useful, for example when you require numbers, but a string of a number was passed in. If there was a coercion step before validation it would account for that.

extend core types

First off awesome library. You have saved me from the muck of json schema!
I find myself having to call superstruct a lot to add date and email validation. I was wondering if it is possible, or could be possible, to extend the core struct instance to have additonal types defined for all structs.
I was doing a special exported struct that I consumed but having to know and manage the require path is getting a tiny bit hairy. Would love your thoughts on this?

Multiple errors

When the data passed in has multiple validation errors, superstruct will throw upon the first error. I think it would be very much desirable to collect all errors and return them. That would make it much more useful, specially for large complex types with many fields.

Error nesting structs

When trying to nest TreeNode structs like below I came up with error:

const Node = struct({
  id: 'number',
  children: [Node]
})

JSFiddle

Maybe I'm missing something, so how can we support such kind of validation? I can such feature pretty handy in slate's schema, is slate going to has this library as dependency?

A custom property with a default value throws an error

Me again ๐Ÿ™‚


When using a struct as the type for a property, it throws an error even if a default value is specified.

See it in action: https://runkit.com/embed/z10qks2qv2v1

const User = superstruct.struct({
  id: 'number',
  name: 'string',
})

const Article = superstruct.struct({
  id: 'number',
  title: 'string',
  author: User,
}, {
  author: {
    id: 1000,
    name: 'Owner',
  },
})

// Passes as expected
Article({
  id: 1,
  title: 'This works as expected',
  author: {
    id: 2,
    name: 'Contributor',
  },
})

// Fails :(
Article({
  id: 1,
  title: 'This does not work!',
})

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.