protoblast
Advanced tools
Comparing version 0.8.13 to 0.8.14
@@ -0,1 +1,11 @@ | ||
## 0.8.14 (2023-11-04) | ||
* Add `LocalDateTime`, `LocalDate` and `LocalTime` classes | ||
* Improve `Object.checksum()` handling of class instances | ||
* Add default `Symbol.toStringTag` implementation for classes | ||
* Add `Decimal` classes | ||
* Make `Object.isPrimitive(arg)` return true for all primitive types | ||
* Add BigInt support to `Object.stringifyPrimitive(arg)` method | ||
* Implement `Symbol.toPrimitive` method for the local date classes so it'll behave like the native Date class | ||
## 0.8.13 (2023-10-15) | ||
@@ -2,0 +12,0 @@ |
@@ -637,2 +637,7 @@ const finished_constitutors = new WeakMap(), | ||
// Set the default `toStringTag` method, if it hasn't been set yet | ||
if (!Obj.getPropertyDescriptor(proto, Symbol.toStringTag)) { | ||
Blast.defineGet(proto, Symbol.toStringTag, toStringTag); | ||
} | ||
// Inherit the prototype content | ||
@@ -710,2 +715,19 @@ newConstructor.prototype = Object.create(proto, { | ||
/** | ||
* Used for custom `toStringTag` behaviour (as a getter) | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.8.14 | ||
* @version 0.8.14 | ||
*/ | ||
function toStringTag() { | ||
let name = this.constructor.name; | ||
if (this.constructor.namespace) { | ||
name = this.constructor.namespace + '.' + name; | ||
} | ||
return name; | ||
} | ||
/** | ||
* Has this class been constituted? | ||
@@ -712,0 +734,0 @@ * |
@@ -421,2 +421,6 @@ module.exports = function BlastInitLoader(modifyPrototype) { | ||
'Date', | ||
'AbstractDateTime', | ||
'LocalDateTime', | ||
'AbstractNumeric', | ||
'Decimal', | ||
'Error', | ||
@@ -423,0 +427,0 @@ 'Informer', |
@@ -124,7 +124,12 @@ const defStat = Blast.createStaticDefiner('Object'); | ||
/** | ||
* Check if the argument is a primitive | ||
* Check if the value is a primitive. | ||
* Returns true for primitive values which include `undefined`, `null`, `boolean`, | ||
* `string`, `number`, `bigint`, and `symbol`. | ||
* | ||
* Despite `typeof null` returning "object", | ||
* it's considered a primitive value and this function accounts for that. | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.1.3 | ||
* @version 0.1.4 | ||
* @version 0.8.14 | ||
* | ||
@@ -137,13 +142,13 @@ * @param {Mixed} arg | ||
var type = typeof arg; | ||
if (type == 'string' || type == 'number' || type == 'boolean') { | ||
if (arg == null) { | ||
return true; | ||
} | ||
return false; | ||
let type = typeof arg; | ||
return type != 'object' && type != 'function'; | ||
}); | ||
/** | ||
* Stringify primitives only | ||
* Stringify (useful) primitives only | ||
* | ||
@@ -166,6 +171,9 @@ * @author Jelle De Loecker <jelle@develry.be> | ||
if (isFinite(arg)) { | ||
return arg; | ||
return arg+''; | ||
} | ||
break; | ||
case 'bigint': | ||
return arg+''; | ||
case 'boolean': | ||
@@ -1373,3 +1381,3 @@ return arg ? 'true' : 'false'; | ||
* @since 0.1.3 | ||
* @version 0.7.0 | ||
* @version 0.8.14 | ||
* | ||
@@ -1383,21 +1391,10 @@ * @param {Object|Array} obj The object to checksum | ||
var split_length, | ||
custom_type, | ||
counter, | ||
result, | ||
length, | ||
names, | ||
ident, | ||
type, | ||
temp, | ||
val, | ||
key, | ||
idx, | ||
i; | ||
let type = typeof obj, | ||
value_of, | ||
is_class_instance, | ||
has_different_value; | ||
type = typeof obj; | ||
// Make sure primitives are primitive | ||
if (type == 'object' && obj != null) { | ||
custom_type = typeof obj[Blast.checksumSymbol]; | ||
let custom_type = typeof obj[Blast.checksumSymbol]; | ||
@@ -1407,19 +1404,31 @@ if (custom_type == 'string') { | ||
} else if (custom_type == 'function') { | ||
return _checksum(obj[Blast.checksumSymbol](), sort_arrays, seen, level + 1); | ||
let checksum = obj[Blast.checksumSymbol](); | ||
if (typeof checksum == 'string' && checksum.length < 32) { | ||
return checksum; | ||
} | ||
return _checksum(checksum, sort_arrays, seen, level + 1); | ||
} else if (typeof obj.valueOf == 'function') { | ||
// Get the value of the object | ||
temp = obj.valueOf(); | ||
value_of = obj.valueOf(); | ||
has_different_value = value_of !== obj; | ||
// If the value is different, use that from here on out | ||
// This handles primitive objects & dates | ||
if (temp != obj) { | ||
if (has_different_value) { | ||
// Test for String, Number of Boolean instances | ||
if (Obj.isPrimitiveObject(obj)) { | ||
obj = temp; | ||
obj = value_of; | ||
type = typeof obj; | ||
is_class_instance = false; | ||
} else { | ||
// Things like dates should not be handled as JUST numbers | ||
type = 'date'; | ||
obj = temp; | ||
if (obj.constructor?.name == 'Date') { | ||
// Things like dates should not be handled as JUST numbers | ||
type = 'date'; | ||
obj = value_of; | ||
} | ||
is_class_instance = true; | ||
} | ||
@@ -1430,2 +1439,4 @@ } | ||
let ident; | ||
if (type == 'function') { | ||
@@ -1441,4 +1452,4 @@ type = 'string'; | ||
if (type == 'string') { | ||
length = obj.length; | ||
split_length = ~~(obj.length / 2); | ||
let length = obj.length; | ||
let split_length = ~~(obj.length / 2); | ||
@@ -1465,2 +1476,5 @@ // Make one of the strings longer than the other | ||
let result, | ||
names; | ||
if (Array.isArray(obj)) { | ||
@@ -1487,11 +1501,59 @@ // Clone the array | ||
} else { | ||
// Get all the keys of the object and sort them alphabetically | ||
names = Object.getOwnPropertyNames(obj).sort(); | ||
result = 'O'; | ||
if (is_class_instance == null) { | ||
is_class_instance = !Obj.isPlainObject(obj); | ||
value_of = obj.valueOf?.(); | ||
} | ||
if (is_class_instance) { | ||
let serialized, | ||
had_error; | ||
if (typeof obj.toDry == 'function') { | ||
try { | ||
serialized = obj.toDry(); | ||
had_error = false; | ||
} catch (err) { | ||
had_error = true; | ||
} | ||
} | ||
if ((had_error || had_error == null) && typeof obj.toJSON == 'function') { | ||
try { | ||
serialized = obj.toJSON(); | ||
had_error = false; | ||
} catch (err) { | ||
had_error = true; | ||
} | ||
} | ||
// Let the result start with a C and the checksum of the constructor name | ||
result = 'C' + Bound.String.checksum(obj.constructor.name).toString(36); | ||
if ((had_error || had_error == null)) { | ||
// Get all the keys of the object and sort them alphabetically | ||
names = Object.getOwnPropertyNames(obj).sort(); | ||
} | ||
if (!names || !names.length) { | ||
let serialized_checksum = _checksum(serialized, sort_arrays, seen, level + 1); | ||
// The serialized checksum will always start with 'A2-S' | ||
return result + '-' + serialized_checksum; | ||
} | ||
} else { | ||
result = 'O'; | ||
// Get all the keys of the object and sort them alphabetically | ||
names = Object.getOwnPropertyNames(obj).sort(); | ||
} | ||
} | ||
// Prepare the temp | ||
temp = ''; | ||
counter = 0; | ||
let counter = 0, | ||
temp = '', | ||
val, | ||
key, | ||
i; | ||
@@ -1512,5 +1574,6 @@ for (i = 0; i < names.length; i++) { | ||
} else if (typeof val == 'object') { | ||
let idx = seen.indexOf(val); | ||
// Handle objects recursively, but beware of circular references | ||
if ((idx = seen.indexOf(val)) == -1) { | ||
if (idx == -1) { | ||
seen.push(val); | ||
@@ -1517,0 +1580,0 @@ val = _checksum(val, sort_arrays, seen, level + 1); |
@@ -1569,2 +1569,15 @@ var rx_protocol = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i, | ||
/** | ||
* Return a checksum | ||
* | ||
* @author Jelle De Loecker <jelle@elevenways.be> | ||
* @since 0.8.14 | ||
* @version 0.8.14 | ||
* | ||
* @return {String} | ||
*/ | ||
RURL.setMethod(Blast.checksumSymbol, function checksum() { | ||
return 'RURL' + Obj.checksum(this.toString()).slice(1); | ||
}); | ||
/** | ||
* Return the URL as a string | ||
@@ -1571,0 +1584,0 @@ * |
{ | ||
"name": "protoblast", | ||
"description": "Native object expansion library", | ||
"version": "0.8.13", | ||
"version": "0.8.14", | ||
"author": "Jelle De Loecker <jelle@elevenways.be>", | ||
@@ -6,0 +6,0 @@ "keywords": [ |
888952
68
36265