# HG changeset patch # User drewp@localhost # Date 1575679279 28800 # Node ID 1988ad2500368c8c9d0f2c8c72809ae03905e042 # Parent 1c3a39057b11eb83b874720f50323716d8261f46 suffixLabels test runswith 'inv test' diff -r 1c3a39057b11 -r 1988ad250036 src/suffixLabels.js --- a/src/suffixLabels.js Fri Dec 06 09:21:49 2019 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -class SuffixLabels { - constructor() { - this.displayNodes = new Map(); // internal string : { label, link } - this.usedSuffixes = {usedBy: null, children: new Map()}; - } - - planDisplayForNode(node) { - const uri = node.nominalValue; - this._planDisplayForUri(uri); - }; - - _planDisplayForUri(uri) { - if (this.displayNodes.has(uri)) { - return; - } - - const segments = uri.split('/'); - let curs = this.usedSuffixes; - let label = null; - - for (let i = segments.length - 1; i >= 0; i--) { - const seg = segments[i]; - if (curs.usedBy && curs.usedBy != uri) { - this._prependClashingUri(curs); - } - - if (!curs.children.has(seg)) { - const child = {usedBy: null, children: new Map()}; - curs.children.set(seg, child); - - if (label === null ) { - label = SuffixLabels._tailSegments(uri, segments.length - i); - child.usedBy = uri; - } - } - curs = curs.children.get(seg); - } - this.displayNodes.set(uri, {label: label}); - } - - _prependClashingUri(curs) { - // Claim: When a clash is discovered, only 1 uri needs to - // change its length, and there will be only one child node to - // follow, and the clashing uri can be changed to prepend that - // one child (since we'll see it again if that one wasn't - // enough). - const clashNode = this.displayNodes.get(curs.usedBy); - const nextLeftSeg = curs.children.entries().next().value; - if (nextLeftSeg[1].usedBy) { - throw new Error("unexpected"); - } - - clashNode.label = nextLeftSeg[0] + '/' + clashNode.label; - nextLeftSeg[1].usedBy = curs.usedBy; - curs.usedBy = null; - - } - - getLabelForNode(node) { - return this.displayNodes.get(node.nominalValue).label; - } - - static _tailSegments(uri, n) { - let i = uri.length; - for (let rep = 0; rep < n; rep++) { - i = uri.lastIndexOf('/', i - 1); - } - return uri.substr(i + 1); - } -}; - -export { SuffixLabels } diff -r 1c3a39057b11 -r 1988ad250036 src/suffixLabels.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/suffixLabels.ts Fri Dec 06 16:41:19 2019 -0800 @@ -0,0 +1,78 @@ +import { Term } from 'n3'; + +type SuffixesNode = { usedBy: null | string, children: Map }; +type DisplayNode = { label: string | null, link?: string }; +class SuffixLabels { + displayNodes: Map; + usedSuffixes: SuffixesNode; + constructor() { + this.displayNodes = new Map(); + this.usedSuffixes = { usedBy: null, children: new Map() }; + } + + planDisplayForNode(node: Term) { + const uri = node.value; + this._planDisplayForUri(uri); + }; + + _planDisplayForUri(uri: string) { + if (this.displayNodes.has(uri)) { + return; + } + + const segments = uri.split('/'); + let curs = this.usedSuffixes; + let label = null; + + for (let i = segments.length - 1; i >= 0; i--) { + const seg = segments[i]; + if (curs.usedBy && curs.usedBy != uri) { + this._prependClashingUri(curs); + } + + if (!curs.children.has(seg)) { + const child = { usedBy: null, children: new Map() }; + curs.children.set(seg, child); + + if (label === null) { + label = SuffixLabels._tailSegments(uri, segments.length - i); + child.usedBy = uri; + } + } + curs = curs.children.get(seg); + } + this.displayNodes.set(uri, { label: label }); + } + + _prependClashingUri(curs: SuffixesNode) { + // Claim: When a clash is discovered, only 1 uri needs to + // change its length, and there will be only one child node to + // follow, and the clashing uri can be changed to prepend that + // one child (since we'll see it again if that one wasn't + // enough). + const clashNode: DisplayNode = this.displayNodes.get(curs.usedBy); + const nextLeftSeg = curs.children.entries().next().value; + if (nextLeftSeg[1].usedBy) { + throw new Error("unexpected"); + } + + clashNode.label = nextLeftSeg[0] + '/' + clashNode.label; + nextLeftSeg[1].usedBy = curs.usedBy; + curs.usedBy = null; + + } + + getLabelForNode(node: string) { + return this.displayNodes.get(node).label; + } + + static _tailSegments(uri: string, n: number) { + let i = uri.length; + for (let rep = 0; rep < n; rep++) { + i = uri.lastIndexOf('/', i - 1); + } + return uri.substr(i + 1); + } +}; + +export { SuffixLabels } diff -r 1c3a39057b11 -r 1988ad250036 src/suffixLabels_test.html --- a/src/suffixLabels_test.html Fri Dec 06 09:21:49 2019 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ - - - - suffixLabels_test - - - - - - - - - - - - - - - diff -r 1c3a39057b11 -r 1988ad250036 src/suffixLabels_test.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/suffixLabels_test.ts Fri Dec 06 16:41:19 2019 -0800 @@ -0,0 +1,70 @@ +import { SuffixLabels } from './suffixLabels'; + +describe("_tailSegments", () => { + it("returns right amount", () => { + expect(SuffixLabels._tailSegments('http://foo/a/bb', 0)).toEqual(''); + expect(SuffixLabels._tailSegments('http://foo/a/bb', 1)).toEqual('bb'); + expect(SuffixLabels._tailSegments('http://foo/a/bb', 2)).toEqual('a/bb'); + expect(SuffixLabels._tailSegments('http://foo/a/bb', 3)).toEqual('foo/a/bb'); + expect(SuffixLabels._tailSegments('http://foo/a/bb', 4)).toEqual('/foo/a/bb'); + expect(SuffixLabels._tailSegments('http://foo/a/bb', 5)).toEqual('http://foo/a/bb'); + }); + it("ok with trailing slash", () => { + expect(SuffixLabels._tailSegments('http://foo/', 0)).toEqual(''); + expect(SuffixLabels._tailSegments('http://foo/', 1)).toEqual(''); + expect(SuffixLabels._tailSegments('http://foo/', 2)).toEqual('foo/'); + }); +}); + +describe("suffixLabels", () => { + const fakeNode = (uri: string) => { return { nominalValue: uri } }; + + it("returns whole url segments", () => { + const suf = new SuffixLabels(); + suf._planDisplayForUri('http://a/b/c/dd'); + suf._planDisplayForUri('http://a/b/c/ee'); + + expect(suf.getLabelForNode('http://a/b/c/dd')).toEqual('dd'); + expect(suf.getLabelForNode('http://a/b/c/ee')).toEqual('ee'); + }); + + it("doesn't treat a repeated uri as a name clash", () => { + const suf = new SuffixLabels(); + suf._planDisplayForUri('http://a/b/c'); + suf._planDisplayForUri('http://a/b/c'); + + expect(suf.getLabelForNode('http://a/b/c')).toEqual('c'); + }); + + it("moves to two segments when needed", () => { + const suf = new SuffixLabels(); + suf._planDisplayForUri('http://a/b/c/d'); + suf._planDisplayForUri('http://a/b/f/d'); + + expect(suf.getLabelForNode('http://a/b/c/d')).toEqual('c/d'); + expect(suf.getLabelForNode('http://a/b/f/d')).toEqual('f/d'); + }); + + it("is ok with clashes at different segment positions", () => { + const suf = new SuffixLabels(); + suf._planDisplayForUri('http://z/z/z/a/b/c'); + suf._planDisplayForUri('http://a/b/c'); + + expect(suf.getLabelForNode('http://z/z/z/a/b/c')).toEqual('z/a/b/c'); + expect(suf.getLabelForNode('http://a/b/c')).toEqual('/a/b/c'); + }); + + it("uses appropriately long suffixes per uri", () => { + const suf = new SuffixLabels(); + suf._planDisplayForUri('http://a/b/c/d/e'); + suf._planDisplayForUri('http://a/b/f/d/e'); + suf._planDisplayForUri('http://a/b/c/g'); + suf._planDisplayForUri('http://a/z'); + + expect(suf.getLabelForNode('http://a/b/c/d/e')).toEqual('c/d/e'); + expect(suf.getLabelForNode('http://a/b/f/d/e')).toEqual('f/d/e'); + expect(suf.getLabelForNode('http://a/b/c/g')).toEqual('g'); + expect(suf.getLabelForNode('http://a/z')).toEqual('z'); + }); + +}); \ No newline at end of file