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

datom

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

datom - npm Package Compare versions

Comparing version 0.0.2 to 1.0.0

162

lib/main.js

@@ -1,5 +0,5 @@

// Generated by CoffeeScript 2.4.1
(function() {
'use strict';
var CND, FONTMIRROR, Fontmirror, LFT, LFT_nofreeze, MAIN, Multimix, assign, badge, copy, debug, echo, help, info, isa, jr, rpr, selector_pattern, type_of, types, urge, validate, warn, whisper;
var CND, Datom, LFT, LFT_nofreeze, MAIN, Multimix, assign, badge, copy, debug, defaults, echo, help, info, isa, jr, p1, p2, rpr, type_of, types, urge, validate, warn, whisper,
indexOf = [].indexOf;

@@ -34,3 +34,3 @@ //###########################################################################################################

({isa, validate, type_of} = types);
({isa, validate, defaults, type_of} = types);

@@ -43,18 +43,8 @@ LFT = require('letsfreezethat');

this._nofreeze = false;
//-----------------------------------------------------------------------------------------------------------
this.create_nofreeze = function() {
var R;
R = new this.Pipedreams();
R._nofreeze = true;
return R;
};
//-----------------------------------------------------------------------------------------------------------
this.freeze = function(d) {
if (this._nofreeze) {
if (this.settings.freeze) {
return LFT.freeze(d);
} else {
return LFT_nofreeze.freeze(d);
} else {
return LFT.freeze(d);
}

@@ -64,6 +54,6 @@ };

this.thaw = function(d) {
if (this._nofreeze) {
if (this.settings.freeze) {
return LFT.thaw(d);
} else {
return LFT_nofreeze.thaw(d);
} else {
return LFT.thaw(d);
}

@@ -75,3 +65,3 @@ };

var draft;
if (this._nofreeze) {
if (!this.settings.freeze) {
draft = this._copy(original);

@@ -151,3 +141,3 @@ if (modifier != null) {

/* Return whether datom is a system datom (i.e. whether its `sigil` equals `'~'`). */
return d.key.match(/^[~\[\]]/);
return d.$key.match(/^[~\[\]]/);
};

@@ -172,3 +162,3 @@

//-----------------------------------------------------------------------------------------------------------
this.new_datom = function(key, value, ...other) {
this.new_datom = function($key, $value, ...other) {
var R;

@@ -181,10 +171,11 @@ /* TAINT should validate key */

datom. */
validate.datom_key(key);
if (value != null) {
if (!isa.object(value)) {
value = {value};
validate.datom_key($key);
validate.datom_value($value);
if ($value != null) {
if ((!this.settings.merge_values) || (!isa.object($value))) {
$value = {$value};
}
R = assign({key}, value, ...other);
R = assign({$key}, $value, ...other);
} else {
R = assign({key}, ...other);
R = assign({$key}, ...other);
}

@@ -198,20 +189,20 @@ while ((isa.object(R.$)) && (isa.object(R.$.$))) {

//-----------------------------------------------------------------------------------------------------------
this.new_single_datom = function(key, value, ...other) {
return this.new_datom(`^${key}`, value, ...other);
this.new_single_datom = function($key, $value, ...other) {
return this.new_datom(`^${$key}`, $value, ...other);
};
this.new_open_datom = function(key, value, ...other) {
return this.new_datom(`<${key}`, value, ...other);
this.new_open_datom = function($key, $value, ...other) {
return this.new_datom(`<${$key}`, $value, ...other);
};
this.new_close_datom = function(key, value, ...other) {
return this.new_datom(`>${key}`, value, ...other);
this.new_close_datom = function($key, $value, ...other) {
return this.new_datom(`>${$key}`, $value, ...other);
};
this.new_system_datom = function(key, value, ...other) {
return this.new_datom(`~${key}`, value, ...other);
this.new_system_datom = function($key, $value, ...other) {
return this.new_datom(`~${$key}`, $value, ...other);
};
this.new_text_datom = function(value, ...other) {
return this.new_single_datom('text', value, ...other);
this.new_text_datom = function($value, ...other) {
return this.new_single_datom('text', $value, ...other);
};

@@ -233,31 +224,57 @@

//-----------------------------------------------------------------------------------------------------------
selector_pattern = /^[<^>\[~\]][^<^>\[~\]]*$/;
p1 = /^(?<skey>(?<sigil>[<^>\[~\]\x23])(?<key>[^<^>\[~\]\x23]*))$/u; // `\x23` used instead of `\#` which causes syntax error (???)
p2 = /^(?<skey>(?<sigil>[<^>\[~\]\x23])(?<key>[^<^>\[~\]\x23]*))\x23(?<attribute>[^<^>\[~\]\x23]+):(?<value>[^<^>\[~\]\x23]+)$/u; // `\x23` used instead of `\#` which causes syntax error (???)
//-----------------------------------------------------------------------------------------------------------
this.select = function(d, selector) {
var ref1, stamped;
var g, k, match, ref1, ref2, ref3, ref4, stamped_values, v;
if (selector == null) {
throw new Error("µ86606 expected a selector, got none");
}
if (!((isa.object(d)) && (d.key != null))) {
if (!((isa.object(d)) && (d.$key != null))) {
return false;
}
//.........................................................................................................
stamped = false;
if (selector.endsWith('#stamped')) {
stamped = true;
selector = selector.slice(0, selector.length - 8);
if (selector === '') {
throw new Error("µ33982 selector cannot just contain tag '#stamped'");
if ((match = (ref1 = selector.match(p2)) != null ? ref1 : selector.match(p1)) == null) {
throw new Error(`µ37799 illegal selector ${rpr(selector)}`);
}
g = {};
ref2 = match.groups;
for (k in ref2) {
v = ref2[k];
if (v !== '') {
g[k] = v;
}
}
if (!selector_pattern.test(selector)) {
//.........................................................................................................
throw new Error(`µ37783 illegal selector ${rpr(selector)}`);
if ((g.attribute != null) && (g.attribute !== 'stamped')) {
throw new Error(`µ77764 unknown attribute name ${rpr(g.attribute)}`);
}
if ((!stamped) && ((ref1 = d.$stamped) != null ? ref1 : false)) {
switch (g.value) {
case void 0:
stamped_values = [false];
break;
case '*':
stamped_values = [true, false];
break;
case 'true':
stamped_values = [true];
break;
case 'false':
stamped_values = [false];
break;
default:
throw new Error(`µ33366 illegal attribute or value in selector ${rpr(selector)}`);
}
if (ref3 = (ref4 = d.$stamped) != null ? ref4 : false, indexOf.call(stamped_values, ref3) < 0) {
//.........................................................................................................
return false;
}
return d.key === selector;
if (g.key != null) {
return d.$key === g.skey;
}
if (!d.$key.startsWith(g.sigil)) {
return false;
}
return true;
};

@@ -270,31 +287,30 @@

Fontmirror = (function() {
class Fontmirror extends Multimix {};
Datom = (function() {
class Datom extends Multimix {
// @include ( require './outliner.mixin' ), { overwrite: false, }
// @include ( require './cachewalker.mixin' ), { overwrite: false, }
// @include ( require './_temp_svgttf' ), { overwrite: false, } ### !!!!!!!!!!!!!!!!!!!!!!!!!!! ###
// @extend MAIN, { overwrite: false, }
Fontmirror.include(MAIN, {
//---------------------------------------------------------------------------------------------------------
constructor(settings = null) {
super();
validate.datom_settings(settings = {...defaults.settings, ...settings});
this.settings = LFT.freeze(settings);
this.Datom = Datom;
return this;
}
};
Datom.include(MAIN, {
overwrite: false
});
return Fontmirror;
return Datom;
}).call(this);
// @include ( require './outliner.mixin' ), { overwrite: false, }
// @include ( require './cachewalker.mixin' ), { overwrite: false, }
// @include ( require './_temp_svgttf' ), { overwrite: false, } ### !!!!!!!!!!!!!!!!!!!!!!!!!!! ###
// @extend MAIN, { overwrite: false, }
module.exports = new Datom();
// #---------------------------------------------------------------------------------------------------------
// constructor: ( target = null ) ->
// super()
// @CLI = require './cli'
// @CFG = require './cfg'
// @TAGS = require './tags'
// @NICKS = require './texfontnamesake'
// @LINKS = require './links'
// @export target if target?
module.exports = FONTMIRROR = new Fontmirror();
}).call(this);
//# sourceMappingURL=main.js.map

@@ -1,5 +0,4 @@

// Generated by CoffeeScript 2.4.1
(function() {
'use strict';
var CND, DATOM, badge, debug, echo, help, info, isa, jr, rpr, test, type_of, types, urge, validate, warn, whisper;
var CND, badge, debug, echo, help, info, isa, jr, rpr, test, type_of, types, urge, validate, warn, whisper;

@@ -37,5 +36,2 @@ //###########################################################################################################

//...........................................................................................................
DATOM = require('../..');
// #-----------------------------------------------------------------------------------------------------------

@@ -117,3 +113,6 @@ // @[ "selector keypatterns" ] = ( T, done ) ->

this["select 2"] = async function(T, done) {
var error, i, len, matcher, probe, probes_and_matchers;
var DATOM, error, i, len, matcher, new_datom, probe, probes_and_matchers, select;
DATOM = require('../..');
({new_datom, select} = DATOM.export());
//.........................................................................................................
probes_and_matchers = [

@@ -123,9 +122,9 @@ [

{
key: '^number',
value: 42,
$key: '^number',
$value: 42,
$stamped: true
},
'^number'
'^number#stamped:*'
],
false
true
],

@@ -135,8 +134,8 @@ [

{
key: '<italic',
$key: '<italic',
$stamped: true
},
'<italic'
'<italic#stamped:*'
],
false
true
],

@@ -146,8 +145,8 @@ [

{
key: '<italic',
$key: '<italic',
$stamped: true
},
'>italic'
'<italic#stamped:*'
],
false
true
],

@@ -157,6 +156,5 @@ [

{
key: '^number',
value: 42
$key: '<italic'
},
'^number'
'<italic#stamped:*'
],

@@ -168,9 +166,8 @@ true

{
key: '^number',
value: 42,
$key: '<italic',
$stamped: true
},
'^number#stamped'
'>italic#stamped:*'
],
true
false
],

@@ -180,8 +177,7 @@ [

{
key: '<italic',
$stamped: true
$key: '<italic'
},
'<italic#stamped'
'>italic#stamped:*'
],
true
false
],

@@ -191,6 +187,7 @@ [

{
key: '<italic',
$key: '^number',
$value: 42,
$stamped: true
},
'>italic#stamped'
'^number'
],

@@ -202,8 +199,8 @@ false

{
key: '<italic',
$key: '<italic',
$stamped: true
},
'<italic#stamped'
'<italic'
],
true
false
],

@@ -213,7 +210,8 @@ [

{
key: '<italic'
$key: '<italic',
$stamped: true
},
'<italic#stamped'
'>italic'
],
true
false
],

@@ -223,7 +221,8 @@ [

{
key: '<italic'
$key: '^number',
$value: 42
},
'>italic#stamped'
'^number'
],
false
true
],

@@ -233,3 +232,3 @@ [

{
key: '<italic',
$key: '<italic',
$stamped: true

@@ -244,3 +243,3 @@ },

{
key: "*data"
$key: "*data"
},

@@ -255,3 +254,3 @@ '*data'

{
key: "data>"
$key: "data>"
},

@@ -266,3 +265,3 @@ 'data>'

{
key: "%data"
$key: "%data"
},

@@ -277,3 +276,3 @@ '%data'

{
key: "[data"
$key: "[data"
},

@@ -288,3 +287,3 @@ '[data'

{
key: "data]"
$key: "data]"
},

@@ -299,3 +298,3 @@ 'data]'

{
key: "]data"
$key: "]data"
},

@@ -314,3 +313,3 @@ ']data'

[d, selector] = probe;
return DATOM.select(d, selector);
return select(d, selector);
});

@@ -324,3 +323,6 @@ }

this["select ignores values other than PODs"] = async function(T, done) {
var error, i, len, matcher, probe, probes_and_matchers;
var DATOM, error, i, len, matcher, new_datom, probe, probes_and_matchers, select;
DATOM = require('../..');
({new_datom, select} = DATOM.export());
//.........................................................................................................
probes_and_matchers = [[[null, '^number'], false], [[123, '^number'], false]];

@@ -335,3 +337,3 @@ //.........................................................................................................

try {
resolve(DATOM.select(d, selector));
resolve(select(d, selector));
} catch (error1) {

@@ -350,2 +352,407 @@ error = error1;

//-----------------------------------------------------------------------------------------------------------
this["new_datom complains when value has `$key`"] = async function(T, done) {
var DATOM, error, i, len, matcher, new_datom, probe, probes_and_matchers, select;
DATOM = require('../..');
({new_datom, select} = DATOM.export());
//.........................................................................................................
probes_and_matchers = [
[
[
"^number",
{
"$value": 123
}
],
{
"$key": "^number",
"$value": 123
},
null
],
[
[
"^number",
{
"$value": 123,
"$key": "something"
}
],
null,
"not a valid datom_value"
]
];
//.........................................................................................................
for (i = 0, len = probes_and_matchers.length; i < len; i++) {
[probe, matcher, error] = probes_and_matchers[i];
await T.perform(probe, matcher, error, function() {
return new Promise(function(resolve, reject) {
var key, value;
[key, value] = probe;
return resolve(new_datom(key, value));
});
});
}
done();
return null;
};
//-----------------------------------------------------------------------------------------------------------
this["new_datom (default settings)"] = async function(T, done) {
var DATOM, error, i, len, matcher, new_datom, probe, probes_and_matchers, select;
DATOM = require('../..');
({new_datom, select} = DATOM.export());
//.........................................................................................................
probes_and_matchers = [
[
["^number",
null],
{
"$key": "^number"
},
null
],
[
["^number",
123],
{
"$key": "^number",
"$value": 123
},
null
],
[
[
"^number",
{
"$value": 123
}
],
{
"$key": "^number",
"$value": 123
},
null
],
[
[
"^number",
{
"value": 123
}
],
{
"$key": "^number",
"value": 123
},
null
],
[
[
"^number",
{
"$value": {
"$value": 123
}
}
],
{
"$key": "^number",
"$value": {
"$value": 123
}
},
null
],
[
[
"^number",
{
"value": {
"$value": 123
}
}
],
{
"$key": "^number",
"value": {
"$value": 123
}
},
null
],
[
[
"^number",
{
"$value": {
"value": 123
}
}
],
{
"$key": "^number",
"$value": {
"value": 123
}
},
null
],
[
[
"^number",
{
"value": {
"value": 123
}
}
],
{
"$key": "^number",
"value": {
"value": 123
}
},
null
],
[
["^value",
123],
{
"$key": "^value",
"$value": 123
},
null
],
[
["<start",
123],
{
"$key": "<start",
"$value": 123
},
null
],
[
[">stop",
123],
{
"$key": ">stop",
"$value": 123
},
null
]
];
//.........................................................................................................
for (i = 0, len = probes_and_matchers.length; i < len; i++) {
[probe, matcher, error] = probes_and_matchers[i];
await T.perform(probe, matcher, error, function() {
return new Promise(function(resolve, reject) {
var key, value;
[key, value] = probe;
return resolve(new_datom(key, value));
});
});
}
done();
return null;
};
//-----------------------------------------------------------------------------------------------------------
this["new_datom (without value merging)"] = async function(T, done) {
var DATOM, error, i, len, matcher, new_datom, probe, probes_and_matchers, select;
DATOM = new (require('../..')).Datom({
merge_values: false
});
({new_datom, select} = DATOM.export());
//.........................................................................................................
probes_and_matchers = [
[
["^number",
null],
{
"$key": "^number"
},
null
],
[
["^number",
123],
{
"$key": "^number",
"$value": 123
},
null
],
[
[
"^number",
{
"$value": 123
}
],
{
"$key": "^number",
"$value": {
"$value": 123
}
},
null
],
[
[
"^number",
{
"value": 123
}
],
{
"$key": "^number",
"$value": {
"value": 123
}
},
null
],
[
[
"^number",
{
"$value": {
"$value": 123
}
}
],
{
"$key": "^number",
"$value": {
"$value": {
"$value": 123
}
}
},
null
],
[
[
"^number",
{
"value": {
"$value": 123
}
}
],
{
"$key": "^number",
"$value": {
"value": {
"$value": 123
}
}
},
null
],
[
[
"^number",
{
"$value": {
"value": 123
}
}
],
{
"$key": "^number",
"$value": {
"$value": {
"value": 123
}
}
},
null
],
[
[
"^number",
{
"value": {
"value": 123
}
}
],
{
"$key": "^number",
"$value": {
"value": {
"value": 123
}
}
},
null
],
[
["^value",
123],
{
"$key": "^value",
"$value": 123
},
null
],
[
["<start",
123],
{
"$key": "<start",
"$value": 123
},
null
],
[
[">stop",
123],
{
"$key": ">stop",
"$value": 123
},
null
]
];
//.........................................................................................................
for (i = 0, len = probes_and_matchers.length; i < len; i++) {
[probe, matcher, error] = probes_and_matchers[i];
await T.perform(probe, matcher, error, function() {
return new Promise(function(resolve, reject) {
var key, value;
[key, value] = probe;
return resolve(new_datom(key, value));
});
});
}
done();
return null;
};
//-----------------------------------------------------------------------------------------------------------
this["freezing"] = function(T, done) {
var DATOM_FREEZE, DATOM_NOFREEZE, new_datom_freeze, new_datom_nofreeze;
DATOM_FREEZE = new (require('../..')).Datom({
freeze: true
});
({
new_datom: new_datom_freeze
} = DATOM_FREEZE.export());
DATOM_NOFREEZE = new (require('../..')).Datom({
freeze: false
});
({
new_datom: new_datom_nofreeze
} = DATOM_NOFREEZE.export());
//.........................................................................................................
T.ok(Object.isFrozen(new_datom_freeze('^mykey')));
T.ok(!Object.isFrozen(new_datom_nofreeze('^mykey')));
done();
return null;
};
//-----------------------------------------------------------------------------------------------------------
this["_regex performance, runaway test"] = function(T, done) {};

@@ -358,11 +765,14 @@

//###########################################################################################################
if (module.parent == null) {
test(this);
if (require.main === module) {
(() => {
return test(this);
})();
}
// test @[ "selector keypatterns" ]
// test @[ "new_datom complains when value has `$key`" ]
// test @[ "selector keypatterns" ]
// test @[ "select 2" ]
// test @[ "new_datom (default settings)" ]
// debug new_datom '^helo', 42
}).call(this);
//# sourceMappingURL=select.test.js.map

@@ -1,2 +0,1 @@

// Generated by CoffeeScript 2.4.1
(function() {

@@ -35,2 +34,17 @@ 'use strict';

//-----------------------------------------------------------------------------------------------------------
this.declare('datom_settings', {
tests: {
"x is a object": function(x) {
return this.isa.object(x);
},
"x.merge_values is a ?boolean": function(x) {
return (x.merge_values == null) || this.isa.boolean(x.merge_values);
},
"x.freeze is a ?boolean": function(x) {
return (x.freeze == null) || this.isa.boolean(x.freeze);
}
}
});
//-----------------------------------------------------------------------------------------------------------
this.declare('datom_nonempty_list_of_positive_integers', function(x) {

@@ -64,3 +78,3 @@ if (!this.isa.nonempty_list(x)) {

"x has sigil": function(x) {
return this.isa.pd_datom_sigil(x[0]);
return this.isa.datom_sigil(x[0]);
}

@@ -79,4 +93,4 @@ }

},
"x.key is a pd_datom_key": function(x) {
return this.isa.pd_datom_key(x.key);
"x.key is a datom_key": function(x) {
return this.isa.datom_key(x.key);
},

@@ -94,3 +108,3 @@ "x.$stamped is an optional boolean": function(x) {

"x.$vnr is an optional nonempty list of positive integers": function(x) {
return (x.$vnr == null) || this.isa.pd_nonempty_list_of_positive_integers(x.$vnr);
return (x.$vnr == null) || this.isa.datom_nonempty_list_of_positive_integers(x.$vnr);
}

@@ -100,17 +114,18 @@ }

// "?..$vnr is a ?positive": ( x ) -> ( not x.$vnr? ) or @isa.positive x.$vnr
// "? has key 'vlnr_txt'": ( x ) -> @has_key x, 'vlnr_txt'
// "? has key 'value'": ( x ) -> @has_key x, 'value'
// "?.vlnr_txt is a nonempty text": ( x ) -> @isa.nonempty_text x.vlnr_txt
// "?.vlnr_txt starts, ends with '[]'": ( x ) -> ( x.vlnr_txt.match /^\[.*\]$/ )?
// "?.vlnr_txt is a JSON array of integers": ( x ) ->
// # debug 'µ55589', x
// ( @isa.list ( lst = JSON.parse x.vlnr_txt ) ) and \
// ( lst.every ( xx ) => ( @isa.integer xx ) and ( @isa.positive xx ) )
//-----------------------------------------------------------------------------------------------------------
this.declare('datom_value', function(x) {
if (!this.isa.object(x)) {
return true;
}
return x.$key === void 0;
});
// #-----------------------------------------------------------------------------------------------------------
// @declare 'true', ( x ) -> x is true
//-----------------------------------------------------------------------------------------------------------
this.defaults = {
settings: {
merge_values: true,
freeze: true
}
};
}).call(this);
//# sourceMappingURL=types.js.map
{
"name": "datom",
"version": "0.0.2",
"version": "1.0.0",
"description": "standardized immutable objects in the spirit of datomic, especially suited for use in data pipelines",

@@ -5,0 +5,0 @@ "main": "lib/main.js",

# Datom &#x269b;
# Datom
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Export Bound Methods](#export-bound-methods)
- [Creation of Bespoke Library Instances](#creation-of-bespoke-library-instances)
- [Configuration Parameters](#configuration-parameters)
- [Methods](#methods)
- [Freezing & Thawing](#freezing--thawing)
- [Stamping](#stamping)
- [Type Testing](#type-testing)
- [Value Creation](#value-creation)
- [Selecting](#selecting)
- [System Properties](#system-properties)
- [WIP](#wip)
- [PipeDreams Datoms (Data Events)](#pipedreams-datoms-data-events)
- [`select = ( d, selector ) ->`](#select---d-selector---)
- [To Do](#to-do)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
standardized immutable objects in the spirit of datomic, especially suited for use in data pipelines
**NOTE: Documentation is still fragmentary. WIP.**
# Export Bound Methods
If you plan on using methods like `new_datom()` or `select()` a lot, consider using `.export()`:
```coffee
DATOM = require 'datom'
{ new_datom
select } = DATOM.export()
```
Now `new_datom()` and `select()` are methods bound to `DATOM`. (Observe that because of the JavaScript
'tear-off' effect, when you do `method = DATOM.method`, then `method()` will likely fail as its reference to
`this` has been lost.)
# Creation of Bespoke Library Instances
In order to configure a copy of the library, pass in a settings object:
```coffee
_DATOM = require 'datom'
settings = { merge_values: false, }
DATOM = new _DATOM.Datom settings
{ new_datom
select } = DATOM.export()
```
Or, mode idiomatically:
```coffee
DATOM = new ( require 'datom' ).Datom { merge_values: false, }
{ new_datom
select } = DATOM.export()
```
The second form also helps to avoid accidental usage of the result of `require 'datom'`, which is of
course the same library with a different configuration.
# Configuration Parameters
* **`merge_values`** (boolean, default: `true`)—Whether to merge attributes of the second argument to
`new_datom()` into the resulting value. When set to `false`, `new_datom '^somekey', somevalue` will always
result in a datom `{ $key: '^somekey', $value: somevalue, }`; when left to the default, and if `somevalue`
is an object, then its attributes will become attributes of the datom, which may result in name clashes in
case any attribute name should start with a `$` (dollar sign).
* **`freeze`** (boolean, default: `true`)—Whether to freeze datoms. When set to `false`, no freezing will
be performed, which may entail slightly improved performance.
# Methods
## Freezing & Thawing
* **`@freeze = ( d ) ->`**
* **`@thaw = ( d ) ->`**
* **`@lets = ( original, modifier ) ->`**
* **`@set = ( d, k, P... ) ->`**
* **`@unset = ( d, k ) ->`**
## Stamping
* **`@stamp = ( d, P... ) ->`**
* **`@unstamp = ( d ) ->`**
## Type Testing
* **`@is_system = ( d ) ->`**
* **`@is_stamped = ( d ) ->`**
* **`@is_fresh = ( d ) ->`**
* **`@is_dirty = ( d ) ->`**
## Value Creation
* **`@new_datom = ( $key, $value, other... ) ->`**
* **`@new_single_datom = ( $key, $value, other... ) ->`**
* **`@new_open_datom = ( $key, $value, other... ) ->`**
* **`@new_close_datom = ( $key, $value, other... ) ->`**
* **`@new_system_datom = ( $key, $value, other... ) ->`**
* **`@new_text_datom = ( $value, other... ) ->`**
* **`@new_end_datom = ->`**
* **`@new_warning = ( ref, message, d, other... ) ->`**
## Selecting
* **`@select = ( d, selector ) ->`**
# System Properties
* **`d.$key`**—key (i.e., type) of a datom.
* **`d.$value`**—'the' proper value of a datom. This is always used in case `new_datom()` was called with a
non-object in the value slot (as in `new_datom '^mykey', 123`), or when the library was configured with `{
merge_values: false, }`.—In case there is no `d.$value`, the datom's proper value is the object that would
result from deleting all properties whose names start with a `$` (dollar sign).
* **`d.$dirty`**—whether the object has been (thawed, then) changed (and then frozen again) since its
`$dirty` property was last cleared or set to `false`.
* **`d.$stamped`**—whether the object has been marked as 'stamped' (i.e., processed).
-------------------------------------------------------------------------------
# WIP
**The below copied from PipeDreams docs, to be updated**
## PipeDreams Datoms (Data Events)
Data streams—of which [pull-streams](https://pull-stream.github.io/),
[PipeStreams](https://github.com/loveencounterflow/pipestreams), and [NodeJS
Streams](https://nodejs.org/api/stream.html) are examples—do their work by
sending pieces of data (that originate from a data source) through a number of
transforms (to finally end up in a data sink).<sup>*note*</sup>
> (*note*) I will ignore here alternative ways of dealing with streams, especially
> the [`EventEmitter` way of dealing with streamed
> data](https://nodejs.org/api/stream.html#stream_api_for_stream_consumers).
> When I say 'streams', I also implicitly mean 'pipelines'; when I say
> 'pipelines', I also implicitly mean 'pipelines to stream data' and 'streams'
> in general.
When NodeJS streams started out, the thinking about those streams was pretty
much confined to saying that ['a stream is a series of
bytes'](http://dominictarr.com/post/145135293917/history-of-streams). Already back then,
an alternative view took hold (I'm slightly paraphrasing here):
> The core interpretation was that stream could be buffers or strings - but the
> userland interpretation was that a stream could be anything that is
> serializeable [...] it was a sequence of buffers, bytes, strings or objects.
> Why not use the same api?
I will no repeat here [what I've written about perceived shortcomings of NodeJS
streams](https://github.com/loveencounterflow/pipestreams/blob/master/pipestreams-manual/chapter-00-comparison.md);
instead, let me iterate a few observations:
* In streaming, data is just data. There's no need for having [a separate
'Object Mode'](https://nodejs.org/api/stream.html#stream_object_mode) or
somesuch.
* There's a single exception to the above rule, and that is when the data item
being sent down the line is `null`. This has historically—by both NodeJS
streams and pull-streams—been interpreted as a termination signal, and I'm not
going to change that (although at some point I might as well).
* When starting out with streams and building fairly simple-minded pipelines,
sending down either raw pieces of business data or else `null` to indicate
termination is enough to satisfy most needs. However, when one transitions to
more complex environments, raw data is not sufficient any more: When
processing text from one format to another, how could a downstream transform
tell whether a given piece of text is raw data or the output of an upstream
transform?
Another case where raw data becomes insufficient are circular
pipelines—pipelines that re-compute (some or all) output values in a recursive
manner. An example which outputs the integer sequences of the [Collatz
Conjecture](https://en.wikipedia.org/wiki/Collatz_conjecture) is [in the tests
folder](https://github.com/loveencounterflow/pipedreams/blob/master/src/tests/circular-pipelines.test.coffee#L36).
There, whenever we see an even number `n`, we send down that even number `n`
alongside with half its value, `n/2`; whenever we see an odd number `n`, we
send it on, followed by its value tripled plus one, `3*n+1`. No matter whether
you put the transform for even numbers in front of that for odd numbers or the
other way round, there will be numbers that come out at the bottom that need
to be re-input into the top of the pipeline, and since there's no telling in
advance how long a Collatz sequence will be for a given integer, it is, in the
general case, insufficient to build a pipeline made from a (necessarily
finite) repetitive sequence of copies of those individual transforms. Thus,
classical streams cannot easily model this kind of processing.
The idea of **datoms**—short for *data atoms*, a term borrowed from [Rich
Hickey's Datomic](https://www.infoq.com/articles/Datomic-Information-Model)—is
to simply to wrap each piece of raw data in a higher-level structure. This is of
course an old idea, but not one that is very prevalent in NodeJS streams, the
fundamental assumption (of classical stream processing) being that all stream
transforms get to process each piece of data, and that all pieces of data are of
equal status (with the exception of `null`).
The PipeDreams sample implementation of Collatz Sequences uses datoms to (1)
wrap the numerical pieces of data, which allows to mark data as processed
(a.k.a. 'stamped'), to (2) mark data as 'to be recycled', and to (3) inject
system-level `sync`hronization signals into the data stream to make sure that
recycled data gets processed before new data is allowed into the stream.
In PipeDreams datoms, **each piece of data is explicitly labelled for its
type**; **each datom may have a different status**: there are **system-level
datoms that serve to orchestrate the flow of data within the pipeline**; there
are **user-level datoms which originate from the application**; there are
**datoms to indicate the opening and closing of regions (phases) in the data
stream**; there are **stream transforms that listen to and act on specific
system-level events**.
Datoms are JS objects that must minimally have a `key` property, a string that
specifies the datom's category, namespace and name; in addition, they may have a
`value` property with the payload (where desired), and any number of other
attributes. The property `$` is used to carry metadata (e.g. from which line in
a source file a given datom was generated from). Thus, we may give the outline
of a datom as (in a rather informal notation) `d := { key, ?value, ?stamped,...,
?$, }`.
The `key` of a datom must be a string that consists of at least two parts, the
`sigil` and the `name`. The `sigil`, a single punctuation character, indicates
the 'category' of each datom; there are two levels and three elementary
categories, giving six types of datoms:
* Application level:
* `^` for **data datoms** (a.k.a. 'singletons'),
* `<` for **start-of-region datoms**,
* `>` for **end-of-region datoms**.
* System level:
* `~` for **data datoms**,
* `[` for **start-of-region datoms**,
* `]` for **end-of-region datoms**.
<!-- System-level events, in particular those without further payload data, are also
called 'signals'; thus, `~collect` is a 'collect signal', and `[data` is a
'start-of-data signal'. Aggregate transforms such as `$collect()`, `$sort()` and
so on listen to the signals of the same name, `~collect` and `~sort`: In the
case of `$collect()`, a collect signal will trigger the sending of the
collection as it looks at that point in time; likewise, `$sort()` will react to
a sort signal by sending all buffered events in the configured ordering.
-->
Normally, one will probably want to send around business data inside (the
`value` property of) application-level data datoms (hence their name, also
shortened to D-datoms); however, one can also set other properties of datom
objects, or send data around using properties of start- or end-of-region datoms.
Region events are intended to be used e.g. when parsing text with markup; say
you want to turn a snippet of HTML like this:
```
<document><div>Helo <em>world!</em></div></document>
```
into another textual representation, you may want to turn that into a sequence
of datoms similar to these, in the order of sending and regions symbolized by
boxes:<sup>*note*</sup>
```
--------------------------------------------------------+
{ key: '<document', } # d1 |
------------------------------------------------------+ |
{ key: '<div', } # d2 | |
{ key: '^text', value: "Helo ", } # d3 | |
----------------------------------------------------+ | |
{ key: '<em', } # d4 | | |
{ key: '^text' value: "world!", } # d5 | | |
{ key: '>em', } # d6 | | |
----------------------------------------------------+ | |
{ key: '>div', } # d7 | |
------------------------------------------------------+ |
{ key: '>document', } # d8 |
--------------------------------------------------------+
```
> *note* by 'in the order of sending' I mean you'd have to send datom `d1`
> first, then `d2` and so on. Trivial until you imagine you write a pipeline and
> then picture how the events will travel down that pipeline:
>
> `pipeline.push $do_this() # s1, might be processing d3 right now`<br>
> `pipeline.push $do_that() # s2, might be processing d2 right now`<br>
> `pipeline.push $do_something_else() # s3, might be processing d1 right now`<br>
>
> Although there's really no telling whether step `s3` will really process datom
> `d1` at the 'same point in time' that step `s2` processes datom `d2` and so on
> (in the strict sense, this is hardly possible in a single-threaded language
> anyway), the visualization still holds a grain of truth: stream transforms
> that come 'later' (further down) in the pipeline will see events near the top
> of your to-do list first, and vice versa. This can be mildly confusing.
## `select = ( d, selector ) ->`
The `select` method can be used to determine whether a given event `d` matches a
set of conditions; typically, one will want to use `select d, selector` to decide
whether a given event is suitable for processing by the stream transform at
hand, or whether it should be passed on unchanged.
The current implementation of `select()` is much dumber and faster than its predecessors; where previously,
it was possible to match datoms with multiple selectors that contained multiple sigils and so forth, the new
version does little more than check wheter the single selector allowed equals the given datom's `key`
value—that's about it, except that one can still `select d, '^somekey#stamped'` to match both unstamped and
stamped datoms.
------------------------------------------------------------------------
# To Do
* [ ] implement piecemeal structural validation such that on repeated calls to a validator instance's
`validate()` method an error will be thrown as soon as unbalanced regions (delimeted by `{ $key: '<token',
..., }` and `{ $key: '>token', ..., }`) are encountered.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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