A library for interacting with Refract elements.
$ npm install minim
In working with the XML-based DOM, there is a limitation on what types are available in the document. Element attributes may only be strings, and element values can only be strings, mixed types, and nested elements.
JSON provides additional types, which include objects, arrays, booleans, and nulls. A plain JSON document, though, provides no structure and no attributes for each property and value in the document.
Refract is a JSON structure for JSON documents to make a more flexible document object model. In Refract, each element has three components:
- Name of the element
- Metadata
- Attributes
- Content (which can be of different elements depending on the element)
An element ends up looking like this:
const element = {
element: 'string',
content: 'bar'
};
var minim = require('minim').namespace();
var arrayElement = minim.toElement([1, 2, 3]);
var refract = minim.toRefract(arrayElement);
The refract
variable above has the following JSON value.
{
"element": "array",
"content": [
{
"element": "number",
"content": 1
},
{
"element": "number",
"content": 2
},
{
"element": "number",
"content": 3
}
]
}
Serialized Refract can be converted back to Minim elements to make a roundtrip.
var arrayElement1 = minim.toElement([1, 2, 3]);
var refracted = minim.toRefract(arrayElement1);
var arrayElement2 = minim.fromRefract(refracted);
Note that due to optional refracting in meta
, anything that looks like an element in the given serialization will be loaded as such.
You can extend elements using the extend
static method.
var StringElement = minim.getElementClass('string');
var NewElement = StringElement.extend({
constructor: function() {
this.__super();
},
customMethod: function() {
// custom code here
}
})
Each Minim element provides the following attributes:
- element (string) - The name of the element
- meta (object) - The element's metadata
- attributes (object) - The element's attributes
- content - The element's content, e.g. a list of other elements.
Additionally, convenience attributes are exposed on the element:
- id (StringElement) - Shortcut for
.meta.get('id')
. - name (StringElement) - Shortcut for
.meta.get('name')
. - classes (ArrayElement) - Shortcut for
.meta.get('classes')
. - title (StringElement) - Shortcut for
.meta.get('title')
. - description (StringElement) - Shortcut for
.meta.get('description')
.
Each Minim element provides the following methods.
The toValue
method returns the JSON value of the Minim element.
var arrayElement = minim.toElement([1, 2, 3]);
var arrayValue = arrayElement.toValue(); // [1, 2, 3]
The toRef
method returns a RefElement referencing the element.
var ref = element.toRef();
toRef
accepts an optional path.
var ref = element.toRef('attributes');
Allows for testing equality with the content of the element.
var stringElement = minim.toElement("foobar");
stringElement.equals('abcd'); // returns false
Creates a clone of the given instance.
var stringElement = minim.toElement("foobar");
var stringElementClone = stringElement.clone();
Recursively find an element. Returns an ArrayElement containing all elements that match the given element name.
const strings = element.findRecursive('string');
You may pass multiple element names to findRecursive
. When multiple element
names are passed down, minim will only find an element that is found within
the other given elements. For example, we can pass in member
and string
so
that we are recursively looking for all string
elements that are found within a
member
element:
const stringInsideMembers = element.findRecursive('member', 'string');
The children
property returns an ArrayElement
containing all of the direct children elements.
var arrayElement = minim.toElement(['a', [1, 2], 'b', 3]);
var numbers = arrayElement.children(function(el) {
return el.element === 'number';
}).toValue(); // [3]
The recursiveChildren
property returns an ArrayElement
containing all of the children elements recursively.
var arrayElement = minim.toElement(['a', [1, 2], 'b', 3]);
var children = arrayElement.recursiveChildren;
children.toValue(); // ['a', 1, 2, 'b', 3]
var evenNumbers = array
.recursiveChildren
.findByElement('number')
.filter((element) => element.toValue() % 2)
Minim supports the following primitive elements
This is an element for representing the null
value.
This is an element for representing string values.
The set
method sets the value of the StringElement
instance.
var stringElement = minim.toElement('');
stringElement.set('foobar');
var value = stringElement.toValue() // toValue() returns 'foobar'
This is an element for representing number values.
The set
method sets the value of the NumberElement
instance.
var numberElement = minim.toElement(0);
numberElement.set(4);
var value = numberElement.toValue() // toValue() returns 4
This is an element for representing boolean values.
The set
method sets the value of the BooleanElement
instance.
var booleanElement = minim.toElement(false);
booleanElement.set(true);
var value = booleanElement.toValue() // toValue() returns true
This is an element for representing arrays.
The array element is iterable if the environment supports the iteration protocol. You can then use the element in for ... of
loops, use the spread operator, yield*
, and destructuring assignment.
const arrayElement = minim.toElement(['a', 'b', 'c']);
for (let item of arrayElement) {
console.log(item);
}
The get
method returns the item of the ArrayElement
instance at the given index.
var arrayElement = minim.toElement(['a', 'b', 'c']);
var value = arrayElement.get(0) // get(0) returns item for 'a'
The getValue
method returns the value of the item of the ArrayElement
instance at the given index.
var arrayElement = minim.toElement(['a', 'b', 'c']);
var value = arrayElement.getValue(0) // get(0) returns 'a'
The getIndex
method returns the item of the array at a given index.
var arrayElement = minim.toElement(['a', 'b', 'c']);
var value = arrayElement.getIndex(0) // returns the item for 'a'
The set
method sets the value of the ArrayElement
instance.
var arrayElement = minim.toElement([]);
arrayElement.set(0, 'z');
var value = arrayElement.get(0) // get(0) returns 'z'
The remove
method removes an item (specified by index) from the ArrayElement
instance.
var arrayElement = minim.toElement(['a', 'b', 'c']);
arrayElement.remove(0);
var value = arrayElement.get(0) // returns 'b'
The map
method may be used to map over an array. Each item given is a Minim instance.
var arrayElement =minim.toElement(['a', 'b', 'c']);
var newArray = arrayElement.map(function(item) {
return item.element;
}); // newArray is now ['string', 'string', 'string']
The filter
method may be used to filter a Minim array. This method returns a Minim array itself rather than a JavaScript array instance.
var arrayElement = minim.toElement(['a', 'b', 'c']);
var newArray = arrayElement.filter(function(item) {
return item.toValue() === 'a'
}); // newArray.toValue() is now ['a']
The reduce
method may be used to reduce over a Minim array or object. The method takes a function and an optional beginning value.
var numbers = minim.toElement([1, 2, 3, 4]);
var total = numbers.reduce(function(result, item) {
return result.toValue() + item.toValue();
}); // total.toValue() === 10
The reduce
method also takes an initial value, which can either be a value or Minim element.
var numbers = minim.toElement([1, 2, 3, 4]);
var total = numbers.reduce(function(result, item) {
return result.toValue() + item.toValue();
}, 10); // total.toValue() === 20
The reduce
method also works with objects:
var objNumbers = minim.toElement({a: 1, b:2, c:3, d:4});
var total = objNumbers.reduce(function(result, item) {
return result.toValue() + item.toValue();
}, 10); // total.toValue() === 20
The function passed to reduce
can accept up to five optional parameters and depends on whether you are using an array element or object element:
Array
result
: the reduced value thus faritem
: the current item in the arrayindex
: the zero-based index of the current item in the arrayarrayElement
: the array element which containsitem
(e.g.numbers
above)
Object
result
: the reduced value thus faritem
: the value element of the current item in the objectkey
: the key element of the current item in the objectmemberElement
: the member element which containskey
andvalue
objectElement
: the object element which containsmemberElement
(e.g.objNumbers
above)
The forEach
method may be used to iterate over a Minim array.
var arrayElement = minim.toElement(['a', 'b', 'c']);
arrayElement.forEach(function(item) {
console.log(item.toValue())
}); // logs each value to console
The shift
method may be used to remove an item from the start of a Minim array.
var arrayElement = minim.toElement(['a', 'b', 'c']);
var element = arrayElement.shift();
console.log(element.toValue()); // a
The unshift
method may be used to inserts items to the start of a Minim array.
var arrayElement = minim.toElement(['a', 'b', 'c']);
arrayElement.unshift('d');
console.log(arrayElement.toValue()); // ['d', 'a', 'b', 'c']
The push
method may be used to add items to a Minim array.
var arrayElement = minim.toElement(['a', 'b', 'c']);
arrayElement.push('d');
console.log(arrayElement.toValue()); // ['a', 'b', 'c', 'd']
The find
method traverses the entire descendent element tree and returns an ArrayElement
of all elements that match the conditional function given.
var arrayElement = minim.toElement(['a', [1, 2], 'b', 3]);
var numbers = arrayElement.find(function(el) {
return el.element === 'number'
}).toValue(); // [1, 2, 3]
The findByClass
method traverses the entire descendent element tree and returns an ArrayElement
of all elements that match the given class.
The findByElement
method traverses the entire descendent element tree and returns an ArrayElement
of all elements that match the given element name.
Search the entire tree to find a matching ID.
elTree.getById('some-id');
Test to see if a collection includes the value given. Does a deep equality check.
var arrayElement = minim.toElement(['a', [1, 2], 'b', 3]);
arrayElement.includes('a'); // returns true
Returns the amount of items in the array element.
arrayElement.length;
Returns whether the array element is empty.
if (arrayElement.isEmpty) {
console.log("We have an empty array");
}
Returns the first element in the collection.
var arrayElement = minim.toElement(['a', [1, 2], 'b', 3]);
arrayElement.first; // returns the element for "a"
Returns the second element in the collection.
var arrayElement = minim.toElement(['a', [1, 2], 'b', 3]);
arrayElement.second; // returns the element for "[1, 2]"
Returns the last element in the collection.
var arrayElement = minim.toElement(['a', [1, 2], 'b', 3]);
arrayElement.last; // returns the element for "3"
This is an element for representing objects. Objects store their items as an ordered array, so they inherit most of the methods above from the ArrayElement
.
The get
method returns the ObjectElement
instance at the given name.
See getKey
and getMember
for ways to get more instances around a key-value pair.
var objectElement = minim.toElement({ foo: 'bar' });
var value = objectElement.get('foo') // returns string instance for 'bar'
The getValue
method returns the value of the ObjectElement
instance at the given name.
var objectElement = minim.toElement({ foo: 'bar' });
var value = objectElement.getValue('foo') // returns 'bar'
The getKey
method returns the key element of a key-value pair.
var objectElement = minim.toElement({ foo: 'bar' });
var key = objectElement.getKey('foo') // returns the key element instance
The getMember
method returns the entire member for a key-value pair.
var objectElement = minim.toElement({ foo: 'bar' });
var member = objectElement.getMember('foo') // returns the member element
var key = member.key; // returns what getKey('foo') returns
var value = member.value; // returns what get('foo') returns
The set
method sets the value of the ObjectElement
instance.
var objectElement = minim.toElement({});
objectElement.set('foo', 'hello world');
var value = objectElement.get('foo') // get('foo') returns 'hello world'
The keys
method returns an array of keys.
var objectElement = minim.toElement({ foo: 'bar' });
var keys = objectElement.keys() // ['foo']
The remove
method removes a key from the ObjectElement
instance.
var objectElement = minim.toElement({ foo: 'bar' });
objectElement.remove('foo');
var keys = objectElement.keys() // []
You can use elementa.meta.remove() or element.attributes.remove() because of this.
The values
method returns an array of keys.
var objectElement = minim.toElement({ foo: 'bar' });
var values = objectElement.values() // ['bar']
The items
method returns an array of key value pairs which can make iteration simpler.
const objectElement = minim.toElement({ foo: 'bar' });
for (let [key, value] of objectElement.items()) {
console.log(key, value); // foo, bar
}
The map
, filter
, and forEach
methods work similar to the ArrayElement
map function, but the callback receives the value, key, and member element instances. The reduce
method receives the reduced value, value, key, member, and object element instances.
See getMember
to see more on how to interact with member elements.
const objectElement = minim.toElement({ foo: 'bar' });
const values = objectElement.map((value, key, member) => {
// key is an instance for foo
// value is an instance for bar
// member is an instance for the member element
return [key.toValue(), value.toValue()]; // ['foo', 'bar']
});
The toRefract
method returns the Refract value of the Minim element.
Note that if any element in meta
has metadata or attributes defined that would be lost by calling toValue()
then that element is also converted to refract.
var arrayElement = namespace.toElement([1, 2, 3]);
var refract = namespace.toRefract();
Minim allows you to register custom elements. For example, if the element name you wish to handle is called category
and it should be handled like an array:
var minim = require('minim').namespace();
var ArrayElement = minim.getElementClass('array');
// Register your custom element
minim.register('category', ArrayElement);
// Load serialized refract elements that includes the new element
var elements = minim.fromRefract({
element: 'category',
meta: {},
attributes: {},
content: [
{
element: 'string',
meta: {},
attributes: {},
content: 'hello, world'
}
]
});
console.log(elements.get(0).content); // hello, world
// Unregister your custom element
minim.unregister('category');
It is also possible to create plugin modules that define elements for custom namespaces. Plugin modules should export a single namespace
function that takes an options
object which contains an existing namespace to which you can add your elements:
var minim = require('minim').namespace();
// Define your plugin module (normally done in a separate file)
var plugin = {
namespace: function(options) {
var base = options.base;
var ArrayElement = base.getElementClass('array');
base.register('category', ArrayElement);
return base;
}
}
// Load the plugin
minim.use(plugin);
The load
property may be used in addition to the namespace
property when a plugin is not implementing a namespace.
var minim = require('minim').namespace();
// Define your plugin module (normally done in a separate file)
var plugin = {
load: function(options) {
// Plugin code here
return base;
}
}
// Load the plugin
minim.use(plugin);
Methods may also be chained when using getters and setters.
var objectElement = minim.toElement({})
.set('name', 'John Doe')
.set('email', 'john@example.com')
.set('id', 4)