Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "urns",
"version": "0.6.0",
"version": "0.6.1-DEV",
"description": "An RFC 8141 compliant URN library with some interesting type related functionality",
"main": "lib/index.js",
"scripts": {
Expand Down Expand Up @@ -28,4 +28,4 @@
"ts-node": "^9.1.1",
"typescript": "^4.2.4"
}
}
}
35 changes: 25 additions & 10 deletions src/parser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ParsedURN, FullURN, BaseURN } from "./types";

const matchcache: Map<string, any> = new Map<string, any>();
const unparsecache: Map<string, any> = new Map<string, any>();
const testcache: Map<string, any> = new Map<string, any>();

/**
* This is a Javascript regular expression for a URN that is compliant with RFC 8141.
*
Expand Down Expand Up @@ -52,9 +56,9 @@ export function createFullURN<
ret += `#${components.f}`;
}
/** Ensure the result satisfies the regular expression */
if (!rfc8141.test(ret)) {
throw new Error("Unable to create a syntactically valid URN");
}
// if (!rfc8141.test(ret)) {
// throw new Error("Unable to create a syntactically valid URN");
// }
return ret as FullURN<NID, NSS, string>;
}

Expand All @@ -70,15 +74,20 @@ export function createURN<
NSS extends string = string
>(nid: NID, nss: NSS): BaseURN<NID, NSS> {
/** Encode the NID */
const cache_key = `${nid}%${nss}`;
if (unparsecache.has(cache_key)) {
return unparsecache.get(cache_key);
}
const encoded_nid = encodeURI(nid);
/** Encode the NSS */
const encoded_nss = encodeURI(nss);
let ret = `urn:${encoded_nid}:${encoded_nss}`;

/** Ensure the result satisfies the regular expression */
if (!rfc8141.test(ret)) {
throw new Error("Unable to create a syntactically valid URN");
}
// if (!rfc8141.test(ret)) {
// throw new Error("Unable to create a syntactically valid URN");
// }
unparsecache.set(cache_key, ret);
return ret as BaseURN<NID, NSS>;
}

Expand All @@ -102,9 +111,9 @@ export function unparseURN<
const fragment = p.fragment ? `#${encodeURI(p.fragment)}` : "";
const ret = `urn:${nid}:${nss}${rcomponent}${qcomponent}${fragment}`;
/** Ensure the result is a valid URN */
if (!rfc8141.test(ret)) {
throw new Error("Unable to create a syntactically valid URN");
}
// if (!rfc8141.test(ret)) {
// throw new Error("Unable to create a syntactically valid URN");
// }
return ret as FullURN<NID, NSS, string>;
}

Expand All @@ -130,6 +139,10 @@ export function parseURN<
NID extends string = string,
NSS extends string = string
>(s: string): ParsedURN<NID, NSS> {
if (matchcache.has(s)) {
return matchcache.get(s);
}

/** Parse this using the regular expression at the top of this file */
const results = s.match(rfc8141);
/** If it doesn't conform, we are done. */
Expand Down Expand Up @@ -161,12 +174,14 @@ export function parseURN<
const fragment = fidx === -1 ? null : decodeURI(results[fidx + 1]);

/** Return the resulting fully parsed URN. */
return {
const ret = {
nid,
nss,
nss_encoded,
rcomponent,
qcomponent,
fragment,
};
matchcache.set(s, ret);
return ret;
}
14 changes: 13 additions & 1 deletion src/space.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export class URNSpace<NID extends string, NSS extends string, R> {
protected nid: NID,
protected options?: Partial<SpaceOptions<NSS, R>>
) {}

private cache = new Map<any, any>();
private parsecache = new Map<any, any>();
/**
* 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.
Expand All @@ -32,12 +35,16 @@ export class URNSpace<NID extends string, NSS extends string, R> {
*/
urn<N extends NSS>(nss: N | R): BaseURN<NID, N> {
let createdURN: BaseURN<NID, N>;
if (this.cache.get(nss)) {
return this.cache.get(nss);
}
if (this.options?.encode) {
createdURN = createURN(this.nid, this.options.encode(nss as R) as N);
} else {
createdURN = createURN(this.nid, nss as N);
}
try {
this.cache.set(nss, createURN);
this.assume(createdURN);
return createdURN;
} catch (e) {
Expand Down Expand Up @@ -183,6 +190,9 @@ export class URNSpace<NID extends string, NSS extends string, R> {
* @returns
*/
parse(urn: FullURN<NID, NSS, string>): ParsedURN<NID, NSS> & { decoded: R } {
if (this.parsecache.has(urn)) {
return this.parsecache.get(urn);
}
const parsed = parseURN<NID, NSS>(urn);
if (!this.isFull(urn)) {
throw new Error(
Expand All @@ -194,7 +204,9 @@ export class URNSpace<NID extends string, NSS extends string, R> {
this.options && this.options.decode
? this.options.decode(parsed.nss)
: ({} as any);
return { ...parsed, decoded };
const ret = { ...parsed, decoded };
this.parsecache.set(urn, ret);
return ret;
} catch (e: any) {
throw new Error(
`Assumption that '${urn}' belongs to the specified URNSpace('${this.nid}') fails in decoding: ${e.message}`
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"target": "es2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
Expand Down
Loading