Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

superstruct

Package Overview
Dependencies
Maintainers
1
Versions
90
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

superstruct - npm Package Compare versions

Comparing version 0.0.5 to 0.1.0

Changelog.md

27

docs/getting-started.md

@@ -12,4 +12,31 @@

To install Superstruct with Yarn or Npm, simply:
```bash
yarn add superstruct
```
```bash
npm install --save superstruct
```
And then you can import it into your code base:
```js
import { struct, superstruct } from 'superstruct'
```
If you would rather import Superstruct with a `<script>` tag, you can use the bundled build:
```html
<script src="https://unpkg.com/superstruct/dist/superstruct.min.js"></script>
```
This will expose the `Superstruct` global with the exported functions.
## Creating Structs
## Defining Custom Data Types

@@ -16,0 +43,0 @@

323

lib/index.js

@@ -8,331 +8,28 @@ 'use strict';

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _structError = require('./struct-error');
var _cloneDeep = require('lodash/cloneDeep');
var _structError2 = _interopRequireDefault(_structError);
var _cloneDeep2 = _interopRequireDefault(_cloneDeep);
var _superstruct = require('./superstruct');
var _componentType = require('component-type');
var _superstruct2 = _interopRequireDefault(_superstruct);
var _componentType2 = _interopRequireDefault(_componentType);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/**
* Default types.
* Create a simple `struct` method for the default types.
*
* @type {Object}
* @type {Function}
*/
var DEFAULT_TYPES = {
any: function any(v) {
return v !== undefined;
},
array: function array(v) {
return (0, _componentType2.default)(v) === 'array';
},
boolean: function boolean(v) {
return (0, _componentType2.default)(v) === 'boolean';
},
buffer: function buffer(v) {
return (0, _componentType2.default)(v) === 'buffer';
},
date: function date(v) {
return (0, _componentType2.default)(v) === 'date';
},
error: function error(v) {
return (0, _componentType2.default)(v) === 'error';
},
function: function _function(v) {
return (0, _componentType2.default)(v) === 'function';
},
null: function _null(v) {
return (0, _componentType2.default)(v) === 'null';
},
number: function number(v) {
return (0, _componentType2.default)(v) === 'number';
},
object: function object(v) {
return (0, _componentType2.default)(v) === 'object';
},
regexp: function regexp(v) {
return (0, _componentType2.default)(v) === 'regexp';
},
string: function string(v) {
return (0, _componentType2.default)(v) === 'string';
},
undefined: function undefined(v) {
return (0, _componentType2.default)(v) === 'undefined';
}
const struct = (0, _superstruct2.default)();
/**
* Define a struct error.
*
* @type {StructError}
*/
};
var StructError = function (_Error) {
_inherits(StructError, _Error);
function StructError(message, data) {
_classCallCheck(this, StructError);
data.code = message;
data.path = data.path || [];
var index = data.index,
key = data.key,
value = data.value,
type = data.type;
switch (message) {
case 'element_invalid':
message = 'Expected the element at index `' + index + '` to be of type "' + type + '", but it was `' + value + '`.';
break;
case 'property_invalid':
case 'property_required':
message = 'Expected the `' + key + '` property to be of type "' + type + '", but it was `' + value + '`.';
break;
case 'property_unknown':
message = 'Unexpected `' + key + '` property that was not defined in the struct.';
break;
case 'value_invalid':
case 'value_required':
message = 'Expected a value of type "' + type + '" but received `' + value + '`.';
break;
default:
throw new Error('Unknown struct error code: "' + message + '"');
}
var _this = _possibleConstructorReturn(this, (StructError.__proto__ || Object.getPrototypeOf(StructError)).call(this, message));
_this.name = 'StructError';
for (var k in data) {
_this[k] = data[k];
}
Error.captureStackTrace(_this, _this.constructor);
return _this;
}
return StructError;
}(Error);
/**
* Create a struct factory from a set of `options`.
* Export.
*
* @param {Object} options
* @return {Function}
*/
function superstruct() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var TYPES = _extends({}, DEFAULT_TYPES, options.types || {});
/**
* Define a scalar struct with a `schema` type string.
*
* @param {String} schema
* @param {Any} defaults
* @return {Function}
*/
function scalarStruct(schema, defaults) {
var isOptional = schema.endsWith('?');
var type = isOptional ? schema.slice(0, -1) : schema;
var types = type.split(/\s*\|\s*/g);
var fns = types.map(function (t) {
var fn = TYPES[t];
if (typeof fn !== 'function') {
throw new Error('No struct validator function found for type "' + t + '".');
}
return fn;
});
return function (value) {
if (!isOptional && value === undefined) {
throw new StructError('value_required', { type: type });
}
if (value !== undefined && !fns.some(function (fn) {
return fn(value);
})) {
throw new StructError('value_invalid', { type: type, value: value });
}
return value;
};
}
/**
* Define a list struct with a `schema` array.
*
* @param {Array} schema
* @param {Any} defaults
* @return {Function}
*/
function listStruct(schema, defaults) {
if (schema.length !== 1) {
throw new Error('List structs must be defined as an array with a single element, but you passed ' + schema.length + ' elements.');
}
schema = schema[0];
var fn = struct(schema);
var type = 'array';
return function (value) {
if (value === undefined) {
throw new StructError('value_required', { type: type });
} else if ((0, _componentType2.default)(value) !== 'array') {
throw new StructError('value_invalid', { type: type, value: value });
}
var ret = value.map(function (v, index) {
try {
return fn(v);
} catch (e) {
var path = [index].concat(e.path);
switch (e.code) {
case 'value_invalid':
throw new StructError('element_invalid', _extends({}, e, { index: index, path: path }));
default:
if ('path' in e) e.path = path;
throw e;
}
}
});
return ret;
};
}
/**
* Define an object struct with a `schema` dictionary.
*
* @param {Object} schema
* @param {Any} defaults
* @return {Function}
*/
function objectStruct(schema, defaults) {
var structs = {};
var type = 'object';
for (var _key in schema) {
var fn = struct(schema[_key]);
structs[_key] = fn;
}
return function (value) {
var isUndefined = false;
if (value === undefined) {
isUndefined = true;
value = {};
} else if ((0, _componentType2.default)(value) !== 'object') {
throw new StructError('value_invalid', { type: type, value: value });
}
var ret = {};
for (var _key2 in structs) {
var s = structs[_key2];
var v = value[_key2];
var r = void 0;
try {
r = s(v);
} catch (e) {
var path = [_key2].concat(e.path);
switch (e.code) {
case 'value_invalid':
throw new StructError('property_invalid', _extends({}, e, { key: _key2, path: path }));
case 'value_required':
throw isUndefined ? new StructError('value_required', { type: type }) : new StructError('property_required', _extends({}, e, { key: _key2, path: path }));
default:
if ('path' in e) e.path = path;
throw e;
}
}
if (_key2 in value) {
ret[_key2] = r;
}
}
for (var _key3 in value) {
if (!(_key3 in structs)) {
throw new StructError('property_unknown', { key: _key3, path: [_key3] });
}
}
return isUndefined ? undefined : ret;
};
}
/**
* Define a struct with `schema`.
*
* @param {Function|String|Array|Object} schema
* @param {Any} defaults
* @return {Function}
*/
function struct(schema, defaults) {
var s = void 0;
if ((0, _componentType2.default)(schema) === 'function') {
s = schema;
} else if ((0, _componentType2.default)(schema) === 'string') {
s = scalarStruct(schema, defaults);
} else if ((0, _componentType2.default)(schema) === 'array') {
s = listStruct(schema, defaults);
} else if ((0, _componentType2.default)(schema) === 'object') {
s = objectStruct(schema, defaults);
} else {
throw new Error('A struct schema definition must be a string, array or object, but you passed: ' + schema);
}
return function (value) {
if (value === undefined) {
value = typeof defaults === 'function' ? defaults() : (0, _cloneDeep2.default)(defaults);
}
return s(value);
};
}
/**
* Return the struct factory.
*/
return struct;
}
/**
* Export the factory and the factory creator.
*
* @type {Function}
*/
var struct = superstruct();
exports.default = struct;
exports.struct = struct;
exports.superstruct = superstruct;
exports.StructError = StructError;
exports.superstruct = _superstruct2.default;
exports.StructError = _structError2.default;
{
"name": "superstruct",
"description": "A simple, expressive way to validate data in Javascript.",
"version": "0.0.5",
"version": "0.1.0",
"license": "MIT",

@@ -11,4 +11,4 @@ "repository": "git://github.com/ianstormtaylor/superstruct.git",

"build:lib": "babel ./src --out-dir ./lib",
"build:max": "mkdir -p ./dist && NODE_ENV=production browserify ./src/index.js --transform babelify --transform envify --standalone Superstruct > ./dist/superstruct.js",
"build:min": "mkdir -p ./dist && NODE_ENV=production browserify ./src/index.js --transform babelify --transform envify --transform uglifyify --standalone Superstruct | uglifyjs > ./dist/superstruct.min.js",
"build:max": "mkdir -p ./dist && browserify ./src/index.js --transform babelify --standalone Superstruct > ./dist/superstruct.js",
"build:min": "mkdir -p ./dist && browserify ./src/index.js --transform babelify --standalone Superstruct > ./dist/superstruct.min.js",
"clean": "rm -rf ./lib ./node_modules",

@@ -29,5 +29,7 @@ "lint": "eslint src/* test/*",

"babel-eslint": "^6.1.0",
"babel-plugin-transform-async-to-generator": "^6.24.1",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.9.0",
"babel-preset-stage-0": "^6.5.0",
"babel-preset-minify": "^0.2.0",
"babelify": "^7.3.0",

@@ -34,0 +36,0 @@ "browserify": "^13.0.1",

@@ -33,5 +33,7 @@

Superstruct makes it easy to define interfaces and then validate Javascript data against them. Its type annotation API was inspired by [Typescript](https://www.typescriptlang.org/docs/handbook/basic-types.html), [Flow](https://flow.org/en/docs/types/) and [GraphQL](http://graphql.org/learn/schema/), which gives it a API familiar, easy to understand API. But Superstruct is designed for runtime data validations, like accepting arbitrary input in a REST or GraphQL API, so it throws detailed errors for you or your end users.
Superstruct makes it easy to define interfaces and then validate Javascript data against them. Its type annotation API was inspired by [Typescript](https://www.typescriptlang.org/docs/handbook/basic-types.html), [Flow](https://flow.org/en/docs/types/), [Go](https://gobyexample.com/structs), and [GraphQL](http://graphql.org/learn/schema/), which gives it a familiar, easy to understand API.
But Superstruct is designed for runtime data validations, so it throws detailed runtime errors for you or your end users. This is especially useful in situations like accepting arbitrary input in a REST or GraphQL API. But it can even be used to validate internal data structures in non-typed code bases.
<br/>

@@ -121,3 +123,3 @@

- **They are tightly coupled to other concerns.** Many validators are implemented as plugins for Express or other HTTP frameworks, which is completely unnecessary and confusing to reason about. And since you can only use them with a web server you end up with even more fragmentation in your codebase.
- **They are tightly coupled to other concerns.** Many validators are implemented as plugins for Express or other HTTP frameworks, which is completely unnecessary and confusing to reason about. And when you need to validate data elsewhere in your code base you end up with fragmentation.

@@ -124,0 +126,0 @@ Of course, not every validation library suffers from all of these issues, but most of them exhibit at least one. If you've run into this problem before, you might like Superstruct.

import cloneDeep from 'lodash/cloneDeep'
import typeOf from 'component-type'
import StructError from './struct-error'
import superstruct from './superstruct'
/**
* Default types.
* Create a simple `struct` method for the default types.
*
* @type {Object}
* @type {Function}
*/
const DEFAULT_TYPES = {
any: v => v !== undefined,
array: v => typeOf(v) === 'array',
boolean: v => typeOf(v) === 'boolean',
buffer: v => typeOf(v) === 'buffer',
date: v => typeOf(v) === 'date',
error: v => typeOf(v) === 'error',
function: v => typeOf(v) === 'function',
null: v => typeOf(v) === 'null',
number: v => typeOf(v) === 'number',
object: v => typeOf(v) === 'object',
regexp: v => typeOf(v) === 'regexp',
string: v => typeOf(v) === 'string',
undefined: v => typeOf(v) === 'undefined',
}
const struct = superstruct()
/**
* Define a struct error.
* Export.
*
* @type {StructError}
*/
class StructError extends Error {
constructor(message, data) {
data.code = message
data.path = data.path || []
const { index, key, value, type } = data
switch (message) {
case 'element_invalid':
message = `Expected the element at index \`${index}\` to be of type "${type}", but it was \`${value}\`.`
break
case 'property_invalid':
case 'property_required':
message = `Expected the \`${key}\` property to be of type "${type}", but it was \`${value}\`.`
break
case 'property_unknown':
message = `Unexpected \`${key}\` property that was not defined in the struct.`
break
case 'value_invalid':
case 'value_required':
message = `Expected a value of type "${type}" but received \`${value}\`.`
break
default:
throw new Error(`Unknown struct error code: "${message}"`)
}
super(message)
this.name = 'StructError'
for (const k in data) {
this[k] = data[k]
}
Error.captureStackTrace(this, this.constructor)
}
}
/**
* Create a struct factory from a set of `options`.
*
* @param {Object} options
* @return {Function}
*/
function superstruct(options = {}) {
const TYPES = {
...DEFAULT_TYPES,
...(options.types || {}),
}
/**
* Define a scalar struct with a `schema` type string.
*
* @param {String} schema
* @param {Any} defaults
* @return {Function}
*/
function scalarStruct(schema, defaults) {
const isOptional = schema.endsWith('?')
const type = isOptional ? schema.slice(0, -1) : schema
const types = type.split(/\s*\|\s*/g)
const fns = types.map((t) => {
const fn = TYPES[t]
if (typeof fn !== 'function') {
throw new Error(`No struct validator function found for type "${t}".`)
}
return fn
})
return (value) => {
if (!isOptional && value === undefined) {
throw new StructError('value_required', { type })
}
if (value !== undefined && !fns.some(fn => fn(value))) {
throw new StructError('value_invalid', { type, value })
}
return value
}
}
/**
* Define a list struct with a `schema` array.
*
* @param {Array} schema
* @param {Any} defaults
* @return {Function}
*/
function listStruct(schema, defaults) {
if (schema.length !== 1) {
throw new Error(`List structs must be defined as an array with a single element, but you passed ${schema.length} elements.`)
}
schema = schema[0]
const fn = struct(schema)
const type = 'array'
return (value) => {
if (value === undefined) {
throw new StructError('value_required', { type })
} else if (typeOf(value) !== 'array') {
throw new StructError('value_invalid', { type, value })
}
const ret = value.map((v, index) => {
try {
return fn(v)
} catch (e) {
const path = [index].concat(e.path)
switch (e.code) {
case 'value_invalid':
throw new StructError('element_invalid', { ...e, index, path })
default:
if ('path' in e) e.path = path
throw e
}
}
})
return ret
}
}
/**
* Define an object struct with a `schema` dictionary.
*
* @param {Object} schema
* @param {Any} defaults
* @return {Function}
*/
function objectStruct(schema, defaults) {
const structs = {}
const type = 'object'
for (const key in schema) {
const fn = struct(schema[key])
structs[key] = fn
}
return (value) => {
let isUndefined = false
if (value === undefined) {
isUndefined = true
value = {}
} else if (typeOf(value) !== 'object') {
throw new StructError('value_invalid', { type, value })
}
const ret = {}
for (const key in structs) {
const s = structs[key]
const v = value[key]
let r
try {
r = s(v)
} catch (e) {
const path = [key].concat(e.path)
switch (e.code) {
case 'value_invalid':
throw new StructError('property_invalid', { ...e, key, path })
case 'value_required':
throw isUndefined
? new StructError('value_required', { type })
: new StructError('property_required', { ...e, key, path })
default:
if ('path' in e) e.path = path
throw e
}
}
if (key in value) {
ret[key] = r
}
}
for (const key in value) {
if (!(key in structs)) {
throw new StructError('property_unknown', { key, path: [key] })
}
}
return isUndefined ? undefined : ret
}
}
/**
* Define a struct with `schema`.
*
* @param {Function|String|Array|Object} schema
* @param {Any} defaults
* @return {Function}
*/
function struct(schema, defaults) {
let s
if (typeOf(schema) === 'function') {
s = schema
} else if (typeOf(schema) === 'string') {
s = scalarStruct(schema, defaults)
} else if (typeOf(schema) === 'array') {
s = listStruct(schema, defaults)
} else if (typeOf(schema) === 'object') {
s = objectStruct(schema, defaults)
} else {
throw new Error(`A struct schema definition must be a string, array or object, but you passed: ${schema}`)
}
return (value) => {
if (value === undefined) {
value = typeof defaults === 'function'
? defaults()
: cloneDeep(defaults)
}
return s(value)
}
}
/**
* Return the struct factory.
*/
return struct
}
/**
* Export the factory and the factory creator.
*
* @type {Function}
*/
const struct = superstruct()
export default struct
export { struct, superstruct, StructError }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc