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

protoblast

Package Overview
Dependencies
Maintainers
1
Versions
103
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

protoblast - npm Package Compare versions

Comparing version 0.4.1 to 0.4.2

11

CHANGELOG.md

@@ -0,1 +1,12 @@

## 0.4.2 (2018-01-15)
* `JSON.dry` will no longer add `namespace` or `dry_class` properties if `toDry` has already set them
* `JSON.undry` will now accept a dried object that has been parsed using regular `JSON.parse` (this is faster than re-stringifying & undrying it)
* Fixed the space problem in `JSON.dry`
* `Object.walk` will now return an object with all the seen objects and a weakmap containing the seen count
* `Object.walk` can now be called without a task function
* If DRY references to a value has a shorter path, use that in the future
* From now on, `json-dry` is its own package once again
* Added `JSON#toDryObject`, an alias for `Dry.toObject`
## 0.4.1 (2018-01-05)

@@ -2,0 +13,0 @@

31

lib/init.js

@@ -481,3 +481,3 @@ module.exports = function BlastInit(modifyPrototype) {

* @since 0.1.0
* @version 0.4.1
* @version 0.4.2
*

@@ -530,3 +530,4 @@ * @param {Object} target The object to add the property to

if (Blast.modifyPrototype) {
// Honour the 'modifyPrototype' setting, except for classes we created ourselves
if (Blast.modifyPrototype || (targetClass && targetClass.setMethod)) {
// Only set if it's not a shim, or if it's not there

@@ -606,2 +607,3 @@ if (!shim || !targetClass.hasOwnProperty(name)) {

//PROTOBLAST START CUT
/**

@@ -619,2 +621,3 @@ * Server side: create client side file

var template,
libpath = require('path'),
result,

@@ -633,3 +636,3 @@ cpath,

cpath = __dirname + '/../client-file-common.js';
cpath = libpath.resolve(__dirname, '..', 'client-file-common.js');
Blast.clientPathCommon = cpath;

@@ -641,3 +644,3 @@ } else {

cpath = __dirname + '/../client-file.js';
cpath = libpath.resolve(__dirname, '..', 'client-file.js');
Blast.clientPath = cpath;

@@ -650,3 +653,3 @@ }

// Get the main template
template = fs.readFileSync(__dirname + '/client.js', {encoding: 'utf8'});
template = fs.readFileSync(libpath.resolve(__dirname, 'client.js'), {encoding: 'utf8'});

@@ -661,2 +664,3 @@ code = '';

'weakmap',
'json-dry',
'function_flow',

@@ -673,8 +677,16 @@ 'function_inheritance',

files.forEach(function(name, index) {
files.forEach(function eachFile(name, index) {
var path;
name = name.toLowerCase();
temp = fs.readFileSync(__dirname + '/' + name + '.js', {encoding: 'utf8'});
if (name == 'json-dry') {
path = require.resolve('json-dry');
} else {
path = libpath.resolve(__dirname, name + '.js');
}
temp = fs.readFileSync(path, {encoding: 'utf8'});
code += 'require.register("' + name + '.js", function(module, exports, require){\n';

@@ -694,3 +706,3 @@ code += temp;

// Remove everything between "//PROTOBLAST START CUT" and "//PROTOBLAST END CUT"
// Remove everything between "PROTOBLAST START CUT" and "PROTOBLAST END CUT" (with slashes)
template = template.replace(/\/\/\s?PROTOBLAST\s?START\s?CUT([\s\S]*?)(\/\/\s?PROTOBLAST\s?END\s?CUT)/gm, '');

@@ -702,2 +714,3 @@

};
//PROTOBLAST END CUT

@@ -896,3 +909,3 @@ var when_ready = [],

// Now create bound methods, which are about 0,000129 ms slower
// Now create bound methods
Collection.Object.each(Collection, function eachCollection(StaticClass, className) {

@@ -899,0 +912,0 @@

@@ -1,602 +0,12 @@

/**
* Circular-JSON code:
* Copyright (C) 2013 by WebReflection
* Modified by Jelle De Loecker
*
* JSON-js code:
* Public domain by Douglas Crockford
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
module.exports = function BlastJSON(Blast, Collection) {
'use strict';
'use strict';
module.exports = function BlastJSON(Blast, Collection, Bound, Obj) {
var specialChar = '~',
safeSpecialChar = '\\x7e',
escapedSafeSpecialChar = '\\' + safeSpecialChar,
safeStartWithSpecialCharRG = new RegExp('(?:^|([^\\\\]))' + escapedSafeSpecialChar),
safeSpecialCharRG = new RegExp(escapedSafeSpecialChar, 'g'),
specialCharRG = new RegExp(safeSpecialChar, 'g'),
getregex = /^\/(.*)\/(.*)/,
iso8061 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/,
undriers = {},
driers = {},
meta,
rep;
var Dry = require('json-dry');
var rx_one = /^[\],:{}\s]*$/,
rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
rx_four = /(?:^|:|,)(?:\s*\[)+/g,
rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
// Override the Dry classes with the Protoblast classes
Dry.Classes = Blast.Classes;
Dry.Classes.__Protoblast = Blast;
// table of character substitutions
meta = {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"': '\\"',
'\\': '\\\\'
};
function string_escaper(a) {
var c = meta[a];
return c == null
? '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4)
: c;
}
function quote(string) {
rx_escapable.lastIndex = 0;
return rx_escapable.test(string)
? '"' + string.replace(rx_escapable, string_escaper) + '"'
: '"' + string + '"';
}
/**
* Generate a replacer function
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.4
* @version 0.3.8
*
* @return {Function}
*/
function generateReplacer(root, replacer, space) {
var seenByConstructor,
constructorMap,
seenObjects,
seenMap,
isRoot,
indent,
chain,
path,
temp,
gap,
i;
isRoot = true;
seenByConstructor = {};
constructorMap = {};
chain = [];
path = [];
seenObjects = [];
seenMap = [];
gap = '';
indent = '';
if (typeof space == 'number') {
for (i = 0; i < space; i++) {
indent += ' ';
}
} else if (typeof space == 'string') {
indent = space;
}
return function dryReplacer(holder, key, value) {
var nameType,
replaced,
partial,
isArray,
isWrap,
mind,
temp,
last,
len,
i,
j,
k, // Member key
v; // Member value
// Process the value to a possible given replacer function
if (replacer != null) {
value = replacer.call(holder, key, value);
}
mind = gap;
if (key === false) {
key = '';
isWrap = true;
// Wrappers get added to the object chain, but not the path
// We need to be able to identify them later on
holder.__isWrap = true;
// See if the wrapped value is an object
if (holder[''] && typeof holder[''] === 'object') {
holder.__isObject = true;
}
}
switch (typeof value) {
case 'function':
if (!driers.Function) {
return;
}
case 'object':
if (value == null) {
value = 'null';
} else {
gap += indent;
// Get the name of the constructor
if (value.constructor) {
nameType = value.constructor.name;
} else {
nameType = 'Object';
}
// Create the map if it doesn't exist yet
if (seenByConstructor[nameType] == null) {
seenByConstructor[nameType] = [];
constructorMap[nameType] = [];
}
while (len = chain.length) {
// If the current object at the end of the chain does not
// match the current holder, move one up
// Don't mess with the chain if this is a wrap object
if (!isWrap && holder !== chain[len-1]) {
last = chain.pop();
// Only pop the path if the popped object isn't a wrapper
// @todo: also check for __isObject or not?
if (last && !last.__isWrap) {
path.pop();
}
} else {
break;
}
}
// Now see if this object has been seen before
if (seenByConstructor[nameType].length) {
i = seenByConstructor[nameType].indexOf(value);
if (i > -1) {
value = quote(seenMap[constructorMap[nameType][i]]);
gap = mind;
break;
}
}
// Store the object in the seen array and return the index
i = seenObjects.push(value) - 1;
j = seenByConstructor[nameType].push(value) - 1;
constructorMap[nameType][j] = i;
// Key cannot contain specialChar but could be not a string
if (!isRoot && !isWrap) {
path.push(('' + key).replace(specialCharRG, safeSpecialChar));
} else {
isRoot = false;
}
seenMap[i] = specialChar + path.join(specialChar);
if (driers[nameType] != null) {
value = driers[nameType].fnc(holder, key, value);
value = {
dry: nameType,
value: value
};
if (driers[nameType].options.add_path !== false) {
value.drypath = path.slice(0);
}
replaced = {'': value};
} else if (nameType == 'RegExp') {
value = {dry: 'regexp', value: value.toString()};
replaced = {'': value};
} else if (typeof value.toDry === 'function') {
temp = value;
value = value.toDry();
// If no path was supplied in the toDry,
// get some more class information
if (!value.path) {
if (temp.constructor) {
if (temp.constructor.namespace) {
value.namespace = temp.constructor.namespace;
}
value.dry_class = temp.constructor.name;
}
}
value.dry = 'toDry';
value.drypath = path.slice(0);
replaced = {'': value};
} else if (typeof value.toJSON === 'function') {
value = value.toJSON();
replaced = {'': value};
} else {
isArray = Array.isArray(value);
}
// Push this object on the chain
chain.push(replaced || value);
if (replaced) {
value = dryReplacer(replaced, false, replaced['']);
// At least one part of the path & chain will have
// to be popped off. This is needed for toJSON calls
// that return primitive values
temp = chain.pop();
// Don't pop off anything from the path if the last item
// from the chain was a wrapper for an object,
// because then it'll already be popped of
if (!(temp && temp.__isWrap && temp.__isObject)) {
temp = path.pop();
}
break;
}
partial = [];
if (isArray) {
len = value.length;
for (i = 0; i < len; i += 1) {
partial[i] = dryReplacer(value, i, value[i]) || 'null';
}
v = partial.length === 0
? '[]'
: gap
? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
: '[' + partial.join(',') + ']';
gap = mind;
} else {
for (k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = dryReplacer(value, k, value[k]);
if (v) {
partial.push(quote(k) + (
gap
? ': '
: ':'
) + v);
}
}
}
v = partial.length === 0
? '{}'
: gap
? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
: '{' + partial.join(',') + '}';
gap = mind;
}
value = v;
}
break;
case 'string':
// Make sure the "special char" doesn't mess things up
if (!isRoot) {
value = value.replace(safeSpecialCharRG, escapedSafeSpecialChar)
.replace(specialChar, safeSpecialChar);
}
value = quote(value);
break;
case 'number':
// Allow infinite values
if (!isFinite(value)) {
if (value > 0) {
value = '{"dry":"+Infinity"}';
} else {
value = '{"dry":"-Infinity"}';
}
break;
}
case 'boolean':
case 'null':
value = String(value);
break;
}
return value;
};
};
/**
* Generate reviver function
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.4
* @version 0.3.8
*
* @return {Function}
*/
function generateReviver(reviver, undryPaths) {
return function dryReviver(key, value) {
var valType = typeof value,
constructor,
temp;
if (valType === 'string') {
if (value.charAt(0) === specialChar) {
return new String(value.slice(1));
} else if (value.match(iso8061)) {
return new Date(value);
}
} else if (value && value.dry != null) {
switch (value.dry) {
case 'regexp':
if (value.value) {
return RegExp.apply(undefined, getregex.exec(value.value).slice(1));
}
break;
case '+Infinity':
return Infinity;
case '-Infinity':
return -Infinity;
case 'toDry':
if (value.path) {
constructor = Collection.Object.path(Blast.Globals, value.path);
} else {
if (value.namespace) {
constructor = Collection.Object.path(Blast.Classes, value.namespace);
} else {
constructor = Blast.Classes;
}
if (value.dry_class) {
constructor = Collection.Object.path(constructor, value.dry_class);
}
}
// Undry this element, but don't put it in the parsed object yet
if (constructor && typeof constructor.unDry === 'function') {
value.undried = constructor.unDry(value.value);
} else {
value.undried = value.value;
}
if (value.drypath) {
undryPaths[value.drypath.join(specialChar)] = value;
} else {
return value.undried;
}
break;
default:
if (typeof value.value !== 'undefined') {
if (undriers[value.dry]) {
value.undried = undriers[value.dry].fnc(this, key, value.value);
} else {
value.undried = value.value;
}
if (value.drypath) {
undryPaths[value.drypath.join(specialChar)] = value;
} else {
return value.undried;
}
}
}
}
if (valType === 'string') {
value = value.replace(safeStartWithSpecialCharRG, '$1' + specialChar)
.replace(escapedSafeSpecialChar, safeSpecialChar);
}
if (reviver == null) {
return value;
}
return reviver.call(this, key, value);
};
};
/**
* Regenerate an array
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.4
* @version 0.1.4
*
* @return {Array}
*/
function regenerateArray(root, current, chain, retrieve, undryPaths) {
var length = current.length,
i;
for (i = 0; i < length; i++) {
// Only regenerate if it's not in the chain
if (chain.indexOf(current[i]) == -1) {
current[i] = regenerate(root, current[i], chain, retrieve, undryPaths);
}
}
return current;
};
/**
* Regenerate an object
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.4
* @version 0.1.4
*
* @return {Object}
*/
function regenerateObject(root, current, chain, retrieve, undryPaths) {
var key;
for (key in current) {
if (current.hasOwnProperty(key)) {
// Only regenerate if it's not in the cain
if (chain.indexOf(current[key]) == -1) {
current[key] = regenerate(root, current[key], chain, retrieve, undryPaths);
}
}
}
return current;
};
/**
* Regenerate a value
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.4
* @version 0.1.4
*
* @return {Mixed}
*/
function regenerate(root, current, chain, retrieve, undryPaths) {
var temp,
i;
chain.push(current);
if (current instanceof Array) {
return regenerateArray(root, current, chain, retrieve, undryPaths);
}
if (current instanceof String) {
if (current.length) {
if (undryPaths[current]) {
return undryPaths[current].undried;
}
if (retrieve.hasOwnProperty(current)) {
temp = retrieve[current];
} else {
temp = retrieve[current] = retrieveFromPath(root, current.split(specialChar));
}
return temp;
} else {
return root;
}
}
if (current instanceof Object) {
return regenerateObject(root, current, chain, retrieve, undryPaths);
}
chain.pop();
return current;
};
/**
* Retrieve from path.
* Set the given value, but only if the containing object exists.
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.4
* @version 0.1.4
*
* @return {Mixed}
*/
function retrieveFromPath(current, keys, value) {
var length = keys.length,
prev,
key,
i;
for (i = 0; i < length; i++) {
// Normalize the key
key = keys[i].replace(safeSpecialCharRG, specialChar);
prev = current;
if (current) {
current = current[key];
} else {
return undefined;
}
}
if (arguments.length === 3) {
prev[key] = value;
current = value;
}
return current;
};
/**
* Deep clone an object

@@ -615,131 +25,4 @@ *

*/
Blast.defineStatic('JSON', 'clone', function clone(obj, custom_method, extra_args, wm) {
Blast.defineStatic('JSON', 'clone', Dry.clone);
var custom_args,
entry_type,
nameType,
entry,
split,
keys,
temp,
len,
i,
target;
if (custom_method instanceof WeakMap) {
wm = custom_method;
custom_method = null;
} else if (!Array.isArray(extra_args)) {
wm = extra_args;
extra_args = null;
}
if (wm == null) {
wm = new WeakMap();
return clone({'_': obj}, custom_method, wm)['_'];
}
if (Array.isArray(obj)) {
target = [];
} else {
target = {};
}
if (custom_method) {
custom_args = [wm].concat(extra_args);
}
keys = Object.keys(obj);
len = keys.length;
// Remember the root object and its clone
wm.set(obj, target);
for (i = 0; i < len; i++) {
entry = obj[keys[i]];
entry_type = typeof entry;
if (entry && (entry_type == 'object' || entry_type == 'function')) {
if (entry_type == 'function' && !driers.Function) {
continue;
}
// If this has been cloned before, use that
if (wm.has(entry)) {
target[keys[i]] = wm.get(entry);
continue;
}
if (entry.constructor) {
nameType = entry.constructor.name;
if (custom_method && entry[custom_method]) {
target[keys[i]] = entry[custom_method].apply(entry, custom_args);
} else if (driers[nameType] != null) {
// Look for a registered drier function
temp = driers[nameType].fnc(obj, keys[i], entry);
if (undriers[nameType]) {
target[keys[i]] = undriers[nameType].fnc(target, keys[i], temp);
} else {
target[keys[i]] = temp;
}
} else if (entry.dryClone) {
// Look for dryClone after
target[keys[i]] = entry.dryClone(wm, custom_method);
} else if (entry.toDry) {
// Perform the toDry function
temp = entry.toDry();
// Clone the value,
// because returned objects aren't necesarilly cloned yet
temp = clone(temp.value, custom_method, wm);
// Perform the undry function
if (entry.constructor.unDry) {
target[keys[i]] = entry.constructor.unDry(temp);
} else {
// If there is no undry function, the clone will be a simple object
target[keys[i]] = temp;
}
} else if (nameType == 'Date') {
target[keys[i]] = new Date(entry);
} else if (nameType == 'RegExp') {
temp = entry.toString();
split = temp.match(/^\/(.*?)\/([gim]*)$/);
if (split) {
target[keys[i]] = new RegExp(split[1], split[2]);
} else {
target[keys[i]] = new RegExp(temp);
}
} else if (typeof entry.clone == 'function') {
// If it supplies a clone method, use that
target[keys[i]] = entry.clone();
} else if (entry.toJSON) {
temp = entry.toJSON();
if (temp && typeof temp == 'object') {
temp = clone(temp, custom_method, wm);
}
target[keys[i]] = temp;
} else {
target[keys[i]] = clone(entry, custom_method, wm);
}
} else {
target[keys[i]] = clone(entry, custom_method, wm);
}
// Remember this clone for later
wm.set(entry, target[keys[i]]);
} else {
target[keys[i]] = entry;
}
}
return target;
});
/**

@@ -758,8 +41,19 @@ * Dry it

*/
Blast.defineStatic('JSON', 'dry', function dry(value, replacer, space) {
var root = {'': value};
return generateReplacer(root, replacer, space)(root, '', value);
});
Blast.defineStatic('JSON', 'dry', Dry.stringify);
/**
* Dry it to an object
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.1.4
* @version 0.4.2
*
* @param {Mixed} value
* @param {Function} replacer
*
* @return {Object}
*/
Blast.defineStatic('JSON', 'toDryObject', Dry.toObject);
/**
* Register a drier

@@ -775,8 +69,3 @@ *

*/
Blast.defineStatic('JSON', 'registerDrier', function registerDrier(constructor_name, fnc, options) {
driers[constructor_name] = {
fnc: fnc,
options: options || {}
};
});
Blast.defineStatic('JSON', 'registerDrier', Dry.registerDrier);

@@ -794,8 +83,3 @@ /**

*/
Blast.defineStatic('JSON', 'registerUndrier', function registerUndrier(constructor_name, fnc, options) {
undriers[constructor_name] = {
fnc: fnc,
options: options || {}
};
});
Blast.defineStatic('JSON', 'registerUndrier', Dry.registerUndrier);

@@ -811,34 +95,4 @@ /**

*/
Blast.defineStatic('JSON', 'undry', function undry(text, reviver) {
Blast.defineStatic('JSON', 'undry', Dry.parse);
var undryPaths = {},
retrieve = {},
result,
path;
result = JSON.parse(text, generateReviver(reviver, undryPaths));
if (result == null) {
return result;
}
for (path in undryPaths) {
undryPaths[path].undried = regenerate(result, undryPaths[path].undried, [], retrieve, undryPaths)
}
// Only now can we resolve paths
result = regenerate(result, result, [], retrieve, undryPaths);
// Now we can replace all the undried values
for (path in undryPaths) {
Collection.Object.setPath(result, undryPaths[path].drypath, undryPaths[path].undried);
}
if (result.undried != null && result.dry == 'toDry') {
return result.undried;
}
return result;
});
/**

@@ -861,2 +115,12 @@ * Safe JSON parsing

/**
* Expose the Dry object
*
* @author Jelle De Loecker <jelle@develry.be>
* @since 0.4.2
* @version 0.4.2
*
* @type {Object}
*/
Blast.defineStatic('JSON', 'Dry', Dry);
};

@@ -462,3 +462,3 @@ module.exports = function BlastObject(Blast, Collection, Bound, Obj) {

/**
/**
* Extract form path info

@@ -676,3 +676,3 @@ *

if (!extension) continue;
// Go over every property of the current object

@@ -921,3 +921,3 @@ for (key in extension) {

* @since 0.1.6
* @version 0.3.8
* @version 0.4.2
*

@@ -929,7 +929,12 @@ * @param {Object} obj The object to walk over

*/
Blast.defineStatic('Object', 'walk', function walk(obj, fnc, limit, seen) {
Blast.defineStatic('Object', 'walk', function walk(obj, fnc, limit, seen, wm) {
var key,
var count,
key,
ret;
if (wm == null) {
wm = new WeakMap();
}
if (typeof limit != 'number') {

@@ -957,3 +962,5 @@ if (Array.isArray(limit)) {

// Fire the function
ret = fnc(obj[key], key, obj);
if (fnc != null) {
ret = fnc(obj[key], key, obj);
}

@@ -975,7 +982,22 @@ // If explicit false is returned,

if (limit > 0) {
walk(obj[key], fnc, limit - 1, seen);
walk(obj[key], fnc, limit - 1, seen, wm);
}
} else {
count = wm.get(obj[key]);
if (!count) {
count = 1;
} else {
count++;
}
wm.set(obj[key], count);
}
}
}
return {
seen : seen,
wm : wm
};
});

@@ -982,0 +1004,0 @@

{
"name": "protoblast",
"description": "Native object expansion library",
"version": "0.4.1",
"version": "0.4.2",
"author": "Jelle De Loecker <jelle@develry.be>",

@@ -14,2 +14,5 @@ "keywords": [

],
"dependencies": {
"json-dry" : "~1.0.0"
},
"repository": "skerit/protoblast",

@@ -16,0 +19,0 @@ "homepage": "https://protoblast.develry.be/",

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