Functional Object eXtraction, Serialization and Transformation (foxst)
Foxst makes it easy to query, extract data from, serialize, and transform any JavaScript object or primitive using a functional programming approach plus regular expressions that can match both object keys and values.
Installation
npm install foxst
Usage
Querying, Extracting, and Transforming
import {xt} from "foxst"
Foxst applies a pattern
to a target
JavaScript object or primitive. The pattern
is either a function
, RegExp
, object
or primitive (string
,number
,boolean
). Typically, it will be an object
with properties, the values of which are literals, functions
, or RegExps
.
If a primitive value stored in a pattern property has the same value as property on the target, it is considered to be a match.
xt({name:"joe"},{name:"joe",age:10}); // returns {name: "joe"}
If a RegExp
stored in a pattern property matches a value in the same property on a target, it is considered a match.
xt({name:/jo./},{name:"joe",age:10}); // returns {name: "joe"}
If a function
stored in a pattern property returns anything other than undefined
, then the same property on the target is considered to be a match and the returned value is used as the result.
xt({name:"joe"},{age:10}); // returns undefined because there is not even a name property on the target
xt({name:(value) => value},{name:"joe",age:10}); // returns {name: "joe"}
xt({name:(value) => value,age:(value)=>value},{name:"joe",age:10}); // returns {name: "joe",age:10}
xt({name:(value) => value,age:(value)=>value>10},{name:"joe",age:10}); // returns {}, target does not have age > 10, but does have some matching keys
xt({name:(value) => value==="joe" ? "joe" : undefined},{name:"joe",age:10}); // returns {name: "joe"}
xt({name:(value) => typeof(value)==="string" ? value.toUpperCase() : undefined},{name:"joe",age:10}); // returns {name: "JOE"}
xt({name:(value) => undefined},{name:"joe",age:10}); // returns {}, there is a name property on target, but value is undefined, so it is dropped
If a RegExp
stored as a property matches a property on the target and any of the above value matching conditions apply, then there is a match.
xt({[/ag./]:10},{name:"joe",age:10}); // returns {age:10}
If a function
stored as a property matches a property on the target and any of the above value matching conditions apply, then there is a match.
xt({[(key) => key==="age" ? key :undefined]:10},{name:"joe",age:10}); // returns {age:10}
A function
stored as a property can change the display name of the key.
xt({[(key) => key==="age" ? key.toUpperCase() : undefined]:10},{name:"joe",age:10}); // returns {AGE:10}
Objects are recursively matched.
xt({name:(value) => value,address:{city:(value)=>value,state:"ny"}},{name:"joe",address:{city:"ny",state:"ny"}});
// returns {name:"joe",address:{city:"ny",state:"ny"}}
In order to hide a value used in a match, return null
or mask characters, e.g. ****
. Or, use a key match and return the special key name anonymous
to drop the property from results.
xt({name:(value) => value,address:{city:(value)=>value,state:(value) => value==="ny" ? null : undefined}},{name:"joe",address:{city:"ny",state:"ny"}});
// returns {name:"joe",address:{city:"ny",state:null}}
xt({name:(value) => value,address:{city:(value)=>value,[(key) => key=="state" ? "anonymous" : undefined]:"ny"}});
// returns {name:"joe",address:{city:"ny"}}
Serializing and Deserializing
import {serializer,reviver} from "foxst";
function <- serializer(boolean | {functions=boolean,regexs=boolean,infinity=boolean,nan=boolean,builtins=boolean})
Passing false sets all flags to false
. The returned function
can be used as the second argument to JSON.stringify
. The flags instruct the function on whether it should ignore
or serialize the items. The builtins
flag covers all array types, Set
and Map
. Custom objects are serialized, although cyclic object can't currently be handled.
function <- reviver(boolean | {functions=boolean,regexs=boolean,infinity=boolean,nan=boolean,builtins=boolean,autocreate=boolean}, {constructors,...})
Passing false sets all flags to false
. The returned function
can be used as the second argument to JSON.parse
. The flags instruct the function on whether it should ignore
or restore the items. The builtins
flag covers all array types, Set
and Map
. Custom objects are restored using constructors passed as an object with keys being constructor names values being classes or constructor functions. The second argument is optional. If autocreate
is true
constructors will be created on the fly. If it is not true
and no constructors are provided, custom objects get restored as POJOs.
You can use serializer
and reviver
to serialize and revive both patterns and targets for transmission over the wire. You should isolate the restoration process to a Worker if you do not have full control over the RegExps
and functions
used in patterns or malicious code could enter your core application.
Unit Test Results
18 specs, 0 failures
Finished in 0.17 seconds
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
src | 98.14 | 97.17 | 100 | 98.14 |
index.js | 98.14 | 97.17 | 100 | 98.14 | 217-219,242-243
----------------|---------|----------|---------|---------|-------------------
Version History (Reverse Chronological Order)
2023-02013 v1.0.0 Improved logic to address multiple matches. Introduced 'anonymous' keys. Added documentation.
2023-02-13 v0.0.2 Code formatting.
2023-02-13 v0.0.1 First public release. 98.7% test coverage. Just lacks documentation.