New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

extraction

Package Overview
Dependencies
Maintainers
1
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

extraction - npm Package Compare versions

Comparing version 0.9.0 to 0.9.1

smp/graph.js

2

bower.json
{
"name": "extraction",
"version": "0.9.0",
"version": "0.9.1",
"description": "Tree Extraction for JavaScript Object Graphs",

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

@@ -45,3 +45,3 @@ /*

},{"./extraction-dsl.js":4,"./extraction-seen.js":7}],6:[function(_dereq_,module,exports){
"use strict";function _typeof(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e}Object.defineProperty(exports,"__esModule",{value:!0});var reifyInternal=function e(t,r,n,o){r.procValueBefore&&(t=r.procValueBefore(t,n)),r.debug&&console.log("reify: DEBUG: path: "+n+", graph: "+("undefined"==typeof t?"undefined":_typeof(t)));var f=!1;if(f=r.isReference?r.isReference(t):"string"==typeof t&&t.match(/^@self(?:\..+|)$/)){var i=void 0;if(i=r.getObject?r.getObject(t):o[t],void 0===i)throw new Error('invalid object reference "'+t+'" at path "'+n+'"');t=i}else if(null!==t&&"object"===("undefined"==typeof t?"undefined":_typeof(t)))if(r.setObject?r.setObject(n,t):o[n]=t,t instanceof Array)for(var l=0;l<t.length;l++)t[l]=e(t[l],r,n+"."+l,o);else for(var a in t)Object.hasOwnProperty.call(t,a)&&(t[a]=e(t[a],r,n+"."+a,o));return r.procValueAfter&&(t=r.procValueAfter(t,n)),t},reify=function(e,t){if("object"!==("undefined"==typeof e?"undefined":_typeof(e)))throw new Error("invalid graph argument (expected object type)");if(null===e)throw new Error("invalid graph argument (expected not-null value)");if(void 0===t&&(t={}),"object"!==("undefined"==typeof t?"undefined":_typeof(t)))throw new Error("invalid options argument (expected object type)");return reifyInternal(e,t,"@self",{"@self":e})};exports["default"]=reify;
"use strict";function _typeof(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e}Object.defineProperty(exports,"__esModule",{value:!0});var reifyInternal=function e(t,r,n,o){r.procValueBefore&&(t=r.procValueBefore(t,n)),r.debug&&console.log("reify: DEBUG: path: "+n+", graph: "+("undefined"==typeof t?"undefined":_typeof(t)));var f=!1;if(f=r.isReference?r.isReference(t):"string"==typeof t&&t.match(/^@self(?:\..+|)$/)){var i=void 0;if(i=r.getObject?r.getObject(t,n):o[t],void 0===i)throw new Error('invalid object reference "'+t+'" at path "'+n+'"');t=i}else if(null!==t&&"object"===("undefined"==typeof t?"undefined":_typeof(t)))if(r.setObject?r.setObject(t,n):o[n]=t,t instanceof Array)for(var l=0;l<t.length;l++)t[l]=e(t[l],r,n+"."+l,o);else for(var a in t)Object.hasOwnProperty.call(t,a)&&(t[a]=e(t[a],r,n+"."+a,o));return r.procValueAfter&&(t=r.procValueAfter(t,n)),t},reify=function(e,t){if("object"!==("undefined"==typeof e?"undefined":_typeof(e)))throw new Error("invalid graph argument (expected object type)");if(null===e)throw new Error("invalid graph argument (expected not-null value)");if(void 0===t&&(t={}),"object"!==("undefined"==typeof t?"undefined":_typeof(t)))throw new Error("invalid options argument (expected object type)");return reifyInternal(e,t,"@self",{"@self":e})};exports["default"]=reify;
},{}],7:[function(_dereq_,module,exports){

@@ -48,0 +48,0 @@ "use strict";function _classCallCheck(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,n){for(var t=0;t<n.length;t++){var s=n[t];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(e,s.key,s)}}return function(n,t,s){return t&&e(n.prototype,t),s&&e(n,s),n}}();Object.defineProperty(exports,"__esModule",{value:!0});var Seen=function(){return"function"==typeof WeakMap?function(){function e(){_classCallCheck(this,e),this.seenMap=new WeakMap}return _createClass(e,[{key:"set",value:function(e,n){this.seenMap.set(e,n)}},{key:"get",value:function(e){return this.seenMap.get(e)}}]),e}():function(){function e(){_classCallCheck(this,e),this.seenSeq=[],this.seenMap={}}return _createClass(e,[{key:"set",value:function(e,n){this.seenMap[this.seenSeq.length]=n,this.seenSeq.push(e)}},{key:"get",value:function(e){var n=this.seenSeq.indexOf(e);return n>=0?this.seenMap[n]:void 0}}]),e}()}();exports["default"]=Seen;

{
"name": "extraction",
"version": "0.9.0",
"version": "0.9.1",
"description": "Tree Extraction for JavaScript Object Graphs",

@@ -5,0 +5,0 @@ "keywords": [ "tree", "graph", "data", "structure", "extraction", "object" ],

@@ -16,3 +16,11 @@

Extraction is a very small JavaScript library... FIXME
Extraction is a small JavaScript library for extracting object trees
from arbitrary object graphs. Object graphs usually have cycles and
contain many information. Hence, the clue is that the extracted object
trees use links to break reference cycles and can be just partial by
leaving out information. The Extraction library is intended for two
main use cases: to support the persisting and restoring of arbitrary
in-memory object graph structures (where the cycle problem has to be
resolved) and to support the generation of responses in REST APIs based
on object graphs (where the partial information has to be resolved).

@@ -37,2 +45,9 @@ Installation

The Extraction library exposes two API functions (signatures given in TypeScript notation):
### `extract`
This is the main API method for extracting an object tree from an object
graph with the help of a tree extraction DSL.
```

@@ -42,2 +57,47 @@ extraction.extract(graph: object, spec: string, options?: object): object

- The `graph` argument has to be an Array of Object and be any start node in the graph.
- The `spec` argument is the tree extraction specification Domain-Specific Language (DSL).
It has to follow the following PEG-style grammar:
RHS | | LHS
---------|-----|---------------------------
spec | ::= | object / array
object | ::= | `"{"` content? `"}"`
array | ::= | `"["` content? `"]"`
content | ::= | (`"->"` num) / (field (`","` field)*)
field | ::= | (property spec) / (`"!"`? property)
property | ::= | id / `"*"` / (num `".."` num) / num
num | ::= | (`"-"`? `[0-9]`+) / `"-oo"` / `"oo"`
id | ::= | `[$a-zA-Z_][$a-zA-Z0-9_]`\*
Hint: the matching of multiple `field` in `content` follows a last-match semantic!
- The `options` argument is optional and can contain the following properties:
- `procValueBefore: (value: any) => any`:<br/>
Pre-process a value (object or property value) before it is taken into account.
A caller could use this to convert the value from a custom type into a standard
JavaScript type.
- `procValueAfter: (value: any) => any`:<br/>
Post-process a value (object or property value) after it was taken into account.
A caller could use this to convert the value into an external representation
like JSON or XML.
- `makeRefValue: (pathFirst: string, pathNow: string, obj: Object) => any`:<br/>
Make an object reference out of an object `obj`, which is now found (again)
at path `pathNow` and the first-time found at `pathFirst`. The default
is to use `pathFirst` as the reference, but a caller could also use
a stub for `obj` (usually based on just the OID of it) as the reference.
- `debug: boolean`:<br/>
Print debug information about internal processing.
### `reify`
This is a utility API method to re-generate an object graph from an
object tree by reifying all self-references back to the referenced
objects.
```

@@ -47,2 +107,195 @@ extraction.reify(tree: object, options?: object): object

- The `tree` argument is the root of an object tree which should be traversed.
- The `options` argument is optional and can contain the following properties:
- `procValueBefore: (value: any) => any`:<br/>
Pre-process a value (object or property value) after it is taken into account.
A caller could use this to convert the value from an external representation
like JSON or XML.
- `procValueAfter: (value: any) => any`:<br/>
Post-process a value (object or property value) after it was taken into account.
A caller could use this to convert the value from a standard type into a custom
JavaScript type.
- `isReference: (value: any) => boolean`:<br/>
Determine whether `value` is an object reference.
- `getObject: (value: any, path: string) => any`:<br/>
Fetch the underlying object from an object reference `value`, found at `path`.
- `setObject: (value: any, path: string) => void`:<br/>
Store an underlying object `value`, found at `path`.
- `debug: boolean`:<br/>
Print debug information about internal processing.
Example
-------
Suppose we have an object graph (aka "business model") based
on two entity definitions (in pseudo language):
```
Person {
id: number
name: string
tags: string+
home: Location
rival: Person?
}
Location {
id: number
name: string
owner: Person?
subs: Location*
}
```
A possible JavaScript instanciation of this object graph definition then
could be:
```js
var Graph = {
Person: [
{ id: 7, name: "God", tags: [ "good", "nice" ] },
{ id: 666, name: "Devil", tags: [ "bad", "cruel" ] }
],
Location: [
{ id: 0, name: "World" },
{ id: 1, name: "Heaven" },
{ id: 999, name: "Hell" }
]
}
Graph.Person[0].home = Graph.Location[1]
Graph.Person[1].home = Graph.Location[2]
Graph.Person[1].rival = Graph.Person[0]
Graph.Person[0].rival = Graph.Person[1]
Graph.Location[0].subs = [ Graph.Location[1], Graph.Location[2] ]
Graph.Location[1].owner = Graph.Person[0]
Graph.Location[2].owner = Graph.Person[1]
```
Because of the relationship cycles in this graph, you cannot easily
serialize this graph as JSON with plain `JSON.stringify()` as it
will detect but not handle the cycles correctly. With the Extraction library
you can serialize and deseralize this graph just fine:
```js
/* import external requirements */
import { extract, reify } from "extraction"
import { expect } from "chai"
import { inspect } from "util"
/* extract entire graph as a tree with self-references */
let tree = extract(Graph, "{ -> oo }")
console.log(inspect(tree, { depth: null }))
// { Person:
// [ { id: 7,
// name: 'God',
// tags: [ 'good', 'nice' ],
// home: { id: 1, name: 'Heaven', owner: '@self.Person.0' },
// rival:
// { id: 666,
// name: 'Devil',
// tags: [ 'bad', 'cruel' ],
// home: { id: 999, name: 'Hell', owner: '@self.Person.0.rival' },
// rival: '@self.Person.0' } },
// '@self.Person.0.rival' ],
// Location:
// [ { id: 0,
// name: 'World',
// subs: [ '@self.Person.0.home', '@self.Person.0.rival.home' ] },
// '@self.Person.0.home',
// '@self.Person.0.rival.home' ] }
/* as the tree has no cycles, it can be serialized/unserialized just fine */
tree = JSON.parse(JSON.stringify(tree))
/* reify the object references to gain the original graph again */
let GraphNew = reify(tree)
expect(GraphNew).to.be.deep.equal(Graph)
```
Now suppose we have a REST API where we want to let Persons
with their home Location be queried:
```js
/* import external requirements */
import HAPI from "hapi"
import { extract } from "./lib/extraction"
/* import sample graph */
import Graph from "./sample-graph"
/* establish a new REST service */
var server = new HAPI.Server()
server.connection({ address: "0.0.0.0", port: "12345" })
/* provide REST endpoints */
server.route({
method: "GET",
path: "/persons/{id}",
handler: (request, reply) => {
let id = parseInt(request.params.id)
let person = Graph.Person.find((person) => person.id === id)
let response = JSON.stringify(extract(
person, "{ id, name, home { id, name } }"
))
reply(response)
}
})
/* fire up REST service */
server.start((err) => {
if (err)
console.log(err)
})
```
Querying the two Persons yields:
```
$ curl http://127.0.0.1:12345/persons/7
{"id":7,"name":"God","home":{"id":1,"name":"Heaven"}}
$ curl http://127.0.0.1:12345/persons/6660
{"id":666,"name":"Devil","home":{"id":999,"name":"Hell"}}
```
Finally, instead of extracting a tree and then encoding it
as JSON, you can immediately encode it during extraction:
```js
extraction.extract(Graph, "{ -> oo }", {
procValueAfter: (value) => {
if (typeof value === "object" && value !== null) {
if (value instanceof Array)
value = "[" + value.join(",") + "]"
else
value = "{" + Object.keys(value).map(function (key) {
return JSON.stringify(key) + ":" + value[key]
}).join(",") + "}"
}
else
value = JSON.stringify(value)
return value
}
}))
// {"Person":[{"id":7,"name":"God","tags":["good","nice"],
// "home":{"id":1,"name":"Heaven","owner":"@self.Person.0"},
// "rival":{"id":666,"name":"Devil","tags":["bad","cruel"],
// "home":{"id":999,"name":"Hell","owner":"@self.Person.0.rival"},
// "rival":"@self.Person.0"}},"@self.Person.0.rival"],
// "Location":[{"id":0,"name":"World","subs":["@self.Person.0.home",
// "@self.Person.0.rival.home"]},"@self.Person.0.home",
// "@self.Person.0.rival.home"]}
```
Implementation Notice

@@ -49,0 +302,0 @@ ---------------------

@@ -45,3 +45,3 @@ /*

if (options.getObject)
obj = options.getObject(node)
obj = options.getObject(node, path)
else

@@ -56,3 +56,3 @@ obj = map[node]

if (options.setObject)
options.setObject(path, node)
options.setObject(node, path)
else

@@ -59,0 +59,0 @@ map[path] = node

/*
** Extraction -- Data Structure Extraction for JavaScript
** Extraction -- Tree Extraction for JavaScript Object Graphs
** Copyright (c) 2015 Ralf S. Engelschall <rse@engelschall.com>

@@ -4,0 +4,0 @@ **

/*
** Extraction -- Data Structure Extraction for JavaScript
** Extraction -- Tree Extraction for JavaScript Object Graphs
** Copyright (c) 2015 Ralf S. Engelschall <rse@engelschall.com>

@@ -10,3 +10,3 @@ **

** distribute, sublicense, and/or sell copies of the Software, and to
** permit persons to whom the Software is furnished to do so, subject to
** permit Person to whom the Software is furnished to do so, subject to
** the following conditions:

@@ -33,23 +33,4 @@ **

var extraction = require("../lib/extraction.js")
var Graph = require("../smp/graph.js")
/* the sample graph */
var persons = [
{ id: 7, name: "God", tags: [ "good", "nice" ] },
{ id: 666, name: "Devil", tags: [ "bad", "cruel" ] }
]
var locations = [
{ id: 1, name: "Heaven" },
{ id: 999, name: "Hell" }
]
persons[0].location = locations[0]
persons[1].location = locations[1]
persons[1].counterpart = persons[0]
persons[0].counterpart = persons[1]
locations[0].owner = persons[0]
locations[0].owner = persons[1]
var graph = {
persons: persons,
locations: locations
}
describe("Extraction Library", function () {

@@ -62,38 +43,17 @@ it("should expose its official API", function () {

it("should extract simply", function () {
expect(extraction.extract(graph, "{}", { ignoreMatchErrors: true, debug: true }))
expect(extraction.extract(Graph, "{}", { ignoreMatchErrors: true, debug: false }))
.to.be.deep.equal({})
expect(extraction.extract(graph, "{ * }", { ignoreMatchErrors: true, debug: true }))
.to.be.deep.equal({ persons: [], locations: [] })
expect(extraction.extract(graph, "{ persons [ * { id, name } ] }", { ignoreMatchErrors: true, debug: true }))
.to.be.deep.equal({ persons: [ { id: 7, name: "God" }, { id: 666, name: "Devil" } ] })
extraction.extract(graph, "{ persons [ * { id, name } ] }")
extraction.extract(graph, "{ persons [ * { id, name } ] }")
/*
console.log(require("util").inspect(extraction(graph,
"{ persons [ * { id, tags [ -> oo ] } ], !locations }"
), { depth: null, colors: true }))
console.log(require("util").inspect(extraction(graph,
"{ -> oo }"
), { depth: null, colors: true }))
*/
console.log(extraction.extract(graph, "{ -> oo }", {
procValueAfter: (value) => {
if (typeof value === "object" && value !== null) {
if (value instanceof Array)
value = "[" + value.join(",") + "]"
else
value = "{" + Object.keys(value).map(function (key) {
return JSON.stringify(key) + ":" + value[key]
}).join(",") + "}"
}
else
value = JSON.stringify(value)
return value
}
}))
var g = extraction.extract(graph, "{ -> oo }")
expect(extraction.extract(Graph, "{ * }", { ignoreMatchErrors: true, debug: false }))
.to.be.deep.equal({ Person: [], Location: [] })
expect(extraction.extract(Graph, "{ Person [ * { id, name } ] }", { ignoreMatchErrors: true, debug: false }))
.to.be.deep.equal({ Person: [ { id: 7, name: "God" }, { id: 666, name: "Devil" } ] })
extraction.extract(Graph, "{ Person [ * { id, name } ] }")
extraction.extract(Graph, "{ Person [ * { id, name } ] }")
})
it("should fully extract and reify again", function () {
var g = extraction.extract(Graph, "{ -> oo }")
extraction.reify(g)
expect(g).to.be.deep.equal(graph)
expect(g).to.be.deep.equal(Graph)
})
})
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