Mercurial > code > home > repos > streamed-graph
changeset 18:4bf74032e2e8
merge
author | drewp@bigasterisk.com |
---|---|
date | Thu, 12 Dec 2019 22:57:14 -0800 |
parents | 94629c39681c (current diff) 3f3c27ed27eb (diff) |
children | 23fa6402c728 |
files | package.json src/rdf_types.ts tasks.py tsconfig.json |
diffstat | 12 files changed, 510 insertions(+), 311 deletions(-) [+] |
line wrap: on
line diff
--- a/index.html Thu Dec 12 22:52:57 2019 -0800 +++ b/index.html Thu Dec 12 22:57:14 2019 -0800 @@ -4,6 +4,6 @@ <h1>streamed-graph demo</h1> <script src="./build/streamed-graph.bundle.js"></script> - <streamed-graph url="http://bang5:9075/graph/events"></streamed-graph> + <streamed-graph url="http://bang5:9075/graph/events" expanded="true"></streamed-graph> </body> </html> \ No newline at end of file
--- a/jasmine.json Thu Dec 12 22:52:57 2019 -0800 +++ b/jasmine.json Thu Dec 12 22:57:14 2019 -0800 @@ -1,5 +1,7 @@ { - "spec_dir": "src", - "spec_files": ["**/*_test.ts"], + "spec_dir": "build", + "spec_files": [ + "test.bundle.js" + ], "oneFailurePerSpec": false } \ No newline at end of file
--- a/src/graph_view.ts Thu Dec 12 22:52:57 2019 -0800 +++ b/src/graph_view.ts Thu Dec 12 22:57:14 2019 -0800 @@ -1,208 +1,238 @@ // from /my/site/homepage/www/rdf/browse/graphView.js -/// <reference types="./n3.d.ts"> +//reference types="./n3.d.ts"> -import { html } from 'lit-html'; +import { html, TemplateResult } from 'lit-html'; import { SuffixLabels } from './suffixLabels'; -import { NamedNode, N3Store } from 'n3'; - -import ns from 'n3/src/IRIs'; -const {rdf} = ns; +import { Quad, Term, NamedNode, N3Store } from '../node_modules/@types/n3/index'; +import { DataFactory, Util } from 'n3'; +const { namedNode } = DataFactory; +// import ns from 'n3/src/IRIs'; +// const { rdf } = ns; -const groupByRdfType = (graph: N3Store) => { - const rdfType = new NamedNode(rdf.type); - const byType: Map<NamedNode, Set<NamedNode>> = new Map(); // type : subjs - const untyped = new Set(); // subjs - graph.getQuads({}, (q) => { - let subjType = null; - graph.getQuads({ - subject: q.subject, - predicate: rdfType - }, - (q2) => { subjType = q2.object; }); - if (subjType) { - subjType = subjType.toString(); +type TypeToSubjs = Map<NamedNode, Set<NamedNode>>; +function groupByRdfType(graph: N3Store): { byType: TypeToSubjs, untyped: Set<NamedNode> } { + const rdfType = namedNode('rdf:type'); + const byType: TypeToSubjs = new Map(); // type : subjs + const untyped: Set<NamedNode> = new Set(); // subjs + graph.forEach((q) => { + let subjType: NamedNode | null = null; + + graph.forObjects((o: Quad) => { + if (Util.isNamedNode(o.object)) { + subjType = o.object as NamedNode; + } + }, q.subject, rdfType, null); + + if (subjType !== null) { if (!byType.has(subjType)) { byType.set(subjType, new Set()); } - byType.get(subjType).add(q.subject.toString()); + (byType.get(subjType) as Set<NamedNode>).add(q.subject as NamedNode); } else { - untyped.add(q.subject.toString()); + untyped.add(q.subject as NamedNode); } - - }); + }, null, null, null, null); return { byType: byType, untyped: untyped }; -}; +} -const graphView = (graph: N3Store) => { - const labels = new SuffixLabels(); - graph.getQuads({}, (q) => { - if (q.subject.interfaceName == "NamedNode") { labels.planDisplayForNode(q.subject); } - if (q.predicate.interfaceName == "NamedNode") { labels.planDisplayForNode(q.predicate); } - if (q.object.interfaceName == "NamedNode") { labels.planDisplayForNode(q.object); } - if (q.object.interfaceName == "Literal" && q.object.datatype) { labels.planDisplayForNode(new NamedNode(q.object.datatype)); } - }); - const rdfNode = (n) => { - if (n.interfaceName == "Literal") { +class NodeDisplay { + labels: SuffixLabels; + constructor(labels: SuffixLabels) { + this.labels = labels; + } + getHtml(n: Term): TemplateResult { + if (n.termType == "Literal") { let dtPart: any = ""; if (n.datatype) { dtPart = html` - ^^<span class="literalType"> - ${rdfNode(new NamedNode(n.datatype))} - </span>`; + ^^<span class="literalType"> + ${this.getHtml(n.datatype)} + </span>`; } - return html`<span class="literal">${n.nominalValue}${dtPart}</span>`; - } - if (n.interfaceName == "NamedNode") { - let dn = labels.getLabelForNode(n); - if (dn.match(/XMLSchema#.*/)) { dn = dn.replace('XMLSchema#', 'xsd:'); } - if (dn.match(/rdf-schema#.*/)) { dn = dn.replace('rdf-schema#', 'rdfs:'); } - return html`<a class="graphUri" href="${n.toString()}">${dn}</a>`; + return html`<span class="literal">${n.value}${dtPart}</span>`; } - return html`[${n.interfaceName} ${n.toNT()}]`; + if (n.termType == "NamedNode") { + let dn: string | undefined = this.labels.getLabelForNode(n.value); + if (dn === undefined) { + throw new Error(`dn=${dn}`); + } + if (dn!.match(/XMLSchema#.*/)) { + dn = dn!.replace('XMLSchema#', 'xsd:'); + } + if (dn!.match(/rdf-schema#.*/)) { + dn = dn!.replace('rdf-schema#', 'rdfs:'); + } + return html`<a class="graphUri" href="${n.value}">${dn}</a>`; + } + + return html`[${n.termType} ${n.value}]`; + } +} + +export class GraphView { + url: string; + graph: N3Store; + nodeDisplay: NodeDisplay; + constructor(url: string, graph: N3Store) { + this.url = url; + this.graph = graph; + + const labels = new SuffixLabels(); + this._addLabelsForAllTerms(labels); + this.nodeDisplay = new NodeDisplay(labels); } - const objBlock = (obj) => { - return html` - <div class="object"> - ${rdfNode(obj)} <!-- indicate what source or graph said this stmt --> - </div> - `; - }; + _addLabelsForAllTerms(labels: SuffixLabels) { + return this.graph.forEach((q: Quad) => { + if (q.subject.termType === "NamedNode") { labels.planDisplayForNode(q.subject); } + if (q.predicate.termType === "NamedNode") { labels.planDisplayForNode(q.predicate); } + if (q.object.termType === "NamedNode") { labels.planDisplayForNode(q.object); } + if (q.object.termType === "Literal" && q.object.datatype) { + labels.planDisplayForNode(q.object.datatype); + } + }, null, null, null, null); + } - /// bunch of table rows - const predBlock = (subj, pred) => { - const objsSet = new Set(); - graph.getQuads({ subject: subj, predicate: pred }, (q) => { - - if (q.object.length) { - console.log(q.object) - } - objsSet.add(q.object); - }); - const objs = Array.from(objsSet.values()); - objs.sort(); + _subjBlock(subj: NamedNode) { + const predsSet: Set<NamedNode> = new Set(); + this.graph.forEach((q: Quad) => { + predsSet.add(q.predicate as NamedNode); + }, subj, null, null, null); + const preds = Array.from(predsSet.values()); + preds.sort(); return html` - <div class="predicate">${rdfNode(pred)} + <div class="subject">${this.nodeDisplay.getHtml(subj)} + <!-- todo: special section for uri/type-and-icon/label/comment --> <div> - ${objs.map(objBlock)} + ${preds.map((p) => { return this._predBlock(subj, p); })} </div> </div> `; - }; + } - const { byType, untyped } = groupByRdfType(graph); - const typedSubjs = Array.from(byType.keys()); - typedSubjs.sort(); - - const untypedSubjs = Array.from(untyped.values()); - untypedSubjs.sort(); + _objBlock(obj: Term) { + return html` + <div class="object"> + ${this.nodeDisplay.getHtml(obj)} <!-- indicate what source or graph said this stmt --> + </div> + `; + } - const subjBlock = (subj) => { - const subjNode = new NamedNode(subj); - const predsSet = new Set(); - graph.getQuads({ subject: subjNode }, (q) => { - predsSet.add(q.predicate); - }); - const preds = Array.from(predsSet.values()); - preds.sort(); + _predBlock(subj: NamedNode, pred: NamedNode) { + const objsSet = new Set(); + this.graph.forEach((q: Quad) => { + objsSet.add(q.object); + }, subj, pred, null, null); + const objs = Array.from(objsSet.values()); + objs.sort(); return html` - <div class="subject">${rdfNode(subjNode)} - <!-- todo: special section for uri/type-and-icon/label/comment --> + <div class="predicate">${this.nodeDisplay.getHtml(pred)} <div> - ${preds.map((p) => { return predBlock(subjNode, p); })} + ${objs.map(this._objBlock.bind(this))} </div> </div> `; - }; - const byTypeBlock = (typeUri) => { - const subjs = Array.from(byType.get(typeUri)); - subjs.sort(); + } + - const graphCells = new Map(); // [subj, pred] : objs - const preds = new Set(); + // const byTypeBlock = (typeUri) => { + // const subjs = Array.from(byType.get(typeUri)); + // subjs.sort(); + + // const graphCells = new Map(); // [subj, pred] : objs + // const preds = new Set(); - subjs.forEach((subj) => { - graph.getQuads({ subject: new NamedNode(subj) }, (q) => { - preds.add(q.predicate.toString()); - const cellKey = subj + '|||' + q.predicate.toString(); - if (!graphCells.has(cellKey)) { - graphCells.set(cellKey, new Set()); - } - graphCells.get(cellKey).add(q.object); - }); - }); - const predsList = Array.from(preds); - predsList.splice(predsList.indexOf('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 1); - // also pull out label, which should be used on 1st column - predsList.sort(); + // subjs.forEach((subj) => { + // graph.getQuads({ subject: new NamedNode(subj) }, (q) => { + // preds.add(q.predicate.toString()); + // const cellKey = subj + '|||' + q.predicate.toString(); + // if (!graphCells.has(cellKey)) { + // graphCells.set(cellKey, new Set()); + // } + // graphCells.get(cellKey).add(q.object); + // }); + // }); + // const predsList = Array.from(preds); + // predsList.splice(predsList.indexOf('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 1); + // // also pull out label, which should be used on 1st column + // predsList.sort(); + + // const thead = () => { + // const predColumnHead = (pred) => { + // return html`<th>${rdfNode(new NamedNode(pred))}</th>`; + // }; + // return html` + // <thead> + // <tr> + // <th></th> + // ${predsList.map(predColumnHead)} + // </tr> + // </thead>`; + // }; - const thead = () => { - const predColumnHead = (pred) => { - return html`<th>${rdfNode(new NamedNode(pred))}</th>`; - }; - return html` - <thead> - <tr> - <th></th> - ${predsList.map(predColumnHead)} - </tr> - </thead>`; - }; + // const instanceRow = (subj) => { + // const cell = (pred) => { + // const objs = graphCells.get(subj + '|||' + pred); + // if (!objs) { + // return html`<td></td>`; + // } + // const objsList = Array.from(objs); + // objsList.sort(); + // const draw = (obj) => { + // return html`<div>${rdfNode(obj)}</div>` + // }; + // return html`<td>${objsList.map(draw)}</td>`; + // }; - const instanceRow = (subj) => { - const cell = (pred) => { - const objs = graphCells.get(subj + '|||' + pred); - if (!objs) { - return html`<td></td>`; - } - const objsList = Array.from(objs); - objsList.sort(); - const draw = (obj) => { - return html`<div>${rdfNode(obj)}</div>` - }; - return html`<td>${objsList.map(draw)}</td>`; - }; + // return html` + // <tr> + // <td>${rdfNode(new NamedNode(subj))}</td> + // ${predsList.map(cell)} + // </tr> + // `; + // }; - return html` - <tr> - <td>${rdfNode(new NamedNode(subj))}</td> - ${predsList.map(cell)} - </tr> - `; - }; + // return html` + // <div>[icon] ${rdfNode(new NamedNode(typeUri))} resources</div> + // <div class="typeBlockScroll"> + // <table class="typeBlock"> + // ${thead()} + // ${subjs.map(instanceRow)} + // </table> + // </div> + // `; + // }; + + makeTemplate(): TemplateResult { + + const { byType, untyped } = groupByRdfType(this.graph); + const typedSubjs = Array.from(byType.keys()); + typedSubjs.sort(); + + const untypedSubjs = Array.from(untyped.values()); + untypedSubjs.sort(); return html` - <div>[icon] ${rdfNode(new NamedNode(typeUri))} resources</div> -<div class="typeBlockScroll"> - <table class="typeBlock"> - ${thead()} - ${subjs.map(instanceRow)} - </table> -</div> - `; - }; - - return html` - <link rel="stylesheet" href="/rdf/browse/style.css"> + <link rel="stylesheet" href="../src/streamed-graph.css"> - <section> - <h2> - Current graph (<a href="${graph.events.url}">${graph.events.url}</a>) - </h2> - <div> - <!-- todo: graphs and provenance. - These statements are all in the - <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.--> - </div> - ${typedSubjs.map(byTypeBlock)} - <div class="spoGrid"> - ${untypedSubjs.map(subjBlock)} - </div> - </section> - `; + <section> + <h2> + Current graph (<a href="${this.url}">${this.url}</a>) + </h2> + <div> + <!-- todo: graphs and provenance. + These statements are all in the + <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.--> + </div> + {typedSubjs.map(byTypeBlock)} + <div class="spoGrid"> + ${untypedSubjs.map(this._subjBlock.bind(this))} + </div> + </section> + `; + } } -export { graphView }
--- a/src/json_ld_quads.ts Thu Dec 12 22:52:57 2019 -0800 +++ b/src/json_ld_quads.ts Thu Dec 12 22:57:14 2019 -0800 @@ -12,7 +12,7 @@ function _emitQuad( onQuad: (q: Quad) => void, subjNode: NamedNode, - pred: string | { '@id': string }, + pred: string, subj: any, graphNode: NamedNode) { let predNode: NamedNode; @@ -20,7 +20,7 @@ predNode = namedNode(rdf.type); } else { - predNode = namedNode(pred['@id']); + predNode = namedNode(pred); } subj[pred as string].forEach(function (obj: any) { const objNode = (obj['@id'] ? namedNode(obj['@id']) : @@ -41,12 +41,14 @@ (expanded as [object]).forEach(function (g) { var graph = g['@id']; var graphNode = namedNode(graph); - g['@graph'].forEach(function (subj) { + g['@graph'].forEach(function (subj: { [predOrId: string]: any; }) { + console.log('process subj', subj) const subjNode = namedNode(subj['@id']); for (let pred in subj) { if (pred === '@id') { continue; - } 2 + } + console.log('emit with', pred); _emitQuad(onQuad, subjNode, pred, subj, graphNode); } });
--- a/src/rdf_types.ts Thu Dec 12 22:52:57 2019 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -export type Node = any; // todo -export type Quad = { - subject: Node; - predicate: Node; - object: Node; - graph: Node, -};
--- a/src/streamed-graph.css Thu Dec 12 22:52:57 2019 -0800 +++ b/src/streamed-graph.css Thu Dec 12 22:57:14 2019 -0800 @@ -19,3 +19,112 @@ display: inline-block; padding: 3px; } + +/* graph view */ +@import url('https://fonts.googleapis.com/css?family=Allerta|Dosis|Jura&display=swap'); + +body.rdfBrowsePage { + background: black; + color: white; + font-family: 'Allerta', sans-serif; + font-size: 12px; +} + +body.rdfBrowsePage pre { + font-family: 'Allerta', sans-serif; +} + +body.rdfBrowsePage a { + color: #b1b1fd; + text-shadow: 1px 1px 0px #0400ff94; + text-decoration-color: #00007714; +} + +section { + border: 1px solid gray; + padding: 4px; + font-family: 'Allerta', sans-serif; +} +.spoGrid { + display: flex; + flex-direction: column; +} +.subject, .predicate { + display: flex; + align-items: baseline; +} + +.predicate, .object { + margin-left: 5px; +} +.subject { border-top: 1px solid #2f2f2f; } +.literal { + border: 1px solid gray; + border-radius: 9px; + padding: 4px; + margin: 3px; +} + +.subject > .node { border: 2px solid rgb(68, 141, 68); } +.literalType { + vertical-align: super; + font-size: 80%; +} +.literal { + display: inline-block; + font-family: monospace; + font-size: 115%; +} +.resource { + display: inline-block; + background: lightblue; + border-radius: 6px; + padding: 1px 6px; + margin: 2px; +} +.predicate > a { + color: #e49dfb; +} +.predicate > a::before { + content: "━"; + font-size: 125%; + font-weight: bolder; + padding-right: 2px; +} +.predicate > a::after { + content: "🠪"; +} +.comment { color: green; } + +table.typeBlock { + border-collapse: collapse; +} +table.typeBlock th { + background: #1f1f1f; + border: 2px #333333 outset; +} +table.typeBlock td { + white-space: nowrap; + background: #2b2b2b; + border: 2px #4a4a4a outset; +} +table.typeBlock td .literal { + padding-top: 1px; + padding-bottom: 1px; +} +.typeBlockScroll { + max-width: 100%; + overflow-x: auto; +} + +/* +for my pages serving rdf data, not necessarily part of browse/ +*/ +.served-resources { + margin-top: 4em; + border-top: 1px solid gray; + padding-top: 1em; +} +.served-resources a { + padding-right: 2em; +}
--- a/src/streamed-graph.ts Thu Dec 12 22:52:57 2019 -0800 +++ b/src/streamed-graph.ts Thu Dec 12 22:57:14 2019 -0800 @@ -6,7 +6,7 @@ import { PolymerElement, html } from '@polymer/polymer'; import { customElement, property, computed } from '@polymer/decorators'; import { render } from 'lit-html'; -import { graphView } from './graph_view'; +import { GraphView } from './graph_view'; import { N3Store } from "n3" import { StreamedGraphClient } from './streamed_graph_client'; @@ -16,81 +16,84 @@ @property({ type: String }) url: string = ''; - @property({ type: Object }) - graph: {version: number, graph: N3Store}; + // @property({ type: Object }) + // graph: {version: number, store!: N3Store}; - @property({ type: Boolean }) - expanded: Boolean = false; + // @property({ type: boolean }) + // expanded: boolean = false; - @computed('expanded') - get expandAction() { - return this.expanded ? '-' : '+'; - } + // @computed('expanded') + // expandAction(): string { + // return this.expanded ? '-' : '+'; + // } - @property({ type: String }) - status: String = ''; + // @property({ type: string }) + // status: string = ''; - sg: StreamedGraphClient; - graphView: Element; - graphViewDirty = true; + // sg: StreamedGraphClient; + // graphView: Element; + // graphViewDirty = true; - static get template() { - return html` - <link rel="stylesheet" href="../src/streamed-graph.css"> - <div id="ui"> - <span class="expander"><button on-click="toggleExpand">{{expandAction}}</button></span> - StreamedGraph <a href="{{url}}">[source]</a>: - {{status}} - </div> - <div id="graphView"></div>`; - } + // static get template() { + // return html` + // <link rel="stylesheet" href="../src/streamed-graph.css"> + // <div id="ui"> + // <span class="expander"><button on-click="toggleExpand">{{expandAction}}</button></span> + // StreamedGraph <a href="{{url}}">[source]</a>: + // {{status}} + // </div> + // <div id="graphView"></div>`; + // } - ready() { - super.ready(); - this.graph = {version: -1, graph: null}; - this.graphView = this.shadowRoot.getElementById("graphView"); + // ready() { + // super.ready(); + // this.graph = {version: -1, store: null}; + // this.graphView = (this.shadowRoot as ShadowRoot).getElementById("graphView") as Element; - this._onUrl(this.url); // todo: watch for changes and rebuild - } + // this._onUrl(this.url); // todo: watch for changes and rebuild + // } - toggleExpand(ev) { - this.expanded = !this.expanded; - if (this.expanded) { - this.redrawGraph() - } else { - this.graphViewDirty = false; - render(null, this.graphView); - } - } + // toggleExpand(ev) { + // this.expanded = !this.expanded; + // if (this.expanded) { + // this.redrawGraph() + // } else { + // this.graphViewDirty = false; + // render(null, this.graphView); + // } + // } - redrawGraph() { - this.graphViewDirty = true; - requestAnimationFrame(this._redrawLater.bind(this)); - } + // redrawGraph() { + // this.graphViewDirty = true; + // requestAnimationFrame(this._redrawLater.bind(this)); + // } - _onUrl(url) { - if (this.sg) { this.sg.close(); } - this.sg = new StreamedGraphClient( - url, - this.onGraphChanged.bind(this), - this.set.bind(this, 'status'), - [],//window.NS, - [] - ); - } + // _onUrl(url) { + // if (this.sg) { this.sg.close(); } + // this.sg = new StreamedGraphClient( + // url, + // this.onGraphChanged.bind(this), + // this.set.bind(this, 'status'), + // [],//window.NS, + // [] + // ); + // } - onGraphChanged() { - this.graph = { version: this.graph.version + 1, graph: this.sg.store }; - if (this.expanded) { - this.redrawGraph(); - } - } + // onGraphChanged() { + // this.graph = { + // version: this.graph.version + 1, + // store: this.sg.store + // }; + // if (this.expanded) { + // this.redrawGraph(); + // } + // } - _redrawLater() { - if (!this.graphViewDirty) return; - render(graphView(this.graph.graph), this.graphView); - this.graphViewDirty = false; - } + // _redrawLater() { + // if (!this.graphViewDirty) return; + // render(new GraphView(this.url, this.graph.store).makeTemplate(), this.graphView); + // this.graphViewDirty = false; + // } } \ No newline at end of file
--- a/src/streamed_graph_client.ts Thu Dec 12 22:52:57 2019 -0800 +++ b/src/streamed_graph_client.ts Thu Dec 12 22:57:14 2019 -0800 @@ -1,13 +1,8 @@ // from /my/site/homepage/www/rdf/streamed-graph.js -import * as async from "async"; -// import * as jsonld from "jsonld"; - import { eachJsonLdQuad } from "./json_ld_quads"; -import { Store } from "n3" - -// /// <reference types="eventsource" /> -// const EventSource = window.EventSource; +import { N3Store } from '../node_modules/@types/n3/index'; +import { Store } from 'n3'; export class StreamedGraphClient { // holds a n3 Store, which is synced to a server-side @@ -15,7 +10,7 @@ onStatus: (msg: string) => void; onGraphChanged: () => void; - store: Store; + store: N3Store; events: EventSource; constructor( eventsUrl: string, @@ -28,7 +23,7 @@ this.onGraphChanged = onGraphChanged; this.onStatus('startup...'); - this.store = new Store({}); + this.store = new Store(); // // Object.keys(prefixes).forEach((prefix) => { // // this.store.setPrefix(prefix, prefixes[prefix]); @@ -74,49 +69,36 @@ }, 3000); }); - this.events.addEventListener('fullGraph', (ev) => { + this.events.addEventListener('fullGraph', async (ev) => { this.onStatus('sync- full graph update'); - let onReplaced = () => { - this.onStatus(`synced ${this.store.size}`); - this.onGraphChanged(); - }; - this.replaceFullGraph(ev.data, onReplaced); + await this.replaceFullGraph(ev.data); + this.onStatus(`synced ${this.store.size}`); + this.onGraphChanged(); }); - this.events.addEventListener('patch', (ev) => { + this.events.addEventListener('patch', async (ev) => { this.onStatus('sync- updating'); - let onPatched = () => { - this.onStatus(`synced ${this.store.size}`); - this.onGraphChanged(); - }; - this.patchGraph(ev.data, onPatched); + await this.patchGraph(ev.data); + this.onStatus(`synced ${this.store.size}`); + this.onGraphChanged(); }); this.onStatus('connecting...'); } - replaceFullGraph(jsonLdText: string, done: () => void) { - this.store = new Store({}); - eachJsonLdQuad(JSON.parse(jsonLdText), - this.store.addQuad.bind(this.store), - done); + // these need some locks + async replaceFullGraph(jsonLdText: string) { + this.store = new Store(); + await eachJsonLdQuad(JSON.parse(jsonLdText), + this.store.addQuad.bind(this.store)); } - patchGraph(patchJson: string, done: () => void) { + async patchGraph(patchJson: string) { var patch = JSON.parse(patchJson).patch; - async.series([ - (done) => { - eachJsonLdQuad(patch.deletes, - this.store.removeQuad.bind(this.store), done); - }, - (done) => { - eachJsonLdQuad(patch.adds, - this.store.addQuad.bind(this.store), done); - }, - /* seriesDone */ (done) => { - done(); - } - ], done); + await eachJsonLdQuad(patch.deletes, + this.store.removeQuad.bind(this.store)); + await eachJsonLdQuad(patch.adds, + this.store.addQuad.bind(this.store)); } close() { @@ -125,7 +107,7 @@ } } - testEventUrl(eventsUrl: string): Promise<void> { + async testEventUrl(eventsUrl: string): Promise<void> { return new Promise<void>((resolve, reject) => { this.onStatus('testing connection'); fetch(eventsUrl, {
--- a/src/suffixLabels.ts Thu Dec 12 22:52:57 2019 -0800 +++ b/src/suffixLabels.ts Thu Dec 12 22:57:14 2019 -0800 @@ -1,13 +1,13 @@ import { Term } from 'n3'; -type SuffixesNode = { usedBy: null | string, children: Map<string, SuffixesNode> }; -type DisplayNode = { label: string | null, link?: string }; +type SuffixesNode = { usedBy?: string, children: Map<string, SuffixesNode> }; +type DisplayNode = { label?: string, link?: string }; class SuffixLabels { displayNodes: Map<string, DisplayNode>; usedSuffixes: SuffixesNode; constructor() { this.displayNodes = new Map(); - this.usedSuffixes = { usedBy: null, children: new Map() }; + this.usedSuffixes = { usedBy: undefined, children: new Map() }; } planDisplayForNode(node: Term) { @@ -22,7 +22,7 @@ const segments = uri.split('/'); let curs = this.usedSuffixes; - let label = null; + let label: string | undefined = undefined; for (let i = segments.length - 1; i >= 0; i--) { const seg = segments[i]; @@ -31,15 +31,15 @@ } if (!curs.children.has(seg)) { - const child = { usedBy: null, children: new Map() }; + const child: SuffixesNode = { usedBy: undefined, children: new Map() }; curs.children.set(seg, child); - if (label === null) { + if (label === undefined) { label = SuffixLabels._tailSegments(uri, segments.length - i); child.usedBy = uri; } } - curs = curs.children.get(seg); + curs = curs.children.get(seg)!; } this.displayNodes.set(uri, { label: label }); } @@ -50,7 +50,7 @@ // 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 clashNode: DisplayNode = this.displayNodes.get(curs.usedBy!)!; const nextLeftSeg = curs.children.entries().next().value; if (nextLeftSeg[1].usedBy) { throw new Error("unexpected"); @@ -58,12 +58,12 @@ clashNode.label = nextLeftSeg[0] + '/' + clashNode.label; nextLeftSeg[1].usedBy = curs.usedBy; - curs.usedBy = null; + curs.usedBy = undefined; } getLabelForNode(node: string) { - return this.displayNodes.get(node).label; + return this.displayNodes.get(node)!.label; } static _tailSegments(uri: string, n: number) {
--- a/tasks.py Thu Dec 12 22:52:57 2019 -0800 +++ b/tasks.py Thu Dec 12 22:57:14 2019 -0800 @@ -18,9 +18,12 @@ @task def test(ctx): ctx.run(f'node_modules/.bin/webpack-cli --config webpack-test.config.ts') +<<<<<<< working copy ctx.run(f'node_modules/.bin/ts-node node_modules/.bin/jasmine --config=jasmine.json') # one time: # yarn policies set-version v2 # in vscode, ctrl-p then: ext install ark120202.vscode-typescript-pnp-plugin # or see https://next.yarnpkg.com/advanced/pnpify for a compatibility runner. +======= + ctx.run(f'node_modules/.bin/ts-node node_modules/.bin/jasmine --config=jasmine.json')>>>>>>> merge rev
--- a/webpack-dev.config.ts Thu Dec 12 22:52:57 2019 -0800 +++ b/webpack-dev.config.ts Thu Dec 12 22:57:14 2019 -0800 @@ -1,35 +1,60 @@ -import path from "path"; -import webpack from 'webpack'; +const path = require("path"); +const webpack = require('webpack'); + +const resolveConfig = { + alias: { + 'webpack-plugin-serve/client': './node_modules/webpack-plugin-serve/client.js', + }, + extensions: ['.ts', '.js', '.json'] +}; -const config: webpack.Configuration = { +const moduleConfig = { + rules: [ + { + test: /\.ts$/, + loader: 'ts-loader', + }, + { + test: /\.css$/i, + use: ['file-loader'] + }, + { + test: /zzzzz\.js$/, use: { + loader: 'babel-loader', + options: { + } + } + } + ] +}; +const pluginsConfig = [ +]; +module.exports = { + name: "dev", mode: "development", entry: [ './src/streamed-graph.ts', - './src/streamed-graph.css' // doesn't emit anything + // './src/streamed-graph.css' // doesn't emit anything ], output: { filename: 'streamed-graph.bundle.js', path: path.resolve(__dirname, 'build') }, - resolve: { - alias: { - 'webpack-plugin-serve/client': './node_modules/webpack-plugin-serve/client.js', - }, - extensions: ['.ts', '.js', '.json'] - }, - module: { - rules: [ - { test: /\.ts$/, use: 'ts-loader', exclude: /node_modules/ }, - { test: /\.css$/i, use: ['file-loader'] }, - ] - }, + resolve: resolveConfig, + devtool: 'source-map', + module: moduleConfig, + plugins: pluginsConfig, devServer: { port: 8082, hot: false, liveReload: true, // doesn't work overlay: true, - watchContentBase: true, + watchContentBase: true + }, + watch: true, + watchOptions: { + ignored: /node_modules/, + poll: 200 } }; -export default config; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webpack-test.config.ts Thu Dec 12 22:57:14 2019 -0800 @@ -0,0 +1,50 @@ +import path from "path"; +import webpack from 'webpack'; +import { CheckerPlugin } from 'awesome-typescript-loader'; + +const resolveConfig = { + alias: { + 'webpack-plugin-serve/client': './node_modules/webpack-plugin-serve/client.js', + }, + extensions: ['.ts', '.js', '.json'] +}; + +const moduleConfig = { + rules: [ + { + test: /\.ts$/, + use: ['awesome-typescript-loader'], + exclude: /node_modules/ + }, + { + test: /\.css$/i, + use: ['file-loader'] + }, + { + test: /zzzzz\.js$/, use: { + loader: 'babel-loader', + options: { + } + } + } + ] +}; +const pluginsConfig = [ + new CheckerPlugin() +]; +export default { + name: "test", + mode: "development", + entry: [ + "./src/json_ld_quads_test.ts" + ], + output: { + filename: "test.bundle.js", + path: path.resolve(__dirname, 'build') + }, + + resolve: resolveConfig, + module: moduleConfig, + plugins: pluginsConfig +}; +