UNPKG

urns

Version:

An RFC 8141 compliant URN library with some interesting type related functionality

234 lines (233 loc) 9.42 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.URNSpace = void 0; var parser_1 = require("./parser"); /** * The `URNSpace` class allows you to define a space of URNs defined * by a common namespace identifier (NID). You can further restrict * this space by providing your own subtype of string for the * namespace specific string (NSS) as well. Furthermore, via the * `options` you can provide your own functions for validating * the NSS (see `is` functionality) and potentially providing * further semantic parsing of the NSS (see `transform` functionality). * * With an instance of `URNSpace` in hand, it becomes very easy to * create new URNs and validate/parse existing URNs that belong * to the space. */ var URNSpace = /** @class */ (function () { /** * Create a new URNSpace with the specifid NID * @param nid Namespace identifer (NID) * @param options */ function URNSpace(nid, options) { this.nid = nid; this.options = options; } // this is here so the enduser can easilu overwrite these for instance to use caching // in derived class URNSpace.prototype._parseURN = function (s) { return parser_1.parseURN(s); }; URNSpace.prototype._createURN = function (nid, nss) { var _a; return parser_1.createURN(nid, nss, (_a = this.options) === null || _a === void 0 ? void 0 : _a.skipVerification); }; URNSpace.prototype._createFullURN = function (nid, nss, components) { var _a; return parser_1.createFullURN(nid, nss, components, (_a = this.options) === null || _a === void 0 ? void 0 : _a.skipVerification); }; /** * Create a new URN in this namespace. The type parameter `N` here * can be a subtype of the `NSS` type parameter of the `URNSpace` itself. * This allows you to deliberately create URNs that are part of a * more narrow subspace. */ URNSpace.prototype.urn = function (nss) { var _a; var createdURN; if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.encode) { createdURN = this._createURN(this.nid, this.options.encode(nss)); } else { createdURN = this._createURN(this.nid, nss); } try { this.assume(createdURN); return createdURN; } catch (e) { throw e; } }; /** * This creates a URN that will no longer conform to the BaseURN type (which assumes no components). * But it is still useful to create full URNs (with components) within a space. **/ URNSpace.prototype.fullUrn = function (nss, components) { var _a; var createdURN; if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.encode) { createdURN = this._createFullURN(this.nid, this.options.encode(nss), components); } else { createdURN = this._createFullURN(this.nid, nss, components); } return createdURN; }; /** * This is the main benefit of a `URNSpace`, it allows you to perform a runtime * check that narrows the scope of an ordinary string down to that of a member * of this URNSpace. This is useful if, for example, you are deserializing * content (e.g., from a JSON payload) and you want to ensure that a given * string is in fact of the (URN) type you expect. * * NB - This confirms that the URN is a base URN (no components). If you are * dealing with a full URN, use isFull * @param s * @returns */ URNSpace.prototype.is = function (s) { /** * Assume it is in this space and then check for exceptions. * * Note: this might prove more expensive in practice in which case you could use an * alternative formulation of the `assume` method here but changing how it addresses * each contingency. I opted for code reuse over optimization here. Time will tell * if that was the right call. */ try { this.assume(s); return true; } catch (e) { return false; } }; /** * Check if this string qualifies as a full URN belonging to this URN space. * * @param s A string which may be a full URN in this space, or it may not * @returns */ URNSpace.prototype.isFull = function (s) { var _a; /** * Assume it is in this space and then check for exceptions. * * Note: this might prove more expensive in practice in which case you could use an * alternative formulation of the `assume` method here but changing how it addresses * each contingency. I opted for code reuse over optimization here. Time will tell * if that was the right call. */ try { /** We start by parsing the string as a URN */ var parsed = this._parseURN(s); /** First check the NID */ if (parsed.nid !== this.nid) return false; /** Next, check the NSS if a predicate is defined */ if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.pred) { if (!this.options.pred(parsed.nss)) { return false; } } return true; } catch (e) { return false; } }; /** * This function is like `is`, but it assumes the result will be true. This can save you some * condition handling. You should use this when you have a high degree of confidence that the * string does actually conform this URNSpace because it will throw an exception if it doesn't. * @param s * @returns */ URNSpace.prototype.assume = function (s) { var _a, _b; /** We start by parsing the string as a URN */ var parsed = this._parseURN(s); /** Then we confirm that it conforms to the type of `BaseURN<NID, NSS>`. */ if (parsed.nid === this.nid && parsed.rcomponent === null && parsed.qcomponent === null && parsed.fragment === null) { /** * If there is an optional `pred` function provided for this space, * run it to perform further semantic validation on the NSS. */ if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.pred) { if (!this.options.pred(parsed.nss)) { throw new Error("Assumption that '" + s + "' belongs to the specified URNSpace('" + this.nid + "') is faulty, predicate failed"); } } /** * Now check if there is an optional transformational process * defined and ensure that it runs without throwing an exception. */ if ((_b = this.options) === null || _b === void 0 ? void 0 : _b.decode) { try { this.options.decode(parsed.nss); } catch (e) { throw new Error("Assumption that '" + s + "' belongs to the specified URNSpace('" + this.nid + "') fails in decoding: " + e.message); } } /** If we get here, the NSS has passed all further validation we can do. */ return s; } throw new Error("Assumption that '" + s + "' belongs to the specified URNSpace('" + this.nid + "') is faulty"); }; /** * This function parses the provided URN and also invokes the optional `decode` function (if provided). * @param urn * @returns */ URNSpace.prototype.parse = function (urn) { var parsed = this._parseURN(urn); if (!this.isFull(urn)) { throw new Error("Assumption that '" + urn + "' belongs to the specified URNSpace('" + this.nid + "') is faulty"); } try { var decoded = this.options && this.options.decode ? this.options.decode(parsed.nss) : {}; return __assign(__assign({}, parsed), { decoded: decoded }); } catch (e) { throw new Error("Assumption that '" + urn + "' belongs to the specified URNSpace('" + this.nid + "') fails in decoding: " + e.message); } }; /** * This helper function is for the use case where you simply want to extract the NSS value * of a provided string. * @param urn * @returns Namespace specific string */ URNSpace.prototype.nss = function (urn) { return this.parse(urn).nss; }; /** * This is another helper function that provides the result of the optional `transform` * function if provided. Otherwise, it simply returns `{}`. */ URNSpace.prototype.decode = function (urn) { return this.parse(urn).decoded; }; return URNSpace; }()); exports.URNSpace = URNSpace;