If you find this useful, please consider supporting my work with a [donation](https://humanwhocodes.com/donate).
## Overview
A JavaScript object merge/validation utility where you can define a different merge and validation strategy for each key. This is helpful when you need to validate complex data structures and then merge them in a way that is more complex than `Object.assign()`.
## Installation
You can install using either npm:
```
npm install @humanwhocodes/object-schema
```
Or Yarn:
```
yarn add @humanwhocodes/object-schema
```
## Usage
Use CommonJS to get access to the `ObjectSchema` constructor:
thrownewError("Expected downloads to be a number.");
}
}
},
// define a strategy for the "versions" key
version:{
required:true,
merge(value1,value2){
returnvalue1.concat(value2);
},
validate(value){
if(!Array.isArray(value)){
thrownewError("Expected versions to be an array.");
}
}
}
});
constrecord1={
downloads:25,
versions:[
"v1.0.0",
"v1.1.0",
"v1.2.0"
]
};
constrecord2={
downloads:125,
versions:[
"v2.0.0",
"v2.1.0",
"v3.0.0"
]
};
// make sure the records are valid
schema.validate(record1);
schema.validate(record2);
// merge together (schema.merge() accepts any number of objects)
constresult=schema.merge(record1,record2);
// result looks like this:
constresult={
downloads:75,
versions:[
"v1.0.0",
"v1.1.0",
"v1.2.0",
"v2.0.0",
"v2.1.0",
"v3.0.0"
]
};
```
## Tips and Tricks
### Named merge strategies
Instead of specifying a `merge()` method, you can specify one of the following strings to use a default merge strategy:
*`"assign"` - use `Object.assign()` to merge the two values into one object.
*`"overwrite"` - the second value always replaces the first.
*`"replace"` - the second value replaces the first if the second is not `undefined`.
For example:
```js
constschema=newObjectSchema({
name:{
merge:"replace",
validate(){}
}
});
```
### Named validation strategies
Instead of specifying a `validate()` method, you can specify one of the following strings to use a default validation strategy:
*`"array"` - value must be an array.
*`"boolean"` - value must be a boolean.
*`"number"` - value must be a number.
*`"object"` - value must be an object.
*`"object?"` - value must be an object or null.
*`"string"` - value must be a string.
*`"string!"` - value must be a non-empty string.
For example:
```js
constschema=newObjectSchema({
name:{
merge:"replace",
validate:"string"
}
});
```
### Subschemas
If you are defining a key that is, itself, an object, you can simplify the process by using a subschema. Instead of defining `merge()` and `validate()`, assign a `schema` key that contains a schema definition, like this:
```js
constschema=newObjectSchema({
name:{
schema:{
first:{
merge:"replace",
validate:"string"
},
last:{
merge:"replace",
validate:"string"
}
}
}
});
schema.validate({
name:{
first:"n",
last:"z"
}
});
```
### Remove Keys During Merge
If the merge strategy for a key returns `undefined`, then the key will not appear in the final object. For example:
```js
constschema=newObjectSchema({
date:{
merge(){
returnundefined;
},
validate(value){
Date.parse(value);// throws an error when invalid
}
}
});
constobject1={date:"5/5/2005"};
constobject2={date:"6/6/2006"};
constresult=schema.merge(object1,object2);
console.log("date"inresult);// false
```
### Requiring Another Key Be Present
If you'd like the presence of one key to require the presence of another key, you can use the `requires` property to specify an array of other properties that any key requires. For example:
```js
constschema=newObjectSchema();
constschema=newObjectSchema({
date:{
merge(){
returnundefined;
},
validate(value){
Date.parse(value);// throws an error when invalid
}
},
time:{
requires:["date"],
merge(first,second){
returnsecond;
},
validate(value){
// ...
}
}
});
// throws error: Key "time" requires keys "date"
schema.validate({
time:"13:45"
});
```
In this example, even though `date` is an optional key, it is required to be present whenever `time` is present.
This is plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript.
It was created as an experimental alternative, faster [React.js JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) parser. Later, it replaced the [official parser](https://github.com/facebookarchive/esprima) and these days is used by many prominent development tools.
## Transpiler
Please note that this tool only parses source code to JSX AST, which is useful for various language tools and services. If you want to transpile your code to regular ES5-compliant JavaScript with source map, check out [Babel](https://babeljs.io/) and [Buble](https://buble.surge.sh/) transpilers which use `acorn-jsx` under the hood.
## Usage
Requiring this module provides you with an Acorn plugin that you can use like this:
Note that official spec doesn't support mix of XML namespaces and object-style access in tag names (#27) like in `<namespace:Object.Property />`, so it was deprecated in `acorn-jsx@3.0`. If you still want to opt-in to support of such constructions, you can pass the following option: