npm package: @iekedemus/shape
Description: A small JavaScript utility for enforcing object shapes
Author: Joel Luukka
Latest version: 4.0.0
Deprecated: This package has been abandoned

# Shape

A simple JavaScript utility for enforcing object shapes.

Shape provides an object construction method and keys that can be used to
reference and rename properties when working with objects. Shape produces
console warnings by default when referencing properties not defined for
the shape, but the behavior can be modified to, for example, throw errors
instead.

Shape does not enforce data types. Only property names.

-------

## Installation

```
npm install @iekedemus/shape
```

-------

## Basic usage

Import (or require) Shape:
```
import { Shape } from '@iekedemus/shape';

or

const { Shape } = require('@iekedemus/shape');
```

Create MyShape object:
```
const myShapePropNames = ["position", "value"];
const MyShape = Shape(myShapePropNames);
```

Use MyShape as an object creation method:
```
const pos = 1;
const val = 5.5;

// provide prop values to constructor in same order as in myShapePropNames array
const myObject = MyShape(pos, val);
```

Use MyShape properties to reference object properties:
```
myObjects.forEach(myObject => {
  const {
    [MyShape.position]: position,
    [MyShape.value]: value,
  } = myObject;

  console.log(`Data point at ${position} has value ${value}`);
});
```

Mistyped properties on MyShape produce a warning message (or other user
defined behavior):
```
const {
  [MyShape.postiion]: position,  // Referencing non-shape property on MyShape
} = myObject;
```

Property names are enforced only through Shape objects, as Shape objects' creation
methods produce normal JS objects:
```
const {
  postiion,  // No warning message will be printed
} = myObject;
```

-------

## Why it works

Mistyping object property names can result in `undefined` or other erroneous
values being extracted from objects. In JavaScript, no errors are thrown or
other hints provided for the programmer:
```
const myObject = { position: 1 };

const { postiion } = myObject;
const pos = myObject.postiion;

console.log(pos, postiion);  // undefined, undefined

```

The same is true for writing to object properties:
```
myObject.postiion = 2;
```

Shapes provide a constructor method for creating uniform JS objects with
correct property names, eliminating one source of typo related errors:
```
const MyShape = Shape(shapeProps);
const myObject = MyShape(...);
```

Reading object properties or writing to them using Shapes provides console warnings (or other
behaviour) on mistyped property names:
```
const { [MyShape.postiion]: pos } = myObject;  // Prints a console warning
myObject[MyShape.positin] = pos + 1;  // Prints a console warning
```

If a renamed property is mistyped later, an error is likely to be thrown (unless
the mistyped name matches something else):
```
const { [MyShape.position]: pos } = myObject;
const nextPos = poss + 1;  // Uncaught ReferenceError: poss is not defined
```

-------

## You don't need `@iekedemus/shape`

This is a tiny utility package offering a method for defining object
constructors and property name validation. It employs a Proxy for wrapping
everything together, but the most important aspects boil down to clever usage
of functions as constructors and object property referencing through constants:
```
const POSITION = 'position';
const VALUE = 'value';

const MyShape = function(pos, val) {
  this[POSITION] = pos;
  this[VALUE] = val;
}

const myObjects = [
  MyShape(1, 5.5),
  MyShape(2, 7.5)
];

myObjects.forEach(myObject => {
  const {
    [POSITION]: position,
    [VALUE]: value,
  } = myObject;

  console.log(`Data point at ${position} has value ${value}`);
});
```

So you don't really need `@iekedemus/shape`, but in case you want to use it, you
know where to find it.

-------


## API
### Import Shape and utilities
```
import {
  Shape,
  getShapeDefinition,
  reconfigure,
  validate,
} from '@iekedemus/shape';

or

const {
  Shape,
  getShapeDefinition,
  reconfigure,
  validate,
} = require('@iekedemus/shape');
```

### Shape
#### Creator
##### Shape(shapeProperties[, options])
Creates a new Shape object.
* shapeProperties {string[]} - An array of property names recognized by this
  Shape.
* options {object} - An object for altering Shape behaviour.
  * handlePropNotInShape {function} (prop) => undefined - A function for
    handling access on non-recognized properties.
* returns - A new MyShape object.

### MyShape
An object returned by `new Shape(...)`.

#### Methods
##### MyShape(...args)
A creation method for objects defined by this Shape.
* ...args {any} - Property values in the same order as in the `shapeProperties`
  array provided for `new Shape(...)`.
* returns - A new object with property entries defined by the shape and `...args` values.

#### Properties
##### MyShape[prop]
Property name getter.
* Always returns the value of `prop`.
* In case MyShape does not recognize the value of `prop`,
  `options.handlePropNotInShape` is called.

### Helper functions
##### getShapeDefinition(myShape)
Returns the arguments based on which myShape was created.
* myShape {Shape} - A shape.
* returns - `{ shape, options }`.

##### reconfigure(myShape[, options])
Creates a new Shape with same properties but different options than in myShape.
* myShape {Shape} - A shape based on which a new shape is created.
* options {object} - Options for the new shape.
* returns - A new shape.

##### validate(myShape, source[, handler])
Finds the differences and similarities between a shape and a source object.
* myShape {Shape} - A shape that defines a set of properties.
* source {object} - An object being validated against myShape.
* handler {function} - A function for defining custom behavior to the validator.
If defined, the handler function is called with the result object of the validation.
* returns - The return value of the handler function or an object with lists of
property names:
  * shape - a list of property names found only on myShape.
  * common - a list of property names found in both myShape and source.
  * source - a lsit of property names found only in the source object.
-------

## License

MIT