Proposal: Let's introduce asCID
static method #111
Description
This idea first was proposed in #109 and later came up in #110. I thought it would be best to factor it out into separate thread and discuss it here.
Problem
At the moment CID.isCID(v)
is used all over the place as a glorified v instanceof CID
check. However it does not check if v
is instanceof CID
instead it checks presence of special symbol. That addresses problem with having multiple different versions of CID
implementations, however it does overlook the fact that two different version may in fact be incompatible e.g. new version may change behavior of specific method e.g. toString
I think that is already happening (per #109 (comment))
In the new CID you can use .toString() with no arguments and it will give you a base32 multibase encoded string for CIDv1 and the bare base58btc encoding for CIDv0.
Even if above is backwards compatible change, incompatible change may come sooner or later.
This is a symptom of more general issue with validation pattern.
If you're inclined I would invite to read excellent parse don't validate primer that explains hazzards of that problem (in the context of typed language, but it applies to this just as well)
Proposal
Changing behavior of CID.isCID(v)
to do component validation (if I interperent @hugomrdias suggestion moxystudio/js-class-is#25 (comment)) is going to be too disruptive to be worth it. Furthermore it would not address the problem stated above. Instead I would like to propose an alternative in form of asCID
static method to which existing code base could be gradually migrated and future code base should default.
Implementation could be something along these lines:
class CID {
/**
* If passed value is a CID or compatible JSON representation, CID instance for it is returned
* otherwise `null` is returned.
* returns `null`.
* @param {any} value
* @returns {CID|null}
*/
asCID(value) {
// If is CID nothing to do here
if (value instanceof CID) {
return value
}
// If CID components validate it's CID from other realm or another version of CID
// In that case CID of this class is assembled from the components.
else if (CIDUtil.checkCIDComponents(other) == null) {
return new CID(value.version, value.codec, value.multihash, value.multibaseName)
}
// Otherwise it's not valid / compatible CID so return `null`
else {
return null
}
}
}
With such method in place existing pattern of
if (CID.isCID(cid)) {
// use cid
}
Could gradually be transitioned to following pattern instead:
const cid = CID.asCID(value)
if (cid) {
// use cid
}
It is a bit more verbose, but it would avoid issues that may arise from version incompatibilities. It will also preserve CID-ness when things are structured cloned.