(function () { const MANIFEST_FILE = "manifest.jsonld"; const PROGRESS_CHUNK_COUNT = 100; const OCTICON_USE = ""; // doesn't render when composed in pieces. if (location.search.substr(1) === "toy") { // some examples from validation/manifest.jsonld const url = new URL(location.search.substr(1) + '/' +'toy', location).href; renderManifest(aFewTests(), "validation/", url); } else { $.ajaxSetup({ mimeType: "text/plain" }); // for persistent FF bug. const url = new URL(location.search.substr(1) + '/' + MANIFEST_FILE, location).href; $.getJSON(url).then(data => { renderManifest(data["@graph"][0].entries, location.search.substr(1) + "/", url); }).fail(e => { $("table thead").append( $("").append( $("").text("directory"), $("").text("description") )); $("table tbody").append( [ {directory: "schemas", description: "ShExC, JSON and Turtle versions of all schemas in the test suite."}, {directory: "validation", description: "Positive and negative ShEx validation tests."}, {directory: "negativeStructure", description: "Constructs that fail structural constraints."}, {directory: "negativeSyntax", description: "Constructs that fail the ShExC grammar."}, {directory: "toy", description: "small, static emulation of some validation tests for easy debugging."}, ].map(d => { return $("").append( $("").append($("", {href: location.href+"?"+d.directory}).text(d.directory)), $("").html(d.description) ); })); }); } let droparea = $("#droparea"); let type = droparea.find("input"); let data = droparea.find("textarea"); droparea.on("dragover", function (evt) { droparea.addClass("droppable"); evt.preventDefault(); }).on("dragleave", () => { droparea.removeClass("droppable"); }).on("drop", evt => { droparea.removeClass("droppable"); evt.preventDefault(); let xfer = evt.originalEvent.dataTransfer; const prefOrder = [ "files", "application/json", "text/uri-list", "text/plain" ]; if (prefOrder.find(l => { if (l.indexOf("/") === -1) { if (xfer[l].length > 0) { type.val(l); data.val(JSON.stringify(xfer[l])); readfiles(xfer[l], data); return true; } } else { if (xfer.getData(l)) { type.val(l); data.val(xfer.getData(l)); return true; } } return false; }) === undefined) { type.val(xfer.types[0]); data.val(xfer.getData(xfer.types[0])); } }).on("dragstart", (evt) => { const t = type.val() let v = data.val() if (t === "text/uri-list") v = v.split(/\n/).filter(s => !!s).map(s => s + "\r\n").join(""); console.log(v) evt.originalEvent.dataTransfer.setData(t, v); }); type.on('mousedown', function(e) { e.stopPropagation(); droparea.attr('draggable', false); }).on('mouseup', function(e) { droparea.attr('draggable', true); }); /* progressively render the tests, adjusting relative URLs by relPrepend. */ function renderManifest (tests, relPrepend, manifestUrl) { let toAdd = []; let startTime = new Date(); let testNo = 0; let chunkSize = Math.max(Math.floor(tests.length / PROGRESS_CHUNK_COUNT), 1); $("#tests").colResizable({ disable: true }); // assumes at least one test entry let progressbar = $( "#progressbar" ), progressLabel = $( ".progress-label" ); progressbar.progressbar({ value: false, max: tests.length, change: function() { progressLabel.text( progressbar.progressbar( "value" ) + "/" + tests.length ); } }); queue(); function queue () { renderTest(tests[testNo]); if (++testNo < tests.length) { if (testNo % chunkSize === 0) { progressbar.progressbar( "value", testNo+1 ); } setTimeout(queue, 0); } else { // done loading tests progressbar.progressbar( "value", testNo+1 ); progressLabel.empty().append( "Loaded " + tests.length + " tests from ", $("", {href: relPrepend + MANIFEST_FILE}).text(relPrepend + MANIFEST_FILE), " in ", (new Date() - startTime)/1000, " seconds." ); setTimeout(() => { $("table tbody").append(toAdd); var h = new URL(location).hash; if (h) highlight(h); $("#tests").colResizable({ fixed:false, liveDrag:true, gripInnerHtml:"
" }); }, 0); } } function highlight (h) { let [top, bottom] = h.substr(1).split(/--/); let topElt = document.getElementById(top); if (topElt) { topElt.scrollIntoView({ behavior: "smooth", block: "start" }); let range = $(topElt); if (bottom) { let botElt = document.getElementById(bottom); if (botElt) { range = range.add(range.nextUntil(botElt)).add(botElt); } } range.addClass("highlight"); } } function renderTest (test) { const structures = { "sht:ValidationTest": { str: "passes", chr: "✓", offset: ["action"], fields: [ {name:"schema", f: link}, {name:"data", f: link}, {name:"shape map", f:makeShapeMap} ] }, "sht:ValidationFailure": { str: "fails" , chr: "✗", offset: ["action"], fields: [ {name:"schema", f: link}, {name:"data", f: link}, {name:"shape map", f:makeShapeMap} ] }, "sht:RepresentationTest": { str: "" , chr: "", offset: [], fields: [ {name:"shex", f: link}, {name:"json", f: link}, {name:"ttl", f:link} ] }, "sht:NegativeStructure": { str: "" , chr: "", offset: [], fields: [ {name:"shex", f: link} ] }, "sht:NegativeSyntax": { str: "" , chr: "", offset: [], fields: [ {name:"shex", f: link} ] } }; let structure = structures[test["@type"]]; if (testNo === 0) { // Table heading with column titles. $("table thead").append( drag("tr", { }, x => JSON.stringify(tests, null, 2), "application/json").append( $(""), $("").text("name"), structure.fields.map(h => { return $("").text(h.name); }) )); } let titleText = "#" + (testNo+1) + " " + structure.str; let id = test["@id"].replace(/#/, '_'); test["@id"] = new URL(id, manifestUrl).href; let status = drag("td", { title: titleText, class: structure.str }, showTest, "application/json").text(structure.chr); let attrs = structure.offset.reduce((acc, o) => { return acc[o]; }, test); let octicon = $("
", { href: '#' + id }).append(OCTICON_USE).on("click", function (evt) { evt.preventDefault(); $(".highlight").removeClass("highlight"); let fragment = $(this).attr("href").substr(1); if (!evt.shiftKey) { location.hash = fragment; } else { location.hash = location.hash + "--" + fragment; } highlight(location.hash); }); let name = drag("td", { title: test.comment }, showTest, "application/json").append( octicon, " ", id.substr(1) ); toAdd = toAdd.concat( $("", {id: id}).append( status, name, // $("").append(shexc), $("").append(data), shapemap structure.fields.map(h => { return h.f(attrs, h.name); }) )); if (testNo === tests.length-1) { // Table footer with column titles. toAdd = toAdd.concat( drag("tr", { }, x => JSON.stringify(tests, null, 2), "application/json").append( $(""), $("").text(tests.length + " tests"), structure.fields.map(h => { return $("").text(h.name); }) ) ); } function showTest (elt) { return JSON.stringify(test, null, 2); } function ttl (ld) { return typeof ld === "object" ? lit(ld) : ld.startsWith("_:") ? ld : "<" + ld + ">"; function lit (o) { let ret = "\""+o["@value"]+"\""; if ("@type" in o) ret += "^^<" + o["@type"] + ">"; if ("language" in o) ret += "@" + o["language"]; return ret; } } function drag (name, attrs, val, type) { return $("<"+name+"/>", attrs).attr("draggable", true). on("dragstart", (evt) => { evt.originalEvent.dataTransfer.setData(type, val(evt.target)); return true; }); } function link (attrs, name) { let val = attrs[name]; let a = $("", { href: relPrepend + val }).text(val); attrs[name] = a.prop("href"); return title(drag("td", {}, elt => { return a.get(0).href; }, "text/uri-list").append(a), a.get(0).href); } function title (target, url) { // localStorage shaves ~1.5s off the load time. if (typeof(Storage) !== "undefined" && url in localStorage) { target.attr("title", localStorage[url].length > 0 ? localStorage[url] : "-- empty file --"); } else { $.ajax({ url: url, dataType: 'text', type: 'GET', async: true }).then(function (data) { if (typeof(Storage) !== "undefined") { localStorage[url] = data; } target.attr("title", data.length > 0 ? data : "-- empty file --"); }).fail(function (jqXHR, status, errorThrown) { target.addClass("error"); target.attr("title", url + " " + status + ": " + errorThrown); }); } return target; } function makeShapeMap (attrs, val) { if ("map" in attrs) { var a = $("", { href: relPrepend + attrs.map }).text(attrs.map); title(a, a.get(0).href) attrs["map"] = a.prop("href"); return drag("", { }, elt => { return a.get(0).href; }, "text/uri-list").append(a); } else { return drag("td", { }, elt => { return elt.innerText; }, "text/plain").text(ttl(attrs.focus) + "@" + ("shape" in attrs ? ttl(attrs.shape) : "START")) } } }; } function readfiles(files, target) { var formData = new FormData(); for (var i = 0; i < files.length; i++) { var file = files[i], name = file.name; formData.append("file", file); var reader = new FileReader(); reader.onload = (function (target) { return function (event) { target.text(event.target.result); }; })(target); reader.readAsText(file); } } function aFewTests () { return [ { "@id": "#0_otherbnode", "@type": "sht:ValidationTest", "action": { "schema": "../schemas/0.shex", "shape": "http://a.example/S1", "data": "Babcd_Ip1_Io1.ttl", "focus": "_:abcd" }, "extensionResults": [], "name": "0_otherbnode", "trait": [ "ToldBNode", "Empty" ], "comment": " { } on { _:abcd }", "status": "mf:proposed" }, { "@id": "#3Eachdot3Extra_pass-iri1", "@type": "sht:ValidationTest", "action": { "schema": "../schemas/3Eachdot3Extra.shex", "shape": "http://a.example/S1", "data": "Is_Ipn_IonX3.ttl", "focus": "http://a.example/s" }, "extensionResults": [], "name": "3Eachdot3Extra_pass-iri1", "trait": [ "Extra", "IriEquivalence", "EachOf" ], "comment": " EXTRA EXTRA EXTRA { [], [], [] } on { ; ; }", "status": "mf:proposed" }, { "@id": "#3circRefS1-IS2-IS3-IS3", "@type": "sht:ValidationTest", "action": { "schema": "../schemas/3circRefS1-IS2-IS3-IS3.shex", "shape": "http://a.example/S1", "data": "3circRefPlus1_pass-open.ttl", "focus": "http://a.example/n1" }, "extensionResults": [], "name": "3circRefS1-IS2-IS3-IS3", "trait": [ "Import" ], "comment": "I2 I3 { ., @? } | I3 { @ } | { @ } on { \"X\" ; . . . \"X\" }", "status": "mf:proposed", "result": "3circRefPlus1_pass-open.val" }, { "@id": "#focusdatatype_pass", "@type": "sht:ValidationTest", "action": { "schema": "../schemas/focusdatatype.shex", "shape": "http://a.example/S1", "data": "Is1_Ip1_LabDTbloodType.ttl", "focus": { "@value": "ab", "@type": "http://a.example/bloodType" } }, "extensionResults": [], "name": "focusdatatype_pass", "trait": [ "FocusConstraint" ], "comment": " on { 'ab'^^my:bloodType }", "status": "mf:proposed" }, { "@id": "#dependent_shape", "@type": "sht:ValidationTest", "action": { "schema": "../schemas/dependent_shape.shex", "data": "dependent_shape.ttl", "map": "dependent_shape_map.json" }, "extensionResults": [], "name": "dependent_shape", "trait": [ "ShapeMap" ], "comment": " { @} { []} on { . .}", "status": "mf:proposed", "result": "dependent_shape_results.json" }, ]; } })();