UNPKG

urns

Version:

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

150 lines (149 loc) 6.05 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseURN = exports.nss = exports.nid = exports.unparseURN = exports.createURN = exports.createFullURN = void 0; /** * This is a Javascript regular expression for a URN that is compliant with RFC 8141. * * You can find a bit more commentary on this here: * * https://stackoverflow.com/questions/59032211/regex-which-matches-urn-by-rfc8141#comment118833940_59048720 * * You can also play around with the Regexp interactively here: * * https://regex101.com/r/WMty99/1 */ var rfc8141 = /^urn:([a-z0-9][a-z0-9-]{1,31}):((?:[-a-z0-9()+,.:=@;$_!*'&~\/]|%[0-9a-f]{2})+)(?:(\?\+)((?:(?!\?=)(?:[-a-z0-9()+,.:=@;$_!*'&~\/\?]|%[0-9a-f]{2}))*))?(?:(\?=)((?:(?!#).)*))?(?:(#)((?:[-a-z0-9()+,.:=@;$_!*'&~\/\?]|%[0-9a-f]{2})*))?$/i; /** * This function takes a given NID and NSS and creates a full URN. This is relatively straight forward. The * only real complexity comes from handling the URI encoding. * @param nid * @param nss * @param {boolean=} skipVerification skip test against rfc8141 regex (optional, default false) * @returns */ function createFullURN(nid, nss, components, skipVerification) { /** Encode the NID */ var encoded_nid = encodeURI(nid); /** Encode the NSS */ var encoded_nss = encodeURI(nss); var ret = "urn:" + encoded_nid + ":" + encoded_nss; if (components === null || components === void 0 ? void 0 : components.r) { ret += "?+" + encodeURIComponent(components.r); } if (components === null || components === void 0 ? void 0 : components.q) { var elements = Object.entries(components.q).map(function (_a) { var key = _a[0], value = _a[1]; return encodeURIComponent(key) + "=" + encodeURIComponent(value); }); ret += "?=" + elements.join("&"); } if (components === null || components === void 0 ? void 0 : components.f) { ret += "#" + components.f; } /** Ensure the result satisfies the regular expression */ if (!skipVerification && !rfc8141.test(ret)) { throw new Error("Unable to create a syntactically valid URN"); } return ret; } exports.createFullURN = createFullURN; /** * This function takes a given NID and NSS and creates a URN. This is relatively straight forward. The * only real complexity comes from handling the URI encoding. * @param nid * @param nss * @param {boolean=} skipVerification skip test against rfc8141 regex (optional, default false) * @returns */ function createURN(nid, nss, skipVerification) { /** Encode the NID */ var encoded_nid = encodeURI(nid); /** Encode the NSS */ var encoded_nss = encodeURI(nss); var ret = "urn:" + encoded_nid + ":" + encoded_nss; /** Ensure the result satisfies the regular expression */ if (!skipVerification && !rfc8141.test(ret)) { throw new Error("Unable to create a syntactically valid URN"); } return ret; } exports.createURN = createURN; /** * This function "unparses" a URN. That is to say that it takes the normal output * of the `parse` function and reverses it to form the original URN. This is quite * similar to the `createURN` function above except that it handles components as * well. * @param p * @param {boolean=} skipVerification skip test against rfc8141 regex (optional, default false) * @returns */ function unparseURN(p, skipVerification) { /** Again, ensure everything is properly URI encoded */ var nid = encodeURI(p.nid); var nss = encodeURI(p.nss); var rcomponent = p.rcomponent ? "?+" + encodeURI(p.rcomponent) : ""; var qcomponent = p.qcomponent ? "?=" + encodeURI(p.qcomponent) : ""; var fragment = p.fragment ? "#" + encodeURI(p.fragment) : ""; var ret = "urn:" + nid + ":" + nss + rcomponent + qcomponent + fragment; /** Ensure the result is a valid URN */ if (!skipVerification && !rfc8141.test(ret)) { throw new Error("Unable to create a syntactically valid URN"); } return ret; } exports.unparseURN = unparseURN; /** A helper function to extract just the namespace identifier (NID) */ function nid(s) { return parseURN(s).nid; } exports.nid = nid; /** A helper function to extract just the namespace specific string (NSS) */ function nss(s) { return parseURN(s).nss; } exports.nss = nss; /** * This function parses a string as a URN and returns an object containing all * the various aspects of the URN. Much of the "heavy lifting" here is done * by the regular expression parsing itself. But there are a few more bits * we need to do in the function as well. * @param s * @returns */ function parseURN(s) { /** Parse this using the regular expression at the top of this file */ var results = s.match(rfc8141); /** If it doesn't conform, we are done. */ if (!results) { throw new Error("String \"" + s + "\" is not a valid RFC8141 compliant URN"); } /* istanbul ignore next */ if (results.length < 3) { throw new Error("Error parsing URN \"" + s + "\""); // I don't see how this can happen } /** URI decode the NID and the NSS */ var nid = decodeURI(results[1]); var nss = decodeURI(results[2]); /** We keep the encoded NSS as well */ var nss_encoded = results[2]; /** * Now we have to go through the Regexp output and match it up with * any r-component, q-component or f-component, if present. */ var ridx = results.indexOf("?+"); var qidx = results.indexOf("?="); var fidx = results.indexOf("#"); var rcomponent = ridx === -1 ? null : decodeURI(results[ridx + 1]); var qcomponent = qidx === -1 ? null : decodeURI(results[qidx + 1]); var fragment = fidx === -1 ? null : decodeURI(results[fidx + 1]); /** Return the resulting fully parsed URN. */ return { nid: nid, nss: nss, nss_encoded: nss_encoded, rcomponent: rcomponent, qcomponent: qcomponent, fragment: fragment, }; } exports.parseURN = parseURN;