Comparing version 1.0.1 to 1.0.2
{ | ||
"optOut": false, | ||
"lastUpdateCheck": 1664845901965 | ||
"lastUpdateCheck": 1665021956542 | ||
} |
{ | ||
"name": "manyfest", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "JSON Object Manifest for Data Description and Parsing", | ||
"main": "index.js", | ||
"main": "source/Manyfest.js", | ||
"scripts": { | ||
@@ -7,0 +7,0 @@ "docker-dev-build-image": "docker build ./ -f Dockerfile_LUXURYCode -t retold/manyfest:local", |
346
README.md
@@ -40,3 +40,3 @@ # Manyfest | ||
``` | ||
```javascript | ||
const libManyfest = require('Manyfest'); | ||
@@ -92,3 +92,3 @@ | ||
``` | ||
```javascript | ||
let animalManyfest = new libManyfest( | ||
@@ -113,3 +113,4 @@ { | ||
"Hash":"ComfET", | ||
"Description":"The most comfortable temperature for this animal to survive in."} | ||
"Description":"The most comfortable temperature for this animal to survive in." | ||
} | ||
} | ||
@@ -140,3 +141,3 @@ }); | ||
``` | ||
```javascript | ||
// Write Code | ||
@@ -149,3 +150,3 @@ let newAnimal = {}; | ||
``` | ||
```javascript | ||
// Read Code | ||
@@ -165,3 +166,3 @@ let newAnimal = {}; | ||
``` | ||
```javascript | ||
let newAnimal = {}; | ||
@@ -187,3 +188,3 @@ | ||
``` | ||
```javascript | ||
let favAnimal = favoriteAnimalAPI(); | ||
@@ -200,3 +201,3 @@ | ||
``` | ||
```javascript | ||
const libManyfest = require('Manyfest'); | ||
@@ -219,3 +220,3 @@ | ||
``` | ||
```javascript | ||
const libManyfest = require('Manyfest'); | ||
@@ -243,2 +244,327 @@ | ||
With manyfest, you can easily create a description for each API and code against getting values by hash. This abstracts the complexity of multiple API services without requiring you to marshal it into your own persistence format. | ||
With manyfest, you can easily create a description for each API and code against getting values by hash. This abstracts the complexity of multiple API services without requiring you to marshal it into your own persistence format. | ||
## Archive dot Org | ||
Modern APIs are super complicated. And worse, they change. Let's take a real example. [Archive.org](https://archive.org/) is a wonderful resource for downloading awesome content gathered from the web and such. | ||
There is an API to access their data. It's ... really messy, the data you get back. below is the JSON for a single video (a rad Count Chocula commercial from 1971) -- it takes quite a bit of scroll to get down to the bottom. | ||
![Count Chocula will Rise Again](http://ia800202.us.archive.org/7/items/FrankenberryCountChoculaTevevisionCommercial1971/frankerberry_countchockula_1971.0001.gif) | ||
```JSON | ||
{ | ||
"created": 1664830085, | ||
"d1": "ia600202.us.archive.org", | ||
"d2": "ia800202.us.archive.org", | ||
"dir": "/7/items/FrankenberryCountChoculaTevevisionCommercial1971", | ||
"files": [ | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000001.jpg", | ||
"source": "derivative", | ||
"format": "Thumbnail", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336956", | ||
"size": "838", | ||
"md5": "e47269cd5a82db9594f265a65785ec12", | ||
"crc32": "165c668b", | ||
"sha1": "383303d9546c381267569ad4e33aff691f0bb8c7" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000004.jpg", | ||
"source": "derivative", | ||
"format": "Thumbnail", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336957", | ||
"size": "6843", | ||
"md5": "c93fa52000ab4665e69b25c403e11aff", | ||
"crc32": "9444e6f6", | ||
"sha1": "716b4f9950b8147f51d3265f9c62ff86451308d5" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000009.jpg", | ||
"source": "derivative", | ||
"format": "Thumbnail", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336957", | ||
"size": "8388", | ||
"md5": "30eb3eb4cbbdfa08d531a0a74da7c000", | ||
"crc32": "be874a9e", | ||
"sha1": "0c392d777609e967b6022be27edad678c5ae74e2" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000014.jpg", | ||
"source": "derivative", | ||
"format": "Thumbnail", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336958", | ||
"size": "5993", | ||
"md5": "4e9ebc3d076bec8cf7dfe76795f8c769", | ||
"crc32": "912ec98c", | ||
"sha1": "01dc49c852e1bbb421199450dd902935c62b06de" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000019.jpg", | ||
"source": "derivative", | ||
"format": "Thumbnail", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336958", | ||
"size": "4951", | ||
"md5": "59f190f0c5b0a048415b26412860b6dd", | ||
"crc32": "a70a30b1", | ||
"sha1": "a284af9757cb24d28f96ec88ec1b1c23a8cea9fe" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000024.jpg", | ||
"source": "derivative", | ||
"format": "Thumbnail", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336959", | ||
"size": "3383", | ||
"md5": "be2a908acd563b896e7758b598295148", | ||
"crc32": "ed467831", | ||
"sha1": "94c001e72ebc86d837a78c61a004db9ab9d597bd" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000029.jpg", | ||
"source": "derivative", | ||
"format": "Thumbnail", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336960", | ||
"size": "3503", | ||
"md5": "c82199d09be07633000fd07b363dd8a3", | ||
"crc32": "a1fd79cb", | ||
"sha1": "2bc8e761edb24a441fa5906dda1c424e1f98a47a" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971_archive.torrent", | ||
"source": "metadata", | ||
"btih": "de6b371e7cc3c83db1cc08150500753eae533409", | ||
"mtime": "1542761794", | ||
"size": "4093", | ||
"md5": "a275d3b4028cccb5bea8b47a88c838af", | ||
"crc32": "5ffa7334", | ||
"sha1": "af8222637b574cba1360d0ea77e231640ffd43c4", | ||
"format": "Archive BitTorrent" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971_files.xml", | ||
"source": "metadata", | ||
"format": "Metadata", | ||
"md5": "3a7e87b08bed1e203a5858b31352c110" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971_meta.xml", | ||
"source": "metadata", | ||
"format": "Metadata", | ||
"mtime": "1542761793", | ||
"size": "1371", | ||
"md5": "0b9c9bf21b9a26aea43a2f735b404624", | ||
"crc32": "41077288", | ||
"sha1": "22e6f2c73bf63072f671d846355da2785db51dbd" | ||
}, | ||
{ | ||
"name": "FrankenberryCountChoculaTevevisionCommercial1971_reviews.xml", | ||
"source": "original", | ||
"mtime": "1466898697", | ||
"size": "620", | ||
"md5": "260bfba5d696772445dcc7ff6e6d5bdb", | ||
"crc32": "25ea3229", | ||
"sha1": "7d541f18fcd5ad9c6e593afe5a80f18771f23b32", | ||
"format": "Metadata" | ||
}, | ||
{ | ||
"name": "__ia_thumb.jpg", | ||
"source": "original", | ||
"mtime": "1539115881", | ||
"size": "7481", | ||
"md5": "8cec324fa0016fd77cc04e6a4b2ebb00", | ||
"crc32": "d9e1b316", | ||
"sha1": "4dab42952fe0405a3b7f80146636b33d7b1bd01e", | ||
"format": "Item Tile", | ||
"rotation": "0" | ||
}, | ||
{ | ||
"name": "frankerberry_countchockula_1971.0001.gif", | ||
"source": "derivative", | ||
"format": "Animated GIF", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336965", | ||
"size": "101114", | ||
"md5": "b78a13094030f104900eb996bafe2b7d", | ||
"crc32": "6650cd8", | ||
"sha1": "669798c037205cac14f70592deef6f7831b3d4a1" | ||
}, | ||
{ | ||
"name": "frankerberry_countchockula_1971.0001.mpg", | ||
"source": "original", | ||
"format": "MPEG2", | ||
"mtime": "1296335803", | ||
"size": "31625216", | ||
"md5": "762ba18b026b85b3f074523e7fcb4db0", | ||
"crc32": "42347f78", | ||
"sha1": "41162dc2d1a91b618124c84628d0c231544a02be", | ||
"length": "31.14", | ||
"height": "480", | ||
"width": "640" | ||
}, | ||
{ | ||
"name": "frankerberry_countchockula_1971.0001.mpg.idx", | ||
"source": "derivative", | ||
"format": "Video Index", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336956", | ||
"size": "31141", | ||
"md5": "49423e072726e4ea3cdd8ebdd26c7dfc", | ||
"crc32": "ae969a68", | ||
"sha1": "805782cd2d0f9002555816daadf3b8607e621f79" | ||
}, | ||
{ | ||
"name": "frankerberry_countchockula_1971.0001.ogv", | ||
"source": "derivative", | ||
"format": "Ogg Video", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336994", | ||
"size": "2248166", | ||
"md5": "f1b933e97ce63594fb28a0a019ff3436", | ||
"crc32": "a2a0e5e9", | ||
"sha1": "a6bf0aec9f006baeca37c03f586686ebe685d59b", | ||
"length": "31.15", | ||
"height": "300", | ||
"width": "400" | ||
}, | ||
{ | ||
"name": "frankerberry_countchockula_1971.0001_512kb.mp4", | ||
"source": "derivative", | ||
"format": "512Kb MPEG4", | ||
"original": "frankerberry_countchockula_1971.0001.mpg", | ||
"mtime": "1296336977", | ||
"size": "2378677", | ||
"md5": "a7750839519c61ba3bb99fc66b32011d", | ||
"crc32": "4dbd37c8", | ||
"sha1": "3929314c192dec006fac2739bcb4730788e8c068", | ||
"length": "31.13", | ||
"height": "240", | ||
"width": "320" | ||
} | ||
], | ||
"files_count": 17, | ||
"item_last_updated": 1542761794, | ||
"item_size": 36431778, | ||
"metadata": { | ||
"identifier": "FrankenberryCountChoculaTevevisionCommercial1971", | ||
"title": "Franken Berry / Count Chocula : Tevevision Commercial 1971", | ||
"creator": "General Mills", | ||
"mediatype": "movies", | ||
"collection": [ | ||
"classic_tv_commercials", | ||
"television" | ||
], | ||
"description": "Count Chocula and Franken Berry were both introduced in 1971. Boo Berry Cereal appeared in 1973 followed by Fruit Brute in 1974. Yummy Mummy appeared more than a decade later in 1988 - completing the the group known as the General Mills Monster Cereals.", | ||
"subject": "Third Eye Cinema; Classic Television Commercials; animation; cartoons;General Mills", | ||
"licenseurl": "http://creativecommons.org/publicdomain/mark/1.0/", | ||
"publicdate": "2011-01-29 21:36:42", | ||
"addeddate": "2011-01-29 21:35:38", | ||
"uploader": "bolexman@msn.com", | ||
"updater": [ | ||
"Bolexman", | ||
"Bolexman", | ||
"Jeff Kaplan" | ||
], | ||
"updatedate": [ | ||
"2011-01-29 21:45:38", | ||
"2011-01-29 21:55:46", | ||
"2011-01-29 23:04:55" | ||
], | ||
"sound": "sound", | ||
"color": "color", | ||
"runtime": "0:31", | ||
"backup_location": "ia903608_22", | ||
"ia_orig__runtime": "31 seconds" | ||
}, | ||
"reviews": [ | ||
{ | ||
"reviewbody": "Sugar cereal cartoon Karloff and Lugosi argue self-importance pre Lorre ghost. Interesting how kids still know the voices without any idea of the origins.", | ||
"reviewtitle": "pre booberry", | ||
"reviewer": "outofthebox", | ||
"reviewdate": "2016-06-25 23:51:36", | ||
"createdate": "2016-06-25 23:51:36", | ||
"stars": "4" | ||
} | ||
], | ||
"server": "ia800202.us.archive.org", | ||
"uniq": 1957612749, | ||
"workable_servers": [ | ||
"ia800202.us.archive.org", | ||
"ia600202.us.archive.org" | ||
] | ||
} | ||
``` | ||
### A Manyfest Schema for Count Chocula to Thrive In | ||
With just a small number of element descriptors, we can make this huge blob of JSON very usable for a developer. | ||
```JSON | ||
{ | ||
"Scope": "Archive.org", | ||
"Descriptors": { | ||
"d1": { | ||
"Hash": "Server", | ||
"Name": "Server", | ||
"Description": "The primary server to download these files from.", | ||
"DataType": "String" | ||
}, | ||
"d2": { | ||
"Hash": "ServerAlternate", | ||
"Name": "Alternate Server", | ||
"Description": "The alternate server to download these files from.", | ||
"DataType": "String" | ||
}, | ||
"dir": { | ||
"Hash": "Path", | ||
"Name": "Server URL Path", | ||
"NameShort": "Path", | ||
"Description": "The path on the server where these files are located." | ||
}, | ||
"metadata.identifier": { | ||
"Hash": "GUID", | ||
"Name": "Globally Unique Identifier", | ||
"NameShort": "GUID", | ||
"Description": "Archive.org unique identifier string." | ||
}, | ||
"metadata.title": { | ||
"Hash": "Title", | ||
"Name": "Title", | ||
"NameShort": "Title", | ||
"Description": "The title of the media item." | ||
}, | ||
"metadata.creator": { | ||
"Hash": "Creator", | ||
"Name": "Creator", | ||
"NameShort": "Creator", | ||
"Description": "The creator of the media item." | ||
}, | ||
"metadata.mediatype": { | ||
"Hash": "Type", | ||
"Name": "Media Type", | ||
"NameShort": "Type", | ||
"Description": "The type of media item." | ||
} | ||
} | ||
} | ||
``` | ||
These two JSON files are in the [examples/chocula](https://github.com/stevenvelozo/manyfest/tree/main/examples/chocula) folder along with a javascript file `Chocula.js` you can try out yourself and hack on. | ||
``` | ||
let libManyfest = require('../../source/Manyfest.js'); | ||
let dataArchiveOrg = require(`./Data-Archive-org-Frankenberry.json`); | ||
let schemaArchiveOrg = require(`./Schema-Archive-org-Item.json`); | ||
let _Schema = new libManyfest(schemaArchiveOrg); | ||
console.log(`The URL for "${_Schema.getValueByHash(dataArchiveOrg,'Title')}" is: ${_Schema.getValueByHash(dataArchiveOrg,'Server')}${_Schema.getValueByHash(dataArchiveOrg,'Path')}`); | ||
``` | ||
@@ -192,2 +192,15 @@ /** | ||
cleanWrapCharacters (pCharacter, pString) | ||
{ | ||
if (pString.startsWith(pCharacter) && pString.endsWith(pCharacter)) | ||
{ | ||
return pString.substring(1, pString.length - 1); | ||
} | ||
else | ||
{ | ||
return pString; | ||
} | ||
} | ||
// Get the value of an element at an address | ||
@@ -201,8 +214,74 @@ getValueAtAddress (pObject, pAddress) | ||
// TODO: Make this work for things like SomeRootObject.Metadata["Some.People.Use.Bad.Object.Property.Names"] | ||
let tmpSeparatorIndex = pAddress.indexOf('.'); | ||
// This is the terminal address string (no more dots so the RECUSION ENDS IN HERE somehow) | ||
if (tmpSeparatorIndex === -1) | ||
{ | ||
// Now is the point in recursion to return the value in the address | ||
return pObject[pAddress]; | ||
// Check if it's a boxed property | ||
let tmpBracketStartIndex = pAddress.indexOf('['); | ||
let tmpBracketStopIndex = pAddress.indexOf(']'); | ||
// Boxed elements look like this: | ||
// MyValues[10] | ||
// MyValues['Name'] | ||
// MyValues["Age"] | ||
// MyValues[`Cost`] | ||
// | ||
// When we are passed SomeObject["Name"] this code below recurses as if it were SomeObject.Name | ||
// The requirements to detect a boxed element are: | ||
// 1) The start bracket is after character 0 | ||
if ((tmpBracketStartIndex > 0) | ||
// 2) The end bracket has something between them | ||
&& (tmpBracketStopIndex > tmpBracketStartIndex) | ||
// 3) There is data | ||
&& (tmpBracketStopIndex - tmpBracketStartIndex > 0)) | ||
{ | ||
// The "Name" of the Object contained too the left of the bracket | ||
let tmpBoxedPropertyName = pAddress.substring(0, tmpBracketStartIndex).trim(); | ||
// If the subproperty doesn't test as a proper Object, none of the rest of this is possible. | ||
// This is a rare case where Arrays testing as Objects is useful | ||
if (typeof(pObject[tmpBoxedPropertyName]) !== 'object') | ||
{ | ||
return undefined; | ||
} | ||
// The "Reference" to the property within it, either an array element or object property | ||
let tmpBoxedPropertyReference = pAddress.substring(tmpBracketStartIndex+1, tmpBracketStopIndex).trim(); | ||
// Attempt to parse the reference as a number, which will be used as an array element | ||
let tmpBoxedPropertyNumber = parseInt(tmpBoxedPropertyReference, 10); | ||
// Guard: If the referrant is a number and the boxed property is not an array, or vice versa, return undefined. | ||
// This seems confusing to me at first read, so explaination: | ||
// Is the Boxed Object an Array? TRUE | ||
// And is the Reference inside the boxed Object not a number? TRUE | ||
// --> So when these are in agreement, it's an impossible access state | ||
if (Array.isArray(pObject[tmpBoxedPropertyName]) == isNaN(tmpBoxedPropertyNumber)) | ||
{ | ||
return undefined; | ||
} | ||
// 4) If the middle part is *only* a number (no single, double or backtick quotes) it is an array element, | ||
// otherwise we will try to treat it as a dynamic object property. | ||
if (isNaN(tmpBoxedPropertyNumber)) | ||
{ | ||
// This isn't a number ... let's treat it as a dynamic object property. | ||
// We would expect the property to be wrapped in some kind of quotes so strip them | ||
tmpBoxedPropertyReference = this.cleanWrapCharacters('"', tmpBoxedPropertyReference); | ||
tmpBoxedPropertyReference = this.cleanWrapCharacters('`', tmpBoxedPropertyReference); | ||
tmpBoxedPropertyReference = this.cleanWrapCharacters("'", tmpBoxedPropertyReference); | ||
// Return the value in the property | ||
return pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference]; | ||
} | ||
else | ||
{ | ||
return pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber]; | ||
} | ||
} | ||
else | ||
{ | ||
// Now is the point in recursion to return the value in the address | ||
return pObject[pAddress]; | ||
} | ||
} | ||
@@ -214,2 +293,66 @@ else | ||
// Test if the tmpNewAddress is an array or object | ||
// Check if it's a boxed property | ||
let tmpBracketStartIndex = tmpSubObjectName.indexOf('['); | ||
let tmpBracketStopIndex = tmpSubObjectName.indexOf(']'); | ||
// Boxed elements look like this: | ||
// MyValues[42] | ||
// MyValues['Color'] | ||
// MyValues["Weight"] | ||
// MyValues[`Diameter`] | ||
// | ||
// When we are passed SomeObject["Name"] this code below recurses as if it were SomeObject.Name | ||
// The requirements to detect a boxed element are: | ||
// 1) The start bracket is after character 0 | ||
if ((tmpBracketStartIndex > 0) | ||
// 2) The end bracket has something between them | ||
&& (tmpBracketStopIndex > tmpBracketStartIndex) | ||
// 3) There is data | ||
&& (tmpBracketStopIndex - tmpBracketStartIndex > 0)) | ||
{ | ||
let tmpBoxedPropertyName = tmpSubObjectName.substring(0, tmpBracketStartIndex).trim(); | ||
let tmpBoxedPropertyReference = tmpSubObjectName.substring(tmpBracketStartIndex+1, tmpBracketStopIndex).trim(); | ||
let tmpBoxedPropertyNumber = parseInt(tmpBoxedPropertyReference, 10); | ||
// Guard: If the referrant is a number and the boxed property is not an array, or vice versa, return undefined. | ||
// This seems confusing to me at first read, so explaination: | ||
// Is the Boxed Object an Array? TRUE | ||
// And is the Reference inside the boxed Object not a number? TRUE | ||
// --> So when these are in agreement, it's an impossible access state | ||
// This could be a failure in the recursion chain because they passed something like this in: | ||
// StudentData.Sections.Algebra.Students[1].Tardy | ||
// BUT | ||
// StudentData.Sections.Algebra.Students[1] is an object, so the .Tardy is not possible to access | ||
// This could be a failure in the recursion chain because they passed something like this in: | ||
// StudentData.Sections.Algebra.Students["JaneDoe"].Grade | ||
// BUT | ||
// StudentData.Sections.Algebra.Students["JaneDoe"] is an array, so the .Grade is not possible to access | ||
// TODO: Should this be an error or something? Should we keep a log of failures like this? | ||
if (Array.isArray(pObject[tmpBoxedPropertyName]) == isNaN(tmpBoxedPropertyNumber)) | ||
{ | ||
return undefined; | ||
} | ||
//This is a bracketed value | ||
// 4) If the middle part is *only* a number (no single, double or backtick quotes) it is an array element, | ||
// otherwise we will try to reat it as a dynamic object property. | ||
if (isNaN(tmpBoxedPropertyNumber)) | ||
{ | ||
// This isn't a number ... let's treat it as a dynanmic object property. | ||
tmpBoxedPropertyReference = this.cleanWrapCharacters('"', tmpBoxedPropertyReference); | ||
tmpBoxedPropertyReference = this.cleanWrapCharacters('`', tmpBoxedPropertyReference); | ||
tmpBoxedPropertyReference = this.cleanWrapCharacters("'", tmpBoxedPropertyReference); | ||
// Recurse directly into the subobject | ||
return this.getValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference], tmpNewAddress); | ||
} | ||
else | ||
{ | ||
// We parsed a valid number out of the boxed property name, so recurse into the array | ||
return this.getValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber], tmpNewAddress); | ||
} | ||
} | ||
// If there is an object property already named for the sub object, but it isn't an object | ||
@@ -216,0 +359,0 @@ // then the system can't set the value in there. Error and abort! |
@@ -19,9 +19,3 @@ /** | ||
{ | ||
setup | ||
( | ||
()=> | ||
{ | ||
// No custom per-test spool-up required | ||
} | ||
); | ||
setup (()=> {} ); | ||
@@ -49,3 +43,3 @@ suite | ||
{ | ||
let _Manyfest = new libManyfest({}); | ||
let _Manyfest = new libManyfest(); | ||
Expect(_Manyfest.scope) | ||
@@ -60,111 +54,3 @@ .to.be.a('string', 'Manyfest should have a scope.'); | ||
); | ||
suite | ||
( | ||
'Object Access', | ||
()=> | ||
{ | ||
test | ||
( | ||
'Properties should be gettable and settable without a schema.', | ||
(fTestComplete)=> | ||
{ | ||
let _Manyfest = new libManyfest({}); | ||
let _SimpleObject = {Name:'Bob',Age:31,Pets:{Fido:'Dog',Spot:'Cat'}}; | ||
Expect(_Manyfest.getValueAtAddress(_SimpleObject,'Name')) | ||
.to.equal('Bob'); | ||
_Manyfest.setValueAtAddress(_SimpleObject,'Name','Jim'); | ||
Expect(_Manyfest.getValueAtAddress(_SimpleObject,'Name')) | ||
.to.equal('Jim'); | ||
fTestComplete(); | ||
} | ||
); | ||
test | ||
( | ||
'Properties should be accessible via Hash.', | ||
(fTestComplete)=> | ||
{ | ||
let animalManyfest = new libManyfest( | ||
{ | ||
"Scope": "Animal", | ||
"Descriptors": | ||
{ | ||
"IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" }, | ||
"Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." }, | ||
"Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." }, | ||
"MedicalStats": | ||
{ | ||
"Name":"Medical Statistics", "Description":"Basic medical statistics for this animal" | ||
}, | ||
"MedicalStats.Temps.MinET": { "Name":"Minimum Environmental Temperature", "NameShort":"MinET", "Description":"Safest minimum temperature for this animal to survive in."}, | ||
"MedicalStats.Temps.MaxET": { "Name":"Maximum Environmental Temperature", "NameShort":"MaxET", "Description":"Safest maximum temperature for this animal to survive in."}, | ||
"MedicalStats.Temps.CET": | ||
{ | ||
"Name":"Comfortable Environmental Temperature", | ||
"NameShort":"Comf Env Temp", | ||
"Hash":"ComfET", | ||
"Description":"The most comfortable temperature for this animal to survive in." | ||
} | ||
} | ||
}); | ||
Expect(animalManyfest.getValueByHash({MedicalStats: { Temps: { CET:200 }},Name:'Froggy'}, 'ComfET')) | ||
.to.equal(200); | ||
fTestComplete(); | ||
} | ||
); | ||
test | ||
( | ||
'Validate should check that required elements exist', | ||
(fTestComplete)=> | ||
{ | ||
let animalManyfest = new libManyfest( | ||
{ | ||
"Scope": "Animal", | ||
"Descriptors": | ||
{ | ||
"IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" }, | ||
"Name": { "Required":true, "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." } | ||
} | ||
}); | ||
let tmpValidationResults = animalManyfest.validate({MedicalStats: { Temps: { CET:200 }},Name:'Froggy'}); | ||
Expect(tmpValidationResults.Error) | ||
.to.equal(null); | ||
fTestComplete(); | ||
} | ||
); | ||
test | ||
( | ||
'Validate should error when required elements do not exist', | ||
(fTestComplete)=> | ||
{ | ||
let animalManyfest = new libManyfest( | ||
{ | ||
"Scope": "Animal", | ||
"Descriptors": | ||
{ | ||
"IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" }, | ||
"Name": { "Required":true, "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." } | ||
} | ||
}); | ||
let tmpValidationResults = animalManyfest.validate({MedicalStats: { Temps: { CET:200 }}}); | ||
Expect(tmpValidationResults.Error) | ||
.to.equal(true); | ||
fTestComplete(); | ||
} | ||
); | ||
} | ||
); | ||
} | ||
); |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
164036
32
2022
561
5