project files added
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2012-2018, Project contributors
|
||||
Copyright (c) 2012-2014, Walmart
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* The names of any contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# topo
|
||||
|
||||
Topological sorting with grouping support.
|
||||
|
||||
[](http://travis-ci.org/hapijs/topo)
|
||||
|
||||
Lead Maintainer: [Devin Ivy](https://github.com/devinivy)
|
||||
|
||||
## Usage
|
||||
|
||||
See the [API Reference](API.md)
|
||||
|
||||
**Example**
|
||||
```js
|
||||
const Topo = require('topo');
|
||||
|
||||
const morning = new Topo();
|
||||
|
||||
morning.add('Nap', { after: ['breakfast', 'prep'] });
|
||||
|
||||
morning.add([
|
||||
'Make toast',
|
||||
'Pour juice'
|
||||
], { before: 'breakfast', group: 'prep' });
|
||||
|
||||
morning.add('Eat breakfast', { group: 'breakfast' });
|
||||
|
||||
morning.nodes; // ['Make toast', 'Pour juice', 'Eat breakfast', 'Nap']
|
||||
```
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
'use strict';
|
||||
|
||||
// Load modules
|
||||
|
||||
const Hoek = require('hoek');
|
||||
|
||||
|
||||
// Declare internals
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = class Topo {
|
||||
|
||||
constructor() {
|
||||
|
||||
this._items = [];
|
||||
this.nodes = [];
|
||||
}
|
||||
|
||||
add(nodes, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// Validate rules
|
||||
|
||||
const before = [].concat(options.before || []);
|
||||
const after = [].concat(options.after || []);
|
||||
const group = options.group || '?';
|
||||
const sort = options.sort || 0; // Used for merging only
|
||||
|
||||
Hoek.assert(!before.includes(group), `Item cannot come before itself: ${group}`);
|
||||
Hoek.assert(!before.includes('?'), 'Item cannot come before unassociated items');
|
||||
Hoek.assert(!after.includes(group), `Item cannot come after itself: ${group}`);
|
||||
Hoek.assert(!after.includes('?'), 'Item cannot come after unassociated items');
|
||||
|
||||
([].concat(nodes)).forEach((node, i) => {
|
||||
|
||||
const item = {
|
||||
seq: this._items.length,
|
||||
sort,
|
||||
before,
|
||||
after,
|
||||
group,
|
||||
node
|
||||
};
|
||||
|
||||
this._items.push(item);
|
||||
});
|
||||
|
||||
// Insert event
|
||||
|
||||
const error = this._sort();
|
||||
Hoek.assert(!error, 'item', (group !== '?' ? `added into group ${group}` : ''), 'created a dependencies error');
|
||||
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
merge(others) {
|
||||
|
||||
others = [].concat(others);
|
||||
for (let i = 0; i < others.length; ++i) {
|
||||
const other = others[i];
|
||||
if (other) {
|
||||
for (let j = 0; j < other._items.length; ++j) {
|
||||
const item = Object.assign({}, other._items[j]); // Shallow cloned
|
||||
this._items.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort items
|
||||
|
||||
this._items.sort(internals.mergeSort);
|
||||
for (let i = 0; i < this._items.length; ++i) {
|
||||
this._items[i].seq = i;
|
||||
}
|
||||
|
||||
const error = this._sort();
|
||||
Hoek.assert(!error, 'merge created a dependencies error');
|
||||
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
_sort() {
|
||||
|
||||
// Construct graph
|
||||
|
||||
const graph = {};
|
||||
const graphAfters = Object.create(null); // A prototype can bungle lookups w/ false positives
|
||||
const groups = Object.create(null);
|
||||
|
||||
for (let i = 0; i < this._items.length; ++i) {
|
||||
const item = this._items[i];
|
||||
const seq = item.seq; // Unique across all items
|
||||
const group = item.group;
|
||||
|
||||
// Determine Groups
|
||||
|
||||
groups[group] = groups[group] || [];
|
||||
groups[group].push(seq);
|
||||
|
||||
// Build intermediary graph using 'before'
|
||||
|
||||
graph[seq] = item.before;
|
||||
|
||||
// Build second intermediary graph with 'after'
|
||||
|
||||
const after = item.after;
|
||||
for (let j = 0; j < after.length; ++j) {
|
||||
graphAfters[after[j]] = (graphAfters[after[j]] || []).concat(seq);
|
||||
}
|
||||
}
|
||||
|
||||
// Expand intermediary graph
|
||||
|
||||
let graphNodes = Object.keys(graph);
|
||||
for (let i = 0; i < graphNodes.length; ++i) {
|
||||
const node = graphNodes[i];
|
||||
const expandedGroups = [];
|
||||
|
||||
const graphNodeItems = Object.keys(graph[node]);
|
||||
for (let j = 0; j < graphNodeItems.length; ++j) {
|
||||
const group = graph[node][graphNodeItems[j]];
|
||||
groups[group] = groups[group] || [];
|
||||
|
||||
for (let k = 0; k < groups[group].length; ++k) {
|
||||
expandedGroups.push(groups[group][k]);
|
||||
}
|
||||
}
|
||||
|
||||
graph[node] = expandedGroups;
|
||||
}
|
||||
|
||||
// Merge intermediary graph using graphAfters into final graph
|
||||
|
||||
const afterNodes = Object.keys(graphAfters);
|
||||
for (let i = 0; i < afterNodes.length; ++i) {
|
||||
const group = afterNodes[i];
|
||||
|
||||
if (groups[group]) {
|
||||
for (let j = 0; j < groups[group].length; ++j) {
|
||||
const node = groups[group][j];
|
||||
graph[node] = graph[node].concat(graphAfters[group]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compile ancestors
|
||||
|
||||
let children;
|
||||
const ancestors = {};
|
||||
graphNodes = Object.keys(graph);
|
||||
for (let i = 0; i < graphNodes.length; ++i) {
|
||||
const node = graphNodes[i];
|
||||
children = graph[node];
|
||||
|
||||
for (let j = 0; j < children.length; ++j) {
|
||||
ancestors[children[j]] = (ancestors[children[j]] || []).concat(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Topo sort
|
||||
|
||||
const visited = {};
|
||||
const sorted = [];
|
||||
|
||||
for (let i = 0; i < this._items.length; ++i) { // Really looping thru item.seq values out of order
|
||||
let next = i;
|
||||
|
||||
if (ancestors[i]) {
|
||||
next = null;
|
||||
for (let j = 0; j < this._items.length; ++j) { // As above, these are item.seq values
|
||||
if (visited[j] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ancestors[j]) {
|
||||
ancestors[j] = [];
|
||||
}
|
||||
|
||||
const shouldSeeCount = ancestors[j].length;
|
||||
let seenCount = 0;
|
||||
for (let k = 0; k < shouldSeeCount; ++k) {
|
||||
if (visited[ancestors[j][k]]) {
|
||||
++seenCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (seenCount === shouldSeeCount) {
|
||||
next = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next !== null) {
|
||||
visited[next] = true;
|
||||
sorted.push(next);
|
||||
}
|
||||
}
|
||||
|
||||
if (sorted.length !== this._items.length) {
|
||||
return new Error('Invalid dependencies');
|
||||
}
|
||||
|
||||
const seqIndex = {};
|
||||
for (let i = 0; i < this._items.length; ++i) {
|
||||
const item = this._items[i];
|
||||
seqIndex[item.seq] = item;
|
||||
}
|
||||
|
||||
const sortedNodes = [];
|
||||
this._items = sorted.map((value) => {
|
||||
|
||||
const sortedItem = seqIndex[value];
|
||||
sortedNodes.push(sortedItem.node);
|
||||
return sortedItem;
|
||||
});
|
||||
|
||||
this.nodes = sortedNodes;
|
||||
}
|
||||
};
|
||||
|
||||
internals.mergeSort = (a, b) => {
|
||||
|
||||
return a.sort === b.sort ? 0 : (a.sort < b.sort ? -1 : 1);
|
||||
};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
*
|
||||
!lib/**
|
||||
!.npmignore
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
Breaking changes are documented using GitHub issues, see [issues labeled "release notes"](https://github.com/hapijs/hoek/issues?q=is%3Aissue+label%3A%22release+notes%22).
|
||||
|
||||
If you want changes of a specific minor or patch release, you can browse the [GitHub milestones](https://github.com/hapijs/hoek/milestones?state=closed&direction=asc&sort=due_date).
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
Copyright (c) 2011-2018, Project contributors
|
||||
Copyright (c) 2011-2014, Walmart
|
||||
Copyright (c) 2011, Yahoo Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* The names of any contributors may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+15
@@ -0,0 +1,15 @@
|
||||

|
||||
|
||||
Utility methods for the hapi ecosystem. This module is not intended to solve every problem for
|
||||
everyone, but rather as a central place to store hapi-specific methods. If you're looking for a
|
||||
general purpose utility module, check out [lodash](https://github.com/lodash/lodash) or
|
||||
[underscore](https://github.com/jashkenas/underscore).
|
||||
|
||||
[](http://travis-ci.org/hapijs/hoek)
|
||||
|
||||
Lead Maintainer: [Gil Pedersen](https://github.com/kanongil)
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
[**API Reference**](API.md)
|
||||
+315
@@ -0,0 +1,315 @@
|
||||
'use strict';
|
||||
|
||||
// Load modules
|
||||
|
||||
|
||||
// Declare internals
|
||||
|
||||
const internals = {
|
||||
arrayType: Symbol('array'),
|
||||
bufferType: Symbol('buffer'),
|
||||
dateType: Symbol('date'),
|
||||
errorType: Symbol('error'),
|
||||
genericType: Symbol('generic'),
|
||||
mapType: Symbol('map'),
|
||||
regexType: Symbol('regex'),
|
||||
setType: Symbol('set'),
|
||||
weakMapType: Symbol('weak-map'),
|
||||
weakSetType: Symbol('weak-set'),
|
||||
mismatched: Symbol('mismatched')
|
||||
};
|
||||
|
||||
|
||||
internals.typeMap = {
|
||||
'[object Array]': internals.arrayType,
|
||||
'[object Date]': internals.dateType,
|
||||
'[object Error]': internals.errorType,
|
||||
'[object Map]': internals.mapType,
|
||||
'[object RegExp]': internals.regexType,
|
||||
'[object Set]': internals.setType,
|
||||
'[object WeakMap]': internals.weakMapType,
|
||||
'[object WeakSet]': internals.weakSetType
|
||||
};
|
||||
|
||||
|
||||
internals.SeenEntry = class {
|
||||
|
||||
constructor(obj, ref) {
|
||||
|
||||
this.obj = obj;
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
isSame(obj, ref) {
|
||||
|
||||
return this.obj === obj && this.ref === ref;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.getInternalType = function (obj) {
|
||||
|
||||
const { typeMap, bufferType, genericType } = internals;
|
||||
|
||||
if (obj instanceof Buffer) {
|
||||
return bufferType;
|
||||
}
|
||||
|
||||
const objName = Object.prototype.toString.call(obj);
|
||||
return typeMap[objName] || genericType;
|
||||
};
|
||||
|
||||
|
||||
internals.getSharedType = function (obj, ref, checkPrototype) {
|
||||
|
||||
if (checkPrototype) {
|
||||
if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {
|
||||
return internals.mismatched;
|
||||
}
|
||||
|
||||
return internals.getInternalType(obj);
|
||||
}
|
||||
|
||||
const type = internals.getInternalType(obj);
|
||||
if (type !== internals.getInternalType(ref)) {
|
||||
return internals.mismatched;
|
||||
}
|
||||
|
||||
return type;
|
||||
};
|
||||
|
||||
|
||||
internals.valueOf = function (obj) {
|
||||
|
||||
const objValueOf = obj.valueOf;
|
||||
if (objValueOf === undefined) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
try {
|
||||
return objValueOf.call(obj);
|
||||
}
|
||||
catch (err) {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.hasOwnEnumerableProperty = function (obj, key) {
|
||||
|
||||
return Object.prototype.propertyIsEnumerable.call(obj, key);
|
||||
};
|
||||
|
||||
|
||||
internals.isSetSimpleEqual = function (obj, ref) {
|
||||
|
||||
for (const entry of obj) {
|
||||
if (!ref.has(entry)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
internals.isDeepEqualObj = function (instanceType, obj, ref, options, seen) {
|
||||
|
||||
const { isDeepEqual, valueOf, hasOwnEnumerableProperty } = internals;
|
||||
const { keys, getOwnPropertySymbols } = Object;
|
||||
|
||||
if (instanceType === internals.arrayType) {
|
||||
if (options.part) {
|
||||
// Check if any index match any other index
|
||||
|
||||
for (let i = 0; i < obj.length; ++i) {
|
||||
const objValue = obj[i];
|
||||
for (let j = 0; j < ref.length; ++j) {
|
||||
if (isDeepEqual(objValue, ref[j], options, seen)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (obj.length !== ref.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < obj.length; ++i) {
|
||||
if (!isDeepEqual(obj[i], ref[i], options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (instanceType === internals.setType) {
|
||||
if (obj.size !== ref.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!internals.isSetSimpleEqual(obj, ref)) {
|
||||
|
||||
// Check for deep equality
|
||||
|
||||
const ref2 = new Set(ref);
|
||||
for (const objEntry of obj) {
|
||||
if (ref2.delete(objEntry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let found = false;
|
||||
for (const refEntry of ref2) {
|
||||
if (isDeepEqual(objEntry, refEntry, options, seen)) {
|
||||
ref2.delete(refEntry);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (instanceType === internals.mapType) {
|
||||
if (obj.size !== ref.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const [key, value] of obj) {
|
||||
if (value === undefined && !ref.has(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDeepEqual(value, ref.get(key), options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (instanceType === internals.errorType) {
|
||||
// Always check name and message
|
||||
|
||||
if (obj.name !== ref.name || obj.message !== ref.message) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check .valueOf()
|
||||
|
||||
const valueOfObj = valueOf(obj);
|
||||
const valueOfRef = valueOf(ref);
|
||||
if (!(obj === valueOfObj && ref === valueOfRef) &&
|
||||
!isDeepEqual(valueOfObj, valueOfRef, options, seen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check properties
|
||||
|
||||
const objKeys = keys(obj);
|
||||
if (!options.part && objKeys.length !== keys(ref).length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < objKeys.length; ++i) {
|
||||
const key = objKeys[i];
|
||||
|
||||
if (!hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDeepEqual(obj[key], ref[key], options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check symbols
|
||||
|
||||
if (options.symbols) {
|
||||
const objSymbols = getOwnPropertySymbols(obj);
|
||||
const refSymbols = new Set(getOwnPropertySymbols(ref));
|
||||
|
||||
for (let i = 0; i < objSymbols.length; ++i) {
|
||||
const key = objSymbols[i];
|
||||
|
||||
if (hasOwnEnumerableProperty(obj, key)) {
|
||||
if (!hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDeepEqual(obj[key], ref[key], options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
refSymbols.delete(key);
|
||||
}
|
||||
|
||||
for (const key of refSymbols) {
|
||||
if (hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
internals.isDeepEqual = function (obj, ref, options, seen) {
|
||||
|
||||
if (obj === ref) { // Copied from Deep-eql, copyright(c) 2013 Jake Luer, jake@alogicalparadox.com, MIT Licensed, https://github.com/chaijs/deep-eql
|
||||
return obj !== 0 || 1 / obj === 1 / ref;
|
||||
}
|
||||
|
||||
const type = typeof obj;
|
||||
|
||||
if (type !== typeof ref) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type !== 'object' ||
|
||||
obj === null ||
|
||||
ref === null) {
|
||||
|
||||
return obj !== obj && ref !== ref; // NaN
|
||||
}
|
||||
|
||||
const instanceType = internals.getSharedType(obj, ref, !!options.prototype);
|
||||
switch (instanceType) {
|
||||
case internals.bufferType:
|
||||
return Buffer.prototype.equals.call(obj, ref);
|
||||
case internals.regexType:
|
||||
return obj.toString() === ref.toString();
|
||||
case internals.mismatched:
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = seen.length - 1; i >= 0; --i) {
|
||||
if (seen[i].isSame(obj, ref)) {
|
||||
return true; // If previous comparison failed, it would have stopped execution
|
||||
}
|
||||
}
|
||||
|
||||
seen.push(new internals.SeenEntry(obj, ref));
|
||||
try {
|
||||
return !!internals.isDeepEqualObj(instanceType, obj, ref, options, seen);
|
||||
}
|
||||
finally {
|
||||
seen.pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = function (obj, ref, options) {
|
||||
|
||||
options = options || { prototype: true };
|
||||
|
||||
return !!internals.isDeepEqual(obj, ref, options, []);
|
||||
};
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
'use strict';
|
||||
|
||||
// Declare internals
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.escapeHtml = function (input) {
|
||||
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let escaped = '';
|
||||
|
||||
for (let i = 0; i < input.length; ++i) {
|
||||
|
||||
const charCode = input.charCodeAt(i);
|
||||
|
||||
if (internals.isSafe(charCode)) {
|
||||
escaped += input[i];
|
||||
}
|
||||
else {
|
||||
escaped += internals.escapeHtmlChar(charCode);
|
||||
}
|
||||
}
|
||||
|
||||
return escaped;
|
||||
};
|
||||
|
||||
|
||||
exports.escapeJson = function (input) {
|
||||
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const lessThan = 0x3C;
|
||||
const greaterThan = 0x3E;
|
||||
const andSymbol = 0x26;
|
||||
const lineSeperator = 0x2028;
|
||||
|
||||
// replace method
|
||||
let charCode;
|
||||
return input.replace(/[<>&\u2028\u2029]/g, (match) => {
|
||||
|
||||
charCode = match.charCodeAt(0);
|
||||
|
||||
if (charCode === lessThan) {
|
||||
return '\\u003c';
|
||||
}
|
||||
|
||||
if (charCode === greaterThan) {
|
||||
return '\\u003e';
|
||||
}
|
||||
|
||||
if (charCode === andSymbol) {
|
||||
return '\\u0026';
|
||||
}
|
||||
|
||||
if (charCode === lineSeperator) {
|
||||
return '\\u2028';
|
||||
}
|
||||
|
||||
return '\\u2029';
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
internals.escapeHtmlChar = function (charCode) {
|
||||
|
||||
const namedEscape = internals.namedHtml[charCode];
|
||||
if (typeof namedEscape !== 'undefined') {
|
||||
return namedEscape;
|
||||
}
|
||||
|
||||
if (charCode >= 256) {
|
||||
return '&#' + charCode + ';';
|
||||
}
|
||||
|
||||
const hexValue = Buffer.from(String.fromCharCode(charCode), 'ascii').toString('hex');
|
||||
return `&#x${hexValue};`;
|
||||
};
|
||||
|
||||
|
||||
internals.isSafe = function (charCode) {
|
||||
|
||||
return (typeof internals.safeCharCodes[charCode] !== 'undefined');
|
||||
};
|
||||
|
||||
|
||||
internals.namedHtml = {
|
||||
'38': '&',
|
||||
'60': '<',
|
||||
'62': '>',
|
||||
'34': '"',
|
||||
'160': ' ',
|
||||
'162': '¢',
|
||||
'163': '£',
|
||||
'164': '¤',
|
||||
'169': '©',
|
||||
'174': '®'
|
||||
};
|
||||
|
||||
|
||||
internals.safeCharCodes = (function () {
|
||||
|
||||
const safe = {};
|
||||
|
||||
for (let i = 32; i < 123; ++i) {
|
||||
|
||||
if ((i >= 97) || // a-z
|
||||
(i >= 65 && i <= 90) || // A-Z
|
||||
(i >= 48 && i <= 57) || // 0-9
|
||||
i === 32 || // space
|
||||
i === 46 || // .
|
||||
i === 44 || // ,
|
||||
i === 45 || // -
|
||||
i === 58 || // :
|
||||
i === 95) { // _
|
||||
|
||||
safe[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return safe;
|
||||
}());
|
||||
+686
@@ -0,0 +1,686 @@
|
||||
'use strict';
|
||||
|
||||
// Load modules
|
||||
|
||||
const Assert = require('assert');
|
||||
const Crypto = require('crypto');
|
||||
const Path = require('path');
|
||||
|
||||
const DeepEqual = require('./deep-equal');
|
||||
const Escape = require('./escape');
|
||||
|
||||
|
||||
// Declare internals
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
// Deep object or array comparison
|
||||
|
||||
exports.deepEqual = DeepEqual;
|
||||
|
||||
|
||||
// Clone object or array
|
||||
|
||||
exports.clone = function (obj, options = {}, _seen = null) {
|
||||
|
||||
if (typeof obj !== 'object' ||
|
||||
obj === null) {
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
const seen = _seen || new Map();
|
||||
|
||||
const lookup = seen.get(obj);
|
||||
if (lookup) {
|
||||
return lookup;
|
||||
}
|
||||
|
||||
let newObj;
|
||||
let cloneDeep = false;
|
||||
const isArray = Array.isArray(obj);
|
||||
|
||||
if (!isArray) {
|
||||
if (Buffer.isBuffer(obj)) {
|
||||
newObj = Buffer.from(obj);
|
||||
}
|
||||
else if (obj instanceof Date) {
|
||||
newObj = new Date(obj.getTime());
|
||||
}
|
||||
else if (obj instanceof RegExp) {
|
||||
newObj = new RegExp(obj);
|
||||
}
|
||||
else {
|
||||
if (options.prototype !== false) { // Defaults to true
|
||||
const proto = Object.getPrototypeOf(obj);
|
||||
if (proto &&
|
||||
proto.isImmutable) {
|
||||
|
||||
newObj = obj;
|
||||
}
|
||||
else {
|
||||
newObj = Object.create(proto);
|
||||
cloneDeep = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
newObj = {};
|
||||
cloneDeep = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
newObj = [];
|
||||
cloneDeep = true;
|
||||
}
|
||||
|
||||
seen.set(obj, newObj);
|
||||
|
||||
if (cloneDeep) {
|
||||
const keys = internals.keys(obj, options);
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i];
|
||||
|
||||
if (isArray && key === 'length') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
|
||||
if (descriptor &&
|
||||
(descriptor.get ||
|
||||
descriptor.set)) {
|
||||
|
||||
Object.defineProperty(newObj, key, descriptor);
|
||||
}
|
||||
else {
|
||||
Object.defineProperty(newObj, key, {
|
||||
enumerable: descriptor ? descriptor.enumerable : true,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: exports.clone(obj[key], options, seen)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (isArray) {
|
||||
newObj.length = obj.length;
|
||||
}
|
||||
}
|
||||
|
||||
return newObj;
|
||||
};
|
||||
|
||||
|
||||
internals.keys = function (obj, options = {}) {
|
||||
|
||||
return options.symbols ? Reflect.ownKeys(obj) : Object.getOwnPropertyNames(obj);
|
||||
};
|
||||
|
||||
|
||||
// Merge all the properties of source into target, source wins in conflict, and by default null and undefined from source are applied
|
||||
|
||||
exports.merge = function (target, source, isNullOverride /* = true */, isMergeArrays /* = true */) {
|
||||
|
||||
exports.assert(target && typeof target === 'object', 'Invalid target value: must be an object');
|
||||
exports.assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
|
||||
|
||||
if (!source) {
|
||||
return target;
|
||||
}
|
||||
|
||||
if (Array.isArray(source)) {
|
||||
exports.assert(Array.isArray(target), 'Cannot merge array onto an object');
|
||||
if (isMergeArrays === false) { // isMergeArrays defaults to true
|
||||
target.length = 0; // Must not change target assignment
|
||||
}
|
||||
|
||||
for (let i = 0; i < source.length; ++i) {
|
||||
target.push(exports.clone(source[i]));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
const keys = internals.keys(source);
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i];
|
||||
if (key === '__proto__' ||
|
||||
!Object.prototype.propertyIsEnumerable.call(source, key)) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = source[key];
|
||||
if (value &&
|
||||
typeof value === 'object') {
|
||||
|
||||
if (!target[key] ||
|
||||
typeof target[key] !== 'object' ||
|
||||
(Array.isArray(target[key]) !== Array.isArray(value)) ||
|
||||
value instanceof Date ||
|
||||
Buffer.isBuffer(value) ||
|
||||
value instanceof RegExp) {
|
||||
|
||||
target[key] = exports.clone(value);
|
||||
}
|
||||
else {
|
||||
exports.merge(target[key], value, isNullOverride, isMergeArrays);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (value !== null &&
|
||||
value !== undefined) { // Explicit to preserve empty strings
|
||||
|
||||
target[key] = value;
|
||||
}
|
||||
else if (isNullOverride !== false) { // Defaults to true
|
||||
target[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
|
||||
// Apply options to a copy of the defaults
|
||||
|
||||
exports.applyToDefaults = function (defaults, options, isNullOverride) {
|
||||
|
||||
exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
|
||||
exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
|
||||
|
||||
if (!options) { // If no options, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const copy = exports.clone(defaults);
|
||||
|
||||
if (options === true) { // If options is set to true, use defaults
|
||||
return copy;
|
||||
}
|
||||
|
||||
return exports.merge(copy, options, isNullOverride === true, false);
|
||||
};
|
||||
|
||||
|
||||
// Clone an object except for the listed keys which are shallow copied
|
||||
|
||||
exports.cloneWithShallow = function (source, keys, options) {
|
||||
|
||||
if (!source ||
|
||||
typeof source !== 'object') {
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
const storage = internals.store(source, keys); // Move shallow copy items to storage
|
||||
const copy = exports.clone(source, options); // Deep copy the rest
|
||||
internals.restore(copy, source, storage); // Shallow copy the stored items and restore
|
||||
return copy;
|
||||
};
|
||||
|
||||
|
||||
internals.store = function (source, keys) {
|
||||
|
||||
const storage = new Map();
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i];
|
||||
const value = exports.reach(source, key);
|
||||
if (typeof value === 'object' ||
|
||||
typeof value === 'function') {
|
||||
|
||||
storage.set(key, value);
|
||||
internals.reachSet(source, key, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
return storage;
|
||||
};
|
||||
|
||||
|
||||
internals.restore = function (copy, source, storage) {
|
||||
|
||||
for (const [key, value] of storage) {
|
||||
internals.reachSet(copy, key, value);
|
||||
internals.reachSet(source, key, value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.reachSet = function (obj, key, value) {
|
||||
|
||||
const path = Array.isArray(key) ? key : key.split('.');
|
||||
let ref = obj;
|
||||
for (let i = 0; i < path.length; ++i) {
|
||||
const segment = path[i];
|
||||
if (i + 1 === path.length) {
|
||||
ref[segment] = value;
|
||||
}
|
||||
|
||||
ref = ref[segment];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Apply options to defaults except for the listed keys which are shallow copied from option without merging
|
||||
|
||||
exports.applyToDefaultsWithShallow = function (defaults, options, keys) {
|
||||
|
||||
exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
|
||||
exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object');
|
||||
exports.assert(keys && Array.isArray(keys), 'Invalid keys');
|
||||
|
||||
if (!options) { // If no options, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const copy = exports.cloneWithShallow(defaults, keys);
|
||||
|
||||
if (options === true) { // If options is set to true, use defaults
|
||||
return copy;
|
||||
}
|
||||
|
||||
const storage = internals.store(options, keys); // Move shallow copy items to storage
|
||||
exports.merge(copy, options, false, false); // Deep copy the rest
|
||||
internals.restore(copy, options, storage); // Shallow copy the stored items and restore
|
||||
return copy;
|
||||
};
|
||||
|
||||
|
||||
// Find the common unique items in two arrays
|
||||
|
||||
exports.intersect = function (array1, array2, justFirst) {
|
||||
|
||||
if (!array1 ||
|
||||
!array2) {
|
||||
|
||||
return (justFirst ? null : []);
|
||||
}
|
||||
|
||||
const common = [];
|
||||
const hash = (Array.isArray(array1) ? new Set(array1) : array1);
|
||||
const found = new Set();
|
||||
for (const value of array2) {
|
||||
if (internals.has(hash, value) &&
|
||||
!found.has(value)) {
|
||||
|
||||
if (justFirst) {
|
||||
return value;
|
||||
}
|
||||
|
||||
common.push(value);
|
||||
found.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return (justFirst ? null : common);
|
||||
};
|
||||
|
||||
|
||||
internals.has = function (ref, key) {
|
||||
|
||||
if (typeof ref.has === 'function') {
|
||||
return ref.has(key);
|
||||
}
|
||||
|
||||
return ref[key] !== undefined;
|
||||
};
|
||||
|
||||
|
||||
// Test if the reference contains the values
|
||||
|
||||
exports.contain = function (ref, values, options = {}) { // options: { deep, once, only, part, symbols }
|
||||
|
||||
/*
|
||||
string -> string(s)
|
||||
array -> item(s)
|
||||
object -> key(s)
|
||||
object -> object (key:value)
|
||||
*/
|
||||
|
||||
let valuePairs = null;
|
||||
if (typeof ref === 'object' &&
|
||||
typeof values === 'object' &&
|
||||
!Array.isArray(ref) &&
|
||||
!Array.isArray(values)) {
|
||||
|
||||
valuePairs = values;
|
||||
const symbols = Object.getOwnPropertySymbols(values).filter(Object.prototype.propertyIsEnumerable.bind(values));
|
||||
values = [...Object.keys(values), ...symbols];
|
||||
}
|
||||
else {
|
||||
values = [].concat(values);
|
||||
}
|
||||
|
||||
exports.assert(typeof ref === 'string' || typeof ref === 'object', 'Reference must be string or an object');
|
||||
exports.assert(values.length, 'Values array cannot be empty');
|
||||
|
||||
let compare;
|
||||
let compareFlags;
|
||||
if (options.deep) {
|
||||
compare = exports.deepEqual;
|
||||
|
||||
const hasOnly = options.hasOwnProperty('only');
|
||||
const hasPart = options.hasOwnProperty('part');
|
||||
|
||||
compareFlags = {
|
||||
prototype: hasOnly ? options.only : hasPart ? !options.part : false,
|
||||
part: hasOnly ? !options.only : hasPart ? options.part : false
|
||||
};
|
||||
}
|
||||
else {
|
||||
compare = (a, b) => a === b;
|
||||
}
|
||||
|
||||
let misses = false;
|
||||
const matches = new Array(values.length);
|
||||
for (let i = 0; i < matches.length; ++i) {
|
||||
matches[i] = 0;
|
||||
}
|
||||
|
||||
if (typeof ref === 'string') {
|
||||
let pattern = '(';
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
const value = values[i];
|
||||
exports.assert(typeof value === 'string', 'Cannot compare string reference to non-string value');
|
||||
pattern += (i ? '|' : '') + exports.escapeRegex(value);
|
||||
}
|
||||
|
||||
const regex = new RegExp(pattern + ')', 'g');
|
||||
const leftovers = ref.replace(regex, ($0, $1) => {
|
||||
|
||||
const index = values.indexOf($1);
|
||||
++matches[index];
|
||||
return ''; // Remove from string
|
||||
});
|
||||
|
||||
misses = !!leftovers;
|
||||
}
|
||||
else if (Array.isArray(ref)) {
|
||||
const onlyOnce = !!(options.only && options.once);
|
||||
if (onlyOnce && ref.length !== values.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < ref.length; ++i) {
|
||||
let matched = false;
|
||||
for (let j = 0; j < values.length && matched === false; ++j) {
|
||||
if (!onlyOnce || matches[j] === 0) {
|
||||
matched = compare(values[j], ref[i], compareFlags) && j;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched !== false) {
|
||||
++matches[matched];
|
||||
}
|
||||
else {
|
||||
misses = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const keys = internals.keys(ref, options);
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i];
|
||||
const pos = values.indexOf(key);
|
||||
if (pos !== -1) {
|
||||
if (valuePairs &&
|
||||
!compare(valuePairs[key], ref[key], compareFlags)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
++matches[pos];
|
||||
}
|
||||
else {
|
||||
misses = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.only) {
|
||||
if (misses || !options.once) {
|
||||
return !misses;
|
||||
}
|
||||
}
|
||||
|
||||
let result = false;
|
||||
for (let i = 0; i < matches.length; ++i) {
|
||||
result = result || !!matches[i];
|
||||
if ((options.once && matches[i] > 1) ||
|
||||
(!options.part && !matches[i])) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// Flatten array
|
||||
|
||||
exports.flatten = function (array, target) {
|
||||
|
||||
const result = target || [];
|
||||
|
||||
for (let i = 0; i < array.length; ++i) {
|
||||
if (Array.isArray(array[i])) {
|
||||
exports.flatten(array[i], result);
|
||||
}
|
||||
else {
|
||||
result.push(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
// Convert an object key chain string ('a.b.c') to reference (object[a][b][c])
|
||||
|
||||
exports.reach = function (obj, chain, options) {
|
||||
|
||||
if (chain === false ||
|
||||
chain === null ||
|
||||
typeof chain === 'undefined') {
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
if (typeof options === 'string') {
|
||||
options = { separator: options };
|
||||
}
|
||||
|
||||
const isChainArray = Array.isArray(chain);
|
||||
|
||||
exports.assert(!isChainArray || !options.separator, 'Separator option no valid for array-based chain');
|
||||
|
||||
const path = isChainArray ? chain : chain.split(options.separator || '.');
|
||||
let ref = obj;
|
||||
for (let i = 0; i < path.length; ++i) {
|
||||
let key = path[i];
|
||||
|
||||
if (Array.isArray(ref)) {
|
||||
const number = Number(key);
|
||||
|
||||
if (Number.isInteger(number) && number < 0) {
|
||||
key = ref.length + number;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ref ||
|
||||
!((typeof ref === 'object' || typeof ref === 'function') && key in ref) ||
|
||||
(typeof ref !== 'object' && options.functions === false)) { // Only object and function can have properties
|
||||
|
||||
exports.assert(!options.strict || i + 1 === path.length, 'Missing segment', key, 'in reach path ', chain);
|
||||
exports.assert(typeof ref === 'object' || options.functions === true || typeof ref !== 'function', 'Invalid segment', key, 'in reach path ', chain);
|
||||
ref = options.default;
|
||||
break;
|
||||
}
|
||||
|
||||
ref = ref[key];
|
||||
}
|
||||
|
||||
return ref;
|
||||
};
|
||||
|
||||
|
||||
exports.reachTemplate = function (obj, template, options) {
|
||||
|
||||
return template.replace(/{([^}]+)}/g, ($0, chain) => {
|
||||
|
||||
const value = exports.reach(obj, chain, options);
|
||||
return (value === undefined || value === null ? '' : value);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.assert = function (condition, ...args) {
|
||||
|
||||
if (condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length === 1 && args[0] instanceof Error) {
|
||||
throw args[0];
|
||||
}
|
||||
|
||||
const msgs = args
|
||||
.filter((arg) => arg !== '')
|
||||
.map((arg) => {
|
||||
|
||||
return typeof arg === 'string' ? arg : arg instanceof Error ? arg.message : exports.stringify(arg);
|
||||
});
|
||||
|
||||
throw new Assert.AssertionError({
|
||||
message: msgs.join(' ') || 'Unknown error',
|
||||
actual: false,
|
||||
expected: true,
|
||||
operator: '==',
|
||||
stackStartFunction: exports.assert
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
exports.Bench = function () {
|
||||
|
||||
this.ts = 0;
|
||||
this.reset();
|
||||
};
|
||||
|
||||
|
||||
exports.Bench.prototype.reset = function () {
|
||||
|
||||
this.ts = exports.Bench.now();
|
||||
};
|
||||
|
||||
|
||||
exports.Bench.prototype.elapsed = function () {
|
||||
|
||||
return exports.Bench.now() - this.ts;
|
||||
};
|
||||
|
||||
|
||||
exports.Bench.now = function () {
|
||||
|
||||
const ts = process.hrtime();
|
||||
return (ts[0] * 1e3) + (ts[1] / 1e6);
|
||||
};
|
||||
|
||||
|
||||
// Escape string for Regex construction
|
||||
|
||||
exports.escapeRegex = function (string) {
|
||||
|
||||
// Escape ^$.*+-?=!:|\/()[]{},
|
||||
return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
|
||||
};
|
||||
|
||||
|
||||
// Escape attribute value for use in HTTP header
|
||||
|
||||
exports.escapeHeaderAttribute = function (attribute) {
|
||||
|
||||
// Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
|
||||
|
||||
exports.assert(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/.test(attribute), 'Bad attribute value (' + attribute + ')');
|
||||
|
||||
return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"'); // Escape quotes and slash
|
||||
};
|
||||
|
||||
|
||||
exports.escapeHtml = function (string) {
|
||||
|
||||
return Escape.escapeHtml(string);
|
||||
};
|
||||
|
||||
|
||||
exports.escapeJson = function (string) {
|
||||
|
||||
return Escape.escapeJson(string);
|
||||
};
|
||||
|
||||
|
||||
exports.once = function (method) {
|
||||
|
||||
if (method._hoekOnce) {
|
||||
return method;
|
||||
}
|
||||
|
||||
let once = false;
|
||||
const wrapped = function (...args) {
|
||||
|
||||
if (!once) {
|
||||
once = true;
|
||||
method(...args);
|
||||
}
|
||||
};
|
||||
|
||||
wrapped._hoekOnce = true;
|
||||
return wrapped;
|
||||
};
|
||||
|
||||
|
||||
exports.ignore = function () { };
|
||||
|
||||
|
||||
exports.uniqueFilename = function (path, extension) {
|
||||
|
||||
if (extension) {
|
||||
extension = extension[0] !== '.' ? '.' + extension : extension;
|
||||
}
|
||||
else {
|
||||
extension = '';
|
||||
}
|
||||
|
||||
path = Path.resolve(path);
|
||||
const name = [Date.now(), process.pid, Crypto.randomBytes(8).toString('hex')].join('-') + extension;
|
||||
return Path.join(path, name);
|
||||
};
|
||||
|
||||
|
||||
exports.stringify = function (...args) {
|
||||
|
||||
try {
|
||||
return JSON.stringify.apply(null, args);
|
||||
}
|
||||
catch (err) {
|
||||
return '[Cannot display object: ' + err.message + ']';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.wait = function (timeout) {
|
||||
|
||||
return new Promise((resolve) => setTimeout(resolve, timeout));
|
||||
};
|
||||
|
||||
|
||||
exports.block = function () {
|
||||
|
||||
return new Promise(exports.ignore);
|
||||
};
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"_from": "hoek@6.x.x",
|
||||
"_id": "hoek@6.1.3",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==",
|
||||
"_location": "/topo/hoek",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "hoek@6.x.x",
|
||||
"name": "hoek",
|
||||
"escapedName": "hoek",
|
||||
"rawSpec": "6.x.x",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "6.x.x"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/topo"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz",
|
||||
"_shasum": "73b7d33952e01fe27a38b0457294b79dd8da242c",
|
||||
"_spec": "hoek@6.x.x",
|
||||
"_where": "C:\\Daten\\Git\\Tumortisch\\node_modules\\topo",
|
||||
"bugs": {
|
||||
"url": "https://github.com/hapijs/hoek/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {},
|
||||
"deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.",
|
||||
"description": "General purpose node utilities",
|
||||
"devDependencies": {
|
||||
"code": "5.x.x",
|
||||
"lab": "18.x.x"
|
||||
},
|
||||
"homepage": "https://github.com/hapijs/hoek#readme",
|
||||
"keywords": [
|
||||
"utilities"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "lib/index.js",
|
||||
"name": "hoek",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/hapijs/hoek.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "lab -a code -t 100 -L",
|
||||
"test-cov-html": "lab -a code -t 100 -L -r html -o coverage.html"
|
||||
},
|
||||
"version": "6.1.3"
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"_from": "topo@3.x.x",
|
||||
"_id": "topo@3.0.3",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==",
|
||||
"_location": "/topo",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "topo@3.x.x",
|
||||
"name": "topo",
|
||||
"escapedName": "topo",
|
||||
"rawSpec": "3.x.x",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "3.x.x"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/joi"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz",
|
||||
"_shasum": "d5a67fb2e69307ebeeb08402ec2a2a6f5f7ad95c",
|
||||
"_spec": "topo@3.x.x",
|
||||
"_where": "C:\\Daten\\Git\\Tumortisch\\node_modules\\joi",
|
||||
"bugs": {
|
||||
"url": "https://github.com/hapijs/topo/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"hoek": "6.x.x"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "Topological sorting with grouping support",
|
||||
"devDependencies": {
|
||||
"code": "5.x.x",
|
||||
"lab": "17.x.x"
|
||||
},
|
||||
"homepage": "https://github.com/hapijs/topo#readme",
|
||||
"keywords": [
|
||||
"topological",
|
||||
"sort",
|
||||
"toposort",
|
||||
"topsort"
|
||||
],
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "lib/index.js",
|
||||
"name": "topo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/hapijs/topo.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "lab -a code -t 100 -L",
|
||||
"test-cov-html": "lab -a code -t 100 -L -r html -o coverage.html"
|
||||
},
|
||||
"version": "3.0.3"
|
||||
}
|
||||
Reference in New Issue
Block a user