urns
Version:
An RFC 8141 compliant URN library with some interesting type related functionality
183 lines (182 loc) • 8.71 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var map_fields_1 = require("./map-fields");
var space_1 = require("./space");
var CachedURNSpace = /** @class */ (function (_super) {
__extends(CachedURNSpace, _super);
function CachedURNSpace() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.cache = new Map();
return _this;
}
CachedURNSpace.prototype._createURN = function (nid, nss) {
var key = nid + ":" + nss;
var res = this.cache.get(key) || _super.prototype._createURN.call(this, nid, nss);
this.cache.set(key, (res + "CACHED"));
return res;
};
return CachedURNSpace;
}(space_1.URNSpace));
describe("Should test derived class", function () {
it("should create a simple space", function () {
/** Create a simple URN space that always uses the namespace identifier "example" */
var space = new CachedURNSpace("example");
/**
* Create a URN inside the "example" space with a "namespace specific string" (NSS) of "a"
*
* NB - We are creating this URN with a narrowed set of possible NSS values ("a" | "b")
*/
var a = space.urn("a");
var aCached = space.urn("a");
expect(aCached).toEqual(a + "CACHED");
});
});
describe("Test usage of urnSpace", function () {
it("should create a simple space", function () {
/** Create a simple URN space that always uses the namespace identifier "example" */
var space = new space_1.URNSpace("example");
/**
* Create a URN inside the "example" space with a "namespace specific string" (NSS) of "a"
*
* NB - We are creating this URN with a narrowed set of possible NSS values ("a" | "b")
*/
var a = space.urn("a");
/** Now create a URN where the only possible value of the NSS is "b" */
var b = space.urn("b");
/**
* This assignement should work since the domain of `b` is a proper subset
* of the domain of `a` (the reverse is not true)
*/
a = b;
/** Create a URN "by hand" and the check that it passes the `is` test */
var ex1 = "urn:example:c";
expect(space.is(ex1)).toEqual(true);
/** Create a URN by hand that is no part of this URN space and ensure it fails the `is` test */
expect(space.is("urn:other:a")).toEqual(false);
});
it("should create a space with encoder if provided", function () {
var space = new space_1.URNSpace("example", {
// encode to v^2
encode: function (v) {
return (v * v).toString();
},
});
expect(space.urn(2)).toEqual("urn:example:4");
});
it("should create a space with an NSS constraint", function () {
/**
* In this case, return type of the `pred` function provides an additional
* constraint on the potential values for the NSS in this space. This is
* picked up by TypeScripts type analysis (and, thus, allows us to detect
* deviations from that type in string literals).
**/
var space = new space_1.URNSpace("example", {
pred: function (s) { return s === "a" || s === "b"; },
});
expect(space.is("urn:example:b")).toEqual(true);
expect(space.is("urn:example:c")).toEqual(false);
expect(function () { return space.assume("urn:example:d"); }).toThrow("Assumption that 'urn:example:d' belongs to the specified URNSpace('example') is faulty");
});
it("should not create invalid urns with an NSS constraint", function () {
/**
* In this case, return type of the `pred` function provides an additional
* constraint on the potential values for the NSS in this space. This is
* picked up by TypeScripts type analysis (and, thus, allows us to detect
* deviations from that type in string literals).
**/
var space = new space_1.URNSpace("example", {
pred: function (s) { return s === "a" || s === "b"; },
});
expect(space.is("urn:example:b")).toEqual(true);
expect(space.is("urn:example:c")).toEqual(false);
expect(function () { return space.urn("d"); }).toThrow("Assumption that 'urn:example:d' belongs to the specified URNSpace('example') is faulty");
expect(function () { return space.assume("urn:example:d"); }).toThrow("Assumption that 'urn:example:d' belongs to the specified URNSpace('example') is faulty");
});
it("should create a space with a decoder", function () {
/** Now we create a URNSpace with a transform function. */
var space = new space_1.URNSpace("example", {
decode: map_fields_1.mapFields(["id", "sub"]),
});
/** Now, when we parse a URN like this one, */
var un = space.parse("urn:example:a:b");
/** We get our NSS parsed for us (in this case into specified fields). */
expect(un.decoded.id).toEqual("a");
expect(un.decoded.sub).toEqual("b");
/** We can even invoke this directly and skip the parse step... */
expect(space.nss("urn:example:a:b")).toEqual("a:b");
expect(space.decode("urn:example:a:b")).toEqual({ id: "a", sub: "b" });
/** One additional check to make sure it parsed everything else as expected. */
expect(un).toEqual({
nid: "example",
nss: "a:b",
nss_encoded: "a:b",
fragment: null,
qcomponent: null,
rcomponent: null,
decoded: {
id: "a",
sub: "b",
},
});
/** Finally, the transform function also provides additional levels of validation. */
expect(space.is("urn:example:a:b:c")).toEqual(false);
expect(space.is("urn:example:a:b")).toEqual(true);
});
it("should creation and querying of full URNs (URNs with components)", function () {
var space = new space_1.URNSpace("ref");
var ex1 = space.fullUrn("foo", { q: { x: "5" } });
expect(ex1).toEqual("urn:ref:foo?=x=5");
expect(space.is(ex1)).toEqual(false);
expect(space.isFull(ex1)).toEqual(true);
expect(space.nss(ex1)).toEqual("foo");
});
it("should create a space with an alternative transform", function () {
var space = new space_1.URNSpace("customer", {
decode: function (nss) {
var v = parseInt(nss);
if (Number.isNaN(v))
throw new Error("NSS (" + nss + ") is not a number!");
return v;
},
});
expect(space.decode("urn:customer:25")).toEqual(25);
expect(function () { return space.decode("urn:customer:twenty-five"); }).toThrow("Assumption that 'urn:customer:twenty-five' belongs to the specified URNSpace('customer') fails in decoding: NSS (twenty-five) is not a number!");
});
it("should create a space without a transformer", function () {
/** A very ordinary URNSpace without transform or predicate */
var space = new space_1.URNSpace("example");
var un = space.parse("urn:example:a:b");
expect(un).toEqual({
nid: "example",
nss: "a:b",
nss_encoded: "a:b",
fragment: null,
qcomponent: null,
rcomponent: null,
decoded: {},
});
});
it("should throw if parts don't match", function () {
/** Create a URNSpace with a transform function */
var space = new space_1.URNSpace("example", {
decode: map_fields_1.mapFields(["id", "sub"]),
});
/** Now give it a URN that doesn't match the expected structure of the NSS. */
expect(function () { return space.parse("urn:example:a"); }).toThrow();
});
});