8000 GitHub - rudof-project/web-demo: Web demo using rudof-lib wasm for validation · GitHub
[go: up one dir, main page]

Skip to content
rudof-projectPublic

About

Web demo using rudof-lib wasm for validation

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

77 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rudof demo

This repo contains the source code of the Web demo based on rudof-lib WebAssembly features

The demo converts RDF data and property graphs between formats, validates them with ShEx, SHACL, DCTAP or PGSchema, generates synthetic data from a SHACL, ShEx or PGSchema schema, queries RDF data with SPARQL, and compares RDF graphs and schemas, all in the browser. rudof (@rudof/rudof) and PlantUML are loaded from jsDelivr when the page runs; everything else is built from this repo.

Building the page

You need Node.js 22 (22.12 or later) and npm.

npm ci              # install the dependencies, as in package-lock.json
npm run dev         # serve the page at http://localhost:5173, reloaded on every change
npm run build       # build the page into dist/
npm run preview     # serve dist/ at http://localhost:4173

dist/ is a static site: its paths are relative, so it can be published in any folder of any web server, as is.

The inputs of RDF data, schemas and queries

The inputs that ask for RDF data, a schema or a query are one component (inputs.js), so that they look and work the same in all the tabs. index.html writes only their textarea, with the kind of the input, its label and its example:

<div class="field">
  <span class="hint" id="shex-data-unused" data-head hidden>Not used: …</span>
  <textarea id="shex-data" data-input="rdf" data-label="RDF data">…</textarea>
</div>

inputs.js runs before the editors are made (codemirror-setup.js), and makes the head of each input: its label, the elements of the field marked data-head, and the menu of its formats (<id>-format) or the name of its only format. Then each one has Text | URL (below), and Visualize when it can be drawn (the RDF data and the ShEx schemas).

  • data-input="rdf": RDF data, in the RDF formats (RDF_FORMATS of schema-convert.js): the RDF data of the RDF, ShEx, SHACL, DCTAP and SPARQL tabs, the target declarations of SHACL, the two of Compare, and the RDF data added to a tab (+ Add RDF data).
  • data-input="schema": a schema, in the formats of its language (data-language: shex, shacl, dctap or pgschema; LANGUAGES of schema-convert.js): the schemas of the Validate tabs. When the page chooses the language (the Schema tab, Generate, Compare), the menu is empty and the page fills it, or the textarea names a menu of its own (data-format-select).
  • data-input="query": a query (data-language="sparql"): the SPARQL query.

The other inputs (property graphs, shape maps, type maps, the prefixes of a DCTAP profile, the configuration of Generate) are editors as before.

The examples of the inputs are the same in all the tabs: the files of examples/person/, which a textarea names with data-example="person/data.ttl" (any textarea can have one). They are persons with a name, maybe a birth date, who know other persons:

File Example of
data.ttl the RDF data of the RDF, ShEx, SHACL, DCTAP, SPARQL and Compare tabs
schema.shex the ShEx schema of the ShEx, Schema and Compare tabs
shapes.ttl, profile.csv, schema.pgs the same schema in SHACL, DCTAP and PGSchema
shapemap.txt the shape map of ShEx and DCTAP
data.pg, typemap.txt the same data as a property graph (Data and PGSchema), and its type map
query.rq the SPARQL query (the first of its examples)

All the schemas say the same: Alice and Carol conform, and Bob doesn't (two names, and a birth date that is not a date). The Generate tab has them as its first example. The build publishes examples/person/ with the page.

Inputs from URLs

As in RDFShape, the RDF data, the schemas and the queries can be given as Text (the editor) or by a URL: the switch next to their names (input-source.js). With URL, a field takes the place of the editor, and the page reads the URL when the tab runs (with fetch: its server must allow other sites to read it, CORS). Its text goes to the input, so rudof reads it as any other text, and the format menu takes the format of the extension of the file (.ttl, .nt, .shex…), when it has one. Under the field, the page says what it read.

  • In the tabs with an endpoint, the URL can be a prefixed name, with the prefixes of the endpoint (and common prefixes): on Wikidata, es:E371 is https://www.wikidata.org/wiki/Special:EntitySchemaText/E371, the EntitySchema E371. The field shows the URL of the prefixed name.
  • Text gives back the text that the input had, and URL the last URL. Edit as text reads the URL and puts its text in the editor.
  • Permalinks have the URL of the input (schema-url=es:E371), not its text.
  • The relative imports of a ShEx schema from a URL are relative to the URL.
  • An example of a manifest, or a result used as input, puts its text in the input, as text.

All the inputs of RDF data, schemas and queries (see The inputs of RDF data, schemas and queries) can be given by a URL.

Inputs as diagrams

Visualize, next to the format menu of the inputs of RDF data (the RDF data of the RDF, ShEx, SHACL, DCTAP and SPARQL tabs, the target declarations of SHACL, and the two of Compare) and of ShEx schemas (of the ShEx tab, and the two of Compare), shows the input as a diagram in place of its editor. rudof writes the diagram in PlantUML (serializeData and serializeCurrentShex), and PlantUML draws it, as for the UML diagrams of the results. The button is then Edit, which shows the editor again.

  • The RDF data of a tab is drawn with the RDF data added to it; the other inputs of RDF data (Compare, the target declarations) alone. An input given by a URL is read first. The relative imports of a ShEx schema are read too.
  • Show PlantUML source shows the source of the diagram, and Download SVG saves the diagram.
  • When the input has an error, the box says it.
  • An example, a result used as input, or Swap in Compare, shows the editor again.

Editors

The inputs of the demo are CodeMirror 6 editors, set up by codemirror-setup.js:

  • Each <textarea data-editor> of index.html is replaced by an editor when the page loads. The textarea stays, hidden, and stands for the editor, so demo.js reads and sets textarea.value as before.

  • The format of the text is fixed with data-language="sparql", or chosen in a select of the page with data-format-select="<id of the select>".

  • The language of each format is in languages/index.js, and is loaded the first time it is needed. Turtle (also TriG, N-Triples, N-Quads and N3), ShExC and shape maps have their own parsers in languages/; RDF/XML, JSON-LD, ShExJ and SPARQL use the CodeMirror packages.

  • Property graphs, their schemas and type maps have Lezer grammars, each language in its own folder:

    • languages/yars-pg/: YARS-PG (yars-pg.grammar). It reads the syntax of rudof (pg.rustemo of rudof's pgschema crate) and YARS-PG 5 (YARSpg.ebnf): metadata, variables, graphs, undirected edges, sets, structs, meta-properties and schemas.
    • languages/pgschema/: PGSchemaC (pgschema.grammar, from pgs.rustemo) and type maps (typemap.grammar, from map.rustemo).

    Each folder has the grammar, highlight.js (the highlighting tag of each node of the grammar) and index.js (the CodeMirror language, with folding and indentation). @lezer/generator compiles the grammars when the page is built and tested (the lezer() plugin of vite.config.js and vitest.config.js). Text that does not follow the grammar is still shown; the highlighting goes on after it.

  • The editors have line numbers, undo history, search (Ctrl+F), bracket matching and closing, and take the colors of the page, light or dark. Ctrl+Enter still validates.

  • The editors of Turtle (TriG, N3), ShExC and SPARQL complete prefixes (prefix-completion.js): after PREFIX (or @prefix), the declarations of the prefixes known; in the text, their aliases (wd:), and choosing one that the text doesn't declare also adds its declaration, with the others, in the style of the text. The prefixes known are those of the text, those of the endpoint of the tab, and common ones (prefixes.js). Ctrl+Space shows them.

  • The results of conversions (RDF data, property graphs, and ShEx and SHACL schemas), of validations and of queries are shown in read-only editors, highlighted in the format chosen for the result. Results in CSV have a CSV | Table switch, to see them as a table; the browser remembers it. demo.js still writes the result in its <pre>, which is hidden, and the viewer follows it (pre[data-viewer]).

Schema

The Schema section (between Data and Validate) converts a schema in ShEx, SHACL, DCTAP or PGSchema, in one of its formats, to another format, to another schema language, to a UML diagram or to a SPARQL query. schema-convert.js has what each language converts to:

From \ To ShEx SHACL DCTAP PGSchema UML SPARQL
ShEx ✓ – – – ✓ ✓
SHACL ✓ ✓ – – ✓ ✓
DCTAP ✓ – ✓ – ✓ ✓
PGSchema – – – ✓ – –

The conversions to ShEx, UML and SPARQL go through ShEx (ShExJ); SHACL, DCTAP and PGSchema are written again as rudof reads them (DCTAP as text or JSON, PGSchema as text: rudof 0.3.25 can't write DCTAP CSV or PGSchemaC yet). What rudof can't do yet (–) is in the menus, marked "not in rudof yet", and can't be chosen. A DCTAP profile has its prefixes and its table view, as in the DCTAP tab of Validate. Use as input reads the result as the schema, when it is a schema in a format the tab reads.

Compare

The Compare section compares two RDF graphs (Data) or two schemas (Schemas), with compare.js. What rudof can't compare yet is in the menus, and can't be chosen: property graphs, and the schemas of SHACL, DCTAP and PGSchema.

  • Data (rudof 0.3.36, diffData) says how the first RDF data and the second one are related, up to the names of their blank nodes: they are isomorphic (the same graph), equivalent (each one is contained in the other, but not isomorphic), the first one is contained in the second one (subgraph) or the second one in the first one (supergraph), or they are different. Blank nodes says how the blank nodes of a graph may be mapped to the terms of the other one: injective (two blank nodes can't go to the same term; the default), homomorphic (they can), or entailment (a blank node can also go to an IRI or a literal).
    • Table has the triples that are only in one of the graphs, as in the other tables of results (sorted, filtered, with links), written with the prefixes of the two inputs, and the blank nodes of the first graph matched in the second one. Report is the report of rudof, and JSON what diffData returns.
    • The names of the graphs of TriG and N-Quads are not compared.
    • When an input can't be read, the result says which one.
  • Schemas (compareSchemas) compares a shape of the first ShEx schema with a shape of the second one, property by property, and shows the report of rudof. Shape is the shape of each schema (a prefixed name of the prefixes of the schema, or an IRI); when it is empty, it is the first shape of the schema. rudof doesn't say yet whether the schemas are equivalent, or one contains the other, and it only reads ShExC for this (ShExJ and ShExR are in the menu, and can't be chosen). In rudof 0.3.36, compareSchemas crashes with SHACL and ShExR (a panic, "not yet implemented"), so the page doesn't call it for them.
  • Swap swaps the two inputs, with their formats and shapes. Permalinks have both inputs: data and data2, or schema and schema2, with #compare/compare-data or #compare/compare-schemas.

ShEx imports

A ShEx schema can import other schemas (IMPORT <iri> in ShExC, imports in ShExJ). Since rudof 0.3.31, rudof with endpoints gets them with fetch (readShexAsync, which goes through setFetch too), so the page reads a schema with imports with it (schema-convert.js, readShexSchema): in the ShEx tab (validations, also on endpoints, and Convert schema) and in the Schema tab. Schemas without imports are read as before (readShex). While rudof gets the imports, the result says "Reading the imported schemas…". A schema with imports is read in a new session: a session that waits can't do anything else.

  • The servers of the imported schemas must allow other sites to read them (CORS).
  • Relative imports (IMPORT <book.shex>) are relative to the file of the schema, when it is the schema of an example of a manifest.
  • What rudof writes keeps the imports (IMPORT, imports): ShEx in other formats, and UML diagrams, are written from the schema read, with its imports. Conversions that read the schema again (ShEx to SPARQL) can't get the imports yet.
  • Only rudof with endpoints has readShexAsync (it needs JSPI): in Firefox and Safari, the page says that the imports need it.

DCTAP

The DCTAP tab of Validate reads a DCTAP profile in CSV (spreadsheets can be saved as CSV). The names of the profile are prefixed names (foaf:name) or names without prefix (Person), so the tab also has Prefixes of the profile, in Turtle syntax: PREFIX foaf: <…>, and BASE <…> for the names without prefix. The basic prefixes of rudof (rdf, rdfs, xsd, sh, dc) are always there. The values of picklists are separated by spaces, as in DCTAP, or by |, as rudof does by default. dctap.js turns the prefixes into the configuration of rudof (TOML).

  • Validate converts the profile to ShEx and validates the data with it, for the shape map. rudof can't convert DCTAP to SHACL yet: the SHACL option of Validate with is there for when it can.
  • Convert the profile to ShEx (ShExC, ShExJ or ShExR), a UML diagram, a SPARQL query, or DCTAP as rudof reads it (text or JSON). SHACL will come with rudof.

The profile is highlighted by column (languages/dctap/): the header names the column of each cell. The CSV | Table switch of the profile shows it as a table (table-view.js, with csv.js), whose cells can be edited: Enter goes to the cell below, Add row and × add and delete rows, and each change is written back to the CSV, which stays the input. The browser remembers the view.

Generate

The Generate section (the last one, after Compare) generates synthetic data from a schema with generate of rudof (since rudof 0.3.37), and validates it with the same schema right away. It has a tab for each schema language, SHACL, ShEx and PGSchema, which share their panel (data-panel="gen"): the tab chooses the language (data-select, data-value), and the permalink keeps it (#generate/gen-shex). generate.js has the views of the result.

As in the tabs of Validate, the schema is the first box, and Generated data the second one: Generate writes in it the data it generated, under them the Generator configuration, and the result is below.

  • The examples are in a manifest, examples/generate/manifest.yml, with the schemas next to it, which the build publishes with the page. Each section is an example (with an id), and each entry of a section a kind of data (kind), with action: generate, the schema in each language (shaclURL, shexURL, pgschemaURL) and the configuration of the generator (config). The Examples menu opens it (Generate examples), and so does the link above the boxes: an entry of it opens the Generate tab, with its schema and its configuration. An example of action: generate of another manifest also goes to the tab; help.html documents the keys.
  • The first example, which the tab has at first, is the one of the other tabs (persons, examples/person/), in SHACL, ShEx and PGSchema: a small schema to edit, to write your own. The others are six models, each written in the three languages: references, keys, facets, labels, LUBM and LDBC SNB. They are written over the RDF encoding of a property graph, so the three schemas generate the same graph, and SHACL and ShEx also get the property graph. The kinds of data write the generator's configuration (TOML, version 2), which can be edited before Generate: valid data, dense or sparse data, a target coherence, or data with errors (20% of the entities broken, one constraint each).
  • The line above the boxes says which example and kind of data the tab has (the first one of the manifest at first). A permalink has the schema and the configuration: when it opens, the example is the one with this schema (and the kind of data the one with this configuration), so its other languages are there too.
  • Generated data has the RDF data (Turtle), or, from a PGSchema, the property graph (YARS-PG); its menu shows the other one when the data has it (the examples of SHACL and ShEx have a property graph too). It can be edited: Validate with, Open in and Download take its text, and the menu keeps the text of each one. Permalinks don't have it.
  • Show: a summary (nodes, the property graph's nodes and edges, the report, what the validator rejects, the nodes of each shape), the type map of the property graph, the ShapeMap, the error report and the validation. With errors, the report says which nodes a correct validator must reject (direct, the broken node, and induced, a node that refers to it) and which changes leave the data valid (trap). The verdict compares it with what the validator rejects. Download saves the view shown, or, with the summary, the generated data.
  • Validate with SHACL / ShEx / PGSchema validates the data here, with the example's schema in that language. Open in SHACL / ShEx / PGSchema copies the data and that schema to the tab of Validate instead. PGSchema needs a property graph, and a schema of your own (one that is edited, or that an example has in one language only) has no other language.
  • The schema, the generated data, the configuration and the result have a height of their own (their handle, or Full screen, makes them bigger): the data can be long.

SPARQL endpoints

In the SPARQL, ShEx, SHACL and DCTAP tabs, the Endpoint field runs the query or the validation on a SPARQL endpoint instead of the RDF data of the page. Its menu has None (the RDF data of the page), the endpoints that rudof knows (Wikidata, DBpedia, UniProt, …) and Other, to write the URL of any other endpoint in the field next to it.

rudof goes to the endpoint: useEndpoint, then runQueryAsync, validateShexAsync or validateShaclAsync. ShEx asks the endpoint for the data of each node of the shape map, and SHACL for the data of its targets. The page describes the endpoint to rudof (endpointConfig in endpoint.js) with the prefixes of the schema, so the shape map can use them: the data of an endpoint has no prefixes.

Under the field, Prefixes of … lists the prefixes that rudof declares for the endpoint (in rudof_rdf/endpoints/<name>.toml of its repository, which the page reads from jsDelivr for the version of rudof it loads: the npm package doesn't have them), or that the settings give it. The editors of the tab offer them, and the validations on the endpoint can use them in their shape maps, with the prefixes of the schema.

With the RDF data, next to the field, also uses the RDF data of the tab: rudof merges it with the data of the endpoint (useEndpoint, then readData with merge), so a validation or a query sees both. SPARQL SERVICE to an endpoint is not available: rudof says that the service is not supported.

This needs rudof built with the endpoints feature (@rudof/rudof/endpoints, in the package since rudof 0.3.27), and its WebAssembly needs JSPI (JavaScript Promise Integration): Chrome and Edge 137 or later have it, Firefox and Safari don't yet. So the page loads @rudof/rudof@<version>/endpoints/web/rudof_wasm.js in browsers with JSPI, and the usual web/ build in the others, or when it can't be loaded. The status line says "with endpoints" when it has them. When rudof with endpoints can't be loaded in a browser with JSPI, the hint of the Endpoint fields says why (as does the tooltip of the status line). Without them, the page sends SPARQL queries to the endpoint itself (endpoint.js, with the SPARQL 1.1 protocol), and the validations can't use endpoints.

The queries to the endpoint

While a run waits for an endpoint, the result shows its queries: how many were sent, answered, waiting and failed, the time of the run (in the head of the result), t 2360 he limits of the requests, Stop, and a table of the queries, the last one first. The table has, for each query, when it was sent, the status of the answer, how long it took, its size, the nodes it asks about (rudof asks about several nodes of a shape map in one query, with VALUES) and the query. A click on a query shows all of it, the endpoint and the start of the answer (at most 4000 characters; JSON indented). The table shows the last 500 queries (it is drawn again at each one). After the result, the switch Result | Queries (n) of the result goes from one to the other, also when the run fails or is stopped.

Stop aborts the queries that wait, and stops the run. rudof can't be stopped from JavaScript: the session goes on with the validation until it gives up. Until then, the requests of the stopped run fail at once, without going to the network (the summary says "stopping: rudof gives up" and how many requests were not sent): else rudof would go on asking the endpoint, and reading its answers, in the page, which can hang it. rudof gives up when its requests fail (after its retries, some seconds). A new run of the tab waits until then (at most 15 s), and says "Stopping the previous run…": the requests of the two runs could not be told apart.

rudof has no logs in WebAssembly, so the page gets the requests from the function that rudof uses to send them (setFetch): endpoint-log.js sends them with fetch and logs them. The query of the SPARQL tab that the page sends itself (without rudof with endpoints) is shown too. rudof counts the requests of a session (requestCount), but can't say it while the session waits, so the page says it after the run, when it differs from the list (the list can have the queries of other tabs that run at the same time).

The limits of the requests

rudof 0.3.29 waits between two requests to an endpoint, so that public endpoints such as Wikidata don't block it, and asks about the nodes of a shape map in batches. The Endpoints section of the settings (also Options, next to the Endpoint field) changes this, in [rdf] of the configuration:

  • Milliseconds between two requests (min_request_interval_ms): 1100 by default, 0 for localhost. 0 doesn't wait. rudof still waits longer when an endpoint answers 429 Too Many Requests, and sends a query again when the answer is 429, 502, 503 or 504, at most 3 times.
  • Requests at the same time (max_concurrent_requests, 1 by default): when rudof gets the nodes of a shape map before it validates them.
  • Nodes in one query (max_nodes_per_query, 20 by default; 1 sends a query for each node).
  • How SHACL gets the data of an endpoint ([shacl] fetch_strategy, rudof 0.3.30): node by node, when the validation needs it (on-demand, the default), or shape by shape before the validation (by-shape), with the data of many focus nodes in one query: far fewer requests when there are many focus nodes. With by-shape, nodes in one query (prefetch_batch_size, 50 by default) and the depth of the data fetched before (prefetch_max_rounds, 16 shape references by default, from the shapes with targets; deeper data is fetched when the validation needs it).
  • How validations get the data of the nodes: SPARQL queries (the default), or the RDF of the IRIs of the nodes (dereference, the strategy of useEndpoint), which needs servers that allow other sites to read them (CORS), and https IRIs. The SPARQL tab always queries the endpoint.

The endpoints that rudof knows have their own limits in their TOML files (such as min_request_interval_ms = 1100 of Wikidata), and so can the endpoints of the settings ([rdf.endpoints.<name>]). The page gives them to rudof with the description of the endpoint (endpointConfig), so they win over the settings, as in rudof: Wikidata keeps 1100 ms when the settings say 0. The result shows the limits that apply to each run: the time between two queries, the requests at the same time and the nodes in one query in the ShEx and DCTAP tabs; the time between two queries and how SHACL gets the data in the SHACL tab; the time between two queries in the SPARQL tab (one query). A limit that the endpoint sets itself is marked so ("1 query every 1.1 s at most (set by Wikidata)"); the others are those of the settings, or the defaults of rudof.

SELECT results show in the table (with the prefixes of the query), as JSON or as CSV. The graphs of CONSTRUCT and DESCRIBE can be written in every RDF format.

The endpoint must allow other sites to query it (CORS), as Wikidata does, and the page (https) can't query an http: endpoint.

The browser tests run with both builds of rudof: with endpoints (from endpoints/web/ of the package) and without them. To test another build of rudof with endpoints, such as one built from the rudof repository, give its folder in RUDOF_ENDPOINTS_DIR:

RUDOF_ENDPOINTS_DIR=<folder with rudof_wasm.js and rudof_wasm_bg.wasm> npm run test:e2e

Header and theme

The header of the demo and of the help page (header.js) has Examples (the examples of the ISWC 2026 tutorial, and how to write a manifest of your own), Help, and About (the manual of rudof, rudof and this demo on GitHub, the npm package, and the versions: the rudof that the page loads, and the version of the demo, in VERSION, with its commit, which the build takes from GITHUB_SHA or from git). Examples and About are <details> menus, which open without JavaScript too.

Next to them, the theme (the sun or the moon): As the system, Light or Dark. The browser keeps it, and an inline script in the <head> of the pages applies it b E870 efore they are drawn. The dark colors are those of :root[data-theme="dark"] in demo.css, and of the system when no theme is chosen; a unit test checks that both are the same.

Settings

The gear of the header opens the settings of rudof (settings.js, settings-dialog.js): the configuration of rudof that applies to every operation of the page. The dialog has the settings that change what rudof does in the browser, by sections:

Section Settings
General the base IRI, the indentation of JSON and JSON-LD results
Endpoints the time between two requests, the requests at the same time, the nodes in one query, how SHACL gets the data of an endpoint (node by node or shape by shape), and how validations get the data of the nodes (see above)
ShEx validation the maximum number of steps, the negation requirement
UML diagrams direction, lines, shadows, labels for IRIs and the properties of the labels, colors
RDF diagrams the colors of IRIs, blank nodes and literals (RDF data converted to a diagram)
SPARQL queries (from ShEx) the variable of the focus node
SHACL to ShEx target classes as rdf:type, blank-node shapes embedded
DCTAP delimiter, quote, flexible rows, delimiter of value shapes, base of datatypes

More settings (TOML) takes any other setting, over those of the form, such as endpoints ([rdf.endpoints.<name>] with name, query_url, a [prefixmap] and the limits of their requests), which are added to the Endpoint menus with their prefixes. The configuration that rudof gets shows the result. Settings that rudof can't read are not saved, and the dialog says why. The browser keeps the settings that differ from the defaults (not the permalinks), and the gear shows how many there are; Reset to defaults forgets them.

The configuration of each operation (the base IRI of the page, the prefixes of a DCTAP profile, the options of SHACL, the description of an endpoint) gets the settings over it (configWithSettings), merged as TOML tables with smol-toml.

More RDF data

Under the RDF data of the RDF, ShEx, SHACL, DCTAP and SPARQL tabs, + Add RDF data adds another editor of RDF data, with its own format (extra-data.js). rudof merges all of them (readData with merge) before it converts, validates or queries them, also with the data of an endpoint. Remove removes one. Permalinks have them as data-2, data-2-format, data-3… An example of a manifest, and Use as input of the RDF tab, replace them.

Results

The results of ShEx, SHACL, DCTAP and PGSchema validations are shown as a table by default (the Table result format): a row for each node and shape, with its result and its details. For ShEx, SHACL and DCTAP, the table is the details text of rudof, read back by box-table.js. The other formats are as rudof writes them.

The tables of results (validations, SPARQL solutions, CSV results) work as in a spreadsheet (table-tools.js):

  • Clicking the name of a column sorts the rows by it: in ascending order, then descending, then in their order again. Numbers are sorted as numbers.
  • The ▾ button next to the name opens the filter of the column: its values (in the rows that the other filters show) with how many rows have each one, a search box, (Select all), the sort orders and Clear filter. The filters of all the columns apply together, the button of a filtered column is marked, and a line under the table says how many rows it shows.
  • Dragging the right border of the name of a column changes its width (the arrow keys too, when the border has the focus). Then the table keeps the widths of its columns (table-layout: fixed): it grows, with a scroll bar, or becomes smaller, and the text that doesn't fit is cut. The widths stay for the next table with the same columns (the tab run again, or another result format and back), until the page is reloaded. A double click on a border gives the table its widths again.

The IRIs of the results are links, which open in another tab (iri-links.js): in the tables of validations, of SPARQL solutions and of CSV results, a cell wd:Q5685 is a link to http://www.wikidata.org/entity/Q5685. The prefixed names are read with the prefixes declared in the inputs of the tab (its data, schema, shape map…), those of its endpoint, and common prefixes. Only http and https IRIs are links; literals and blank nodes are text, and sorting and filters read the text of the cells, as before.

The other tables of the page have these borders too (makeResizable of table-tools.js): the table view of the DCTAP profile (whose widths stay when it is drawn again, as the text changes; the column of the buttons has none) and the table of the queries to an endpoint (drawn again at each query, with the same widths, also while a border is dragged).

When rudof crashes (a panic, or it runs out of stack), its WebAssembly module can't be used again. The result says what happened, and the page loads a new instance of rudof (the same module, from the cache), so that the tabs can run again without a reload; the status says "loaded again after an error". The results shown before can't be reformatted.

SHACL options

Next to the Validate button of the SHACL tab:

  • Recursion: what rudof does with shapes that refer to themselves, in a cycle (recursion_semantics, whose values are none, lfp and gfp since rudof 0.3.28; cautious and brave are their old names):

    • No recursion refuses a shapes graph with a cycle.
    • LFP: Conservative Mode (least fixed point, the default) is false unless proven: a node in a cycle conforms only when this can be shown without assuming that it conforms.
    • GFP: Permissive Mode (greatest fixed point) is true unless disproven: a node in a cycle conforms unless something shows that it does not.

    The options and the ⓘ next to the menu say this in their tooltips. Permalinks with the old names (recursion=cautious, recursion=brave) still work.

  • Show: the Errors (the violations and other results), the Evidences (why the nodes conform), and whether the evidences are only those of shapes, or also those of each constraint. By default, the errors and the evidences of shapes.

The Shapes graph is optional: when it is empty, rudof takes the shapes from the RDF data (readShacl without shapes), and the verdict says so. The same goes for SHACL examples of manifests without schema.

Under the shapes graph, the optional Target declarations are RDF triples that say which nodes the shapes apply to (such as :PersonShape sh:targetNode :alice .), in their own format. When they are not empty, rudof reads the shapes graph (or the RDF data, without a shapes graph) and the target declarations as RDF data in a session of their own, merges them, and reads the merged graph as the shapes. The verdict says "(with the target declarations)". In manifests, SHACL examples give them with targets or targetsURL, and targetsFormat (Turtle by default, or the format of the file extension). In permalinks, they are targets and targets-format.

They are the [shacl] section of the configuration of rudof (recursion_semantics, store_errors, store_evidences and evidence_shapes_only). Without the errors, the verdict doesn't count them.

Layout

layout.js lets you arrange the boxes of every tab (Data, Validate and Query):

  • Layout menu, next to Permalink: the two boxes of a row side by side or one above the other, in their order or swapped (for example the result left of the data, or the schema above the data). The browser remembers the choice. On narrow screens the boxes are always one above the other.
  • Splitter: side by side, drag the line between the two boxes to change their widths, or focus it (Tab) and use the arrow keys. A double click makes the widths equal again. The browser remembers the widths of each tab.
  • Heights: drag the handle at the bottom right corner of an editor or a result.
  • Full screen: the button at the top right of each editor and each result shows it on the whole window of the browser. The button again, or Esc, gives the normal size back. Ctrl+Enter still runs the tab.

Examples

examples/ has examples of every input format (RDF/XML, Turtle, TriG, N-Triples, N-Quads, N3, JSON-LD, SPARQL, ShExC and ShExJ), to try the editors with. The tests check that rudof accepts all of them.

Manifests

The Help page of the demo (help.html) explains how to run the examples of a manifest and documents the format of manifests, with an example for each action and validation engine.

The page can list the examples of a manifest, a YAML file such as the one of shex.js, and load the example chosen into the editors:

https://rudof-project.github.io/web-demo/?manifestURL=https://shex.js.org/doc/tests-manifest.yaml

manifest.js reads the manifest (it is loaded, with its YAML parser, only when the page has a manifestURL). Each entry is an example, in the vocabulary of shex.js:

- schemaLabel: clinical observation   # the examples are grouped by schema
  schemaURL: ClinObs.shex             # or the schema itself: schema: |
  dataLabel: the least an Observation can be
  data: |                             # or dataURL:
    <Obs1> :subject <Patient2> .
  queryMap: <Obs1>@START              # the shape map, or queryMapURL:
  status: conformant                  # or nonconformant
  comment: Shown in the list of examples

A manifest can also put its examples in sections, which can have sections too. An item with section is a section: its title, an optional comment and examples, a list of examples and sections. A manifest without sections is a list of examples, as before, and keeps the menu of examples (grouped by schemaLabel). A manifest with sections shows them as a tree (parseSections in manifest.js, showSections in demo.js): the titles of the sections, closed, with the number of their examples; a click on a title opens the section (<details>), with its comment, and another click closes it. The examples are numbered in the order of the manifest, depth first, so &example=<n> still names one, and the demo opens its sections.

- section: Knowledge Graphs
  comment: Examples about Knowledge Graphs
  examples:
  - comment: Tim Berners-Lee in RDF (Turtle)
    dataURL: ex01.ttl
    action: data
  - section: RDF 1.2
    examples:
    - comment: RDF 1.2 (annotated triples)
      dataURL: ex05_annotated.ttl
      action: data
- comment: An example out of the sections
  dataURL: ex02.ttl
  action: data

Optional keys say what to do with an example. Without them, an entry is a ShEx validation, as in the manifests of shex.js:

Key Values Default
action data (load the data in the Data tab), validate (validate it in the Validate tab), query (run a query on it in the Query tab), schema (show the schema in the Schema tab, to convert it) validate
dataFormat an RDF format (turtle, ntriples, rdfxml, jsonld, trig, n3, nquads), or yars-pg for property graphs turtle
schemaFormat shex (ShExC), shexj or json (ShExJ), an RDF format (ShExR, or SHACL shapes; json is JSON-LD for SHACL), pgschema, or csv (DCTAP) shex
validationEngine shex, shacl or pgschema pgschema for property graphs or pgschema schemas, otherwise shex
query, queryURL the query, for action: query
queryFormat sparql sparql
queryEngine sparql sparql
endpoint the SPARQL endpoint the query or the validation (ShEx, SHACL, DCTAP) runs on, instead of the data (then the data is optional). Validations need a browser with JSPI
typeMap, typeMapURL the type map of PGSchema (or queryMap)
schemaLanguage (or schemaEngine) shex, shacl, pgschema or dctap: the language of the schema. DCTAP profiles go to the DCTAP tab, which validates them with ShEx. With action: schema, the language of the Schema tab dctap for CSV schemas (schemaFormat: csv or .csv files)
prefixes, prefixesURL the prefixes of a DCTAP profile, as Turtle declarations (PREFIX, BASE)
picklistSeparator space or "|": the separator of the values of picklists in DCTAP space
- dataLabel: Tim Berners Lee in RDF (SPARQL query)
  dataURL: ex01.ttl
  dataFormat: turtle
  queryURL: ex01.sparql
  action: query
- dataLabel: Tim Berners Lee as a property graph
  dataURL: ex02.pg
  dataFormat: yars-pg
  action: data
- schemaURL: ex11_researcher.shex
  action: schema                      # opens the schema in the Schema tab

URLs are relative to the manifest. Without a format, the format of a file is taken from its extension (.shex, .json, .ttl, .nt, .jsonld, .pg…), and the one of inline text is the default (or JSON-LD and ShExJ for text that starts with {). The list shows the comment of each example (or its dataLabel, if it has no comment). Choosing an example opens the tab of its action and loads its inputs; press the button of the tab (Validate, Run query, Convert) to run it. When an example is validated as loaded, the verdict says whether the result is the one of its status. Examples that the demo can't run are listed but can't be loaded; Why … examples can't be run, below the list, says why, with a hint to change each entry and the entry as the demo read it. They are validations on an endpoint in browsers without JSPI, validations that read their data as they go (neighborhood: of shex.js) without an endpoint, queries on property graphs, and formats that the tab can't read (such as TriX). &example=<n> loads the n-th example (from 1) when the page opens; the URL gets it when an example is chosen, so it can be shared. Choosing an example also puts its inputs in the URL (see Permalinks); the Reload the examples link, next to the list, opens the page again with only ?manifestURL=….

The manifest and its files are read by the browser, so their server must allow other sites to read them (CORS); GitHub Pages and raw.githubusercontent.com do. The tab of each action and validation engine, and the formats it reads, are in TARGETS of manifest.js.

Permalinks

After each operation (converting, validating, running a query, changing a result format, choosing a tab or an example), the query of the URL gets the inputs and options of the tab shown, and the fragment names the tab:

?schema=PREFIX%20…&data=PREFIX%20…&shape-map=%3CObs1%3E%40START%0A&schema-format=shexc&…#validate/shex

An input given by a URL is its URL, in the parameter of the input with -url (schema-url=es:E371). The Permalink button writes the inputs as they are now in the URL, and copies it. Opening the URL puts the inputs and options back in their tab. permalink.js has the parameters of each tab:

Tab Parameters
Convert (Schema) schema-language, schema-format, schema, prefixes, picklist, to, to-format
RDF data, data-format, result-format
Property graph data, result-format
ShEx schema, data, shape-map, endpoint, endpoint-data, schema-format, data-format, result-format, schema-result-format
SHACL shapes, data, endpoint, endpoint-data, shapes-format, data-format, mode, recursion, errors, evidences, evidences-shapes, result-format, schema-result-format
DCTAP dctap, prefixes, picklist, data, endpoint, endpoint-data, shape-map, data-format, engine, result-format, schema-result-format
PGSchema schema, data, type-map, result-format
SPARQL data, data-format, query, endpoint, endpoint-data, result-format

The RDF data added to a tab are data-2, data-2-format… (see More RDF data). Checkboxes (such as errors of SHACL) are true or false. manifestURL and example are kept. A URL without a fragment opens the tab of its parameters (ShEx for shape-map or schema), so links in the style of shex.js (?schema=…&data=…&shape-map=…) open the ShEx tab. When a URL has an example and inputs too, the inputs of the URL are used: they are the example as it was edited.

Servers refuse URLs that are too long (414 URI Too Long), and the inputs can be long (the schemas of Generate are up to 9,000 characters, 13,500 in a URL). When the query of a permalink is longer than 2,000 characters, its inputs go in one parameter, z: their query, compressed with deflate (fflate) and written in base64url, about ten times shorter. manifestURL and example stay as they are. Opening the URL expands them; a link that was cut, and can't be expanded, opens the page without its inputs.

The inputs are sent to the server of the page with the URL, and servers limit the length of URLs (often to about 8 KB), so very long inputs may not fit in a permalink.

Tests

npm test            # unit tests (Vitest, with jsdom)
npm run test:e2e    # the built page in Chromium (Playwright)

The browser tests build the page and serve it with npm run preview. rudof is served to the page from node_modules, so they don't need the network. The first time, install Chromium with:

npx playwright install --with-deps chromium

or use a Chromium you already have:

CHROMIUM_PATH=/path/to/chromium npm run test:e2e

demo.js loads the rudof version of package.json (the one the tests use), so updating rudof is only a change of package.json and package-lock.json (npm install --save-dev --save-exact @rudof/rudof@<version>).

Publishing

The GitHub Actions workflow runs the tests and builds the page on every push and pull request, and publishes dist/ to the gh-pages branch on every push to main.

update-rudof.yml updates @rudof/rudof to its latest release on npm once a day (or when run by hand from the Actions tab): it tests the update, pushes it to main and publishes the page. To update the page as soon as rudof is released, rudof's release workflow can send it a repository_dispatch, once the package is on npm:

- uses: peter-evans/repository-dispatch@v3
  with:
    token: ${{ secrets.WEB_DEMO_TOKEN }}  # may write to rudof-project/web-demo
    repository: rudof-project/web-demo
    event-type: rudof-released

About

Web demo using rudof-lib wasm for validation

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0